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