Quinoa all test code coverage report
Current view: top level - Base - Factory.hpp (source / functions) Hit Total Coverage
Commit: -128-NOTFOUND Lines: 14 14 100.0 %
Date: 2024-04-29 14:42:33 Functions: 93 93 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 12 28 42.9 %

           Branch data     Line data    Source code
       1                 :            : // *****************************************************************************
       2                 :            : /*!
       3                 :            :   \file      src/Base/Factory.hpp
       4                 :            :   \copyright 2012-2015 J. Bakosi,
       5                 :            :              2016-2018 Los Alamos National Security, LLC.,
       6                 :            :              2019-2021 Triad National Security, LLC.
       7                 :            :              All rights reserved. See the LICENSE file for details.
       8                 :            :   \brief     Factory utilities
       9                 :            :   \details   Factory utilities. The functions defined in this file help
      10                 :            :     interfacing with object factories. For a short introduction on what
      11                 :            :     factories are good for, see
      12                 :            :     http://www.boost.org/doc/libs/release/libs/functional/factory.
      13                 :            : */
      14                 :            : // *****************************************************************************
      15                 :            : #ifndef Factory_h
      16                 :            : #define Factory_h
      17                 :            : 
      18                 :            : #include <functional>
      19                 :            : 
      20                 :            : #include "NoWarning/factory.hpp"
      21                 :            : #include "NoWarning/value_factory.hpp"
      22                 :            : 
      23                 :            : #include "Exception.hpp"
      24                 :            : 
      25                 :            : namespace tk {
      26                 :            : 
      27                 :            : //! Register class into factory with given key. This is used to register a
      28                 :            : //! derived-class object's constructor (deriving from some base class) to a
      29                 :            : //! factory. The factory itself is a std::map< key, std::function< Child*() > >,
      30                 :            : //! i.e., an associative container, associating some key to a std::function
      31                 :            : //! object holding a pointer of Child's base class constructor. The constructor
      32                 :            : //! and its bound arguments are stored via boost::factory, which, in this
      33                 :            : //! use-case, yields the correct function object of type Base constructor pointer
      34                 :            : //! and thus facilitates runtime polymorphism. This function works in conjunction
      35                 :            : //! with boost::factory, i.e., uses reference semantics (works with storing
      36                 :            : //! pointers of objects). For a simple example on how to use this function, see
      37                 :            : //! tests/unit/Base/Factory.h.
      38                 :            : //! \param[in] f Factory to register to (std::map with value using reference
      39                 :            : //!   semantics)
      40                 :            : //! \param[in] key Key used to identify the entry in the factory
      41                 :            : //! \param[in] args Variable number of arguments to pass to the constructor
      42                 :            : //!   being registered. Note that the constructor arguments are only bound to
      43                 :            : //!   the constructor and stored in the factory (an std::map with value using
      44                 :            : //!   reference semantics). The object is not instantiated here, i.e., the
      45                 :            : //!   constructor is not called here. The object can be instantiated by function
      46                 :            : //!   instantiate. \see instantiate
      47                 :            : template< class C, class Key, class Factory, typename... ConstructorArgs >
      48                 :            : void record( Factory& f, const Key& key, ConstructorArgs&&... args ) {
      49 [ +  - ][ +  - ]:          3 :   f.emplace( key,
         [ +  - ][ +  - ]
      50                 :            :              std::bind( boost::factory< C* >(),
      51                 :            :                         std::forward< ConstructorArgs >( args )... ) );
      52                 :            : }
      53                 :            : 
      54                 :            : //! Instantiate object from factory. Factory must have a mapped_value which must
      55                 :            : //! have a result_type ptr, e.g., std::map< Key, std::function< Obj*() > >. This
      56                 :            : //! wrapper function can be used to instantiate an derived-class object from a
      57                 :            : //! factory, repeatedly filled with wrapper function 'record' above. The
      58                 :            : //! factory, as described in the documentation of 'record', stores base class
      59                 :            : //! pointers in an associative container, thereby facilitating runtime
      60                 :            : //! polymorphism and a simple lookup-and-instantiate-style object creation. The
      61                 :            : //! object instantiated is of type Child class. This function works in
      62                 :            : //! conjunction with boost::factory, i.e., uses reference semantics (works with
      63                 :            : //! storing pointers of objects). For a simple example on how to
      64                 :            : //! use this function, see tests/unit//Base/Factory.h.
      65                 :            : //! \param[in] f Factory to instantiate object from (std::map with value using
      66                 :            : //!   reference semantics)
      67                 :            : //! \param[in] key Key used to identify the object to instantiate from factory
      68                 :            : //! \return std::unique_ptr pointing to the object instantiated from factory
      69                 :            : //! \see record
      70                 :            : template< class Factory, class Key,
      71                 :            :           class Obj = typename std::remove_pointer<
      72                 :            :                         typename Factory::mapped_type::result_type >::type >
      73                 :          2 : std::unique_ptr< Obj > instantiate( const Factory& f, const Key& key ) {
      74                 :            :   const auto it = f.find( key );
      75                 :            :   Assert( it != end( f ), "No such object registered in factory" );
      76                 :          2 :   return std::unique_ptr< Obj >( it->second() );
      77                 :            : }
      78                 :            : 
      79                 :            : //! Register "model" class of "host" into factory with given key. This wrapper
      80                 :            : //! can be used to in a similar manner to 'record', but uses
      81                 :            : //! boost::value_factory to bind the model object constructor to its arguments
      82                 :            : //! and place it in the associative container storing host class objects. The
      83                 :            : //! container is thus of type std::map< key, std::function< T() > >, i.e.,
      84                 :            : //! associating a key to a function holding a constructor (and not its
      85                 :            : //! pointer). Runtime polymorphism here is realized entirely within the "base"
      86                 :            : //! class. See walker::DiffEq in DiffEq/DiffEq.h for an example and more
      87                 :            : //! information on runtime polymorphism without client-side inheritance. As a
      88                 :            : //! result, this wrapper works with factories that use value semantics, as opposed
      89                 :            : //! to 'record' and instantiate which work with reference semantics factories.
      90                 :            : //! In order to differentiate between runtime polymorphic classes using
      91                 :            : //! reference semantics, consistent with classes realizing runtime polymorphism
      92                 :            : //! without client-side inheritance, we call Host as the "Base" class and Model
      93                 :            : //! as the "derived" (or child) class. This wrapper function works in
      94                 :            : //! conjunction with boost::value_factory, i.e., uses value semantics (works
      95                 :            : //! with storing objects instead of object pointers). For a simple example on
      96                 :            : //! how to use this function, see tests/unit//Base/Factory.h.
      97                 :            : //! \param[in] f Factory to register to (std::map with value using value
      98                 :            : //!   semantics)
      99                 :            : //! \param[in] key Key used to identify the entry in the factory
     100                 :            : //! \param[in] args Variable number of arguments to pass to the constructor
     101                 :            : //!   being registered. Note that the constructor arguments are only bound to
     102                 :            : //!   the constructor and stored in the factory (an std::map with value using
     103                 :            : //!   value semantics). The object is not instantiated here, i.e., the
     104                 :            : //!   constructor is not called here. The object can be instantiated by simply
     105                 :            : //!   calling the function call operator () on the mapped value. For an example,
     106                 :            : //!   RNGStack::selected() in RNG/RNGStack.C.
     107                 :            : template< class Host, class ModelConstructor, class Factory, class Key,
     108                 :            :           typename... ModelConstrArgs >
     109                 :          2 : void recordModel( Factory& f, const Key& key, ModelConstrArgs&&... args ) {
     110                 :            :   // Bind model constructor to its arguments
     111         [ +  - ]:          2 :   std::function< ModelConstructor() > c =
     112                 :            :     std::bind( boost::value_factory< ModelConstructor >(),
     113                 :            :                std::forward< ModelConstrArgs >( args )... );
     114                 :            :   // Bind host to std::function of model constructor and place in factory
     115 [ -  + ][ -  - ]:          2 :   f.emplace( key, std::bind( boost::value_factory< Host >(), std::move(c) ) );
     116                 :          2 : }
     117                 :            : 
     118                 :            : //! Register model class of host into factory with given key using late binding.
     119                 :            : //! This variant of 'record' is very similar to 'recordModel', but registers a
     120                 :            : //! model class constructor to a factory with late binding of the constructor
     121                 :            : //! argument. Late binding allows specifying the constructor argument at the
     122                 :            : //! time when the object is instantiated instead of at the time when it is
     123                 :            : //! registered. This has all the benefits of using a factory and allows passing
     124                 :            : //! information into the model object only when it is available. The late bind
     125                 :            : //! is facilitated via std::bind instead of std::bind using a placeholder,
     126                 :            : //! _1, which stands for the first argument (bound later, i.e., not here). The
     127                 :            : //! value of the model constructor argument is then not used here, only its
     128                 :            : //! type, used to perform the late binding. The binding happens to both the
     129                 :            : //! model constructor via std::function (passed to the host constructor) as well
     130                 :            : //! as explicitly to the host constructor. Prescribing late binding to the model
     131                 :            : //! constructor ensures that the compiler requires the argument to the model
     132                 :            : //! constructor, i.e., ensures that the host constructor is required to pass the
     133                 :            : //! argument to the model constructor. Prescribing late binding to the host
     134                 :            : //! constructor puts in the actual request that an argument (with the correct
     135                 :            : //! type) must be passed to the host constructor at instantiate time, which then
     136                 :            : //! will forward it to the model constructor. See also, for example,
     137                 :            : //! walker::DiffEq's corresponding constructor. An example of client-side code
     138                 :            : //! is in walker::DiffEqStack::registerDiffEq for registration into factory, and
     139                 :            : //! DiffEqStack::createDiffEq for instantiation late-passing the argument.
     140                 :            : //! \param[in] f Factory to register to (std::map with value using value
     141                 :            : //!   semantics)
     142                 :            : //! \param[in] key Key used to identify the entry in the factory
     143                 :            : //! \warning Only works with a single constructor argument
     144                 :            : template< class Host, class ModelConstructor, class Factory, class Key >
     145                 :     205920 : void recordModelLate( Factory& f, const Key& key ) {
     146                 :            :   // Prescribe late binding the model constructor to its single argument
     147         [ +  - ]:     205920 :   std::function< ModelConstructor() > c =
     148                 :            :     std::bind( boost::value_factory< ModelConstructor >() );
     149                 :            :   // Bind host to std::function of model constructor and place in factory and
     150                 :            :   // also explicitly bind single model constructor argument to host constructor
     151 [ -  + ][ -  - ]:     205920 :   f.emplace( key, std::bind( boost::value_factory< Host >(), std::move(c) ) );
     152                 :     205920 : }
     153                 :            : 
     154                 :            : //! Register Charm++ model class of host into factory with given key. We bind a
     155                 :            : //! host constructor to its arguments of which the first one is a std::function
     156                 :            : //! holding a model constructor type (modeling, i.e., used polymorhically with
     157                 :            : //! host), followed by an optional number of others (possibly zero) with
     158                 :            : //! arbitrary types. Note that the model constructor is a nullptr (default-
     159                 :            : //! constructed) and only used to forward its type to the call site inside
     160                 :            : //! std::function. The host constructor function is then placed into the
     161                 :            : //! factory. This is because Charm++ chares do not explicitly invoke
     162                 :            : //! constructors, only call ckNew() on their proxy, which requires all
     163                 :            : //! constructor arguments to be present and forwarded to the actual constructor
     164                 :            : //! that is only called at a later point in time. This can then be used by those
     165                 :            : //! constructors of hosts that invoke the model constructors' proxies' ckNew()
     166                 :            : //! and ignore the std::function. See, e.g., rngtest::Battery() and the
     167                 :            : //! associated unit tests in tests/unit//Base/Factory.h.
     168                 :            : //! \param[in] f Factory to register to (std::map with value using value
     169                 :            : //!   semantics)
     170                 :            : //! \param[in] key Key used to identify the entry in the factory
     171                 :            : //! \param[in] args Variable number of arguments to pass to the constructor
     172                 :            : //!   being registered.
     173                 :            : template< class Host, class ModelConstructor, class Factory, class Key,
     174                 :            :           typename... ModelConstrArgs >
     175         [ +  - ]:          2 : void recordCharmModel( Factory& f, const Key& key, ModelConstrArgs&&... args ) {
     176 [ +  + ][ -  + ]:          3 :   f.emplace( key, std::bind( boost::value_factory< Host >(),
                 [ -  - ]
     177                 :            :                              std::function< ModelConstructor() >(), // nullptr
     178                 :            :                              std::forward< ModelConstrArgs >( args )...) );
     179                 :          2 : }
     180                 :            : 
     181                 :            : } // tk::
     182                 :            : 
     183                 :            : #endif // Factory_h

Generated by: LCOV version 1.14