Branch data Line data Source code
1 : : // ***************************************************************************** 2 : : /*! 3 : : \file src/RNGTest/Battery.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 Random number generator test harness 9 : : \details This file defines a generic random number generator test harness 10 : : class. The class uses runtime polymorphism without client-side inheritance: 11 : : inheritance is confined to the internals of the class, invisible to 12 : : client-code. The class exclusively deals with ownership enabling client-side 13 : : value semantics. Credit goes to Sean Parent at Adobe: 14 : : https://github.com/sean-parent/ 15 : : sean-parent.github.com/wiki/Papers-and-Presentations. 16 : : */ 17 : : // ***************************************************************************** 18 : : #ifndef Battery_h 19 : : #define Battery_h 20 : : 21 : : #include <functional> 22 : : #include <memory> 23 : : 24 : : #include "NoWarning/charm++.hpp" 25 : : 26 : : #include "Macro.hpp" 27 : : #include "Has.hpp" 28 : : 29 : : namespace rngtest { 30 : : 31 : : //! \brief Battery 32 : : //! \details This class uses runtime polymorphism without client-side 33 : : //! inheritance: inheritance is confined to the internals of the this class, 34 : : //! invisible to client-code. The class exclusively deals with ownership 35 : : //! enabling client-side value semantics. Credit goes to Sean Parent at Adobe: 36 : : //! https://github.com/sean-parent/sean-parent.github.com/wiki/ 37 : : //! Papers-and-Presentations. For example client code that models a Battery, 38 : : //! see rngtest::TestU01Suite. 39 : : class Battery { 40 : : 41 : : public: 42 : : //! \brief Constructor taking a function pointer to a constructor of an 43 : : //! object modeling Concept 44 : : //! \details Passing std::function allows late execution of the constructor 45 : : //! of T, i.e., at some future time, and thus usage from a factory. Note 46 : : //! that the value of the first function argument, std::function<T()>, is 47 : : //! not used here, but its constructor type, T, is used to enable the 48 : : //! compiler to deduce the model constructor type, used to create its 49 : : //! Charm proxy, defined by T::Proxy. The actual constructor of T is not 50 : : //! called here but at some future time by the Charm++ runtime system, 51 : : //! here only an asynchrounous ckNew() is called, i.e., a message (or 52 : : //! request) for a future call to T's constructor. This overload is only 53 : : //! enabled for Charm++ chare objects defining typedef 'Proxy', which must 54 : : //! define the Charm++ proxy. All optional constructor arguments are 55 : : //! forwarded to ckNew() and thus to T's constructor. If it was somehow 56 : : //! possible to obtain all bound arguments' types and values from an 57 : : //! already-bound std::function, we could use those instead of having to 58 : : //! explicitly forward the model constructor arguments via this host 59 : : //! constructor. 60 : : //! \param[in] c Function pointer to a constructor of an object modeling 61 : : //! Concept. 62 : : //! \param[in] args Constructor arguments 63 : : //! \see See also tk::recordCharmModel(). 64 : : template< typename T, typename... CtrArgs > 65 : 4 : explicit Battery( std::function<T()> c [[maybe_unused]], CtrArgs... args ) : 66 : : self( std::make_unique< Model< typename T::Proxy > > 67 [ + - ]: 4 : (std::move(T::Proxy::ckNew(std::forward<CtrArgs>(args)...))) ) { 68 [ - + ][ - - ]: 4 : Assert( c == nullptr, "std::function argument to Battery Charm++ " [ - - ][ - - ] 69 : : "constructor must be nullptr" ); 70 : 4 : } 71 : : 72 : : //! Public interface to evaluating a statistical test 73 : : void evaluate( std::vector< std::vector< std::string > > status ) const 74 : : { self->evaluate( status ); } 75 : : 76 : : //! Public interface to collecting the number of statistics from a test 77 : : void npval( std::size_t n ) const { self->npval( n ); } 78 : : 79 : : //! Public interface to collecting test name(s) from a test 80 : : void names( std::vector< std::string > n ) const { self->names( n ); } 81 : : 82 : : //! Copy assignment 83 : : Battery& operator=( const Battery& x ) 84 : : { Battery tmp(x); *this = std::move(tmp); return *this; } 85 : : //! Copy constructor 86 : : Battery( const Battery& x ) : self( x.self->copy() ) {} 87 : : //! Move assignment 88 : : Battery& operator=( Battery&& ) noexcept = default; 89 : : //! Move constructor 90 : : Battery( Battery&& ) noexcept = default; 91 : : 92 : : private: 93 : : //! Concept is a pure virtual base class specifying the requirements of 94 : : //! polymorphic objects deriving from it 95 : : struct Concept { 96 : 4 : Concept() = default; 97 : 0 : Concept( const Concept& ) = default; 98 : 4 : virtual ~Concept() = default; 99 : : virtual Concept* copy() const = 0; 100 : : virtual void evaluate( std::vector< std::vector< std::string > > 101 : : status ) = 0; 102 : : virtual void npval( std::size_t n ) = 0; 103 : : virtual void names( std::vector< std::string > n ) = 0; 104 : : }; 105 : : 106 : : //! Model models the Concept above by deriving from it and overriding the 107 : : //! the virtual functions required by Concept 108 : : template< typename T > 109 : : struct Model : Concept { 110 [ + - ]: 4 : Model( T x ) : data( std::move(x) ) {} 111 [ - - ]: 0 : Concept* copy() const override { return new Model( *this ); } 112 : 0 : void evaluate( std::vector< std::vector< std::string > > status ) 113 : 0 : override { data.evaluate( status ); } 114 : 0 : void npval( std::size_t n ) override { data.npval( n ); } 115 : 0 : void names( std::vector< std::string > n ) override { data.names( n ); } 116 : : T data; 117 : : }; 118 : : 119 : : std::unique_ptr< Concept > self; //!< Base pointer used polymorphically 120 : : }; 121 : : 122 : : } // rngtest:: 123 : : 124 : : #endif // Battery_h