JeVois  1.12
JeVois Smart Embedded Machine Vision Toolkit
Share this page:
Component.H
Go to the documentation of this file.
1 // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2 //
3 // JeVois Smart Embedded Machine Vision Toolkit - Copyright (C) 2016 by Laurent Itti, the University of Southern
4 // California (USC), and iLab at USC. See http://iLab.usc.edu and http://jevois.org for information about this project.
5 //
6 // This file is part of the JeVois Smart Embedded Machine Vision Toolkit. This program is free software; you can
7 // redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software
8 // Foundation, version 2. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
9 // without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
10 // License for more details. You should have received a copy of the GNU General Public License along with this program;
11 // if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
12 //
13 // Contact information: Laurent Itti - 3641 Watt Way, HNB-07A - Los Angeles, CA 90089-2520 - USA.
14 // Tel: +1 213 740 3527 - itti@pollux.usc.edu - http://iLab.usc.edu - http://jevois.org
15 // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
16 /*! \file */
17 
18 // This code is inspired by the Neuromorphic Robotics Toolkit (http://nrtkit.org)
19 
20 #pragma once
21 
23 #include <boost/thread.hpp>
24 #include <string>
25 #include <vector>
26 #include <map>
27 #include <unordered_map>
28 #include <future>
29 
30 namespace jevois
31 {
32  class Manager;
33  class Engine;
34  class UserInterface;
35 
36  /*! \defgroup component Model components, parameters, manager, and associated classes
37 
38  These classes define how a complex model or vision processing pipeline with user-tunable parameters can be built
39  from components.
40 
41  How to explore this documentation module:
42 
43  - Start with looking at Component, which highlights the broad conceptual framework of how one may assemble complex
44  vision processing pipelines in JeVois, with substantial re-use of shared algorithmic elements.
45 
46  - Then have a look a \ref parameter which provides details on how to implement and use parameters in your
47  components. Parameters can be created for any valid C++ type, and serve the goal of allowing end-users of your
48  algorithm to tune some of the behavior of your algorithms.
49 
50  - Finally have a look at Manager, which is a special component that is the root of a component hierarchy.
51 
52  - You will then be ready to move to the next level by loking at the other elements in the documentation
53  module.
54 
55  \ingroup core */
56 
57  // ######################################################################
58  //! A component of a model hierarchy.
59  /*! Model Components form the heart of every JeVois application, as their main purpose is to allow 1) building complex
60  vision processing pipelines from shared, re-usable processing elements; 2) a uniform interface for tunable
61  parameters that these processing elements may have. In fact, every class which needs to expose parameters to the
62  user should inherit directly or indirectly from Component. Parameters are simple wrappers around any valid C++
63  type, along with some description, default values, possibly specification of valid values, etc. Parameters are
64  used to adjust the behavior of processing elements by allowing end-users to change the parameter values (think,
65  e.g., of a threshold in some image processing algorithm).
66 
67  Components typically form a component hierarchy with a Manager (including Engine) at the root, and a tree of
68  sub-Components below. To form this tree, just use the Manager::addComponent() and Component::addSubComponent()
69  methods to add some children, and then add some children to those children, etc...
70 
71  One intent behind Component is to enable substantial code re-use when implementing complex vision processing
72  frameworks, and to alleviate the burden of passing many parameters to function calls when invoking the processing
73  elements. This is a strong departure from many other frameworks such as OpenCV, which by and large rely on
74  functions with many parameters (though later versions do use classes as well). For example, the way one invokes a
75  Canny edge detector in OpenCV is to call the function:
76 
77  \code
78  void Canny(InputArray image, OutputArray edges, double threshold1, double threshold2,
79  int apertureSize = 3, bool L2gradient = false)
80  \endcode
81 
82  Beyond possible confusion about which value goes to which argument in the long list (which languages such as
83  Python solve by allowing access to arguments by name), one major issue with this approach is that either every
84  function using Canny must provide a mechanism for the user to set the parameters (threshold1, threshold2, etc),
85  or, in most cases, those will just end up being hardwired, limiting the applicability of the end application to
86  different image sizes, environment types, etc.
87 
88  In contrast, in the JeVois framework, one would create a Canny Component, with Parameter settings for the
89  thresholds, etc and a member function
90 
91  \code
92  OutputArray process(InputArray in)
93  \endcode
94 
95  One would typically first set the parameter values, then call the function. Setting the parameters can be done by
96  the code that will use the function, but, more often, it is left to the user. In a particular vision pipeline,
97  resonable default values may be provided for the parameters at the beginning, then leaving those parameters
98  accessible to end users who may want to modify them. Modification of parameters in JeVois is handled either at the
99  start of the application by parsing command-line arguments, when a new processing Module is instantiated, or while
100  it is running, by interacting with the Engine that manages the system via its Serial ports.
101 
102  Any complex vision processing pipeline that includes the Canny component in its hierarchy will expose its
103  parameters so that they can be set, either by users (via command-line arguments, commands issued over serial
104  ports, etc), or by other components in the hierarchy. If multiple instances of a Component are present in a
105  hierarchy, their parameters can either all be set at once to a single (shared) value, or they can be accessed and
106  set individually to different values (each Component has a unique instance name, and a so-called descriptor is
107  created by concatenating instance names of a component and all its parents; parameters of a specific Component
108  instance can be accessed by prefixing that instance's descriptor to the parameter name). Parameters provide a
109  uniform interface for setting/getting the parameter values, so that programmers do not have to program accessor
110  functions in each of their components for each of their parameters(e.g., adding a Parameter<int> for threshold1 to
111  your component will automatically add set(), get(), etc functions for it into your component).
112 
113 
114  In addition, Component provides some level of introspection or reflection: one can access a component instance
115  name, class name, descriptor that includes names of all its parents in the hierarchy, and iterate over its
116  parameters, over its sub-components, etc.
117 
118  Component is inherently thread-safe and the component interface is written so as to encourage thread-safe use; for
119  example, no function is provided that returns the parent of a component, as another thread could change that
120  between the time that parent is returned and the time it is used. Instead, functions are provided that can
121  traverse the hierarchy up or down in a thread-safe manner and execute some action on the components that are
122  encountered during that traversal.
123 
124  Components are brought into action in several phases:
125 
126  - Construction: In constructors, Parameter values have not been set yet so nothing that depends on them should be
127  initialized yet. Typically, constructors should only initialize fixed component resources which are independent
128  of Parameter values, or they can also set default values for parameters, which may later be overriden by
129  command-line arguments. In many situations, the constructor would do nothing, and most of the initialization
130  work would be delayed until the Parameter values have been set, during the component's init() phase.
131 
132  - initialization: When init() is called on the manager (including Engine), it propagates down the entire Component
133  hierarchy, as follows:
134 
135  - recursively call preInit() on all sub-components.
136  - run preInit() on the current component (the preInit() function can be overriden by derived classes to
137  implement some custom initialization; note that Parameter values are not yet finalized at this point and
138  should not be used yet).
139  - Manager then parses the command-line and possibly sets parameters. Parameters are considered ready to use from
140  this point on.
141  - for parameters of this component that have a callback but it has not yet been invoked because that parameter
142  has not been explicitly set at the command line, call the callback one first time with the default parameter
143  value. This is so that callbacks that create resources (e.g., callback for a parameter for the device name of
144  a device, which opens the device when called) are called at least once before init() is complete.
145  - recursively flip the state of all sub-components to initialized, then flip the component state to initialized.
146  - recursively run postInit() on all sub-components (derived classes may override postInit(), and would typically
147  allocate resources that depend on parameter values in their override of postInit()), then on the current
148  component.
149 
150  The initialization flow is fixed. Classes that derive from Component can override preInit() for intializations
151  that do not rely on Parameter values and postInit() for those that do. Once init() is complete on the Manager,
152  all components in the hierarchy are considered ready for operation.
153 
154  If a component is added to an already-initialized hierarchy, it will be brought up to the same init state as its
155  parent at the time of addition. This is typically the case when one selects a new video format from a USB host
156  on a JeVois system that is already running and streaming video. The Module handling the old format is furst
157  un-initialized by Engine, then it is destroyed, the new Module is instantiated for the new format, and it is
158  initialized before the stream of video frames is directed to it.
159 
160  - uninit: This is the dual of init(), with preUninit() and postUninit() following the same logic as preInit() and
161  postInit(). Specific order is:
162 
163  - preUninit() is recursively called on all sub-component then on the component (note that initialized() is still
164  true at this point);
165  - component flips to un-initalized, then recursivey all its sub-components
166  - postUninit() is called on component, then recursively on all its sub-components.
167 
168  Note how both init() and uninit() are private in Component, and thus cannot be called directly. Manager (and hence
169  Engine which derives from Manager) makes them public so that you can call them on the manager. That is, your
170  entire hierarchy is either initialized or not.
171 
172  Because powering up the JeVois hardware platform automatically constructs and initializes the default processing
173  pipeline, and because of the aforementioned was in which Engine changes processing modules when users change video
174  format, most components just assume that their vision processing functions will never be called when the component
175  is not initialized, and thus they just skip testing for initialized() altogether (to save CPU cycles).
176 
177  \ingroup component */
178  class Component : public virtual ParameterRegistry
179  {
180  public:
181  //protected: // FIXME inherited constructor does not compile if protected!
182  //! Constructor
183  /*! The standard way to create a component is via Component::addSubComponent() or Manager::addComponent(), rather
184  than constructing them by hand. Components constructed via the constructor (e.g., calling operator new) will
185  not be attached to a Component hierarchy. It is recommended that derived components also have an instance
186  constructor argument and pass it down to the base Component class, to allow complex systems with several
187  instances of a same Component. In fact, for most components, the inherited constructor is appropriate:
188 
189  \code
190  class MyComp : public jevois::Component
191  {
192  public:
193  // Inherited constructor
194  using jevois::Component::Component;
195 
196  // Virtual destructor for safe inheritance
197  virtual ~MyComp();
198  };
199  \endcode */
200  Component(std::string const & instance);
201 
202  //! Virtual destructor for safe inheritance
203  /*! Calls uninit() if component is initialized. */
204  virtual ~Component();
205 
206  //! @name Component hierarchies
207  //! @{
208 
209  //! Pseudo-constructor: construct and add another component as a subcomponent of this one
210  /*! A child component of type Comp (which must derive from jevois::Component) will be created and added as a
211  sub-component of this. The child logically "belongs" to this component, and will automatically be initialized,
212  un-initialized, and deleted when the parent component is. In addition to construction, adding a subcomponent
213  will bring it up to the same init() state as the owner component.
214 
215  When setting parameters, the sub-Component can be referenced as a child of this component. For instance, if
216  we have a ComponentParent which has ComponentChild as a sub-Component, and ComponentChild has parameter named
217  coolChildParam, then that parameter could be specified on the command line by
218 
219  \code
220  --ComponentParentInstanceName:ComponentChildInstanceName:coolChildParamName="whatever"
221  \endcode
222 
223  or over a Serial port by
224 
225  \code
226  setpar ComponentParentInstanceName:ComponentChildInstanceName:coolChildParamName whatever
227  \endcode
228 
229  \param instance A string identifying a particular instance of a Component, no two sub-components of a
230  component may have the same instance name. The instance name should be passed in through your derived
231  Component's constructor, allowing users to disambiguate between multiple instances of your Component. If the
232  instance name is empty, the actual instance will be named <ComponentClassname># with # replaced (if necessary)
233  by a unique number. If the instance name is not empty but contains a #, only that # is replaced (if necessary)
234  by a number that makes the instance name unique. The final name is accessible via instanceName() once your
235  component is constructed. There is no default value for instance in the base class to catch derived classes
236  that forgot to pass it down to the base, but it may be a good idea to set an empty string default to instance
237  in derived classes.
238 
239  \note Sub-components always inherit the path of their top-level parent (a top-level component is one that was
240  directly added to a Manager via Manager::addComponent()). See absolutePath(). This is so that different
241  modules can provide different data for their components; for example, a FaceDetector component may require
242  some face template data files to operate; if those are loaded using a relative path name, different modules
243  that use the FaceDetector may use different face template data files. */
244  template <class Comp, typename... Args>
245  std::shared_ptr<Comp> addSubComponent(std::string const & instance, Args && ...args);
246 
247  //! Remove a sub-Component from this Component, by shared_ptr
248  /*! \note Beware that the passed shared_ptr is invalidated in the process. A warning is issued if the use_count is
249  not down to zero after that (i.e., there are additional shared_ptr pointers to this Component floating around,
250  which prevent it from actually being deleted. */
251  template <class Comp>
252  void removeSubComponent(std::shared_ptr<Comp> & component);
253 
254  //! Remove a sub-Component from this Component, by instance name
255  void removeSubComponent(std::string const & instance, bool warnIfNotFound = true);
256 
257  //! Get a sub-component by instance name
258  /*! This method does a dynamic_pointer_cast to Comp if it is not the default (jevois::Component). Throws if
259  component is not found by instance name, or it is found but not of type Comp (if Comp is specified). Note that
260  once you hold a shared_ptr to a Component, it is guaranteed that the component will not be destroyed until
261  that shared_ptr is released. If the JeVois system tries to destroy the component (e.g., someone calls
262  removeSubComponent()), the component will be un-initialized and its parent will be unset, so it will not be
263  fully operational and will be actually deleted when the last shared_ptr to it runs out of scope. */
264  template <class Comp = jevois::Component>
265  std::shared_ptr<Comp> getSubComponent(std::string const & instance) const;
266 
267  //! Returns true if this component is top-level, i.e., its parent is jevois::Manager
268  /*! The Module of Engine is top-level. */
269  bool isTopLevel() const;
270 
271  //! Get a handle to our Engine, or throw if we do not have an Engine as root ancestor
272  /*! Use with caution as this could break runtime loading/unloading of component hierarchies. */
273  Engine * engine() const;
274 
275  //! @}
276 
277  //! @name Component runtime
278  //! @{
279 
280  //! Has this component been initialized yet?
281  bool initialized() const;
282 
283  //! @}
284 
285  //! @name Component metainfo-related functions
286  //! @{
287 
288  //! The class name of this component
289  std::string const & className() const;
290 
291  //! The instance name of this component
292  std::string const & instanceName() const;
293 
294  //! @}
295 
296  /*! @name Component Parameter-related functions
297 
298  Each Component can hold Parameter objects (through inheritance) that can be set externally by users to modify
299  the operation of the Component, and that can be accessed or set by the Component itself.
300 
301  Note how the JeVois framework uses inheritance for parameters as opposed to making them class data members of
302  the owning Component. See \ref parameter for detailed explanations. */
303  //! @{
304 
305  //! Set a parameter value
306  /*! Throws if we don't have a parameter by that name or the value does not work out. Here is how the descriptor
307  works:
308 
309  The basic format is
310 
311  \code
312  [ComponentInstanceName]:[...]:[paramname]
313  \endcode
314 
315  Note that any <code>[ComponentInstanceName]</code> token can also be replaced by a *, which is equivalent to
316  any number of any ComponentInstanceName specifications. So use the * to reach parameters when you don't know
317  how deep they are. If there is some other ComponentInstanceName between a * and the final paramname, then
318  recursion is turned off and anything between the * and paramname must match intervening components/instances.
319 
320  For example,
321 
322  @code
323  MyInst:*:CoolComp:MyParam
324  @endcode
325 
326  would match parameters where MyInst matches the top-level component (the one on which you call setParamVal()),
327  then would recurse through any number of subcomponents, until one of them matches CoolComp, and then we would
328  look for MyParam parameter in that subcomponent, and we would not look any deeper.
329 
330  Finally note that there is an implicit first *: that is automatically prepended to your description, so if you
331  just specify a paramname and nothing else before it, we will set all params by that name in all subcomponents
332  no matter how deep they are (as if you had specified *:paramname).
333 
334  @throws std::exception if no Parameter matches the given descriptor.
335  @return list of fully-unrolled (no '*') descriptors of the parameters that were matched and set. The list is
336  guaranteed to have at least one element since we throw if no matching parameter is found. */
337  template <typename T>
338  std::vector<std::string> setParamVal(std::string const & paramdescriptor, T const & val);
339 
340  //! Set a parameter value, simple version assuming only one parameter match
341  /*! This calls setParamVal(), and checks that exactly one match was found.
342  @throws std::exception if not exactly one Parameter matches the given descriptor. */
343  template <typename T>
344  void setParamValUnique(std::string const & paramdescriptor, T const & val);
345 
346  //! Get parameter(s) value(s) by descriptor
347  /*! Use this method to get the current value of a Component's parameter from the string descriptor. Values for all
348  parameters that match the descriptor are returned.
349 
350  For example, if the class MyComponent has an integer parameter named "myparam" you could get the
351  value like so:
352 
353  @code
354  std::shared_ptr<MyComponent> comp = addSubComponent<MyComponent>("mycomp");
355  auto paramValues = comp->getParamVal<int>("myparam");
356  for (auto const & pp : paramValues) LINFO("Parameter " << pp.first << " = " << pp.second);
357  @endcode
358 
359  @throws jevois::exception::ParameterException if no Parameter matches the given descriptor.
360  @return list of <paramdescriptor, value> for all parameters that matched the given descriptor. The list is
361  guaranteed to have at least one element since we throw if no matching parameter is found.
362 
363  \see setParamVal for a detailed explanation of the paramdescriptor */
364  template <typename T>
365  std::vector<std::pair<std::string, T> > getParamVal(std::string const & paramdescriptor) const;
366 
367  //! Get a parameter value, simple version assuming only one parameter match
368  /*! This calls getParamVal(), checks that exactly one match was found, and returns its value.
369  For example, if the class MyComponent has an integer parameter named "myparam" you could get the
370  value like so:
371 
372  @code
373  std::shared_ptr<MyComponent> comp(new MyComponent);
374  int paramValue = comp->getParamValUnique<int>("myparam");
375  @endcode
376 
377  @throws jevois::exception::ParameterException if not exactly one Parameter matches the given descriptor. */
378  template <typename T>
379  T getParamValUnique(std::string const & paramdescriptor) const;
380 
381  //! Set a parameter value, by string
382  /*! \see setParamVal for a detailed explanation of the paramdescriptor
383  @throws jevois::exception::ParameterException if no Parameter matches the given descriptor or if the
384  given string cannot be converted to the Parameter's native type.
385  @return list of fully-unrolled (no '*') descriptors of the parameters that were matched and set. The list is
386  guaranteed to have at least one element since we throw if no matching parameter is found. */
387  std::vector<std::string> setParamString(std::string const & paramdescriptor, std::string const & val);
388 
389  //! Set a parameter value by string, simple version assuming only one parameter match
390  /*! This calls setParamVal(), and checks that exactly one match was found.
391  @throws jevois::exception::ParameterException if not exactly one Parameter matches the given descriptor. */
392  void setParamStringUnique(std::string const & paramdescriptor, std::string const & val);
393 
394  //! Get a parameter value, by string
395  /*! \see setParamVal for a detailed explanation of the paramdescriptor
396  Use this method to get the current value of a Component's parameter from the string descriptor. Values for all
397  parameters that match the descriptor are returned, as string.
398  @throws jevois::exception::ParameterException if no Parameter matches the given descriptor.
399  @return list of <paramdescriptor, valuestring> for all parameters that matched the given descriptor. The list
400  is guaranteed to have at least one element since we throw if no matching parameter is found. */
401  std::vector<std::pair<std::string, std::string> > getParamString(std::string const & paramdescriptor) const;
402 
403  //! Get a parameter value by string, simple version assuming only one parameter match
404  /*! This calls getParamVal(), checks that exactly one match was found, and returns its value as a string.
405  @throws jevois::exception::ParameterException if not exactly one Parameter matches the given descriptor. */
406  std::string getParamStringUnique(std::string const & paramdescriptor) const;
407 
408  //! Freeze a parameter, by name, see ParameterBase::freeze()
409  void freezeParam(std::string const & paramdescriptor);
410 
411  //! Unfreeze a parameter, by name, see ParameterBase::unFreeze()
412  void unFreezeParam(std::string const & paramdescriptor);
413 
414  //! Freeze all parameters
415  void freezeAllParams();
416 
417  //! Unfreeze all parameters
418  void unFreezeAllParams();
419 
420  //! Get our full descriptor (including all parents) as [Instancename]:[...]:[...]
421  std::string descriptor() const;
422 
423  //! Set some parameters from a file
424  /*! The file should have entries "descriptor=value", one per line, where the parameter descriptors should be
425  relative to this component. If the file name is relative, our component path will be prefixed to it using
426  absolutePath(). */
427  void setParamsFromFile(std::string const & filename);
428 
429  //! Set some parameters from an open stream
430  /*! The stream should have entries "descriptor=value", one per line, where the parameter descriptors should be
431  relative to this component. absfile is only used for error messages and should be the absolute path of the
432  file opened in 'is', or some other text for error messages. */
433  std::istream & setParamsFromStream(std::istream & is, std::string const & absfile);
434 
435  //! Get machine-oriented descriptions of all parameters
436  virtual void paramInfo(std::shared_ptr<UserInterface> s, std::map<std::string, std::string> & categs,
437  bool skipFrozen, std::string const & cname = "", std::string const & pfx = "");
438 
439  //! @}
440 
441  /*! @name Component path-related functions
442 
443  Each Component can keep track of a preferred filesystem path. Typically, users should not tamper with this,
444  but Module objects (which derive from Component) that are dynamically loaded will have that path set to the
445  path where the Module's shared object file (.so) was found. This allows those modules to access some of their
446  local configuration data, which may, for example, be stored in an \c etc/ directory under the module path. */
447  //! @{
448 
449  //! Assign a filesystem path to this component
450  void setPath(std::string const & path);
451 
452  //! If given path is relative (not starting with /), prepend the Component path to it
453  /*! If path is absolute, no-op. If path is empty, return the Component's path as set with setPath(). */
454  std::string absolutePath(std::string const & path = "");
455 
456  //! @}
457 
458  protected:
459  //! @name Component setup functions overloadable by derived classes
460 
461  //! @{
462 
463  //! Called before all sub-Components are init()ed
464  virtual void preInit() { }
465 
466  //! Called after all sub-Components are init()ed
467  virtual void postInit() { }
468 
469  //! Called before all sub-Components are uninit()ed
470  virtual void preUninit() { }
471 
472  //! Called after all sub-Components are uninit()ed
473  virtual void postUninit() { }
474 
475  //! @}
476 
477  private:
478  template <typename T> friend class ParameterCore;
479  friend class Manager; // Allow Manager to access our subs directly (in addComponent, etc)
480  friend class Engine; // Allow Engine to add already-created components (the module)
481  friend class Module; // Allow Module to access itsParent
482 
483  mutable boost::shared_mutex itsMtx; // Mutex used to protect our internals other than subcomps and parameters
484 
485  // Storage for sub-Components
486  std::vector<std::shared_ptr<Component> > itsSubComponents;
487 
488  // Mutex to protect our list of subcomponents
489  mutable boost::shared_mutex itsSubMtx;
490 
491  // Recursively populate a list of parameters, for help message
492  void populateHelpMessage(std::string const & cname,
493  std::unordered_map<std::string /* categ+categdesc */,
494  std::unordered_map<std::string /* name+defaultval+validvals+descrip */,
495  std::vector<std::pair<std::string /* component */, std::string /* value */ > > > > &
496  helplist, bool recurse = true) const;
497 
498  //! Initialization
499  /*! Invoke: runPreInit(), then setInitialized(), finally runPostInit() */
500  virtual void init();
501 
502  //! Recursively run preInit()
503  void runPreInit();
504 
505  //! Recursively set initialized flag
506  void setInitialized();
507 
508  //! Recursively run postInit()
509  void runPostInit();
510 
511  //! Un-initialize
512  /* Invoke: runPreUninit(), then setUninitialized(), finally runPostUninit() */
513  virtual void uninit();
514 
515  //! Recursively run preUninit()
516  void runPreUninit();
517 
518  //! Recursively set uninitialized flag
519  void setUninitialized();
520 
521  //! Recursively run postUninit()
522  void runPostUninit();
523 
524  // Our meta information. Only access this through meta(), even from within Component!
525  mutable boost::shared_mutex itsMetaMtx;
526  std::string const itsClassName;
527  std::string itsInstanceName;
528 
529  // Has this Component been initialized?
530  volatile bool itsInitialized;
531 
532  // The Component which contains this one as a sub-Component - this may be NULL if the component is not part of any
533  // hierarchy, or is the manager.
534  Component * itsParent;
535 
536  void findParamAndActOnIt(std::string const & descriptor,
537  std::function<void(jevois::ParameterBase * param, std::string const & unrolled)> doit,
538  std::function<bool()> empty) const;
539  void findParamAndActOnIt(std::vector<std::string> const & descrip, bool recur, size_t idx,
540  std::string const & unrolled,
541  std::function<void(jevois::ParameterBase *, std::string const &)> doit) const;
542 
543  std::string itsPath; // filesystem path assigned to this Component, empty by default
544 
545  //! Helper function to compute an automatic instance name, if needed
546  /*! Parent modules call this before adding a sub-module, to make sure its name will not clash with existing
547  sub-modules. Parameter classname can be empty if instance is not. Throws if a unique name cannot be created
548  (e.g., no # was provided and the instance name clashes with other sub-modules). itsSubMtx on the parent must
549  be locked by caller to make sure the computed name remains available as we return it */
550  std::string computeInstanceName(std::string const & instance, std::string const & classname = "") const;
551 
552  //! Actually remove a sub, no type checking here, for internal use only
553  /*! Uplck is assumed to already be locked for read, will be upgraded to write lock. Itr is an iterator on
554  itsSubComponents pointing at the component to remove. It will get reset(). displayname is just Component,
555  SubModule, etc for messages purposes. */
556  void doRemoveSubComponent(std::vector<std::shared_ptr<Component> >::iterator & itr,
557  boost::upgrade_lock<boost::shared_mutex> & uplck,
558  std::string const & displayname);
559  };
560 } //jevois
561 
562 // Include inlined implementation details that are of no interest to the end user
564 
virtual void preInit()
Called before all sub-Components are init()ed.
Definition: Component.H:464
A changeable parameter for a Component, core class.
Definition: Parameter.H:183
std::vector< std::string > setParamString(std::string const &paramdescriptor, std::string const &val)
Set a parameter value, by string.
Definition: Component.C:358
std::vector< std::string > setParamVal(std::string const &paramdescriptor, T const &val)
Set a parameter value.
void setParamValUnique(std::string const &paramdescriptor, T const &val)
Set a parameter value, simple version assuming only one parameter match.
std::string const & className() const
The class name of this component.
Definition: Component.C:39
std::shared_ptr< Comp > addSubComponent(std::string const &instance, Args &&...args)
Pseudo-constructor: construct and add another component as a subcomponent of this one...
Definition: ComponentImpl.H:29
void setPath(std::string const &path)
Assign a filesystem path to this component.
Definition: Component.C:501
Manager of a hierarchy of Component objects.
Definition: Manager.H:73
void setParamStringUnique(std::string const &paramdescriptor, std::string const &val)
Set a parameter value by string, simple version assuming only one parameter match.
Definition: Component.C:374
T getParamValUnique(std::string const &paramdescriptor) const
Get a parameter value, simple version assuming only one parameter match.
void setParamsFromFile(std::string const &filename)
Set some parameters from a file.
Definition: Component.C:454
bool isTopLevel() const
Returns true if this component is top-level, i.e., its parent is jevois::Manager. ...
Definition: Component.C:119
void freezeParam(std::string const &paramdescriptor)
Freeze a parameter, by name, see ParameterBase::freeze()
Definition: Component.C:414
A component of a model hierarchy.
Definition: Component.H:178
bool initialized() const
Has this component been initialized yet?
Definition: Component.C:206
std::string getParamStringUnique(std::string const &paramdescriptor) const
Get a parameter value by string, simple version assuming only one parameter match.
Definition: Component.C:401
virtual void preUninit()
Called before all sub-Components are uninit()ed.
Definition: Component.H:470
Engine * engine() const
Get a handle to our Engine, or throw if we do not have an Engine as root ancestor.
Definition: Component.C:129
virtual ~Component()
Virtual destructor for safe inheritance.
Definition: Component.C:54
std::vector< std::pair< std::string, T > > getParamVal(std::string const &paramdescriptor) const
Get parameter(s) value(s) by descriptor.
std::string descriptor() const
Get our full descriptor (including all parents) as [Instancename]:[...]:[...].
Definition: Component.C:276
std::shared_ptr< Comp > getSubComponent(std::string const &instance) const
Get a sub-component by instance name.
Definition: ComponentImpl.H:62
void removeSubComponent(std::shared_ptr< Comp > &component)
Remove a sub-Component from this Component, by shared_ptr.
Base class for Parameter.
Definition: Parameter.H:121
Component(std::string const &instance)
Constructor.
Definition: Component.C:32
std::istream & setParamsFromStream(std::istream &is, std::string const &absfile)
Set some parameters from an open stream.
Definition: Component.C:463
virtual void paramInfo(std::shared_ptr< UserInterface > s, std::map< std::string, std::string > &categs, bool skipFrozen, std::string const &cname="", std::string const &pfx="")
Get machine-oriented descriptions of all parameters.
Definition: Component.C:533
virtual void postInit()
Called after all sub-Components are init()ed.
Definition: Component.H:467
std::vector< std::pair< std::string, std::string > > getParamString(std::string const &paramdescriptor) const
Get a parameter value, by string.
Definition: Component.C:385
void unFreezeParam(std::string const &paramdescriptor)
Unfreeze a parameter, by name, see ParameterBase::unFreeze()
Definition: Component.C:426
JeVois processing engine - gets images from camera sensor, processes them, and sends results over USB...
Definition: Engine.H:265
Virtual base class for a vision processing module.
Definition: Module.H:336
void freezeAllParams()
Freeze all parameters.
Definition: Component.C:438
A simple registry of all parameters associated with a Component.
void unFreezeAllParams()
Unfreeze all parameters.
Definition: Component.C:446
std::string const & instanceName() const
The instance name of this component.
Definition: Component.C:50
virtual void postUninit()
Called after all sub-Components are uninit()ed.
Definition: Component.H:473
std::string absolutePath(std::string const &path="")
If given path is relative (not starting with /), prepend the Component path to it.
Definition: Component.C:515