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