From 95cf462869d9105be4774e03b7d43f30331ba2f2 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Thu, 27 Apr 2017 16:31:22 -0700 Subject: [PATCH 001/521] Signals and slots upgraded for C++11 --- Library/Application/KTDataQueueProcessor.hh | 2 +- Library/Application/KTPrintDataStructure.hh | 6 +- Library/CMakeLists.txt | 1 - Library/Processor/KTProcessor.hh | 51 +-- Library/Processor/KTSignal.cc | 52 --- Library/Processor/KTSignal.hh | 145 ++----- Library/Processor/KTSignalWrapper.hh | 2 +- Library/Processor/KTSlot.hh | 421 +++++++------------- Library/Processor/KTSlotWrapper.hh | 14 +- 9 files changed, 188 insertions(+), 506 deletions(-) delete mode 100644 Library/Processor/KTSignal.cc diff --git a/Library/Application/KTDataQueueProcessor.hh b/Library/Application/KTDataQueueProcessor.hh index 05376e9..f07e92b 100644 --- a/Library/Application/KTDataQueueProcessor.hh +++ b/Library/Application/KTDataQueueProcessor.hh @@ -129,7 +129,7 @@ namespace Nymph // Signals //********* protected: - KTSignalOneArg< void > fQueueDoneSignal; + KTSignalDone fQueueDoneSignal; }; diff --git a/Library/Application/KTPrintDataStructure.hh b/Library/Application/KTPrintDataStructure.hh index 72b7026..5d6eec4 100644 --- a/Library/Application/KTPrintDataStructure.hh +++ b/Library/Application/KTPrintDataStructure.hh @@ -72,9 +72,9 @@ namespace Nymph //*************** private: - KTSlotOneArg< void (KTDataPtr) > fDataStructSlot; - KTSlotOneArg< void (KTDataPtr) > fCutStructSlot; - KTSlotOneArg< void (KTDataPtr) > fDataAndCutStructSlot; + KTSlotOneArg< void, KTDataPtr > fDataStructSlot; + KTSlotOneArg< void, KTDataPtr > fCutStructSlot; + KTSlotOneArg< void, KTDataPtr > fDataAndCutStructSlot; }; } diff --git a/Library/CMakeLists.txt b/Library/CMakeLists.txt index c7d0c0d..ad41bec 100644 --- a/Library/CMakeLists.txt +++ b/Library/CMakeLists.txt @@ -64,7 +64,6 @@ set( NYMPH_SOURCEFILES ${DATA_DIR}/KTData.cc ${PROC_DIR}/KTPrimaryProcessor.cc ${PROC_DIR}/KTProcessor.cc - ${PROC_DIR}/KTSignal.cc ${PROC_DIR}/KTSignalWrapper.cc ${PROC_DIR}/KTSlotWrapper.cc ${IO_DIR}/KTReader.cc diff --git a/Library/Processor/KTProcessor.hh b/Library/Processor/KTProcessor.hh index 7aa8e6c..21ba7ee 100644 --- a/Library/Processor/KTProcessor.hh +++ b/Library/Processor/KTProcessor.hh @@ -18,8 +18,6 @@ #include "factory.hh" -#include -#include #include #include @@ -61,14 +59,8 @@ namespace Nymph template< class XProcessor > void RegisterSignal(std::string name, XProcessor* signalPtr); - template< class XTarget, typename XReturn > - void RegisterSlot(std::string name, XTarget* target, XReturn (XTarget::* funcPtr)()); - - template< class XTarget, typename XReturn, typename XArg1 > - void RegisterSlot(std::string name, XTarget* target, XReturn (XTarget::* funcPtr)(XArg1)); - - template< class XTarget, typename XReturn, typename XArg1, typename XArg2 > - void RegisterSlot(std::string name, XTarget* target, XReturn (XTarget::* funcPtr)(XArg1, XArg2)); + template< class XTarget, typename XReturn, typename... XArgs > + void RegisterSlot(std::string name, XTarget* target, XReturn (XTarget::* funcPtr)(XArgs...)); KTSignalWrapper* GetSignal(const std::string& name); @@ -92,49 +84,18 @@ namespace Nymph return; } - template< class XTarget, typename XReturn > - void KTProcessor::RegisterSlot(std::string name, XTarget* target, XReturn (XTarget::* funcPtr)()) - { - KTDEBUG(processorlog, "Registering slot <" << name << "> in processor <" << fConfigName << ">"); - - KTSignalConcept< XReturn () > signalConcept; - - boost::function< XReturn () > *func = new boost::function< XReturn () >(boost::bind(funcPtr, target)); - - KTSlotWrapper* slot = new KTSlotWrapper(func, &signalConcept); - fSlotMap.insert(SlotMapVal(name, slot)); - return; - } - - template< class XTarget, typename XReturn, typename XArg1 > - void KTProcessor::RegisterSlot(std::string name, XTarget* target, XReturn (XTarget::* funcPtr)(XArg1)) + template< class XTarget, typename XReturn, typename... XArgs > + void KTProcessor::RegisterSlot(std::string name, XTarget* target, XReturn (XTarget::* funcPtr)(XArgs...)) { KTDEBUG(processorlog, "Registering slot <" << name << "> in processor <" << fConfigName << ">"); - KTSignalConcept< XReturn (XArg1) > signalConcept; + KTSignalConcept< XReturn (XArgs...) > signalConcept; - boost::function< XReturn (XArg1) > *func = new boost::function< XReturn (XArg1) >(boost::bind(funcPtr, target, _1)); - - KTSlotWrapper* slot = new KTSlotWrapper(func, &signalConcept); + KTSlotWrapper* slot = new KTSlotWrapper([funcPtr, target](XArgs... args){return (target->*funcPtr)(args...);}, &signalConcept); fSlotMap.insert(SlotMapVal(name, slot)); return; } - template< class XTarget, typename XReturn, typename XArg1, typename XArg2 > - void KTProcessor::RegisterSlot(std::string name, XTarget* target, XReturn (XTarget::* funcPtr)(XArg1, XArg2)) - { - KTDEBUG(processorlog, "Registering slot <" << name << "> in processor <" << fConfigName << ">"); - - KTSignalConcept< XReturn (XArg1, XArg2) > signalConcept; - - boost::function< XReturn (XArg1, XArg2) > *func = new boost::function< XReturn (XArg1, XArg2) >(boost::bind(funcPtr, target, _1, _2)); - - KTSlotWrapper* slot = new KTSlotWrapper(func, &signalConcept); - fSlotMap.insert(SlotMapVal(name, slot)); - return; - } - - #define KT_REGISTER_PROCESSOR(proc_class, proc_name) \ static ::scarab::registrar< ::Nymph::KTProcessor, proc_class, const std::string& > sProc##proc_class##Registrar( proc_name ); diff --git a/Library/Processor/KTSignal.cc b/Library/Processor/KTSignal.cc deleted file mode 100644 index 535ab2d..0000000 --- a/Library/Processor/KTSignal.cc +++ /dev/null @@ -1,52 +0,0 @@ -/* - * KTSignal.cc - * - * Created on: Feb 25, 2013 - * Author: nsoblath - */ - -#include "KTSignal.hh" - -namespace Nymph -{ - - KTSignalOneArg< void >::KTSignalOneArg(const std::string& name, KTProcessor* proc) : - fSignal() - { - proc->RegisterSignal(name, &fSignal); - } - - KTSignalOneArg< void >::KTSignalOneArg() : - fSignal() - {} - - KTSignalOneArg< void >::KTSignalOneArg(const KTSignalOneArg&) : - fSignal() - {} - - KTSignalOneArg< void >::~KTSignalOneArg() - { - } - - - - KTSignalData::KTSignalData(const std::string& name, KTProcessor* proc) : - KTSignalOneArg(name, proc), - fRefSignal() - { - proc->RegisterSignal("ref-"+name, &fRefSignal); - } - - KTSignalData::~KTSignalData() - { - } - - KTSignalData::KTSignalData() - { - } - - KTSignalData::KTSignalData(const KTSignalData&) - { - } - -} diff --git a/Library/Processor/KTSignal.hh b/Library/Processor/KTSignal.hh index 5a5b3cb..11130c9 100644 --- a/Library/Processor/KTSignal.hh +++ b/Library/Processor/KTSignal.hh @@ -19,83 +19,53 @@ namespace Nymph { /*! - @class KTSignalOneArg + @class KTSignal @author N. S. Oblath - @brief Creates a signal that takes a single argument. + @brief Creates a signal that takes 0 or more arguments. @details The signal is emitted by calling operator(). - If a KTDataSlot is being used, and the Slot has been given a pointer to this signal, the Slot will emit the Signal. + If a KTSlot is being used, and the Slot has been given a pointer to this signal, the Slot will emit the Signal. Usage: - In your Processor's header add a member variable of type KTDataSignal< ArgumentType >. + In your Processor's header add a member variable of type KTSignal< ArgumentTypes >. Initialize the signal with the processor's 'this' pointer and the name of the signal. To use the signal, call it as: fSignalObject(arg); */ - template< class XSignalArgument > - class KTSignalOneArg - { - public: - typedef void (signature)(XSignalArgument); - typedef boost::signals2::signal< signature > boost_signal; - typedef typename boost::signals2::signal< signature >::slot_type slot_type; - - public: - KTSignalOneArg(); - KTSignalOneArg(const std::string& name, KTProcessor* proc); - virtual ~KTSignalOneArg(); - - protected: - KTSignalOneArg(const KTSignalOneArg&); - - public: - void operator()(XSignalArgument arg); - - boost_signal* Signal(); - - protected: - boost_signal fSignal; - - }; - - - template<> - class KTSignalOneArg< void > + template< class... XSignalArguments > + class KTSignal { public: - typedef void (signature)(void); + typedef void (signature)( XSignalArguments... ); typedef boost::signals2::signal< signature > boost_signal; - // the following line is, technically, not valid C++03 code because the 'typename' keyword - // is appearing outside of a template (since the template here is fully specified, this counts). - // It should compiler with most new-ish compilers, even when compiling under C++03 mode. - // It has been tested successfully with GCC 4.6 and Clang 3.1 typedef typename boost::signals2::signal< signature >::slot_type slot_type; public: - KTSignalOneArg(); - KTSignalOneArg(const std::string& name, KTProcessor* proc); - virtual ~KTSignalOneArg(); + KTSignal(); + KTSignal( const std::string& name, KTProcessor* proc ); + virtual ~KTSignal(); protected: - KTSignalOneArg(const KTSignalOneArg&); + KTSignal( const KTSignal& ); public: - void operator()(); + void operator()( XSignalArguments... args ); boost_signal* Signal(); protected: boost_signal fSignal; - }; - // convenience typedef for KTSignalDone - typedef KTSignalOneArg KTSignalDone; - + /// Convenience typedef for done signals + typedef KTSignal<> KTSignalDone; + // Convenience typedef for backwards compatibility + template< typename XDataType > + using KTSignalOneArg = KTSignal< XDataType >; /*! @class KTSignalData @@ -115,93 +85,46 @@ namespace Nymph That's it! */ + typedef KTSignal< KTDataPtr > KTSignalData; - class KTSignalData : public KTSignalOneArg< KTDataPtr > - { - public: - typedef void (signature)(KTDataPtr); - typedef boost::signals2::signal< signature > boost_signal; - typedef boost::signals2::signal< signature >::slot_type slot_type; - - typedef void (ref_signature)(KTDataPtr&); - typedef boost::signals2::signal< ref_signature > ref_boost_signal; - typedef boost::signals2::signal< ref_signature >::slot_type ref_slot_type; - public: - KTSignalData(); - KTSignalData(const std::string& name, KTProcessor* proc); - virtual ~KTSignalData(); - - protected: - KTSignalData(const KTSignalData&); + //******************* + // Implementations + //******************* - public: - void operator()(KTDataPtr arg); - - ref_boost_signal* RefSignal(); - - protected: - ref_boost_signal fRefSignal; - }; - - - - template< class XSignalArgument > - KTSignalOneArg< XSignalArgument >::KTSignalOneArg(const std::string& name, KTProcessor* proc) : + template< class... XSignalArguments > + KTSignal< XSignalArguments... >::KTSignal( const std::string& name, KTProcessor* proc ) : fSignal() { proc->RegisterSignal(name, &fSignal); } - template< class XSignalArgument > - KTSignalOneArg< XSignalArgument >::KTSignalOneArg() : + template< class... XSignalArguments > + KTSignal< XSignalArguments... >::KTSignal() : fSignal() {} - template< class XSignalArgument > - KTSignalOneArg< XSignalArgument >::KTSignalOneArg(const KTSignalOneArg&) : + template< class... XSignalArguments > + KTSignal< XSignalArguments... >::KTSignal( const KTSignal& ) : fSignal() {} - template< class XSignalArgument > - KTSignalOneArg< XSignalArgument >::~KTSignalOneArg() - { - } - - template< class XSignalArgument > - inline void KTSignalOneArg< XSignalArgument >::operator()(XSignalArgument arg) + template< class... XSignalArguments > + KTSignal< XSignalArguments... >::~KTSignal() { - fSignal(arg); } - template< class XSignalArgument > - inline typename KTSignalOneArg< XSignalArgument >::boost_signal* KTSignalOneArg< XSignalArgument >::Signal() + template< class... XSignalArguments > + inline void KTSignal< XSignalArguments... >::operator()( XSignalArguments... args ) { - return &fSignal; + fSignal( args... ); } - - inline void KTSignalOneArg< void >::operator()() - { - fSignal(); - } - - inline typename KTSignalOneArg< void >::boost_signal* KTSignalOneArg< void >::Signal() + template< class... XSignalArguments > + inline typename KTSignal< XSignalArguments... >::boost_signal* KTSignal< XSignalArguments... >::Signal() { return &fSignal; } - - inline void KTSignalData::operator()(KTDataPtr arg) - { - fSignal(arg); - fRefSignal(arg); - } - - inline typename KTSignalData::ref_boost_signal* KTSignalData::RefSignal() - { - return &fRefSignal; - } - } /* namespace Nymph */ #endif /* KTSIGNAL_HH_ */ diff --git a/Library/Processor/KTSignalWrapper.hh b/Library/Processor/KTSignalWrapper.hh index 4b0382e..22ed542 100644 --- a/Library/Processor/KTSignalWrapper.hh +++ b/Library/Processor/KTSignalWrapper.hh @@ -55,7 +55,7 @@ namespace Nymph return fSignal; } private: - XSignature* fSignal; //not owned by this KTSignalWrapper + XSignature* fSignal; //not owned by this KTSpecifiedInternalSignalWrapper }; public: diff --git a/Library/Processor/KTSlot.hh b/Library/Processor/KTSlot.hh index 116ec31..7dc21bd 100644 --- a/Library/Processor/KTSlot.hh +++ b/Library/Processor/KTSlot.hh @@ -12,212 +12,162 @@ #include "KTLogger.hh" #include "KTSignal.hh" -#include -#include - +#include +#include #include namespace Nymph { KTLOGGER(slotlog, "KTSlot"); - template< typename Signature> - class KTSlotNoArg - { - public: - typedef boost::function< Signature > function_signature; - typedef typename function_signature::result_type return_type; - - public: - /// Constructor for the case where the processor has the function that will be called by the slot - template< class XFuncOwnerType > - KTSlotNoArg(const std::string& name, XFuncOwnerType* owner, return_type (XFuncOwnerType::*func)()); - /// Constructor for the case where the processor and the object with the function that will be called are different - template< class XFuncOwnerType > - KTSlotNoArg(const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, return_type (XFuncOwnerType::*func)()); - virtual ~KTSlotNoArg(); - - return_type operator()(); - - protected: - boost::function< Signature > fFunc; - - }; - /*! - @class KTSlotOneArg + @class KTSlot @author N. S. Oblath - @brief Creates a slot that calls a member function of the func_owner_type object, taking one argument. + @brief Creates a slot that calls a member function of the func_owner_type object, taking 0 or more arguments. @details Usage: To use this slot type the function to be called by the slot must exist in an object of type FuncOwnerType. - The function should have the signature ReturnType (ArgumentType). + The function should have the signature ReturnType (Args). - In your Processor's header add a member variable of type KTSlotOneArg< ProcessorType, ArgumentType, ReturnType >. + In your Processor's header add a member variable of type KTSlot< ProcessorType, ReturnType, Args >. The variable may be private. Initialize the slot with the name of the slot, the address of the owner of the slot function, and the function pointer. Optionally, if the Processor is separate from the owner of the slot function, the Processor address is specified as the second argument to the constructor. */ - template< typename Signature> - class KTSlotOneArg + template< typename ReturnType, typename... Args > + class KTSlot { - public: - typedef boost::function< Signature > function_signature; - typedef typename function_signature::result_type return_type; - typedef typename function_signature::argument_type argument_type; - public: /// Constructor for the case where the processor has the function that will be called by the slot template< class XFuncOwnerType > - KTSlotOneArg(const std::string& name, XFuncOwnerType* owner, return_type (XFuncOwnerType::*func)(argument_type)); - /// Constructor for the case where the processor and the object with the function that will be called are different - template< class XFuncOwnerType > - KTSlotOneArg(const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, return_type (XFuncOwnerType::*func)(argument_type)); - virtual ~KTSlotOneArg(); - - return_type operator()(argument_type arg); + KTSlot( const std::string& name, XFuncOwnerType* owner, ReturnType (XFuncOwnerType::*func)( Args... ) ); - protected: - boost::function< Signature > fFunc; - - }; - - template< typename Signature> - class KTSlotTwoArg - { - public: - typedef boost::function< Signature > function_signature; - typedef typename function_signature::result_type return_type; - typedef typename function_signature::first_argument_type first_argument_type; - typedef typename function_signature::second_argument_type second_argument_type; - - public: - /// Constructor for the case where the processor has the function that will be called by the slot - template< class XFuncOwnerType > - KTSlotTwoArg(const std::string& name, XFuncOwnerType* owner, return_type (XFuncOwnerType::*func)(first_argument_type, second_argument_type)); /// Constructor for the case where the processor and the object with the function that will be called are different template< class XFuncOwnerType > - KTSlotTwoArg(const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, return_type (XFuncOwnerType::*func)(first_argument_type, second_argument_type)); - virtual ~KTSlotTwoArg(); - - return_type operator()(first_argument_type arg1, second_argument_type arg2); + KTSlot( const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, ReturnType (XFuncOwnerType::*func)( Args... ) ); - protected: - boost::function< Signature > fFunc; + virtual ~KTSlot(); }; + // Typedefs for backwards compatibility + template < typename ReturnType > + using KTSlotNoArg = KTSlot< ReturnType >; - template< typename Signature> - template< class XFuncOwnerType > - KTSlotNoArg< Signature >::KTSlotNoArg(const std::string& name, XFuncOwnerType* owner, return_type (XFuncOwnerType::*func)()) : - fFunc(boost::bind(func, owner)) - { - owner->RegisterSlot(name, this, &KTSlotNoArg::operator()); - } + template < typename ReturnType, typename Arg1 > + using KTSlotOneArg = KTSlot< ReturnType, Arg1 >; - template< typename Signature> - template< class XFuncOwnerType > - KTSlotNoArg< Signature >::KTSlotNoArg(const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, return_type (XFuncOwnerType::*func)()) : - fFunc(boost::bind(func, owner)) - { - proc->RegisterSlot(name, this, &KTSlotNoArg::operator()); - } + template< typename ReturnType, typename Arg1, typename Arg2 > + using KTSlotTwoArg = KTSlot< ReturnType, Arg1, Arg2 >; - template< typename Signature> - KTSlotNoArg< Signature >::~KTSlotNoArg() - { - } - template< typename Signature> - typename KTSlotNoArg< Signature >::return_type KTSlotNoArg< Signature >::operator()() - { - return fFunc(); - } + /*! + @class KTDataSlot + @author N. S. Oblath + @brief Creates a slot that takes a KTDataPtr object as the argument; the function that gets called should take 0 or more DataType&'s as its argument. + @details + Usage: + This slot type adds the slot function (signature void (KTDataPtr). + Your processor (or, optionally, a different object) must have a member function with the signature bool (DataType1&, . . .). + The slot function checks that the provided KTData object contains data of type DataType, and then calls the member function. + In your Processor's header add a member variable of type KTSlotOneArg< DataType >. + The variable may be private. - template< typename Signature> - template< class XFuncOwnerType > - KTSlotOneArg< Signature >::KTSlotOneArg(const std::string& name, XFuncOwnerType* owner, return_type (XFuncOwnerType::*func)(argument_type)) : - fFunc(boost::bind(func, owner, _1)) - { - owner->RegisterSlot(name, this, &KTSlotOneArg::operator()); - } + Initialize the slot with the name of the slot, the address of the owner of the slot function, and the function pointer. + Optionally, if the Processor is separate from the owner of the slot function, the Processor address is specified as the second argument to the constructor. - template< typename Signature> - template< class XFuncOwnerType > - KTSlotOneArg< Signature >::KTSlotOneArg(const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, return_type (XFuncOwnerType::*func)(argument_type)) : - fFunc(boost::bind(func, owner, _1)) + Also optionally, a signal to be emitted after the return of the member function can be specified as the last argument. + */ + template< class... XDataTypes > + class KTSlotData { - proc->RegisterSlot(name, this, &KTSlotOneArg::operator()); - } + //public: + //typedef XDataType data_type; + //typedef std::function< bool( KTDataPtr ) > function_signature; + //typedef typename function_signature::result_type return_type; - template< typename Signature> - KTSlotOneArg< Signature >::~KTSlotOneArg() - { - } + public: + /// Constructor for the case where the processor has the function that will be called by the slot + template< class XFuncOwnerType > + KTSlotData( const std::string& name, XFuncOwnerType* owner, bool (XFuncOwnerType::*func)( XDataTypes&... ), KTSignalData* signalPtr=nullptr ); - template< typename Signature> - typename KTSlotOneArg< Signature >::return_type KTSlotOneArg< Signature >::operator()(argument_type arg) - { - return fFunc(arg); - } + /// Constructor for the case where the processor and the object with the function that will be called are different + template< class XFuncOwnerType > + KTSlotData( const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, bool (XFuncOwnerType::*func)( XDataTypes&... ), KTSignalData* signalPtr=nullptr ); + virtual ~KTSlotData(); + void operator()( KTDataPtr data ); + protected: + template< typename... DataTypes > + bool DataPresent( KTDataPtr data ); + //template< > + //bool DataPresent( KTDataPtr data ); + //template< typename DataType, typename... DataTypes > + //bool DataPresent( KTDataPtr data ); - template< typename Signature> - template< class XFuncOwnerType > - KTSlotTwoArg< Signature >::KTSlotTwoArg(const std::string& name, XFuncOwnerType* owner, return_type (XFuncOwnerType::*func)(first_argument_type, second_argument_type)) : - fFunc(boost::bind(func, owner, _1, _2)) - { - owner->RegisterSlot(name, this, &KTSlotTwoArg::operator()); - } + //function_signature fFunc; + std::function< bool (XDataTypes&...) > fFunc; - template< typename Signature> - template< class XFuncOwnerType > - KTSlotTwoArg< Signature >::KTSlotTwoArg(const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, return_type (XFuncOwnerType::*func)(first_argument_type, second_argument_type)) : - fFunc(boost::bind(func, owner, _1, _2)) - { - proc->RegisterSlot(name, this, &KTSlotTwoArg::operator()); - } + KTSignalData* fSignalPtr; + }; - template< typename Signature> - KTSlotTwoArg< Signature >::~KTSlotTwoArg() + // helper structs (have to be defined outside the templated KTSlot class to use specialization + template< typename... DataTypes > + struct DataPresentHelper { - } + static bool DataPresent( KTDataPtr ) + { + return true; + } + }; - template< typename Signature> - typename KTSlotTwoArg< Signature >::return_type KTSlotTwoArg< Signature >::operator()(first_argument_type arg1, second_argument_type arg2) + template< typename DataType, typename... DataTypes > + struct DataPresentHelper< DataType, DataTypes... > { - return fFunc(arg1, arg2); - } + static bool DataPresent( KTDataPtr data ) + { + if( ! data->Has< DataType >() ) + { + KTERROR( slotlog, "Data not found with type <" << typeid( DataType ).name() << ">" ); + return false; + } + return DataPresentHelper< DataTypes... >::DataPresent( data ); + } + }; + // Typedefs for backwards compatibility + template< typename XDataType1 > + using KTSlotDataOneType = KTSlotData< XDataType1 >; + template< typename XDataType1, typename XDataType2 > + using KTSlotDataTwoTypes = KTSlotData< XDataType1, XDataType2 >; /*! - @class KTDataSlotOneArg + @class KTSlotDone @author N. S. Oblath - @brief Creates a slot that takes a KTDataPtr object as the argument; the function that gets called should take DataType& as its argument. + @brief Creates a slot to receive indication that upstream processing is complete and will emit a similar signal. @details Usage: - This slot type adds the slot function (signature void (KTDataPtr). - Your processor (or, optionally, a different object) must have a member function with the signature bool (DataType&). - The slot function checks that the provided KTData object contains data of type DataType, and then calls the member function. + This slot type adds the slot function (signature void ()). + Your processor (or, optionally, a different object) must have a member function with the signature void (). + The slot calls the member function. - In your Processor's header add a member variable of type KTSlotOneArg< DataType >. + In your Processor's header add a member variable of type KTDoneSlot. The variable may be private. Initialize the slot with the name of the slot, the address of the owner of the slot function, and the function pointer. @@ -225,155 +175,94 @@ namespace Nymph Also optionally, a signal to be emitted after the return of the member function can be specified as the last argument. */ - template< class XDataType > - class KTSlotDataOneType - { - public: - typedef XDataType data_type; - typedef boost::function< void (KTDataPtr) > function_signature; - typedef typename function_signature::result_type return_type; - typedef typename function_signature::argument_type argument_type; - - public: - /// Constructor for the case where the processor has the function that will be called by the slot - template< class XFuncOwnerType > - KTSlotDataOneType(const std::string& name, XFuncOwnerType* owner, bool (XFuncOwnerType::*func)(data_type&), KTSignalData* signalPtr=NULL); - /// Constructor for the case where the processor and the object with the function that will be called are different - template< class XFuncOwnerType > - KTSlotDataOneType(const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, bool (XFuncOwnerType::*func)(data_type&), KTSignalData* signalPtr=NULL); - virtual ~KTSlotDataOneType(); - - void operator()(KTDataPtr data); - - protected: - boost::function< bool (data_type&) > fFunc; - - KTSignalData* fSignalPtr; - }; - - - template< class XDataType1, class XDataType2 > - class KTSlotDataTwoTypes + class KTSlotDone { - public: - typedef XDataType1 first_data_type; - typedef XDataType2 second_data_type; - typedef boost::function< void (KTDataPtr) > function_signature; - typedef typename function_signature::result_type return_type; - typedef typename function_signature::argument_type argument_type; - public: /// Constructor for the case where the processor has the function that will be called by the slot template< class XFuncOwnerType > - KTSlotDataTwoTypes(const std::string& name, XFuncOwnerType* owner, bool (XFuncOwnerType::*func)(first_data_type&, second_data_type&), KTSignalData* signalPtr=NULL); + KTSlotDone(const std::string& name, XFuncOwnerType* owner, void (XFuncOwnerType::*func)(), KTSignalDone* signalPtr=NULL); /// Constructor for the case where the processor and the object with the function that will be called are different template< class XFuncOwnerType > - KTSlotDataTwoTypes(const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, bool (XFuncOwnerType::*func)(first_data_type&, second_data_type&), KTSignalData* signalPtr=NULL); - virtual ~KTSlotDataTwoTypes(); + KTSlotDone(const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, void (XFuncOwnerType::*func)(), KTSignalDone* signalPtr=NULL); + virtual ~KTSlotDone(); - void operator()(KTDataPtr data); + void operator()(); protected: - boost::function< bool (first_data_type&, second_data_type&) > fFunc; + boost::function< void () > fFunc; - KTSignalData* fSignalPtr; + KTSignalDone* fSignalPtr; }; + //******************* + // Implementations + //******************* + // KTSlot - - template< class XDataType > + template< typename ReturnType, typename... Args > template< class XFuncOwnerType > - KTSlotDataOneType< XDataType >::KTSlotDataOneType(const std::string& name, XFuncOwnerType* owner, bool (XFuncOwnerType::*func)(data_type&), KTSignalData* signalPtr) : - fFunc(boost::bind(func, owner, _1)), - fSignalPtr(signalPtr) + KTSlot< ReturnType, Args... >::KTSlot( const std::string& name, XFuncOwnerType* owner, ReturnType (XFuncOwnerType::*func)( Args... ) ) { - owner->RegisterSlot(name, this, &KTSlotDataOneType::operator()); + owner->RegisterSlot( name, owner, func ); } - template< class XDataType > + template< typename ReturnType, typename... Args > template< class XFuncOwnerType > - KTSlotDataOneType< XDataType >::KTSlotDataOneType(const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, bool (XFuncOwnerType::*func)(data_type&), KTSignalData* signalPtr) : - fFunc(boost::bind(func, owner, _1)), - fSignalPtr(signalPtr) + KTSlot< ReturnType, Args... >::KTSlot( const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, ReturnType (XFuncOwnerType::*func)( Args... ) ) { - proc->RegisterSlot(name, this, &KTSlotDataOneType::operator()); + proc->RegisterSlot( name, owner, func ); } - template< class XDataType > - KTSlotDataOneType< XDataType >::~KTSlotDataOneType() + template< typename ReturnType, typename... Args > + KTSlot< ReturnType, Args... >::~KTSlot() { } - template< class XDataType > - void KTSlotDataOneType< XDataType >::operator()(KTDataPtr data) - { - // Standard data slot pattern: - // Check to ensure that the required data type is present - if (! data->Has< data_type >()) - { - KTERROR(slotlog, "Data not found with type <" << typeid(data_type).name() << ">"); - return; - } - // Call the function - if (! fFunc(data->Of< data_type >())) - { - KTERROR(slotlog, "Something went wrong while analyzing data with type <" << typeid(data_type).name() << ">"); - return; - } - // If there's a signal pointer, emit the signal - if (fSignalPtr != NULL) - { - (*fSignalPtr)(data); - } - return; - } - + // KTSlotData - template< class XDataType1, class XDataType2 > + template< class... XDataTypes > template< class XFuncOwnerType > - KTSlotDataTwoTypes< XDataType1, XDataType2 >::KTSlotDataTwoTypes(const std::string& name, XFuncOwnerType* owner, bool (XFuncOwnerType::*func)(first_data_type&, second_data_type&), KTSignalData* signalPtr) : - fFunc(boost::bind(func, owner, _1, _2)), + KTSlotData< XDataTypes... >::KTSlotData(const std::string& name, XFuncOwnerType* owner, bool (XFuncOwnerType::*func)( XDataTypes&... ), KTSignalData* signalPtr) : + fFunc([func, owner](XDataTypes... args){return (owner->*func)(args...);}), fSignalPtr(signalPtr) { - owner->RegisterSlot(name, this, &KTSlotDataTwoTypes::operator()); + owner->RegisterSlot(name, this, &KTSlotData::operator()); } - template< class XDataType1, class XDataType2 > + template< class... XDataTypes > template< class XFuncOwnerType > - KTSlotDataTwoTypes< XDataType1, XDataType2 >::KTSlotDataTwoTypes(const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, bool (XFuncOwnerType::*func)(first_data_type&, second_data_type&), KTSignalData* signalPtr) : - fFunc(boost::bind(func, owner, _1, _2)), + KTSlotData< XDataTypes... >::KTSlotData(const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, bool (XFuncOwnerType::*func)( XDataTypes&... ), KTSignalData* signalPtr) : + fFunc([func, owner](XDataTypes... args){return (owner->*func)(args...);}), fSignalPtr(signalPtr) { - proc->RegisterSlot(name, this, &KTSlotDataTwoTypes::operator()); + proc->RegisterSlot(name, this, &KTSlotData::operator()); } - template< class XDataType1, class XDataType2 > - KTSlotDataTwoTypes< XDataType1, XDataType2 >::~KTSlotDataTwoTypes() + template< class... XDataTypes > + KTSlotData< XDataTypes... >::~KTSlotData() { } - template< class XDataType1, class XDataType2 > - void KTSlotDataTwoTypes< XDataType1, XDataType2 >::operator()(KTDataPtr data) + template< class... XDataTypes > + void KTSlotData< XDataTypes... >::operator()( KTDataPtr data ) { // Standard data slot pattern: // Check to ensure that the required data type is present - if (! data->Has< first_data_type >()) - { - KTERROR(slotlog, "Data not found with type <" << typeid(first_data_type).name() << ">"); - return; - } - if (! data->Has< second_data_type >()) + + if (! DataPresent< XDataTypes... >( data ) ) { - KTERROR(slotlog, "Data not found with type <" << typeid(second_data_type).name() << ">"); + KTFATAL( slotlog, "Failed to find all of the necessary data types in the standard slot function. Aborting." ); + raise(SIGINT); return; } // Call the function - if (! fFunc(data->Of< first_data_type >(), data->Of< second_data_type >())) + if ( ! fFunc(data->Of< XDataTypes >()...) ) { - KTERROR(slotlog, "Something went wrong while analyzing data with types <" << typeid(first_data_type).name() << "> and <" << typeid(second_data_type).name() << ">"); + KTFATAL( slotlog, "Something went wrong in the standard slot function. Aborting." ); + raise(SIGINT); return; } // If there's a signal pointer, emit the signal @@ -384,53 +273,19 @@ namespace Nymph return; } - - /*! - @class KTDoneSlot - @author N. S. Oblath - - @brief Creates a slot to receive indication that upstream processing is complete and will emit a similar signal. - - @details - Usage: - This slot type adds the slot function (signature void (). - Your processor (or, optionally, a different object) must have a member function with the signature bool (). - The slot calls the member function. - - In your Processor's header add a member variable of type KTDoneSlot. - The variable may be private. - - Initialize the slot with the name of the slot, the address of the owner of the slot function, and the function pointer. - Optionally, if the Processor is separate from the owner of the slot function, the Processor address is specified as the second argument to the constructor. - - Also optionally, a signal to be emitted after the return of the member function can be specified as the last argument. - */ - class KTSlotDone + template< class... XDataTypes > + template< typename... DataTypes > + bool KTSlotData< XDataTypes... >::DataPresent( KTDataPtr data ) { - public: - typedef boost::function< void () > function_signature; - typedef bool return_type; - - public: - /// Constructor for the case where the processor has the function that will be called by the slot - template< class XFuncOwnerType > - KTSlotDone(const std::string& name, XFuncOwnerType* owner, void (XFuncOwnerType::*func)(), KTSignalDone* signalPtr=NULL); - /// Constructor for the case where the processor and the object with the function that will be called are different - template< class XFuncOwnerType > - KTSlotDone(const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, void (XFuncOwnerType::*func)(), KTSignalDone* signalPtr=NULL); - virtual ~KTSlotDone(); + return DataPresentHelper< DataTypes... >::DataPresent( data ); + } - void operator()(); - protected: - boost::function< void () > fFunc; - - KTSignalDone* fSignalPtr; - }; + // KTSlotDone template< class XFuncOwnerType > KTSlotDone::KTSlotDone(const std::string& name, XFuncOwnerType* owner, void (XFuncOwnerType::*func)(), KTSignalDone* signalPtr) : - fFunc(boost::bind(func, owner)), + fFunc([func, owner](){return (owner->*func)();}), fSignalPtr(signalPtr) { owner->RegisterSlot(name, this, &KTSlotDone::operator()); @@ -438,7 +293,7 @@ namespace Nymph template< class XFuncOwnerType > KTSlotDone::KTSlotDone(const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, void (XFuncOwnerType::*func)(), KTSignalDone* signalPtr) : - fFunc(boost::bind(func, owner)), + fFunc([func, owner](){return (owner->*func)();}), fSignalPtr(signalPtr) { proc->RegisterSlot(name, this, &KTSlotDone::operator()); @@ -461,7 +316,5 @@ namespace Nymph return; } - - } /* namespace Nymph */ #endif /* KTSLOT_HH_ */ diff --git a/Library/Processor/KTSlotWrapper.hh b/Library/Processor/KTSlotWrapper.hh index 3139143..6b7eed7 100644 --- a/Library/Processor/KTSlotWrapper.hh +++ b/Library/Processor/KTSlotWrapper.hh @@ -11,7 +11,6 @@ #include "KTConnection.hh" #include "KTSignalWrapper.hh" -#include #include namespace Nymph @@ -38,14 +37,13 @@ namespace Nymph class KTSpecifiedInternalSlotWrapper : public KTInternalSlotWrapper, public boost::noncopyable { public: - KTSpecifiedInternalSlotWrapper(XSignature* funcPtr, XTypeContainer* typeCont=NULL) : + KTSpecifiedInternalSlotWrapper(XSignature funcPtr, XTypeContainer* typeCont=NULL) : fSlot(funcPtr) { (void)typeCont; // to suppress warnings } virtual ~KTSpecifiedInternalSlotWrapper() { - delete fSlot; } virtual KTConnection Connect(KTSignalWrapper* signalWrap, int groupNum=-1) @@ -61,18 +59,18 @@ namespace Nymph } if (groupNum >= 0) { - return derivedSignalWrapper->GetSignal()->connect(groupNum, *fSlot); + return derivedSignalWrapper->GetSignal()->connect(groupNum, fSlot); } - return derivedSignalWrapper->GetSignal()->connect(*fSlot); + return derivedSignalWrapper->GetSignal()->connect(fSlot); } private: - XSignature* fSlot; // is owned by this KTSlot + XSignature fSlot; }; public: template< typename XSignature, typename XTypeContainer > - KTSlotWrapper(XSignature* signalPtr, XTypeContainer* typeCont); + KTSlotWrapper(XSignature signalPtr, XTypeContainer* typeCont); ~KTSlotWrapper(); private: @@ -91,7 +89,7 @@ namespace Nymph }; template< typename XSignature, typename XTypeContainer > - KTSlotWrapper::KTSlotWrapper(XSignature* signalPtr, XTypeContainer* typeCont) : + KTSlotWrapper::KTSlotWrapper(XSignature signalPtr, XTypeContainer* typeCont) : fSlotWrapper(new KTSpecifiedInternalSlotWrapper< XSignature, XTypeContainer >(signalPtr, typeCont)), fConnection() {} From 0ea8f8038f5f43d67163c046fa6844150c489ea1 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Fri, 28 Apr 2017 16:42:13 -0700 Subject: [PATCH 002/521] Slightly improved slots: now with inheritance! --- Library/Processor/KTSlot.hh | 42 ++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/Library/Processor/KTSlot.hh b/Library/Processor/KTSlot.hh index 7dc21bd..9756266 100644 --- a/Library/Processor/KTSlot.hh +++ b/Library/Processor/KTSlot.hh @@ -86,7 +86,7 @@ namespace Nymph Also optionally, a signal to be emitted after the return of the member function can be specified as the last argument. */ template< class... XDataTypes > - class KTSlotData + class KTSlotData : public KTSlot< void, KTDataPtr > { //public: //typedef XDataType data_type; @@ -175,15 +175,15 @@ namespace Nymph Also optionally, a signal to be emitted after the return of the member function can be specified as the last argument. */ - class KTSlotDone + class KTSlotDone : public KTSlot< void > { public: /// Constructor for the case where the processor has the function that will be called by the slot template< class XFuncOwnerType > - KTSlotDone(const std::string& name, XFuncOwnerType* owner, void (XFuncOwnerType::*func)(), KTSignalDone* signalPtr=NULL); + KTSlotDone( const std::string& name, XFuncOwnerType* owner, void (XFuncOwnerType::*func)(), KTSignalDone* signalPtr=nullptr ); /// Constructor for the case where the processor and the object with the function that will be called are different template< class XFuncOwnerType > - KTSlotDone(const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, void (XFuncOwnerType::*func)(), KTSignalDone* signalPtr=NULL); + KTSlotDone( const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, void (XFuncOwnerType::*func)(), KTSignalDone* signalPtr=nullptr ); virtual ~KTSlotDone(); void operator()(); @@ -226,19 +226,19 @@ namespace Nymph template< class... XDataTypes > template< class XFuncOwnerType > KTSlotData< XDataTypes... >::KTSlotData(const std::string& name, XFuncOwnerType* owner, bool (XFuncOwnerType::*func)( XDataTypes&... ), KTSignalData* signalPtr) : - fFunc([func, owner](XDataTypes... args){return (owner->*func)(args...);}), - fSignalPtr(signalPtr) + KTSlot( name, owner, this, &KTSlotData::operator() ), + fFunc( [func, owner]( XDataTypes... args ){ return (owner->*func)(args...);} ), + fSignalPtr( signalPtr ) { - owner->RegisterSlot(name, this, &KTSlotData::operator()); } template< class... XDataTypes > template< class XFuncOwnerType > KTSlotData< XDataTypes... >::KTSlotData(const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, bool (XFuncOwnerType::*func)( XDataTypes&... ), KTSignalData* signalPtr) : + KTSlot( name, proc, this, &KTSlotData::operator() ), fFunc([func, owner](XDataTypes... args){return (owner->*func)(args...);}), fSignalPtr(signalPtr) { - proc->RegisterSlot(name, this, &KTSlotData::operator()); } template< class... XDataTypes > @@ -252,23 +252,23 @@ namespace Nymph // Standard data slot pattern: // Check to ensure that the required data type is present - if (! DataPresent< XDataTypes... >( data ) ) + if( ! DataPresent< XDataTypes... >( data ) ) { KTFATAL( slotlog, "Failed to find all of the necessary data types in the standard slot function. Aborting." ); - raise(SIGINT); + raise( SIGINT ); return; } // Call the function - if ( ! fFunc(data->Of< XDataTypes >()...) ) + if( ! fFunc(data->Of< XDataTypes >()...) ) { KTFATAL( slotlog, "Something went wrong in the standard slot function. Aborting." ); - raise(SIGINT); + raise( SIGINT ); return; } // If there's a signal pointer, emit the signal - if (fSignalPtr != NULL) + if( fSignalPtr != nullptr ) { - (*fSignalPtr)(data); + (*fSignalPtr)( data ); } return; } @@ -285,18 +285,18 @@ namespace Nymph template< class XFuncOwnerType > KTSlotDone::KTSlotDone(const std::string& name, XFuncOwnerType* owner, void (XFuncOwnerType::*func)(), KTSignalDone* signalPtr) : - fFunc([func, owner](){return (owner->*func)();}), - fSignalPtr(signalPtr) + KTSlot( name, owner, this, &KTSlotDone::operator() ), + fFunc( [func, owner](){ return (owner->*func)(); } ), + fSignalPtr( signalPtr ) { - owner->RegisterSlot(name, this, &KTSlotDone::operator()); } template< class XFuncOwnerType > KTSlotDone::KTSlotDone(const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, void (XFuncOwnerType::*func)(), KTSignalDone* signalPtr) : - fFunc([func, owner](){return (owner->*func)();}), - fSignalPtr(signalPtr) + KTSlot( name, proc, this, &KTSlotDone::operator() ), + fFunc( [func, owner](){ return (owner->*func)(); } ), + fSignalPtr( signalPtr ) { - proc->RegisterSlot(name, this, &KTSlotDone::operator()); } inline KTSlotDone::~KTSlotDone() @@ -309,7 +309,7 @@ namespace Nymph fFunc(); // If there's a signal pointer, emit the signal - if (fSignalPtr != NULL) + if( fSignalPtr != nullptr ) { (*fSignalPtr)(); } From 3c0aa16951d5a0d8a23d65185f7944209ed833e6 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Sun, 30 Apr 2017 16:22:15 -0700 Subject: [PATCH 003/521] Initial work at switching to two-argument data signal/slot standard --- Library/Application/KTDataQueueProcessor.hh | 4 +- Library/Application/KTProcessorToolbox.cc | 25 ++++++++++--- Library/Data/KTData.hh | 8 ++-- Library/Processor/KTPrimaryProcessor.cc | 10 ++++- Library/Processor/KTPrimaryProcessor.hh | 8 ++-- Library/Processor/KTSignal.hh | 2 +- Library/Processor/KTSlot.hh | 41 +++++++++++++++------ 7 files changed, 70 insertions(+), 28 deletions(-) diff --git a/Library/Application/KTDataQueueProcessor.hh b/Library/Application/KTDataQueueProcessor.hh index f07e92b..b550a7e 100644 --- a/Library/Application/KTDataQueueProcessor.hh +++ b/Library/Application/KTDataQueueProcessor.hh @@ -91,7 +91,7 @@ namespace Nymph //********* public: /// Begins processing of queue (switches status from kStopped to kRunning) - bool Run(); + bool Run( std::promise< KTDataPtr >& promise ); /// Stops processing of queue (switches status to kStopped) void Stop(); @@ -225,7 +225,7 @@ namespace Nymph } template< class XProcessorType > - bool KTDataQueueProcessorTemplate< XProcessorType >::Run() + bool KTDataQueueProcessorTemplate< XProcessorType >::Run( std::promise< KTDataPtr >& promise ) { fStatus = kRunning; KTINFO(eqplog, "Queue started"); diff --git a/Library/Application/KTProcessorToolbox.cc b/Library/Application/KTProcessorToolbox.cc index 30d1b1e..54f6b1c 100644 --- a/Library/Application/KTProcessorToolbox.cc +++ b/Library/Application/KTProcessorToolbox.cc @@ -16,6 +16,8 @@ #include #endif +#include +#include #include using std::deque; @@ -250,15 +252,28 @@ namespace Nymph #endif for (RunQueue::const_iterator rqIter = fRunQueue.begin(); rqIter != fRunQueue.end(); ++rqIter) { -#ifdef SINGLETHREADED +//#ifdef SINGLETHREADED + std::promise< KTDataPtr > promise; for (ThreadGroup::const_iterator tgIter = rqIter->begin(); tgIter != rqIter->end(); ++tgIter) { - if (! tgIter->fProc->Run()) + std::thread thread( tgIter->fProc, &KTPrimaryProcessor::operator(), promise ); + std::future< KTDataPtr > future = promise.get_future(); + thread.join(); + try { - return false; + future.get(); + } + catch( std::exception& e ) + { + KTERROR( proclog, "An error occurred while running processor <" << tgIter->fProc->GetName() << ">: " << e.what() ); + break; } + //if (! tgIter->fProc->Run()) + //{ + // return false; + //} } -#else +//#else KTDEBUG(proclog, "Starting thread group " << iGroup); boost::thread_group parallelThreads; unsigned iThread = 0; @@ -274,7 +289,7 @@ namespace Nymph // wait for execution to complete parallelThreads.join_all(); iGroup++; -#endif +//#endif } KTPROG(proclog, ". . . processing complete."); return true; diff --git a/Library/Data/KTData.hh b/Library/Data/KTData.hh index 7413acc..959756a 100644 --- a/Library/Data/KTData.hh +++ b/Library/Data/KTData.hh @@ -13,8 +13,8 @@ #include "KTCutStatus.hh" #include "KTMemberVariable.hh" -#include - +#include +#include #include namespace Nymph @@ -71,7 +71,9 @@ namespace Nymph return fCutStatus; } - typedef boost::shared_ptr< KTData > KTDataPtr; + typedef std::shared_ptr< KTData > KTDataPtr; + + typedef std::promise< KTDataPtr > KTDataPtrReturn; } /* namespace Nymph */ #endif /* KTDATA_HH_ */ diff --git a/Library/Processor/KTPrimaryProcessor.cc b/Library/Processor/KTPrimaryProcessor.cc index 6cb5749..aba5411 100644 --- a/Library/Processor/KTPrimaryProcessor.cc +++ b/Library/Processor/KTPrimaryProcessor.cc @@ -22,11 +22,17 @@ namespace Nymph { } - void KTPrimaryProcessor::operator ()() + void KTPrimaryProcessor::operator ()( std::promise< KTDataPtr >& promise ) { - if (! Run()) + if (! Run( promise )) { KTERROR(proclog, "An error occurred during processor running."); + //TODO: make sure we're using the exception pointer correctly + promise.set_exception( std::make_exception_ptr( std::exception( "An error occurred during processor running" ) ) ); + } + else + { + promise.set_value( KTDataPtr() ); } return; } diff --git a/Library/Processor/KTPrimaryProcessor.hh b/Library/Processor/KTPrimaryProcessor.hh index f9120c8..27150ed 100644 --- a/Library/Processor/KTPrimaryProcessor.hh +++ b/Library/Processor/KTPrimaryProcessor.hh @@ -12,22 +12,24 @@ #include "KTLogger.hh" +#include + namespace Nymph { class KTPrimaryProcessor : public KTProcessor { public: - KTPrimaryProcessor(const std::string& name = "default-primary-processor-name"); + KTPrimaryProcessor( const std::string& name = "default-primary-processor-name" ); virtual ~KTPrimaryProcessor(); public: /// Callable function used by boost::thread - virtual void operator()(); + virtual void operator()( std::promise< KTDataPtr >& promise ); public: /// Starts the main action of the processor - virtual bool Run() = 0; + virtual bool Run( std::promise< KTDataPtr >& promise ) = 0; }; diff --git a/Library/Processor/KTSignal.hh b/Library/Processor/KTSignal.hh index 11130c9..5b69017 100644 --- a/Library/Processor/KTSignal.hh +++ b/Library/Processor/KTSignal.hh @@ -85,7 +85,7 @@ namespace Nymph That's it! */ - typedef KTSignal< KTDataPtr > KTSignalData; + typedef KTSignal< KTDataPtr, KTDataPtrReturn& > KTSignalData; //******************* diff --git a/Library/Processor/KTSlot.hh b/Library/Processor/KTSlot.hh index 9756266..5e3010e 100644 --- a/Library/Processor/KTSlot.hh +++ b/Library/Processor/KTSlot.hh @@ -9,6 +9,7 @@ #define KTSLOT_HH_ #include "KTData.hh" +#include "KTException.hh" #include "KTLogger.hh" #include "KTSignal.hh" @@ -51,6 +52,10 @@ namespace Nymph virtual ~KTSlot(); + const std::string& GetName() const; + + protected: + std::string fName; }; // Typedefs for backwards compatibility @@ -66,7 +71,7 @@ namespace Nymph /*! - @class KTDataSlot + @class KTSlotData @author N. S. Oblath @brief Creates a slot that takes a KTDataPtr object as the argument; the function that gets called should take 0 or more DataType&'s as its argument. @@ -86,7 +91,7 @@ namespace Nymph Also optionally, a signal to be emitted after the return of the member function can be specified as the last argument. */ template< class... XDataTypes > - class KTSlotData : public KTSlot< void, KTDataPtr > + class KTSlotData : public KTSlot< void, KTDataPtr, KTDataPtrReturn& > { //public: //typedef XDataType data_type; @@ -104,7 +109,7 @@ namespace Nymph virtual ~KTSlotData(); - void operator()( KTDataPtr data ); + void operator()( KTDataPtr data, KTDataPtrReturn& ret ); protected: template< typename... DataTypes > @@ -203,14 +208,16 @@ namespace Nymph template< typename ReturnType, typename... Args > template< class XFuncOwnerType > - KTSlot< ReturnType, Args... >::KTSlot( const std::string& name, XFuncOwnerType* owner, ReturnType (XFuncOwnerType::*func)( Args... ) ) + KTSlot< ReturnType, Args... >::KTSlot( const std::string& name, XFuncOwnerType* owner, ReturnType (XFuncOwnerType::*func)( Args... ) ): + fName( name ) { owner->RegisterSlot( name, owner, func ); } template< typename ReturnType, typename... Args > template< class XFuncOwnerType > - KTSlot< ReturnType, Args... >::KTSlot( const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, ReturnType (XFuncOwnerType::*func)( Args... ) ) + KTSlot< ReturnType, Args... >::KTSlot( const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, ReturnType (XFuncOwnerType::*func)( Args... ) ) : + fName( name ) { proc->RegisterSlot( name, owner, func ); } @@ -220,6 +227,11 @@ namespace Nymph { } + template< typename ReturnType, typename... Args > + const std::string& KTSlot< ReturnType, Args... >::GetName() const + { + return fName; + } // KTSlotData @@ -247,28 +259,33 @@ namespace Nymph } template< class... XDataTypes > - void KTSlotData< XDataTypes... >::operator()( KTDataPtr data ) + void KTSlotData< XDataTypes... >::operator()( KTDataPtr data, KTDataPtrReturn& ret ) { // Standard data slot pattern: - // Check to ensure that the required data type is present + // Check to ensure that the required data type is present if( ! DataPresent< XDataTypes... >( data ) ) { - KTFATAL( slotlog, "Failed to find all of the necessary data types in the standard slot function. Aborting." ); - raise( SIGINT ); + KTERROR( slotlog, "Failed to find all of the necessary data types in slot <" << fName << ">. Aborting." ); + ret.set_exception( std::make_exception_ptr( KTException() << "Failed to find all of the necessary data types in slot <" << fName << ">. Aborting." ) ); return; } + // Call the function if( ! fFunc(data->Of< XDataTypes >()...) ) { - KTFATAL( slotlog, "Something went wrong in the standard slot function. Aborting." ); - raise( SIGINT ); + KTERROR( slotlog, "Something went wrong in slot <" << fName << ">. Aborting." ); + ret.set_exception( std::make_exception_ptr( KTException() << "Something went wrong in slot <" << fName << ">. Aborting." ) ); return; } + + // Set the return + ret.set_value( data ); + // If there's a signal pointer, emit the signal if( fSignalPtr != nullptr ) { - (*fSignalPtr)( data ); + (*fSignalPtr)( data, ret ); } return; } From f3bf136d68f31ebbfbf7ed118b7884ac1153a67d Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Sun, 30 Apr 2017 22:44:11 -0700 Subject: [PATCH 004/521] Nymph compiles now with most of the changes required to use KTDataPtrReturn; parallel-thread running in KTProcessorToolbox has not been implemented yet. --- Library/Application/KTDataQueueProcessor.cc | 8 +++--- Library/Application/KTDataQueueProcessor.hh | 30 +++++++++++---------- Library/Application/KTPrintDataStructure.cc | 24 ++++++++--------- Library/Application/KTPrintDataStructure.hh | 16 +++++------ Library/Application/KTProcessorToolbox.cc | 16 ++++++----- Library/Application/KTProcessorToolbox.hh | 2 +- Library/Application/KTThroughputProfiler.cc | 4 +-- Library/Application/KTThroughputProfiler.hh | 4 +-- Library/Data/KTApplyCut.cc | 10 +++---- Library/Data/KTApplyCut.hh | 2 +- Library/Data/KTCutFilter.cc | 8 +++--- Library/Data/KTCutFilter.hh | 2 +- Library/Data/KTData.hh | 3 +++ Library/Processor/KTPrimaryProcessor.cc | 10 +++---- Library/Processor/KTPrimaryProcessor.hh | 5 ++-- Library/Processor/KTSlot.hh | 2 +- 16 files changed, 77 insertions(+), 69 deletions(-) diff --git a/Library/Application/KTDataQueueProcessor.cc b/Library/Application/KTDataQueueProcessor.cc index 64e766a..b45adf0 100644 --- a/Library/Application/KTDataQueueProcessor.cc +++ b/Library/Application/KTDataQueueProcessor.cc @@ -31,15 +31,15 @@ namespace Nymph return true; } - void KTDataQueueProcessor::EmitDataSignal(KTDataPtr data) + void KTDataQueueProcessor::EmitDataSignal(KTDataPtr data, KTDataPtrReturn& ret) { - fDataSignal(data); + fDataSignal(data, ret); return; } - void KTDataQueueProcessor::QueueData(KTDataPtr& data) + void KTDataQueueProcessor::QueueData(KTDataPtr& data, KTDataPtrReturn& ret) { - return DoQueueData(data, &KTDataQueueProcessor::EmitDataSignal); + return DoQueueData(data, ret, &KTDataQueueProcessor::EmitDataSignal); } /* void KTDataQueueProcessor::QueueDataList(list< KTDataPtr >* dataList) diff --git a/Library/Application/KTDataQueueProcessor.hh b/Library/Application/KTDataQueueProcessor.hh index b550a7e..6a37c2f 100644 --- a/Library/Application/KTDataQueueProcessor.hh +++ b/Library/Application/KTDataQueueProcessor.hh @@ -49,7 +49,7 @@ namespace Nymph struct DataAndFunc { KTDataPtr fData; - void (XProcessorType::*fFuncPtr)(KTDataPtr); + void (XProcessorType::*fFuncPtr)(KTDataPtr, KTDataPtrReturn&); }; typedef KTConcurrentQueue< DataAndFunc > Queue; @@ -80,10 +80,10 @@ namespace Nymph // Derived Processor function pointer //************************************** public: - void SetFuncPtr(void (XProcessorType::*ptr)(KTDataPtr)); + void SetFuncPtr(void (XProcessorType::*ptr)(KTDataPtr, KTDataPtrReturn&)); protected: - void (XProcessorType::*fFuncPtr)(KTDataPtr); + void (XProcessorType::*fFuncPtr)(KTDataPtr, KTDataPtrReturn&); //********* @@ -91,13 +91,13 @@ namespace Nymph //********* public: /// Begins processing of queue (switches status from kStopped to kRunning) - bool Run( std::promise< KTDataPtr >& promise ); + bool Run( KTDataPtrReturn& ret ); /// Stops processing of queue (switches status to kStopped) void Stop(); /// Begins processing of queue if status is already kRunning; otherwise does nothing. - bool ProcessQueue(); + bool ProcessQueue( KTDataPtrReturn& ret ); void ClearQueue(); @@ -111,7 +111,7 @@ namespace Nymph protected: /// Queue an data object /// Assumes ownership of the data; original shared pointer will be nullified - void DoQueueData(KTDataPtr& data, void (XProcessorType::*func)(KTDataPtr)); + void DoQueueData(KTDataPtr& data, KTDataPtrReturn& ret, void (XProcessorType::*func)(KTDataPtr, KTDataPtrReturn&)); /// Queue a list of data objects /// Assumes ownership of all data objects and the list; original shared pointers will be nullified @@ -145,6 +145,8 @@ namespace Nymph @brief Generic data queue for asynchronous processing @details + Asynchronously emits a signal for each data object it receives. + Allows the user to start an asynchronous chain of processors. Configuration name: "data-queue" @@ -166,7 +168,7 @@ namespace Nymph bool ConfigureSubClass(const scarab::param_node* node); public: - void EmitDataSignal(KTDataPtr data); + void EmitDataSignal(KTDataPtr data, KTDataPtrReturn& ret); //*************** // Signals @@ -181,7 +183,7 @@ namespace Nymph public: /// Queue an data object; will emit data signal /// Assumes ownership of the data; original shared pointer will be nullified - void QueueData(KTDataPtr& data); + void QueueData(KTDataPtr& data, KTDataPtrReturn& ret); /// Queue a list of data objects; will emit data signal /// Assumes ownership of all data objects and the list; original shared pointers will be nullified @@ -225,11 +227,11 @@ namespace Nymph } template< class XProcessorType > - bool KTDataQueueProcessorTemplate< XProcessorType >::Run( std::promise< KTDataPtr >& promise ) + bool KTDataQueueProcessorTemplate< XProcessorType >::Run( std::promise< KTDataPtr >& ret ) { fStatus = kRunning; KTINFO(eqplog, "Queue started"); - return ProcessQueue(); + return ProcessQueue( ret ); } template< class XProcessorType > @@ -242,7 +244,7 @@ namespace Nymph } template< class XProcessorType > - void KTDataQueueProcessorTemplate< XProcessorType >::SetFuncPtr(void (XProcessorType::*ptr)(KTDataPtr)) + void KTDataQueueProcessorTemplate< XProcessorType >::SetFuncPtr(void (XProcessorType::*ptr)(KTDataPtr, KTDataPtrReturn&)) { fFuncPtr = ptr; return; @@ -250,7 +252,7 @@ namespace Nymph template< class XProcessorType > - bool KTDataQueueProcessorTemplate< XProcessorType >::ProcessQueue() + bool KTDataQueueProcessorTemplate< XProcessorType >::ProcessQueue( KTDataPtrReturn& ret ) { KTINFO(eqplog, "Beginning to process queue"); while (fStatus != kStopped) @@ -260,7 +262,7 @@ namespace Nymph if ((fQueue.*fPopFromQueue)(daf)) { KTDEBUG(eqplog, "Data acquired for processing"); - (static_cast(this)->*(daf.fFuncPtr))(daf.fData); + (static_cast(this)->*(daf.fFuncPtr))(daf.fData, ret); if (daf.fData->GetLastData()) fStatus = kStopped; } else @@ -294,7 +296,7 @@ namespace Nymph template< class XProcessorType > - void KTDataQueueProcessorTemplate< XProcessorType >::DoQueueData(KTDataPtr& data, void (XProcessorType::*func)(KTDataPtr)) + void KTDataQueueProcessorTemplate< XProcessorType >::DoQueueData(KTDataPtr& data, KTDataPtrReturn& ret, void (XProcessorType::*func)(KTDataPtr, KTDataPtrReturn&)) { KTDEBUG(eqplog, "Queueing data"); DataAndFunc daf; diff --git a/Library/Application/KTPrintDataStructure.cc b/Library/Application/KTPrintDataStructure.cc index de30bbc..df922e4 100644 --- a/Library/Application/KTPrintDataStructure.cc +++ b/Library/Application/KTPrintDataStructure.cc @@ -38,36 +38,36 @@ namespace Nymph return true; } - void KTPrintDataStructure::PrintDataStructure(KTDataPtr dataPtr) + void KTPrintDataStructure::PrintDataStructure(KTDataPtr dataPtr, KTDataPtrReturn& ret) { - DoPrintDataStructure(dataPtr); + DoPrintDataStructure(dataPtr, ret); - fDataSignal(dataPtr); + fDataSignal(dataPtr, ret); return; } - void KTPrintDataStructure::PrintCutStructure(KTDataPtr dataPtr) + void KTPrintDataStructure::PrintCutStructure(KTDataPtr dataPtr, KTDataPtrReturn& ret) { - DoPrintCutStructure(dataPtr); + DoPrintCutStructure(dataPtr, ret); - fDataSignal(dataPtr); + fDataSignal(dataPtr, ret); return; } - void KTPrintDataStructure::PrintDataAndCutStructure(KTDataPtr dataPtr) + void KTPrintDataStructure::PrintDataAndCutStructure(KTDataPtr dataPtr, KTDataPtrReturn& ret) { - DoPrintDataStructure(dataPtr); - DoPrintCutStructure(dataPtr); + DoPrintDataStructure(dataPtr, ret); + DoPrintCutStructure(dataPtr, ret); - fDataSignal(dataPtr); + fDataSignal(dataPtr, ret); return; } - void KTPrintDataStructure::DoPrintDataStructure(KTDataPtr dataPtr) + void KTPrintDataStructure::DoPrintDataStructure(KTDataPtr dataPtr, KTDataPtrReturn&) { std::stringstream printbuf; @@ -87,7 +87,7 @@ namespace Nymph return; } - void KTPrintDataStructure::DoPrintCutStructure(KTDataPtr dataPtr) + void KTPrintDataStructure::DoPrintCutStructure(KTDataPtr dataPtr, KTDataPtrReturn&) { std::stringstream printbuf; diff --git a/Library/Application/KTPrintDataStructure.hh b/Library/Application/KTPrintDataStructure.hh index 5d6eec4..e37f3cd 100644 --- a/Library/Application/KTPrintDataStructure.hh +++ b/Library/Application/KTPrintDataStructure.hh @@ -52,13 +52,13 @@ namespace Nymph bool Configure(const scarab::param_node* node); public: - void PrintDataStructure(KTDataPtr dataPtr); - void PrintCutStructure(KTDataPtr dataPtr); - void PrintDataAndCutStructure(KTDataPtr dataPtr); + void PrintDataStructure(KTDataPtr dataPtr, KTDataPtrReturn& ret); + void PrintCutStructure(KTDataPtr dataPtr, KTDataPtrReturn& ret); + void PrintDataAndCutStructure(KTDataPtr dataPtr, KTDataPtrReturn& ret); private: - void DoPrintDataStructure(KTDataPtr dataPtr); - void DoPrintCutStructure(KTDataPtr dataPtr); + void DoPrintDataStructure(KTDataPtr dataPtr, KTDataPtrReturn& ret); + void DoPrintCutStructure(KTDataPtr dataPtr, KTDataPtrReturn& ret); //*************** // Signals @@ -72,9 +72,9 @@ namespace Nymph //*************** private: - KTSlotOneArg< void, KTDataPtr > fDataStructSlot; - KTSlotOneArg< void, KTDataPtr > fCutStructSlot; - KTSlotOneArg< void, KTDataPtr > fDataAndCutStructSlot; + KTSlot< void, KTDataPtr, KTDataPtrReturn& > fDataStructSlot; + KTSlot< void, KTDataPtr, KTDataPtrReturn& > fCutStructSlot; + KTSlot< void, KTDataPtr, KTDataPtrReturn& > fDataAndCutStructSlot; }; } diff --git a/Library/Application/KTProcessorToolbox.cc b/Library/Application/KTProcessorToolbox.cc index 54f6b1c..9cd0173 100644 --- a/Library/Application/KTProcessorToolbox.cc +++ b/Library/Application/KTProcessorToolbox.cc @@ -250,30 +250,32 @@ namespace Nymph #ifndef SINGLETHREADED unsigned iGroup = 0; #endif - for (RunQueue::const_iterator rqIter = fRunQueue.begin(); rqIter != fRunQueue.end(); ++rqIter) + for (RunQueue::iterator rqIter = fRunQueue.begin(); rqIter != fRunQueue.end(); ++rqIter) { //#ifdef SINGLETHREADED - std::promise< KTDataPtr > promise; - for (ThreadGroup::const_iterator tgIter = rqIter->begin(); tgIter != rqIter->end(); ++tgIter) + for (ThreadGroup::iterator tgIter = rqIter->begin(); tgIter != rqIter->end(); ++tgIter) { - std::thread thread( tgIter->fProc, &KTPrimaryProcessor::operator(), promise ); + std::promise< KTDataPtr > promise; + std::thread thread( &KTPrimaryProcessor::operator(), tgIter->fProc, std::move( promise ) ); std::future< KTDataPtr > future = promise.get_future(); - thread.join(); try { future.get(); } catch( std::exception& e ) { - KTERROR( proclog, "An error occurred while running processor <" << tgIter->fProc->GetName() << ">: " << e.what() ); + KTERROR( proclog, "An error occurred while running processor <" << tgIter->fName << ">: " << e.what() ); break; } + thread.join(); //if (! tgIter->fProc->Run()) //{ // return false; //} } //#else +// for now, don't do this seciton of code +#if 0 KTDEBUG(proclog, "Starting thread group " << iGroup); boost::thread_group parallelThreads; unsigned iThread = 0; @@ -289,7 +291,7 @@ namespace Nymph // wait for execution to complete parallelThreads.join_all(); iGroup++; -//#endif +#endif // this endif was here before i put in the temporary #if 0 } KTPROG(proclog, ". . . processing complete."); return true; diff --git a/Library/Application/KTProcessorToolbox.hh b/Library/Application/KTProcessorToolbox.hh index 4a7c287..1e891ba 100644 --- a/Library/Application/KTProcessorToolbox.hh +++ b/Library/Application/KTProcessorToolbox.hh @@ -173,7 +173,7 @@ namespace Nymph { bool operator() (const Thread& lhs, const Thread& rhs) { - return lhs.fName < rhs.fName; + return lhs.fProc < rhs.fProc; } }; typedef std::set< Thread, CompareThread > ThreadGroup; diff --git a/Library/Application/KTThroughputProfiler.cc b/Library/Application/KTThroughputProfiler.cc index 547d38f..f7ee624 100644 --- a/Library/Application/KTThroughputProfiler.cc +++ b/Library/Application/KTThroughputProfiler.cc @@ -64,7 +64,7 @@ namespace Nymph return Diff(fTimeStart, fTimeEnd); } - void KTThroughputProfiler::StartProfiling(KTDataPtr header) + void KTThroughputProfiler::StartProfiling(KTDataPtr header, KTDataPtrReturn&) { KTINFO(proflog, "Profiling started"); fNDataProcessed = 0; @@ -72,7 +72,7 @@ namespace Nymph return; } - void KTThroughputProfiler::Data(KTDataPtr data) + void KTThroughputProfiler::Data(KTDataPtr data, KTDataPtrReturn&) { (void)data; fNDataProcessed++; diff --git a/Library/Application/KTThroughputProfiler.hh b/Library/Application/KTThroughputProfiler.hh index afd4ea5..1098f19 100644 --- a/Library/Application/KTThroughputProfiler.hh +++ b/Library/Application/KTThroughputProfiler.hh @@ -86,9 +86,9 @@ namespace Nymph void Start(); void Stop(); - void StartProfiling(KTDataPtr data); + void StartProfiling(KTDataPtr data, KTDataPtrReturn& ret); - void Data(KTDataPtr data); + void Data(KTDataPtr data, KTDataPtrReturn& ret); void Finish(); diff --git a/Library/Data/KTApplyCut.cc b/Library/Data/KTApplyCut.cc index 6677451..8c29b86 100644 --- a/Library/Data/KTApplyCut.cc +++ b/Library/Data/KTApplyCut.cc @@ -83,11 +83,11 @@ namespace Nymph } - void KTApplyCut::ApplyCut(KTDataPtr dataPtr) + void KTApplyCut::ApplyCut(KTDataPtr dataPtr, KTDataPtrReturn& ret) { if (fCut == NULL) { - KTERROR(cutlog, "No cut was specified"); + ret.set_exception( std::make_exception_ptr( KTException() << "No cut was specified" ) ); return; } @@ -95,13 +95,13 @@ namespace Nymph if (cutFailed) { - fAfterCutFailSignal(dataPtr); + fAfterCutFailSignal(dataPtr, ret); } else { - fAfterCutPassSignal(dataPtr); + fAfterCutPassSignal(dataPtr, ret); } - fAfterCutSignal(dataPtr); + fAfterCutSignal(dataPtr, ret); return; } diff --git a/Library/Data/KTApplyCut.hh b/Library/Data/KTApplyCut.hh index e678a29..dc93853 100644 --- a/Library/Data/KTApplyCut.hh +++ b/Library/Data/KTApplyCut.hh @@ -67,7 +67,7 @@ namespace Nymph KTCut* fCut; public: - void ApplyCut(KTDataPtr); + void ApplyCut(KTDataPtr dataPtr, KTDataPtrReturn& ret); //*************** diff --git a/Library/Data/KTCutFilter.cc b/Library/Data/KTCutFilter.cc index 0b54852..397c266 100644 --- a/Library/Data/KTCutFilter.cc +++ b/Library/Data/KTCutFilter.cc @@ -74,18 +74,18 @@ namespace Nymph return cutStatus.IsCut(fCutMask); } - void KTCutFilter::FilterData(KTDataPtr dataPtr) + void KTCutFilter::FilterData(KTDataPtr dataPtr, KTDataPtrReturn& ret) { // all KTDataPtr's have KTData, so we won't bother checking if (Filter(dataPtr->Of< KTData >())) { - fAfterCutFailSignal(dataPtr); + fAfterCutFailSignal(dataPtr, ret); } else { - fAfterCutPassSignal(dataPtr); + fAfterCutPassSignal(dataPtr, ret); } - fAfterCutSignal(dataPtr); + fAfterCutSignal(dataPtr, ret); return; } diff --git a/Library/Data/KTCutFilter.hh b/Library/Data/KTCutFilter.hh index 289ddc2..d4e1dde 100644 --- a/Library/Data/KTCutFilter.hh +++ b/Library/Data/KTCutFilter.hh @@ -80,7 +80,7 @@ namespace Nymph public: bool Filter(KTData& data); - void FilterData(KTDataPtr); + void FilterData(KTDataPtr dataPtr, KTDataPtrReturn& ret); //*************** diff --git a/Library/Data/KTData.hh b/Library/Data/KTData.hh index 959756a..7e3293f 100644 --- a/Library/Data/KTData.hh +++ b/Library/Data/KTData.hh @@ -75,5 +75,8 @@ namespace Nymph typedef std::promise< KTDataPtr > KTDataPtrReturn; +#define THROW_RETURN_EXCEPTION( ret_promise, exception ) \ + ret_promise.set_exception( std::make_exception_ptr( exception ) ); + } /* namespace Nymph */ #endif /* KTDATA_HH_ */ diff --git a/Library/Processor/KTPrimaryProcessor.cc b/Library/Processor/KTPrimaryProcessor.cc index aba5411..36d993d 100644 --- a/Library/Processor/KTPrimaryProcessor.cc +++ b/Library/Processor/KTPrimaryProcessor.cc @@ -7,6 +7,7 @@ #include "KTPrimaryProcessor.hh" +#include "KTException.hh" #include "KTLogger.hh" namespace Nymph @@ -22,17 +23,16 @@ namespace Nymph { } - void KTPrimaryProcessor::operator ()( std::promise< KTDataPtr >& promise ) + void KTPrimaryProcessor::operator ()( KTDataPtrReturn ret ) { - if (! Run( promise )) + if (! Run( ret )) { KTERROR(proclog, "An error occurred during processor running."); - //TODO: make sure we're using the exception pointer correctly - promise.set_exception( std::make_exception_ptr( std::exception( "An error occurred during processor running" ) ) ); + THROW_RETURN_EXCEPTION( ret, KTException() << "An error occurred during processor running" ); } else { - promise.set_value( KTDataPtr() ); + ret.set_value( KTDataPtr() ); } return; } diff --git a/Library/Processor/KTPrimaryProcessor.hh b/Library/Processor/KTPrimaryProcessor.hh index 27150ed..24812de 100644 --- a/Library/Processor/KTPrimaryProcessor.hh +++ b/Library/Processor/KTPrimaryProcessor.hh @@ -10,6 +10,7 @@ #include "KTProcessor.hh" +#include "KTData.hh" #include "KTLogger.hh" #include @@ -25,11 +26,11 @@ namespace Nymph public: /// Callable function used by boost::thread - virtual void operator()( std::promise< KTDataPtr >& promise ); + virtual void operator()( KTDataPtrReturn ret ); public: /// Starts the main action of the processor - virtual bool Run( std::promise< KTDataPtr >& promise ) = 0; + virtual bool Run( KTDataPtrReturn& ret ) = 0; }; diff --git a/Library/Processor/KTSlot.hh b/Library/Processor/KTSlot.hh index 5e3010e..a0e6271 100644 --- a/Library/Processor/KTSlot.hh +++ b/Library/Processor/KTSlot.hh @@ -275,7 +275,7 @@ namespace Nymph if( ! fFunc(data->Of< XDataTypes >()...) ) { KTERROR( slotlog, "Something went wrong in slot <" << fName << ">. Aborting." ); - ret.set_exception( std::make_exception_ptr( KTException() << "Something went wrong in slot <" << fName << ">. Aborting." ) ); + THROW_RETURN_EXCEPTION( ret, KTException() << "Something went wrong in slot <" << fName << ">. Aborting." ); return; } From f09b4a5735380ba31dba255126be38e4cdfcfd1c Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Wed, 3 May 2017 14:39:20 -0700 Subject: [PATCH 005/521] =?UTF-8?q?Mid-edit=20update.=20=20Won=E2=80=99t?= =?UTF-8?q?=20build.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Library/Application/KTDataQueueProcessor.cc | 9 +- Library/Application/KTDataQueueProcessor.hh | 49 ++- Library/Application/KTPrintDataStructure.cc | 24 +- Library/Application/KTPrintDataStructure.hh | 10 +- Library/Application/KTProcessorToolbox.cc | 368 +++++++++++++++++--- Library/Application/KTProcessorToolbox.hh | 81 ++++- Library/Application/KTThroughputProfiler.cc | 4 +- Library/Application/KTThroughputProfiler.hh | 4 +- Library/Data/KTApplyCut.cc | 8 +- Library/Data/KTApplyCut.hh | 2 +- Library/Data/KTCutFilter.cc | 8 +- Library/Data/KTCutFilter.hh | 2 +- Library/Processor/KTPrimaryProcessor.cc | 17 +- Library/Processor/KTPrimaryProcessor.hh | 21 +- Library/Processor/KTProcessor.cc | 49 +-- Library/Processor/KTProcessor.hh | 44 ++- Library/Processor/KTSignal.hh | 23 +- Library/Processor/KTSlot.hh | 49 +-- Library/Processor/KTSlotWrapper.hh | 22 +- Library/Processor/KTThreadReference.cc | 44 +++ Library/Processor/KTThreadReference.hh | 32 ++ 21 files changed, 685 insertions(+), 185 deletions(-) create mode 100644 Library/Processor/KTThreadReference.cc create mode 100644 Library/Processor/KTThreadReference.hh diff --git a/Library/Application/KTDataQueueProcessor.cc b/Library/Application/KTDataQueueProcessor.cc index b45adf0..0719f15 100644 --- a/Library/Application/KTDataQueueProcessor.cc +++ b/Library/Application/KTDataQueueProcessor.cc @@ -17,6 +17,7 @@ namespace Nymph KTDataQueueProcessorTemplate< KTDataQueueProcessor >(name), fDataSignal("data", this) { + SetFuncPtr(&KTDataQueueProcessor::EmitDataSignal); RegisterSlot("data", this, &KTDataQueueProcessor::QueueData); //RegisterSlot("data-list", this, &KTDataQueueProcessor::QueueDataList); } @@ -31,15 +32,15 @@ namespace Nymph return true; } - void KTDataQueueProcessor::EmitDataSignal(KTDataPtr data, KTDataPtrReturn& ret) + void KTDataQueueProcessor::EmitDataSignal(KTDataPtr data, KTDataPtrReturn& ret, KTProcessorToolbox::ThreadPacket& threadPacket) { - fDataSignal(data, ret); + fDataSignal(data, ret, threadPacket); return; } - void KTDataQueueProcessor::QueueData(KTDataPtr& data, KTDataPtrReturn& ret) + void KTDataQueueProcessor::QueueData(KTDataPtr& data, KTDataPtrReturn& ret, KTProcessorToolbox::ThreadPacket& threadPacket) { - return DoQueueData(data, ret, &KTDataQueueProcessor::EmitDataSignal); + return DoQueueData(data, ret, threadPacket); } /* void KTDataQueueProcessor::QueueDataList(list< KTDataPtr >* dataList) diff --git a/Library/Application/KTDataQueueProcessor.hh b/Library/Application/KTDataQueueProcessor.hh index 6a37c2f..7e89616 100644 --- a/Library/Application/KTDataQueueProcessor.hh +++ b/Library/Application/KTDataQueueProcessor.hh @@ -46,10 +46,12 @@ namespace Nymph class KTDataQueueProcessorTemplate : public KTPrimaryProcessor { public: + typedef void (XProcessorType::*FuncPtrType)(KTDataPtr, KTDataPtrReturn&, KTProcessorToolbox::ThreadPacket&); + struct DataAndFunc { KTDataPtr fData; - void (XProcessorType::*fFuncPtr)(KTDataPtr, KTDataPtrReturn&); + FuncPtrType fFuncPtr; }; typedef KTConcurrentQueue< DataAndFunc > Queue; @@ -76,14 +78,14 @@ namespace Nymph protected: Status fStatus; - //************************************** - // Derived Processor function pointer - //************************************** + //********************************************** + // Derived Processor function pointer (optional) + //********************************************** public: - void SetFuncPtr(void (XProcessorType::*ptr)(KTDataPtr, KTDataPtrReturn&)); + void SetFuncPtr(FuncPtrType ptr); protected: - void (XProcessorType::*fFuncPtr)(KTDataPtr, KTDataPtrReturn&); + FuncPtrType fFuncPtr; //********* @@ -91,13 +93,13 @@ namespace Nymph //********* public: /// Begins processing of queue (switches status from kStopped to kRunning) - bool Run( KTDataPtrReturn& ret ); + bool Run( KTDataPtrReturn& ret, KTProcessorToolbox::ThreadPacket& threadPacket ); /// Stops processing of queue (switches status to kStopped) void Stop(); /// Begins processing of queue if status is already kRunning; otherwise does nothing. - bool ProcessQueue( KTDataPtrReturn& ret ); + bool ProcessQueue( KTDataPtrReturn& ret, KTProcessorToolbox::ThreadPacket& threadPacket ); void ClearQueue(); @@ -109,9 +111,13 @@ namespace Nymph // Queueing functions for slots //********* protected: - /// Queue an data object + /// Queue an data object with a provided function + /// Assumes ownership of the data; original shared pointer will be nullified + void DoQueueData(KTDataPtr& data, KTDataPtrReturn& ret, KTProcessorToolbox::ThreadPacket& threadPacket, FuncPtrType func); + + /// Queue an data object with fFuncPtr /// Assumes ownership of the data; original shared pointer will be nullified - void DoQueueData(KTDataPtr& data, KTDataPtrReturn& ret, void (XProcessorType::*func)(KTDataPtr, KTDataPtrReturn&)); + void DoQueueData(KTDataPtr& data, KTDataPtrReturn& ret, KTProcessorToolbox::ThreadPacket& threadPacket); /// Queue a list of data objects /// Assumes ownership of all data objects and the list; original shared pointers will be nullified @@ -168,7 +174,7 @@ namespace Nymph bool ConfigureSubClass(const scarab::param_node* node); public: - void EmitDataSignal(KTDataPtr data, KTDataPtrReturn& ret); + void EmitDataSignal(KTDataPtr data, KTDataPtrReturn& ret, KTProcessorToolbox::ThreadPacket& threadPacket); //*************** // Signals @@ -183,7 +189,7 @@ namespace Nymph public: /// Queue an data object; will emit data signal /// Assumes ownership of the data; original shared pointer will be nullified - void QueueData(KTDataPtr& data, KTDataPtrReturn& ret); + void QueueData(KTDataPtr& data, KTDataPtrReturn& ret, KTProcessorToolbox::ThreadPacket& threadPacket); /// Queue a list of data objects; will emit data signal /// Assumes ownership of all data objects and the list; original shared pointers will be nullified @@ -227,11 +233,11 @@ namespace Nymph } template< class XProcessorType > - bool KTDataQueueProcessorTemplate< XProcessorType >::Run( std::promise< KTDataPtr >& ret ) + bool KTDataQueueProcessorTemplate< XProcessorType >::Run( std::promise< KTDataPtr >& ret, KTProcessorToolbox::ThreadPacket& threadPacket ) { fStatus = kRunning; KTINFO(eqplog, "Queue started"); - return ProcessQueue( ret ); + return ProcessQueue( ret, threadPacket ); } template< class XProcessorType > @@ -244,7 +250,7 @@ namespace Nymph } template< class XProcessorType > - void KTDataQueueProcessorTemplate< XProcessorType >::SetFuncPtr(void (XProcessorType::*ptr)(KTDataPtr, KTDataPtrReturn&)) + void KTDataQueueProcessorTemplate< XProcessorType >::SetFuncPtr(FuncPtrType ptr) { fFuncPtr = ptr; return; @@ -252,7 +258,7 @@ namespace Nymph template< class XProcessorType > - bool KTDataQueueProcessorTemplate< XProcessorType >::ProcessQueue( KTDataPtrReturn& ret ) + bool KTDataQueueProcessorTemplate< XProcessorType >::ProcessQueue( KTDataPtrReturn& ret, KTProcessorToolbox::ThreadPacket& threadPacket ) { KTINFO(eqplog, "Beginning to process queue"); while (fStatus != kStopped) @@ -262,7 +268,7 @@ namespace Nymph if ((fQueue.*fPopFromQueue)(daf)) { KTDEBUG(eqplog, "Data acquired for processing"); - (static_cast(this)->*(daf.fFuncPtr))(daf.fData, ret); + (static_cast(this)->*(daf.fFuncPtr))(daf.fData, ret, threadPacket); if (daf.fData->GetLastData()) fStatus = kStopped; } else @@ -296,7 +302,7 @@ namespace Nymph template< class XProcessorType > - void KTDataQueueProcessorTemplate< XProcessorType >::DoQueueData(KTDataPtr& data, KTDataPtrReturn& ret, void (XProcessorType::*func)(KTDataPtr, KTDataPtrReturn&)) + void KTDataQueueProcessorTemplate< XProcessorType >::DoQueueData(KTDataPtr& data, KTDataPtrReturn& ret, KTProcessorToolbox::ThreadPacket& threadPacket, FuncPtrType func) { KTDEBUG(eqplog, "Queueing data"); DataAndFunc daf; @@ -306,6 +312,13 @@ namespace Nymph fQueue.push(daf); return; } + + template< class XProcessorType > + void KTDataQueueProcessorTemplate< XProcessorType >::DoQueueData(KTDataPtr& data, KTDataPtrReturn& ret, KTProcessorToolbox::ThreadPacket& threadPacket) + { + DoQueueData(data, ret, threadPacket, &fFuncPtr); + return; + } /* template< class XProcessorType > void KTDataQueueProcessorTemplate< XProcessorType >::DoQueueDataList(std::list< KTDataPtr& >* dataList, void (XProcessorType::*func)(KTDataPtr)) diff --git a/Library/Application/KTPrintDataStructure.cc b/Library/Application/KTPrintDataStructure.cc index df922e4..ec19d62 100644 --- a/Library/Application/KTPrintDataStructure.cc +++ b/Library/Application/KTPrintDataStructure.cc @@ -38,36 +38,36 @@ namespace Nymph return true; } - void KTPrintDataStructure::PrintDataStructure(KTDataPtr dataPtr, KTDataPtrReturn& ret) + void KTPrintDataStructure::PrintDataStructure(KTDataPtr dataPtr, KTDataPtrReturn& ret, KTProcessorToolbox::ThreadPacket& threadPacket) { - DoPrintDataStructure(dataPtr, ret); + DoPrintDataStructure(dataPtr, ret, threadPacket); - fDataSignal(dataPtr, ret); + fDataSignal(dataPtr, ret, threadPacket); return; } - void KTPrintDataStructure::PrintCutStructure(KTDataPtr dataPtr, KTDataPtrReturn& ret) + void KTPrintDataStructure::PrintCutStructure(KTDataPtr dataPtr, KTDataPtrReturn& ret, KTProcessorToolbox::ThreadPacket& threadPacket) { - DoPrintCutStructure(dataPtr, ret); + DoPrintCutStructure(dataPtr, ret, threadPacket); - fDataSignal(dataPtr, ret); + fDataSignal(dataPtr, ret, threadPacket); return; } - void KTPrintDataStructure::PrintDataAndCutStructure(KTDataPtr dataPtr, KTDataPtrReturn& ret) + void KTPrintDataStructure::PrintDataAndCutStructure(KTDataPtr dataPtr, KTDataPtrReturn& ret, KTProcessorToolbox::ThreadPacket& threadPacket) { - DoPrintDataStructure(dataPtr, ret); - DoPrintCutStructure(dataPtr, ret); + DoPrintDataStructure(dataPtr, ret, threadPacket); + DoPrintCutStructure(dataPtr, ret, threadPacket); - fDataSignal(dataPtr, ret); + fDataSignal(dataPtr, ret, threadPacket); return; } - void KTPrintDataStructure::DoPrintDataStructure(KTDataPtr dataPtr, KTDataPtrReturn&) + void KTPrintDataStructure::DoPrintDataStructure(KTDataPtr dataPtr, KTDataPtrReturn&, KTProcessorToolbox::ThreadPacket& threadPacket) { std::stringstream printbuf; @@ -87,7 +87,7 @@ namespace Nymph return; } - void KTPrintDataStructure::DoPrintCutStructure(KTDataPtr dataPtr, KTDataPtrReturn&) + void KTPrintDataStructure::DoPrintCutStructure(KTDataPtr dataPtr, KTDataPtrReturn&, KTProcessorToolbox::ThreadPacket& threadPacket) { std::stringstream printbuf; diff --git a/Library/Application/KTPrintDataStructure.hh b/Library/Application/KTPrintDataStructure.hh index e37f3cd..8928600 100644 --- a/Library/Application/KTPrintDataStructure.hh +++ b/Library/Application/KTPrintDataStructure.hh @@ -52,13 +52,13 @@ namespace Nymph bool Configure(const scarab::param_node* node); public: - void PrintDataStructure(KTDataPtr dataPtr, KTDataPtrReturn& ret); - void PrintCutStructure(KTDataPtr dataPtr, KTDataPtrReturn& ret); - void PrintDataAndCutStructure(KTDataPtr dataPtr, KTDataPtrReturn& ret); + void PrintDataStructure(KTDataPtr dataPtr, KTDataPtrReturn& ret, KTProcessorToolbox::ThreadPacket& threadPacket); + void PrintCutStructure(KTDataPtr dataPtr, KTDataPtrReturn& ret, KTProcessorToolbox::ThreadPacket& threadPacket); + void PrintDataAndCutStructure(KTDataPtr dataPtr, KTDataPtrReturn& ret, KTProcessorToolbox::ThreadPacket& threadPacket); private: - void DoPrintDataStructure(KTDataPtr dataPtr, KTDataPtrReturn& ret); - void DoPrintCutStructure(KTDataPtr dataPtr, KTDataPtrReturn& ret); + void DoPrintDataStructure(KTDataPtr dataPtr, KTDataPtrReturn& ret, KTProcessorToolbox::ThreadPacket& threadPacket); + void DoPrintCutStructure(KTDataPtr dataPtr, KTDataPtrReturn& ret, KTProcessorToolbox::ThreadPacket& threadPacket); //*************** // Signals diff --git a/Library/Application/KTProcessorToolbox.cc b/Library/Application/KTProcessorToolbox.cc index 9cd0173..efae329 100644 --- a/Library/Application/KTProcessorToolbox.cc +++ b/Library/Application/KTProcessorToolbox.cc @@ -32,8 +32,17 @@ namespace Nymph KTProcessorToolbox::KTProcessorToolbox(const std::string& name) : KTConfigurable(name), fProcFactory(scarab::factory< KTProcessor, const std::string& >::get_instance()), + fRunSingleThreaded( true ), //TODO: switch this to false once multithreading is available fRunQueue(), - fProcMap() + fProcMap(), + fThreadFutures(), + fThreadPackets(), + fContinueSignaler(), + fMasterContSignal(), + fBreakContMutex(), + fDoRunThread( nullptr ), + fDoRunPromise(), + fDoRunBreakFlag( false ) { } @@ -45,7 +54,10 @@ namespace Nymph bool KTProcessorToolbox::Configure(const scarab::param_node* node) { KTPROG(proclog, "Configuring . . ."); - // Deal with "processor" blocks first + + SetRunSingleThreaded( node->get_value( "single-threaded", fRunSingleThreaded ) ); + + // Deal with "processor" blocks const scarab::param_array* procArray = node->array_at( "processors" ); if (procArray == NULL) { @@ -244,60 +256,6 @@ namespace Nymph return true; } - bool KTProcessorToolbox::Run() - { - KTPROG(proclog, "Beginning processing . . ."); -#ifndef SINGLETHREADED - unsigned iGroup = 0; -#endif - for (RunQueue::iterator rqIter = fRunQueue.begin(); rqIter != fRunQueue.end(); ++rqIter) - { -//#ifdef SINGLETHREADED - for (ThreadGroup::iterator tgIter = rqIter->begin(); tgIter != rqIter->end(); ++tgIter) - { - std::promise< KTDataPtr > promise; - std::thread thread( &KTPrimaryProcessor::operator(), tgIter->fProc, std::move( promise ) ); - std::future< KTDataPtr > future = promise.get_future(); - try - { - future.get(); - } - catch( std::exception& e ) - { - KTERROR( proclog, "An error occurred while running processor <" << tgIter->fName << ">: " << e.what() ); - break; - } - thread.join(); - //if (! tgIter->fProc->Run()) - //{ - // return false; - //} - } -//#else -// for now, don't do this seciton of code -#if 0 - KTDEBUG(proclog, "Starting thread group " << iGroup); - boost::thread_group parallelThreads; - unsigned iThread = 0; - for (ThreadGroup::const_iterator tgIter = rqIter->begin(); tgIter != rqIter->end(); ++tgIter) - { - // create a boost::thread object to launch the thread - // use boost::ref to avoid copying the processor - KTDEBUG(proclog, "Starting thread " << iThread << ": " << tgIter->fName); - parallelThreads.create_thread(boost::ref(*(tgIter->fProc))); - //parallelThreads.create_thread(boost::ref(**tgIter)); - iThread++; - } - // wait for execution to complete - parallelThreads.join_all(); - iGroup++; -#endif // this endif was here before i put in the temporary #if 0 - } - KTPROG(proclog, ". . . processing complete."); - return true; - } - - KTProcessor* KTProcessorToolbox::GetProcessor(const std::string& procName) { ProcMapIt it = fProcMap.find(procName); @@ -508,4 +466,302 @@ namespace Nymph return true; } + void KTProcessorToolbox::AsyncRun() + { + if( fDoRunThread != nullptr ) + { + KTERROR( proclog, "It appears that a run has already been started" ); + return; + } + + bool willRunSingleThreaded = fRunSingleThreaded; +#ifdef SINGLETHREADED + willRunSingleThreaded = true; +#endif + + if( willRunSingleThreaded ) + { + auto singleThreadRun = [&]() + { + try + { + // reset the continue signaler + fContinueSignaler = std::promise< void >(); + fMasterContSignal( fContinueSignaler.get_future() ); + if( ! fMasterContSignal.valid() ) + { + KTERROR( proclog, "Invalid master continue-signal created" ); + throw std::future_error( std::future_errc::no_state ); + } + // copy for use in this function + std::shared_future< void > continueSignal = fMasterContSignal; + + KTPROG( proclog, "Starting single-threaded processing" ); + + for (RunQueue::iterator rqIter = fRunQueue.begin(); rqIter != fRunQueue.end(); ++rqIter) + { + for (ThreadGroup::iterator tgIter = rqIter->begin(); tgIter != rqIter->end(); ++tgIter) + { + std::string procName( tgIter->fName ); + KTINFO( proclog, "Starting processor <" << procName << ">" ); + + KTDataPtrReturn dataRet; + fThreadFutures.push_back( dataRet.get_future() ); + if( ! fThreadFutures.back().valid() ) + { + KTERROR( proclog, "Invalid thread future created" ); + throw std::future_error( std::future_errc::no_state ); + } + + fThreadPackets.push_back( ThreadPacket() ); + fThreadPackets.back().fProcTB = this; + fThreadPackets.back().fContinueSignal = fMasterContSignal; + + std::thread thread( &KTPrimaryProcessor::operator(), tgIter->fProc, std::move( dataRet ), fThreadPackets.back() ); + + KTDEBUG( proclog, "Thread ID is <" << fThreadPackets.back().fThread->get_id() << ">" ); + + bool stillRunning = true; // determines behavior that depends on whether a return from the thread was temporary or from the thread completing + do + { + std::future_status status; + do + { + status = fThreadFutures.back().wait_for(std::chrono::milliseconds(500)); + } while (status != std::future_status::ready); + + stillRunning = false; + if( fThreadPackets.back().fBreakFlag ) + { + KTDEBUG( proclog, "Breakpoint reached" ); + continueSignal.wait(); + stillRunning = true; + } + else + { + try + { + fThreadFutures.back().get(); + } + catch( std::exception& e ) + { + // this transfers an exception thrown by a processor to the outer catch block in this function + throw KTException() << "An error occurred while running processor <" << procName << ">: " << e.what(); + } + stillRunning = false; + } + } while( stillRunning ); + + KTINFO( proclog, "Processor <" << procName << "> has finished" ); + + thread.join(); + } // end for loop over the thread group + } // end for loop over the run-queue + + KTPROG( proclog, "Processing is complete (single-threaded)" ); + } + catch( ... ) + { + // exceptions thrown in this function or from within processors will end up here + fDoRunPromise.set_exception( std::current_exception() ); + } + fDoRunPromise.set_value(); + return; + }; + + fDoRunThread = new std::thread( singleThreadRun ); + } + else + { + auto multiThreadRun = [&]() + { + try + { + std::shared_future< void > fMasterContSignal( fContinueSignaler.get_future() ); + if( ! fMasterContSignal.valid() ) + { + KTERROR( proclog, "Invalid master continue-signal created" ); + throw std::future_error( std::future_errc::no_state ); + } + + KTPROG( proclog, "Starting multi-threaded processing" ); + + // TODO logic to start threads goes here + + KTPROG( proclog, "Processing is complete (multi-threaded)" ); + } + catch( ... ) + { + fDoRunPromise.set_exception( std::current_exception() ); + } + fDoRunPromise.set_value(); + return; + }; + + fDoRunThread = new std::thread( multiThreadRun ); + } + + return; + } + + bool KTProcessorToolbox::WaitForBreak() + { + std::future< void > doRunFuture = fDoRunPromise.get_future(); + + std::future_status doRunStatus; + do + { + doRunStatus = doRunFuture.wait_for( std::chrono::milliseconds( 500 ) ); + } while( doRunStatus != std::future_status::ready ); + + if( fDoRunBreakFlag ) + { + KTDEBUG( proclog, "Breakpoint reached" ); + return true; + } + + try + { + doRunFuture.get(); + return false; + } + catch( std::exception& e ) + { + // this transfers an exception thrown by a processor to the outer catch block in this function + throw; + } + } + + void KTProcessorToolbox::Continue() + { + std::unique_lock< std::mutex > breakContLock( fBreakContMutex ); + + // futures have been used; clear them to be replaced + fThreadFutures.clear(); + + // reset all break flags + fDoRunBreakFlag = false; + for( std::vector< ThreadPacket >::iterator tpIt = fThreadPackets.begin(); tpIt != fThreadPackets.end(); ++tpIt ) + { + tpIt->fBreakFlag = false; + } + + KTINFO( proclog, "Continuing from breakpoint" ); + // signal everything to resume + fContinueSignaler.set_value(); + + // reset the signaler and all signals + // hopefull the delay of creating the new signaler and starting the for loop is enough that anything waiting on the old signal has already seen that signal and moved on + fContinueSignaler = std::promise< void >(); + for( std::vector< ThreadPacket >::iterator tpIt = fThreadPackets.begin(); tpIt != fThreadPackets(); ++tpIt ) + { + tpIt->fContinueSignal = fContinueSignaler.get_future(); + } + + return; + } + + void KTProcessorToolbox::InitiateBreak() + { + std::unique_lock< std::mutex > breakContLock( fBreakContMutex ); + + // set all break flags + fDoRunBreakFlag = true; + for( std::vector< ThreadPacket >::iterator tpIt = fThreadPackets.begin(); tpIt != fThreadPackets.end(); ++tpIt ) + { + tpIt->fBreakFlag = true; + } + + return; + } + + bool KTProcessorToolbox::Run() + { + AsyncRun(); + + std::future< void > doRunFuture = fDoRunPromise.get_future(); + + try + { + while( WaitForBreak() ) + { + KTINFO( proclog, "Skipping breakpoint" ); + Continue(); + } + } + catch( std::exception& e ) + { + KTERROR( proclog, "An error occurred: " << e.what() ); + return false; + } + + return true; + + /* + KTPROG(proclog, "Beginning processing . . ."); +#ifndef SINGLETHREADED + unsigned iGroup = 0; +#endif + try + { + for (RunQueue::iterator rqIter = fRunQueue.begin(); rqIter != fRunQueue.end(); ++rqIter) + { + //#ifdef SINGLETHREADED + for (ThreadGroup::iterator tgIter = rqIter->begin(); tgIter != rqIter->end(); ++tgIter) + { + std::promise< KTDataPtr > promise; + std::future< KTDataPtr > future = promise.get_future(); + std::thread thread( &KTPrimaryProcessor::operator(), tgIter->fProc, std::move( promise ) ); + if( ! future.valid() ) + { + throw std::future_error( std::future_errc::no_state ); + } + std::future_status status; + do + { + status = future.wait_for(std::chrono::milliseconds(500)); + } while (status != std::future_status::ready); + + try + { + future.get(); + } + catch( std::exception& e ) + { + throw KTException() << "An error occurred while running processor <" << tgIter->fName << ">: " << e.what(); + } + thread.join(); + } +//#else +// for now, don't do this section of code +#if 0 + KTDEBUG(proclog, "Starting thread group " << iGroup); + boost::thread_group parallelThreads; + unsigned iThread = 0; + for (ThreadGroup::const_iterator tgIter = rqIter->begin(); tgIter != rqIter->end(); ++tgIter) + { + // create a boost::thread object to launch the thread + // use boost::ref to avoid copying the processor + KTDEBUG(proclog, "Starting thread " << iThread << ": " << tgIter->fName); + parallelThreads.create_thread(boost::ref(*(tgIter->fProc))); + //parallelThreads.create_thread(boost::ref(**tgIter)); + iThread++; + } + // wait for execution to complete + parallelThreads.join_all(); + iGroup++; +#endif // this endif was here before i put in the temporary #if 0 + } + } + catch( std::exception& e ) + { + KTERROR( proclog, e.what() ); + return false; + } + KTPROG(proclog, ". . . processing complete."); + return true; + */ + } + + } /* namespace Nymph */ diff --git a/Library/Application/KTProcessorToolbox.hh b/Library/Application/KTProcessorToolbox.hh index 1e891ba..e29c15b 100644 --- a/Library/Application/KTProcessorToolbox.hh +++ b/Library/Application/KTProcessorToolbox.hh @@ -10,7 +10,7 @@ #define KTPROCESSORTOOLBOX_HH_ #include "KTConfigurable.hh" -//#include "KTNOFactory.hh" +#include "KTMemberVariable.hh" #include "factory.hh" @@ -47,6 +47,7 @@ namespace Nymph Available (nested) configuration values:
    +
  • run-single-threaded (bool) -- specify whether to run in single-threaded mode (will be ignored if the application has been compiled with the SINGLETHREADED flag set)
  • processors (array of objects) -- create a processor; each object in the array should consist of:
    • type -- string specifying the processor type (matches the string given to the Registrar, which should be specified before the class implementation in each processor's .cc file).
    • @@ -88,12 +89,7 @@ namespace Nymph /// Configure processors (only those specified in the toolbox) bool ConfigureProcessors(const scarab::param_node* node); - - public: - /// Process the run queue. - /// This will call Run() on all of the processors in the queue. - bool Run(); - + MEMBERVARIABLE( bool, RunSingleThreaded ); private: struct ProcessorInfo @@ -182,6 +178,65 @@ namespace Nymph RunQueue fRunQueue; + public: + struct ThreadPacket + { + KTProcessorToolbox* fProcTB; + bool fBreakFlag; // only use outside of blocks protected by fBreakContMutex are reads, so we shouldn't need to make this an atomic + std::shared_future< void > fContinueSignal; + std::thread* fThread; + + void Break( const KTDataPtr& dataPtr, KTDataPtrReturn& ret ) + { + bool breakInititatedHere = false; + if( /* breakpoint is set here */ false ) + { + breakInititatedHere = true; + fProcTB->InitiateBreak(); + } + if( fBreakFlag || breakInititatedHere ) + { + ret.set_value( dataPtr ); + fContinueSignal.wait(); + ret = KTDataPtrReturn(); + fProcTB->TakeFuture( ret.get_future() ); + } + return; + } + }; + + /// Process the run queue. + /// This will call Run() on all of the processors in the queue. + bool Run(); + + void AsyncRun(); + + void WaitForContinue(); + + /// Returns when processing is completed or a breakpoint is reached + /// Throws an exception if an error occurred during processing + /// If the return is true, processing can continue after the break + bool WaitForBreak(); + + void Continue(); + + private: + // called from ThreadPacket::Break + void InitiateBreak(); + // called from ThreadPacket::Break + void TakeFuture( std::future< KTDataPtr > future ); + + std::vector< std::future< KTDataPtr > > fThreadFutures; + std::vector< ThreadPacket > fThreadPackets; + + std::promise< void > fContinueSignaler; + std::shared_future< void > fMasterContSignal; + std::mutex fBreakContMutex; + + std::thread* fDoRunThread; + std::promise< void > fDoRunPromise; + bool fDoRunBreakFlag; // only use outside of blocks protected by fBreakContMutex is reads, so we shouldn't need to make this an atomic + }; inline void KTProcessorToolbox::PopBackOfRunQueue() @@ -196,6 +251,18 @@ namespace Nymph return; } + inline void KTProcessorToolbox::WaitForContinue() + { + fMasterContSignal.wait(); + return; + } + + inline void KTProcessorToolbox::TakeFuture( std::future< KTDataPtr > future ) + { + fThreadFutures.push_back( future ); + return; + } + } /* namespace Nymph */ diff --git a/Library/Application/KTThroughputProfiler.cc b/Library/Application/KTThroughputProfiler.cc index f7ee624..94bd66b 100644 --- a/Library/Application/KTThroughputProfiler.cc +++ b/Library/Application/KTThroughputProfiler.cc @@ -64,7 +64,7 @@ namespace Nymph return Diff(fTimeStart, fTimeEnd); } - void KTThroughputProfiler::StartProfiling(KTDataPtr header, KTDataPtrReturn&) + void KTThroughputProfiler::StartProfiling(KTDataPtr header, KTDataPtrReturn&, KTProcessorToolbox::ThreadPacket&) { KTINFO(proflog, "Profiling started"); fNDataProcessed = 0; @@ -72,7 +72,7 @@ namespace Nymph return; } - void KTThroughputProfiler::Data(KTDataPtr data, KTDataPtrReturn&) + void KTThroughputProfiler::Data(KTDataPtr data, KTDataPtrReturn&, KTProcessorToolbox::ThreadPacket&) { (void)data; fNDataProcessed++; diff --git a/Library/Application/KTThroughputProfiler.hh b/Library/Application/KTThroughputProfiler.hh index 1098f19..216b3e8 100644 --- a/Library/Application/KTThroughputProfiler.hh +++ b/Library/Application/KTThroughputProfiler.hh @@ -86,9 +86,9 @@ namespace Nymph void Start(); void Stop(); - void StartProfiling(KTDataPtr data, KTDataPtrReturn& ret); + void StartProfiling(KTDataPtr data, KTDataPtrReturn& ret, KTProcessorToolbox::ThreadPacket& threadPacket); - void Data(KTDataPtr data, KTDataPtrReturn& ret); + void Data(KTDataPtr data, KTDataPtrReturn& ret, KTProcessorToolbox::ThreadPacket& threadPacket); void Finish(); diff --git a/Library/Data/KTApplyCut.cc b/Library/Data/KTApplyCut.cc index 8c29b86..b34f0a5 100644 --- a/Library/Data/KTApplyCut.cc +++ b/Library/Data/KTApplyCut.cc @@ -83,7 +83,7 @@ namespace Nymph } - void KTApplyCut::ApplyCut(KTDataPtr dataPtr, KTDataPtrReturn& ret) + void KTApplyCut::ApplyCut(KTDataPtr dataPtr, KTDataPtrReturn ret, KTProcessorToolbox::ThreadPacket& threadPacket) { if (fCut == NULL) { @@ -95,13 +95,13 @@ namespace Nymph if (cutFailed) { - fAfterCutFailSignal(dataPtr, ret); + fAfterCutFailSignal(dataPtr, ret, threadPacket); } else { - fAfterCutPassSignal(dataPtr, ret); + fAfterCutPassSignal(dataPtr, ret, threadPacket); } - fAfterCutSignal(dataPtr, ret); + fAfterCutSignal(dataPtr, ret, threadPacket); return; } diff --git a/Library/Data/KTApplyCut.hh b/Library/Data/KTApplyCut.hh index dc93853..235afcf 100644 --- a/Library/Data/KTApplyCut.hh +++ b/Library/Data/KTApplyCut.hh @@ -67,7 +67,7 @@ namespace Nymph KTCut* fCut; public: - void ApplyCut(KTDataPtr dataPtr, KTDataPtrReturn& ret); + void ApplyCut(KTDataPtr dataPtr, KTDataPtrReturn ret, KTProcessorToolbox::ThreadPacket& threadPacket); //*************** diff --git a/Library/Data/KTCutFilter.cc b/Library/Data/KTCutFilter.cc index 397c266..6e04137 100644 --- a/Library/Data/KTCutFilter.cc +++ b/Library/Data/KTCutFilter.cc @@ -74,18 +74,18 @@ namespace Nymph return cutStatus.IsCut(fCutMask); } - void KTCutFilter::FilterData(KTDataPtr dataPtr, KTDataPtrReturn& ret) + void KTCutFilter::FilterData(KTDataPtr dataPtr, KTDataPtrReturn& ret, KTProcessorToolbox::ThreadPacket& threadPacket) { // all KTDataPtr's have KTData, so we won't bother checking if (Filter(dataPtr->Of< KTData >())) { - fAfterCutFailSignal(dataPtr, ret); + fAfterCutFailSignal(dataPtr, ret, threadPacket); } else { - fAfterCutPassSignal(dataPtr, ret); + fAfterCutPassSignal(dataPtr, ret, threadPacket); } - fAfterCutSignal(dataPtr, ret); + fAfterCutSignal(dataPtr, ret, threadPacket); return; } diff --git a/Library/Data/KTCutFilter.hh b/Library/Data/KTCutFilter.hh index d4e1dde..74d94cc 100644 --- a/Library/Data/KTCutFilter.hh +++ b/Library/Data/KTCutFilter.hh @@ -80,7 +80,7 @@ namespace Nymph public: bool Filter(KTData& data); - void FilterData(KTDataPtr dataPtr, KTDataPtrReturn& ret); + void FilterData(KTDataPtr dataPtr, KTDataPtrReturn& ret, KTProcessorToolbox::ThreadPacket& threadPacket); //*************** diff --git a/Library/Processor/KTPrimaryProcessor.cc b/Library/Processor/KTPrimaryProcessor.cc index 36d993d..97a0c24 100644 --- a/Library/Processor/KTPrimaryProcessor.cc +++ b/Library/Processor/KTPrimaryProcessor.cc @@ -12,10 +12,11 @@ namespace Nymph { - KTLOGGER(proclog, "KTPrimaryProcessor"); + KTLOGGER( proclog, "KTPrimaryProcessor" ); - KTPrimaryProcessor::KTPrimaryProcessor(const std::string& name) : - KTProcessor(name) + KTPrimaryProcessor::KTPrimaryProcessor( const std::string& name ) : + KTProcessor( name ), + fThreadRef() { } @@ -23,16 +24,16 @@ namespace Nymph { } - void KTPrimaryProcessor::operator ()( KTDataPtrReturn ret ) + void KTPrimaryProcessor::operator ()() { - if (! Run( ret )) + if( ! Run() ) { - KTERROR(proclog, "An error occurred during processor running."); - THROW_RETURN_EXCEPTION( ret, KTException() << "An error occurred during processor running" ); + KTERROR( proclog, "An error occurred during processor running." ); + THROW_RETURN_EXCEPTION( fThreadRef.fDataPtrRet, KTException() << "An error occurred during processor running" ); } else { - ret.set_value( KTDataPtr() ); + fThreadRef.fDataPtrRet.set_value( KTDataPtr() ); } return; } diff --git a/Library/Processor/KTPrimaryProcessor.hh b/Library/Processor/KTPrimaryProcessor.hh index 24812de..596246c 100644 --- a/Library/Processor/KTPrimaryProcessor.hh +++ b/Library/Processor/KTPrimaryProcessor.hh @@ -11,7 +11,7 @@ #include "KTProcessor.hh" #include "KTData.hh" -#include "KTLogger.hh" +#include "KTThreadReference.hh" #include @@ -25,14 +25,25 @@ namespace Nymph virtual ~KTPrimaryProcessor(); public: - /// Callable function used by boost::thread - virtual void operator()( KTDataPtrReturn ret ); + /// Callable function used by std::thread + void operator()(); - public: /// Starts the main action of the processor - virtual bool Run( KTDataPtrReturn& ret ) = 0; + virtual bool Run() = 0; + + void SetThreadReference( KTThreadReference&& ref ); + + protected: + KTThreadReference fThreadRef; + }; + inline void KTPrimaryProcessor::SetThreadReference( KTThreadReference&& ref ) + { + fThreadRef = ref; + return; + } + } /* namespace Nymph */ #endif /* KTPRIMARYPROCESSOR_HH_ */ diff --git a/Library/Processor/KTProcessor.cc b/Library/Processor/KTProcessor.cc index 72a717d..4a62d9d 100644 --- a/Library/Processor/KTProcessor.cc +++ b/Library/Processor/KTProcessor.cc @@ -27,7 +27,9 @@ namespace Nymph KTProcessor::KTProcessor(const string& name) : KTConfigurable(name), fSignalMap(), - fSlotMap() + fSlotMap(), + fSlotToSigMap(), + fSigConnMap() { } @@ -44,13 +46,35 @@ namespace Nymph } } + void KTProcessor::PassThreadRefUpdate(const std::string& slotName, KTThreadReference* threadRef) + { + // get the list of slot-to-signal connections for this slot + auto stsRange = fSlotToSigMap.equal_range(slotName); + + // loop over signals called in the performance of slot slotName + for (SlotToSigMapCIt stsIt = stsRange.first; stsIt != stsRange.second; ++stsIt) + { + // loop over all processor:slots called by this signal + auto sigConnRange = fSigConnMap.equal_range(stsIt->second); + for (SigConnMapCIt sigConnIt = sigConnRange.first; sigConnIt != sigConnRange.second; ++sigConnIt) + { + // update the thread reference pointer for this connection + sigConnIt->second.fThreadRef = threadRef; + // pass the update on to the connected-to processor + sigConnIt->second.fProc->PassThreadRefUpdate(sigConnIt->second.fSlotName, threadRef); + } + } + } + void KTProcessor::ConnectASlot(const std::string& signalName, KTProcessor* processor, const std::string& slotName, int groupNum) { + // get the signal and slot wrapper pointers KTSignalWrapper* signal = GetSignal(signalName); KTSlotWrapper* slot = processor->GetSlot(slotName); try { + // make the connection ConnectSignalToSlot(signal, slot, groupNum); } catch (std::exception& e) @@ -62,28 +86,11 @@ namespace Nymph string("\tIf the slot pointer is NULL, you may have the slot name wrong."); throw std::logic_error(errorMsg); } - KTDEBUG(processorlog, "Connected signal <" << signalName << "> to slot <" << slotName << ">"); - return; - } - - void KTProcessor::ConnectASignal(KTProcessor* processor, const std::string& signalName, const std::string& slotName, int groupNum) - { - KTSignalWrapper* signal = processor->GetSignal(signalName); - KTSlotWrapper* slot = GetSlot(slotName); + // record the connection in the signal-connection map + fSigConnMap.insert(SigConnMapVal(signalName, std::make_pair(processor, slotName))); - try - { - ConnectSignalToSlot(signal, slot, groupNum); - } - catch (std::exception& e) - { - string errorMsg = string("Exception caught in KTProcessor::ConnectASignal; signal: ") + - signalName + string(", slot: ") + slotName + string("\n") + e.what() + string("\n") + - string("Check that the signatures of the signal and slot match exactly."); - throw std::logic_error(errorMsg); - } - KTDEBUG(processorlog, "Connected slot <" << signalName << "> to signal <" << slotName << ">"); + KTDEBUG(processorlog, "Connected signal <" << this->GetConfigName() << ":" << signalName << "> to slot <" << processor->GetConfigName() << ":" << slotName << ">"); return; } diff --git a/Library/Processor/KTProcessor.hh b/Library/Processor/KTProcessor.hh index 21ba7ee..b9a217b 100644 --- a/Library/Processor/KTProcessor.hh +++ b/Library/Processor/KTProcessor.hh @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -35,6 +36,8 @@ namespace Nymph ProcessorException(std::string const& why); }; + class KTThreadReference; + class KTProcessor : public KTConfigurable { protected: @@ -46,46 +49,62 @@ namespace Nymph typedef SlotMap::iterator SlotMapIt; typedef SlotMap::value_type SlotMapVal; + typedef std::multimap< std::string, std::string > SlotToSigMap; + typedef SlotToSigMap::iterator SlotToSigMapIt; + typedef SlotToSigMap::const_iterator SlotToSigMapCIt; + typedef SlotToSigMap::value_type SlotToSigMapVal; + + typedef std::multimap< std::string, std::pair< KTProcessor*, std::string > > SigConnMap; + typedef SigConnMap::iterator SigConnMapIt; + typedef SigConnMap::const_iterator SigConnMapCIt; + typedef SigConnMap::value_type SigConnMapVal; + public: KTProcessor(const std::string& name="default-proc-name"); virtual ~KTProcessor(); public: + void PassThreadRefUpdate(const std::string& slotName, KTThreadReference* threadRef); void ConnectASlot(const std::string& signalName, KTProcessor* processor, const std::string& slotName, int groupNum=-1); void ConnectASignal(KTProcessor* processor, const std::string& signalName, const std::string& slotName, int groupNum=-1); - void ConnectSignalToSlot(KTSignalWrapper* signal, KTSlotWrapper* slot, int groupNum=-1); template< class XProcessor > - void RegisterSignal(std::string name, XProcessor* signalPtr); + KTSignalWrapper* RegisterSignal(std::string name, XProcessor* signalPtr); template< class XTarget, typename XReturn, typename... XArgs > - void RegisterSlot(std::string name, XTarget* target, XReturn (XTarget::* funcPtr)(XArgs...)); + KTSlotWrapper* RegisterSlot(std::string name, XTarget* target, XReturn (XTarget::* funcPtr)(XArgs...), std::initializer_list< std::string > signals); KTSignalWrapper* GetSignal(const std::string& name); KTSlotWrapper* GetSlot(const std::string& name); protected: + void ConnectSignalToSlot(KTSignalWrapper* signal, KTSlotWrapper* slot, int groupNum=-1); SignalMap fSignalMap; SlotMap fSlotMap; + // maps which slots call which signals in this processor + SlotToSigMap fSlotToSigMap; + + // maps which signals get connected to which slots in other processors + SigConnMap fSigConnMap; }; template< typename XSignalSig > - void KTProcessor::RegisterSignal(std::string name, XSignalSig* signalPtr) + KTSignalWrapper* KTProcessor::RegisterSignal(std::string name, XSignalSig* signalPtr) { KTDEBUG(processorlog, "Registering signal <" << name << "> in processor <" << fConfigName << ">"); KTSignalWrapper* sig = new KTSignalWrapper(signalPtr); fSignalMap.insert(SigMapVal(name, sig)); - return; + return sig; } template< class XTarget, typename XReturn, typename... XArgs > - void KTProcessor::RegisterSlot(std::string name, XTarget* target, XReturn (XTarget::* funcPtr)(XArgs...)) + KTSlotWrapper* KTProcessor::RegisterSlot(std::string name, XTarget* target, XReturn (XTarget::* funcPtr)(XArgs...), std::initializer_list< std::string > signals) { KTDEBUG(processorlog, "Registering slot <" << name << "> in processor <" << fConfigName << ">"); @@ -93,9 +112,22 @@ namespace Nymph KTSlotWrapper* slot = new KTSlotWrapper([funcPtr, target](XArgs... args){return (target->*funcPtr)(args...);}, &signalConcept); fSlotMap.insert(SlotMapVal(name, slot)); + + for (std::initializer_list< std::string >::const_iterator sigIt = signals.begin(); sigIt != signals.end(); ++sigIt) + { + fSlotToSigMap.insert(SlotToSigMapVal(name, *sigIt)); + KTDEBUG(processorlog, "Slot-to-signal connection <" << name << "> --> <" << *sigIt << ">"); + } + return slot; + } + + inline void KTProcessor::ConnectASignal(KTProcessor* processor, const std::string& signalName, const std::string& slotName, int groupNum) + { + processor->ConnectASlot(signalName, this, slotName, groupNum); return; } + #define KT_REGISTER_PROCESSOR(proc_class, proc_name) \ static ::scarab::registrar< ::Nymph::KTProcessor, proc_class, const std::string& > sProc##proc_class##Registrar( proc_name ); diff --git a/Library/Processor/KTSignal.hh b/Library/Processor/KTSignal.hh index 5b69017..cad637f 100644 --- a/Library/Processor/KTSignal.hh +++ b/Library/Processor/KTSignal.hh @@ -56,8 +56,12 @@ namespace Nymph boost_signal* Signal(); + const std::string& GetName() const; + protected: boost_signal fSignal; + + std::string fName; }; /// Convenience typedef for done signals @@ -85,7 +89,7 @@ namespace Nymph That's it! */ - typedef KTSignal< KTDataPtr, KTDataPtrReturn& > KTSignalData; + typedef KTSignal< KTDataPtr > KTSignalData; //******************* @@ -94,19 +98,22 @@ namespace Nymph template< class... XSignalArguments > KTSignal< XSignalArguments... >::KTSignal( const std::string& name, KTProcessor* proc ) : - fSignal() + fSignal(), + fName( name ) { proc->RegisterSignal(name, &fSignal); } template< class... XSignalArguments > KTSignal< XSignalArguments... >::KTSignal() : - fSignal() + fSignal(), + fName("none") {} template< class... XSignalArguments > - KTSignal< XSignalArguments... >::KTSignal( const KTSignal& ) : - fSignal() + KTSignal< XSignalArguments... >::KTSignal( const KTSignal& signal ) : + fSignal(), + fName( signal.fName ) {} template< class... XSignalArguments > @@ -126,5 +133,11 @@ namespace Nymph return &fSignal; } + template< class... XSignalArguments > + inline const std::string& KTSignal< XSignalArguments... >::GetName() const + { + return fName; + } + } /* namespace Nymph */ #endif /* KTSIGNAL_HH_ */ diff --git a/Library/Processor/KTSlot.hh b/Library/Processor/KTSlot.hh index a0e6271..f547d4d 100644 --- a/Library/Processor/KTSlot.hh +++ b/Library/Processor/KTSlot.hh @@ -14,7 +14,6 @@ #include "KTSignal.hh" #include -#include #include namespace Nymph @@ -44,11 +43,11 @@ namespace Nymph public: /// Constructor for the case where the processor has the function that will be called by the slot template< class XFuncOwnerType > - KTSlot( const std::string& name, XFuncOwnerType* owner, ReturnType (XFuncOwnerType::*func)( Args... ) ); + KTSlot( const std::string& name, XFuncOwnerType* owner, ReturnType (XFuncOwnerType::*func)( Args... ), std::initializer_list< std::string > signals ); /// Constructor for the case where the processor and the object with the function that will be called are different template< class XFuncOwnerType > - KTSlot( const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, ReturnType (XFuncOwnerType::*func)( Args... ) ); + KTSlot( const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, ReturnType (XFuncOwnerType::*func)( Args... ), std::initializer_list< std::string > signals ); virtual ~KTSlot(); @@ -56,6 +55,7 @@ namespace Nymph protected: std::string fName; + KTSlotWrapper* fSlotWrapper; }; // Typedefs for backwards compatibility @@ -91,7 +91,7 @@ namespace Nymph Also optionally, a signal to be emitted after the return of the member function can be specified as the last argument. */ template< class... XDataTypes > - class KTSlotData : public KTSlot< void, KTDataPtr, KTDataPtrReturn& > + class KTSlotData : public KTSlot< void, KTDataPtr > { //public: //typedef XDataType data_type; @@ -109,7 +109,7 @@ namespace Nymph virtual ~KTSlotData(); - void operator()( KTDataPtr data, KTDataPtrReturn& ret ); + void operator()( KTDataPtr data ); protected: template< typename... DataTypes > @@ -208,18 +208,18 @@ namespace Nymph template< typename ReturnType, typename... Args > template< class XFuncOwnerType > - KTSlot< ReturnType, Args... >::KTSlot( const std::string& name, XFuncOwnerType* owner, ReturnType (XFuncOwnerType::*func)( Args... ) ): + KTSlot< ReturnType, Args... >::KTSlot( const std::string& name, XFuncOwnerType* owner, ReturnType (XFuncOwnerType::*func)( Args... ), std::initializer_list< std::string > signals ): fName( name ) { - owner->RegisterSlot( name, owner, func ); + fSlotWrapper = owner->RegisterSlot( name, owner, func, signals ); } template< typename ReturnType, typename... Args > template< class XFuncOwnerType > - KTSlot< ReturnType, Args... >::KTSlot( const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, ReturnType (XFuncOwnerType::*func)( Args... ) ) : + KTSlot< ReturnType, Args... >::KTSlot( const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, ReturnType (XFuncOwnerType::*func)( Args... ), std::initializer_list< std::string > signals ) : fName( name ) { - proc->RegisterSlot( name, owner, func ); + fSlotWrapper = proc->RegisterSlot( name, owner, func, signals ); } template< typename ReturnType, typename... Args > @@ -238,7 +238,7 @@ namespace Nymph template< class... XDataTypes > template< class XFuncOwnerType > KTSlotData< XDataTypes... >::KTSlotData(const std::string& name, XFuncOwnerType* owner, bool (XFuncOwnerType::*func)( XDataTypes&... ), KTSignalData* signalPtr) : - KTSlot( name, owner, this, &KTSlotData::operator() ), + KTSlot( name, owner, this, &KTSlotData::operator(), {signalPtr->GetName()} ), fFunc( [func, owner]( XDataTypes... args ){ return (owner->*func)(args...);} ), fSignalPtr( signalPtr ) { @@ -247,9 +247,9 @@ namespace Nymph template< class... XDataTypes > template< class XFuncOwnerType > KTSlotData< XDataTypes... >::KTSlotData(const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, bool (XFuncOwnerType::*func)( XDataTypes&... ), KTSignalData* signalPtr) : - KTSlot( name, proc, this, &KTSlotData::operator() ), - fFunc([func, owner](XDataTypes... args){return (owner->*func)(args...);}), - fSignalPtr(signalPtr) + KTSlot( name, proc, this, &KTSlotData::operator(), { signalPtr->GetName()} ), + fFunc( [func, owner]( XDataTypes... args ){return (owner->*func) (args... );} ), + fSignalPtr( signalPtr ) { } @@ -259,33 +259,36 @@ namespace Nymph } template< class... XDataTypes > - void KTSlotData< XDataTypes... >::operator()( KTDataPtr data, KTDataPtrReturn& ret ) + void KTSlotData< XDataTypes... >::operator()( KTDataPtr dataPtr ) { // Standard data slot pattern: + KTThreadReference* ref = fSlotWrapper->GetThreadRef(); + // Check to ensure that the required data type is present - if( ! DataPresent< XDataTypes... >( data ) ) + if( ! DataPresent< XDataTypes... >( dataPtr ) ) { KTERROR( slotlog, "Failed to find all of the necessary data types in slot <" << fName << ">. Aborting." ); - ret.set_exception( std::make_exception_ptr( KTException() << "Failed to find all of the necessary data types in slot <" << fName << ">. Aborting." ) ); + ref->fDataPtrRet.set_exception( std::make_exception_ptr( KTException() << "Failed to find all of the necessary data types in slot <" << fName << ">. Aborting." ) ); return; } // Call the function - if( ! fFunc(data->Of< XDataTypes >()...) ) + if( ! fFunc( dataPtr->Of< XDataTypes >()... ) ) { KTERROR( slotlog, "Something went wrong in slot <" << fName << ">. Aborting." ); - THROW_RETURN_EXCEPTION( ret, KTException() << "Something went wrong in slot <" << fName << ">. Aborting." ); + THROW_RETURN_EXCEPTION( ref->fDataPtrRet, KTException() << "Something went wrong in slot <" << fName << ">. Aborting." ); return; } - // Set the return - ret.set_value( data ); + // Perform breakpoint here if necessary (either if initiated here or if stopping here due to a breakpoint elsewhere) + // Sets the dataPtr into the return + ref->Break( dataPtr ); // If there's a signal pointer, emit the signal if( fSignalPtr != nullptr ) { - (*fSignalPtr)( data, ret ); + (*fSignalPtr)( dataPtr ); } return; } @@ -302,7 +305,7 @@ namespace Nymph template< class XFuncOwnerType > KTSlotDone::KTSlotDone(const std::string& name, XFuncOwnerType* owner, void (XFuncOwnerType::*func)(), KTSignalDone* signalPtr) : - KTSlot( name, owner, this, &KTSlotDone::operator() ), + KTSlot( name, owner, this, &KTSlotDone::operator(), {signalPtr->GetName()} ), fFunc( [func, owner](){ return (owner->*func)(); } ), fSignalPtr( signalPtr ) { @@ -310,7 +313,7 @@ namespace Nymph template< class XFuncOwnerType > KTSlotDone::KTSlotDone(const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, void (XFuncOwnerType::*func)(), KTSignalDone* signalPtr) : - KTSlot( name, proc, this, &KTSlotDone::operator() ), + KTSlot( name, proc, this, &KTSlotDone::operator(), {signalPtr->GetName()} ), fFunc( [func, owner](){ return (owner->*func)(); } ), fSignalPtr( signalPtr ) { diff --git a/Library/Processor/KTSlotWrapper.hh b/Library/Processor/KTSlotWrapper.hh index 6b7eed7..a020d11 100644 --- a/Library/Processor/KTSlotWrapper.hh +++ b/Library/Processor/KTSlotWrapper.hh @@ -10,6 +10,7 @@ #include "KTConnection.hh" #include "KTSignalWrapper.hh" +#include "KTThreadReference.hh" #include @@ -86,12 +87,20 @@ namespace Nymph private: KTConnection fConnection; + public: + KTThreadReference* GetThreadRef(); + void SetThreadRef(KTThreadReference* ref); + + private: + KTThreadReference* fThreadRef; + }; template< typename XSignature, typename XTypeContainer > KTSlotWrapper::KTSlotWrapper(XSignature signalPtr, XTypeContainer* typeCont) : fSlotWrapper(new KTSpecifiedInternalSlotWrapper< XSignature, XTypeContainer >(signalPtr, typeCont)), - fConnection() + fConnection(), + fThreadRef() {} inline void KTSlotWrapper::SetConnection(KTConnection conn) @@ -112,5 +121,16 @@ namespace Nymph return; } + inline KTThreadReference* KTSlotWrapper::GetThreadRef() + { + return fThreadRef; + } + + inline void KTSlotWrapper::SetThreadRef(KTThreadReference* ref) + { + fThreadRef = ref; + return; + } + } /* namespace Nymph */ #endif /* KTSLOTWRAPPER_HH_ */ diff --git a/Library/Processor/KTThreadReference.cc b/Library/Processor/KTThreadReference.cc new file mode 100644 index 0000000..c62a3a9 --- /dev/null +++ b/Library/Processor/KTThreadReference.cc @@ -0,0 +1,44 @@ +/* + * KTThreadReference.cc + * + * Created on: May 2, 2017 + * Author: obla999 + */ + +#include "KTThreadReference.hh" + +namespace Nymph +{ + + KTThreadReference::KTThreadReference() : + fDataPtrRet(), + fProcTB( nullptr ), + fBreakFlag( false ), + fContinueSignal(), + fThread( nullptr ) + { + } + + KTThreadReference::~KTThreadReference() + { + } + + void KTThreadReference::Break( const KTDataPtr& dataPtr ) + { + bool breakInititatedHere = false; + if( /* breakpoint is set here */ false ) + { + breakInititatedHere = true; + fProcTB->InitiateBreak(); + } + if( fBreakFlag || breakInititatedHere ) + { + fDataPtrRet.set_value( dataPtr ); + fContinueSignal.wait(); + fDataPtrRet = KTDataPtrReturn(); + fProcTB->TakeFuture( fDataPtrRet.get_future() ); + } + return; + } + +} /* namespace Nymph */ diff --git a/Library/Processor/KTThreadReference.hh b/Library/Processor/KTThreadReference.hh new file mode 100644 index 0000000..06d65ce --- /dev/null +++ b/Library/Processor/KTThreadReference.hh @@ -0,0 +1,32 @@ +/* + * KTThreadReference.hh + * + * Created on: May 2, 2017 + * Author: obla999 + */ + +#ifndef KTTHREADREFERENCE_HH_ +#define KTTHREADREFERENCE_HH_ + +#include "KTData.hh" + +#include + +namespace Nymph +{ + class KTProcessorToolbox; + + struct KTThreadReference + { + KTDataPtrReturn fDataPtrRet; + KTProcessorToolbox* fProcTB; + bool fBreakFlag; // only use outside of blocks protected by fBreakContMutex are reads, so we shouldn't need to make this an atomic + std::shared_future< void > fContinueSignal; + std::thread* fThread; + + void Break( const KTDataPtr& dataPtr ); + }; + +} /* namespace Nymph */ + +#endif /* KTTHREADREFERENCE_HH_ */ From 8a257b0ad707a429afb0db722821e5429b4a13de Mon Sep 17 00:00:00 2001 From: Ben LaRoque Date: Wed, 3 May 2017 16:21:31 -0700 Subject: [PATCH 006/521] need to register processors --- Library/Processor/KTProcessor.hh | 8 +++ Library/Processor/KTProcessorPy.hh | 80 +----------------------------- 2 files changed, 9 insertions(+), 79 deletions(-) diff --git a/Library/Processor/KTProcessor.hh b/Library/Processor/KTProcessor.hh index 7aa8e6c..5aec8d1 100644 --- a/Library/Processor/KTProcessor.hh +++ b/Library/Processor/KTProcessor.hh @@ -52,6 +52,9 @@ namespace Nymph KTProcessor(const std::string& name="default-proc-name"); virtual ~KTProcessor(); + template< class XDerivedProc > + static scarab::registrar< Nymph::KTProcessor, XDerivedProc, const std::string& >* RegisterProcessor( const std::string& name ); + public: void ConnectASlot(const std::string& signalName, KTProcessor* processor, const std::string& slotName, int groupNum=-1); @@ -134,6 +137,11 @@ namespace Nymph return; } + template< class XDerivedProc > + scarab::registrar< KTProcessor, XDerivedProc, const std::string& >* KTProcessor::RegisterProcessor( const std::string& name ) + { + return new scarab::registrar< KTProcessor, XDerivedProc, const std::string& >( name ); + } #define KT_REGISTER_PROCESSOR(proc_class, proc_name) \ static ::scarab::registrar< ::Nymph::KTProcessor, proc_class, const std::string& > sProc##proc_class##Registrar( proc_name ); diff --git a/Library/Processor/KTProcessorPy.hh b/Library/Processor/KTProcessorPy.hh index 92677db..31a4b9b 100644 --- a/Library/Processor/KTProcessorPy.hh +++ b/Library/Processor/KTProcessorPy.hh @@ -24,86 +24,8 @@ void export_Processor() .def("ConnectASignal", &KTProcessor::ConnectASignal) .def("ConnectSignalToSlot", &KTProcessor::ConnectSignalToSlot) .def("Configure", Configure_JsonStr, "Configure from json encoded configuration") - //.def("GetSignal", KTProcessor::GetSignal) - //.def("RegisterSignal", &KTProcessor::RegisterSignal) + //.def("RegisterProcessor", &KTProcessor::RegisterProcessor, return_value_policy()) ; } -/*{ - class KTProcessor : public KTConfigurable - { - public: - - template< class XProcessor > - void RegisterSignal(std::string name, XProcessor* signalPtr); - - template< class XTarget, typename XReturn > - void RegisterSlot(std::string name, XTarget* target, XReturn (XTarget::* funcPtr)()); - - template< class XTarget, typename XReturn, typename XArg1 > - void RegisterSlot(std::string name, XTarget* target, XReturn (XTarget::* funcPtr)(XArg1)); - - template< class XTarget, typename XReturn, typename XArg1, typename XArg2 > - void RegisterSlot(std::string name, XTarget* target, XReturn (XTarget::* funcPtr)(XArg1, XArg2)); - - KTSignalWrapper* GetSignal(const std::string& name); - - KTSlotWrapper* GetSlot(const std::string& name); - - }; - - - template< typename XSignalSig > - void KTProcessor::RegisterSignal(std::string name, XSignalSig* signalPtr) - { - KTDEBUG(processorlog, "Registering signal <" << name << "> in processor <" << fConfigName << ">"); - KTSignalWrapper* sig = new KTSignalWrapper(signalPtr); - fSignalMap.insert(SigMapVal(name, sig)); - return; - } - - template< class XTarget, typename XReturn > - void KTProcessor::RegisterSlot(std::string name, XTarget* target, XReturn (XTarget::* funcPtr)()) - { - KTDEBUG(processorlog, "Registering slot <" << name << "> in processor <" << fConfigName << ">"); - - KTSignalConcept< XReturn () > signalConcept; - - boost::function< XReturn () > *func = new boost::function< XReturn () >(boost::bind(funcPtr, target)); - - KTSlotWrapper* slot = new KTSlotWrapper(func, &signalConcept); - fSlotMap.insert(SlotMapVal(name, slot)); - return; - } - - template< class XTarget, typename XReturn, typename XArg1 > - void KTProcessor::RegisterSlot(std::string name, XTarget* target, XReturn (XTarget::* funcPtr)(XArg1)) - { - KTDEBUG(processorlog, "Registering slot <" << name << "> in processor <" << fConfigName << ">"); - - KTSignalConcept< XReturn (XArg1) > signalConcept; - - boost::function< XReturn (XArg1) > *func = new boost::function< XReturn (XArg1) >(boost::bind(funcPtr, target, _1)); - - KTSlotWrapper* slot = new KTSlotWrapper(func, &signalConcept); - fSlotMap.insert(SlotMapVal(name, slot)); - return; - } - - template< class XTarget, typename XReturn, typename XArg1, typename XArg2 > - void KTProcessor::RegisterSlot(std::string name, XTarget* target, XReturn (XTarget::* funcPtr)(XArg1, XArg2)) - { - KTDEBUG(processorlog, "Registering slot <" << name << "> in processor <" << fConfigName << ">"); - - KTSignalConcept< XReturn (XArg1, XArg2) > signalConcept; - - boost::function< XReturn (XArg1, XArg2) > *func = new boost::function< XReturn (XArg1, XArg2) >(boost::bind(funcPtr, target, _1, _2)); - - KTSlotWrapper* slot = new KTSlotWrapper(func, &signalConcept); - fSlotMap.insert(SlotMapVal(name, slot)); - return; - } - - -}*/ #endif /* KTPROCESSORPY_HH_ */ From 4bc996571b39747cce301cc0ae17b7f5069e3d2f Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Wed, 3 May 2017 16:36:57 -0700 Subject: [PATCH 007/521] =?UTF-8?q?More=20partial=20work.=20=20Some=20thin?= =?UTF-8?q?gs=20compile,=20some=20don=E2=80=99t.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Library/Application/KTDataQueueProcessor.cc | 11 +++--- Library/Application/KTDataQueueProcessor.hh | 29 +++++++------- Library/Application/KTPrintDataStructure.cc | 36 ++++++++++------- Library/Application/KTPrintDataStructure.hh | 16 ++++---- Library/Application/KTProcessorToolbox.cc | 43 ++++++++++++++------- Library/Application/KTProcessorToolbox.hh | 8 ++-- Library/CMakeLists.txt | 2 + Library/Data/KTApplyCut.cc | 16 +++++--- Library/Data/KTApplyCut.hh | 4 +- Library/Data/KTCutFilter.cc | 19 ++++++--- Library/Data/KTCutFilter.hh | 4 +- Library/Processor/KTPrimaryProcessor.hh | 10 ++++- Library/Processor/KTProcessor.cc | 7 ++-- Library/Processor/KTSlot.hh | 10 ++++- Library/Processor/KTSlotWrapper.hh | 4 +- Library/Processor/KTThreadReference.cc | 17 +------- Library/Processor/KTThreadReference.hh | 9 ++++- Scarab | 2 +- 18 files changed, 147 insertions(+), 100 deletions(-) diff --git a/Library/Application/KTDataQueueProcessor.cc b/Library/Application/KTDataQueueProcessor.cc index 0719f15..237f4b2 100644 --- a/Library/Application/KTDataQueueProcessor.cc +++ b/Library/Application/KTDataQueueProcessor.cc @@ -18,7 +18,7 @@ namespace Nymph fDataSignal("data", this) { SetFuncPtr(&KTDataQueueProcessor::EmitDataSignal); - RegisterSlot("data", this, &KTDataQueueProcessor::QueueData); + fQueueDataSW = RegisterSlot("data", this, &KTDataQueueProcessor::QueueData); //RegisterSlot("data-list", this, &KTDataQueueProcessor::QueueDataList); } @@ -32,15 +32,16 @@ namespace Nymph return true; } - void KTDataQueueProcessor::EmitDataSignal(KTDataPtr data, KTDataPtrReturn& ret, KTProcessorToolbox::ThreadPacket& threadPacket) + void KTDataQueueProcessor::EmitDataSignal(KTDataPtr data) { - fDataSignal(data, ret, threadPacket); + fDataSignal(data); return; } - void KTDataQueueProcessor::QueueData(KTDataPtr& data, KTDataPtrReturn& ret, KTProcessorToolbox::ThreadPacket& threadPacket) + void KTDataQueueProcessor::QueueData(KTDataPtr& data) { - return DoQueueData(data, ret, threadPacket); + fQueueDataSW->GetThreadRef()->Break(data); + return DoQueueData(data); } /* void KTDataQueueProcessor::QueueDataList(list< KTDataPtr >* dataList) diff --git a/Library/Application/KTDataQueueProcessor.hh b/Library/Application/KTDataQueueProcessor.hh index 7e89616..4ed2f35 100644 --- a/Library/Application/KTDataQueueProcessor.hh +++ b/Library/Application/KTDataQueueProcessor.hh @@ -46,7 +46,7 @@ namespace Nymph class KTDataQueueProcessorTemplate : public KTPrimaryProcessor { public: - typedef void (XProcessorType::*FuncPtrType)(KTDataPtr, KTDataPtrReturn&, KTProcessorToolbox::ThreadPacket&); + typedef void (XProcessorType::*FuncPtrType)(KTDataPtr); struct DataAndFunc { @@ -93,13 +93,13 @@ namespace Nymph //********* public: /// Begins processing of queue (switches status from kStopped to kRunning) - bool Run( KTDataPtrReturn& ret, KTProcessorToolbox::ThreadPacket& threadPacket ); + bool Run(); /// Stops processing of queue (switches status to kStopped) void Stop(); /// Begins processing of queue if status is already kRunning; otherwise does nothing. - bool ProcessQueue( KTDataPtrReturn& ret, KTProcessorToolbox::ThreadPacket& threadPacket ); + bool ProcessQueue(); void ClearQueue(); @@ -113,11 +113,11 @@ namespace Nymph protected: /// Queue an data object with a provided function /// Assumes ownership of the data; original shared pointer will be nullified - void DoQueueData(KTDataPtr& data, KTDataPtrReturn& ret, KTProcessorToolbox::ThreadPacket& threadPacket, FuncPtrType func); + void DoQueueData(KTDataPtr& data, FuncPtrType func); /// Queue an data object with fFuncPtr /// Assumes ownership of the data; original shared pointer will be nullified - void DoQueueData(KTDataPtr& data, KTDataPtrReturn& ret, KTProcessorToolbox::ThreadPacket& threadPacket); + void DoQueueData(KTDataPtr& data); /// Queue a list of data objects /// Assumes ownership of all data objects and the list; original shared pointers will be nullified @@ -174,7 +174,7 @@ namespace Nymph bool ConfigureSubClass(const scarab::param_node* node); public: - void EmitDataSignal(KTDataPtr data, KTDataPtrReturn& ret, KTProcessorToolbox::ThreadPacket& threadPacket); + void EmitDataSignal(KTDataPtr data); //*************** // Signals @@ -189,7 +189,8 @@ namespace Nymph public: /// Queue an data object; will emit data signal /// Assumes ownership of the data; original shared pointer will be nullified - void QueueData(KTDataPtr& data, KTDataPtrReturn& ret, KTProcessorToolbox::ThreadPacket& threadPacket); + void QueueData(KTDataPtr& data); + KTSlotWrapper* fQueueDataSW; /// Queue a list of data objects; will emit data signal /// Assumes ownership of all data objects and the list; original shared pointers will be nullified @@ -233,11 +234,11 @@ namespace Nymph } template< class XProcessorType > - bool KTDataQueueProcessorTemplate< XProcessorType >::Run( std::promise< KTDataPtr >& ret, KTProcessorToolbox::ThreadPacket& threadPacket ) + bool KTDataQueueProcessorTemplate< XProcessorType >::Run() { fStatus = kRunning; KTINFO(eqplog, "Queue started"); - return ProcessQueue( ret, threadPacket ); + return ProcessQueue(); } template< class XProcessorType > @@ -258,7 +259,7 @@ namespace Nymph template< class XProcessorType > - bool KTDataQueueProcessorTemplate< XProcessorType >::ProcessQueue( KTDataPtrReturn& ret, KTProcessorToolbox::ThreadPacket& threadPacket ) + bool KTDataQueueProcessorTemplate< XProcessorType >::ProcessQueue() { KTINFO(eqplog, "Beginning to process queue"); while (fStatus != kStopped) @@ -268,7 +269,7 @@ namespace Nymph if ((fQueue.*fPopFromQueue)(daf)) { KTDEBUG(eqplog, "Data acquired for processing"); - (static_cast(this)->*(daf.fFuncPtr))(daf.fData, ret, threadPacket); + (static_cast(this)->*(daf.fFuncPtr))(daf.fData); if (daf.fData->GetLastData()) fStatus = kStopped; } else @@ -302,7 +303,7 @@ namespace Nymph template< class XProcessorType > - void KTDataQueueProcessorTemplate< XProcessorType >::DoQueueData(KTDataPtr& data, KTDataPtrReturn& ret, KTProcessorToolbox::ThreadPacket& threadPacket, FuncPtrType func) + void KTDataQueueProcessorTemplate< XProcessorType >::DoQueueData(KTDataPtr& data, FuncPtrType func) { KTDEBUG(eqplog, "Queueing data"); DataAndFunc daf; @@ -314,9 +315,9 @@ namespace Nymph } template< class XProcessorType > - void KTDataQueueProcessorTemplate< XProcessorType >::DoQueueData(KTDataPtr& data, KTDataPtrReturn& ret, KTProcessorToolbox::ThreadPacket& threadPacket) + void KTDataQueueProcessorTemplate< XProcessorType >::DoQueueData(KTDataPtr& data) { - DoQueueData(data, ret, threadPacket, &fFuncPtr); + DoQueueData(data, &fFuncPtr); return; } /* diff --git a/Library/Application/KTPrintDataStructure.cc b/Library/Application/KTPrintDataStructure.cc index ec19d62..438b6a2 100644 --- a/Library/Application/KTPrintDataStructure.cc +++ b/Library/Application/KTPrintDataStructure.cc @@ -23,9 +23,9 @@ namespace Nymph KTPrintDataStructure::KTPrintDataStructure(const std::string& name) : KTProcessor(name), fDataSignal("data", this), - fDataStructSlot("print-data", this, &KTPrintDataStructure::PrintDataStructure), - fCutStructSlot("print-cuts", this, &KTPrintDataStructure::PrintCutStructure), - fDataAndCutStructSlot("print-data-and-cuts", this, &KTPrintDataStructure::PrintDataAndCutStructure) + fDataStructSlot("print-data", this, &KTPrintDataStructure::PrintDataStructure, {"data"}), + fCutStructSlot("print-cuts", this, &KTPrintDataStructure::PrintCutStructure, {"data"}), + fDataAndCutStructSlot("print-data-and-cuts", this, &KTPrintDataStructure::PrintDataAndCutStructure, {"data"}) { } @@ -38,36 +38,42 @@ namespace Nymph return true; } - void KTPrintDataStructure::PrintDataStructure(KTDataPtr dataPtr, KTDataPtrReturn& ret, KTProcessorToolbox::ThreadPacket& threadPacket) + void KTPrintDataStructure::PrintDataStructure(KTDataPtr dataPtr) { - DoPrintDataStructure(dataPtr, ret, threadPacket); + DoPrintDataStructure(dataPtr); - fDataSignal(dataPtr, ret, threadPacket); + fDataStructSlot.GetSlotWrapper()->GetThreadRef()->Break( dataPtr ); + + fDataSignal(dataPtr); return; } - void KTPrintDataStructure::PrintCutStructure(KTDataPtr dataPtr, KTDataPtrReturn& ret, KTProcessorToolbox::ThreadPacket& threadPacket) + void KTPrintDataStructure::PrintCutStructure(KTDataPtr dataPtr) { - DoPrintCutStructure(dataPtr, ret, threadPacket); + DoPrintCutStructure(dataPtr); + + fCutStructSlot.GetSlotWrapper()->GetThreadRef()->Break( dataPtr ); - fDataSignal(dataPtr, ret, threadPacket); + fDataSignal(dataPtr); return; } - void KTPrintDataStructure::PrintDataAndCutStructure(KTDataPtr dataPtr, KTDataPtrReturn& ret, KTProcessorToolbox::ThreadPacket& threadPacket) + void KTPrintDataStructure::PrintDataAndCutStructure(KTDataPtr dataPtr) { - DoPrintDataStructure(dataPtr, ret, threadPacket); - DoPrintCutStructure(dataPtr, ret, threadPacket); + DoPrintDataStructure(dataPtr); + DoPrintCutStructure(dataPtr); + + fDataAndCutStructSlot.GetSlotWrapper()->GetThreadRef()->Break( dataPtr ); - fDataSignal(dataPtr, ret, threadPacket); + fDataSignal(dataPtr); return; } - void KTPrintDataStructure::DoPrintDataStructure(KTDataPtr dataPtr, KTDataPtrReturn&, KTProcessorToolbox::ThreadPacket& threadPacket) + void KTPrintDataStructure::DoPrintDataStructure(KTDataPtr dataPtr) { std::stringstream printbuf; @@ -87,7 +93,7 @@ namespace Nymph return; } - void KTPrintDataStructure::DoPrintCutStructure(KTDataPtr dataPtr, KTDataPtrReturn&, KTProcessorToolbox::ThreadPacket& threadPacket) + void KTPrintDataStructure::DoPrintCutStructure(KTDataPtr dataPtr) { std::stringstream printbuf; diff --git a/Library/Application/KTPrintDataStructure.hh b/Library/Application/KTPrintDataStructure.hh index 8928600..77375fd 100644 --- a/Library/Application/KTPrintDataStructure.hh +++ b/Library/Application/KTPrintDataStructure.hh @@ -52,13 +52,13 @@ namespace Nymph bool Configure(const scarab::param_node* node); public: - void PrintDataStructure(KTDataPtr dataPtr, KTDataPtrReturn& ret, KTProcessorToolbox::ThreadPacket& threadPacket); - void PrintCutStructure(KTDataPtr dataPtr, KTDataPtrReturn& ret, KTProcessorToolbox::ThreadPacket& threadPacket); - void PrintDataAndCutStructure(KTDataPtr dataPtr, KTDataPtrReturn& ret, KTProcessorToolbox::ThreadPacket& threadPacket); + void PrintDataStructure(KTDataPtr dataPtr); + void PrintCutStructure(KTDataPtr dataPtr); + void PrintDataAndCutStructure(KTDataPtr dataPtr); private: - void DoPrintDataStructure(KTDataPtr dataPtr, KTDataPtrReturn& ret, KTProcessorToolbox::ThreadPacket& threadPacket); - void DoPrintCutStructure(KTDataPtr dataPtr, KTDataPtrReturn& ret, KTProcessorToolbox::ThreadPacket& threadPacket); + void DoPrintDataStructure(KTDataPtr dataPtr); + void DoPrintCutStructure(KTDataPtr dataPtr); //*************** // Signals @@ -72,9 +72,9 @@ namespace Nymph //*************** private: - KTSlot< void, KTDataPtr, KTDataPtrReturn& > fDataStructSlot; - KTSlot< void, KTDataPtr, KTDataPtrReturn& > fCutStructSlot; - KTSlot< void, KTDataPtr, KTDataPtrReturn& > fDataAndCutStructSlot; + KTSlot< void, KTDataPtr > fDataStructSlot; + KTSlot< void, KTDataPtr > fCutStructSlot; + KTSlot< void, KTDataPtr > fDataAndCutStructSlot; }; } diff --git a/Library/Application/KTProcessorToolbox.cc b/Library/Application/KTProcessorToolbox.cc index efae329..e48014e 100644 --- a/Library/Application/KTProcessorToolbox.cc +++ b/Library/Application/KTProcessorToolbox.cc @@ -36,7 +36,7 @@ namespace Nymph fRunQueue(), fProcMap(), fThreadFutures(), - fThreadPackets(), + //fThreadPackets(), fContinueSignaler(), fMasterContSignal(), fBreakContMutex(), @@ -504,7 +504,7 @@ namespace Nymph { std::string procName( tgIter->fName ); KTINFO( proclog, "Starting processor <" << procName << ">" ); - +/* KTDataPtrReturn dataRet; fThreadFutures.push_back( dataRet.get_future() ); if( ! fThreadFutures.back().valid() ) @@ -512,14 +512,29 @@ namespace Nymph KTERROR( proclog, "Invalid thread future created" ); throw std::future_error( std::future_errc::no_state ); } +*/ + KTThreadReference thisThreadRef; + + fThreadFutures.push_back( thisThreadRef.fDataPtrRet.get_future() ); + if( ! fThreadFutures.back().valid() ) + { + KTERROR( proclog, "Invalid thread future created" ); + throw std::future_error( std::future_errc::no_state ); + } + + fThreadIndicators.push_back( KTThreadIndicator() ); + fThreadIndicators.back().fBreakFlag = false; + fThreadIndicators.back().fContinueSignal = fMasterContSignal; - fThreadPackets.push_back( ThreadPacket() ); - fThreadPackets.back().fProcTB = this; - fThreadPackets.back().fContinueSignal = fMasterContSignal; + thisThreadRef.fThreadIndicator = &fThreadIndicators.back(); + thisThreadRef.fProcTB = this; - std::thread thread( &KTPrimaryProcessor::operator(), tgIter->fProc, std::move( dataRet ), fThreadPackets.back() ); + //std::thread thread( &KTPrimaryProcessor::operator(), tgIter->fProc, std::move( dataRet ), fThreadPackets.back() ); + tgIter->fProc->SetThreadRef( std::move( thisThreadRef ) ); + std::thread thread( &KTPrimaryProcessor::operator(), tgIter->fProc ); + tgIter->fProc->GetThreadRef()->fThread = &thread; - KTDEBUG( proclog, "Thread ID is <" << fThreadPackets.back().fThread->get_id() << ">" ); + KTDEBUG( proclog, "Thread ID is <" << thread.get_id() << ">" ); bool stillRunning = true; // determines behavior that depends on whether a return from the thread was temporary or from the thread completing do @@ -531,7 +546,7 @@ namespace Nymph } while (status != std::future_status::ready); stillRunning = false; - if( fThreadPackets.back().fBreakFlag ) + if( fThreadIndicators.back().fBreakFlag ) { KTDEBUG( proclog, "Breakpoint reached" ); continueSignal.wait(); @@ -641,9 +656,9 @@ namespace Nymph // reset all break flags fDoRunBreakFlag = false; - for( std::vector< ThreadPacket >::iterator tpIt = fThreadPackets.begin(); tpIt != fThreadPackets.end(); ++tpIt ) + for( std::vector< KTThreadIndicator >::iterator tiIt = fThreadIndicators.begin(); tiIt != fThreadIndicators.end(); ++tiIt ) { - tpIt->fBreakFlag = false; + tiIt->fBreakFlag = false; } KTINFO( proclog, "Continuing from breakpoint" ); @@ -653,9 +668,9 @@ namespace Nymph // reset the signaler and all signals // hopefull the delay of creating the new signaler and starting the for loop is enough that anything waiting on the old signal has already seen that signal and moved on fContinueSignaler = std::promise< void >(); - for( std::vector< ThreadPacket >::iterator tpIt = fThreadPackets.begin(); tpIt != fThreadPackets(); ++tpIt ) + for( std::vector< KTThreadIndicator >::iterator tiIt = fThreadIndicators.begin(); tiIt != fThreadIndicators(); ++tiIt ) { - tpIt->fContinueSignal = fContinueSignaler.get_future(); + tiIt->fContinueSignal = fContinueSignaler.get_future(); } return; @@ -667,9 +682,9 @@ namespace Nymph // set all break flags fDoRunBreakFlag = true; - for( std::vector< ThreadPacket >::iterator tpIt = fThreadPackets.begin(); tpIt != fThreadPackets.end(); ++tpIt ) + for( std::vector< KTThreadIndicator >::iterator tiIt = fThreadIndicators.begin(); tiIt != fThreadIndicators.end(); ++tiIt ) { - tpIt->fBreakFlag = true; + tiIt->fBreakFlag = true; } return; diff --git a/Library/Application/KTProcessorToolbox.hh b/Library/Application/KTProcessorToolbox.hh index e29c15b..9c1cbb1 100644 --- a/Library/Application/KTProcessorToolbox.hh +++ b/Library/Application/KTProcessorToolbox.hh @@ -179,7 +179,7 @@ namespace Nymph RunQueue fRunQueue; public: - struct ThreadPacket +/* struct ThreadPacket { KTProcessorToolbox* fProcTB; bool fBreakFlag; // only use outside of blocks protected by fBreakContMutex are reads, so we shouldn't need to make this an atomic @@ -189,7 +189,7 @@ namespace Nymph void Break( const KTDataPtr& dataPtr, KTDataPtrReturn& ret ) { bool breakInititatedHere = false; - if( /* breakpoint is set here */ false ) + if( /* breakpoint is set here *//* false ) { breakInititatedHere = true; fProcTB->InitiateBreak(); @@ -204,7 +204,7 @@ namespace Nymph return; } }; - +*/ /// Process the run queue. /// This will call Run() on all of the processors in the queue. bool Run(); @@ -227,7 +227,7 @@ namespace Nymph void TakeFuture( std::future< KTDataPtr > future ); std::vector< std::future< KTDataPtr > > fThreadFutures; - std::vector< ThreadPacket > fThreadPackets; + std::vector< KTThreadIndicator > fThreadIndicators; std::promise< void > fContinueSignaler; std::shared_future< void > fMasterContSignal; diff --git a/Library/CMakeLists.txt b/Library/CMakeLists.txt index ad41bec..6ef9eee 100644 --- a/Library/CMakeLists.txt +++ b/Library/CMakeLists.txt @@ -35,6 +35,7 @@ set( NYMPH_HEADERFILES ${PROC_DIR}/KTSignalWrapper.hh ${PROC_DIR}/KTSlot.hh ${PROC_DIR}/KTSlotWrapper.hh + ${PROC_DIR}/KTThreadReference.hh ${IO_DIR}/KTReader.hh ${IO_DIR}/KTWriter.hh ${APPL_DIR}/KTApplication.hh @@ -66,6 +67,7 @@ set( NYMPH_SOURCEFILES ${PROC_DIR}/KTProcessor.cc ${PROC_DIR}/KTSignalWrapper.cc ${PROC_DIR}/KTSlotWrapper.cc + ${PROC_DIR}/KTThreadReference.cc ${IO_DIR}/KTReader.cc ${IO_DIR}/KTWriter.cc ${APPL_DIR}/KTApplication.cc diff --git a/Library/Data/KTApplyCut.cc b/Library/Data/KTApplyCut.cc index b34f0a5..8952288 100644 --- a/Library/Data/KTApplyCut.cc +++ b/Library/Data/KTApplyCut.cc @@ -25,7 +25,7 @@ namespace Nymph fAfterCutPassSignal("pass", this), fAfterCutFailSignal("fail", this) { - RegisterSlot("apply", this, &KTApplyCut::ApplyCut); + fApplyCutSW = RegisterSlot("apply", this, &KTApplyCut::ApplyCut, {"all", "pass", "fail"}); } KTApplyCut::~KTApplyCut() @@ -83,25 +83,29 @@ namespace Nymph } - void KTApplyCut::ApplyCut(KTDataPtr dataPtr, KTDataPtrReturn ret, KTProcessorToolbox::ThreadPacket& threadPacket) + void KTApplyCut::ApplyCut(KTDataPtr dataPtr) { + KTThreadReference* ref = fApplyCutSW->GetThreadRef(); + if (fCut == NULL) { - ret.set_exception( std::make_exception_ptr( KTException() << "No cut was specified" ) ); + ref->fDataPtrRet.set_exception( std::make_exception_ptr( KTException() << "No cut was specified" ) ); return; } bool cutFailed = fCut->Apply(dataPtr); + ref->Break( dataPtr ); + if (cutFailed) { - fAfterCutFailSignal(dataPtr, ret, threadPacket); + fAfterCutFailSignal(dataPtr); } else { - fAfterCutPassSignal(dataPtr, ret, threadPacket); + fAfterCutPassSignal(dataPtr); } - fAfterCutSignal(dataPtr, ret, threadPacket); + fAfterCutSignal(dataPtr); return; } diff --git a/Library/Data/KTApplyCut.hh b/Library/Data/KTApplyCut.hh index 235afcf..79be604 100644 --- a/Library/Data/KTApplyCut.hh +++ b/Library/Data/KTApplyCut.hh @@ -67,7 +67,7 @@ namespace Nymph KTCut* fCut; public: - void ApplyCut(KTDataPtr dataPtr, KTDataPtrReturn ret, KTProcessorToolbox::ThreadPacket& threadPacket); + void ApplyCut(KTDataPtr dataPtr); //*************** @@ -83,6 +83,8 @@ namespace Nymph // Slots //*************** + KTSlotWrapper* fApplyCutSW; + private: }; diff --git a/Library/Data/KTCutFilter.cc b/Library/Data/KTCutFilter.cc index 6e04137..979e25d 100644 --- a/Library/Data/KTCutFilter.cc +++ b/Library/Data/KTCutFilter.cc @@ -28,7 +28,7 @@ namespace Nymph fAfterCutPassSignal("pass", this), fAfterCutFailSignal("fail", this) { - RegisterSlot("filter", this, &KTCutFilter::FilterData); + fFilterDataSW = RegisterSlot("filter", this, &KTCutFilter::FilterData, {"all", "pass", "fail"}); } KTCutFilter::~KTCutFilter() @@ -74,18 +74,25 @@ namespace Nymph return cutStatus.IsCut(fCutMask); } - void KTCutFilter::FilterData(KTDataPtr dataPtr, KTDataPtrReturn& ret, KTProcessorToolbox::ThreadPacket& threadPacket) + void KTCutFilter::FilterData(KTDataPtr dataPtr) { + KTThreadReference* ref = fFilterDataSW->GetThreadRef(); + // all KTDataPtr's have KTData, so we won't bother checking - if (Filter(dataPtr->Of< KTData >())) + + bool failCut = Filter(dataPtr->Of< KTData >()); + + ref->Break( dataPtr ); + + if (failCut) { - fAfterCutFailSignal(dataPtr, ret, threadPacket); + fAfterCutFailSignal(dataPtr); } else { - fAfterCutPassSignal(dataPtr, ret, threadPacket); + fAfterCutPassSignal(dataPtr); } - fAfterCutSignal(dataPtr, ret, threadPacket); + fAfterCutSignal(dataPtr); return; } diff --git a/Library/Data/KTCutFilter.hh b/Library/Data/KTCutFilter.hh index 74d94cc..89522b4 100644 --- a/Library/Data/KTCutFilter.hh +++ b/Library/Data/KTCutFilter.hh @@ -80,7 +80,7 @@ namespace Nymph public: bool Filter(KTData& data); - void FilterData(KTDataPtr dataPtr, KTDataPtrReturn& ret, KTProcessorToolbox::ThreadPacket& threadPacket); + void FilterData(KTDataPtr dataPtr); //*************** @@ -96,6 +96,8 @@ namespace Nymph // Slots //*************** + KTSlotWrapper* fFilterDataSW; + private: }; diff --git a/Library/Processor/KTPrimaryProcessor.hh b/Library/Processor/KTPrimaryProcessor.hh index 596246c..39e0364 100644 --- a/Library/Processor/KTPrimaryProcessor.hh +++ b/Library/Processor/KTPrimaryProcessor.hh @@ -31,7 +31,8 @@ namespace Nymph /// Starts the main action of the processor virtual bool Run() = 0; - void SetThreadReference( KTThreadReference&& ref ); + void SetThreadRef( KTThreadReference&& ref ); + KTThreadReference* GetThreadRef(); protected: KTThreadReference fThreadRef; @@ -39,11 +40,16 @@ namespace Nymph }; - inline void KTPrimaryProcessor::SetThreadReference( KTThreadReference&& ref ) + inline void KTPrimaryProcessor::SetThreadRef( KTThreadReference&& ref ) { fThreadRef = ref; return; } + inline KTThreadReference* KTPrimaryProcessor::GetThreadRef() + { + return &fThreadRef; + } + } /* namespace Nymph */ #endif /* KTPRIMARYPROCESSOR_HH_ */ diff --git a/Library/Processor/KTProcessor.cc b/Library/Processor/KTProcessor.cc index 4a62d9d..c6a5a6a 100644 --- a/Library/Processor/KTProcessor.cc +++ b/Library/Processor/KTProcessor.cc @@ -48,6 +48,9 @@ namespace Nymph void KTProcessor::PassThreadRefUpdate(const std::string& slotName, KTThreadReference* threadRef) { + // update the thread reference pointer for this slot + GetSlot(slotName)->SetThreadRef(threadRef); + // get the list of slot-to-signal connections for this slot auto stsRange = fSlotToSigMap.equal_range(slotName); @@ -58,10 +61,8 @@ namespace Nymph auto sigConnRange = fSigConnMap.equal_range(stsIt->second); for (SigConnMapCIt sigConnIt = sigConnRange.first; sigConnIt != sigConnRange.second; ++sigConnIt) { - // update the thread reference pointer for this connection - sigConnIt->second.fThreadRef = threadRef; // pass the update on to the connected-to processor - sigConnIt->second.fProc->PassThreadRefUpdate(sigConnIt->second.fSlotName, threadRef); + sigConnIt->second.first->PassThreadRefUpdate(sigConnIt->second.second, threadRef); } } } diff --git a/Library/Processor/KTSlot.hh b/Library/Processor/KTSlot.hh index f547d4d..ad6de31 100644 --- a/Library/Processor/KTSlot.hh +++ b/Library/Processor/KTSlot.hh @@ -53,6 +53,8 @@ namespace Nymph const std::string& GetName() const; + KTSlotWrapper* GetSlotWrapper(); + protected: std::string fName; KTSlotWrapper* fSlotWrapper; @@ -228,11 +230,17 @@ namespace Nymph } template< typename ReturnType, typename... Args > - const std::string& KTSlot< ReturnType, Args... >::GetName() const + inline const std::string& KTSlot< ReturnType, Args... >::GetName() const { return fName; } + template< typename ReturnType, typename... Args > + inline KTSlotWrapper* KTSlot< ReturnType, Args... >::GetSlotWrapper() + { + return fSlotWrapper; + } + // KTSlotData template< class... XDataTypes > diff --git a/Library/Processor/KTSlotWrapper.hh b/Library/Processor/KTSlotWrapper.hh index a020d11..675d570 100644 --- a/Library/Processor/KTSlotWrapper.hh +++ b/Library/Processor/KTSlotWrapper.hh @@ -88,7 +88,7 @@ namespace Nymph KTConnection fConnection; public: - KTThreadReference* GetThreadRef(); + KTThreadReference* GetThreadRef() const; void SetThreadRef(KTThreadReference* ref); private: @@ -121,7 +121,7 @@ namespace Nymph return; } - inline KTThreadReference* KTSlotWrapper::GetThreadRef() + inline KTThreadReference* KTSlotWrapper::GetThreadRef() const { return fThreadRef; } diff --git a/Library/Processor/KTThreadReference.cc b/Library/Processor/KTThreadReference.cc index c62a3a9..a05256e 100644 --- a/Library/Processor/KTThreadReference.cc +++ b/Library/Processor/KTThreadReference.cc @@ -10,19 +10,6 @@ namespace Nymph { - KTThreadReference::KTThreadReference() : - fDataPtrRet(), - fProcTB( nullptr ), - fBreakFlag( false ), - fContinueSignal(), - fThread( nullptr ) - { - } - - KTThreadReference::~KTThreadReference() - { - } - void KTThreadReference::Break( const KTDataPtr& dataPtr ) { bool breakInititatedHere = false; @@ -31,10 +18,10 @@ namespace Nymph breakInititatedHere = true; fProcTB->InitiateBreak(); } - if( fBreakFlag || breakInititatedHere ) + if( fThreadIndicator->fBreakFlag || breakInititatedHere ) { fDataPtrRet.set_value( dataPtr ); - fContinueSignal.wait(); + fThreadIndicator->fContinueSignal.wait(); fDataPtrRet = KTDataPtrReturn(); fProcTB->TakeFuture( fDataPtrRet.get_future() ); } diff --git a/Library/Processor/KTThreadReference.hh b/Library/Processor/KTThreadReference.hh index 06d65ce..955544f 100644 --- a/Library/Processor/KTThreadReference.hh +++ b/Library/Processor/KTThreadReference.hh @@ -16,13 +16,18 @@ namespace Nymph { class KTProcessorToolbox; + struct KTThreadIndicator + { + bool fBreakFlag; // only use outside of blocks protected by a mutex are reads, so we shouldn't need to make this an atomic + std::shared_future< void > fContinueSignal; + }; + struct KTThreadReference { KTDataPtrReturn fDataPtrRet; KTProcessorToolbox* fProcTB; - bool fBreakFlag; // only use outside of blocks protected by fBreakContMutex are reads, so we shouldn't need to make this an atomic - std::shared_future< void > fContinueSignal; std::thread* fThread; + KTThreadIndicator* fThreadIndicator; void Break( const KTDataPtr& dataPtr ); }; diff --git a/Scarab b/Scarab index 1371810..7ee4812 160000 --- a/Scarab +++ b/Scarab @@ -1 +1 @@ -Subproject commit 137181089541410fd165a255765a833fce9688c9 +Subproject commit 7ee4812376649615f4cf97412c338201dd43e321 From 0cba7d25409e1d955569cdc25b7a77f51b5d4789 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Thu, 4 May 2017 09:58:08 -0700 Subject: [PATCH 008/521] Minor fixes to get things compiling --- Library/Application/KTDataQueueProcessor.cc | 2 +- Library/Application/KTDataQueueProcessor.hh | 8 ++--- Library/Application/KTProcessorToolbox.cc | 9 +++--- Library/Application/KTProcessorToolbox.hh | 10 ++++-- Library/Application/KTThroughputProfiler.cc | 10 +++--- Library/Application/KTThroughputProfiler.hh | 4 +-- Library/Processor/KTPrimaryProcessor.hh | 2 +- Library/Processor/KTThreadReference.cc | 35 +++++++++++++++++++++ Library/Processor/KTThreadReference.hh | 7 +++++ 9 files changed, 67 insertions(+), 20 deletions(-) diff --git a/Library/Application/KTDataQueueProcessor.cc b/Library/Application/KTDataQueueProcessor.cc index 237f4b2..ceaaef0 100644 --- a/Library/Application/KTDataQueueProcessor.cc +++ b/Library/Application/KTDataQueueProcessor.cc @@ -18,7 +18,7 @@ namespace Nymph fDataSignal("data", this) { SetFuncPtr(&KTDataQueueProcessor::EmitDataSignal); - fQueueDataSW = RegisterSlot("data", this, &KTDataQueueProcessor::QueueData); + fQueueDataSW = RegisterSlot("data", this, &KTDataQueueProcessor::QueueData, {}); //RegisterSlot("data-list", this, &KTDataQueueProcessor::QueueDataList); } diff --git a/Library/Application/KTDataQueueProcessor.hh b/Library/Application/KTDataQueueProcessor.hh index 4ed2f35..a0ef2b5 100644 --- a/Library/Application/KTDataQueueProcessor.hh +++ b/Library/Application/KTDataQueueProcessor.hh @@ -213,9 +213,9 @@ namespace Nymph fPopFromQueue(&KTConcurrentQueue< DataAndFunc >::wait_and_pop), fQueueDoneSignal("queue-done", this) { - RegisterSlot("use-timed-pop", this, &KTDataQueueProcessorTemplate< XProcessorType >::SwitchToTimedPop); - RegisterSlot("use-untimed-pop", this, &KTDataQueueProcessorTemplate< XProcessorType >::SwitchToUntimedPop); - RegisterSlot("use-single-pop", this, &KTDataQueueProcessorTemplate< XProcessorType >::SwitchToSinglePop); + RegisterSlot("use-timed-pop", this, &KTDataQueueProcessorTemplate< XProcessorType >::SwitchToTimedPop, {}); + RegisterSlot("use-untimed-pop", this, &KTDataQueueProcessorTemplate< XProcessorType >::SwitchToUntimedPop, {}); + RegisterSlot("use-single-pop", this, &KTDataQueueProcessorTemplate< XProcessorType >::SwitchToSinglePop, {}); } template< class XProcessorType > @@ -317,7 +317,7 @@ namespace Nymph template< class XProcessorType > void KTDataQueueProcessorTemplate< XProcessorType >::DoQueueData(KTDataPtr& data) { - DoQueueData(data, &fFuncPtr); + DoQueueData(data, fFuncPtr); return; } /* diff --git a/Library/Application/KTProcessorToolbox.cc b/Library/Application/KTProcessorToolbox.cc index e48014e..37d9150 100644 --- a/Library/Application/KTProcessorToolbox.cc +++ b/Library/Application/KTProcessorToolbox.cc @@ -7,6 +7,7 @@ #include "KTProcessorToolbox.hh" +#include "KTException.hh" #include "KTLogger.hh" #include "KTPrimaryProcessor.hh" @@ -487,7 +488,7 @@ namespace Nymph { // reset the continue signaler fContinueSignaler = std::promise< void >(); - fMasterContSignal( fContinueSignaler.get_future() ); + fMasterContSignal = fContinueSignaler.get_future(); if( ! fMasterContSignal.valid() ) { KTERROR( proclog, "Invalid master continue-signal created" ); @@ -666,9 +667,9 @@ namespace Nymph fContinueSignaler.set_value(); // reset the signaler and all signals - // hopefull the delay of creating the new signaler and starting the for loop is enough that anything waiting on the old signal has already seen that signal and moved on - fContinueSignaler = std::promise< void >(); - for( std::vector< KTThreadIndicator >::iterator tiIt = fThreadIndicators.begin(); tiIt != fThreadIndicators(); ++tiIt ) + // hopefully the delay of creating the new signaler and starting the for loop is enough that anything waiting on the old signal has already seen that signal and moved on + fContinueSignaler = std::move( std::promise< void >() ); + for( std::vector< KTThreadIndicator >::iterator tiIt = fThreadIndicators.begin(); tiIt != fThreadIndicators.end(); ++tiIt ) { tiIt->fContinueSignal = fContinueSignaler.get_future(); } diff --git a/Library/Application/KTProcessorToolbox.hh b/Library/Application/KTProcessorToolbox.hh index 9c1cbb1..56623b7 100644 --- a/Library/Application/KTProcessorToolbox.hh +++ b/Library/Application/KTProcessorToolbox.hh @@ -11,10 +11,12 @@ #include "KTConfigurable.hh" #include "KTMemberVariable.hh" +#include "KTThreadReference.hh" #include "factory.hh" #include +#include #include #include #include @@ -221,10 +223,12 @@ namespace Nymph void Continue(); private: + friend class KTThreadReference; + // called from ThreadPacket::Break void InitiateBreak(); // called from ThreadPacket::Break - void TakeFuture( std::future< KTDataPtr > future ); + void TakeFuture( std::future< KTDataPtr >&& future ); std::vector< std::future< KTDataPtr > > fThreadFutures; std::vector< KTThreadIndicator > fThreadIndicators; @@ -257,9 +261,9 @@ namespace Nymph return; } - inline void KTProcessorToolbox::TakeFuture( std::future< KTDataPtr > future ) + inline void KTProcessorToolbox::TakeFuture( std::future< KTDataPtr >&& future ) { - fThreadFutures.push_back( future ); + fThreadFutures.push_back( std::move( future ) ); return; } diff --git a/Library/Application/KTThroughputProfiler.cc b/Library/Application/KTThroughputProfiler.cc index 94bd66b..19e43fa 100644 --- a/Library/Application/KTThroughputProfiler.cc +++ b/Library/Application/KTThroughputProfiler.cc @@ -28,9 +28,9 @@ namespace Nymph fTimeEnd(), fNDataProcessed(0) { - RegisterSlot("start", this, &KTThroughputProfiler::StartProfiling); - RegisterSlot("data", this, &KTThroughputProfiler::Data); - RegisterSlot("stop", this, &KTThroughputProfiler::Finish); + RegisterSlot("start", this, &KTThroughputProfiler::StartProfiling, {}); + RegisterSlot("data", this, &KTThroughputProfiler::Data, {}); + RegisterSlot("stop", this, &KTThroughputProfiler::Finish, {}); }; KTThroughputProfiler::~KTThroughputProfiler() @@ -64,7 +64,7 @@ namespace Nymph return Diff(fTimeStart, fTimeEnd); } - void KTThroughputProfiler::StartProfiling(KTDataPtr header, KTDataPtrReturn&, KTProcessorToolbox::ThreadPacket&) + void KTThroughputProfiler::StartProfiling(KTDataPtr header) { KTINFO(proflog, "Profiling started"); fNDataProcessed = 0; @@ -72,7 +72,7 @@ namespace Nymph return; } - void KTThroughputProfiler::Data(KTDataPtr data, KTDataPtrReturn&, KTProcessorToolbox::ThreadPacket&) + void KTThroughputProfiler::Data(KTDataPtr data) { (void)data; fNDataProcessed++; diff --git a/Library/Application/KTThroughputProfiler.hh b/Library/Application/KTThroughputProfiler.hh index 216b3e8..afd4ea5 100644 --- a/Library/Application/KTThroughputProfiler.hh +++ b/Library/Application/KTThroughputProfiler.hh @@ -86,9 +86,9 @@ namespace Nymph void Start(); void Stop(); - void StartProfiling(KTDataPtr data, KTDataPtrReturn& ret, KTProcessorToolbox::ThreadPacket& threadPacket); + void StartProfiling(KTDataPtr data); - void Data(KTDataPtr data, KTDataPtrReturn& ret, KTProcessorToolbox::ThreadPacket& threadPacket); + void Data(KTDataPtr data); void Finish(); diff --git a/Library/Processor/KTPrimaryProcessor.hh b/Library/Processor/KTPrimaryProcessor.hh index 39e0364..4c7764e 100644 --- a/Library/Processor/KTPrimaryProcessor.hh +++ b/Library/Processor/KTPrimaryProcessor.hh @@ -42,7 +42,7 @@ namespace Nymph inline void KTPrimaryProcessor::SetThreadRef( KTThreadReference&& ref ) { - fThreadRef = ref; + fThreadRef = std::move( ref ); return; } diff --git a/Library/Processor/KTThreadReference.cc b/Library/Processor/KTThreadReference.cc index a05256e..d98918f 100644 --- a/Library/Processor/KTThreadReference.cc +++ b/Library/Processor/KTThreadReference.cc @@ -7,9 +7,44 @@ #include "KTThreadReference.hh" +#include "KTProcessorToolbox.hh" + namespace Nymph { + KTThreadReference::KTThreadReference() : + fDataPtrRet(), + fProcTB( nullptr ), + fThread( nullptr ), + fThreadIndicator( nullptr ) + {} + + KTThreadReference::KTThreadReference( KTThreadReference&& orig ) : + fDataPtrRet( std::move( orig.fDataPtrRet ) ), + fProcTB( orig.fProcTB ), + fThread( orig.fThread ), + fThreadIndicator( orig.fThreadIndicator ) + { + orig.fProcTB = nullptr; + orig.fThread = nullptr; + orig.fThreadIndicator = nullptr; + } + + KTThreadReference& KTThreadReference::operator=( KTThreadReference&& orig ) + { + fDataPtrRet = std::move( orig.fDataPtrRet ); + fProcTB = orig.fProcTB; + fThread = orig.fThread; + fThreadIndicator = orig.fThreadIndicator; + + orig.fProcTB = nullptr; + orig.fThread = nullptr; + orig.fThreadIndicator = nullptr; + + return *this; + } + + void KTThreadReference::Break( const KTDataPtr& dataPtr ) { bool breakInititatedHere = false; diff --git a/Library/Processor/KTThreadReference.hh b/Library/Processor/KTThreadReference.hh index 955544f..a29c479 100644 --- a/Library/Processor/KTThreadReference.hh +++ b/Library/Processor/KTThreadReference.hh @@ -29,6 +29,13 @@ namespace Nymph std::thread* fThread; KTThreadIndicator* fThreadIndicator; + KTThreadReference(); + KTThreadReference( const KTThreadReference& ) = delete; + KTThreadReference( KTThreadReference&& orig ); + + KTThreadReference& operator=( const KTThreadReference& ) = delete; + KTThreadReference& operator=( KTThreadReference&& ); + void Break( const KTDataPtr& dataPtr ); }; From 01c7752592fd798013df12c748530d18333ba695 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Thu, 4 May 2017 10:30:37 -0700 Subject: [PATCH 009/521] Switched Nymph logger to use the Scarab logger --- Executables/Validation/TestLogger.cc | 3 +- Library/CMakeLists.txt | 1 - Library/Utility/KTLogger.cc | 195 -------------- Library/Utility/KTLogger.hh | 365 ++------------------------- 4 files changed, 24 insertions(+), 540 deletions(-) delete mode 100644 Library/Utility/KTLogger.cc diff --git a/Executables/Validation/TestLogger.cc b/Executables/Validation/TestLogger.cc index 0a2e871..4190f03 100644 --- a/Executables/Validation/TestLogger.cc +++ b/Executables/Validation/TestLogger.cc @@ -10,14 +10,13 @@ #include #include -using namespace Nymph; - KTLOGGER(logger, "TestLogger") int main() { try { + KTTRACE(logger, "This is a TRACE message from Nymph"); KTDEBUG(logger, "This is a DEBUG message from Nymph"); KTINFO(logger, "This is an INFO message from Nymph"); KTPROG(logger, "This is a PROG message from Nymph"); diff --git a/Library/CMakeLists.txt b/Library/CMakeLists.txt index 6ef9eee..28a7e8d 100644 --- a/Library/CMakeLists.txt +++ b/Library/CMakeLists.txt @@ -56,7 +56,6 @@ set( NYMPH_SOURCEFILES ${UTIL_DIR}/KTDirectory.cc ${UTIL_DIR}/KTEventLoop.cc ${UTIL_DIR}/KTException.cc - ${UTIL_DIR}/KTLogger.cc ${UTIL_DIR}/KTTime.cc ${DATA_DIR}/KTApplyCut.cc ${DATA_DIR}/KTCut.cc diff --git a/Library/Utility/KTLogger.cc b/Library/Utility/KTLogger.cc deleted file mode 100644 index 7cc8719..0000000 --- a/Library/Utility/KTLogger.cc +++ /dev/null @@ -1,195 +0,0 @@ -/* - * KTLogger.cc - * - * Created on: Jan 21, 2014 - * Author: nsoblath - */ - -/* - * KTLogger.cc - * based on KLogger.cxx from KATRIN's Kasper - * - * Created on: 18.11.2011 - * Author: Marco Haag - */ - -#include "KTLogger.hh" - -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace std; - -namespace Nymph -{ - const string& EndColor() {static string* color = new string(KTCOLOR_PREFIX KTCOLOR_NORMAL KTCOLOR_SUFFIX); return *color;} - const string& FatalColor() {static string* color = new string(KTCOLOR_PREFIX KTCOLOR_BRIGHT KTCOLOR_SEPARATOR KTCOLOR_FOREGROUND_RED KTCOLOR_SUFFIX); return *color;} - const string& ErrorColor() {static string* color = new string(KTCOLOR_PREFIX KTCOLOR_BRIGHT KTCOLOR_SEPARATOR KTCOLOR_FOREGROUND_RED KTCOLOR_SUFFIX); return *color;} - const string& WarnColor() {static string* color = new string(KTCOLOR_PREFIX KTCOLOR_BRIGHT KTCOLOR_SEPARATOR KTCOLOR_FOREGROUND_YELLOW KTCOLOR_SUFFIX); return *color;} - const string& ProgColor() {static string* color = new string(KTCOLOR_PREFIX KTCOLOR_BRIGHT KTCOLOR_SEPARATOR KTCOLOR_FOREGROUND_BLUE KTCOLOR_SUFFIX); return *color;} - const string& InfoColor() {static string* color = new string(KTCOLOR_PREFIX KTCOLOR_BRIGHT KTCOLOR_SEPARATOR KTCOLOR_FOREGROUND_GREEN KTCOLOR_SUFFIX); return *color;} - const string& DebugColor() {static string* color = new string(KTCOLOR_PREFIX KTCOLOR_BRIGHT KTCOLOR_SEPARATOR KTCOLOR_FOREGROUND_CYAN KTCOLOR_SUFFIX); return *color;} - const string& OtherColor() {static string* color = new string(KTCOLOR_PREFIX KTCOLOR_BRIGHT KTCOLOR_SEPARATOR KTCOLOR_FOREGROUND_WHITE KTCOLOR_SUFFIX); return *color;} - - struct KTLogger::Private - { - static char sDateTimeFormat[16]; - static time_t sRawTime; - static tm* sProcessedTime; - static char sTimeBuff[512]; - static size_t getTimeAbsoluteStr() - { - time(&KTLogger::Private::sRawTime); - sProcessedTime = localtime(&KTLogger::Private::sRawTime); - return strftime(KTLogger::Private::sTimeBuff, 512, - KTLogger::Private::sDateTimeFormat, - KTLogger::Private::sProcessedTime); - } - - const char* fLogger; - bool fColored; - ELevel fThreshold; - - static const char* level2Str(ELevel level) - { - switch(level) - { - case eTrace : return "TRACE"; break; - case eDebug : return "DEBUG"; break; - case eInfo : return "INFO"; break; - case eProg : return "PROG"; break; - case eWarn : return "WARN"; break; - case eError : return "ERROR"; break; - case eFatal : return "FATAL"; break; - default : return "XXX"; - } - } - - static string level2Color(ELevel level) - { - switch(level) - { - case eTrace : return DebugColor(); break; - case eDebug : return DebugColor(); break; - case eInfo : return InfoColor(); break; - case eProg : return ProgColor(); break; - case eWarn : return WarnColor(); break; - case eError : return ErrorColor(); break; - case eFatal : return FatalColor(); break; - default : return OtherColor(); - } - } - - - void logCout(ELevel level, const string& message, const Location& loc) - { - getTimeAbsoluteStr(); - if (fColored) - { - //cout << color << KTLogger::Private::sTimeBuff << " [" << setw(5) << level << "] " << setw(16) << left << loc.fFileName << "(" << loc.fLineNumber << "): " << message << skKTEndColor << endl; - cout << Private::level2Color(level) << KTLogger::Private::sTimeBuff << " [" << setw(5) << Private::level2Str(level) << "] "; - copy(loc.fFileName.end() - std::min< int >(loc.fFileName.size(), 16), loc.fFileName.end(), ostream_iterator(cout)); - cout << "(" << loc.fLineNumber << "): "; - cout << message << EndColor() << endl; - } - else - { - //cout << KTLogger::Private::sTimeBuff << " [" << setw(5) << level << "] " << setw(16) << left << loc.fFileName << "(" << loc.fLineNumber << "): " << message << endl; - cout << KTLogger::Private::sTimeBuff << " [" << setw(5) << level << "] "; - copy(loc.fFileName.end() - std::min< int >(loc.fFileName.size(), 16), loc.fFileName.end(), ostream_iterator(cout)); - cout << "(" << loc.fLineNumber << "): "; - cout << message << endl; - } - } - - void logCerr(ELevel level, const string& message, const Location& loc) - { - getTimeAbsoluteStr(); - if (fColored) - { - //cout << color << KTLogger::Private::sTimeBuff << " [" << setw(5) << level << "] " << setw(16) << left << loc.fFileName << "(" << loc.fLineNumber << "): " << message << skKTEndColor << endl; - cerr << Private::level2Color(level) << KTLogger::Private::sTimeBuff << " [" << setw(5) << Private::level2Str(level) << "] "; - copy(loc.fFileName.end() - std::min< int >(loc.fFileName.size(), 16), loc.fFileName.end(), ostream_iterator(cout)); - cerr << "(" << loc.fLineNumber << "): "; - cerr << message << EndColor() << endl; - } - else - { - //cout << KTLogger::Private::sTimeBuff << " [" << setw(5) << level << "] " << setw(16) << left << loc.fFileName << "(" << loc.fLineNumber << "): " << message << endl; - cerr << KTLogger::Private::sTimeBuff << " [" << setw(5) << Private::level2Str(level) << "] "; - copy(loc.fFileName.end() - std::min< int >(loc.fFileName.size(), 16), loc.fFileName.end(), ostream_iterator(cout)); - cerr << "(" << loc.fLineNumber << "): "; - cerr << message << endl; - } - } - }; - - char KTLogger::Private::sDateTimeFormat[16]; - time_t KTLogger::Private::sRawTime; - tm* KTLogger::Private::sProcessedTime; - char KTLogger::Private::sTimeBuff[512]; - - KTLogger::KTLogger(const char* name) : fPrivate(new Private()) - { - if (name == 0) - { - fPrivate->fLogger = "root"; - } - else - { - const char* logName = strrchr(name, '/') ? strrchr(name, '/') + 1 : name; - fPrivate->fLogger = logName; - } - fPrivate->fColored = true; - sprintf(KTLogger::Private::sDateTimeFormat, "%%T"); - SetLevel(eDebug); - } - - KTLogger::KTLogger(const std::string& name) : fPrivate(new Private()) - { - fPrivate->fLogger = name.c_str(); - fPrivate->fColored = true; - sprintf(KTLogger::Private::sDateTimeFormat, "%%T"); - SetLevel(eDebug); - } - - KTLogger::~KTLogger() - { - delete fPrivate; - } - - bool KTLogger::IsLevelEnabled(ELevel level) const - { - return level >= fPrivate->fThreshold; - } - - void KTLogger::SetLevel(ELevel level) const - { -#if defined(NDEBUG) && defined(STANDARD) - fPrivate->fThreshold = level >= eInfo ? level : eInfo; -#elif defined(NDEBUG) - fPrivate->fThreshold = level >= eProg ? level : eProg; -#else - fPrivate->fThreshold = level; -#endif - } - - void KTLogger::Log(ELevel level, const string& message, const Location& loc) - { - if (level >= eWarn) - { - fPrivate->logCerr(level, message, loc); - } - else - { - fPrivate->logCout(level, message, loc); - } - } -} - diff --git a/Library/Utility/KTLogger.hh b/Library/Utility/KTLogger.hh index f1fec2f..1c38ae1 100644 --- a/Library/Utility/KTLogger.hh +++ b/Library/Utility/KTLogger.hh @@ -9,352 +9,33 @@ #ifndef KTLOGGER_HH_ #define KTLOGGER_HH_ -/** - * @file - * @brief Contains the logger class and macros, based on Kasper's KLogger class. - * @date Created on: 18.11.2011 - * @author Marco Haag - * - */ - -// UTILITY MACROS - -#ifndef LOGGER_UTILITY_MACROS_ -#define LOGGER_UTILITY_MACROS_ - -#define STRINGIFY(x) #x -#define TOSTRING(x) STRINGIFY(x) -#define __FILE_LINE__ __FILE__ "(" TOSTRING(__LINE__) ")" -#define __FILENAME_LINE__ (strrchr(__FILE__, '/') ? strrchr(__FILE_LINE__, '/') + 1 : __FILE_LINE__) - -#if defined(_MSC_VER) -#if _MSC_VER >= 1300 -#define __FUNC__ __FUNCSIG__ -#endif -#else -#if defined(__GNUC__) -#define __FUNC__ __PRETTY_FUNCTION__ -#endif -#endif -#if !defined(__FUNC__) -#define __FUNC__ "" -#endif - -#define va_num_args(...) va_num_args_impl(__VA_ARGS__, 5,4,3,2,1) -#define va_num_args_impl(_1,_2,_3,_4,_5,N,...) N - -#define macro_dispatcher(func, ...) macro_dispatcher_(func, va_num_args(__VA_ARGS__)) -#define macro_dispatcher_(func, nargs) macro_dispatcher__(func, nargs) -#define macro_dispatcher__(func, nargs) func ## nargs - -#endif /* LOGGER_UTILITY_MACROS_ */ - -// COLOR DEFINITIONS -#define KTCOLOR_NORMAL "0" -#define KTCOLOR_BRIGHT "1" -#define KTCOLOR_FOREGROUND_RED "31" -#define KTCOLOR_FOREGROUND_GREEN "32" -#define KTCOLOR_FOREGROUND_YELLOW "33" -#define KTCOLOR_FOREGROUND_BLUE "34" -#define KTCOLOR_FOREGROUND_CYAN "36" -#define KTCOLOR_FOREGROUND_WHITE "37" -#define KTCOLOR_PREFIX "\033[" -#define KTCOLOR_SUFFIX "m" -#define KTCOLOR_SEPARATOR ";" - -// INCLUDES - -#include -#include -#include - -// CLASS DEFINITIONS +#include "logger.hh" -/** - * The standard Nymph namespace. +/* + * The Nymph logger is now a simple rebranding of the Scarab logger */ -namespace Nymph -{ - - /** - * The Nymph logger. - * - * The usage and syntax is inspired by log4j. logger itself uses the log4cxx library if it - * was available on the system during compiling, otherwise it falls back to std::stream. - * - * The logger output can be configured in a file specified with the environment variable - * @a LOGGER_CONFIGURATION (by default log4cxx.properties in the config directory). - * - * In most cases the following macro can be used - * to instantiate a Logger in your code: - *
      LOGGER(myLogger, "loggerName");
      - * - * This is equivalent to: - *
      static Nymph::logger myLogger("loggerName");
      - * - * For logging the following macros can be used. The source code location will then automatically - * included in the output: - * - *
      -     * KTLOG(myLogger, level, "message");
      -     * KTTRACE(myLogger, "message");
      -     * KTDEBUG(myLogger, "message");
      -     * KTINFO(myLogger, "message");
      -     * KTPROG(myLogger, "message");
      -     * KTWARN(myLogger, "message");
      -     * KTERROR(myLogger, "message");
      -     * KTFATAL(myLogger, "message");
      -     *
      -     * KTASSERT(myLogger, assertion, "message");
      -     *
      -     * KTLOG_ONCE(myLogger, level, "message");
      -     * KTTRACE_ONCE(myLogger, "message");
      -     * KTDEBUG_ONCE(myLogger, "message");
      -     * KTINFO_ONCE(myLogger, "message");
      -     * KTPROG_ONCE(myLogger, "message");
      -     * KTWARN_ONCE(myLogger, "message");
      -     * KTERROR_ONCE(myLogger, "message");
      -     * KTFATAL_ONCE(myLogger, "message");
      -     * 
      - * - */ - class KTLogger - { - public: - enum ELevel { - eTrace, eDebug, eInfo, eProg, eWarn, eError, eFatal - }; - - public: - /** - * A simple struct used by the Logger macros to pass information about the filename and line number. - * Not to be used directly by the user! - */ - struct Location { - Location(const char* const fileName = "", const char* const functionName = "", int lineNumber = -1) : - fLineNumber(lineNumber), fFileName(fileName), fFunctionName(functionName) - { } - int fLineNumber; - std::string fFileName; - std::string fFunctionName; - }; - - public: - static KTLogger& GetRootLogger() { - static KTLogger rootLogger; - return rootLogger; - } - - public: - /** - * Standard constructor assigning a name to the logger instance. - * @param name The logger name. - */ - KTLogger(const char* name = 0); - /// @overload - KTLogger(const std::string& name); - - virtual ~KTLogger(); - - /** - * Check whether a certain log-level is enabled. - * @param level The log level as string representation. - * @return - */ - bool IsLevelEnabled(ELevel level) const; - - /** - * Set a loggers minimum logging level - * @param level string identifying the log level - */ - void SetLevel(ELevel level) const; - - /** - * Log a message with the specified level. - * Use the macro LOG(logger, level, message). - * @param level The log level. - * @param message The message. - * @param loc Source code location (set automatically by the corresponding macro). - */ - void Log(ELevel level, const std::string& message, const Location& loc = Location()); - - /** - * Log a message at TRACE level. - * Use the macro TRACE(logger, message). - * @param message The message. - * @param loc Source code location (set automatically by the corresponding macro). - */ - void LogTrace(const std::string& message, const Location& loc = Location()) - { - Log(eTrace, message, loc); - } - /** - * Log a message at DEBUG level. - * Use the macro DEBUG(logger, message). - * @param message The message. - * @param loc Source code location (set automatically by the corresponding macro). - */ - void LogDebug(const std::string& message, const Location& loc = Location()) - { - Log(eDebug, message, loc); - } - /** - * Log a message at INFO level. - * Use the macro INFO(logger, message). - * @param message The message. - * @param loc Source code location (set automatically by the corresponding macro). - */ - void LogInfo(const std::string& message, const Location& loc = Location()) - { - Log(eInfo, message, loc); - } - /** - * Log a message at PROG level. - * Use the macro PROG(logger, message). - * @param message The message. - * @param loc Source code location (set automatically by the corresponding macro). - */ - void LogProg(const std::string& message, const Location& loc = Location()) - { - Log(eProg, message, loc); - } - /** - * Log a message at WARN level. - * Use the macro WARN(logger, message). - * @param message The message. - * @param loc Source code location (set automatically by the corresponding macro). - */ - void LogWarn(const std::string& message, const Location& loc = Location()) - { - Log(eWarn, message, loc); - } - /** - * Log a message at ERROR level. - * Use the macro ERROR(logger, message). - * @param message The message. - * @param loc Source code location (set automatically by the corresponding macro). - */ - void LogError(const std::string& message, const Location& loc = Location()) - { - Log(eError, message, loc); - } - /** - * Log a message at FATAL level. - * Use the macro FATAL(logger, message). - * @param message The message. - * @param loc Source code location (set automatically by the corresponding macro). - */ - void LogFatal(const std::string& message, const Location& loc = Location()) - { - Log(eFatal, message, loc); - } - - private: - struct Private; - Private* fPrivate; - }; - -} - -// PRIVATE MACROS - -#define __KTDEFAULT_LOGGER ::Nymph::KTLogger::GetRootLogger() - -#define __KTLOG_LOCATION ::Nymph::KTLogger::Location(__FILE__, __FUNC__, __LINE__) - -#define __KTLOG_LOG_4(I,L,M,O) \ - { \ - if (I.IsLevelEnabled(::Nymph::KTLogger::e##L)) { \ - static bool _sLoggerMarker = false; \ - if (!O || !_sLoggerMarker) { \ - _sLoggerMarker = true; \ - ::std::ostringstream stream; stream << M; \ - I.Log(::Nymph::KTLogger::e##L, stream.str(), __KTLOG_LOCATION); \ - } \ - } \ - } - -#define __KTLOG_LOG_3(I,L,M) __KTLOG_LOG_4(I,L,M,false) -#define __KTLOG_LOG_2(L,M) __KTLOG_LOG_4(__KTDEFAULT_LOGGER,L,M,false) -#define __KTLOG_LOG_1(M) __KTLOG_LOG_4(__KTDEFAULT_LOGGER,Debug,M,false) - -#define __KTLOG_TRACE_2(I,M) __KTLOG_LOG_4(I,Trace,M,false) -#define __KTLOG_TRACE_1(M) __KTLOG_LOG_4(__KTDEFAULT_LOGGER,Trace,M,false) - -#ifndef NDEBUG -#define __KTLOG_DEBUG_2(I,M) __KTLOG_LOG_4(I,Debug,M,false) -#define __KTLOG_DEBUG_1(M) __KTLOG_LOG_4(__KTDEFAULT_LOGGER,Debug,M,false) -#else -#define __KTLOG_DEBUG_2(I,M) __KTLOG_LOG_4(I,Debug,"",false) -#define __KTLOG_DEBUG_1(M) __KTLOG_LOG_4(__KTDEFAULT_LOGGER,Debug,"",false) -#endif - -#define __KTLOG_INFO_2(I,M) __KTLOG_LOG_4(I,Info,M,false) -#define __KTLOG_INFO_1(M) __KTLOG_LOG_4(__KTDEFAULT_LOGGER,Info,M,false) - -#define __KTLOG_PROG_2(I,M) __KTLOG_LOG_4(I,Prog,M,false) -#define __KTLOG_PROG_1(M) __KTLOG_LOG_4(__KTDEFAULT_LOGGER,Prog,M,false) - -#define __KTLOG_WARN_2(I,M) __KTLOG_LOG_4(I,Warn,M,false) -#define __KTLOG_WARN_1(M) __KTLOG_LOG_4(__KTDEFAULT_LOGGER,Warn,M,false) - -#define __KTLOG_ERROR_2(I,M) __KTLOG_LOG_4(I,Error,M,false) -#define __KTLOG_ERROR_1(M) __KTLOG_LOG_4(__KTDEFAULT_LOGGER,Error,M,false) - -#define __KTLOG_FATAL_2(I,M) __KTLOG_LOG_4(I,Fatal,M,false) -#define __KTLOG_FATAL_1(M) __KTLOG_LOG_4(__KTDEFAULT_LOGGER,Fatal,M,false) - -#define __KTLOG_ASSERT_3(I,C,M) if (!(C)) { __MTLOG_ERROR_2(I,M) } -#define __KTLOG_ASSERT_2(C,M) __KTLOG_ASSERT_3(__KTDEFAULT_LOGGER,C,M) - - -#define __KTLOG_LOG_ONCE_3(I,L,M) __KTLOG_LOG_4(I,L,M,true) -#define __KTLOG_LOG_ONCE_2(L,M) __KTLOG_LOG_4(__KTDEFAULT_LOGGER,L,M,true) -#define __KTLOG_LOG_ONCE_1(M) __KTLOG_LOG_4(__KTDEFAULT_LOGGER,Debug,M,true) - -#define __KTLOG_TRACE_ONCE_2(I,M) __KTLOG_LOG_4(I,Trace,M,true) -#define __KTLOG_TRACE_ONCE_1(M) __KTLOG_LOG_4(__KTDEFAULT_LOGGER,Trace,M,true) - -#define __KTLOG_DEBUG_ONCE_2(I,M) __KTLOG_LOG_4(I,Debug,M,true) -#define __KTLOG_DEBUG_ONCE_1(M) __KTLOG_LOG_4(__KTDEFAULT_LOGGER,Debug,M,true) - -#define __KTLOG_INFO_ONCE_2(I,M) __KTLOG_LOG_4(I,Info,M,true) -#define __KTLOG_INFO_ONCE_1(M) __KTLOG_LOG_4(__KTDEFAULT_LOGGER,Info,M,true) - -#define __KTLOG_PROG_ONCE_2(I,M) __KTLOG_LOG_4(I,Prog,M,true) -#define __KTLOG_PROG_ONCE_1(M) __KTLOG_LOG_4(__KTDEFAULT_LOGGER,Prog,M,true) - -#define __KTLOG_WARN_ONCE_2(I,M) __KTLOG_LOG_4(I,Warn,M,true) -#define __KTLOG_WARN_ONCE_1(M) __KTLOG_LOG_4(__KTDEFAULT_LOGGER,Warn,M,true) - -#define __KTLOG_ERROR_ONCE_2(I,M) __KTLOG_LOG_4(I,Error,M,true) -#define __KTLOG_ERROR_ONCE_1(M) __KTLOG_LOG_4(__KTDEFAULT_LOGGER,Error,M,true) - -#define __KTLOG_FATAL_ONCE_2(I,M) __KTLOG_LOG_4(I,Fatal,M,true) -#define __KTLOG_FATAL_ONCE_1(M) __KTLOG_LOG_4(__KTDEFAULT_LOGGER,Fatal,M,true) - // PUBLIC MACROS -#define KTLOGGER(I,K) static ::Nymph::KTLogger I(K); - -#define KTLOG(...) macro_dispatcher(__KTLOG_LOG_, __VA_ARGS__)(__VA_ARGS__) -#define KTTRACE(...) macro_dispatcher(__KTLOG_TRACE_, __VA_ARGS__)(__VA_ARGS__) -#define KTDEBUG(...) macro_dispatcher(__KTLOG_DEBUG_, __VA_ARGS__)(__VA_ARGS__) -#define KTINFO(...) macro_dispatcher(__KTLOG_INFO_, __VA_ARGS__)(__VA_ARGS__) -#define KTPROG(...) macro_dispatcher(__KTLOG_PROG_, __VA_ARGS__)(__VA_ARGS__) -#define KTWARN(...) macro_dispatcher(__KTLOG_WARN_, __VA_ARGS__)(__VA_ARGS__) -#define KTERROR(...) macro_dispatcher(__KTLOG_ERROR_, __VA_ARGS__)(__VA_ARGS__) -#define KTFATAL(...) macro_dispatcher(__KTLOG_FATAL_, __VA_ARGS__)(__VA_ARGS__) -#define KTASSERT(...) macro_dispatcher(__KTLOG_ASSERT_, __VA_ARGS__)(__VA_ARGS__) - -#define KTLOG_ONCE(...) macro_dispatcher(__KTLOG_LOG_ONCE_, __VA_ARGS__)(__VA_ARGS__) -#define KTTRACE_ONCE(...) macro_dispatcher(__KTLOG_TRACE_ONCE_, __VA_ARGS__)(__VA_ARGS__) -#define KTDEBUG_ONCE(...) macro_dispatcher(__KTLOG_DEBUG_ONCE_, __VA_ARGS__)(__VA_ARGS__) -#define KTINFO_ONCE(...) macro_dispatcher(__KTLOG_INFO_ONCE_, __VA_ARGS__)(__VA_ARGS__) -#define KTPROG_ONCE(...) macro_dispatcher(__KTLOG_PROG_ONCE_, __VA_ARGS__)(__VA_ARGS__) -#define KTWARN_ONCE(...) macro_dispatcher(__KTLOG_WARN_ONCE_, __VA_ARGS__)(__VA_ARGS__) -#define KTERROR_ONCE(...) macro_dispatcher(__KTLOG_ERROR_ONCE_, __VA_ARGS__)(__VA_ARGS__) -#define KTFATAL_ONCE(...) macro_dispatcher(__KTLOG_FATAL_ONCE_, __VA_ARGS__)(__VA_ARGS__) +#define KTLOGGER(I,K) static ::scarab::logger I(K); + +#define KTLOG(...) macro_dispatcher(__LOG_LOG_, __VA_ARGS__)(__VA_ARGS__) +#define KTTRACE(...) macro_dispatcher(__LOG_TRACE_, __VA_ARGS__)(__VA_ARGS__) +#define KTDEBUG(...) macro_dispatcher(__LOG_DEBUG_, __VA_ARGS__)(__VA_ARGS__) +#define KTINFO(...) macro_dispatcher(__LOG_INFO_, __VA_ARGS__)(__VA_ARGS__) +#define KTPROG(...) macro_dispatcher(__LOG_PROG_, __VA_ARGS__)(__VA_ARGS__) +#define KTWARN(...) macro_dispatcher(__LOG_WARN_, __VA_ARGS__)(__VA_ARGS__) +#define KTERROR(...) macro_dispatcher(__LOG_ERROR_, __VA_ARGS__)(__VA_ARGS__) +#define KTFATAL(...) macro_dispatcher(__LOG_FATAL_, __VA_ARGS__)(__VA_ARGS__) +#define KTASSERT(...) macro_dispatcher(__LOG_ASSERT_, __VA_ARGS__)(__VA_ARGS__) + +#define KTLOG_ONCE(...) macro_dispatcher(__LOG_LOG_ONCE_, __VA_ARGS__)(__VA_ARGS__) +#define KTTRACE_ONCE(...) macro_dispatcher(__LOG_TRACE_ONCE_, __VA_ARGS__)(__VA_ARGS__) +#define KTDEBUG_ONCE(...) macro_dispatcher(__LOG_DEBUG_ONCE_, __VA_ARGS__)(__VA_ARGS__) +#define KTINFO_ONCE(...) macro_dispatcher(__LOG_INFO_ONCE_, __VA_ARGS__)(__VA_ARGS__) +#define KTPROG_ONCE(...) macro_dispatcher(__LOG_PROG_ONCE_, __VA_ARGS__)(__VA_ARGS__) +#define KTWARN_ONCE(...) macro_dispatcher(__LOG_WARN_ONCE_, __VA_ARGS__)(__VA_ARGS__) +#define KTERROR_ONCE(...) macro_dispatcher(__LOG_ERROR_ONCE_, __VA_ARGS__)(__VA_ARGS__) +#define KTFATAL_ONCE(...) macro_dispatcher(__LOG_FATAL_ONCE_, __VA_ARGS__)(__VA_ARGS__) #endif /* KTLOGGER_HH_ */ From 6b2ce00085402ccf85fe4497f4cf73107622ccb0 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Thu, 4 May 2017 10:30:53 -0700 Subject: [PATCH 010/521] Minor fix to KTTestProcessor to get it to build --- Executables/Validation/KTTestProcessor.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Executables/Validation/KTTestProcessor.cc b/Executables/Validation/KTTestProcessor.cc index ad14cdf..8f1cc45 100644 --- a/Executables/Validation/KTTestProcessor.cc +++ b/Executables/Validation/KTTestProcessor.cc @@ -39,8 +39,8 @@ namespace Nymph KTTestProcessorB::KTTestProcessorB() { - RegisterSlot("first_slot", this, &KTTestProcessorB::Slot1); - RegisterSlot("second_slot", this, &KTTestProcessorB::Slot2); + RegisterSlot("first_slot", this, &KTTestProcessorB::Slot1, {}); + RegisterSlot("second_slot", this, &KTTestProcessorB::Slot2, {}); } KTTestProcessorB::~KTTestProcessorB() From 084ff010d026619db21e3126ef7ebf42067ff125 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Thu, 4 May 2017 10:51:05 -0700 Subject: [PATCH 011/521] Changed KTSlot to assume that the return type of the function is void (matching KTSignal) --- Executables/Validation/KTTestProcessor.cc | 15 ++++--- Executables/Validation/KTTestProcessor.hh | 27 ++++++++---- Executables/Validation/TestSignalsAndSlots.cc | 4 +- Library/Application/KTPrintDataStructure.hh | 6 +-- Library/Processor/KTSlot.hh | 42 +++++++++---------- 5 files changed, 50 insertions(+), 44 deletions(-) diff --git a/Executables/Validation/KTTestProcessor.cc b/Executables/Validation/KTTestProcessor.cc index 8f1cc45..101db06 100644 --- a/Executables/Validation/KTTestProcessor.cc +++ b/Executables/Validation/KTTestProcessor.cc @@ -14,9 +14,8 @@ namespace Nymph KTLOGGER(testsiglog, "KTTestProcessor") KTTestProcessorA::KTTestProcessorA() : - fTheSignal() + fTheSignal("the-signal", this) { - RegisterSignal("the_signal", &fTheSignal); } KTTestProcessorA::~KTTestProcessorA() @@ -37,10 +36,10 @@ namespace Nymph - KTTestProcessorB::KTTestProcessorB() + KTTestProcessorB::KTTestProcessorB() : + fSlot1("first-slot", this, &KTTestProcessorB::SlotFunc1, {}), + fSlot2("second-slot", this, &KTTestProcessorB::SlotFunc2, {}) { - RegisterSlot("first_slot", this, &KTTestProcessorB::Slot1, {}); - RegisterSlot("second_slot", this, &KTTestProcessorB::Slot2, {}); } KTTestProcessorB::~KTTestProcessorB() @@ -52,15 +51,15 @@ namespace Nymph return true; } - void KTTestProcessorB::Slot1(int input) + void KTTestProcessorB::SlotFunc1(int input) { KTINFO(testsiglog, "Slot1: input is " << input); return; } - void KTTestProcessorB::Slot2(int input) + void KTTestProcessorB::SlotFunc2(int input) { - KTINFO(testsiglog, "Slot2: twice input is " << 2*input); + KTINFO(testsiglog, "Slot2: twice input is " << 2 * input); return; } diff --git a/Executables/Validation/KTTestProcessor.hh b/Executables/Validation/KTTestProcessor.hh index 7756093..ed0bd93 100644 --- a/Executables/Validation/KTTestProcessor.hh +++ b/Executables/Validation/KTTestProcessor.hh @@ -10,14 +10,17 @@ #include "KTProcessor.hh" +#include "KTSignal.hh" +#include "KTSlot.hh" + namespace Nymph { + /*! + * A simple test processor that emits a signal with an integer argument + */ class KTTestProcessorA : public KTProcessor { - public: - typedef KTSignalConcept< void (int) >::signal TheSignal; - public: KTTestProcessorA(); virtual ~KTTestProcessorA(); @@ -26,11 +29,13 @@ namespace Nymph void EmitSignals(int); - //private: - TheSignal fTheSignal; + private: + KTSignal< int > fTheSignal; }; - + /*! + * A simple test procesor that has two slots with integer arguments + */ class KTTestProcessorB : public KTProcessor { public: @@ -39,9 +44,13 @@ namespace Nymph bool Configure(const scarab::param_node* node); - void Slot1(int); - void Slot2(int); - }; + void SlotFunc1(int); + void SlotFunc2(int); + + private: + KTSlot< int > fSlot1; + KTSlot< int > fSlot2; +}; } /* namespace Nymph */ diff --git a/Executables/Validation/TestSignalsAndSlots.cc b/Executables/Validation/TestSignalsAndSlots.cc index f81b6bc..e1154c6 100644 --- a/Executables/Validation/TestSignalsAndSlots.cc +++ b/Executables/Validation/TestSignalsAndSlots.cc @@ -36,8 +36,8 @@ int main() KTINFO(testsiglog, "Connecting the_signal to first_slot and second_slot"); try { - tpA.ConnectASlot("the_signal", &tpB, "first_slot", 20); - tpB.ConnectASignal(&tpA, "the_signal", "second_slot", 10); + tpA.ConnectASlot("the-signal", &tpB, "first-slot", 20); + tpB.ConnectASignal(&tpA, "the-signal", "second-slot", 10); } catch(std::exception& e) { diff --git a/Library/Application/KTPrintDataStructure.hh b/Library/Application/KTPrintDataStructure.hh index 77375fd..204ab09 100644 --- a/Library/Application/KTPrintDataStructure.hh +++ b/Library/Application/KTPrintDataStructure.hh @@ -72,9 +72,9 @@ namespace Nymph //*************** private: - KTSlot< void, KTDataPtr > fDataStructSlot; - KTSlot< void, KTDataPtr > fCutStructSlot; - KTSlot< void, KTDataPtr > fDataAndCutStructSlot; + KTSlot< KTDataPtr > fDataStructSlot; + KTSlot< KTDataPtr > fCutStructSlot; + KTSlot< KTDataPtr > fDataAndCutStructSlot; }; } diff --git a/Library/Processor/KTSlot.hh b/Library/Processor/KTSlot.hh index ad6de31..797282c 100644 --- a/Library/Processor/KTSlot.hh +++ b/Library/Processor/KTSlot.hh @@ -8,7 +8,6 @@ #ifndef KTSLOT_HH_ #define KTSLOT_HH_ -#include "KTData.hh" #include "KTException.hh" #include "KTLogger.hh" #include "KTSignal.hh" @@ -37,17 +36,17 @@ namespace Nymph Initialize the slot with the name of the slot, the address of the owner of the slot function, and the function pointer. Optionally, if the Processor is separate from the owner of the slot function, the Processor address is specified as the second argument to the constructor. */ - template< typename ReturnType, typename... Args > + template< typename... Args > class KTSlot { public: /// Constructor for the case where the processor has the function that will be called by the slot template< class XFuncOwnerType > - KTSlot( const std::string& name, XFuncOwnerType* owner, ReturnType (XFuncOwnerType::*func)( Args... ), std::initializer_list< std::string > signals ); + KTSlot( const std::string& name, XFuncOwnerType* owner, void (XFuncOwnerType::*func)( Args... ), std::initializer_list< std::string > signals ); /// Constructor for the case where the processor and the object with the function that will be called are different template< class XFuncOwnerType > - KTSlot( const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, ReturnType (XFuncOwnerType::*func)( Args... ), std::initializer_list< std::string > signals ); + KTSlot( const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, void (XFuncOwnerType::*func)( Args... ), std::initializer_list< std::string > signals ); virtual ~KTSlot(); @@ -62,14 +61,13 @@ namespace Nymph // Typedefs for backwards compatibility - template < typename ReturnType > - using KTSlotNoArg = KTSlot< ReturnType >; + typedef KTSlot<> KTSlotNoArg; - template < typename ReturnType, typename Arg1 > - using KTSlotOneArg = KTSlot< ReturnType, Arg1 >; + template < typename Arg1 > + using KTSlotOneArg = KTSlot< Arg1 >; - template< typename ReturnType, typename Arg1, typename Arg2 > - using KTSlotTwoArg = KTSlot< ReturnType, Arg1, Arg2 >; + template< typename Arg1, typename Arg2 > + using KTSlotTwoArg = KTSlot< Arg1, Arg2 >; /*! @@ -93,7 +91,7 @@ namespace Nymph Also optionally, a signal to be emitted after the return of the member function can be specified as the last argument. */ template< class... XDataTypes > - class KTSlotData : public KTSlot< void, KTDataPtr > + class KTSlotData : public KTSlot< KTDataPtr > { //public: //typedef XDataType data_type; @@ -182,7 +180,7 @@ namespace Nymph Also optionally, a signal to be emitted after the return of the member function can be specified as the last argument. */ - class KTSlotDone : public KTSlot< void > + class KTSlotDone : public KTSlot<> { public: /// Constructor for the case where the processor has the function that will be called by the slot @@ -208,35 +206,35 @@ namespace Nymph // KTSlot - template< typename ReturnType, typename... Args > + template< typename... Args > template< class XFuncOwnerType > - KTSlot< ReturnType, Args... >::KTSlot( const std::string& name, XFuncOwnerType* owner, ReturnType (XFuncOwnerType::*func)( Args... ), std::initializer_list< std::string > signals ): + KTSlot< Args... >::KTSlot( const std::string& name, XFuncOwnerType* owner, void (XFuncOwnerType::*func)( Args... ), std::initializer_list< std::string > signals ): fName( name ) { fSlotWrapper = owner->RegisterSlot( name, owner, func, signals ); } - template< typename ReturnType, typename... Args > + template< typename... Args > template< class XFuncOwnerType > - KTSlot< ReturnType, Args... >::KTSlot( const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, ReturnType (XFuncOwnerType::*func)( Args... ), std::initializer_list< std::string > signals ) : + KTSlot< Args... >::KTSlot( const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, void (XFuncOwnerType::*func)( Args... ), std::initializer_list< std::string > signals ) : fName( name ) { fSlotWrapper = proc->RegisterSlot( name, owner, func, signals ); } - template< typename ReturnType, typename... Args > - KTSlot< ReturnType, Args... >::~KTSlot() + template< typename... Args > + KTSlot< Args... >::~KTSlot() { } - template< typename ReturnType, typename... Args > - inline const std::string& KTSlot< ReturnType, Args... >::GetName() const + template< typename... Args > + inline const std::string& KTSlot< Args... >::GetName() const { return fName; } - template< typename ReturnType, typename... Args > - inline KTSlotWrapper* KTSlot< ReturnType, Args... >::GetSlotWrapper() + template< typename... Args > + inline KTSlotWrapper* KTSlot< Args... >::GetSlotWrapper() { return fSlotWrapper; } From 74556825d06b7b11795455157b1b4869009cd0b9 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Thu, 4 May 2017 12:51:43 -0700 Subject: [PATCH 012/521] Capture thread reference actions in function pointers to avoid the need to refer to the processor toolbox --- Library/Application/KTProcessorToolbox.cc | 4 +++- Library/Processor/KTSlot.hh | 2 +- Library/Processor/KTThreadReference.cc | 24 +++++++++++++++-------- Library/Processor/KTThreadReference.hh | 6 ++++-- 4 files changed, 24 insertions(+), 12 deletions(-) diff --git a/Library/Application/KTProcessorToolbox.cc b/Library/Application/KTProcessorToolbox.cc index 37d9150..38bed17 100644 --- a/Library/Application/KTProcessorToolbox.cc +++ b/Library/Application/KTProcessorToolbox.cc @@ -528,7 +528,9 @@ namespace Nymph fThreadIndicators.back().fContinueSignal = fMasterContSignal; thisThreadRef.fThreadIndicator = &fThreadIndicators.back(); - thisThreadRef.fProcTB = this; + //thisThreadRef.fProcTB = this; + thisThreadRef.fInitiateBreakFunc = [&](){ this->InitiateBreak(); }; + thisThreadRef.fRefreshFutureFunc = [&]( std::future< KTDataPtr >&& ret ){ this->TakeFuture( std::move(ret) ); }; //std::thread thread( &KTPrimaryProcessor::operator(), tgIter->fProc, std::move( dataRet ), fThreadPackets.back() ); tgIter->fProc->SetThreadRef( std::move( thisThreadRef ) ); diff --git a/Library/Processor/KTSlot.hh b/Library/Processor/KTSlot.hh index 797282c..0d7ba13 100644 --- a/Library/Processor/KTSlot.hh +++ b/Library/Processor/KTSlot.hh @@ -275,7 +275,7 @@ namespace Nymph if( ! DataPresent< XDataTypes... >( dataPtr ) ) { KTERROR( slotlog, "Failed to find all of the necessary data types in slot <" << fName << ">. Aborting." ); - ref->fDataPtrRet.set_exception( std::make_exception_ptr( KTException() << "Failed to find all of the necessary data types in slot <" << fName << ">. Aborting." ) ); + THROW_RETURN_EXCEPTION( ref->fDataPtrRet, KTException() << "Failed to find all of the necessary data types in slot <" << fName << ">. Aborting." ); return; } diff --git a/Library/Processor/KTThreadReference.cc b/Library/Processor/KTThreadReference.cc index d98918f..2733fa3 100644 --- a/Library/Processor/KTThreadReference.cc +++ b/Library/Processor/KTThreadReference.cc @@ -7,25 +7,29 @@ #include "KTThreadReference.hh" -#include "KTProcessorToolbox.hh" +//#include "KTProcessorToolbox.hh" namespace Nymph { KTThreadReference::KTThreadReference() : fDataPtrRet(), - fProcTB( nullptr ), + //fProcTB( nullptr ), + fInitiateBreakFunc(), + fRefreshFutureFunc(), fThread( nullptr ), fThreadIndicator( nullptr ) {} KTThreadReference::KTThreadReference( KTThreadReference&& orig ) : fDataPtrRet( std::move( orig.fDataPtrRet ) ), - fProcTB( orig.fProcTB ), + //fProcTB( orig.fProcTB ), + fInitiateBreakFunc( std::move( orig.fInitiateBreakFunc ) ), + fRefreshFutureFunc( std::move( orig.fRefreshFutureFunc ) ), fThread( orig.fThread ), fThreadIndicator( orig.fThreadIndicator ) { - orig.fProcTB = nullptr; + //orig.fProcTB = nullptr; orig.fThread = nullptr; orig.fThreadIndicator = nullptr; } @@ -33,11 +37,13 @@ namespace Nymph KTThreadReference& KTThreadReference::operator=( KTThreadReference&& orig ) { fDataPtrRet = std::move( orig.fDataPtrRet ); - fProcTB = orig.fProcTB; + //fProcTB = orig.fProcTB; + fInitiateBreakFunc = std::move( orig.fInitiateBreakFunc ); + fRefreshFutureFunc = std::move( orig.fRefreshFutureFunc ); fThread = orig.fThread; fThreadIndicator = orig.fThreadIndicator; - orig.fProcTB = nullptr; + //orig.fProcTB = nullptr; orig.fThread = nullptr; orig.fThreadIndicator = nullptr; @@ -51,14 +57,16 @@ namespace Nymph if( /* breakpoint is set here */ false ) { breakInititatedHere = true; - fProcTB->InitiateBreak(); + fInitiateBreakFunc(); + //fProcTB->InitiateBreak(); } if( fThreadIndicator->fBreakFlag || breakInititatedHere ) { fDataPtrRet.set_value( dataPtr ); fThreadIndicator->fContinueSignal.wait(); fDataPtrRet = KTDataPtrReturn(); - fProcTB->TakeFuture( fDataPtrRet.get_future() ); + //fProcTB->TakeFuture( fDataPtrRet.get_future() ); + fRefreshFutureFunc( fDataPtrRet.get_future() ); } return; } diff --git a/Library/Processor/KTThreadReference.hh b/Library/Processor/KTThreadReference.hh index a29c479..9aa167f 100644 --- a/Library/Processor/KTThreadReference.hh +++ b/Library/Processor/KTThreadReference.hh @@ -14,7 +14,7 @@ namespace Nymph { - class KTProcessorToolbox; + //class KTProcessorToolbox; struct KTThreadIndicator { @@ -25,7 +25,9 @@ namespace Nymph struct KTThreadReference { KTDataPtrReturn fDataPtrRet; - KTProcessorToolbox* fProcTB; + //KTProcessorToolbox* fProcTB; + std::function< void() > fInitiateBreakFunc; + std::function< void(std::future< KTDataPtr >&&) > fRefreshFutureFunc; std::thread* fThread; KTThreadIndicator* fThreadIndicator; From fafdafe22ff80b5bbcdaeb42831570a9b2ff0014 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Thu, 4 May 2017 12:52:02 -0700 Subject: [PATCH 013/521] Added TestExceptionInSlot.cc validation program --- Executables/Validation/CMakeLists.txt | 1 + Executables/Validation/KTTestProcessor.cc | 34 +++++++- Executables/Validation/KTTestProcessor.hh | 21 ++++- Executables/Validation/TestExceptionInSlot.cc | 85 +++++++++++++++++++ Executables/Validation/TestSignalsAndSlots.cc | 2 +- 5 files changed, 138 insertions(+), 5 deletions(-) create mode 100644 Executables/Validation/TestExceptionInSlot.cc diff --git a/Executables/Validation/CMakeLists.txt b/Executables/Validation/CMakeLists.txt index 5e5f9cf..004d75a 100644 --- a/Executables/Validation/CMakeLists.txt +++ b/Executables/Validation/CMakeLists.txt @@ -46,6 +46,7 @@ if (Nymph_ENABLE_TESTING) TestCacheDirectory TestCut TestCutFilter + TestExceptionInSlot TestLogger TestPrintData TestSignalsAndSlots diff --git a/Executables/Validation/KTTestProcessor.cc b/Executables/Validation/KTTestProcessor.cc index 101db06..91481dd 100644 --- a/Executables/Validation/KTTestProcessor.cc +++ b/Executables/Validation/KTTestProcessor.cc @@ -7,6 +7,7 @@ #include "KTTestProcessor.hh" +#include "KTException.hh" #include "KTLogger.hh" namespace Nymph @@ -34,8 +35,6 @@ namespace Nymph } - - KTTestProcessorB::KTTestProcessorB() : fSlot1("first-slot", this, &KTTestProcessorB::SlotFunc1, {}), fSlot2("second-slot", this, &KTTestProcessorB::SlotFunc2, {}) @@ -65,4 +64,35 @@ namespace Nymph + KTTestProcessorC::KTTestProcessorC() : + fSlot1("first-slot", this, &KTTestProcessorC::SlotFunc1, {}) + { + } + + KTTestProcessorC::~KTTestProcessorC() + { + } + + bool KTTestProcessorC::Configure(const scarab::param_node*) + { + return true; + } + + void KTTestProcessorC::SlotFunc1(int input) + { + KTThreadReference* ref = fSlot1.GetSlotWrapper()->GetThreadRef(); + + try + { + KTINFO(testsiglog, "Slot1: input is " << input); + throw KTException() << "A HUGE problem occurred!!!! (just kidding, this is the expected result)"; + } + catch( ... ) + { + ref->fDataPtrRet.set_exception( std::current_exception() ); + } + return; + } + + } /* namespace Nymph */ diff --git a/Executables/Validation/KTTestProcessor.hh b/Executables/Validation/KTTestProcessor.hh index ed0bd93..02b9f80 100644 --- a/Executables/Validation/KTTestProcessor.hh +++ b/Executables/Validation/KTTestProcessor.hh @@ -34,7 +34,7 @@ namespace Nymph }; /*! - * A simple test procesor that has two slots with integer arguments + * A simple test processor that has two slots with integer arguments */ class KTTestProcessorB : public KTProcessor { @@ -50,7 +50,24 @@ namespace Nymph private: KTSlot< int > fSlot1; KTSlot< int > fSlot2; -}; + }; + + /*! + * A simple test processor that has one slot that throws an exception + */ + class KTTestProcessorC : public KTProcessor + { + public: + KTTestProcessorC(); + virtual ~KTTestProcessorC(); + + bool Configure(const scarab::param_node* node); + + void SlotFunc1(int); + + private: + KTSlot< int > fSlot1; + }; } /* namespace Nymph */ diff --git a/Executables/Validation/TestExceptionInSlot.cc b/Executables/Validation/TestExceptionInSlot.cc new file mode 100644 index 0000000..4cf39bf --- /dev/null +++ b/Executables/Validation/TestExceptionInSlot.cc @@ -0,0 +1,85 @@ +/* + * TestExceptionInSlot.cc + * + * Created on: May 4, 2017 + * Author: N. Oblath + * + * Intended outcome: Exception is thrown in first-slot when the first signal (5) is emitted; the second signal should not be emitted. + */ + +#include "KTTestProcessor.hh" +#include "KTLogger.hh" + +#include + +using namespace Nymph; + +KTLOGGER( testexclog, "TestExceptionInSlot" ) + +int main() +{ + + KTTestProcessorA tpA; + KTTestProcessorC tpC; + + KTINFO( testexclog, "Connecting the-signal to first-slot" ); + try + { + tpA.ConnectASlot( "the-signal", &tpC, "first-slot", 20 ); + } + catch( std::exception& e ) + { + KTERROR( testexclog, "A problem occurred while connecting the signal and slots:\n" << e.what() ); + return -1; + } + + // setup to execute processors asynchronously + KTThreadReference exeThreadRef; + auto exeThreadFuture = exeThreadRef.fDataPtrRet.get_future(); + tpC.GetSlot( "first-slot" )->SetThreadRef (&exeThreadRef ); + + std::atomic< bool > canceled( false ); + + auto exeFunc = [&]() { + std::this_thread::sleep_for( std::chrono::milliseconds(1) ); // delay to let the main thread get to the std::future::wait() call + + KTINFO( testexclog, "Emitting signals" ); + + if( canceled.load() ) return; + KTINFO( testexclog, "First test signal: 5" ); + tpA.EmitSignals( 5 ); + + std::this_thread::sleep_for( std::chrono::milliseconds(1) ); // delay to let the main thread react to the exception + + if( canceled.load() ) return; + KTINFO( testexclog, "Second test signal: 18" ); + tpA.EmitSignals( 18 ); + + return; + }; + + // run the thread + std::thread thread( exeFunc ); + + // wait for a result to be set + exeThreadFuture.wait(); + + try + { + exeThreadFuture.get(); + } + catch( std::exception& e ) + { + canceled = true; + KTERROR( testexclog, "An error occurred while running a processor: " << e.what() ); + } + + thread.join(); + + KTINFO( testexclog, "Tests complete" ); + + return 0; +} + + + diff --git a/Executables/Validation/TestSignalsAndSlots.cc b/Executables/Validation/TestSignalsAndSlots.cc index e1154c6..e026364 100644 --- a/Executables/Validation/TestSignalsAndSlots.cc +++ b/Executables/Validation/TestSignalsAndSlots.cc @@ -33,7 +33,7 @@ int main() */ /* More Complicated Test */ - KTINFO(testsiglog, "Connecting the_signal to first_slot and second_slot"); + KTINFO(testsiglog, "Connecting the-signal to first-slot and second-slot"); try { tpA.ConnectASlot("the-signal", &tpB, "first-slot", 20); From 7e53b2970bac71ea464d2daf7dfcb46444470e8d Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Thu, 4 May 2017 16:40:09 -0700 Subject: [PATCH 014/521] Added KTTestPrimaryProcessor and TestPrimaryProcessor. Added cancelation ability and passing of thread ref from the primary processor. --- Executables/Validation/CMakeLists.txt | 3 + .../Validation/KTTestPrimaryProcessor.cc | 47 ++++++++++++++ .../Validation/KTTestPrimaryProcessor.hh | 40 ++++++++++++ Executables/Validation/KTTestProcessor.cc | 12 +--- Executables/Validation/TestExceptionInSlot.cc | 28 ++++---- .../Validation/TestPrimaryProcessor.cc | 64 +++++++++++++++++++ Library/Application/KTDataQueueProcessor.cc | 1 + Library/Application/KTDataQueueProcessor.hh | 2 +- Library/Application/KTProcessorToolbox.cc | 6 +- Library/IO/KTReader.cc | 2 +- Library/Processor/KTPrimaryProcessor.cc | 38 +++++++++-- Library/Processor/KTPrimaryProcessor.hh | 13 ++-- Library/Processor/KTProcessor.hh | 1 + Library/Processor/KTThreadReference.cc | 17 ++--- Library/Processor/KTThreadReference.hh | 6 +- 15 files changed, 222 insertions(+), 58 deletions(-) create mode 100644 Executables/Validation/KTTestPrimaryProcessor.cc create mode 100644 Executables/Validation/KTTestPrimaryProcessor.hh create mode 100644 Executables/Validation/TestPrimaryProcessor.cc diff --git a/Executables/Validation/CMakeLists.txt b/Executables/Validation/CMakeLists.txt index 004d75a..58ceed9 100644 --- a/Executables/Validation/CMakeLists.txt +++ b/Executables/Validation/CMakeLists.txt @@ -15,12 +15,14 @@ if (Nymph_ENABLE_TESTING) set (VALIDATION_HEADERFILES KTTestConfigurable.hh KTTestCuts.hh + KTTestPrimaryProcessor.hh KTTestProcessor.hh ) set (VALIDATION_SOURCEFILES KTTestConfigurable.cc KTTestCuts.cc + KTTestPrimaryProcessor.cc KTTestProcessor.cc ) @@ -48,6 +50,7 @@ if (Nymph_ENABLE_TESTING) TestCutFilter TestExceptionInSlot TestLogger + TestPrimaryProcessor TestPrintData TestSignalsAndSlots TestThroughputProfiler diff --git a/Executables/Validation/KTTestPrimaryProcessor.cc b/Executables/Validation/KTTestPrimaryProcessor.cc new file mode 100644 index 0000000..2792158 --- /dev/null +++ b/Executables/Validation/KTTestPrimaryProcessor.cc @@ -0,0 +1,47 @@ +/* + * KTTestPrimaryProcessor.cc + * + * Created on: May 4, 2017 + * Author: N.S. Oblath + */ + +#include "KTTestPrimaryProcessor.hh" + +namespace Nymph +{ + + KTTestPrimaryProcessor::KTTestPrimaryProcessor() : + KTPrimaryProcessor( {"the-signal"} ), + fIterations(10), + fTheSignal("the-signal", this) + { + } + + KTTestPrimaryProcessor::~KTTestPrimaryProcessor() + { + } + + bool KTTestPrimaryProcessor::Configure( const scarab::param_node* node ) + { + if( node == nullptr ) return true; + + SetIterations( node->get_value( "iterations", GetIterations() ) ); + + return true; + } + + bool KTTestPrimaryProcessor::Run() + { + for( unsigned iIteration = 0; iIteration < fIterations; ++iIteration ) + { + // e.g. for a real processor, do some work here instead of sleeping + std::this_thread::sleep_for( std::chrono::milliseconds(1) ); + + if( fThreadRef.fThreadIndicator->fCanceled ) break; + + fTheSignal( iIteration ); + } + return true; + } + +} /* namespace Nymph */ diff --git a/Executables/Validation/KTTestPrimaryProcessor.hh b/Executables/Validation/KTTestPrimaryProcessor.hh new file mode 100644 index 0000000..8b7f6c5 --- /dev/null +++ b/Executables/Validation/KTTestPrimaryProcessor.hh @@ -0,0 +1,40 @@ +/* + * KTTestPrimaryProcessor.hh + * + * Created on: May 4, 2017 + * Author: N.S. Oblath + */ + +#ifndef KTTESTPRIMARYPROCESSOR_HH_ +#define KTTESTPRIMARYPROCESSOR_HH_ + +#include "KTPrimaryProcessor.hh" + +#include "KTMemberVariable.hh" +#include "KTSignal.hh" + +namespace Nymph +{ + + class KTTestPrimaryProcessor : public KTPrimaryProcessor + { + public: + KTTestPrimaryProcessor(); + virtual ~KTTestPrimaryProcessor(); + + public: + bool Configure( const scarab::param_node* node ); + + MEMBERVARIABLE( unsigned, Iterations ); + + public: + virtual bool Run(); + + private: + KTSignal< int > fTheSignal; + + }; + +} /* namespace Nymph */ + +#endif /* KTTESTPRIMARYPROCESSOR_HH_ */ diff --git a/Executables/Validation/KTTestProcessor.cc b/Executables/Validation/KTTestProcessor.cc index 91481dd..5be413e 100644 --- a/Executables/Validation/KTTestProcessor.cc +++ b/Executables/Validation/KTTestProcessor.cc @@ -82,15 +82,9 @@ namespace Nymph { KTThreadReference* ref = fSlot1.GetSlotWrapper()->GetThreadRef(); - try - { - KTINFO(testsiglog, "Slot1: input is " << input); - throw KTException() << "A HUGE problem occurred!!!! (just kidding, this is the expected result)"; - } - catch( ... ) - { - ref->fDataPtrRet.set_exception( std::current_exception() ); - } + KTINFO(testsiglog, "Slot1: input is " << input); + throw KTException() << "A HUGE problem occurred!!!! (just kidding, this is the expected result)"; + return; } diff --git a/Executables/Validation/TestExceptionInSlot.cc b/Executables/Validation/TestExceptionInSlot.cc index 4cf39bf..033bd34 100644 --- a/Executables/Validation/TestExceptionInSlot.cc +++ b/Executables/Validation/TestExceptionInSlot.cc @@ -41,19 +41,26 @@ int main() std::atomic< bool > canceled( false ); auto exeFunc = [&]() { - std::this_thread::sleep_for( std::chrono::milliseconds(1) ); // delay to let the main thread get to the std::future::wait() call + try + { + std::this_thread::sleep_for( std::chrono::milliseconds(1) ); // delay to let the main thread get to the std::future::wait() call - KTINFO( testexclog, "Emitting signals" ); + KTINFO( testexclog, "Emitting signals" ); - if( canceled.load() ) return; - KTINFO( testexclog, "First test signal: 5" ); - tpA.EmitSignals( 5 ); + if( canceled.load() ) return; + KTINFO( testexclog, "First test signal: 5" ); + tpA.EmitSignals( 5 ); - std::this_thread::sleep_for( std::chrono::milliseconds(1) ); // delay to let the main thread react to the exception + std::this_thread::sleep_for( std::chrono::milliseconds(1) ); // delay to let the main thread react to the exception - if( canceled.load() ) return; - KTINFO( testexclog, "Second test signal: 18" ); - tpA.EmitSignals( 18 ); + if( canceled.load() ) return; + KTINFO( testexclog, "Second test signal: 18" ); + tpA.EmitSignals( 18 ); + } + catch( ... ) + { + exeThreadRef.fDataPtrRet.set_exception( std::current_exception() ); + } return; }; @@ -80,6 +87,3 @@ int main() return 0; } - - - diff --git a/Executables/Validation/TestPrimaryProcessor.cc b/Executables/Validation/TestPrimaryProcessor.cc new file mode 100644 index 0000000..2050c3d --- /dev/null +++ b/Executables/Validation/TestPrimaryProcessor.cc @@ -0,0 +1,64 @@ +/* + * TestPrimaryProcessor.cc + * + * Created on: May 4, 2017 + * Author: obla999 + */ + +#include "KTTestPrimaryProcessor.hh" +#include "KTTestProcessor.hh" + +#include "KTLogger.hh" + +#include + +using namespace Nymph; + +KTLOGGER( testpplog, "TestPrimaryProcessor" ) + +int main() +{ + + KTTestPrimaryProcessor tpp; + KTTestProcessorB tp; + + KTINFO( testpplog, "Connecting the-signal to first-slot" ); + try + { + tpp.ConnectASlot( "the-signal", &tp, "first-slot", 20 ); + } + catch( std::exception& e ) + { + KTERROR( testpplog, "A problem occurred while connecting the signal and slots:\n" << e.what() ); + return -1; + } + + // setup to execute processors asynchronously + KTThreadReference exeThreadRef; + auto exeThreadFuture = exeThreadRef.fDataPtrRet.get_future(); + + KTThreadIndicator exeThreadInd; + exeThreadRef.fThreadIndicator = &exeThreadInd; + + // run the thread + std::thread thread( &KTPrimaryProcessor::operator(), &tpp, std::move( exeThreadRef ) ); + + // wait for a result to be set + exeThreadFuture.wait(); + + try + { + exeThreadFuture.get(); + } + catch( std::exception& e ) + { + exeThreadInd.fCanceled = true; + KTERROR( testpplog, "An error occurred while running a processor: " << e.what() ); + } + + thread.join(); + + KTINFO( testpplog, "Tests complete" ); + + return 0; +} diff --git a/Library/Application/KTDataQueueProcessor.cc b/Library/Application/KTDataQueueProcessor.cc index ceaaef0..6b8599d 100644 --- a/Library/Application/KTDataQueueProcessor.cc +++ b/Library/Application/KTDataQueueProcessor.cc @@ -19,6 +19,7 @@ namespace Nymph { SetFuncPtr(&KTDataQueueProcessor::EmitDataSignal); fQueueDataSW = RegisterSlot("data", this, &KTDataQueueProcessor::QueueData, {}); + fSignalsEmitted.push_back("data"); //RegisterSlot("data-list", this, &KTDataQueueProcessor::QueueDataList); } diff --git a/Library/Application/KTDataQueueProcessor.hh b/Library/Application/KTDataQueueProcessor.hh index a0ef2b5..867efb8 100644 --- a/Library/Application/KTDataQueueProcessor.hh +++ b/Library/Application/KTDataQueueProcessor.hh @@ -206,7 +206,7 @@ namespace Nymph template< class XProcessorType > KTDataQueueProcessorTemplate< XProcessorType >::KTDataQueueProcessorTemplate(const std::string& name) : - KTPrimaryProcessor(name), + KTPrimaryProcessor({"queue-done"}, name), fStatus(kStopped), fFuncPtr(NULL), fQueue(), diff --git a/Library/Application/KTProcessorToolbox.cc b/Library/Application/KTProcessorToolbox.cc index 38bed17..9003141 100644 --- a/Library/Application/KTProcessorToolbox.cc +++ b/Library/Application/KTProcessorToolbox.cc @@ -533,9 +533,9 @@ namespace Nymph thisThreadRef.fRefreshFutureFunc = [&]( std::future< KTDataPtr >&& ret ){ this->TakeFuture( std::move(ret) ); }; //std::thread thread( &KTPrimaryProcessor::operator(), tgIter->fProc, std::move( dataRet ), fThreadPackets.back() ); - tgIter->fProc->SetThreadRef( std::move( thisThreadRef ) ); - std::thread thread( &KTPrimaryProcessor::operator(), tgIter->fProc ); - tgIter->fProc->GetThreadRef()->fThread = &thread; + //tgIter->fProc->SetThreadRef( std::move( thisThreadRef ) ); + std::thread thread( &KTPrimaryProcessor::operator(), tgIter->fProc, std::move( thisThreadRef ) ); + //tgIter->fProc->GetThreadRef()->fThread = &thread; KTDEBUG( proclog, "Thread ID is <" << thread.get_id() << ">" ); diff --git a/Library/IO/KTReader.cc b/Library/IO/KTReader.cc index b3ac907..0aa7b2d 100644 --- a/Library/IO/KTReader.cc +++ b/Library/IO/KTReader.cc @@ -11,7 +11,7 @@ namespace Nymph { KTReader::KTReader(const std::string& name) : - KTPrimaryProcessor(name) + KTPrimaryProcessor({}, name) { } diff --git a/Library/Processor/KTPrimaryProcessor.cc b/Library/Processor/KTPrimaryProcessor.cc index 97a0c24..437f498 100644 --- a/Library/Processor/KTPrimaryProcessor.cc +++ b/Library/Processor/KTPrimaryProcessor.cc @@ -14,26 +14,50 @@ namespace Nymph { KTLOGGER( proclog, "KTPrimaryProcessor" ); - KTPrimaryProcessor::KTPrimaryProcessor( const std::string& name ) : + KTPrimaryProcessor::KTPrimaryProcessor( std::initializer_list< std::string > signals, const std::string& name ) : KTProcessor( name ), + fSignalsEmitted( signals ), fThreadRef() { + } KTPrimaryProcessor::~KTPrimaryProcessor() { } - void KTPrimaryProcessor::operator ()() + void KTPrimaryProcessor::operator ()( KTThreadReference&& ref ) { - if( ! Run() ) + fThreadRef = std::move( ref ); + + // pass updated thread reference to downstream slots + for( auto sigIt = fSignalsEmitted.begin(); sigIt != fSignalsEmitted.end(); ++sigIt ) + { + // loop over all processor:slots called by this signal + auto sigConnRange = fSigConnMap.equal_range( *sigIt ); + for( SigConnMapCIt sigConnIt = sigConnRange.first; sigConnIt != sigConnRange.second; ++sigConnIt ) + { + // pass the update on to the connected-to processor + sigConnIt->second.first->PassThreadRefUpdate( sigConnIt->second.second, &fThreadRef ); + } + } + + // go! + try { - KTERROR( proclog, "An error occurred during processor running." ); - THROW_RETURN_EXCEPTION( fThreadRef.fDataPtrRet, KTException() << "An error occurred during processor running" ); + if( ! Run() ) + { + KTERROR( proclog, "An error occurred during processor running." ); + THROW_RETURN_EXCEPTION( fThreadRef.fDataPtrRet, KTException() << "An error occurred during processor running" ); + } + else + { + fThreadRef.fDataPtrRet.set_value( KTDataPtr() ); + } } - else + catch( ... ) { - fThreadRef.fDataPtrRet.set_value( KTDataPtr() ); + fThreadRef.fDataPtrRet.set_exception( std::current_exception() ); } return; } diff --git a/Library/Processor/KTPrimaryProcessor.hh b/Library/Processor/KTPrimaryProcessor.hh index 4c7764e..9dd3b1f 100644 --- a/Library/Processor/KTPrimaryProcessor.hh +++ b/Library/Processor/KTPrimaryProcessor.hh @@ -21,31 +21,26 @@ namespace Nymph class KTPrimaryProcessor : public KTProcessor { public: - KTPrimaryProcessor( const std::string& name = "default-primary-processor-name" ); + KTPrimaryProcessor( std::initializer_list< std::string > signals, const std::string& name = "default-primary-processor-name" ); virtual ~KTPrimaryProcessor(); public: /// Callable function used by std::thread - void operator()(); + void operator()( KTThreadReference&& ref ); /// Starts the main action of the processor virtual bool Run() = 0; - void SetThreadRef( KTThreadReference&& ref ); KTThreadReference* GetThreadRef(); protected: + std::vector< std::string > fSignalsEmitted; + KTThreadReference fThreadRef; }; - inline void KTPrimaryProcessor::SetThreadRef( KTThreadReference&& ref ) - { - fThreadRef = std::move( ref ); - return; - } - inline KTThreadReference* KTPrimaryProcessor::GetThreadRef() { return &fThreadRef; diff --git a/Library/Processor/KTProcessor.hh b/Library/Processor/KTProcessor.hh index b9a217b..f29a1c8 100644 --- a/Library/Processor/KTProcessor.hh +++ b/Library/Processor/KTProcessor.hh @@ -64,6 +64,7 @@ namespace Nymph virtual ~KTProcessor(); public: + /// For a slot that is called, update the slot's ThreadRef, and pass the update to any slots that get called by signals emitted by this slot void PassThreadRefUpdate(const std::string& slotName, KTThreadReference* threadRef); void ConnectASlot(const std::string& signalName, KTProcessor* processor, const std::string& slotName, int groupNum=-1); diff --git a/Library/Processor/KTThreadReference.cc b/Library/Processor/KTThreadReference.cc index 2733fa3..745717b 100644 --- a/Library/Processor/KTThreadReference.cc +++ b/Library/Processor/KTThreadReference.cc @@ -11,40 +11,35 @@ namespace Nymph { + KTThreadIndicator::KTThreadIndicator() : + fBreakFlag( false ), + fContinueSignal(), + fCanceled( false ) + {} KTThreadReference::KTThreadReference() : fDataPtrRet(), - //fProcTB( nullptr ), fInitiateBreakFunc(), fRefreshFutureFunc(), - fThread( nullptr ), fThreadIndicator( nullptr ) {} KTThreadReference::KTThreadReference( KTThreadReference&& orig ) : fDataPtrRet( std::move( orig.fDataPtrRet ) ), - //fProcTB( orig.fProcTB ), fInitiateBreakFunc( std::move( orig.fInitiateBreakFunc ) ), fRefreshFutureFunc( std::move( orig.fRefreshFutureFunc ) ), - fThread( orig.fThread ), fThreadIndicator( orig.fThreadIndicator ) { - //orig.fProcTB = nullptr; - orig.fThread = nullptr; orig.fThreadIndicator = nullptr; } KTThreadReference& KTThreadReference::operator=( KTThreadReference&& orig ) { fDataPtrRet = std::move( orig.fDataPtrRet ); - //fProcTB = orig.fProcTB; fInitiateBreakFunc = std::move( orig.fInitiateBreakFunc ); fRefreshFutureFunc = std::move( orig.fRefreshFutureFunc ); - fThread = orig.fThread; fThreadIndicator = orig.fThreadIndicator; - //orig.fProcTB = nullptr; - orig.fThread = nullptr; orig.fThreadIndicator = nullptr; return *this; @@ -58,14 +53,12 @@ namespace Nymph { breakInititatedHere = true; fInitiateBreakFunc(); - //fProcTB->InitiateBreak(); } if( fThreadIndicator->fBreakFlag || breakInititatedHere ) { fDataPtrRet.set_value( dataPtr ); fThreadIndicator->fContinueSignal.wait(); fDataPtrRet = KTDataPtrReturn(); - //fProcTB->TakeFuture( fDataPtrRet.get_future() ); fRefreshFutureFunc( fDataPtrRet.get_future() ); } return; diff --git a/Library/Processor/KTThreadReference.hh b/Library/Processor/KTThreadReference.hh index 9aa167f..a918210 100644 --- a/Library/Processor/KTThreadReference.hh +++ b/Library/Processor/KTThreadReference.hh @@ -14,21 +14,19 @@ namespace Nymph { - //class KTProcessorToolbox; - struct KTThreadIndicator { bool fBreakFlag; // only use outside of blocks protected by a mutex are reads, so we shouldn't need to make this an atomic std::shared_future< void > fContinueSignal; + bool fCanceled; + KTThreadIndicator(); }; struct KTThreadReference { KTDataPtrReturn fDataPtrRet; - //KTProcessorToolbox* fProcTB; std::function< void() > fInitiateBreakFunc; std::function< void(std::future< KTDataPtr >&&) > fRefreshFutureFunc; - std::thread* fThread; KTThreadIndicator* fThreadIndicator; KTThreadReference(); From 983cc2510b452d62f8f9f4fbf6ad12c489105710 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Thu, 4 May 2017 16:54:03 -0700 Subject: [PATCH 015/521] Cleanup in the processor toolbox --- Library/Application/KTProcessorToolbox.cc | 81 +---------------------- Library/Application/KTProcessorToolbox.hh | 26 -------- 2 files changed, 1 insertion(+), 106 deletions(-) diff --git a/Library/Application/KTProcessorToolbox.cc b/Library/Application/KTProcessorToolbox.cc index 9003141..6467523 100644 --- a/Library/Application/KTProcessorToolbox.cc +++ b/Library/Application/KTProcessorToolbox.cc @@ -505,15 +505,7 @@ namespace Nymph { std::string procName( tgIter->fName ); KTINFO( proclog, "Starting processor <" << procName << ">" ); -/* - KTDataPtrReturn dataRet; - fThreadFutures.push_back( dataRet.get_future() ); - if( ! fThreadFutures.back().valid() ) - { - KTERROR( proclog, "Invalid thread future created" ); - throw std::future_error( std::future_errc::no_state ); - } -*/ + KTThreadReference thisThreadRef; fThreadFutures.push_back( thisThreadRef.fDataPtrRet.get_future() ); @@ -524,18 +516,13 @@ namespace Nymph } fThreadIndicators.push_back( KTThreadIndicator() ); - fThreadIndicators.back().fBreakFlag = false; fThreadIndicators.back().fContinueSignal = fMasterContSignal; thisThreadRef.fThreadIndicator = &fThreadIndicators.back(); - //thisThreadRef.fProcTB = this; thisThreadRef.fInitiateBreakFunc = [&](){ this->InitiateBreak(); }; thisThreadRef.fRefreshFutureFunc = [&]( std::future< KTDataPtr >&& ret ){ this->TakeFuture( std::move(ret) ); }; - //std::thread thread( &KTPrimaryProcessor::operator(), tgIter->fProc, std::move( dataRet ), fThreadPackets.back() ); - //tgIter->fProc->SetThreadRef( std::move( thisThreadRef ) ); std::thread thread( &KTPrimaryProcessor::operator(), tgIter->fProc, std::move( thisThreadRef ) ); - //tgIter->fProc->GetThreadRef()->fThread = &thread; KTDEBUG( proclog, "Thread ID is <" << thread.get_id() << ">" ); @@ -714,72 +701,6 @@ namespace Nymph } return true; - - /* - KTPROG(proclog, "Beginning processing . . ."); -#ifndef SINGLETHREADED - unsigned iGroup = 0; -#endif - try - { - for (RunQueue::iterator rqIter = fRunQueue.begin(); rqIter != fRunQueue.end(); ++rqIter) - { - //#ifdef SINGLETHREADED - for (ThreadGroup::iterator tgIter = rqIter->begin(); tgIter != rqIter->end(); ++tgIter) - { - std::promise< KTDataPtr > promise; - std::future< KTDataPtr > future = promise.get_future(); - std::thread thread( &KTPrimaryProcessor::operator(), tgIter->fProc, std::move( promise ) ); - if( ! future.valid() ) - { - throw std::future_error( std::future_errc::no_state ); - } - std::future_status status; - do - { - status = future.wait_for(std::chrono::milliseconds(500)); - } while (status != std::future_status::ready); - - try - { - future.get(); - } - catch( std::exception& e ) - { - throw KTException() << "An error occurred while running processor <" << tgIter->fName << ">: " << e.what(); - } - thread.join(); - } -//#else -// for now, don't do this section of code -#if 0 - KTDEBUG(proclog, "Starting thread group " << iGroup); - boost::thread_group parallelThreads; - unsigned iThread = 0; - for (ThreadGroup::const_iterator tgIter = rqIter->begin(); tgIter != rqIter->end(); ++tgIter) - { - // create a boost::thread object to launch the thread - // use boost::ref to avoid copying the processor - KTDEBUG(proclog, "Starting thread " << iThread << ": " << tgIter->fName); - parallelThreads.create_thread(boost::ref(*(tgIter->fProc))); - //parallelThreads.create_thread(boost::ref(**tgIter)); - iThread++; - } - // wait for execution to complete - parallelThreads.join_all(); - iGroup++; -#endif // this endif was here before i put in the temporary #if 0 - } - } - catch( std::exception& e ) - { - KTERROR( proclog, e.what() ); - return false; - } - KTPROG(proclog, ". . . processing complete."); - return true; - */ } - } /* namespace Nymph */ diff --git a/Library/Application/KTProcessorToolbox.hh b/Library/Application/KTProcessorToolbox.hh index 56623b7..ca2725e 100644 --- a/Library/Application/KTProcessorToolbox.hh +++ b/Library/Application/KTProcessorToolbox.hh @@ -181,32 +181,6 @@ namespace Nymph RunQueue fRunQueue; public: -/* struct ThreadPacket - { - KTProcessorToolbox* fProcTB; - bool fBreakFlag; // only use outside of blocks protected by fBreakContMutex are reads, so we shouldn't need to make this an atomic - std::shared_future< void > fContinueSignal; - std::thread* fThread; - - void Break( const KTDataPtr& dataPtr, KTDataPtrReturn& ret ) - { - bool breakInititatedHere = false; - if( /* breakpoint is set here *//* false ) - { - breakInititatedHere = true; - fProcTB->InitiateBreak(); - } - if( fBreakFlag || breakInititatedHere ) - { - ret.set_value( dataPtr ); - fContinueSignal.wait(); - ret = KTDataPtrReturn(); - fProcTB->TakeFuture( ret.get_future() ); - } - return; - } - }; -*/ /// Process the run queue. /// This will call Run() on all of the processors in the queue. bool Run(); From a165bd8b9aad99c4137a2c320f1166a54f3e2bbc Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Thu, 4 May 2017 17:38:35 -0700 Subject: [PATCH 016/521] Added KTTestProcessorToolbox --- Executables/Validation/CMakeLists.txt | 1 + .../Validation/KTTestPrimaryProcessor.cc | 6 +- .../Validation/KTTestPrimaryProcessor.hh | 4 +- Executables/Validation/KTTestProcessor.cc | 14 ++++- Executables/Validation/KTTestProcessor.hh | 6 +- .../Validation/TestProcessorToolbox.cc | 62 +++++++++++++++++++ 6 files changed, 83 insertions(+), 10 deletions(-) create mode 100644 Executables/Validation/TestProcessorToolbox.cc diff --git a/Executables/Validation/CMakeLists.txt b/Executables/Validation/CMakeLists.txt index 58ceed9..ed5d3f9 100644 --- a/Executables/Validation/CMakeLists.txt +++ b/Executables/Validation/CMakeLists.txt @@ -52,6 +52,7 @@ if (Nymph_ENABLE_TESTING) TestLogger TestPrimaryProcessor TestPrintData + TestProcessorToolbox TestSignalsAndSlots TestThroughputProfiler ) diff --git a/Executables/Validation/KTTestPrimaryProcessor.cc b/Executables/Validation/KTTestPrimaryProcessor.cc index 2792158..290ac9a 100644 --- a/Executables/Validation/KTTestPrimaryProcessor.cc +++ b/Executables/Validation/KTTestPrimaryProcessor.cc @@ -10,8 +10,10 @@ namespace Nymph { - KTTestPrimaryProcessor::KTTestPrimaryProcessor() : - KTPrimaryProcessor( {"the-signal"} ), + KT_REGISTER_PROCESSOR(KTTestPrimaryProcessor, "test-p-proc"); + + KTTestPrimaryProcessor::KTTestPrimaryProcessor( const std::string& name ) : + KTPrimaryProcessor( {"the-signal"}, name ), fIterations(10), fTheSignal("the-signal", this) { diff --git a/Executables/Validation/KTTestPrimaryProcessor.hh b/Executables/Validation/KTTestPrimaryProcessor.hh index 8b7f6c5..6cc104a 100644 --- a/Executables/Validation/KTTestPrimaryProcessor.hh +++ b/Executables/Validation/KTTestPrimaryProcessor.hh @@ -16,10 +16,10 @@ namespace Nymph { - class KTTestPrimaryProcessor : public KTPrimaryProcessor + class KTTestPrimaryProcessor : public KTPrimaryProcessor { public: - KTTestPrimaryProcessor(); + KTTestPrimaryProcessor( const std::string& name = "test-p-proc" ); virtual ~KTTestPrimaryProcessor(); public: diff --git a/Executables/Validation/KTTestProcessor.cc b/Executables/Validation/KTTestProcessor.cc index 5be413e..8b5d38f 100644 --- a/Executables/Validation/KTTestProcessor.cc +++ b/Executables/Validation/KTTestProcessor.cc @@ -14,7 +14,10 @@ namespace Nymph { KTLOGGER(testsiglog, "KTTestProcessor") - KTTestProcessorA::KTTestProcessorA() : + KT_REGISTER_PROCESSOR(KTTestProcessorA, "test-proc-a"); + + KTTestProcessorA::KTTestProcessorA( const std::string& name ) : + KTProcessor( name ), fTheSignal("the-signal", this) { } @@ -35,7 +38,10 @@ namespace Nymph } - KTTestProcessorB::KTTestProcessorB() : + KT_REGISTER_PROCESSOR(KTTestProcessorB, "test-proc-b"); + + KTTestProcessorB::KTTestProcessorB( const std::string& name ) : + KTProcessor( name ), fSlot1("first-slot", this, &KTTestProcessorB::SlotFunc1, {}), fSlot2("second-slot", this, &KTTestProcessorB::SlotFunc2, {}) { @@ -63,8 +69,10 @@ namespace Nymph } + KT_REGISTER_PROCESSOR(KTTestProcessorC, "test-proc-c"); - KTTestProcessorC::KTTestProcessorC() : + KTTestProcessorC::KTTestProcessorC( const std::string& name ) : + KTProcessor( name ), fSlot1("first-slot", this, &KTTestProcessorC::SlotFunc1, {}) { } diff --git a/Executables/Validation/KTTestProcessor.hh b/Executables/Validation/KTTestProcessor.hh index 02b9f80..e444126 100644 --- a/Executables/Validation/KTTestProcessor.hh +++ b/Executables/Validation/KTTestProcessor.hh @@ -22,7 +22,7 @@ namespace Nymph class KTTestProcessorA : public KTProcessor { public: - KTTestProcessorA(); + KTTestProcessorA( const std::string& name = "test-proc-a" ); virtual ~KTTestProcessorA(); bool Configure(const scarab::param_node* node); @@ -39,7 +39,7 @@ namespace Nymph class KTTestProcessorB : public KTProcessor { public: - KTTestProcessorB(); + KTTestProcessorB( const std::string& name = "test-proc-b" ); virtual ~KTTestProcessorB(); bool Configure(const scarab::param_node* node); @@ -58,7 +58,7 @@ namespace Nymph class KTTestProcessorC : public KTProcessor { public: - KTTestProcessorC(); + KTTestProcessorC( const std::string& name = "test-proc-c" ); virtual ~KTTestProcessorC(); bool Configure(const scarab::param_node* node); diff --git a/Executables/Validation/TestProcessorToolbox.cc b/Executables/Validation/TestProcessorToolbox.cc new file mode 100644 index 0000000..40645b6 --- /dev/null +++ b/Executables/Validation/TestProcessorToolbox.cc @@ -0,0 +1,62 @@ +/* + * TestProcessorToolbox.cc + * + * Created on: May 4, 2017 + * Author: N.S. Oblath + */ + +#include "KTProcessorToolbox.hh" + +#include "KTLogger.hh" + +#include + +using namespace Nymph; + +KTLOGGER( testptlog, "TestProcessorToolbox" ) + +int main() +{ + KTINFO( testptlog, "Preparing to run" ); + + KTProcessorToolbox ptb; + + if( ! ptb.AddProcessor( "test-p-proc", "tpp" ) ) + { + KTERROR( testptlog, "Unable to create test primary processor" ); + return -1; + } + + if( ! ptb.AddProcessor( "test-proc-b", "tp" ) ) + { + KTERROR( testptlog, "Unable to create test processor b" ); + return -1; + } + + if( ! ptb.MakeConnection( "tpp:the-signal", "tp:first-slot" ) ) + { + KTERROR( testptlog, "Unable to connect tpp to tp" ); + return -1; + } + + if( ! ptb.PushBackToRunQueue( "tpp" ) ) + { + KTERROR( testptlog, "Unable to add tpp to the run queue" ); + return -1; + } + + KTINFO( testptlog, "Starting asynchronous run" ); + ptb.AsyncRun(); + + while( ptb.WaitForBreak() ) + { + KTINFO( testptlog, "Reached breakpoint; continuing" ); + ptb.Continue(); + } + + KTINFO( testptlog, "Processing complete" ); + + KTINFO( testptlog, "Tests complete" ); + + return 0; +} From c05aef03d4a737e331abc3194f30797bf2bb1da7 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Fri, 5 May 2017 16:10:33 -0700 Subject: [PATCH 017/521] Added TestPrimaryProcessorNoThreading and TestUseBreakpoint. A bunch of debugging later, and breakpoints work! --- Executables/Validation/CMakeLists.txt | 2 + Executables/Validation/KTTestProcessor.cc | 4 + Executables/Validation/KTTestProcessor.hh | 3 + .../Validation/TestPrimaryProcessor.cc | 7 +- .../TestPrimaryProcessorNoThreading.cc | 45 ++++++++++ .../Validation/TestProcessorToolbox.cc | 8 +- Executables/Validation/TestUseBreakpoint.cc | 82 +++++++++++++++++++ Library/Application/KTDataQueueProcessor.cc | 2 +- Library/Application/KTPrintDataStructure.cc | 9 +- Library/Application/KTProcessorToolbox.cc | 65 +++++++++++---- Library/Application/KTProcessorToolbox.hh | 7 +- Library/Data/KTApplyCut.cc | 2 +- Library/Data/KTCutFilter.cc | 2 +- Library/Processor/KTPrimaryProcessor.cc | 3 +- Library/Processor/KTPrimaryProcessor.hh | 3 +- Library/Processor/KTProcessor.cc | 20 +++++ Library/Processor/KTProcessor.hh | 4 +- Library/Processor/KTSlot.hh | 6 +- Library/Processor/KTSlotWrapper.hh | 19 ++++- Library/Processor/KTThreadReference.cc | 21 +++-- Library/Processor/KTThreadReference.hh | 5 +- 21 files changed, 272 insertions(+), 47 deletions(-) create mode 100644 Executables/Validation/TestPrimaryProcessorNoThreading.cc create mode 100644 Executables/Validation/TestUseBreakpoint.cc diff --git a/Executables/Validation/CMakeLists.txt b/Executables/Validation/CMakeLists.txt index ed5d3f9..a3e1dc2 100644 --- a/Executables/Validation/CMakeLists.txt +++ b/Executables/Validation/CMakeLists.txt @@ -51,10 +51,12 @@ if (Nymph_ENABLE_TESTING) TestExceptionInSlot TestLogger TestPrimaryProcessor + TestPrimaryProcessorNoThreading TestPrintData TestProcessorToolbox TestSignalsAndSlots TestThroughputProfiler + TestUseBreakpoint ) pbuilder_executables( TEST_PROGRAMS LIB_DEPENDENCIES ) diff --git a/Executables/Validation/KTTestProcessor.cc b/Executables/Validation/KTTestProcessor.cc index 8b5d38f..826b673 100644 --- a/Executables/Validation/KTTestProcessor.cc +++ b/Executables/Validation/KTTestProcessor.cc @@ -45,6 +45,8 @@ namespace Nymph fSlot1("first-slot", this, &KTTestProcessorB::SlotFunc1, {}), fSlot2("second-slot", this, &KTTestProcessorB::SlotFunc2, {}) { + fSlot1Wrapper = GetSlot( "first-slot" ); + fSlot2Wrapper = GetSlot( "second-slot" ); } KTTestProcessorB::~KTTestProcessorB() @@ -59,12 +61,14 @@ namespace Nymph void KTTestProcessorB::SlotFunc1(int input) { KTINFO(testsiglog, "Slot1: input is " << input); + fSlot1Wrapper->GetThreadRef()->Break( KTDataPtr(), fSlot1Wrapper->GetDoBreakpoint()); return; } void KTTestProcessorB::SlotFunc2(int input) { KTINFO(testsiglog, "Slot2: twice input is " << 2 * input); + fSlot2Wrapper->GetThreadRef()->Break( KTDataPtr(), fSlot2Wrapper->GetDoBreakpoint()); return; } diff --git a/Executables/Validation/KTTestProcessor.hh b/Executables/Validation/KTTestProcessor.hh index e444126..689ccc0 100644 --- a/Executables/Validation/KTTestProcessor.hh +++ b/Executables/Validation/KTTestProcessor.hh @@ -50,6 +50,9 @@ namespace Nymph private: KTSlot< int > fSlot1; KTSlot< int > fSlot2; + + KTSlotWrapper* fSlot1Wrapper; + KTSlotWrapper* fSlot2Wrapper; }; /*! diff --git a/Executables/Validation/TestPrimaryProcessor.cc b/Executables/Validation/TestPrimaryProcessor.cc index 2050c3d..6e543df 100644 --- a/Executables/Validation/TestPrimaryProcessor.cc +++ b/Executables/Validation/TestPrimaryProcessor.cc @@ -2,7 +2,7 @@ * TestPrimaryProcessor.cc * * Created on: May 4, 2017 - * Author: obla999 + * Author: N.S. Oblath */ #include "KTTestPrimaryProcessor.hh" @@ -37,9 +37,6 @@ int main() KTThreadReference exeThreadRef; auto exeThreadFuture = exeThreadRef.fDataPtrRet.get_future(); - KTThreadIndicator exeThreadInd; - exeThreadRef.fThreadIndicator = &exeThreadInd; - // run the thread std::thread thread( &KTPrimaryProcessor::operator(), &tpp, std::move( exeThreadRef ) ); @@ -52,7 +49,7 @@ int main() } catch( std::exception& e ) { - exeThreadInd.fCanceled = true; + exeThreadRef.fThreadIndicator->fCanceled = true; KTERROR( testpplog, "An error occurred while running a processor: " << e.what() ); } diff --git a/Executables/Validation/TestPrimaryProcessorNoThreading.cc b/Executables/Validation/TestPrimaryProcessorNoThreading.cc new file mode 100644 index 0000000..d35a22f --- /dev/null +++ b/Executables/Validation/TestPrimaryProcessorNoThreading.cc @@ -0,0 +1,45 @@ +/* + * TestPrimaryProcessorNoThreading.cc + * + * Created on: May 5, 2017 + * Author: N.S. Oblath + */ + +#include "KTTestPrimaryProcessor.hh" +#include "KTTestProcessor.hh" + +#include "KTLogger.hh" + +using namespace Nymph; + +KTLOGGER( testpplog, "TestPrimaryProcessorNoThreading" ) + +int main() +{ + + KTTestPrimaryProcessor tpp; + KTTestProcessorB tp; + + KTINFO( testpplog, "Connecting the-signal to first-slot" ); + try + { + tpp.ConnectASlot( "the-signal", &tp, "first-slot", 20 ); + } + catch( std::exception& e ) + { + KTERROR( testpplog, "A problem occurred while connecting the signal and slots:\n" << e.what() ); + return -1; + } + + KTINFO( testpplog, "Running the primary processor" ) + + if( ! tpp.Run() ) + { + KTERROR( testpplog, "Something went wrong while running the primary processor" ); + return -1; + } + + KTINFO( testpplog, "Tests complete" ); + + return 0; +} diff --git a/Executables/Validation/TestProcessorToolbox.cc b/Executables/Validation/TestProcessorToolbox.cc index 40645b6..fbbf287 100644 --- a/Executables/Validation/TestProcessorToolbox.cc +++ b/Executables/Validation/TestProcessorToolbox.cc @@ -9,8 +9,6 @@ #include "KTLogger.hh" -#include - using namespace Nymph; KTLOGGER( testptlog, "TestProcessorToolbox" ) @@ -21,33 +19,39 @@ int main() KTProcessorToolbox ptb; + // add the primary processor if( ! ptb.AddProcessor( "test-p-proc", "tpp" ) ) { KTERROR( testptlog, "Unable to create test primary processor" ); return -1; } + // add processor b if( ! ptb.AddProcessor( "test-proc-b", "tp" ) ) { KTERROR( testptlog, "Unable to create test processor b" ); return -1; } + // make connections if( ! ptb.MakeConnection( "tpp:the-signal", "tp:first-slot" ) ) { KTERROR( testptlog, "Unable to connect tpp to tp" ); return -1; } + // set the run queue if( ! ptb.PushBackToRunQueue( "tpp" ) ) { KTERROR( testptlog, "Unable to add tpp to the run queue" ); return -1; } + // go! KTINFO( testptlog, "Starting asynchronous run" ); ptb.AsyncRun(); + // wait for run completion, and ignore breakpoints while( ptb.WaitForBreak() ) { KTINFO( testptlog, "Reached breakpoint; continuing" ); diff --git a/Executables/Validation/TestUseBreakpoint.cc b/Executables/Validation/TestUseBreakpoint.cc new file mode 100644 index 0000000..7e9040f --- /dev/null +++ b/Executables/Validation/TestUseBreakpoint.cc @@ -0,0 +1,82 @@ +/* + * TestUseBreakpoint.cc + * + * Created on: May 5, 2017 + * Author: N.S. Oblath + */ + +#include "KTProcessorToolbox.hh" + +#include "KTProcessor.hh" // temporary (todo below) + +#include "KTLogger.hh" + +using namespace Nymph; + +KTLOGGER( testptlog, "TestUseBreakpoint" ) + +int main() +{ + KTINFO( testptlog, "Preparing to run" ); + + KTProcessorToolbox ptb; + + // add the primary processor + if( ! ptb.AddProcessor( "test-p-proc", "tpp" ) ) + { + KTERROR( testptlog, "Unable to create test primary processor" ); + return -1; + } + + // add processor b + if( ! ptb.AddProcessor( "test-proc-b", "tp" ) ) + { + KTERROR( testptlog, "Unable to create test processor b" ); + return -1; + } + // set breakpoint + // TODO: use configuration instead of manually setting + ptb.GetProcessor( "tp" )->SetDoBreakpoint( "first-slot", true ); + + // make connections + if( ! ptb.MakeConnection( "tpp:the-signal", "tp:first-slot" ) ) + { + KTERROR( testptlog, "Unable to connect tpp to tp" ); + return -1; + } + + // set the run queue + if( ! ptb.PushBackToRunQueue( "tpp" ) ) + { + KTERROR( testptlog, "Unable to add tpp to the run queue" ); + return -1; + } + + // go! + KTINFO( testptlog, "Starting asynchronous run" ); + ptb.AsyncRun(); + + KTINFO( testptlog, "Starting asynchronous breakpoint user" ); + auto buFuture = std::async( std::launch::async, [&](){ + KTINFO( testptlog, "In breakpoint user thread" ); + while( ptb.WaitForBreak() ) + { + KTPROG( testptlog, "Reached breakpoint; waiting for user input" ); + std::string temp; + KTPROG( testptlog, "Please press [return]" ); + getline( std::cin, temp ); + ptb.Continue(); + } + KTINFO( testptlog, "Finished breakpoint user thread" ); + return; + }); + + KTINFO( testptlog, "Waiting for the end of the run" ); + ptb.WaitForEndOfRun(); + + KTINFO( testptlog, "Processing complete" ); + + KTINFO( testptlog, "Tests complete" ); + + return 0; +} diff --git a/Library/Application/KTDataQueueProcessor.cc b/Library/Application/KTDataQueueProcessor.cc index 6b8599d..bca51fd 100644 --- a/Library/Application/KTDataQueueProcessor.cc +++ b/Library/Application/KTDataQueueProcessor.cc @@ -41,7 +41,7 @@ namespace Nymph void KTDataQueueProcessor::QueueData(KTDataPtr& data) { - fQueueDataSW->GetThreadRef()->Break(data); + fQueueDataSW->GetThreadRef()->Break(data, fQueueDataSW->GetDoBreakpoint()); return DoQueueData(data); } /* diff --git a/Library/Application/KTPrintDataStructure.cc b/Library/Application/KTPrintDataStructure.cc index 438b6a2..dd04708 100644 --- a/Library/Application/KTPrintDataStructure.cc +++ b/Library/Application/KTPrintDataStructure.cc @@ -42,7 +42,8 @@ namespace Nymph { DoPrintDataStructure(dataPtr); - fDataStructSlot.GetSlotWrapper()->GetThreadRef()->Break( dataPtr ); + KTSlotWrapper* slotWrap = fDataStructSlot.GetSlotWrapper(); + slotWrap->GetThreadRef()->Break( dataPtr, slotWrap->GetDoBreakpoint() ); fDataSignal(dataPtr); @@ -53,7 +54,8 @@ namespace Nymph { DoPrintCutStructure(dataPtr); - fCutStructSlot.GetSlotWrapper()->GetThreadRef()->Break( dataPtr ); + KTSlotWrapper* slotWrap = fCutStructSlot.GetSlotWrapper(); + fCutStructSlot.GetSlotWrapper()->GetThreadRef()->Break( dataPtr, slotWrap->GetDoBreakpoint() ); fDataSignal(dataPtr); @@ -66,7 +68,8 @@ namespace Nymph DoPrintDataStructure(dataPtr); DoPrintCutStructure(dataPtr); - fDataAndCutStructSlot.GetSlotWrapper()->GetThreadRef()->Break( dataPtr ); + KTSlotWrapper* slotWrap = fDataAndCutStructSlot.GetSlotWrapper(); + fDataAndCutStructSlot.GetSlotWrapper()->GetThreadRef()->Break( dataPtr, slotWrap->GetDoBreakpoint() ); fDataSignal(dataPtr); diff --git a/Library/Application/KTProcessorToolbox.cc b/Library/Application/KTProcessorToolbox.cc index 965e808..9964547 100644 --- a/Library/Application/KTProcessorToolbox.cc +++ b/Library/Application/KTProcessorToolbox.cc @@ -39,10 +39,10 @@ namespace Nymph fRunQueue(), fProcMap(), fThreadFutures(), - //fThreadPackets(), fContinueSignaler(), fMasterContSignal(), fBreakContMutex(), + fWaitForBreakMutex(), fDoRunThread( nullptr ), fDoRunPromise(), fDoRunBreakFlag( false ) @@ -508,6 +508,9 @@ namespace Nymph return; } + fDoRunPromise = std::promise< void >(); + fDoRunFuture = fDoRunPromise.get_future().share(); + bool willRunSingleThreaded = fRunSingleThreaded; #ifdef SINGLETHREADED willRunSingleThreaded = true; @@ -521,7 +524,7 @@ namespace Nymph { // reset the continue signaler fContinueSignaler = std::promise< void >(); - fMasterContSignal = fContinueSignaler.get_future(); + fMasterContSignal = fContinueSignaler.get_future().share(); if( ! fMasterContSignal.valid() ) { KTERROR( proclog, "Invalid master continue-signal created" ); @@ -548,10 +551,10 @@ namespace Nymph throw std::future_error( std::future_errc::no_state ); } - fThreadIndicators.push_back( KTThreadIndicator() ); - fThreadIndicators.back().fContinueSignal = fMasterContSignal; + fThreadIndicators.emplace_back( new KTThreadIndicator() ); + fThreadIndicators.back()->fContinueSignal = fMasterContSignal; - thisThreadRef.fThreadIndicator = &fThreadIndicators.back(); + thisThreadRef.fThreadIndicator = fThreadIndicators.back(); thisThreadRef.fInitiateBreakFunc = [&](){ this->InitiateBreak(); }; thisThreadRef.fRefreshFutureFunc = [&]( std::future< KTDataPtr >&& ret ){ this->TakeFuture( std::move(ret) ); }; @@ -569,11 +572,13 @@ namespace Nymph } while (status != std::future_status::ready); stillRunning = false; - if( fThreadIndicators.back().fBreakFlag ) + if( fThreadIndicators.back()->fBreakFlag ) { KTDEBUG( proclog, "Breakpoint reached" ); continueSignal.wait(); + KTDEBUG( proclog, "Breakpoint finished" ); stillRunning = true; + continueSignal = fMasterContSignal; // refresh the local copy of the shared future } else { @@ -593,6 +598,8 @@ namespace Nymph KTINFO( proclog, "Processor <" << procName << "> has finished" ); thread.join(); + fThreadIndicators.pop_back(); + fThreadFutures.pop_back(); } // end for loop over the thread group } // end for loop over the run-queue @@ -644,7 +651,7 @@ namespace Nymph bool KTProcessorToolbox::WaitForBreak() { - std::future< void > doRunFuture = fDoRunPromise.get_future(); + std::shared_future< void > doRunFuture = fDoRunFuture; std::future_status doRunStatus; do @@ -654,22 +661,36 @@ namespace Nymph if( fDoRunBreakFlag ) { - KTDEBUG( proclog, "Breakpoint reached" ); + KTDEBUG( proclog, "Breakpoint reached (the wait is over)" ); return true; } try { doRunFuture.get(); + KTDEBUG( proclog, "End-of-run reached (the wait-for-break is over)" ); return false; } catch( std::exception& e ) { - // this transfers an exception thrown by a processor to the outer catch block in this function - throw; + KTERROR( proclog, "An error occurred during processing: " << e.what() ); + return false; } } + void KTProcessorToolbox::WaitForEndOfRun() + { + KTDEBUG( proclog, "Waiting for end-of-run" ); + while( WaitForBreak() ) + { + KTDEBUG( proclog, "Reached breakpoint; waiting for continue" ); + WaitForContinue(); + KTDEBUG( proclog, "Processing resuming; waiting for end-of-run" ); + } + KTDEBUG( proclog, "End-of-run reached" ); + return; + } + void KTProcessorToolbox::Continue() { std::unique_lock< std::mutex > breakContLock( fBreakContMutex ); @@ -679,21 +700,26 @@ namespace Nymph // reset all break flags fDoRunBreakFlag = false; - for( std::vector< KTThreadIndicator >::iterator tiIt = fThreadIndicators.begin(); tiIt != fThreadIndicators.end(); ++tiIt ) + for( auto tiIt = fThreadIndicators.begin(); tiIt != fThreadIndicators.end(); ++tiIt ) { - tiIt->fBreakFlag = false; + (*tiIt)->fBreakFlag = false; } + // reset the do-run promise and future + fDoRunPromise = std::promise< void >(); + fDoRunFuture = fDoRunPromise.get_future().share(); + KTINFO( proclog, "Continuing from breakpoint" ); // signal everything to resume fContinueSignaler.set_value(); // reset the signaler and all signals // hopefully the delay of creating the new signaler and starting the for loop is enough that anything waiting on the old signal has already seen that signal and moved on - fContinueSignaler = std::move( std::promise< void >() ); - for( std::vector< KTThreadIndicator >::iterator tiIt = fThreadIndicators.begin(); tiIt != fThreadIndicators.end(); ++tiIt ) + fContinueSignaler = std::promise< void >(); + fMasterContSignal = fContinueSignaler.get_future().share(); + for( auto tiIt = fThreadIndicators.begin(); tiIt != fThreadIndicators.end(); ++tiIt ) { - tiIt->fContinueSignal = fContinueSignaler.get_future(); + (*tiIt)->fContinueSignal = fMasterContSignal; } return; @@ -704,12 +730,17 @@ namespace Nymph std::unique_lock< std::mutex > breakContLock( fBreakContMutex ); // set all break flags + // master break flag fDoRunBreakFlag = true; - for( std::vector< KTThreadIndicator >::iterator tiIt = fThreadIndicators.begin(); tiIt != fThreadIndicators.end(); ++tiIt ) + // thread break flags + for( auto tiIt = fThreadIndicators.begin(); tiIt != fThreadIndicators.end(); ++tiIt ) { - tiIt->fBreakFlag = true; + (*tiIt)->fBreakFlag = true; } + // use the do-run promise to signal the break + fDoRunPromise.set_value(); + return; } diff --git a/Library/Application/KTProcessorToolbox.hh b/Library/Application/KTProcessorToolbox.hh index 43b35e0..d8dfcd4 100644 --- a/Library/Application/KTProcessorToolbox.hh +++ b/Library/Application/KTProcessorToolbox.hh @@ -169,7 +169,6 @@ namespace Nymph Thread(KTPrimaryProcessor* proc, const std::string& name) : fProc(proc), fName(name) {} }; - //typedef std::set< KTPrimaryProcessor* > ThreadGroup; struct CompareThread { bool operator() (const Thread& lhs, const Thread& rhs) @@ -197,6 +196,8 @@ namespace Nymph /// If the return is true, processing can continue after the break bool WaitForBreak(); + void WaitForEndOfRun(); + void Continue(); private: @@ -208,14 +209,16 @@ namespace Nymph void TakeFuture( std::future< KTDataPtr >&& future ); std::vector< std::future< KTDataPtr > > fThreadFutures; - std::vector< KTThreadIndicator > fThreadIndicators; + std::vector< std::shared_ptr< KTThreadIndicator > > fThreadIndicators; std::promise< void > fContinueSignaler; std::shared_future< void > fMasterContSignal; std::mutex fBreakContMutex; + std::mutex fWaitForBreakMutex; std::thread* fDoRunThread; std::promise< void > fDoRunPromise; + std::shared_future< void > fDoRunFuture; bool fDoRunBreakFlag; // only use outside of blocks protected by fBreakContMutex is reads, so we shouldn't need to make this an atomic }; diff --git a/Library/Data/KTApplyCut.cc b/Library/Data/KTApplyCut.cc index 8952288..3907a42 100644 --- a/Library/Data/KTApplyCut.cc +++ b/Library/Data/KTApplyCut.cc @@ -95,7 +95,7 @@ namespace Nymph bool cutFailed = fCut->Apply(dataPtr); - ref->Break( dataPtr ); + ref->Break( dataPtr, fApplyCutSW->GetDoBreakpoint() ); if (cutFailed) { diff --git a/Library/Data/KTCutFilter.cc b/Library/Data/KTCutFilter.cc index 979e25d..7104a8b 100644 --- a/Library/Data/KTCutFilter.cc +++ b/Library/Data/KTCutFilter.cc @@ -82,7 +82,7 @@ namespace Nymph bool failCut = Filter(dataPtr->Of< KTData >()); - ref->Break( dataPtr ); + ref->Break( dataPtr, fFilterDataSW->GetDoBreakpoint() ); if (failCut) { diff --git a/Library/Processor/KTPrimaryProcessor.cc b/Library/Processor/KTPrimaryProcessor.cc index 437f498..0d089b8 100644 --- a/Library/Processor/KTPrimaryProcessor.cc +++ b/Library/Processor/KTPrimaryProcessor.cc @@ -17,7 +17,8 @@ namespace Nymph KTPrimaryProcessor::KTPrimaryProcessor( std::initializer_list< std::string > signals, const std::string& name ) : KTProcessor( name ), fSignalsEmitted( signals ), - fThreadRef() + fThreadRef(), + fDoBreakpoint(false) { } diff --git a/Library/Processor/KTPrimaryProcessor.hh b/Library/Processor/KTPrimaryProcessor.hh index 9dd3b1f..a7be18d 100644 --- a/Library/Processor/KTPrimaryProcessor.hh +++ b/Library/Processor/KTPrimaryProcessor.hh @@ -33,12 +33,13 @@ namespace Nymph KTThreadReference* GetThreadRef(); + MEMBERVARIABLE( bool, DoBreakpoint ); + protected: std::vector< std::string > fSignalsEmitted; KTThreadReference fThreadRef; - }; inline KTThreadReference* KTPrimaryProcessor::GetThreadRef() diff --git a/Library/Processor/KTProcessor.cc b/Library/Processor/KTProcessor.cc index c6a5a6a..9db9633 100644 --- a/Library/Processor/KTProcessor.cc +++ b/Library/Processor/KTProcessor.cc @@ -132,6 +132,26 @@ namespace Nymph return iter->second; } + inline bool KTProcessor::GetDoBreakpoint(const std::string& slotName) + { + KTSlotWrapper* slot = GetSlot(slotName); + if (slot != nullptr) + { + return slot->GetDoBreakpoint(); + } + KTWARN(processorlog, "Slot <" << slotName << "> was not found"); + return false; + } + void KTProcessor::SetDoBreakpoint(const std::string& slotName, bool flag) + { + KTSlotWrapper* slot = GetSlot(slotName); + if (slot != nullptr) + { + return slot->SetDoBreakpoint(flag); + } + KTWARN(processorlog, "Slot <" << slotName << "> was not found"); + return; + } } /* namespace Nymph */ diff --git a/Library/Processor/KTProcessor.hh b/Library/Processor/KTProcessor.hh index f29a1c8..ca2ef41 100644 --- a/Library/Processor/KTProcessor.hh +++ b/Library/Processor/KTProcessor.hh @@ -80,6 +80,9 @@ namespace Nymph KTSlotWrapper* GetSlot(const std::string& name); + bool GetDoBreakpoint(const std::string& slotName); + void SetDoBreakpoint(const std::string& slotName, bool flag); + protected: void ConnectSignalToSlot(KTSignalWrapper* signal, KTSlotWrapper* slot, int groupNum=-1); @@ -128,7 +131,6 @@ namespace Nymph return; } - #define KT_REGISTER_PROCESSOR(proc_class, proc_name) \ static ::scarab::registrar< ::Nymph::KTProcessor, proc_class, const std::string& > sProc##proc_class##Registrar( proc_name ); diff --git a/Library/Processor/KTSlot.hh b/Library/Processor/KTSlot.hh index 0d7ba13..ac43597 100644 --- a/Library/Processor/KTSlot.hh +++ b/Library/Processor/KTSlot.hh @@ -289,7 +289,7 @@ namespace Nymph // Perform breakpoint here if necessary (either if initiated here or if stopping here due to a breakpoint elsewhere) // Sets the dataPtr into the return - ref->Break( dataPtr ); + ref->Break( dataPtr, fSlotWrapper->GetDoBreakpoint() ); // If there's a signal pointer, emit the signal if( fSignalPtr != nullptr ) @@ -334,6 +334,10 @@ namespace Nymph // Call the function fFunc(); + // Perform breakpoint here if necessary (either if initiated here or if stopping here due to a breakpoint elsewhere) + // Sets the dataPtr into the return + fSlotWrapper->GetThreadRef()->Break( KTDataPtr(), fSlotWrapper->GetDoBreakpoint() ); + // If there's a signal pointer, emit the signal if( fSignalPtr != nullptr ) { diff --git a/Library/Processor/KTSlotWrapper.hh b/Library/Processor/KTSlotWrapper.hh index 675d570..329619b 100644 --- a/Library/Processor/KTSlotWrapper.hh +++ b/Library/Processor/KTSlotWrapper.hh @@ -91,8 +91,12 @@ namespace Nymph KTThreadReference* GetThreadRef() const; void SetThreadRef(KTThreadReference* ref); + bool GetDoBreakpoint() const; + void SetDoBreakpoint(bool flag); + private: KTThreadReference* fThreadRef; + bool fDoBreakpoint; }; @@ -100,7 +104,8 @@ namespace Nymph KTSlotWrapper::KTSlotWrapper(XSignature signalPtr, XTypeContainer* typeCont) : fSlotWrapper(new KTSpecifiedInternalSlotWrapper< XSignature, XTypeContainer >(signalPtr, typeCont)), fConnection(), - fThreadRef() + fThreadRef(), + fDoBreakpoint(false) {} inline void KTSlotWrapper::SetConnection(KTConnection conn) @@ -132,5 +137,17 @@ namespace Nymph return; } + inline bool KTSlotWrapper::GetDoBreakpoint() const + { + return fDoBreakpoint; + } + + inline void KTSlotWrapper::SetDoBreakpoint(bool flag) + { + fDoBreakpoint = flag; + return; + } + + } /* namespace Nymph */ #endif /* KTSLOTWRAPPER_HH_ */ diff --git a/Library/Processor/KTThreadReference.cc b/Library/Processor/KTThreadReference.cc index 745717b..36ef20a 100644 --- a/Library/Processor/KTThreadReference.cc +++ b/Library/Processor/KTThreadReference.cc @@ -7,7 +7,9 @@ #include "KTThreadReference.hh" -//#include "KTProcessorToolbox.hh" +#include "KTLogger.hh" + +KTLOGGER( trlog, "KTThreadReference" ); namespace Nymph { @@ -21,7 +23,7 @@ namespace Nymph fDataPtrRet(), fInitiateBreakFunc(), fRefreshFutureFunc(), - fThreadIndicator( nullptr ) + fThreadIndicator( new KTThreadIndicator() ) {} KTThreadReference::KTThreadReference( KTThreadReference&& orig ) : @@ -45,20 +47,23 @@ namespace Nymph return *this; } - - void KTThreadReference::Break( const KTDataPtr& dataPtr ) + void KTThreadReference::Break( const KTDataPtr& dataPtr, bool doBreakpoint ) { - bool breakInititatedHere = false; - if( /* breakpoint is set here */ false ) + if( doBreakpoint ) { - breakInititatedHere = true; + KTDEBUG( trlog, "Initiating break" ); fInitiateBreakFunc(); } - if( fThreadIndicator->fBreakFlag || breakInititatedHere ) + if( fThreadIndicator->fBreakFlag || doBreakpoint ) { + KTDEBUG( trlog, "Reacting to break" ); + // set the return for this thread fDataPtrRet.set_value( dataPtr ); + // wait for continue signal fThreadIndicator->fContinueSignal.wait(); + // reset the promise fDataPtrRet = KTDataPtrReturn(); + // pass the future back to the processor toolbox (if it's in use) fRefreshFutureFunc( fDataPtrRet.get_future() ); } return; diff --git a/Library/Processor/KTThreadReference.hh b/Library/Processor/KTThreadReference.hh index a918210..f317d62 100644 --- a/Library/Processor/KTThreadReference.hh +++ b/Library/Processor/KTThreadReference.hh @@ -10,6 +10,7 @@ #include "KTData.hh" +#include #include namespace Nymph @@ -27,7 +28,7 @@ namespace Nymph KTDataPtrReturn fDataPtrRet; std::function< void() > fInitiateBreakFunc; std::function< void(std::future< KTDataPtr >&&) > fRefreshFutureFunc; - KTThreadIndicator* fThreadIndicator; + std::shared_ptr< KTThreadIndicator > fThreadIndicator; KTThreadReference(); KTThreadReference( const KTThreadReference& ) = delete; @@ -36,7 +37,7 @@ namespace Nymph KTThreadReference& operator=( const KTThreadReference& ) = delete; KTThreadReference& operator=( KTThreadReference&& ); - void Break( const KTDataPtr& dataPtr ); + void Break( const KTDataPtr& dataPtr, bool doBreakpoint ); }; } /* namespace Nymph */ From 5eadbb358ea74d771b95208e16ef0b3a7e4004a9 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Fri, 5 May 2017 17:05:28 -0700 Subject: [PATCH 018/521] Adding breakpoints can now be done in a config file. Some stability improvements. --- Executables/Validation/TestUseBreakpoint.cc | 11 +- Library/Application/KTProcessorToolbox.cc | 106 +++++++++++++++++--- Library/Application/KTProcessorToolbox.hh | 27 ++++- Library/Processor/KTProcessor.cc | 8 +- 4 files changed, 125 insertions(+), 27 deletions(-) diff --git a/Executables/Validation/TestUseBreakpoint.cc b/Executables/Validation/TestUseBreakpoint.cc index 7e9040f..42fc2ce 100644 --- a/Executables/Validation/TestUseBreakpoint.cc +++ b/Executables/Validation/TestUseBreakpoint.cc @@ -7,8 +7,6 @@ #include "KTProcessorToolbox.hh" -#include "KTProcessor.hh" // temporary (todo below) - #include "KTLogger.hh" using namespace Nymph; @@ -35,8 +33,11 @@ int main() return -1; } // set breakpoint - // TODO: use configuration instead of manually setting - ptb.GetProcessor( "tp" )->SetDoBreakpoint( "first-slot", true ); + if( ! ptb.SetBreakpoint( "tp", "first-slot" ) ) + { + KTERROR( testptlog, "Unable to set the breakpoint" ); + return -1; + } // make connections if( ! ptb.MakeConnection( "tpp:the-signal", "tp:first-slot" ) ) @@ -76,6 +77,8 @@ int main() KTINFO( testptlog, "Processing complete" ); + ptb.JoinRunThread(); + KTINFO( testptlog, "Tests complete" ); return 0; diff --git a/Library/Application/KTProcessorToolbox.cc b/Library/Application/KTProcessorToolbox.cc index 9964547..ce198eb 100644 --- a/Library/Application/KTProcessorToolbox.cc +++ b/Library/Application/KTProcessorToolbox.cc @@ -42,7 +42,6 @@ namespace Nymph fContinueSignaler(), fMasterContSignal(), fBreakContMutex(), - fWaitForBreakMutex(), fDoRunThread( nullptr ), fDoRunPromise(), fDoRunBreakFlag( false ) @@ -51,6 +50,10 @@ namespace Nymph KTProcessorToolbox::~KTProcessorToolbox() { + CancelThreads(); + + JoinRunThread(); + ClearProcessors(); } @@ -166,6 +169,15 @@ namespace Nymph return false; } + if (connNode->has("breakpoint")) + { + if (! SetBreakpoint(connNode->get_value("slot"))) + { + KTERROR(proclog, "Unable to set breakpoint on <" << connNode->get_value("slot")); + return false; + } + } + KTINFO(proclog, "Signal <" << connNode->get_value("signal") << "> connected to slot <" << connNode->get_value("slot") << ">"); } } @@ -422,6 +434,72 @@ namespace Nymph return true; } + bool KTProcessorToolbox::SetBreakpoint(const std::string& slot) + { + string slotProcName, slotName; + if (! ParseSignalSlotName(slot, slotProcName, slotName)) + { + KTERROR(proclog, "Unable to parse slot name: <" << slot << ">"); + return false; + } + + return SetBreakpoint(slotProcName, slotName); + } + + bool KTProcessorToolbox::SetBreakpoint(const std::string& slotProcName, const std::string& slotName) + { + KTProcessor* slotProc = GetProcessor(slotProcName); + if (slotProc == NULL) + { + KTERROR(proclog, "Processor named <" << slotProcName << "> was not found!"); + return false; + } + + try + { + slotProc->SetDoBreakpoint(slotName, true); + return true; + } + catch (std::exception& e) + { + KTERROR(proclog, "Unable to set breakpoint: " << e.what()); + return false; + } + } + + bool KTProcessorToolbox::RemoveBreakpoint(const std::string& slot) + { + string slotProcName, slotName; + if (! ParseSignalSlotName(slot, slotProcName, slotName)) + { + KTERROR(proclog, "Unable to parse slot name: <" << slot << ">"); + return false; + } + + return RemoveBreakpoint(slotProcName, slotName); + } + + bool KTProcessorToolbox::RemoveBreakpoint(const std::string& slotProcName, const std::string& slotName) + { + KTProcessor* slotProc = GetProcessor(slotProcName); + if (slotProc == NULL) + { + KTERROR(proclog, "Processor named <" << slotProcName << "> was not found!"); + return false; + } + + try + { + slotProc->SetDoBreakpoint(slotName, false); + return true; + } + catch (std::exception& e) + { + KTERROR(proclog, "Unable to set breakpoint: " << e.what()); + return false; + } + } + bool KTProcessorToolbox::ParseSignalSlotName(const std::string& toParse, std::string& nameOfProc, std::string& nameOfSigSlot) const { size_t sepPos = toParse.find_first_of(fSigSlotNameSep); @@ -744,25 +822,23 @@ namespace Nymph return; } + void KTProcessorToolbox::CancelThreads() + { + std::unique_lock< std::mutex > breakContLock( fBreakContMutex ); + for( auto tiIt = fThreadIndicators.begin(); tiIt != fThreadIndicators.end(); ++tiIt ) + { + (*tiIt)->fCanceled = true; + } + return; + } + bool KTProcessorToolbox::Run() { AsyncRun(); - std::future< void > doRunFuture = fDoRunPromise.get_future(); + WaitForEndOfRun(); - try - { - while( WaitForBreak() ) - { - KTINFO( proclog, "Skipping breakpoint" ); - Continue(); - } - } - catch( std::exception& e ) - { - KTERROR( proclog, "An error occurred: " << e.what() ); - return false; - } + JoinRunThread(); return true; } diff --git a/Library/Application/KTProcessorToolbox.hh b/Library/Application/KTProcessorToolbox.hh index d8dfcd4..ef300d4 100644 --- a/Library/Application/KTProcessorToolbox.hh +++ b/Library/Application/KTProcessorToolbox.hh @@ -141,6 +141,18 @@ namespace Nymph /// Both processors should already have been added to the Toolbox bool MakeConnection(const std::string& signalProcName, const std::string& signalName, const std::string& slotProcName, const std::string& slotName, int order = std::numeric_limits< int >::min()); + /// Set a breakpoint on a slot + /// Slot string should be formatted as: [processor name]:[slot name] + bool SetBreakpoint(const std::string& slot); + /// Set a breakpoint on a slot + bool SetBreakpoint(const std::string& slotProcName, const std::string& slotName); + + /// Remove a breakpoint from a slot + /// Slot string should be formatted as: [processor name]:[slot name] + bool RemoveBreakpoint(const std::string& slot); + /// Remove a breakpoint from a slot + bool RemoveBreakpoint(const std::string& slotProcName, const std::string& slotName); + private: bool ParseSignalSlotName(const std::string& toParse, std::string& nameOfProc, std::string& nameOfSigSlot) const; static const char fSigSlotNameSep = ':'; @@ -200,6 +212,10 @@ namespace Nymph void Continue(); + void CancelThreads(); + + void JoinRunThread(); + private: friend class KTThreadReference; @@ -214,12 +230,11 @@ namespace Nymph std::promise< void > fContinueSignaler; std::shared_future< void > fMasterContSignal; std::mutex fBreakContMutex; - std::mutex fWaitForBreakMutex; std::thread* fDoRunThread; std::promise< void > fDoRunPromise; std::shared_future< void > fDoRunFuture; - bool fDoRunBreakFlag; // only use outside of blocks protected by fBreakContMutex is reads, so we shouldn't need to make this an atomic + bool fDoRunBreakFlag; }; @@ -247,7 +262,13 @@ namespace Nymph return; } - + inline void KTProcessorToolbox::JoinRunThread() + { + if( fDoRunThread == nullptr ) return; + fDoRunThread->join(); + delete fDoRunThread; + fDoRunThread = nullptr; + } } /* namespace Nymph */ #endif /* KTPROCESSORTOOLBOX_HH_ */ diff --git a/Library/Processor/KTProcessor.cc b/Library/Processor/KTProcessor.cc index 9db9633..06fc429 100644 --- a/Library/Processor/KTProcessor.cc +++ b/Library/Processor/KTProcessor.cc @@ -7,10 +7,9 @@ #include "KTProcessor.hh" +#include "KTException.hh" //#include "KTLogger.hh" -#include - #include using std::string; @@ -139,8 +138,7 @@ namespace Nymph { return slot->GetDoBreakpoint(); } - KTWARN(processorlog, "Slot <" << slotName << "> was not found"); - return false; + throw KTException() << "Slot <" << slotName << "> was not found"; } void KTProcessor::SetDoBreakpoint(const std::string& slotName, bool flag) @@ -150,7 +148,7 @@ namespace Nymph { return slot->SetDoBreakpoint(flag); } - KTWARN(processorlog, "Slot <" << slotName << "> was not found"); + throw KTException() << "Slot <" << slotName << "> was not found"; return; } From 8f15788e2e3668461a8bcc83427892cdd91fa83d Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Mon, 8 May 2017 13:22:24 -0700 Subject: [PATCH 019/521] Switched to boost::thread in KTProcessorToolbox --- CMakeLists.txt | 2 +- Library/Application/KTProcessorToolbox.cc | 129 +++++++++++++++++----- Library/Application/KTProcessorToolbox.hh | 17 +-- Library/Processor/KTThreadReference.hh | 5 +- 4 files changed, 113 insertions(+), 40 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 102466c..69381f7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -75,7 +75,7 @@ set( RAPIDJSON_FILE_BUFFER_SIZE ${RAPIDJSON_FILE_BUFFER_SIZE} PARENT_SCOPE ) ####### # Boost (1.46 required for filesystem version 3) -list (APPEND Boost_COMPONENTS date_time filesystem program_options system thread) +list (APPEND Boost_COMPONENTS chrono date_time filesystem program_options system thread) if (Nymph_ENABLE_PYTHON) list(APPEND Boost_COMPONENTS python) endif (Nymph_ENABLE_PYTHON) diff --git a/Library/Application/KTProcessorToolbox.cc b/Library/Application/KTProcessorToolbox.cc index ce198eb..3750a8e 100644 --- a/Library/Application/KTProcessorToolbox.cc +++ b/Library/Application/KTProcessorToolbox.cc @@ -12,16 +12,10 @@ #include "KTPrimaryProcessor.hh" #include "factory.hh" +#include "param_codec.hh" -#ifndef SINGLETHREADED +#include #include -#endif - -#include -#include -#include - -#include "param_codec.hh" using std::deque; using std::set; @@ -586,7 +580,7 @@ namespace Nymph return; } - fDoRunPromise = std::promise< void >(); + fDoRunPromise = boost::promise< void >(); fDoRunFuture = fDoRunPromise.get_future().share(); bool willRunSingleThreaded = fRunSingleThreaded; @@ -601,15 +595,15 @@ namespace Nymph try { // reset the continue signaler - fContinueSignaler = std::promise< void >(); + fContinueSignaler = boost::promise< void >(); fMasterContSignal = fContinueSignaler.get_future().share(); if( ! fMasterContSignal.valid() ) { KTERROR( proclog, "Invalid master continue-signal created" ); - throw std::future_error( std::future_errc::no_state ); + throw KTException() << "Invalid master continue-signal created"; } // copy for use in this function - std::shared_future< void > continueSignal = fMasterContSignal; + boost::shared_future< void > continueSignal = fMasterContSignal; KTPROG( proclog, "Starting single-threaded processing" ); @@ -626,7 +620,7 @@ namespace Nymph if( ! fThreadFutures.back().valid() ) { KTERROR( proclog, "Invalid thread future created" ); - throw std::future_error( std::future_errc::no_state ); + throw KTException() << "Invalid thread future created"; } fThreadIndicators.emplace_back( new KTThreadIndicator() ); @@ -636,7 +630,8 @@ namespace Nymph thisThreadRef.fInitiateBreakFunc = [&](){ this->InitiateBreak(); }; thisThreadRef.fRefreshFutureFunc = [&]( std::future< KTDataPtr >&& ret ){ this->TakeFuture( std::move(ret) ); }; - std::thread thread( &KTPrimaryProcessor::operator(), tgIter->fProc, std::move( thisThreadRef ) ); + //boost::thread thread( &KTPrimaryProcessor::operator(), tgIter->fProc, std::move( thisThreadRef ) ); + boost::thread thread( [&](){ tgIter->fProc->operator()( std::move( thisThreadRef ) ); } ); KTDEBUG( proclog, "Thread ID is <" << thread.get_id() << ">" ); @@ -692,50 +687,124 @@ namespace Nymph return; }; - fDoRunThread = new std::thread( singleThreadRun ); + fDoRunThread = new boost::thread( singleThreadRun ); } else - { + {/* auto multiThreadRun = [&]() { try { - std::shared_future< void > fMasterContSignal( fContinueSignaler.get_future() ); + // reset the continue signaler + fContinueSignaler = boost::promise< void >(); + fMasterContSignal = fContinueSignaler.get_future().share(); if( ! fMasterContSignal.valid() ) { KTERROR( proclog, "Invalid master continue-signal created" ); - throw std::future_error( std::future_errc::no_state ); + throw boost::future_error( boost::future_errc::no_state ); } + // copy for use in this function + boost::shared_future< void > continueSignal = fMasterContSignal; KTPROG( proclog, "Starting multi-threaded processing" ); - // TODO logic to start threads goes here + for (RunQueue::iterator rqIter = fRunQueue.begin(); rqIter != fRunQueue.end(); ++rqIter) + { + vector< boost::thread > threads; + + for (ThreadGroup::iterator tgIter = rqIter->begin(); tgIter != rqIter->end(); ++tgIter) + { + std::string procName( tgIter->fName ); + KTINFO( proclog, "Starting processor <" << procName << ">" ); + + KTThreadReference thisThreadRef; + + fThreadFutures.push_back( thisThreadRef.fDataPtrRet.get_future() ); + if( ! fThreadFutures.back().valid() ) + { + KTERROR( proclog, "Invalid thread future created" ); + throw boost::future_error( boost::future_errc::no_state ); + } + + fThreadIndicators.emplace_back( new KTThreadIndicator() ); + fThreadIndicators.back()->fContinueSignal = fMasterContSignal; + + thisThreadRef.fThreadIndicator = fThreadIndicators.back(); + thisThreadRef.fInitiateBreakFunc = [&](){ this->InitiateBreak(); }; + thisThreadRef.fRefreshFutureFunc = [&]( boost::future< KTDataPtr >&& ret ){ this->TakeFuture( std::move(ret) ); }; + + threads.emplace_back( boost::thread( &KTPrimaryProcessor::operator(), tgIter->fProc, std::move( thisThreadRef ) ) ); + + KTDEBUG( proclog, "Thread ID is <" << threads.back().get_id() << ">" ); + }// end for loop over the thread group + + bool stillRunning = true; // determines behavior that depends on whether a return from the thread was temporary or from the thread completing + do + { + boost::future_status status; + do + { + status = fThreadFutures.back().wait_for(boost::chrono::milliseconds(500)); + } while (status != boost::future_status::ready); + + stillRunning = false; + if( fDoRunBreakFlag ) + { + KTDEBUG( proclog, "Breakpoint reached" ); + continueSignal.wait(); + KTDEBUG( proclog, "Breakpoint finished" ); + stillRunning = true; + continueSignal = fMasterContSignal; // refresh the local copy of the shared future + } + else + { + try + { + fThreadFutures.back().get(); + } + catch( std::exception& e ) + { + // this transfers an exception thrown by a processor to the outer catch block in this function + throw KTException() << "An error occurred while running processor <" << procName << ">: " << e.what(); + } + stillRunning = false; + } + } while( stillRunning ); + + KTINFO( proclog, "Processor <" << procName << "> has finished" ); + + thread.join(); + fThreadIndicators.pop_back(); + fThreadFutures.pop_back(); + + } // end for loop over the run-queue KTPROG( proclog, "Processing is complete (multi-threaded)" ); } catch( ... ) { + // exceptions thrown in this function or from within processors will end up here fDoRunPromise.set_exception( std::current_exception() ); } fDoRunPromise.set_value(); return; }; - fDoRunThread = new std::thread( multiThreadRun ); - } + fDoRunThread = new boost::thread( multiThreadRun ); + */} return; } bool KTProcessorToolbox::WaitForBreak() { - std::shared_future< void > doRunFuture = fDoRunFuture; + boost::shared_future< void > doRunFuture = fDoRunFuture; - std::future_status doRunStatus; + boost::future_status doRunStatus; do { - doRunStatus = doRunFuture.wait_for( std::chrono::milliseconds( 500 ) ); - } while( doRunStatus != std::future_status::ready ); + doRunStatus = doRunFuture.wait_for( boost::chrono::milliseconds( 500 ) ); + } while( doRunStatus != boost::future_status::ready ); if( fDoRunBreakFlag ) { @@ -771,7 +840,7 @@ namespace Nymph void KTProcessorToolbox::Continue() { - std::unique_lock< std::mutex > breakContLock( fBreakContMutex ); + boost::unique_lock< boost::mutex > breakContLock( fBreakContMutex ); // futures have been used; clear them to be replaced fThreadFutures.clear(); @@ -784,7 +853,7 @@ namespace Nymph } // reset the do-run promise and future - fDoRunPromise = std::promise< void >(); + fDoRunPromise = boost::promise< void >(); fDoRunFuture = fDoRunPromise.get_future().share(); KTINFO( proclog, "Continuing from breakpoint" ); @@ -793,7 +862,7 @@ namespace Nymph // reset the signaler and all signals // hopefully the delay of creating the new signaler and starting the for loop is enough that anything waiting on the old signal has already seen that signal and moved on - fContinueSignaler = std::promise< void >(); + fContinueSignaler = boost::promise< void >(); fMasterContSignal = fContinueSignaler.get_future().share(); for( auto tiIt = fThreadIndicators.begin(); tiIt != fThreadIndicators.end(); ++tiIt ) { @@ -805,7 +874,7 @@ namespace Nymph void KTProcessorToolbox::InitiateBreak() { - std::unique_lock< std::mutex > breakContLock( fBreakContMutex ); + boost::unique_lock< boost::mutex > breakContLock( fBreakContMutex ); // set all break flags // master break flag @@ -824,7 +893,7 @@ namespace Nymph void KTProcessorToolbox::CancelThreads() { - std::unique_lock< std::mutex > breakContLock( fBreakContMutex ); + boost::unique_lock< boost::mutex > breakContLock( fBreakContMutex ); for( auto tiIt = fThreadIndicators.begin(); tiIt != fThreadIndicators.end(); ++tiIt ) { (*tiIt)->fCanceled = true; diff --git a/Library/Application/KTProcessorToolbox.hh b/Library/Application/KTProcessorToolbox.hh index ef300d4..b07b9ed 100644 --- a/Library/Application/KTProcessorToolbox.hh +++ b/Library/Application/KTProcessorToolbox.hh @@ -15,8 +15,11 @@ #include "factory.hh" +#include +#include +#include + #include -#include #include #include #include @@ -227,13 +230,13 @@ namespace Nymph std::vector< std::future< KTDataPtr > > fThreadFutures; std::vector< std::shared_ptr< KTThreadIndicator > > fThreadIndicators; - std::promise< void > fContinueSignaler; - std::shared_future< void > fMasterContSignal; - std::mutex fBreakContMutex; + boost::promise< void > fContinueSignaler; + boost::shared_future< void > fMasterContSignal; + boost::mutex fBreakContMutex; - std::thread* fDoRunThread; - std::promise< void > fDoRunPromise; - std::shared_future< void > fDoRunFuture; + boost::thread* fDoRunThread; + boost::promise< void > fDoRunPromise; + boost::shared_future< void > fDoRunFuture; bool fDoRunBreakFlag; }; diff --git a/Library/Processor/KTThreadReference.hh b/Library/Processor/KTThreadReference.hh index f317d62..f149014 100644 --- a/Library/Processor/KTThreadReference.hh +++ b/Library/Processor/KTThreadReference.hh @@ -10,15 +10,16 @@ #include "KTData.hh" +#include + #include -#include namespace Nymph { struct KTThreadIndicator { bool fBreakFlag; // only use outside of blocks protected by a mutex are reads, so we shouldn't need to make this an atomic - std::shared_future< void > fContinueSignal; + boost::shared_future< void > fContinueSignal; bool fCanceled; KTThreadIndicator(); }; From 190988990892994bbc0a8a1273d051ac231192d1 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Mon, 8 May 2017 17:50:43 -0700 Subject: [PATCH 020/521] Multithreaded running complete and tested --- Executables/Validation/CMakeLists.txt | 1 + .../TestProcessorToolboxMultithreaded.cc | 87 +++++++++++++++ Executables/Validation/TestUseBreakpoint.cc | 3 +- Library/Application/KTProcessorToolbox.cc | 101 ++++++++++++------ Library/Application/KTProcessorToolbox.hh | 44 +++++++- Library/Data/KTData.hh | 6 +- Library/Processor/KTThreadReference.cc | 9 +- Library/Processor/KTThreadReference.hh | 3 +- 8 files changed, 208 insertions(+), 46 deletions(-) create mode 100644 Executables/Validation/TestProcessorToolboxMultithreaded.cc diff --git a/Executables/Validation/CMakeLists.txt b/Executables/Validation/CMakeLists.txt index a3e1dc2..c8d1b48 100644 --- a/Executables/Validation/CMakeLists.txt +++ b/Executables/Validation/CMakeLists.txt @@ -54,6 +54,7 @@ if (Nymph_ENABLE_TESTING) TestPrimaryProcessorNoThreading TestPrintData TestProcessorToolbox + TestProcessorToolboxMultithreaded TestSignalsAndSlots TestThroughputProfiler TestUseBreakpoint diff --git a/Executables/Validation/TestProcessorToolboxMultithreaded.cc b/Executables/Validation/TestProcessorToolboxMultithreaded.cc new file mode 100644 index 0000000..f9a348c --- /dev/null +++ b/Executables/Validation/TestProcessorToolboxMultithreaded.cc @@ -0,0 +1,87 @@ +/* + * TestProcessorToolboxMultithreaded.cc + * + * Created on: May 8, 2017 + * Author: N.S. Oblath + */ + +#include "KTProcessorToolbox.hh" + +#include "KTLogger.hh" + +using namespace Nymph; + +KTLOGGER( testptlog, "TestProcessorToolbox" ) + +int main() +{ + KTINFO( testptlog, "Preparing to run" ); + + KTProcessorToolbox ptb; + + // add the primary processor, thread 1 + if( ! ptb.AddProcessor( "test-p-proc", "tpp1" ) ) + { + KTERROR( testptlog, "Unable to create test primary processor (thread 1)" ); + return -1; + } + + // add processor b, thread 1 + if( ! ptb.AddProcessor( "test-proc-b", "tp1" ) ) + { + KTERROR( testptlog, "Unable to create test processor b (thread 1)" ); + return -1; + } + + // add the primary processor, thread 2 + if( ! ptb.AddProcessor( "test-p-proc", "tpp2" ) ) + { + KTERROR( testptlog, "Unable to create test primary processor (thread 2)" ); + return -1; + } + + // add processor b, thread 2 + if( ! ptb.AddProcessor( "test-proc-b", "tp2" ) ) + { + KTERROR( testptlog, "Unable to create test processor b (thread 2)" ); + return -1; + } + + // make connections, thread 1 + if( ! ptb.MakeConnection( "tpp1:the-signal", "tp1:first-slot" ) ) + { + KTERROR( testptlog, "Unable to connect tpp1 to tp1" ); + return -1; + } + + // make connections, thread 2 + if( ! ptb.MakeConnection( "tpp2:the-signal", "tp2:first-slot" ) ) + { + KTERROR( testptlog, "Unable to connect tpp2 to tp2" ); + return -1; + } + + // set the run queue + if( ! ptb.PushBackToRunQueue( {"tpp1", "tpp2"} ) ) + { + KTERROR( testptlog, "Unable to add {tpp1, tpp2} to the run queue" ); + return -1; + } + + // go! + KTINFO( testptlog, "Starting asynchronous run" ); + ptb.AsyncRun(); + + // wait for run completion, and ignore breakpoints + while( ptb.WaitForBreak() ) + { + KTINFO( testptlog, "Reached breakpoint; continuing" ); + ptb.Continue(); + } + + KTINFO( testptlog, "Processing complete" ); + + KTINFO( testptlog, "Tests complete" ); + + return 0; +} diff --git a/Executables/Validation/TestUseBreakpoint.cc b/Executables/Validation/TestUseBreakpoint.cc index 42fc2ce..466b814 100644 --- a/Executables/Validation/TestUseBreakpoint.cc +++ b/Executables/Validation/TestUseBreakpoint.cc @@ -9,6 +9,7 @@ #include "KTLogger.hh" + using namespace Nymph; KTLOGGER( testptlog, "TestUseBreakpoint" ) @@ -58,7 +59,7 @@ int main() ptb.AsyncRun(); KTINFO( testptlog, "Starting asynchronous breakpoint user" ); - auto buFuture = std::async( std::launch::async, [&](){ + auto buFuture = boost::async( boost::launch::async, [&](){ KTINFO( testptlog, "In breakpoint user thread" ); while( ptb.WaitForBreak() ) { diff --git a/Library/Application/KTProcessorToolbox.cc b/Library/Application/KTProcessorToolbox.cc index 3750a8e..ae65d3d 100644 --- a/Library/Application/KTProcessorToolbox.cc +++ b/Library/Application/KTProcessorToolbox.cc @@ -14,7 +14,6 @@ #include "factory.hh" #include "param_codec.hh" -#include #include using std::deque; @@ -29,7 +28,7 @@ namespace Nymph KTProcessorToolbox::KTProcessorToolbox(const std::string& name) : KTConfigurable(name), fProcFactory(scarab::factory< KTProcessor, const std::string& >::get_instance()), - fRunSingleThreaded( true ), //TODO: switch this to false once multithreading is available + fRunSingleThreaded( false ), fRunQueue(), fProcMap(), fThreadFutures(), @@ -616,7 +615,14 @@ namespace Nymph KTThreadReference thisThreadRef; - fThreadFutures.push_back( thisThreadRef.fDataPtrRet.get_future() ); + //fThreadFutures.get<1>().insert( LabeledFuture{ procName, thisThreadRef.fDataPtrRet.get_future() } ); + //fThreadFutures.push_back( LabeledFuture{ procName, thisThreadRef.fDataPtrRet.get_future() } ); + fThreadFutures.push_back( std::move( thisThreadRef.fDataPtrRet.get_future() ) ); + fThreadNames.push_back( procName ); + //auto& futureNameIndex = fThreadFutures.get<1>(); + + //auto thisFuturePtr = futureNameIndex.find( procName ); + //if( ! thisFuturePtr->fFuture.valid() ) if( ! fThreadFutures.back().valid() ) { KTERROR( proclog, "Invalid thread future created" ); @@ -628,7 +634,7 @@ namespace Nymph thisThreadRef.fThreadIndicator = fThreadIndicators.back(); thisThreadRef.fInitiateBreakFunc = [&](){ this->InitiateBreak(); }; - thisThreadRef.fRefreshFutureFunc = [&]( std::future< KTDataPtr >&& ret ){ this->TakeFuture( std::move(ret) ); }; + thisThreadRef.fRefreshFutureFunc = [&]( const std::string& name, Future&& ret ){ this->TakeFuture( name, std::move(ret) ); }; //boost::thread thread( &KTPrimaryProcessor::operator(), tgIter->fProc, std::move( thisThreadRef ) ); boost::thread thread( [&](){ tgIter->fProc->operator()( std::move( thisThreadRef ) ); } ); @@ -638,16 +644,17 @@ namespace Nymph bool stillRunning = true; // determines behavior that depends on whether a return from the thread was temporary or from the thread completing do { - std::future_status status; + boost::future_status status; do { - status = fThreadFutures.back().wait_for(std::chrono::milliseconds(500)); - } while (status != std::future_status::ready); + //status = thisFuturePtr->fFuture.wait_for( std::chrono::milliseconds(500) ); + status = fThreadFutures.back().wait_for( boost::chrono::milliseconds(500) ); + } while (status != boost::future_status::ready); stillRunning = false; if( fThreadIndicators.back()->fBreakFlag ) { - KTDEBUG( proclog, "Breakpoint reached" ); + KTDEBUG( proclog, "Breakpoint reached (originated in thread <" << fThreadNames.back() << ">)" ); continueSignal.wait(); KTDEBUG( proclog, "Breakpoint finished" ); stillRunning = true; @@ -657,10 +664,15 @@ namespace Nymph { try { + //futureNameIndex.modify( thisFuturePtr, [](LabeledFuture& lFuture){ lFuture.fFuture.get(); } ); fThreadFutures.back().get(); + KTINFO( proclog, "Thread <" << fThreadNames.back() << "> has finished" ); + fThreadFutures.pop_back(); + fThreadNames.pop_back(); } catch( std::exception& e ) { + KTERROR( proclog, "Thread <" << fThreadNames.back() << "> threw an error: " << e.what() ); // this transfers an exception thrown by a processor to the outer catch block in this function throw KTException() << "An error occurred while running processor <" << procName << ">: " << e.what(); } @@ -671,8 +683,9 @@ namespace Nymph KTINFO( proclog, "Processor <" << procName << "> has finished" ); thread.join(); - fThreadIndicators.pop_back(); - fThreadFutures.pop_back(); + fThreadIndicators.clear(); + fThreadFutures.clear(); + fThreadNames.clear(); } // end for loop over the thread group } // end for loop over the run-queue @@ -690,7 +703,7 @@ namespace Nymph fDoRunThread = new boost::thread( singleThreadRun ); } else - {/* + { auto multiThreadRun = [&]() { try @@ -701,7 +714,7 @@ namespace Nymph if( ! fMasterContSignal.valid() ) { KTERROR( proclog, "Invalid master continue-signal created" ); - throw boost::future_error( boost::future_errc::no_state ); + throw KTException() << "Invalid master continue-signal created"; } // copy for use in this function boost::shared_future< void > continueSignal = fMasterContSignal; @@ -710,7 +723,9 @@ namespace Nymph for (RunQueue::iterator rqIter = fRunQueue.begin(); rqIter != fRunQueue.end(); ++rqIter) { - vector< boost::thread > threads; + boost::thread_group threads; + + //auto& futureNameIndex = fThreadFutures.get<1>(); for (ThreadGroup::iterator tgIter = rqIter->begin(); tgIter != rqIter->end(); ++tgIter) { @@ -719,11 +734,17 @@ namespace Nymph KTThreadReference thisThreadRef; - fThreadFutures.push_back( thisThreadRef.fDataPtrRet.get_future() ); + //futureNameIndex.insert( LabeledFuture{ procName, thisThreadRef.fDataPtrRet.get_future() } ); + //fThreadFutures.push_back( LabeledFuture{ procName, thisThreadRef.fDataPtrRet.get_future() } ); + fThreadFutures.push_back( std::move( thisThreadRef.fDataPtrRet.get_future() ) ); + fThreadNames.push_back( procName ); + + //auto thisFuturePtr = futureNameIndex.find( procName ); + //if( ! thisFuturePtr->fFuture.valid() ) if( ! fThreadFutures.back().valid() ) { KTERROR( proclog, "Invalid thread future created" ); - throw boost::future_error( boost::future_errc::no_state ); + throw KTException() << "Invalid thread future created"; } fThreadIndicators.emplace_back( new KTThreadIndicator() ); @@ -731,26 +752,31 @@ namespace Nymph thisThreadRef.fThreadIndicator = fThreadIndicators.back(); thisThreadRef.fInitiateBreakFunc = [&](){ this->InitiateBreak(); }; - thisThreadRef.fRefreshFutureFunc = [&]( boost::future< KTDataPtr >&& ret ){ this->TakeFuture( std::move(ret) ); }; + thisThreadRef.fRefreshFutureFunc = [&]( const std::string& name, Future&& ret ){ this->TakeFuture( name, std::move(ret) ); }; - threads.emplace_back( boost::thread( &KTPrimaryProcessor::operator(), tgIter->fProc, std::move( thisThreadRef ) ) ); + //threads.emplace_back( boost::thread( &KTPrimaryProcessor::operator(), tgIter->fProc, std::move( thisThreadRef ) ) ); + boost::thread* thisThread = new boost::thread( [&](){ tgIter->fProc->operator()( std::move( thisThreadRef ) ); } ); + KTDEBUG( proclog, "Thread ID is <" << thisThread->get_id() << ">" ); + + threads.add_thread( thisThread ); - KTDEBUG( proclog, "Thread ID is <" << threads.back().get_id() << ">" ); }// end for loop over the thread group + //auto& futureIndex = fThreadFutures.get<0>(); + bool stillRunning = true; // determines behavior that depends on whether a return from the thread was temporary or from the thread completing do { - boost::future_status status; - do - { - status = fThreadFutures.back().wait_for(boost::chrono::milliseconds(500)); - } while (status != boost::future_status::ready); + //auto finishedFuturePtr = boost::wait_for_any( futureIndex.begin(), futureIndex.end() ); + auto finishedFuturePtr = boost::wait_for_any( fThreadFutures.begin(), fThreadFutures.end() ); + size_t iThread = finishedFuturePtr - fThreadFutures.begin(); + std::string threadName( fThreadNames[iThread] ); stillRunning = false; if( fDoRunBreakFlag ) { - KTDEBUG( proclog, "Breakpoint reached" ); + // a breakpoint has been reached + KTDEBUG( proclog, "Breakpoint reached (originated in thread <" << threadName << ">)" ); continueSignal.wait(); KTDEBUG( proclog, "Breakpoint finished" ); stillRunning = true; @@ -758,25 +784,32 @@ namespace Nymph } else { + // we're finished a thread; get its results try { - fThreadFutures.back().get(); + //futureIndex.modify( finishedFuturePtr, [](LabeledFuture& lFuture){ lFuture.fFuture.get(); } ); + finishedFuturePtr->get(); + KTINFO( proclog, "Thread <" << threadName << "> has finished" ); + fThreadFutures.erase( finishedFuturePtr ); + fThreadNames.erase( fThreadNames.begin() + iThread ); } catch( std::exception& e ) { + KTERROR( proclog, "Thread <" << threadName << "> threw an error: " << e.what() ); // this transfers an exception thrown by a processor to the outer catch block in this function - throw KTException() << "An error occurred while running processor <" << procName << ">: " << e.what(); + throw KTException() << "An error occurred while running processor <" << threadName << ">: " << e.what(); } - stillRunning = false; + + fThreadFutures.erase( finishedFuturePtr ); + if( fThreadFutures.empty() ) stillRunning = false; + else stillRunning = true; } } while( stillRunning ); - KTINFO( proclog, "Processor <" << procName << "> has finished" ); - - thread.join(); - fThreadIndicators.pop_back(); - fThreadFutures.pop_back(); - + threads.join_all(); + fThreadIndicators.clear(); + fThreadFutures.clear(); + fThreadNames.clear(); } // end for loop over the run-queue KTPROG( proclog, "Processing is complete (multi-threaded)" ); @@ -791,7 +824,7 @@ namespace Nymph }; fDoRunThread = new boost::thread( multiThreadRun ); - */} + } return; } diff --git a/Library/Application/KTProcessorToolbox.hh b/Library/Application/KTProcessorToolbox.hh index b07b9ed..3cc488e 100644 --- a/Library/Application/KTProcessorToolbox.hh +++ b/Library/Application/KTProcessorToolbox.hh @@ -15,15 +15,23 @@ #include "factory.hh" +#define BOOST_THREAD_PROVIDES_FUTURE #include #include #include +//#include +//#include +//#include +//#include + #include #include #include #include +//namespace bmi = boost::multi_index; + namespace Nymph { class KTPrimaryProcessor; @@ -222,13 +230,36 @@ namespace Nymph private: friend class KTThreadReference; + typedef boost::unique_future< KTDataPtr > Future; + //typedef std::future< KTDataPtr > Future; + // called from ThreadPacket::Break void InitiateBreak(); // called from ThreadPacket::Break - void TakeFuture( std::future< KTDataPtr >&& future ); - - std::vector< std::future< KTDataPtr > > fThreadFutures; - std::vector< std::shared_ptr< KTThreadIndicator > > fThreadIndicators; + void TakeFuture( const std::string& name, Future&& future ); + + //struct LabeledFuture + //{ + // std::string fName; + // std::future< KTDataPtr > fFuture; + //}; + //typedef std::vector< LabeledFuture > ThreadFutures; + typedef std::vector< Future > ThreadFutures; + typedef std::vector< std::string > ThreadNames; + //typedef std::map< std::string, std::future< KTDataPtr > > ThreadFutures; + //typedef boost::multi_index_container< + // LabeledFuture, + // bmi::indexed_by< + // bmi::random_access<>, + // bmi::ordered_unique< bmi::member< KTProcessorToolbox::LabeledFuture, std::string, &KTProcessorToolbox::LabeledFuture::fName > > + // > + //> ThreadFutures; + + ThreadFutures fThreadFutures; + ThreadNames fThreadNames; + + typedef std::vector< std::shared_ptr< KTThreadIndicator > > ThreadIndicators; + ThreadIndicators fThreadIndicators; boost::promise< void > fContinueSignaler; boost::shared_future< void > fMasterContSignal; @@ -259,9 +290,12 @@ namespace Nymph return; } - inline void KTProcessorToolbox::TakeFuture( std::future< KTDataPtr >&& future ) + inline void KTProcessorToolbox::TakeFuture( const std::string& name, Future&& future ) { + //fThreadFutures.get<1>().insert( LabeledFuture{ name, std::move( future ) } ); + //fThreadFutures.push_back( LabeledFuture{ name, std::move( future ) } ); fThreadFutures.push_back( std::move( future ) ); + fThreadNames.push_back( name ); return; } diff --git a/Library/Data/KTData.hh b/Library/Data/KTData.hh index 7e3293f..32838e9 100644 --- a/Library/Data/KTData.hh +++ b/Library/Data/KTData.hh @@ -13,7 +13,9 @@ #include "KTCutStatus.hh" #include "KTMemberVariable.hh" -#include +#include + +//#include #include #include @@ -73,7 +75,7 @@ namespace Nymph typedef std::shared_ptr< KTData > KTDataPtr; - typedef std::promise< KTDataPtr > KTDataPtrReturn; + typedef boost::promise< KTDataPtr > KTDataPtrReturn; #define THROW_RETURN_EXCEPTION( ret_promise, exception ) \ ret_promise.set_exception( std::make_exception_ptr( exception ) ); diff --git a/Library/Processor/KTThreadReference.cc b/Library/Processor/KTThreadReference.cc index 36ef20a..1309bf0 100644 --- a/Library/Processor/KTThreadReference.cc +++ b/Library/Processor/KTThreadReference.cc @@ -23,14 +23,16 @@ namespace Nymph fDataPtrRet(), fInitiateBreakFunc(), fRefreshFutureFunc(), - fThreadIndicator( new KTThreadIndicator() ) + fThreadIndicator( new KTThreadIndicator() ), + fPrimaryProcName() {} KTThreadReference::KTThreadReference( KTThreadReference&& orig ) : fDataPtrRet( std::move( orig.fDataPtrRet ) ), fInitiateBreakFunc( std::move( orig.fInitiateBreakFunc ) ), fRefreshFutureFunc( std::move( orig.fRefreshFutureFunc ) ), - fThreadIndicator( orig.fThreadIndicator ) + fThreadIndicator( orig.fThreadIndicator ), + fPrimaryProcName( std::move( orig.fPrimaryProcName ) ) { orig.fThreadIndicator = nullptr; } @@ -41,6 +43,7 @@ namespace Nymph fInitiateBreakFunc = std::move( orig.fInitiateBreakFunc ); fRefreshFutureFunc = std::move( orig.fRefreshFutureFunc ); fThreadIndicator = orig.fThreadIndicator; + fPrimaryProcName = std::move( orig.fPrimaryProcName ); orig.fThreadIndicator = nullptr; @@ -64,7 +67,7 @@ namespace Nymph // reset the promise fDataPtrRet = KTDataPtrReturn(); // pass the future back to the processor toolbox (if it's in use) - fRefreshFutureFunc( fDataPtrRet.get_future() ); + fRefreshFutureFunc( fPrimaryProcName, std::move( fDataPtrRet.get_future() ) ); } return; } diff --git a/Library/Processor/KTThreadReference.hh b/Library/Processor/KTThreadReference.hh index f149014..3f90f74 100644 --- a/Library/Processor/KTThreadReference.hh +++ b/Library/Processor/KTThreadReference.hh @@ -28,8 +28,9 @@ namespace Nymph { KTDataPtrReturn fDataPtrRet; std::function< void() > fInitiateBreakFunc; - std::function< void(std::future< KTDataPtr >&&) > fRefreshFutureFunc; + std::function< void(const std::string&, boost::unique_future< KTDataPtr >&&) > fRefreshFutureFunc; std::shared_ptr< KTThreadIndicator > fThreadIndicator; + std::string fPrimaryProcName; KTThreadReference(); KTThreadReference( const KTThreadReference& ) = delete; From 0531df763bcb0a8973eb3a5b1f04b95be7f09737 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Tue, 9 May 2017 11:14:27 -0700 Subject: [PATCH 021/521] Scarab logger updates --- Scarab | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Scarab b/Scarab index 7ee4812..953b806 160000 --- a/Scarab +++ b/Scarab @@ -1 +1 @@ -Subproject commit 7ee4812376649615f4cf97412c338201dd43e321 +Subproject commit 953b806ee1e1c675e977e7285cc258f231eb88df From 76c0ea5ba3197aba36ce5a5fd74c80ee5b0845e9 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Tue, 9 May 2017 11:36:23 -0700 Subject: [PATCH 022/521] Fixed logger macros for non-debug mode --- Library/Utility/KTLogger.hh | 46 ++++++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/Library/Utility/KTLogger.hh b/Library/Utility/KTLogger.hh index 1c38ae1..5e1bf9c 100644 --- a/Library/Utility/KTLogger.hh +++ b/Library/Utility/KTLogger.hh @@ -19,23 +19,33 @@ #define KTLOGGER(I,K) static ::scarab::logger I(K); -#define KTLOG(...) macro_dispatcher(__LOG_LOG_, __VA_ARGS__)(__VA_ARGS__) -#define KTTRACE(...) macro_dispatcher(__LOG_TRACE_, __VA_ARGS__)(__VA_ARGS__) -#define KTDEBUG(...) macro_dispatcher(__LOG_DEBUG_, __VA_ARGS__)(__VA_ARGS__) -#define KTINFO(...) macro_dispatcher(__LOG_INFO_, __VA_ARGS__)(__VA_ARGS__) -#define KTPROG(...) macro_dispatcher(__LOG_PROG_, __VA_ARGS__)(__VA_ARGS__) -#define KTWARN(...) macro_dispatcher(__LOG_WARN_, __VA_ARGS__)(__VA_ARGS__) -#define KTERROR(...) macro_dispatcher(__LOG_ERROR_, __VA_ARGS__)(__VA_ARGS__) -#define KTFATAL(...) macro_dispatcher(__LOG_FATAL_, __VA_ARGS__)(__VA_ARGS__) -#define KTASSERT(...) macro_dispatcher(__LOG_ASSERT_, __VA_ARGS__)(__VA_ARGS__) - -#define KTLOG_ONCE(...) macro_dispatcher(__LOG_LOG_ONCE_, __VA_ARGS__)(__VA_ARGS__) -#define KTTRACE_ONCE(...) macro_dispatcher(__LOG_TRACE_ONCE_, __VA_ARGS__)(__VA_ARGS__) -#define KTDEBUG_ONCE(...) macro_dispatcher(__LOG_DEBUG_ONCE_, __VA_ARGS__)(__VA_ARGS__) -#define KTINFO_ONCE(...) macro_dispatcher(__LOG_INFO_ONCE_, __VA_ARGS__)(__VA_ARGS__) -#define KTPROG_ONCE(...) macro_dispatcher(__LOG_PROG_ONCE_, __VA_ARGS__)(__VA_ARGS__) -#define KTWARN_ONCE(...) macro_dispatcher(__LOG_WARN_ONCE_, __VA_ARGS__)(__VA_ARGS__) -#define KTERROR_ONCE(...) macro_dispatcher(__LOG_ERROR_ONCE_, __VA_ARGS__)(__VA_ARGS__) -#define KTFATAL_ONCE(...) macro_dispatcher(__LOG_FATAL_ONCE_, __VA_ARGS__)(__VA_ARGS__) +#define LOG(...) macro_dispatcher(__LOG_LOG_, __VA_ARGS__)(__VA_ARGS__) +#ifdef NDEBUG +#define LTRACE(...) +#define LDEBUG(...) +#else +#define LTRACE(...) macro_dispatcher(__LOG_TRACE_, __VA_ARGS__)(__VA_ARGS__) +#define LDEBUG(...) macro_dispatcher(__LOG_DEBUG_, __VA_ARGS__)(__VA_ARGS__) +#endif +#define LINFO(...) macro_dispatcher(__LOG_INFO_, __VA_ARGS__)(__VA_ARGS__) +#define LPROG(...) macro_dispatcher(__LOG_PROG_, __VA_ARGS__)(__VA_ARGS__) +#define LWARN(...) macro_dispatcher(__LOG_WARN_, __VA_ARGS__)(__VA_ARGS__) +#define LERROR(...) macro_dispatcher(__LOG_ERROR_, __VA_ARGS__)(__VA_ARGS__) +#define LFATAL(...) macro_dispatcher(__LOG_FATAL_, __VA_ARGS__)(__VA_ARGS__) +#define LASSERT(...) macro_dispatcher(__LOG_ASSERT_, __VA_ARGS__)(__VA_ARGS__) + +#define LOG_ONCE(...) macro_dispatcher(__LOG_LOG_ONCE_, __VA_ARGS__)(__VA_ARGS__) +#ifdef NDEBUG +#define LTRACE_ONCE(...) +#define LDEBUG_ONCE(...) +#else +#define LTRACE_ONCE(...) macro_dispatcher(__LOG_TRACE_ONCE_, __VA_ARGS__)(__VA_ARGS__) +#define LDEBUG_ONCE(...) macro_dispatcher(__LOG_DEBUG_ONCE_, __VA_ARGS__)(__VA_ARGS__) +#endif +#define LINFO_ONCE(...) macro_dispatcher(__LOG_INFO_ONCE_, __VA_ARGS__)(__VA_ARGS__) +#define LPROG_ONCE(...) macro_dispatcher(__LOG_PROG_ONCE_, __VA_ARGS__)(__VA_ARGS__) +#define LWARN_ONCE(...) macro_dispatcher(__LOG_WARN_ONCE_, __VA_ARGS__)(__VA_ARGS__) +#define LERROR_ONCE(...) macro_dispatcher(__LOG_ERROR_ONCE_, __VA_ARGS__)(__VA_ARGS__) +#define LFATAL_ONCE(...) macro_dispatcher(__LOG_FATAL_ONCE_, __VA_ARGS__)(__VA_ARGS__) #endif /* KTLOGGER_HH_ */ From 992aba38c361c4dd7c2431f3d51b8e37af95ec76 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Tue, 9 May 2017 11:43:57 -0700 Subject: [PATCH 023/521] =?UTF-8?q?This=20time,=20I=20swear=20it=E2=80=99s?= =?UTF-8?q?=20right?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Library/Utility/KTLogger.hh | 44 ++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/Library/Utility/KTLogger.hh b/Library/Utility/KTLogger.hh index 5e1bf9c..adeee63 100644 --- a/Library/Utility/KTLogger.hh +++ b/Library/Utility/KTLogger.hh @@ -19,33 +19,33 @@ #define KTLOGGER(I,K) static ::scarab::logger I(K); -#define LOG(...) macro_dispatcher(__LOG_LOG_, __VA_ARGS__)(__VA_ARGS__) +#define KTLOG(...) macro_dispatcher(__LOG_LOG_, __VA_ARGS__)(__VA_ARGS__) #ifdef NDEBUG -#define LTRACE(...) -#define LDEBUG(...) +#define KTTRACE(...) +#define KTDEBUG(...) #else -#define LTRACE(...) macro_dispatcher(__LOG_TRACE_, __VA_ARGS__)(__VA_ARGS__) -#define LDEBUG(...) macro_dispatcher(__LOG_DEBUG_, __VA_ARGS__)(__VA_ARGS__) +#define KTTRACE(...) macro_dispatcher(__LOG_TRACE_, __VA_ARGS__)(__VA_ARGS__) +#define KTDEBUG(...) macro_dispatcher(__LOG_DEBUG_, __VA_ARGS__)(__VA_ARGS__) #endif -#define LINFO(...) macro_dispatcher(__LOG_INFO_, __VA_ARGS__)(__VA_ARGS__) -#define LPROG(...) macro_dispatcher(__LOG_PROG_, __VA_ARGS__)(__VA_ARGS__) -#define LWARN(...) macro_dispatcher(__LOG_WARN_, __VA_ARGS__)(__VA_ARGS__) -#define LERROR(...) macro_dispatcher(__LOG_ERROR_, __VA_ARGS__)(__VA_ARGS__) -#define LFATAL(...) macro_dispatcher(__LOG_FATAL_, __VA_ARGS__)(__VA_ARGS__) -#define LASSERT(...) macro_dispatcher(__LOG_ASSERT_, __VA_ARGS__)(__VA_ARGS__) - -#define LOG_ONCE(...) macro_dispatcher(__LOG_LOG_ONCE_, __VA_ARGS__)(__VA_ARGS__) +#define KTINFO(...) macro_dispatcher(__LOG_INFO_, __VA_ARGS__)(__VA_ARGS__) +#define KTPROG(...) macro_dispatcher(__LOG_PROG_, __VA_ARGS__)(__VA_ARGS__) +#define KTWARN(...) macro_dispatcher(__LOG_WARN_, __VA_ARGS__)(__VA_ARGS__) +#define KTERROR(...) macro_dispatcher(__LOG_ERROR_, __VA_ARGS__)(__VA_ARGS__) +#define KTFATAL(...) macro_dispatcher(__LOG_FATAL_, __VA_ARGS__)(__VA_ARGS__) +#define KTASSERT(...) macro_dispatcher(__LOG_ASSERT_, __VA_ARGS__)(__VA_ARGS__) + +#define KTLOG_ONCE(...) macro_dispatcher(__LOG_LOG_ONCE_, __VA_ARGS__)(__VA_ARGS__) #ifdef NDEBUG -#define LTRACE_ONCE(...) -#define LDEBUG_ONCE(...) +#define KTTRACE_ONCE(...) +#define KTDEBUG_ONCE(...) #else -#define LTRACE_ONCE(...) macro_dispatcher(__LOG_TRACE_ONCE_, __VA_ARGS__)(__VA_ARGS__) -#define LDEBUG_ONCE(...) macro_dispatcher(__LOG_DEBUG_ONCE_, __VA_ARGS__)(__VA_ARGS__) +#define KTTRACE_ONCE(...) macro_dispatcher(__LOG_TRACE_ONCE_, __VA_ARGS__)(__VA_ARGS__) +#define KTDEBUG_ONCE(...) macro_dispatcher(__LOG_DEBUG_ONCE_, __VA_ARGS__)(__VA_ARGS__) #endif -#define LINFO_ONCE(...) macro_dispatcher(__LOG_INFO_ONCE_, __VA_ARGS__)(__VA_ARGS__) -#define LPROG_ONCE(...) macro_dispatcher(__LOG_PROG_ONCE_, __VA_ARGS__)(__VA_ARGS__) -#define LWARN_ONCE(...) macro_dispatcher(__LOG_WARN_ONCE_, __VA_ARGS__)(__VA_ARGS__) -#define LERROR_ONCE(...) macro_dispatcher(__LOG_ERROR_ONCE_, __VA_ARGS__)(__VA_ARGS__) -#define LFATAL_ONCE(...) macro_dispatcher(__LOG_FATAL_ONCE_, __VA_ARGS__)(__VA_ARGS__) +#define KTINFO_ONCE(...) macro_dispatcher(__LOG_INFO_ONCE_, __VA_ARGS__)(__VA_ARGS__) +#define KTPROG_ONCE(...) macro_dispatcher(__LOG_PROG_ONCE_, __VA_ARGS__)(__VA_ARGS__) +#define KTWARN_ONCE(...) macro_dispatcher(__LOG_WARN_ONCE_, __VA_ARGS__)(__VA_ARGS__) +#define KTERROR_ONCE(...) macro_dispatcher(__LOG_ERROR_ONCE_, __VA_ARGS__)(__VA_ARGS__) +#define KTFATAL_ONCE(...) macro_dispatcher(__LOG_FATAL_ONCE_, __VA_ARGS__)(__VA_ARGS__) #endif /* KTLOGGER_HH_ */ From 7bdd382f93a193a2bf7d7efb0ce706df5adbb1ba Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Tue, 9 May 2017 12:14:58 -0700 Subject: [PATCH 024/521] Added wait-for-thread-to-start in KTProcessorToolbox. Some polishing. Adjusting test routines. --- Executables/Validation/CMakeLists.txt | 3 +- .../Validation/KTTestPrimaryProcessor.cc | 2 +- .../Validation/TestPrimaryProcessor.cc | 15 ++- .../TestProcessorToolbox2Threads.cc | 107 ++++++++++++++++++ .../TestProcessorToolboxMultithreaded.cc | 46 +++----- ... => TestProcessorToolboxSinglethreaded.cc} | 7 +- Library/Application/KTProcessorToolbox.cc | 49 +++++--- Library/Processor/KTPrimaryProcessor.cc | 5 +- Library/Processor/KTPrimaryProcessor.hh | 6 +- 9 files changed, 186 insertions(+), 54 deletions(-) create mode 100644 Executables/Validation/TestProcessorToolbox2Threads.cc rename Executables/Validation/{TestProcessorToolbox.cc => TestProcessorToolboxSinglethreaded.cc} (88%) diff --git a/Executables/Validation/CMakeLists.txt b/Executables/Validation/CMakeLists.txt index c8d1b48..4b43ee9 100644 --- a/Executables/Validation/CMakeLists.txt +++ b/Executables/Validation/CMakeLists.txt @@ -53,8 +53,9 @@ if (Nymph_ENABLE_TESTING) TestPrimaryProcessor TestPrimaryProcessorNoThreading TestPrintData - TestProcessorToolbox + TestProcessorToolbox2Threads TestProcessorToolboxMultithreaded + TestProcessorToolboxSinglethreaded TestSignalsAndSlots TestThroughputProfiler TestUseBreakpoint diff --git a/Executables/Validation/KTTestPrimaryProcessor.cc b/Executables/Validation/KTTestPrimaryProcessor.cc index 290ac9a..39e6121 100644 --- a/Executables/Validation/KTTestPrimaryProcessor.cc +++ b/Executables/Validation/KTTestPrimaryProcessor.cc @@ -37,7 +37,7 @@ namespace Nymph for( unsigned iIteration = 0; iIteration < fIterations; ++iIteration ) { // e.g. for a real processor, do some work here instead of sleeping - std::this_thread::sleep_for( std::chrono::milliseconds(1) ); + boost::this_thread::sleep_for( boost::chrono::milliseconds(1) ); if( fThreadRef.fThreadIndicator->fCanceled ) break; diff --git a/Executables/Validation/TestPrimaryProcessor.cc b/Executables/Validation/TestPrimaryProcessor.cc index 6e543df..22d3c1e 100644 --- a/Executables/Validation/TestPrimaryProcessor.cc +++ b/Executables/Validation/TestPrimaryProcessor.cc @@ -10,7 +10,7 @@ #include "KTLogger.hh" -#include +#include using namespace Nymph; @@ -38,7 +38,18 @@ int main() auto exeThreadFuture = exeThreadRef.fDataPtrRet.get_future(); // run the thread - std::thread thread( &KTPrimaryProcessor::operator(), &tpp, std::move( exeThreadRef ) ); + boost::condition_variable threadStartedCV; + boost::mutex threadStartedMutex; + bool threadStartedFlag = false; + + boost::unique_lock< boost::mutex > threadStartedLock( threadStartedMutex ); + boost::thread thread( [&](){ tpp( std::move( exeThreadRef ), threadStartedCV, threadStartedFlag ); } ); + + while( ! threadStartedFlag ) + { + threadStartedCV.wait( threadStartedLock ); + } + KTDEBUG( testpplog, "Thread has started" ); // wait for a result to be set exeThreadFuture.wait(); diff --git a/Executables/Validation/TestProcessorToolbox2Threads.cc b/Executables/Validation/TestProcessorToolbox2Threads.cc new file mode 100644 index 0000000..c45a573 --- /dev/null +++ b/Executables/Validation/TestProcessorToolbox2Threads.cc @@ -0,0 +1,107 @@ +/* + * TestProcessorToolboxMultithreaded.cc + * + * Created on: May 8, 2017 + * Author: N.S. Oblath + */ + +#include "KTProcessorToolbox.hh" + +#include "KTLogger.hh" + +using namespace Nymph; + +KTLOGGER( testptlog, "TestProcessorToolbox" ) + +int main() +{ + KTINFO( testptlog, "Preparing to run" ); + + KTProcessorToolbox ptb; + + // add the primary processor, thread 1 + if( ! ptb.AddProcessor( "test-p-proc", "tpp1" ) ) + { + KTERROR( testptlog, "Unable to create test primary processor (thread 1)" ); + return -1; + } + + // add processor b, thread 1 + if( ! ptb.AddProcessor( "test-proc-b", "tp1" ) ) + { + KTERROR( testptlog, "Unable to create test processor b (thread 1)" ); + return -1; + } + + // add the primary processor, thread 2 + if( ! ptb.AddProcessor( "test-p-proc", "tpp2" ) ) + { + KTERROR( testptlog, "Unable to create test primary processor (thread 2)" ); + return -1; + } + + // add processor b, thread 2 + if( ! ptb.AddProcessor( "test-proc-b", "tp2" ) ) + { + KTERROR( testptlog, "Unable to create test processor b (thread 2)" ); + return -1; + } + + // set breakpoint, thread 1 + if( ! ptb.SetBreakpoint( "tp1", "first-slot" ) ) + { + KTERROR( testptlog, "Unable to set the breakpoint" ); + return -1; + } + + // no breakpoint, thread2 + + // make connections, thread 1 + if( ! ptb.MakeConnection( "tpp1:the-signal", "tp1:first-slot" ) ) + { + KTERROR( testptlog, "Unable to connect tpp1 to tp1" ); + return -1; + } + + // make connections, thread 2 + if( ! ptb.MakeConnection( "tpp2:the-signal", "tp2:second-slot" ) ) + { + KTERROR( testptlog, "Unable to connect tpp2 to tp2" ); + return -1; + } + + // set the run queue + if( ! ptb.PushBackToRunQueue( {"tpp1", "tpp2"} ) ) + { + KTERROR( testptlog, "Unable to add {tpp1, tpp2} to the run queue" ); + return -1; + } + + // go! + KTINFO( testptlog, "Starting asynchronous run" ); + ptb.AsyncRun(); + + KTINFO( testptlog, "Starting asynchronous breakpoint user" ); + auto buFuture = boost::async( boost::launch::async, [&](){ + KTINFO( testptlog, "In breakpoint user thread" ); + while( ptb.WaitForBreak() ) + { + KTPROG( testptlog, "Reached breakpoint; waiting for user input" ); + std::string temp; + KTPROG( testptlog, "Please press [return]" ); + getline( std::cin, temp ); + ptb.Continue(); + } + KTINFO( testptlog, "Finished breakpoint user thread" ); + return; + }); + + KTINFO( testptlog, "Waiting for the end of the run" ); + ptb.WaitForEndOfRun(); + + KTINFO( testptlog, "Processing complete" ); + + KTINFO( testptlog, "Tests complete" ); + + return 0; +} diff --git a/Executables/Validation/TestProcessorToolboxMultithreaded.cc b/Executables/Validation/TestProcessorToolboxMultithreaded.cc index f9a348c..29848fc 100644 --- a/Executables/Validation/TestProcessorToolboxMultithreaded.cc +++ b/Executables/Validation/TestProcessorToolboxMultithreaded.cc @@ -11,7 +11,7 @@ using namespace Nymph; -KTLOGGER( testptlog, "TestProcessorToolbox" ) +KTLOGGER( testptlog, "TestProcessorToolboxMultithreaded" ) int main() { @@ -19,52 +19,34 @@ int main() KTProcessorToolbox ptb; - // add the primary processor, thread 1 - if( ! ptb.AddProcessor( "test-p-proc", "tpp1" ) ) - { - KTERROR( testptlog, "Unable to create test primary processor (thread 1)" ); - return -1; - } - - // add processor b, thread 1 - if( ! ptb.AddProcessor( "test-proc-b", "tp1" ) ) - { - KTERROR( testptlog, "Unable to create test processor b (thread 1)" ); - return -1; - } - - // add the primary processor, thread 2 - if( ! ptb.AddProcessor( "test-p-proc", "tpp2" ) ) - { - KTERROR( testptlog, "Unable to create test primary processor (thread 2)" ); - return -1; - } + // set for multi-threaded running + ptb.SetRunSingleThreaded( false ); - // add processor b, thread 2 - if( ! ptb.AddProcessor( "test-proc-b", "tp2" ) ) + // add the primary processor + if( ! ptb.AddProcessor( "test-p-proc", "tpp" ) ) { - KTERROR( testptlog, "Unable to create test processor b (thread 2)" ); + KTERROR( testptlog, "Unable to create test primary processor" ); return -1; } - // make connections, thread 1 - if( ! ptb.MakeConnection( "tpp1:the-signal", "tp1:first-slot" ) ) + // add processor b + if( ! ptb.AddProcessor( "test-proc-b", "tp" ) ) { - KTERROR( testptlog, "Unable to connect tpp1 to tp1" ); + KTERROR( testptlog, "Unable to create test processor b" ); return -1; } - // make connections, thread 2 - if( ! ptb.MakeConnection( "tpp2:the-signal", "tp2:first-slot" ) ) + // make connections + if( ! ptb.MakeConnection( "tpp:the-signal", "tp:first-slot" ) ) { - KTERROR( testptlog, "Unable to connect tpp2 to tp2" ); + KTERROR( testptlog, "Unable to connect tpp to tp" ); return -1; } // set the run queue - if( ! ptb.PushBackToRunQueue( {"tpp1", "tpp2"} ) ) + if( ! ptb.PushBackToRunQueue( "tpp" ) ) { - KTERROR( testptlog, "Unable to add {tpp1, tpp2} to the run queue" ); + KTERROR( testptlog, "Unable to add tpp to the run queue" ); return -1; } diff --git a/Executables/Validation/TestProcessorToolbox.cc b/Executables/Validation/TestProcessorToolboxSinglethreaded.cc similarity index 88% rename from Executables/Validation/TestProcessorToolbox.cc rename to Executables/Validation/TestProcessorToolboxSinglethreaded.cc index fbbf287..b0c1ca7 100644 --- a/Executables/Validation/TestProcessorToolbox.cc +++ b/Executables/Validation/TestProcessorToolboxSinglethreaded.cc @@ -1,5 +1,5 @@ /* - * TestProcessorToolbox.cc + * TestProcessorToolboxSinglethreaded.cc * * Created on: May 4, 2017 * Author: N.S. Oblath @@ -11,7 +11,7 @@ using namespace Nymph; -KTLOGGER( testptlog, "TestProcessorToolbox" ) +KTLOGGER( testptlog, "TestProcessorToolboxSinglethreaded" ) int main() { @@ -19,6 +19,9 @@ int main() KTProcessorToolbox ptb; + // set for single-threaded running + ptb.SetRunSingleThreaded( true ); + // add the primary processor if( ! ptb.AddProcessor( "test-p-proc", "tpp" ) ) { diff --git a/Library/Application/KTProcessorToolbox.cc b/Library/Application/KTProcessorToolbox.cc index ae65d3d..ca988bb 100644 --- a/Library/Application/KTProcessorToolbox.cc +++ b/Library/Application/KTProcessorToolbox.cc @@ -636,8 +636,19 @@ namespace Nymph thisThreadRef.fInitiateBreakFunc = [&](){ this->InitiateBreak(); }; thisThreadRef.fRefreshFutureFunc = [&]( const std::string& name, Future&& ret ){ this->TakeFuture( name, std::move(ret) ); }; + boost::condition_variable threadStartedCV; + boost::mutex threadStartedMutex; + bool threadStartedFlag = false; + //boost::thread thread( &KTPrimaryProcessor::operator(), tgIter->fProc, std::move( thisThreadRef ) ); - boost::thread thread( [&](){ tgIter->fProc->operator()( std::move( thisThreadRef ) ); } ); + boost::unique_lock< boost::mutex > threadStartedLock( threadStartedMutex ); + boost::thread thread( [&](){ tgIter->fProc->operator()( std::move( thisThreadRef ), threadStartedCV, threadStartedFlag ); } ); + KTDEBUG( proclog, "Thread ID is <" << thread.get_id() << ">; waiting for thread start" ); + while( ! threadStartedFlag ) + { + threadStartedCV.wait( threadStartedLock ); + } + KTDEBUG( proclog, "Thread has started" ); KTDEBUG( proclog, "Thread ID is <" << thread.get_id() << ">" ); @@ -654,7 +665,7 @@ namespace Nymph stillRunning = false; if( fThreadIndicators.back()->fBreakFlag ) { - KTDEBUG( proclog, "Breakpoint reached (originated in thread <" << fThreadNames.back() << ">)" ); + KTDEBUG( proclog, "Breakpoint reached (seen first in thread <" << fThreadNames.back() << ">; may not be where breakpoint is set)" ); continueSignal.wait(); KTDEBUG( proclog, "Breakpoint finished" ); stillRunning = true; @@ -691,8 +702,9 @@ namespace Nymph KTPROG( proclog, "Processing is complete (single-threaded)" ); } - catch( ... ) + catch( std::exception& e ) { + KTDEBUG( proclog, "Caught exception thrown in a processor or in the multi-threaded run function: " << e.what() ); // exceptions thrown in this function or from within processors will end up here fDoRunPromise.set_exception( std::current_exception() ); } @@ -754,9 +766,19 @@ namespace Nymph thisThreadRef.fInitiateBreakFunc = [&](){ this->InitiateBreak(); }; thisThreadRef.fRefreshFutureFunc = [&]( const std::string& name, Future&& ret ){ this->TakeFuture( name, std::move(ret) ); }; + boost::condition_variable threadStartedCV; + boost::mutex threadStartedMutex; + bool threadStartedFlag = false; + //threads.emplace_back( boost::thread( &KTPrimaryProcessor::operator(), tgIter->fProc, std::move( thisThreadRef ) ) ); - boost::thread* thisThread = new boost::thread( [&](){ tgIter->fProc->operator()( std::move( thisThreadRef ) ); } ); - KTDEBUG( proclog, "Thread ID is <" << thisThread->get_id() << ">" ); + boost::unique_lock< boost::mutex > threadStartedLock( threadStartedMutex ); + boost::thread* thisThread = new boost::thread( [&](){ tgIter->fProc->operator()( std::move( thisThreadRef ), threadStartedCV, threadStartedFlag ); } ); + KTDEBUG( proclog, "Thread ID is <" << thisThread->get_id() << ">; waiting for thread start" ); + while( ! threadStartedFlag ) + { + threadStartedCV.wait( threadStartedLock ); + } + KTDEBUG( proclog, "Thread has started" ); threads.add_thread( thisThread ); @@ -776,7 +798,7 @@ namespace Nymph if( fDoRunBreakFlag ) { // a breakpoint has been reached - KTDEBUG( proclog, "Breakpoint reached (originated in thread <" << threadName << ">)" ); + KTDEBUG( proclog, "Breakpoint reached (seen first in thread <" << threadName << ">; may not be where breakpoint is set)" ); continueSignal.wait(); KTDEBUG( proclog, "Breakpoint finished" ); stillRunning = true; @@ -800,7 +822,6 @@ namespace Nymph throw KTException() << "An error occurred while running processor <" << threadName << ">: " << e.what(); } - fThreadFutures.erase( finishedFuturePtr ); if( fThreadFutures.empty() ) stillRunning = false; else stillRunning = true; } @@ -814,9 +835,10 @@ namespace Nymph KTPROG( proclog, "Processing is complete (multi-threaded)" ); } - catch( ... ) + catch( std::exception& e ) { // exceptions thrown in this function or from within processors will end up here + KTDEBUG( proclog, "Caught exception thrown in a processor or in the multi-threaded run function: " << e.what() ); fDoRunPromise.set_exception( std::current_exception() ); } fDoRunPromise.set_value(); @@ -833,11 +855,12 @@ namespace Nymph { boost::shared_future< void > doRunFuture = fDoRunFuture; - boost::future_status doRunStatus; - do - { - doRunStatus = doRunFuture.wait_for( boost::chrono::milliseconds( 500 ) ); - } while( doRunStatus != boost::future_status::ready ); + doRunFuture.wait(); + //boost::future_status doRunStatus; + //do + //{ + // doRunStatus = doRunFuture.wait_for( boost::chrono::milliseconds( 500 ) ); + //} while( doRunStatus != boost::future_status::ready ); if( fDoRunBreakFlag ) { diff --git a/Library/Processor/KTPrimaryProcessor.cc b/Library/Processor/KTPrimaryProcessor.cc index 0d089b8..ce2e9f4 100644 --- a/Library/Processor/KTPrimaryProcessor.cc +++ b/Library/Processor/KTPrimaryProcessor.cc @@ -27,10 +27,13 @@ namespace Nymph { } - void KTPrimaryProcessor::operator ()( KTThreadReference&& ref ) + void KTPrimaryProcessor::operator ()( KTThreadReference&& ref, boost::condition_variable& startedCV, bool& startedFlag ) { fThreadRef = std::move( ref ); + startedFlag = true; + startedCV.notify_all(); + // pass updated thread reference to downstream slots for( auto sigIt = fSignalsEmitted.begin(); sigIt != fSignalsEmitted.end(); ++sigIt ) { diff --git a/Library/Processor/KTPrimaryProcessor.hh b/Library/Processor/KTPrimaryProcessor.hh index a7be18d..b470303 100644 --- a/Library/Processor/KTPrimaryProcessor.hh +++ b/Library/Processor/KTPrimaryProcessor.hh @@ -13,7 +13,9 @@ #include "KTData.hh" #include "KTThreadReference.hh" -#include +#include + +#include namespace Nymph { @@ -26,7 +28,7 @@ namespace Nymph public: /// Callable function used by std::thread - void operator()( KTThreadReference&& ref ); + void operator()( KTThreadReference&& ref, boost::condition_variable& startedCV, bool& startedFlag ); /// Starts the main action of the processor virtual bool Run() = 0; From 80354c0bcf6c2c1b5974a0edb7dc420da3e4fbbc Mon Sep 17 00:00:00 2001 From: Ben LaRoque Date: Tue, 9 May 2017 12:19:27 -0700 Subject: [PATCH 025/521] processor structural changes --- Library/Processor/KTProcessorPy.hh | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/Library/Processor/KTProcessorPy.hh b/Library/Processor/KTProcessorPy.hh index 31a4b9b..f258310 100644 --- a/Library/Processor/KTProcessorPy.hh +++ b/Library/Processor/KTProcessorPy.hh @@ -20,11 +20,27 @@ void export_Processor() // KTProcessor base class class_("KTProcessor", no_init) + //.def("RegisterProcessor", pure_virtual(&KTProcessor::RegisterProcessor), return_value_policy(), "register a processor") + + // PassThreadRefUpdate... needs KTThreadReference + //.def("PassThreadRefUpdate", &KTProcessor::PassThreadRefUpdate) .def("ConnectASlot", &KTProcessor::ConnectASlot) .def("ConnectASignal", &KTProcessor::ConnectASignal) - .def("ConnectSignalToSlot", &KTProcessor::ConnectSignalToSlot) + + // these next four need wrappers for return types (KT[Signal,Slot]Wrapper) + //.def("RegisterSignal", &KTProcessor::RegisterSignal) + //.def("RegisterSlot", &KTProcessor::RegisterSlot) + //.def("GetSignal", &KTProcessor::GetSignal) + //.def("GetSlot", &KTProcessor::GetSlot) + + /* now protected */ + //.def("ConnectSignalToSlot", &KTProcessor::ConnectSignalToSlot) + + .def("GetDoBreakpoint", &KTProcessor::GetDoBreakpoint) + .def("SetDoBreakpoint", &KTProcessor::SetDoBreakpoint) + + /* Inherited methods from unwrapped bases */ .def("Configure", Configure_JsonStr, "Configure from json encoded configuration") - //.def("RegisterProcessor", &KTProcessor::RegisterProcessor, return_value_policy()) ; } From 7b63e69b90362228e1254c44da25f7e7a31be1b1 Mon Sep 17 00:00:00 2001 From: Ben LaRoque Date: Tue, 9 May 2017 12:42:28 -0700 Subject: [PATCH 026/521] update Processor Toolbox wrapper methods --- Library/Application/KTProcessorToolboxPy.hh | 29 ++++++++++++++++----- 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/Library/Application/KTProcessorToolboxPy.hh b/Library/Application/KTProcessorToolboxPy.hh index 19404d5..f45e283 100644 --- a/Library/Application/KTProcessorToolboxPy.hh +++ b/Library/Application/KTProcessorToolboxPy.hh @@ -10,6 +10,7 @@ #define KTPROCESSORTOOLBOXPY_HH_ #include "KTProcessorToolbox.hh" +#include "KTPythonMacros.hh" // Make connection overloads /* default values here? */ @@ -36,23 +37,29 @@ void export_ProcessorToolbox() using namespace Nymph; using namespace boost::python; class_("KTProcessorToolbox", init()) - .def("Run", &KTProcessorToolbox::Run, "Call Run() on all processors in the run queue") - .def("GetProcessor", GetProcessor_wrap, return_value_policy(), "Get a pointer to a processor in the toolbox") + // members related to configuration .def("ConfigureProcessors", ConfigureProcessors_JsonStr, "Configure processors from a json dictionary. Top-level keys are processor names, values are dictionaries with their configurations") + PROPERTYMEMBER(KTProcessorToolbox, RunSingleThreaded) + + + // Processor access + .def("GetProcessor", GetProcessor_wrap, return_value_policy(), "Get a pointer to a processor in the toolbox") .def("AddProcessor", AddProcessor_Ref, "add a processor to the toolbox, toolbox takes ownership") .def("AddProcessor", AddProcessor_TypeStr, "add a processor to the toolbox, toolbox takes ownership") .def("RemoveProcessor", &KTProcessorToolbox::RemoveProcessor, "remove a processor from the toolbox") - - //TODO: Not 100% certain that the reference count for this processor is now correct, given the return_value_policy + /* TODO: Not 100% certain that the reference count for this processor is now correct, given the return_value_policy */ .def("ReleaseProcessor", &KTProcessorToolbox::ReleaseProcessor, return_value_policy(), "Remove a processor from the toolbox and return it to the user, ownership is passed") - .def("ClearProcessors", &KTProcessorToolbox::ClearProcessors, "Remove all processors and clear run queue") - // make signal-slot connection + // Processor connections .def("MakeConnection", MakeConnection_3args, "Make a signal-slot connection") .def("MakeConnection", MakeConnection_4args) + /* TODO use macro for arg counts?*/ + //.def("SetBreakpoint", &KTProcessorToolbox::SetBreakpoint, "set breakpoint on a slot") + //.def("RemoveBreakpoint", &KTProcessorToolbox::RemoveBreakpoint, "remove breakpoint from a slot") + // Run Queue // Push new processor(s) to back of run queue .def("PushBackToRunQueue", PushBackToRunQueue_string, "Push processor(s) to the back of the run queue") .def("PushBackToRunQueue", PushBackToRunQueue_init_list) @@ -61,6 +68,16 @@ void export_ProcessorToolbox() // Remove items from run queue .def("PopBackOfRunQueue", &KTProcessorToolbox::PopBackOfRunQueue, "Remove the last item in the run queue, whether it's a single processor or a group of processors") .def("ClearRunQueue", &KTProcessorToolbox::ClearRunQueue, "Clear the run queue") + + // Run methods + .def("Run", &KTProcessorToolbox::Run, "Call Run() on all processors in the run queue") + .def("AsyncRun", &KTProcessorToolbox::AsyncRun, "Non-blocking call to Run()") + .def("WaitForContinue", &KTProcessorToolbox::WaitForContinue) + .def("WaitForBreak", &KTProcessorToolbox::WaitForBreak, "Resume execution until reaching next breakpoint") + .def("WaitForEndOfRun", &KTProcessorToolbox::WaitForEndOfRun, "Resume execution until reaching end of run, skipping breakpoints") + .def("Continue", &KTProcessorToolbox::Continue, "Resume runqueue execution") + .def("CancelThreads", &KTProcessorToolbox::CancelThreads) + .def("JoinRunThread", &KTProcessorToolbox::JoinRunThread) ; } From f7b8b66fe818c4779eaacfc2adb36c18f172cd89 Mon Sep 17 00:00:00 2001 From: Ben LaRoque Date: Tue, 9 May 2017 14:32:11 -0700 Subject: [PATCH 027/521] new methods for breakpoints --- Library/Application/KTProcessorToolboxPy.hh | 26 +++++++++++++++------ 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/Library/Application/KTProcessorToolboxPy.hh b/Library/Application/KTProcessorToolboxPy.hh index f45e283..20a260b 100644 --- a/Library/Application/KTProcessorToolboxPy.hh +++ b/Library/Application/KTProcessorToolboxPy.hh @@ -13,9 +13,19 @@ #include "KTPythonMacros.hh" // Make connection overloads - /* default values here? */ -bool (Nymph::KTProcessorToolbox::*MakeConnection_3args)(const std::string&, const std::string&, int order) = &Nymph::KTProcessorToolbox::MakeConnection; -bool (Nymph::KTProcessorToolbox::*MakeConnection_4args)(const std::string&, const std::string&, const std::string&, const std::string&, int order) = &Nymph::KTProcessorToolbox::MakeConnection; + /* need two macros to cover all signatures*/ +bool (Nymph::KTProcessorToolbox::*MakeConnection_2names)(const std::string&, const std::string&, int order) = &Nymph::KTProcessorToolbox::MakeConnection; +BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(MakeConnection_2names_overloads, Nymph::KTProcessorToolbox::MakeConnection, 2, 3) +bool (Nymph::KTProcessorToolbox::*MakeConnection_4names)(const std::string&, const std::string&, const std::string&, const std::string&, int order) = &Nymph::KTProcessorToolbox::MakeConnection; +BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(MakeConnection_4names_overloads, Nymph::KTProcessorToolbox::MakeConnection, 4, 5) + +// Set and Remove breakpoint overloads +bool (Nymph::KTProcessorToolbox::*SetBreakpoint_1arg)(const std::string&) = &Nymph::KTProcessorToolbox::SetBreakpoint; +bool (Nymph::KTProcessorToolbox::*SetBreakpoint_2arg)(const std::string&, const std::string&) = &Nymph::KTProcessorToolbox::SetBreakpoint; +bool (Nymph::KTProcessorToolbox::*RemoveBreakpoint_1arg)(const std::string&) = &Nymph::KTProcessorToolbox::RemoveBreakpoint; +bool (Nymph::KTProcessorToolbox::*RemoveBreakpoint_2arg)(const std::string&, const std::string&) = &Nymph::KTProcessorToolbox::RemoveBreakpoint; +//BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(SetBreakpoint_overloads, Nymph::KTProcessorToolbox::SetBreakpoint, 1, 2) +//BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(RemoveBreakpoint_overloads, Nymph::KTProcessorToolbox::SetBreakpoint, 1, 2) // Run queue pushback overloads bool (Nymph::KTProcessorToolbox::*PushBackToRunQueue_string)(const std::string& name) = &Nymph::KTProcessorToolbox::PushBackToRunQueue; @@ -53,11 +63,13 @@ void export_ProcessorToolbox() .def("ClearProcessors", &KTProcessorToolbox::ClearProcessors, "Remove all processors and clear run queue") // Processor connections - .def("MakeConnection", MakeConnection_3args, "Make a signal-slot connection") - .def("MakeConnection", MakeConnection_4args) + .def("MakeConnection", MakeConnection_2names, MakeConnection_2names_overloads()) + .def("MakeConnection", MakeConnection_4names, MakeConnection_4names_overloads()) /* TODO use macro for arg counts?*/ - //.def("SetBreakpoint", &KTProcessorToolbox::SetBreakpoint, "set breakpoint on a slot") - //.def("RemoveBreakpoint", &KTProcessorToolbox::RemoveBreakpoint, "remove breakpoint from a slot") + .def("SetBreakpoint", SetBreakpoint_1arg, "add breakpoint to 'procName:slotName'") + .def("SetBreakpoint", SetBreakpoint_2arg, "add breakpoint to 'procName, slotName'") + .def("RemoveBreakpoint", RemoveBreakpoint_1arg, "add breakpoint to 'procName:slotName'") + .def("RemoveBreakpoint", RemoveBreakpoint_2arg, "add breakpoint to 'procName, slotName'") // Run Queue // Push new processor(s) to back of run queue From 2cd822cd686d353d962e7aedb8fb31051e957aa2 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Tue, 9 May 2017 14:44:07 -0700 Subject: [PATCH 028/521] Attempts to improve parallel-running stability --- Library/Application/KTProcessorToolbox.cc | 6 ++++++ Library/Application/KTProcessorToolbox.hh | 1 + Library/Processor/KTPrimaryProcessor.cc | 6 +++--- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/Library/Application/KTProcessorToolbox.cc b/Library/Application/KTProcessorToolbox.cc index ca988bb..a6e6f52 100644 --- a/Library/Application/KTProcessorToolbox.cc +++ b/Library/Application/KTProcessorToolbox.cc @@ -789,6 +789,7 @@ namespace Nymph bool stillRunning = true; // determines behavior that depends on whether a return from the thread was temporary or from the thread completing do { + boost::unique_lock< boost::mutex > threadFuturesLock( fThreadFuturesMutex ); //auto finishedFuturePtr = boost::wait_for_any( futureIndex.begin(), futureIndex.end() ); auto finishedFuturePtr = boost::wait_for_any( fThreadFutures.begin(), fThreadFutures.end() ); size_t iThread = finishedFuturePtr - fThreadFutures.begin(); @@ -798,9 +799,11 @@ namespace Nymph if( fDoRunBreakFlag ) { // a breakpoint has been reached + threadFuturesLock.unlock(); KTDEBUG( proclog, "Breakpoint reached (seen first in thread <" << threadName << ">; may not be where breakpoint is set)" ); continueSignal.wait(); KTDEBUG( proclog, "Breakpoint finished" ); + boost::unique_lock< boost::mutex > breakContLock( fBreakContMutex ); stillRunning = true; continueSignal = fMasterContSignal; // refresh the local copy of the shared future } @@ -827,8 +830,10 @@ namespace Nymph } } while( stillRunning ); + KTDEBUG( proclog, "Joining threads" ); threads.join_all(); fThreadIndicators.clear(); + boost::unique_lock< boost::mutex > threadFuturesLock( fThreadFuturesMutex ); fThreadFutures.clear(); fThreadNames.clear(); } // end for loop over the run-queue @@ -897,6 +902,7 @@ namespace Nymph void KTProcessorToolbox::Continue() { boost::unique_lock< boost::mutex > breakContLock( fBreakContMutex ); + boost::unique_lock< boost::mutex > threadFuturesLock( fThreadFuturesMutex ); // futures have been used; clear them to be replaced fThreadFutures.clear(); diff --git a/Library/Application/KTProcessorToolbox.hh b/Library/Application/KTProcessorToolbox.hh index 3cc488e..cb3c58f 100644 --- a/Library/Application/KTProcessorToolbox.hh +++ b/Library/Application/KTProcessorToolbox.hh @@ -257,6 +257,7 @@ namespace Nymph ThreadFutures fThreadFutures; ThreadNames fThreadNames; + boost::mutex fThreadFuturesMutex; typedef std::vector< std::shared_ptr< KTThreadIndicator > > ThreadIndicators; ThreadIndicators fThreadIndicators; diff --git a/Library/Processor/KTPrimaryProcessor.cc b/Library/Processor/KTPrimaryProcessor.cc index ce2e9f4..dda0ad4 100644 --- a/Library/Processor/KTPrimaryProcessor.cc +++ b/Library/Processor/KTPrimaryProcessor.cc @@ -31,9 +31,6 @@ namespace Nymph { fThreadRef = std::move( ref ); - startedFlag = true; - startedCV.notify_all(); - // pass updated thread reference to downstream slots for( auto sigIt = fSignalsEmitted.begin(); sigIt != fSignalsEmitted.end(); ++sigIt ) { @@ -46,6 +43,9 @@ namespace Nymph } } + startedFlag = true; + startedCV.notify_all(); + // go! try { From aff864efcc0dba75bba59172de9c4060db55342e Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Tue, 9 May 2017 14:46:52 -0700 Subject: [PATCH 029/521] Cleanup --- Library/Application/KTProcessorToolbox.cc | 21 --------------------- Library/Application/KTProcessorToolbox.hh | 23 ----------------------- 2 files changed, 44 deletions(-) diff --git a/Library/Application/KTProcessorToolbox.cc b/Library/Application/KTProcessorToolbox.cc index a6e6f52..9471780 100644 --- a/Library/Application/KTProcessorToolbox.cc +++ b/Library/Application/KTProcessorToolbox.cc @@ -615,14 +615,10 @@ namespace Nymph KTThreadReference thisThreadRef; - //fThreadFutures.get<1>().insert( LabeledFuture{ procName, thisThreadRef.fDataPtrRet.get_future() } ); - //fThreadFutures.push_back( LabeledFuture{ procName, thisThreadRef.fDataPtrRet.get_future() } ); fThreadFutures.push_back( std::move( thisThreadRef.fDataPtrRet.get_future() ) ); fThreadNames.push_back( procName ); //auto& futureNameIndex = fThreadFutures.get<1>(); - //auto thisFuturePtr = futureNameIndex.find( procName ); - //if( ! thisFuturePtr->fFuture.valid() ) if( ! fThreadFutures.back().valid() ) { KTERROR( proclog, "Invalid thread future created" ); @@ -640,7 +636,6 @@ namespace Nymph boost::mutex threadStartedMutex; bool threadStartedFlag = false; - //boost::thread thread( &KTPrimaryProcessor::operator(), tgIter->fProc, std::move( thisThreadRef ) ); boost::unique_lock< boost::mutex > threadStartedLock( threadStartedMutex ); boost::thread thread( [&](){ tgIter->fProc->operator()( std::move( thisThreadRef ), threadStartedCV, threadStartedFlag ); } ); KTDEBUG( proclog, "Thread ID is <" << thread.get_id() << ">; waiting for thread start" ); @@ -658,7 +653,6 @@ namespace Nymph boost::future_status status; do { - //status = thisFuturePtr->fFuture.wait_for( std::chrono::milliseconds(500) ); status = fThreadFutures.back().wait_for( boost::chrono::milliseconds(500) ); } while (status != boost::future_status::ready); @@ -675,7 +669,6 @@ namespace Nymph { try { - //futureNameIndex.modify( thisFuturePtr, [](LabeledFuture& lFuture){ lFuture.fFuture.get(); } ); fThreadFutures.back().get(); KTINFO( proclog, "Thread <" << fThreadNames.back() << "> has finished" ); fThreadFutures.pop_back(); @@ -737,8 +730,6 @@ namespace Nymph { boost::thread_group threads; - //auto& futureNameIndex = fThreadFutures.get<1>(); - for (ThreadGroup::iterator tgIter = rqIter->begin(); tgIter != rqIter->end(); ++tgIter) { std::string procName( tgIter->fName ); @@ -746,13 +737,9 @@ namespace Nymph KTThreadReference thisThreadRef; - //futureNameIndex.insert( LabeledFuture{ procName, thisThreadRef.fDataPtrRet.get_future() } ); - //fThreadFutures.push_back( LabeledFuture{ procName, thisThreadRef.fDataPtrRet.get_future() } ); fThreadFutures.push_back( std::move( thisThreadRef.fDataPtrRet.get_future() ) ); fThreadNames.push_back( procName ); - //auto thisFuturePtr = futureNameIndex.find( procName ); - //if( ! thisFuturePtr->fFuture.valid() ) if( ! fThreadFutures.back().valid() ) { KTERROR( proclog, "Invalid thread future created" ); @@ -770,7 +757,6 @@ namespace Nymph boost::mutex threadStartedMutex; bool threadStartedFlag = false; - //threads.emplace_back( boost::thread( &KTPrimaryProcessor::operator(), tgIter->fProc, std::move( thisThreadRef ) ) ); boost::unique_lock< boost::mutex > threadStartedLock( threadStartedMutex ); boost::thread* thisThread = new boost::thread( [&](){ tgIter->fProc->operator()( std::move( thisThreadRef ), threadStartedCV, threadStartedFlag ); } ); KTDEBUG( proclog, "Thread ID is <" << thisThread->get_id() << ">; waiting for thread start" ); @@ -784,8 +770,6 @@ namespace Nymph }// end for loop over the thread group - //auto& futureIndex = fThreadFutures.get<0>(); - bool stillRunning = true; // determines behavior that depends on whether a return from the thread was temporary or from the thread completing do { @@ -861,11 +845,6 @@ namespace Nymph boost::shared_future< void > doRunFuture = fDoRunFuture; doRunFuture.wait(); - //boost::future_status doRunStatus; - //do - //{ - // doRunStatus = doRunFuture.wait_for( boost::chrono::milliseconds( 500 ) ); - //} while( doRunStatus != boost::future_status::ready ); if( fDoRunBreakFlag ) { diff --git a/Library/Application/KTProcessorToolbox.hh b/Library/Application/KTProcessorToolbox.hh index cb3c58f..3392a81 100644 --- a/Library/Application/KTProcessorToolbox.hh +++ b/Library/Application/KTProcessorToolbox.hh @@ -20,17 +20,11 @@ #include #include -//#include -//#include -//#include -//#include - #include #include #include #include -//namespace bmi = boost::multi_index; namespace Nymph { @@ -231,29 +225,14 @@ namespace Nymph friend class KTThreadReference; typedef boost::unique_future< KTDataPtr > Future; - //typedef std::future< KTDataPtr > Future; // called from ThreadPacket::Break void InitiateBreak(); // called from ThreadPacket::Break void TakeFuture( const std::string& name, Future&& future ); - //struct LabeledFuture - //{ - // std::string fName; - // std::future< KTDataPtr > fFuture; - //}; - //typedef std::vector< LabeledFuture > ThreadFutures; typedef std::vector< Future > ThreadFutures; typedef std::vector< std::string > ThreadNames; - //typedef std::map< std::string, std::future< KTDataPtr > > ThreadFutures; - //typedef boost::multi_index_container< - // LabeledFuture, - // bmi::indexed_by< - // bmi::random_access<>, - // bmi::ordered_unique< bmi::member< KTProcessorToolbox::LabeledFuture, std::string, &KTProcessorToolbox::LabeledFuture::fName > > - // > - //> ThreadFutures; ThreadFutures fThreadFutures; ThreadNames fThreadNames; @@ -293,8 +272,6 @@ namespace Nymph inline void KTProcessorToolbox::TakeFuture( const std::string& name, Future&& future ) { - //fThreadFutures.get<1>().insert( LabeledFuture{ name, std::move( future ) } ); - //fThreadFutures.push_back( LabeledFuture{ name, std::move( future ) } ); fThreadFutures.push_back( std::move( future ) ); fThreadNames.push_back( name ); return; From 8f58f1b0bc27d92304b36dd79dbcae4291155b3f Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Tue, 9 May 2017 14:58:52 -0700 Subject: [PATCH 030/521] Added an interface to get data objects; compiles, but untested --- Library/Application/KTProcessorToolbox.cc | 25 +++++++++++++++++++++++ Library/Application/KTProcessorToolbox.hh | 2 ++ 2 files changed, 27 insertions(+) diff --git a/Library/Application/KTProcessorToolbox.cc b/Library/Application/KTProcessorToolbox.cc index 9471780..199f1b8 100644 --- a/Library/Application/KTProcessorToolbox.cc +++ b/Library/Application/KTProcessorToolbox.cc @@ -913,6 +913,31 @@ namespace Nymph return; } + KTDataPtr KTProcessorToolbox::GetData( const std::string& threadName ) + { + boost::unique_lock< boost::mutex > threadFuturesLock( fThreadFuturesMutex ); + + auto tnIt = fThreadNames.begin(); + for( ; tnIt != fThreadNames.end(); ++tnIt ) + { + if( *tnIt == threadName ) break; + } + if( tnIt == fThreadNames.end() ) + { + KTWARN( proclog, "Did not find thread <" << threadName << ">" ); + throw KTException() << "Did not find thread <" << threadName << ">" ; + } + + size_t iThread = tnIt - fThreadNames.begin(); + if( iThread >= fThreadFutures.size() ) + { + KTERROR( proclog, "Thread futures and thread names are unsynchronized" ); + throw KTException() << "Thread futures and thread names are unsynchronized; found thread name <" << threadName << "> at position <" << iThread << ">, but there are only <" << fThreadFutures.size() << "> futures."; + } + + return fThreadFutures[ iThread ].get(); + } + void KTProcessorToolbox::InitiateBreak() { boost::unique_lock< boost::mutex > breakContLock( fBreakContMutex ); diff --git a/Library/Application/KTProcessorToolbox.hh b/Library/Application/KTProcessorToolbox.hh index 3392a81..14e57bc 100644 --- a/Library/Application/KTProcessorToolbox.hh +++ b/Library/Application/KTProcessorToolbox.hh @@ -221,6 +221,8 @@ namespace Nymph void JoinRunThread(); + KTDataPtr GetData( const std::string& threadName ); + private: friend class KTThreadReference; From d637af9f8617030bd337c34e9b49435ec9f7321c Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Tue, 9 May 2017 15:43:25 -0700 Subject: [PATCH 031/521] Fixed mistaken inline marking --- Library/Processor/KTProcessor.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Library/Processor/KTProcessor.cc b/Library/Processor/KTProcessor.cc index 06fc429..b1ce746 100644 --- a/Library/Processor/KTProcessor.cc +++ b/Library/Processor/KTProcessor.cc @@ -131,7 +131,7 @@ namespace Nymph return iter->second; } - inline bool KTProcessor::GetDoBreakpoint(const std::string& slotName) + bool KTProcessor::GetDoBreakpoint(const std::string& slotName) { KTSlotWrapper* slot = GetSlot(slotName); if (slot != nullptr) From 178d40b8cafcb82bae1619e5cccf8a03328c2233 Mon Sep 17 00:00:00 2001 From: Ben LaRoque Date: Tue, 9 May 2017 15:53:39 -0700 Subject: [PATCH 032/521] missing include (mac != linux) --- Executables/Validation/TestExceptionInSlot.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/Executables/Validation/TestExceptionInSlot.cc b/Executables/Validation/TestExceptionInSlot.cc index 033bd34..05b599a 100644 --- a/Executables/Validation/TestExceptionInSlot.cc +++ b/Executables/Validation/TestExceptionInSlot.cc @@ -11,6 +11,7 @@ #include "KTLogger.hh" #include +#include using namespace Nymph; From d5d2a2d4691505a42104e6da5f36510a35d80bf7 Mon Sep 17 00:00:00 2001 From: Ben LaRoque Date: Tue, 9 May 2017 16:39:12 -0700 Subject: [PATCH 033/521] update authors, toolbox interface update --- AUTHORS | 2 ++ Library/Application/KTProcessorToolboxPy.hh | 10 ++++++---- Library/Processor/KTProcessor.cc | 2 +- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/AUTHORS b/AUTHORS index e2b4c3e..9b85a75 100644 --- a/AUTHORS +++ b/AUTHORS @@ -4,8 +4,10 @@ Authors and Copyright Holders for Nymph Individuals ----------- Noah S. Oblath [1] +Benjamin H. LaRoque [2] Institutions ------------ 1. Pacific Northwest National Laboratory, Richland, WA +2. University of California, Santa Barbara, CA diff --git a/Library/Application/KTProcessorToolboxPy.hh b/Library/Application/KTProcessorToolboxPy.hh index 20a260b..16dc109 100644 --- a/Library/Application/KTProcessorToolboxPy.hh +++ b/Library/Application/KTProcessorToolboxPy.hh @@ -85,11 +85,13 @@ void export_ProcessorToolbox() .def("Run", &KTProcessorToolbox::Run, "Call Run() on all processors in the run queue") .def("AsyncRun", &KTProcessorToolbox::AsyncRun, "Non-blocking call to Run()") .def("WaitForContinue", &KTProcessorToolbox::WaitForContinue) - .def("WaitForBreak", &KTProcessorToolbox::WaitForBreak, "Resume execution until reaching next breakpoint") - .def("WaitForEndOfRun", &KTProcessorToolbox::WaitForEndOfRun, "Resume execution until reaching end of run, skipping breakpoints") - .def("Continue", &KTProcessorToolbox::Continue, "Resume runqueue execution") - .def("CancelThreads", &KTProcessorToolbox::CancelThreads) + .def("WaitForBreak", &KTProcessorToolbox::WaitForBreak, "blocking call that waits until a breakpoint is reached, you must manually Continue()") + .def("WaitForEndOfRun", &KTProcessorToolbox::WaitForEndOfRun, "blocking call to Continue() execution until end of run is reached, you must manually Continue()") + .def("Continue", &KTProcessorToolbox::Continue, "non-blocking call to resume execution") + .def("CancelThreads", &KTProcessorToolbox::CancelThreads, "kill any running thread at the next breakpoint check") .def("JoinRunThread", &KTProcessorToolbox::JoinRunThread) + + .def("GetData", &KTProcessorToolbox::GetData) ; } diff --git a/Library/Processor/KTProcessor.cc b/Library/Processor/KTProcessor.cc index 06fc429..b1ce746 100644 --- a/Library/Processor/KTProcessor.cc +++ b/Library/Processor/KTProcessor.cc @@ -131,7 +131,7 @@ namespace Nymph return iter->second; } - inline bool KTProcessor::GetDoBreakpoint(const std::string& slotName) + bool KTProcessor::GetDoBreakpoint(const std::string& slotName) { KTSlotWrapper* slot = GetSlot(slotName); if (slot != nullptr) From 6bcf5f9419660eb5fb172df51bed71709bde6d77 Mon Sep 17 00:00:00 2001 From: Ben LaRoque Date: Tue, 9 May 2017 16:39:28 -0700 Subject: [PATCH 034/521] using boost in exception test program --- Executables/Validation/TestExceptionInSlot.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Executables/Validation/TestExceptionInSlot.cc b/Executables/Validation/TestExceptionInSlot.cc index 05b599a..1fe808d 100644 --- a/Executables/Validation/TestExceptionInSlot.cc +++ b/Executables/Validation/TestExceptionInSlot.cc @@ -10,7 +10,7 @@ #include "KTTestProcessor.hh" #include "KTLogger.hh" -#include +#include #include using namespace Nymph; @@ -44,7 +44,7 @@ int main() auto exeFunc = [&]() { try { - std::this_thread::sleep_for( std::chrono::milliseconds(1) ); // delay to let the main thread get to the std::future::wait() call + boost::this_thread::sleep_for( boost::chrono::milliseconds(1) ); // delay to let the main thread get to the std::future::wait() call KTINFO( testexclog, "Emitting signals" ); @@ -52,7 +52,7 @@ int main() KTINFO( testexclog, "First test signal: 5" ); tpA.EmitSignals( 5 ); - std::this_thread::sleep_for( std::chrono::milliseconds(1) ); // delay to let the main thread react to the exception + boost::this_thread::sleep_for( boost::chrono::milliseconds(1) ); // delay to let the main thread react to the exception if( canceled.load() ) return; KTINFO( testexclog, "Second test signal: 18" ); @@ -67,7 +67,7 @@ int main() }; // run the thread - std::thread thread( exeFunc ); + boost::thread thread( exeFunc ); // wait for a result to be set exeThreadFuture.wait(); From 1ec7c5460daa5ddd1685fd387e153c135c33e8ed Mon Sep 17 00:00:00 2001 From: Ben LaRoque Date: Tue, 9 May 2017 16:40:10 -0700 Subject: [PATCH 035/521] Scarab changes --- Scarab | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Scarab b/Scarab index 953b806..409659a 160000 --- a/Scarab +++ b/Scarab @@ -1 +1 @@ -Subproject commit 953b806ee1e1c675e977e7285cc258f231eb88df +Subproject commit 409659a19eccd1e871e6b17b2af62e65a7e78c6c From 8b15896d557ecf5951cf628348265ce5770ade67 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Wed, 10 May 2017 12:03:38 -0700 Subject: [PATCH 036/521] Protect KTProcessorToolbox::WaitForBreak() and Continue() against out-of-sequence calls. Handle exceptions that can now be thrown by WaitForBreak(). --- .../TestProcessorToolbox2Threads.cc | 155 +++++++++--------- .../TestProcessorToolboxMultithreaded.cc | 97 ++++++----- .../TestProcessorToolboxSinglethreaded.cc | 96 ++++++----- Library/Application/KTProcessorToolbox.cc | 43 +++-- 4 files changed, 218 insertions(+), 173 deletions(-) diff --git a/Executables/Validation/TestProcessorToolbox2Threads.cc b/Executables/Validation/TestProcessorToolbox2Threads.cc index c45a573..d92960f 100644 --- a/Executables/Validation/TestProcessorToolbox2Threads.cc +++ b/Executables/Validation/TestProcessorToolbox2Threads.cc @@ -15,93 +15,100 @@ KTLOGGER( testptlog, "TestProcessorToolbox" ) int main() { - KTINFO( testptlog, "Preparing to run" ); - - KTProcessorToolbox ptb; - - // add the primary processor, thread 1 - if( ! ptb.AddProcessor( "test-p-proc", "tpp1" ) ) - { - KTERROR( testptlog, "Unable to create test primary processor (thread 1)" ); - return -1; - } - - // add processor b, thread 1 - if( ! ptb.AddProcessor( "test-proc-b", "tp1" ) ) + try { - KTERROR( testptlog, "Unable to create test processor b (thread 1)" ); - return -1; - } + KTINFO( testptlog, "Preparing to run" ); - // add the primary processor, thread 2 - if( ! ptb.AddProcessor( "test-p-proc", "tpp2" ) ) - { - KTERROR( testptlog, "Unable to create test primary processor (thread 2)" ); - return -1; - } + KTProcessorToolbox ptb; - // add processor b, thread 2 - if( ! ptb.AddProcessor( "test-proc-b", "tp2" ) ) - { - KTERROR( testptlog, "Unable to create test processor b (thread 2)" ); - return -1; - } - - // set breakpoint, thread 1 - if( ! ptb.SetBreakpoint( "tp1", "first-slot" ) ) - { - KTERROR( testptlog, "Unable to set the breakpoint" ); - return -1; - } + // add the primary processor, thread 1 + if( ! ptb.AddProcessor( "test-p-proc", "tpp1" ) ) + { + KTERROR( testptlog, "Unable to create test primary processor (thread 1)" ); + return -1; + } - // no breakpoint, thread2 + // add processor b, thread 1 + if( ! ptb.AddProcessor( "test-proc-b", "tp1" ) ) + { + KTERROR( testptlog, "Unable to create test processor b (thread 1)" ); + return -1; + } - // make connections, thread 1 - if( ! ptb.MakeConnection( "tpp1:the-signal", "tp1:first-slot" ) ) - { - KTERROR( testptlog, "Unable to connect tpp1 to tp1" ); - return -1; - } + // add the primary processor, thread 2 + if( ! ptb.AddProcessor( "test-p-proc", "tpp2" ) ) + { + KTERROR( testptlog, "Unable to create test primary processor (thread 2)" ); + return -1; + } - // make connections, thread 2 - if( ! ptb.MakeConnection( "tpp2:the-signal", "tp2:second-slot" ) ) - { - KTERROR( testptlog, "Unable to connect tpp2 to tp2" ); - return -1; - } + // add processor b, thread 2 + if( ! ptb.AddProcessor( "test-proc-b", "tp2" ) ) + { + KTERROR( testptlog, "Unable to create test processor b (thread 2)" ); + return -1; + } - // set the run queue - if( ! ptb.PushBackToRunQueue( {"tpp1", "tpp2"} ) ) - { - KTERROR( testptlog, "Unable to add {tpp1, tpp2} to the run queue" ); - return -1; - } + // set breakpoint, thread 1 + if( ! ptb.SetBreakpoint( "tp1", "first-slot" ) ) + { + KTERROR( testptlog, "Unable to set the breakpoint" ); + return -1; + } - // go! - KTINFO( testptlog, "Starting asynchronous run" ); - ptb.AsyncRun(); + // no breakpoint, thread2 - KTINFO( testptlog, "Starting asynchronous breakpoint user" ); - auto buFuture = boost::async( boost::launch::async, [&](){ - KTINFO( testptlog, "In breakpoint user thread" ); - while( ptb.WaitForBreak() ) + // make connections, thread 1 + if( ! ptb.MakeConnection( "tpp1:the-signal", "tp1:first-slot" ) ) { - KTPROG( testptlog, "Reached breakpoint; waiting for user input" ); - std::string temp; - KTPROG( testptlog, "Please press [return]" ); - getline( std::cin, temp ); - ptb.Continue(); + KTERROR( testptlog, "Unable to connect tpp1 to tp1" ); + return -1; } - KTINFO( testptlog, "Finished breakpoint user thread" ); - return; - }); - - KTINFO( testptlog, "Waiting for the end of the run" ); - ptb.WaitForEndOfRun(); - KTINFO( testptlog, "Processing complete" ); + // make connections, thread 2 + if( ! ptb.MakeConnection( "tpp2:the-signal", "tp2:second-slot" ) ) + { + KTERROR( testptlog, "Unable to connect tpp2 to tp2" ); + return -1; + } - KTINFO( testptlog, "Tests complete" ); + // set the run queue + if( ! ptb.PushBackToRunQueue( {"tpp1", "tpp2"} ) ) + { + KTERROR( testptlog, "Unable to add {tpp1, tpp2} to the run queue" ); + return -1; + } + // go! + KTINFO( testptlog, "Starting asynchronous run" ); + ptb.AsyncRun(); + + KTINFO( testptlog, "Starting asynchronous breakpoint user" ); + auto buFuture = boost::async( boost::launch::async, [&](){ + KTINFO( testptlog, "In breakpoint user thread" ); + while( ptb.WaitForBreak() ) + { + KTPROG( testptlog, "Reached breakpoint; waiting for user input" ); + std::string temp; + KTPROG( testptlog, "Please press [return]" ); + getline( std::cin, temp ); + ptb.Continue(); + } + KTINFO( testptlog, "Finished breakpoint user thread" ); + return; + }); + + KTINFO( testptlog, "Waiting for the end of the run" ); + ptb.WaitForEndOfRun(); + + KTINFO( testptlog, "Processing complete" ); + + KTINFO( testptlog, "Tests complete" ); + } + catch( std::exception& e ) + { + KTERROR( testptlog, "Exception caught: " << e.what() ); + return -1; + } return 0; } diff --git a/Executables/Validation/TestProcessorToolboxMultithreaded.cc b/Executables/Validation/TestProcessorToolboxMultithreaded.cc index 29848fc..d71b5ab 100644 --- a/Executables/Validation/TestProcessorToolboxMultithreaded.cc +++ b/Executables/Validation/TestProcessorToolboxMultithreaded.cc @@ -15,55 +15,62 @@ KTLOGGER( testptlog, "TestProcessorToolboxMultithreaded" ) int main() { - KTINFO( testptlog, "Preparing to run" ); - - KTProcessorToolbox ptb; - - // set for multi-threaded running - ptb.SetRunSingleThreaded( false ); - - // add the primary processor - if( ! ptb.AddProcessor( "test-p-proc", "tpp" ) ) - { - KTERROR( testptlog, "Unable to create test primary processor" ); - return -1; - } - - // add processor b - if( ! ptb.AddProcessor( "test-proc-b", "tp" ) ) - { - KTERROR( testptlog, "Unable to create test processor b" ); - return -1; - } - - // make connections - if( ! ptb.MakeConnection( "tpp:the-signal", "tp:first-slot" ) ) + try { - KTERROR( testptlog, "Unable to connect tpp to tp" ); - return -1; + KTINFO( testptlog, "Preparing to run" ); + + KTProcessorToolbox ptb; + + // set for multi-threaded running + ptb.SetRunSingleThreaded( false ); + + // add the primary processor + if( ! ptb.AddProcessor( "test-p-proc", "tpp" ) ) + { + KTERROR( testptlog, "Unable to create test primary processor" ); + return -1; + } + + // add processor b + if( ! ptb.AddProcessor( "test-proc-b", "tp" ) ) + { + KTERROR( testptlog, "Unable to create test processor b" ); + return -1; + } + + // make connections + if( ! ptb.MakeConnection( "tpp:the-signal", "tp:first-slot" ) ) + { + KTERROR( testptlog, "Unable to connect tpp to tp" ); + return -1; + } + + // set the run queue + if( ! ptb.PushBackToRunQueue( "tpp" ) ) + { + KTERROR( testptlog, "Unable to add tpp to the run queue" ); + return -1; + } + + // go! + KTINFO( testptlog, "Starting asynchronous run" ); + ptb.AsyncRun(); + + // wait for run completion, and ignore breakpoints + while( ptb.WaitForBreak() ) + { + KTINFO( testptlog, "Reached breakpoint; continuing" ); + ptb.Continue(); + } + + KTINFO( testptlog, "Processing complete" ); + + KTINFO( testptlog, "Tests complete" ); } - - // set the run queue - if( ! ptb.PushBackToRunQueue( "tpp" ) ) + catch( std::exception& e ) { - KTERROR( testptlog, "Unable to add tpp to the run queue" ); + KTERROR( testptlog, "Exception caught: " << e.what() ); return -1; } - - // go! - KTINFO( testptlog, "Starting asynchronous run" ); - ptb.AsyncRun(); - - // wait for run completion, and ignore breakpoints - while( ptb.WaitForBreak() ) - { - KTINFO( testptlog, "Reached breakpoint; continuing" ); - ptb.Continue(); - } - - KTINFO( testptlog, "Processing complete" ); - - KTINFO( testptlog, "Tests complete" ); - return 0; } diff --git a/Executables/Validation/TestProcessorToolboxSinglethreaded.cc b/Executables/Validation/TestProcessorToolboxSinglethreaded.cc index b0c1ca7..56a73db 100644 --- a/Executables/Validation/TestProcessorToolboxSinglethreaded.cc +++ b/Executables/Validation/TestProcessorToolboxSinglethreaded.cc @@ -15,55 +15,63 @@ KTLOGGER( testptlog, "TestProcessorToolboxSinglethreaded" ) int main() { - KTINFO( testptlog, "Preparing to run" ); - - KTProcessorToolbox ptb; - - // set for single-threaded running - ptb.SetRunSingleThreaded( true ); - - // add the primary processor - if( ! ptb.AddProcessor( "test-p-proc", "tpp" ) ) - { - KTERROR( testptlog, "Unable to create test primary processor" ); - return -1; - } - - // add processor b - if( ! ptb.AddProcessor( "test-proc-b", "tp" ) ) + try { - KTERROR( testptlog, "Unable to create test processor b" ); - return -1; + KTINFO( testptlog, "Preparing to run" ); + + KTProcessorToolbox ptb; + + // set for single-threaded running + ptb.SetRunSingleThreaded( true ); + + // add the primary processor + if( ! ptb.AddProcessor( "test-p-proc", "tpp" ) ) + { + KTERROR( testptlog, "Unable to create test primary processor" ); + return -1; + } + + // add processor b + if( ! ptb.AddProcessor( "test-proc-b", "tp" ) ) + { + KTERROR( testptlog, "Unable to create test processor b" ); + return -1; + } + + // make connections + if( ! ptb.MakeConnection( "tpp:the-signal", "tp:first-slot" ) ) + { + KTERROR( testptlog, "Unable to connect tpp to tp" ); + return -1; + } + + // set the run queue + if( ! ptb.PushBackToRunQueue( "tpp" ) ) + { + KTERROR( testptlog, "Unable to add tpp to the run queue" ); + return -1; + } + + // go! + KTINFO( testptlog, "Starting asynchronous run" ); + ptb.AsyncRun(); + + // wait for run completion, and ignore breakpoints + while( ptb.WaitForBreak() ) + { + KTINFO( testptlog, "Reached breakpoint; continuing" ); + ptb.Continue(); + } + + KTINFO( testptlog, "Processing complete" ); + + KTINFO( testptlog, "Tests complete" ); } - - // make connections - if( ! ptb.MakeConnection( "tpp:the-signal", "tp:first-slot" ) ) + catch( std::exception& e ) { - KTERROR( testptlog, "Unable to connect tpp to tp" ); + KTERROR( testptlog, "Exception caught: " << e.what() ); return -1; } - // set the run queue - if( ! ptb.PushBackToRunQueue( "tpp" ) ) - { - KTERROR( testptlog, "Unable to add tpp to the run queue" ); - return -1; - } - - // go! - KTINFO( testptlog, "Starting asynchronous run" ); - ptb.AsyncRun(); - - // wait for run completion, and ignore breakpoints - while( ptb.WaitForBreak() ) - { - KTINFO( testptlog, "Reached breakpoint; continuing" ); - ptb.Continue(); - } - - KTINFO( testptlog, "Processing complete" ); - - KTINFO( testptlog, "Tests complete" ); - return 0; } diff --git a/Library/Application/KTProcessorToolbox.cc b/Library/Application/KTProcessorToolbox.cc index 199f1b8..6fc3973 100644 --- a/Library/Application/KTProcessorToolbox.cc +++ b/Library/Application/KTProcessorToolbox.cc @@ -843,6 +843,10 @@ namespace Nymph bool KTProcessorToolbox::WaitForBreak() { boost::shared_future< void > doRunFuture = fDoRunFuture; + if( ! doRunFuture.valid() ) + { + throw KTException() << "Cannot wait for a break in the current state (the \"DoRun\" future does not have a valid shared state)"; + } doRunFuture.wait(); @@ -867,19 +871,32 @@ namespace Nymph void KTProcessorToolbox::WaitForEndOfRun() { - KTDEBUG( proclog, "Waiting for end-of-run" ); - while( WaitForBreak() ) + try + { + KTDEBUG( proclog, "Waiting for end-of-run" ); + while( WaitForBreak() ) + { + KTDEBUG( proclog, "Reached breakpoint; waiting for continue" ); + WaitForContinue(); + KTDEBUG( proclog, "Processing resuming; waiting for end-of-run" ); + } + KTDEBUG( proclog, "End-of-run reached" ); + } + catch( std::exception& e ) { - KTDEBUG( proclog, "Reached breakpoint; waiting for continue" ); - WaitForContinue(); - KTDEBUG( proclog, "Processing resuming; waiting for end-of-run" ); + throw; } - KTDEBUG( proclog, "End-of-run reached" ); return; } void KTProcessorToolbox::Continue() { + if( ! fDoRunBreakFlag ) + { + KTWARN( proclog, "Not currently at a breakpoint" ); + return; + } + boost::unique_lock< boost::mutex > breakContLock( fBreakContMutex ); boost::unique_lock< boost::mutex > threadFuturesLock( fThreadFuturesMutex ); @@ -969,12 +986,18 @@ namespace Nymph bool KTProcessorToolbox::Run() { - AsyncRun(); - - WaitForEndOfRun(); + try + { + AsyncRun(); - JoinRunThread(); + WaitForEndOfRun(); + JoinRunThread(); + } + catch( std::exception& e ) + { + throw; + } return true; } From a0f9dc1d71c76398e9f768da407542524a285d67 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Wed, 10 May 2017 14:01:10 -0700 Subject: [PATCH 037/521] Function initializations fixed in KTThreadReference; Switch to using shared_futures everywhere (seems to improve stability a little); Added generic function to pass work amongst connected processors. --- Library/Application/KTProcessorToolbox.hh | 2 +- Library/Processor/KTProcessor.cc | 20 +++-------------- Library/Processor/KTProcessor.hh | 26 +++++++++++++++++++++++ Library/Processor/KTThreadReference.cc | 6 +++--- Library/Processor/KTThreadReference.hh | 2 +- 5 files changed, 34 insertions(+), 22 deletions(-) diff --git a/Library/Application/KTProcessorToolbox.hh b/Library/Application/KTProcessorToolbox.hh index 14e57bc..f9bc967 100644 --- a/Library/Application/KTProcessorToolbox.hh +++ b/Library/Application/KTProcessorToolbox.hh @@ -226,7 +226,7 @@ namespace Nymph private: friend class KTThreadReference; - typedef boost::unique_future< KTDataPtr > Future; + typedef boost::shared_future< KTDataPtr > Future; // called from ThreadPacket::Break void InitiateBreak(); diff --git a/Library/Processor/KTProcessor.cc b/Library/Processor/KTProcessor.cc index b1ce746..cee44ed 100644 --- a/Library/Processor/KTProcessor.cc +++ b/Library/Processor/KTProcessor.cc @@ -47,23 +47,9 @@ namespace Nymph void KTProcessor::PassThreadRefUpdate(const std::string& slotName, KTThreadReference* threadRef) { - // update the thread reference pointer for this slot - GetSlot(slotName)->SetThreadRef(threadRef); - - // get the list of slot-to-signal connections for this slot - auto stsRange = fSlotToSigMap.equal_range(slotName); - - // loop over signals called in the performance of slot slotName - for (SlotToSigMapCIt stsIt = stsRange.first; stsIt != stsRange.second; ++stsIt) - { - // loop over all processor:slots called by this signal - auto sigConnRange = fSigConnMap.equal_range(stsIt->second); - for (SigConnMapCIt sigConnIt = sigConnRange.first; sigConnIt != sigConnRange.second; ++sigConnIt) - { - // pass the update on to the connected-to processor - sigConnIt->second.first->PassThreadRefUpdate(sigConnIt->second.second, threadRef); - } - } + std::function< void(KTThreadReference*) > funcObj = [this, &slotName](KTThreadReference* ref){ GetSlot(slotName)->SetThreadRef(ref); }; + PassToConnProcs(slotName, funcObj, threadRef); + return; } void KTProcessor::ConnectASlot(const std::string& signalName, KTProcessor* processor, const std::string& slotName, int groupNum) diff --git a/Library/Processor/KTProcessor.hh b/Library/Processor/KTProcessor.hh index 49d1bd3..735c863 100644 --- a/Library/Processor/KTProcessor.hh +++ b/Library/Processor/KTProcessor.hh @@ -87,6 +87,9 @@ namespace Nymph void SetDoBreakpoint(const std::string& slotName, bool flag); protected: + template< typename XReturn, typename... XArgs > + void PassToConnProcs(const std::string& slotName, std::function< XReturn(XArgs...) > function, XArgs... args); + void ConnectSignalToSlot(KTSignalWrapper* signal, KTSlotWrapper* slot, int groupNum=-1); SignalMap fSignalMap; @@ -134,6 +137,29 @@ namespace Nymph return; } + template< typename XReturn, typename... XArgs > + void KTProcessor::PassToConnProcs(const std::string& slotName, std::function< XReturn(XArgs...) > function, XArgs... args) + { + // update this slot + function(args...); + + // get the list of slot-to-signal connections for this slot + auto stsRange = fSlotToSigMap.equal_range(slotName); + + // loop over signals called in the performance of slot slotName + for (SlotToSigMapCIt stsIt = stsRange.first; stsIt != stsRange.second; ++stsIt) + { + // loop over all processor:slots called by this signal + auto sigConnRange = fSigConnMap.equal_range(stsIt->second); + for (SigConnMapCIt sigConnIt = sigConnRange.first; sigConnIt != sigConnRange.second; ++sigConnIt) + { + // pass the update on to the connected-to processor + sigConnIt->second.first->PassToConnProcs(sigConnIt->second.second, function, args...); + } + } + return; + } + template< class XDerivedProc > scarab::registrar< KTProcessor, XDerivedProc, const std::string& >* KTProcessor::RegisterProcessor( const std::string& name ) { diff --git a/Library/Processor/KTThreadReference.cc b/Library/Processor/KTThreadReference.cc index 1309bf0..f439320 100644 --- a/Library/Processor/KTThreadReference.cc +++ b/Library/Processor/KTThreadReference.cc @@ -21,8 +21,8 @@ namespace Nymph KTThreadReference::KTThreadReference() : fDataPtrRet(), - fInitiateBreakFunc(), - fRefreshFutureFunc(), + fInitiateBreakFunc( [](){return;} ), + fRefreshFutureFunc( [](const std::string&, boost::shared_future< KTDataPtr >&&){return;} ), fThreadIndicator( new KTThreadIndicator() ), fPrimaryProcName() {} @@ -67,7 +67,7 @@ namespace Nymph // reset the promise fDataPtrRet = KTDataPtrReturn(); // pass the future back to the processor toolbox (if it's in use) - fRefreshFutureFunc( fPrimaryProcName, std::move( fDataPtrRet.get_future() ) ); + fRefreshFutureFunc( fPrimaryProcName, std::move( fDataPtrRet.get_future().share() ) ); } return; } diff --git a/Library/Processor/KTThreadReference.hh b/Library/Processor/KTThreadReference.hh index 3f90f74..c77a175 100644 --- a/Library/Processor/KTThreadReference.hh +++ b/Library/Processor/KTThreadReference.hh @@ -28,7 +28,7 @@ namespace Nymph { KTDataPtrReturn fDataPtrRet; std::function< void() > fInitiateBreakFunc; - std::function< void(const std::string&, boost::unique_future< KTDataPtr >&&) > fRefreshFutureFunc; + std::function< void(const std::string&, boost::shared_future< KTDataPtr >&&) > fRefreshFutureFunc; std::shared_ptr< KTThreadIndicator > fThreadIndicator; std::string fPrimaryProcName; From c6e97253ef3ee590260a6cfd11d5755db641d886 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Tue, 23 May 2017 16:30:21 -0700 Subject: [PATCH 038/521] =?UTF-8?q?Adaptations=20for=20scarab2=E2=80=99s?= =?UTF-8?q?=20new=20param=20interface?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Executables/Validation/TestApplication.cc | 8 +--- Library/Application/KTApplication.cc | 24 +++++------ Library/Application/KTApplication.hh | 2 +- Library/Application/KTCommandLineHandler.cc | 12 +++--- Library/Application/KTConfigurator.cc | 16 -------- Library/Application/KTConfigurator.hh | 42 ++++++++++++++++---- Library/Application/KTProcessorToolbox.cc | 44 +++++++++------------ Library/Application/KTRunNymph.cc | 12 +++--- Library/Utility/KTConfigurable.cc | 3 +- Scarab | 2 +- 10 files changed, 81 insertions(+), 84 deletions(-) diff --git a/Executables/Validation/TestApplication.cc b/Executables/Validation/TestApplication.cc index cd8759d..810fada 100644 --- a/Executables/Validation/TestApplication.cc +++ b/Executables/Validation/TestApplication.cc @@ -82,13 +82,9 @@ int main(int argc, char** argv) KTTestConfigurable* testObj = new KTTestConfigurable(); - const scarab::param_node* topNode = app->GetConfigurator()->Config(); - if (topNode == NULL) - { - KTWARN(testapplog, "Top-level node <" << testObj->GetConfigName() << "> was not found"); - } + const scarab::param_node& topNode = app->GetConfigurator()->Config(); - if (testObj->Configure(topNode->node_at(testObj->GetConfigName()))) + if (testObj->Configure(&topNode.node_at(testObj->GetConfigName()))) { KTINFO(testapplog, "Configuration complete:\n" << "\tInt data: " << testObj->GetIntData() << '\n' diff --git a/Library/Application/KTApplication.cc b/Library/Application/KTApplication.cc index 3dff6d0..0dca130 100644 --- a/Library/Application/KTApplication.cc +++ b/Library/Application/KTApplication.cc @@ -99,7 +99,7 @@ namespace Nymph fConfigurator->Merge( *clConfigOverride ); } - KTINFO( applog, "Final configuration:\n" << *(fConfigurator->Config()) ); + KTINFO( applog, "Final configuration:\n" << fConfigurator->Config() ); AddConfigOptionsToCLHandler(fConfigurator->Config(), ""); fCLHandler->FinalizeNewOptionGroups(); @@ -122,37 +122,37 @@ namespace Nymph } } - void KTApplication::AddConfigOptionsToCLHandler(const scarab::param* param, const std::string& rootName) + void KTApplication::AddConfigOptionsToCLHandler(const scarab::param& param, const std::string& rootName) { - if (param->is_null()) + if (param.is_null()) { fCLHandler->AddOption("Config File Options", "Configuration flag: " + rootName, rootName, false); } - else if (param->is_value()) + else if (param.is_value()) { fCLHandler->AddOption< string >("Config File Options", "Configuration value: " + rootName, rootName, false); } - else if (param->is_array()) + else if (param.is_array()) { string nextRootName(rootName); if (! rootName.empty() && rootName.back() != '.') nextRootName += "."; - const scarab::param_array* paramArray = ¶m->as_array(); - unsigned arraySize = paramArray->size(); + const scarab::param_array& paramArray = param.as_array(); + unsigned arraySize = paramArray.size(); for (unsigned iParam = 0; iParam < arraySize; ++iParam) { - AddConfigOptionsToCLHandler(paramArray->at(iParam), nextRootName + std::to_string(iParam)); + AddConfigOptionsToCLHandler(paramArray.at(iParam), nextRootName + std::to_string(iParam)); } } - else if (param->is_node()) + else if (param.is_node()) { string nextRootName(rootName); if (! rootName.empty()) nextRootName += "."; - const scarab::param_node* paramNode = ¶m->as_node(); - for (scarab::param_node::const_iterator nodeIt = paramNode->begin(); nodeIt != paramNode->end(); ++nodeIt) + const scarab::param_node& paramNode = param.as_node(); + for (scarab::param_node::const_iterator nodeIt = paramNode.begin(); nodeIt != paramNode.end(); ++nodeIt) { - AddConfigOptionsToCLHandler(nodeIt->second, nextRootName + nodeIt->first); + AddConfigOptionsToCLHandler(*nodeIt->second, nextRootName + nodeIt->first); } } diff --git a/Library/Application/KTApplication.hh b/Library/Application/KTApplication.hh index c0c2ddf..677bbbc 100644 --- a/Library/Application/KTApplication.hh +++ b/Library/Application/KTApplication.hh @@ -62,7 +62,7 @@ namespace Nymph virtual ~KTApplication(); private: - void AddConfigOptionsToCLHandler(const scarab::param* param, const std::string& rootName); + void AddConfigOptionsToCLHandler(const scarab::param& param, const std::string& rootName); public: virtual bool Configure(const scarab::param_node* node); diff --git a/Library/Application/KTCommandLineHandler.cc b/Library/Application/KTCommandLineHandler.cc index 8f8b073..40ea9fc 100644 --- a/Library/Application/KTCommandLineHandler.cc +++ b/Library/Application/KTCommandLineHandler.cc @@ -273,19 +273,19 @@ namespace Nymph size_t t_node_start_pos = 0; size_t t_node_sep_pos = t_full_name.find_first_of( fNodeSeparator ); - scarab::param_node* parentNode = &fConfigOverrideValues; + scarab::param_node& parentNode = fConfigOverrideValues; while (t_node_sep_pos != string::npos) { string nodeName(t_full_name.substr(t_node_start_pos, t_node_sep_pos)); - if (parentNode->has(nodeName)) + if (parentNode.has(nodeName)) { - parentNode = parentNode->node_at(nodeName); + parentNode = parentNode.node_at(nodeName); } else { scarab::param_node* newChildNode = new scarab::param_node(); - parentNode->add(nodeName, newChildNode); - parentNode = newChildNode; + parentNode.add(nodeName, newChildNode); + parentNode = *newChildNode; } t_node_start_pos = t_node_sep_pos + 1; t_node_sep_pos = t_full_name.find_first_of(fNodeSeparator, t_node_start_pos); @@ -298,7 +298,7 @@ namespace Nymph //std::cout << "(parser) adding < " << t_name << "<" << t_type << "> > = <" << new_value.value() << ">" << std::endl; - parentNode->replace( valueName, new_value ); + parentNode.replace( valueName, new_value ); continue; } diff --git a/Library/Application/KTConfigurator.cc b/Library/Application/KTConfigurator.cc index e1f8ba2..0c5ae12 100644 --- a/Library/Application/KTConfigurator.cc +++ b/Library/Application/KTConfigurator.cc @@ -27,20 +27,4 @@ namespace Nymph delete fMasterConfig; } - void KTConfigurator::Merge(const scarab::param_node& aNode) - { - fMasterConfig->merge(aNode); - return; - } - - scarab::param_node* KTConfigurator::Config() - { - return fMasterConfig; - } - - const scarab::param_node* KTConfigurator::Config() const - { - return fMasterConfig; - } - } /* namespace Nymph */ diff --git a/Library/Application/KTConfigurator.hh b/Library/Application/KTConfigurator.hh index 92d8ffa..d38872f 100644 --- a/Library/Application/KTConfigurator.hh +++ b/Library/Application/KTConfigurator.hh @@ -30,8 +30,8 @@ namespace Nymph public: void Merge(const scarab::param_node& aNode); - scarab::param_node* Config(); - const scarab::param_node* Config() const; + scarab::param_node& Config(); + const scarab::param_node& Config() const; template< typename XReturnType > XReturnType Get( const std::string& aName ) const; @@ -50,26 +50,52 @@ namespace Nymph template< typename XReturnType > XReturnType KTConfigurator::Get( const std::string& aName ) const { - fParamBuffer = const_cast< scarab::param* >( fMasterConfig->at( aName ) ); - if( fParamBuffer != NULL && fParamBuffer->is_value() ) + try { - return fParamBuffer->as_value().get< XReturnType >(); + fParamBuffer = &const_cast< scarab::param& >( fMasterConfig->at( aName ) ); + if( fParamBuffer->is_value() ) + { + return fParamBuffer->as_value().get< XReturnType >(); + } } + catch( std::exception& e ) + {} throw KTException() << "configurator does not have a value for <" << aName << ">"; } template< typename XReturnType > XReturnType KTConfigurator::Get( const std::string& aName, XReturnType aDefault ) const { - fParamBuffer = const_cast< scarab::param* >( fMasterConfig->at( aName ) ); - if( fParamBuffer != NULL && fParamBuffer->is_value() ) + try { - return fParamBuffer->as_value().get< XReturnType >(); + fParamBuffer = &const_cast< scarab::param& >( fMasterConfig->at( aName ) ); + if( fParamBuffer->is_value() ) + { + return fParamBuffer->as_value().get< XReturnType >(); + } } + catch( std::exception& e ) + {} return aDefault; + } + inline void KTConfigurator::Merge(const scarab::param_node& aNode) + { + fMasterConfig->merge(aNode); + return; + } + + inline scarab::param_node& KTConfigurator::Config() + { + return *fMasterConfig; } + inline const scarab::param_node& KTConfigurator::Config() const + { + return *fMasterConfig; + } + + } /* namespace Nymph */ #endif /* KTCONFIGURATOR_HH_ */ diff --git a/Library/Application/KTProcessorToolbox.cc b/Library/Application/KTProcessorToolbox.cc index 6fc3973..a29e8f6 100644 --- a/Library/Application/KTProcessorToolbox.cc +++ b/Library/Application/KTProcessorToolbox.cc @@ -57,14 +57,14 @@ namespace Nymph SetRunSingleThreaded( node->get_value( "single-threaded", fRunSingleThreaded ) ); // Deal with "processor" blocks - const scarab::param_array* procArray = node->array_at( "processors" ); - if (procArray == NULL) + if (! node->has("processors")) { KTWARN(proclog, "No processors were specified"); } else { - for( scarab::param_array::const_iterator procIt = procArray->begin(); procIt != procArray->end(); ++procIt ) + const scarab::param_array& procArray = node->array_at( "processors" ); + for( scarab::param_array::const_iterator procIt = procArray.begin(); procIt != procArray.end(); ++procIt ) { if( ! (*procIt)->is_node() ) { @@ -108,14 +108,14 @@ namespace Nymph // Then deal with connections" - const scarab::param_array* connArray = node->array_at( "connections" ); - if (connArray == NULL) + if (! node->has("connections")) { KTWARN(proclog, "No connections were specified"); } else { - for( scarab::param_array::const_iterator connIt = connArray->begin(); connIt != connArray->end(); ++connIt ) + const scarab::param_array& connArray = node->array_at( "connections" ); + for( scarab::param_array::const_iterator connIt = connArray.begin(); connIt != connArray.end(); ++connIt ) { if( ! (*connIt)->is_node() ) { @@ -180,14 +180,14 @@ namespace Nymph // The run queue is an array of processor names, or groups of names, which will be run sequentially. // If names are grouped (in another array), those in that group will be run in parallel. // In single threaded mode all threads will be run sequentially in the order they were specified. - const scarab::param_array* rqArray = node->array_at( "run-queue" ); - if (rqArray == NULL) + if (! node->has("run-queue")) { KTWARN(proclog, "Run queue was not specified"); } else { - for (scarab::param_array::const_iterator rqIt = rqArray->begin(); rqIt != rqArray->end(); ++rqIt) + const scarab::param_array& rqArray = node->array_at( "run-queue" ); + for (scarab::param_array::const_iterator rqIt = rqArray.begin(); rqIt != rqArray.end(); ++rqIt) { if ((*rqIt)->is_value()) { @@ -235,29 +235,21 @@ namespace Nymph { KTDEBUG(proclog, "Attempting to configure processor <" << iter->first << ">"); string procName = iter->first; - string nameUsed; - const scarab::param_node* subNode = node->node_at(procName); - if (subNode == NULL) + string nameUsed(procName); + if (! node->has(nameUsed)) { - string configName = iter->second.fProc->GetConfigName(); - KTWARN(proclog, "Did not find a parameter node <" << procName << ">\n" - "\tWill check using the generic name of the processor, <" << configName << ">."); - subNode = node->node_at(configName); - if (subNode == NULL) + nameUsed = iter->second.fProc->GetConfigName(); + if (! node->has(nameUsed)) { - KTWARN(proclog, "Did not find a parameter node <" << configName << ">\n" - "\tProcessor <" << iter->first << "> was not configured."); + KTWARN(proclog, "Did not find a parameter node <" << procName << "> or <" << nameUsed << ">\n" + "\tProcessor <" << procName << "> was not configured."); continue; } - nameUsed = configName; } - else - { - nameUsed = procName; - } - if (! iter->second.fProc->Configure(subNode)) + const scarab::param_node& subNode = node->node_at(nameUsed); + if (! iter->second.fProc->Configure(&subNode)) { - KTERROR(proclog, "An error occurred while configuring processor <" << iter->first << "> with parameter node <" << nameUsed << ">"); + KTERROR(proclog, "An error occurred while configuring processor <" << procName << "> with parameter node <" << nameUsed << ">"); return false; } } diff --git a/Library/Application/KTRunNymph.cc b/Library/Application/KTRunNymph.cc index 7888242..4f7ea90 100644 --- a/Library/Application/KTRunNymph.cc +++ b/Library/Application/KTRunNymph.cc @@ -21,9 +21,9 @@ namespace Nymph { try { - const scarab::param_node* parentConfigNode = app->GetConfigurator()->Config(); + const scarab::param_node& parentConfigNode = app->GetConfigurator()->Config(); - if (! app->Configure(parentConfigNode->node_at(app->GetConfigName()))) + if( ! app->Configure(&parentConfigNode.node_at(app->GetConfigName() ) ) ) { KTERROR( nlog, "Unable to configure the application. Aborting."); return -2; @@ -33,16 +33,16 @@ namespace Nymph // This will create all of the requested processors, connect their signals and slots, and fill the run queue. KTProcessorToolbox procTB; - if ( ! procTB.Configure( parentConfigNode->node_at( procTB.GetConfigName() ) ) ) + if ( ! procTB.Configure( &parentConfigNode.node_at( procTB.GetConfigName() ) ) ) { - KTERROR( nlog, "Unable to configure processor toolbox. Aborting."); + KTERROR( nlog, "Unable to configure processor toolbox. Aborting." ); return -3; } // Configure the processors - if ( ! procTB.ConfigureProcessors( parentConfigNode ) ) + if ( ! procTB.ConfigureProcessors( &parentConfigNode ) ) { - KTERROR( nlog, "Unable to configure processors. Aborting."); + KTERROR( nlog, "Unable to configure processors. Aborting." ); return -4; } diff --git a/Library/Utility/KTConfigurable.cc b/Library/Utility/KTConfigurable.cc index 542ff5e..e2f6acc 100644 --- a/Library/Utility/KTConfigurable.cc +++ b/Library/Utility/KTConfigurable.cc @@ -61,8 +61,7 @@ namespace Nymph { if (fIsConfigured) return true; - scarab::param_node* node = KTConfigurator::get_instance()->Config(); - if (! this->Configure(node)) + if (! this->Configure(&KTConfigurator::get_instance()->Config())) { KTERROR(conflog, "An error occurred while configuring <" << fConfigName << ">"); return false; diff --git a/Scarab b/Scarab index 409659a..16beb8e 160000 --- a/Scarab +++ b/Scarab @@ -1 +1 @@ -Subproject commit 409659a19eccd1e871e6b17b2af62e65a7e78c6c +Subproject commit 16beb8efb83d718f79c3e3d5b0b5ea2359226455 From 87964eeff45bcaa1d697b80417f25d8bf14de175 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Tue, 23 May 2017 17:07:41 -0700 Subject: [PATCH 039/521] Scarab now has a terminate() function to give useful information for unhandled exceptions --- Scarab | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Scarab b/Scarab index 16beb8e..d6eb49f 160000 --- a/Scarab +++ b/Scarab @@ -1 +1 @@ -Subproject commit 16beb8efb83d718f79c3e3d5b0b5ea2359226455 +Subproject commit d6eb49f445a7d675e3e76b56ba12b175dca10d92 From f4ee90bf427c0a6d6f046f36efd1532adf4cf9ca Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Wed, 24 May 2017 18:12:16 -0700 Subject: [PATCH 040/521] Messy, but just possibly functional refactoring of how threads are handled by KTProcessorToolbox --- .../Validation/KTTestPrimaryProcessor.cc | 2 +- Executables/Validation/KTTestProcessor.cc | 2 +- Executables/Validation/TestExceptionInSlot.cc | 21 +- .../Validation/TestPrimaryProcessor.cc | 19 +- .../TestProcessorToolbox2Threads.cc | 5 + .../TestProcessorToolboxMultithreaded.cc | 5 + .../TestProcessorToolboxSinglethreaded.cc | 5 + Executables/Validation/TestUseBreakpoint.cc | 123 ++--- Library/Application/KTProcessorToolbox.cc | 467 ++++++++++-------- Library/Application/KTProcessorToolbox.hh | 69 ++- Library/Data/KTApplyCut.cc | 2 +- Library/Data/KTCutFilter.cc | 2 +- Library/Processor/KTPrimaryProcessor.cc | 12 +- Library/Processor/KTPrimaryProcessor.hh | 10 +- Library/Processor/KTProcessor.cc | 4 +- Library/Processor/KTProcessor.hh | 2 +- Library/Processor/KTSlot.hh | 2 +- Library/Processor/KTSlotWrapper.hh | 10 +- Library/Processor/KTThreadReference.cc | 69 ++- Library/Processor/KTThreadReference.hh | 23 +- 20 files changed, 518 insertions(+), 336 deletions(-) diff --git a/Executables/Validation/KTTestPrimaryProcessor.cc b/Executables/Validation/KTTestPrimaryProcessor.cc index 39e6121..42f8aab 100644 --- a/Executables/Validation/KTTestPrimaryProcessor.cc +++ b/Executables/Validation/KTTestPrimaryProcessor.cc @@ -39,7 +39,7 @@ namespace Nymph // e.g. for a real processor, do some work here instead of sleeping boost::this_thread::sleep_for( boost::chrono::milliseconds(1) ); - if( fThreadRef.fThreadIndicator->fCanceled ) break; + if( fThreadRef->fCanceled ) break; fTheSignal( iIteration ); } diff --git a/Executables/Validation/KTTestProcessor.cc b/Executables/Validation/KTTestProcessor.cc index 826b673..5401600 100644 --- a/Executables/Validation/KTTestProcessor.cc +++ b/Executables/Validation/KTTestProcessor.cc @@ -92,7 +92,7 @@ namespace Nymph void KTTestProcessorC::SlotFunc1(int input) { - KTThreadReference* ref = fSlot1.GetSlotWrapper()->GetThreadRef(); + std::shared_ptr< KTThreadReference > ref = fSlot1.GetSlotWrapper()->GetThreadRef(); KTINFO(testsiglog, "Slot1: input is " << input); throw KTException() << "A HUGE problem occurred!!!! (just kidding, this is the expected result)"; diff --git a/Executables/Validation/TestExceptionInSlot.cc b/Executables/Validation/TestExceptionInSlot.cc index 1fe808d..6944424 100644 --- a/Executables/Validation/TestExceptionInSlot.cc +++ b/Executables/Validation/TestExceptionInSlot.cc @@ -35,9 +35,9 @@ int main() } // setup to execute processors asynchronously - KTThreadReference exeThreadRef; - auto exeThreadFuture = exeThreadRef.fDataPtrRet.get_future(); - tpC.GetSlot( "first-slot" )->SetThreadRef (&exeThreadRef ); + std::shared_ptr< KTThreadReference > exeThreadRef = std::make_shared< KTThreadReference >(); + //boost::shared_future< KTDataPtr > exeThreadFuture = exeThreadRef->fDataPtrRetFuture; + tpC.GetSlot( "first-slot" )->SetThreadRef( exeThreadRef ); std::atomic< bool > canceled( false ); @@ -60,7 +60,7 @@ int main() } catch( ... ) { - exeThreadRef.fDataPtrRet.set_exception( std::current_exception() ); + exeThreadRef->fDataPtrRet.set_exception( boost::current_exception() ); } return; @@ -70,16 +70,21 @@ int main() boost::thread thread( exeFunc ); // wait for a result to be set - exeThreadFuture.wait(); + exeThreadRef->fDataPtrRetFuture.wait(); try { - exeThreadFuture.get(); + exeThreadRef->fDataPtrRetFuture.get(); } - catch( std::exception& e ) + //catch( std::exception& e ) + //{ + // canceled = true; + // KTERROR( testexclog, "An error occurred while running a processor: " << e.what() ); + //} + catch( boost::exception& e ) { canceled = true; - KTERROR( testexclog, "An error occurred while running a processor: " << e.what() ); + KTERROR( testexclog, "An error occurred while running a processor: " << diagnostic_information( e ) ); } thread.join(); diff --git a/Executables/Validation/TestPrimaryProcessor.cc b/Executables/Validation/TestPrimaryProcessor.cc index 22d3c1e..e549215 100644 --- a/Executables/Validation/TestPrimaryProcessor.cc +++ b/Executables/Validation/TestPrimaryProcessor.cc @@ -34,8 +34,10 @@ int main() } // setup to execute processors asynchronously - KTThreadReference exeThreadRef; - auto exeThreadFuture = exeThreadRef.fDataPtrRet.get_future(); + //KTThreadReference exeThreadRef; + //auto exeThreadFuture = exeThreadRef.fDataPtrRet.get_future(); + std::shared_ptr< KTThreadReference > exeThreadRef = std::make_shared< KTThreadReference >(); + exeThreadRef->fName = std::string( "tpp" ); // run the thread boost::condition_variable threadStartedCV; @@ -43,7 +45,7 @@ int main() bool threadStartedFlag = false; boost::unique_lock< boost::mutex > threadStartedLock( threadStartedMutex ); - boost::thread thread( [&](){ tpp( std::move( exeThreadRef ), threadStartedCV, threadStartedFlag ); } ); + boost::thread thread( [&](){ tpp( exeThreadRef, threadStartedCV, threadStartedFlag ); } ); while( ! threadStartedFlag ) { @@ -52,17 +54,22 @@ int main() KTDEBUG( testpplog, "Thread has started" ); // wait for a result to be set - exeThreadFuture.wait(); + exeThreadRef->fDataPtrRetFuture.wait(); try { - exeThreadFuture.get(); + exeThreadRef->fDataPtrRetFuture.get(); } catch( std::exception& e ) { - exeThreadRef.fThreadIndicator->fCanceled = true; + exeThreadRef->fCanceled = true; KTERROR( testpplog, "An error occurred while running a processor: " << e.what() ); } + catch( boost::exception& e ) + { + exeThreadRef->fCanceled = true; + KTERROR( testpplog, "An error occurred while running a processor: " << diagnostic_information( e ) ); + } thread.join(); diff --git a/Executables/Validation/TestProcessorToolbox2Threads.cc b/Executables/Validation/TestProcessorToolbox2Threads.cc index d92960f..c43459f 100644 --- a/Executables/Validation/TestProcessorToolbox2Threads.cc +++ b/Executables/Validation/TestProcessorToolbox2Threads.cc @@ -110,5 +110,10 @@ int main() KTERROR( testptlog, "Exception caught: " << e.what() ); return -1; } + catch( boost::exception& e ) + { + KTERROR( testptlog, "Exception caught: " << diagnostic_information( e ) ); + return -1; + } return 0; } diff --git a/Executables/Validation/TestProcessorToolboxMultithreaded.cc b/Executables/Validation/TestProcessorToolboxMultithreaded.cc index d71b5ab..089407c 100644 --- a/Executables/Validation/TestProcessorToolboxMultithreaded.cc +++ b/Executables/Validation/TestProcessorToolboxMultithreaded.cc @@ -72,5 +72,10 @@ int main() KTERROR( testptlog, "Exception caught: " << e.what() ); return -1; } + catch( boost::exception& e ) + { + KTERROR( testptlog, "Exception caught: " << diagnostic_information( e ) ); + return -1; + } return 0; } diff --git a/Executables/Validation/TestProcessorToolboxSinglethreaded.cc b/Executables/Validation/TestProcessorToolboxSinglethreaded.cc index 56a73db..65144ab 100644 --- a/Executables/Validation/TestProcessorToolboxSinglethreaded.cc +++ b/Executables/Validation/TestProcessorToolboxSinglethreaded.cc @@ -72,6 +72,11 @@ int main() KTERROR( testptlog, "Exception caught: " << e.what() ); return -1; } + catch( boost::exception& e ) + { + KTERROR( testptlog, "Exception caught: " << diagnostic_information( e ) ); + return -1; + } return 0; } diff --git a/Executables/Validation/TestUseBreakpoint.cc b/Executables/Validation/TestUseBreakpoint.cc index 466b814..738fd04 100644 --- a/Executables/Validation/TestUseBreakpoint.cc +++ b/Executables/Validation/TestUseBreakpoint.cc @@ -16,71 +16,82 @@ KTLOGGER( testptlog, "TestUseBreakpoint" ) int main() { - KTINFO( testptlog, "Preparing to run" ); - - KTProcessorToolbox ptb; - - // add the primary processor - if( ! ptb.AddProcessor( "test-p-proc", "tpp" ) ) - { - KTERROR( testptlog, "Unable to create test primary processor" ); - return -1; - } - - // add processor b - if( ! ptb.AddProcessor( "test-proc-b", "tp" ) ) - { - KTERROR( testptlog, "Unable to create test processor b" ); - return -1; - } - // set breakpoint - if( ! ptb.SetBreakpoint( "tp", "first-slot" ) ) + try { - KTERROR( testptlog, "Unable to set the breakpoint" ); - return -1; - } - - // make connections - if( ! ptb.MakeConnection( "tpp:the-signal", "tp:first-slot" ) ) - { - KTERROR( testptlog, "Unable to connect tpp to tp" ); - return -1; - } - - // set the run queue - if( ! ptb.PushBackToRunQueue( "tpp" ) ) - { - KTERROR( testptlog, "Unable to add tpp to the run queue" ); - return -1; - } + KTINFO( testptlog, "Preparing to run" ); - // go! - KTINFO( testptlog, "Starting asynchronous run" ); - ptb.AsyncRun(); + KTProcessorToolbox ptb; - KTINFO( testptlog, "Starting asynchronous breakpoint user" ); - auto buFuture = boost::async( boost::launch::async, [&](){ - KTINFO( testptlog, "In breakpoint user thread" ); - while( ptb.WaitForBreak() ) + // add the primary processor + if( ! ptb.AddProcessor( "test-p-proc", "tpp" ) ) { - KTPROG( testptlog, "Reached breakpoint; waiting for user input" ); - std::string temp; - KTPROG( testptlog, "Please press [return]" ); - getline( std::cin, temp ); - ptb.Continue(); + KTERROR( testptlog, "Unable to create test primary processor" ); + return -1; } - KTINFO( testptlog, "Finished breakpoint user thread" ); - return; - }); - KTINFO( testptlog, "Waiting for the end of the run" ); - ptb.WaitForEndOfRun(); + // add processor b + if( ! ptb.AddProcessor( "test-proc-b", "tp" ) ) + { + KTERROR( testptlog, "Unable to create test processor b" ); + return -1; + } + // set breakpoint + if( ! ptb.SetBreakpoint( "tp", "first-slot" ) ) + { + KTERROR( testptlog, "Unable to set the breakpoint" ); + return -1; + } - KTINFO( testptlog, "Processing complete" ); + // make connections + if( ! ptb.MakeConnection( "tpp:the-signal", "tp:first-slot" ) ) + { + KTERROR( testptlog, "Unable to connect tpp to tp" ); + return -1; + } - ptb.JoinRunThread(); + // set the run queue + if( ! ptb.PushBackToRunQueue( "tpp" ) ) + { + KTERROR( testptlog, "Unable to add tpp to the run queue" ); + return -1; + } - KTINFO( testptlog, "Tests complete" ); + // go! + KTINFO( testptlog, "Starting asynchronous run" ); + ptb.AsyncRun(); + + KTINFO( testptlog, "Starting asynchronous breakpoint user" ); + auto buFuture = boost::async( boost::launch::async, [&](){ + KTINFO( testptlog, "In breakpoint user thread" ); + while( ptb.WaitForBreak() ) + { + KTPROG( testptlog, "Reached breakpoint; waiting for user input" ); + std::string temp; + KTPROG( testptlog, "Please press [return]" ); + getline( std::cin, temp ); + ptb.Continue(); + } + KTINFO( testptlog, "Finished breakpoint user thread" ); + return; + }); + + KTINFO( testptlog, "Waiting for the end of the run" ); + ptb.WaitForEndOfRun(); + + KTINFO( testptlog, "Processing complete" ); + + ptb.JoinRunThread(); + + KTINFO( testptlog, "Tests complete" ); + } + catch( std::exception& e ) + { + KTERROR( testptlog, "Caught exception: " << e.what() ); + } + catch( boost::exception& e ) + { + KTERROR( testptlog, "Caught exception: " << diagnostic_information( e ) ); + } return 0; } diff --git a/Library/Application/KTProcessorToolbox.cc b/Library/Application/KTProcessorToolbox.cc index a29e8f6..95bb39a 100644 --- a/Library/Application/KTProcessorToolbox.cc +++ b/Library/Application/KTProcessorToolbox.cc @@ -14,6 +14,7 @@ #include "factory.hh" #include "param_codec.hh" +#include #include using std::deque; @@ -31,7 +32,9 @@ namespace Nymph fRunSingleThreaded( false ), fRunQueue(), fProcMap(), - fThreadFutures(), + fThreadReferences(), + fThreadFuturesMutex(), + //fThreadFutures(), fContinueSignaler(), fMasterContSignal(), fBreakContMutex(), @@ -581,176 +584,204 @@ namespace Nymph if( willRunSingleThreaded ) { - auto singleThreadRun = [&]() + StartSingleThreadedRun(); + } + else + { + StartMultiThreadedRun(); + } + + return; + } + + void KTProcessorToolbox::StartSingleThreadedRun() + { + auto singleThreadRun = [&]() + { + try { - try + // reset the continue signaler + fContinueSignaler = boost::promise< void >(); + fMasterContSignal = fContinueSignaler.get_future().share(); + if( ! fMasterContSignal.valid() ) { - // reset the continue signaler - fContinueSignaler = boost::promise< void >(); - fMasterContSignal = fContinueSignaler.get_future().share(); - if( ! fMasterContSignal.valid() ) - { - KTERROR( proclog, "Invalid master continue-signal created" ); - throw KTException() << "Invalid master continue-signal created"; - } - // copy for use in this function - boost::shared_future< void > continueSignal = fMasterContSignal; + KTERROR( proclog, "Invalid master continue-signal created" ); + throw KTException() << "Invalid master continue-signal created"; + } + // copy for use in this function + boost::shared_future< void > continueSignal = fMasterContSignal; - KTPROG( proclog, "Starting single-threaded processing" ); + KTPROG( proclog, "Starting single-threaded processing" ); - for (RunQueue::iterator rqIter = fRunQueue.begin(); rqIter != fRunQueue.end(); ++rqIter) + for (RunQueue::iterator rqIter = fRunQueue.begin(); rqIter != fRunQueue.end(); ++rqIter) + { + for (ThreadGroup::iterator tgIter = rqIter->begin(); tgIter != rqIter->end(); ++tgIter) { - for (ThreadGroup::iterator tgIter = rqIter->begin(); tgIter != rqIter->end(); ++tgIter) - { - std::string procName( tgIter->fName ); - KTINFO( proclog, "Starting processor <" << procName << ">" ); + boost::unique_lock< boost::mutex > threadFuturesLock( fThreadFuturesMutex ); - KTThreadReference thisThreadRef; + std::string procName( tgIter->fName ); + KTINFO( proclog, "Starting processor <" << procName << ">" ); - fThreadFutures.push_back( std::move( thisThreadRef.fDataPtrRet.get_future() ) ); - fThreadNames.push_back( procName ); - //auto& futureNameIndex = fThreadFutures.get<1>(); + //KTThreadReference thisThreadRef; + std::shared_ptr< KTThreadReference > thisThreadRef = std::make_shared< KTThreadReference >(); + thisThreadRef->fName = procName; - if( ! fThreadFutures.back().valid() ) - { - KTERROR( proclog, "Invalid thread future created" ); - throw KTException() << "Invalid thread future created"; - } + //fThreadFutures.push_back( std::move( thisThreadRef.fDataPtrRet.get_future() ) ); + //fThreadNames.push_back( procName ); + //auto& futureNameIndex = fThreadFutures.get<1>(); - fThreadIndicators.emplace_back( new KTThreadIndicator() ); - fThreadIndicators.back()->fContinueSignal = fMasterContSignal; + //if( ! fThreadFutures.back().valid() ) + //{ + // KTERROR( proclog, "Invalid thread future created" ); + // throw KTException() << "Invalid thread future created"; + //} - thisThreadRef.fThreadIndicator = fThreadIndicators.back(); - thisThreadRef.fInitiateBreakFunc = [&](){ this->InitiateBreak(); }; - thisThreadRef.fRefreshFutureFunc = [&]( const std::string& name, Future&& ret ){ this->TakeFuture( name, std::move(ret) ); }; + //fThreadIndicators.emplace_back( new KTThreadIndicator() ); + //fThreadIndicators.back()->fContinueSignal = fMasterContSignal; + thisThreadRef->fContinueSignal = fMasterContSignal; - boost::condition_variable threadStartedCV; - boost::mutex threadStartedMutex; - bool threadStartedFlag = false; + //thisThreadRef->fThreadIndicator = fThreadIndicators.back(); + thisThreadRef->fInitiateBreakFunc = [&](){ this->InitiateBreak(); }; + //thisThreadRef->fRefreshFutureFunc = [&]( const std::string& name, Future&& ret ){ this->TakeFuture( name, std::move(ret) ); }; - boost::unique_lock< boost::mutex > threadStartedLock( threadStartedMutex ); - boost::thread thread( [&](){ tgIter->fProc->operator()( std::move( thisThreadRef ), threadStartedCV, threadStartedFlag ); } ); - KTDEBUG( proclog, "Thread ID is <" << thread.get_id() << ">; waiting for thread start" ); - while( ! threadStartedFlag ) - { - threadStartedCV.wait( threadStartedLock ); - } - KTDEBUG( proclog, "Thread has started" ); + fThreadReferences.push_back( thisThreadRef ); + + boost::condition_variable threadStartedCV; + boost::mutex threadStartedMutex; + bool threadStartedFlag = false; - KTDEBUG( proclog, "Thread ID is <" << thread.get_id() << ">" ); + boost::unique_lock< boost::mutex > threadStartedLock( threadStartedMutex ); + boost::thread thread( [&](){ tgIter->fProc->operator()( thisThreadRef, threadStartedCV, threadStartedFlag ); } ); + KTDEBUG( proclog, "Thread ID is <" << thread.get_id() << ">; waiting for thread start" ); + while( ! threadStartedFlag ) + { + threadStartedCV.wait( threadStartedLock ); + } + KTDEBUG( proclog, "Thread has started" ); - bool stillRunning = true; // determines behavior that depends on whether a return from the thread was temporary or from the thread completing + KTDEBUG( proclog, "Thread ID is <" << thread.get_id() << ">" ); + + threadFuturesLock.unlock(); + + bool stillRunning = true; // determines behavior that depends on whether a return from the thread was temporary or from the thread completing + do + { + boost::future_status status; do { - boost::future_status status; - do - { - status = fThreadFutures.back().wait_for( boost::chrono::milliseconds(500) ); - } while (status != boost::future_status::ready); + status = fThreadReferences.back()->fDataPtrRetFuture.wait_for( boost::chrono::milliseconds(500) ); + } while (status != boost::future_status::ready); - stillRunning = false; - if( fThreadIndicators.back()->fBreakFlag ) + stillRunning = false; + if( fThreadReferences.back()->fBreakFlag ) + { + KTDEBUG( proclog, "Breakpoint reached (seen first in thread <" << fThreadReferences.back()->fName << ">; may not be where breakpoint is set)" ); + continueSignal.wait(); + KTDEBUG( proclog, "Breakpoint finished" ); + stillRunning = true; + continueSignal = fMasterContSignal; // refresh the local copy of the shared future + } + else + { + try { - KTDEBUG( proclog, "Breakpoint reached (seen first in thread <" << fThreadNames.back() << ">; may not be where breakpoint is set)" ); - continueSignal.wait(); - KTDEBUG( proclog, "Breakpoint finished" ); - stillRunning = true; - continueSignal = fMasterContSignal; // refresh the local copy of the shared future + fThreadReferences.back()->fDataPtrRetFuture.get(); + KTINFO( proclog, "Thread <" << fThreadReferences.back()->fName << "> has finished" ); + fThreadReferences.pop_back(); } - else + catch( boost::exception& e ) { - try - { - fThreadFutures.back().get(); - KTINFO( proclog, "Thread <" << fThreadNames.back() << "> has finished" ); - fThreadFutures.pop_back(); - fThreadNames.pop_back(); - } - catch( std::exception& e ) - { - KTERROR( proclog, "Thread <" << fThreadNames.back() << "> threw an error: " << e.what() ); - // this transfers an exception thrown by a processor to the outer catch block in this function - throw KTException() << "An error occurred while running processor <" << procName << ">: " << e.what(); - } - stillRunning = false; + KTERROR( proclog, "Thread <" << fThreadReferences.back()->fName << "> threw an error: " << diagnostic_information( e ) ); + // this transfers an exception thrown by a processor to the outer catch block in this function + throw KTException() << "An error occurred while running processor <" << procName << ">: " << diagnostic_information( e ); } - } while( stillRunning ); + stillRunning = false; + } + } while( stillRunning ); - KTINFO( proclog, "Processor <" << procName << "> has finished" ); + KTINFO( proclog, "Processor <" << procName << "> has finished" ); - thread.join(); - fThreadIndicators.clear(); - fThreadFutures.clear(); - fThreadNames.clear(); - } // end for loop over the thread group - } // end for loop over the run-queue + thread.join(); + fThreadReferences.clear(); + //fThreadFutures.clear(); + //fThreadNames.clear(); + } // end for loop over the thread group + } // end for loop over the run-queue - KTPROG( proclog, "Processing is complete (single-threaded)" ); - } - catch( std::exception& e ) - { - KTDEBUG( proclog, "Caught exception thrown in a processor or in the multi-threaded run function: " << e.what() ); - // exceptions thrown in this function or from within processors will end up here - fDoRunPromise.set_exception( std::current_exception() ); - } - fDoRunPromise.set_value(); - return; - }; + KTPROG( proclog, "Processing is complete (single-threaded)" ); + } + catch( std::exception& e ) + { + KTDEBUG( proclog, "Caught exception thrown in a processor or in the single-threaded run function: " << e.what() ); + // exceptions thrown in this function or from within processors will end up here + fDoRunPromise.set_exception( std::current_exception() ); + } + catch( boost::exception& e ) + { + KTDEBUG( proclog, "Caught exception thrown in a processor or in the single-threaded run function: " << diagnostic_information( e ) ); + // exceptions thrown in this function or from within processors will end up here + fDoRunPromise.set_exception( std::current_exception() ); + } + fDoRunPromise.set_value(); + return; + }; // end single-threaded run lambda - fDoRunThread = new boost::thread( singleThreadRun ); - } - else + fDoRunThread = new boost::thread( singleThreadRun ); + return; + } + void KTProcessorToolbox::StartMultiThreadedRun() + { + auto multiThreadRun = [&]() { - auto multiThreadRun = [&]() + try { - try + // reset the continue signaler + fContinueSignaler = boost::promise< void >(); + fMasterContSignal = fContinueSignaler.get_future().share(); + if( ! fMasterContSignal.valid() ) { - // reset the continue signaler - fContinueSignaler = boost::promise< void >(); - fMasterContSignal = fContinueSignaler.get_future().share(); - if( ! fMasterContSignal.valid() ) - { - KTERROR( proclog, "Invalid master continue-signal created" ); - throw KTException() << "Invalid master continue-signal created"; - } - // copy for use in this function - boost::shared_future< void > continueSignal = fMasterContSignal; + KTERROR( proclog, "Invalid master continue-signal created" ); + throw KTException() << "Invalid master continue-signal created"; + } + // copy for use in this function + boost::shared_future< void > continueSignal = fMasterContSignal; - KTPROG( proclog, "Starting multi-threaded processing" ); + KTPROG( proclog, "Starting multi-threaded processing" ); - for (RunQueue::iterator rqIter = fRunQueue.begin(); rqIter != fRunQueue.end(); ++rqIter) - { - boost::thread_group threads; + for (RunQueue::iterator rqIter = fRunQueue.begin(); rqIter != fRunQueue.end(); ++rqIter) + { + boost::thread_group threads; + + { // scope for threadFuturesLock + boost::unique_lock< boost::mutex > threadFuturesLock( fThreadFuturesMutex ); for (ThreadGroup::iterator tgIter = rqIter->begin(); tgIter != rqIter->end(); ++tgIter) { std::string procName( tgIter->fName ); KTINFO( proclog, "Starting processor <" << procName << ">" ); - KTThreadReference thisThreadRef; - - fThreadFutures.push_back( std::move( thisThreadRef.fDataPtrRet.get_future() ) ); - fThreadNames.push_back( procName ); + //KTThreadReference thisThreadRef; + std::shared_ptr< KTThreadReference > thisThreadRef = std::make_shared< KTThreadReference >(); + thisThreadRef->fName = procName; - if( ! fThreadFutures.back().valid() ) - { - KTERROR( proclog, "Invalid thread future created" ); - throw KTException() << "Invalid thread future created"; - } + //fThreadFutures.push_back( std::move( thisThreadRef.fDataPtrRet.get_future() ) ); + //fThreadNames.push_back( procName ); - fThreadIndicators.emplace_back( new KTThreadIndicator() ); - fThreadIndicators.back()->fContinueSignal = fMasterContSignal; - - thisThreadRef.fThreadIndicator = fThreadIndicators.back(); - thisThreadRef.fInitiateBreakFunc = [&](){ this->InitiateBreak(); }; - thisThreadRef.fRefreshFutureFunc = [&]( const std::string& name, Future&& ret ){ this->TakeFuture( name, std::move(ret) ); }; + //fThreadIndicators.emplace_back( new KTThreadIndicator() ); + //fThreadIndicators.back()->fContinueSignal = fMasterContSignal; + thisThreadRef->fContinueSignal = fMasterContSignal; + //thisThreadRef->fThreadIndicator = fThreadIndicators.back(); + thisThreadRef->fInitiateBreakFunc = [&](){ this->InitiateBreak(); }; + //thisThreadRef->fRefreshFutureFunc = [&]( const std::string& name, Future&& ret ){ this->TakeFuture( name, std::move(ret) ); }; boost::condition_variable threadStartedCV; boost::mutex threadStartedMutex; bool threadStartedFlag = false; + fThreadReferences.push_back( thisThreadRef ); + boost::unique_lock< boost::mutex > threadStartedLock( threadStartedMutex ); - boost::thread* thisThread = new boost::thread( [&](){ tgIter->fProc->operator()( std::move( thisThreadRef ), threadStartedCV, threadStartedFlag ); } ); + boost::thread* thisThread = new boost::thread( [&](){ tgIter->fProc->operator()( thisThreadRef, threadStartedCV, threadStartedFlag ); } ); KTDEBUG( proclog, "Thread ID is <" << thisThread->get_id() << ">; waiting for thread start" ); while( ! threadStartedFlag ) { @@ -761,85 +792,116 @@ namespace Nymph threads.add_thread( thisThread ); }// end for loop over the thread group + } // end scope for threadFuturesLock - bool stillRunning = true; // determines behavior that depends on whether a return from the thread was temporary or from the thread completing - do + bool stillRunning = true; // determines behavior that depends on whether a return from the thread was temporary or from the thread completing + do + { + boost::unique_lock< boost::mutex > threadFuturesLock( fThreadFuturesMutex ); + //KTThreadRefFutureIterator finishedFuturePtr( fThreadReferences.begin()); + //auto finishedFuturePtr = boost::wait_for_any( futureIndex.begin(), futureIndex.end() ); + //auto finishedFuturePtr = boost::wait_for_any( fThreadFutures.begin(), fThreadFutures.end() ); + auto finishedFuturePtr = boost::wait_for_any( KTThreadRefFutureIterator(fThreadReferences.begin()), KTThreadRefFutureIterator(fThreadReferences.end()) ); + size_t iThread = finishedFuturePtr - KTThreadRefFutureIterator(fThreadReferences.begin()); + auto finishedReferencePtr = fThreadReferences.begin() + iThread; + std::string threadName( (*finishedReferencePtr)->fName ); + //KTDEBUG( proclog, "Thread <" << iThread << " (" << threadName << ") > has stopped for some reason" ); + KTWARN( proclog, "Thread <" << iThread << " (" << threadName << ") > has stopped for some reason" ); // TODO: swtich this back to DEBUG + + stillRunning = false; + if( fDoRunBreakFlag ) { - boost::unique_lock< boost::mutex > threadFuturesLock( fThreadFuturesMutex ); - //auto finishedFuturePtr = boost::wait_for_any( futureIndex.begin(), futureIndex.end() ); - auto finishedFuturePtr = boost::wait_for_any( fThreadFutures.begin(), fThreadFutures.end() ); - size_t iThread = finishedFuturePtr - fThreadFutures.begin(); - std::string threadName( fThreadNames[iThread] ); - - stillRunning = false; - if( fDoRunBreakFlag ) + // a breakpoint has been reached + //KTDEBUG( proclog, "Breakpoint reached (seen first in thread <" << threadName << ">; may not be where breakpoint is set)" ); + KTWARN( proclog, "Breakpoint reached (seen first in thread <" << threadName << ">; may not be where breakpoint is set)" ); //TODO: switch this back to debug + threadFuturesLock.unlock(); + // wait here for the user to continue + continueSignal.wait(); + KTDEBUG( proclog, "Breakpoint finished" ); + boost::unique_lock< boost::mutex > breakContLock( fBreakContMutex ); + stillRunning = true; + continueSignal = fMasterContSignal; // refresh the local copy of the shared future + } + else + { + // we're finished a thread; get its results + try { - // a breakpoint has been reached - threadFuturesLock.unlock(); - KTDEBUG( proclog, "Breakpoint reached (seen first in thread <" << threadName << ">; may not be where breakpoint is set)" ); - continueSignal.wait(); - KTDEBUG( proclog, "Breakpoint finished" ); - boost::unique_lock< boost::mutex > breakContLock( fBreakContMutex ); - stillRunning = true; - continueSignal = fMasterContSignal; // refresh the local copy of the shared future + //futureIndex.modify( finishedFuturePtr, [](LabeledFuture& lFuture){ lFuture.fFuture.get(); } ); + //KTINFO( proclog, "Thread <" << threadName << "> has finished" ); + KTWARN( proclog, "Thread <" << threadName << "> has finished" ); // TODO: switch this back to INFO + finishedFuturePtr->get(); + fThreadReferences.erase( finishedReferencePtr ); + //fThreadFutures.erase( finishedFuturePtr ); + //fThreadNames.erase( fThreadNames.begin() + iThread ); } - else + catch( boost::exception& e ) { - // we're finished a thread; get its results - try - { - //futureIndex.modify( finishedFuturePtr, [](LabeledFuture& lFuture){ lFuture.fFuture.get(); } ); - finishedFuturePtr->get(); - KTINFO( proclog, "Thread <" << threadName << "> has finished" ); - fThreadFutures.erase( finishedFuturePtr ); - fThreadNames.erase( fThreadNames.begin() + iThread ); - } - catch( std::exception& e ) - { - KTERROR( proclog, "Thread <" << threadName << "> threw an error: " << e.what() ); - // this transfers an exception thrown by a processor to the outer catch block in this function - throw KTException() << "An error occurred while running processor <" << threadName << ">: " << e.what(); - } - - if( fThreadFutures.empty() ) stillRunning = false; - else stillRunning = true; + KTERROR( proclog, "Thread <" << threadName << "> threw an error: " << diagnostic_information( e ) ); + // this transfers an exception thrown by a processor to the outer catch block in this function + throw KTException() << "An error occurred while running processor <" << threadName << ">: " << diagnostic_information( e ); } - } while( stillRunning ); - - KTDEBUG( proclog, "Joining threads" ); - threads.join_all(); - fThreadIndicators.clear(); - boost::unique_lock< boost::mutex > threadFuturesLock( fThreadFuturesMutex ); - fThreadFutures.clear(); - fThreadNames.clear(); - } // end for loop over the run-queue - KTPROG( proclog, "Processing is complete (multi-threaded)" ); - } - catch( std::exception& e ) - { - // exceptions thrown in this function or from within processors will end up here - KTDEBUG( proclog, "Caught exception thrown in a processor or in the multi-threaded run function: " << e.what() ); - fDoRunPromise.set_exception( std::current_exception() ); - } - fDoRunPromise.set_value(); + if( fThreadReferences.empty() ) stillRunning = false; + else stillRunning = true; + } + } while( stillRunning ); + + KTDEBUG( proclog, "Joining threads" ); + threads.join_all(); + //fThreadIndicators.clear(); + boost::unique_lock< boost::mutex > threadFuturesLock( fThreadFuturesMutex ); + fThreadReferences.clear(); + //fThreadFutures.clear(); + //fThreadNames.clear(); + } // end for loop over the run-queue + + KTPROG( proclog, "Processing is complete (multi-threaded)" ); + } + catch( std::exception& e ) + { + // exceptions thrown in this function or from within processors will end up here + KTERROR( proclog, "Caught std::exception thrown in a processor or in the multi-threaded run function: " << e.what() ); + KTWARN( proclog, "Setting boost::exception of do-run-promise in StartMultiThreadedRun" ); + fDoRunPromise.set_exception( boost::current_exception() ); return; - }; - - fDoRunThread = new boost::thread( multiThreadRun ); - } + } + catch( boost::exception& e ) + { + // exceptions thrown in this function or from within processors will end up here + KTERROR( proclog, "Caught std::exception thrown in a processor or in the multi-threaded run function: " << diagnostic_information( e ) ); + KTWARN( proclog, "Setting boost::exception of do-run-promise in StartMultiThreadedRun" ); + fDoRunPromise.set_exception( boost::current_exception() ); + return; + } + KTWARN( proclog, "Setting value of do-run-promise in StartMultiThreadedRun" ); + fDoRunPromise.set_value(); + return; + }; // end multi-threaded run lambda + fDoRunThread = new boost::thread( multiThreadRun ); return; } + bool KTProcessorToolbox::WaitForBreak() { + boost::unique_lock< boost::mutex > breakContLock( fBreakContMutex ); + + if( fDoRunBreakFlag ) + { + KTWARN( proclog, "Can't wait for a break; Already at a breakpoint" ); + return true; + } + boost::shared_future< void > doRunFuture = fDoRunFuture; if( ! doRunFuture.valid() ) { throw KTException() << "Cannot wait for a break in the current state (the \"DoRun\" future does not have a valid shared state)"; } + breakContLock.unlock(); + doRunFuture.wait(); if( fDoRunBreakFlag ) @@ -850,7 +912,7 @@ namespace Nymph try { - doRunFuture.get(); + doRunFuture.get(); // TODO: do we really need this? NSO, 5/23/17 KTDEBUG( proclog, "End-of-run reached (the wait-for-break is over)" ); return false; } @@ -893,13 +955,14 @@ namespace Nymph boost::unique_lock< boost::mutex > threadFuturesLock( fThreadFuturesMutex ); // futures have been used; clear them to be replaced - fThreadFutures.clear(); + //fThreadFutures.clear(); // reset all break flags fDoRunBreakFlag = false; - for( auto tiIt = fThreadIndicators.begin(); tiIt != fThreadIndicators.end(); ++tiIt ) + for( auto tiIt = fThreadReferences.begin(); tiIt != fThreadReferences.end(); ++tiIt ) { (*tiIt)->fBreakFlag = false; + (*tiIt)->RefreshDataPtrRet(); } // reset the do-run promise and future @@ -908,13 +971,14 @@ namespace Nymph KTINFO( proclog, "Continuing from breakpoint" ); // signal everything to resume + KTWARN( proclog, "Setting value of continue-signaler promise" ); fContinueSignaler.set_value(); // reset the signaler and all signals // hopefully the delay of creating the new signaler and starting the for loop is enough that anything waiting on the old signal has already seen that signal and moved on fContinueSignaler = boost::promise< void >(); fMasterContSignal = fContinueSignaler.get_future().share(); - for( auto tiIt = fThreadIndicators.begin(); tiIt != fThreadIndicators.end(); ++tiIt ) + for( auto tiIt = fThreadReferences.begin(); tiIt != fThreadReferences.end(); ++tiIt ) { (*tiIt)->fContinueSignal = fMasterContSignal; } @@ -926,41 +990,36 @@ namespace Nymph { boost::unique_lock< boost::mutex > threadFuturesLock( fThreadFuturesMutex ); - auto tnIt = fThreadNames.begin(); - for( ; tnIt != fThreadNames.end(); ++tnIt ) + auto tnIt = fThreadReferences.begin(); + for( ; tnIt != fThreadReferences.end(); ++tnIt ) { - if( *tnIt == threadName ) break; + if( (*tnIt)->fName == threadName ) break; } - if( tnIt == fThreadNames.end() ) + if( tnIt == fThreadReferences.end() ) { KTWARN( proclog, "Did not find thread <" << threadName << ">" ); throw KTException() << "Did not find thread <" << threadName << ">" ; } - size_t iThread = tnIt - fThreadNames.begin(); - if( iThread >= fThreadFutures.size() ) - { - KTERROR( proclog, "Thread futures and thread names are unsynchronized" ); - throw KTException() << "Thread futures and thread names are unsynchronized; found thread name <" << threadName << "> at position <" << iThread << ">, but there are only <" << fThreadFutures.size() << "> futures."; - } - - return fThreadFutures[ iThread ].get(); + return (*tnIt)->fDataPtrRetFuture.get(); } void KTProcessorToolbox::InitiateBreak() { boost::unique_lock< boost::mutex > breakContLock( fBreakContMutex ); + if( fDoRunBreakFlag ) return; // set all break flags // master break flag fDoRunBreakFlag = true; // thread break flags - for( auto tiIt = fThreadIndicators.begin(); tiIt != fThreadIndicators.end(); ++tiIt ) + for( auto tiIt = fThreadReferences.begin(); tiIt != fThreadReferences.end(); ++tiIt ) { (*tiIt)->fBreakFlag = true; } // use the do-run promise to signal the break + KTWARN( proclog, "Setting value of do-run-promise" ); fDoRunPromise.set_value(); return; @@ -969,7 +1028,7 @@ namespace Nymph void KTProcessorToolbox::CancelThreads() { boost::unique_lock< boost::mutex > breakContLock( fBreakContMutex ); - for( auto tiIt = fThreadIndicators.begin(); tiIt != fThreadIndicators.end(); ++tiIt ) + for( auto tiIt = fThreadReferences.begin(); tiIt != fThreadReferences.end(); ++tiIt ) { (*tiIt)->fCanceled = true; } diff --git a/Library/Application/KTProcessorToolbox.hh b/Library/Application/KTProcessorToolbox.hh index f9bc967..dfebeae 100644 --- a/Library/Application/KTProcessorToolbox.hh +++ b/Library/Application/KTProcessorToolbox.hh @@ -20,6 +20,10 @@ #include #include +#include +#include +#include + #include #include #include @@ -228,20 +232,25 @@ namespace Nymph typedef boost::shared_future< KTDataPtr > Future; + void StartSingleThreadedRun(); + void StartMultiThreadedRun(); + // called from ThreadPacket::Break void InitiateBreak(); // called from ThreadPacket::Break - void TakeFuture( const std::string& name, Future&& future ); + //void TakeFuture( const std::string& name, Future&& future ); + + std::vector< std::shared_ptr< KTThreadReference > > fThreadReferences; - typedef std::vector< Future > ThreadFutures; - typedef std::vector< std::string > ThreadNames; + //typedef std::vector< Future > ThreadFutures; + //typedef std::vector< std::string > ThreadNames; - ThreadFutures fThreadFutures; - ThreadNames fThreadNames; + //ThreadFutures fThreadFutures; + //ThreadNames fThreadNames; boost::mutex fThreadFuturesMutex; - typedef std::vector< std::shared_ptr< KTThreadIndicator > > ThreadIndicators; - ThreadIndicators fThreadIndicators; + //typedef std::vector< std::shared_ptr< KTThreadIndicator > > ThreadIndicators; + //ThreadIndicators fThreadIndicators; boost::promise< void > fContinueSignaler; boost::shared_future< void > fMasterContSignal; @@ -254,6 +263,40 @@ namespace Nymph }; + template< class Value, class IIterator > + class KTThreadRefFutureIter : public boost::iterator_adaptor< KTThreadRefFutureIter< Value, IIterator >, IIterator, Value, boost::random_access_traversal_tag > + { + private: + // used for the conversion constructor below + struct enabler {}; + + public: + KTThreadRefFutureIter() : + KTThreadRefFutureIter::iterator_adaptor_() + {} + KTThreadRefFutureIter( const IIterator& other ) : + KTThreadRefFutureIter::iterator_adaptor_( other ) + {} + + // converts from Iterator to ConstIterator, but the enable_if business prevents converting from ConstIterator to Iterator + template< class OtherValue, class OtherIIterator > + KTThreadRefFutureIter( const KTThreadRefFutureIter< OtherValue, OtherIIterator > & other, typename boost::enable_if< boost::is_convertible< OtherValue, Value >, enabler >::type = enabler() ) : + KTThreadRefFutureIter::iterator_adaptor_( other.base ) + {} + + private: + friend class boost::iterator_core_access; + + Value& dereference() const + { + return (*(this->base_reference()))->fDataPtrRetFuture; + } + }; + + typedef KTThreadRefFutureIter< boost::unique_future< KTDataPtr >, std::vector< std::shared_ptr< KTThreadReference > >::iterator > KTThreadRefFutureIterator; + typedef KTThreadRefFutureIter< const boost::unique_future< KTDataPtr >, std::vector< std::shared_ptr< KTThreadReference > >::const_iterator > KTThreadRefFutureConstIterator; + + inline void KTProcessorToolbox::PopBackOfRunQueue() { fRunQueue.pop_back(); @@ -272,12 +315,12 @@ namespace Nymph return; } - inline void KTProcessorToolbox::TakeFuture( const std::string& name, Future&& future ) - { - fThreadFutures.push_back( std::move( future ) ); - fThreadNames.push_back( name ); - return; - } + //inline void KTProcessorToolbox::TakeFuture( const std::string& name, Future&& future ) + //{ + // fThreadFutures.push_back( std::move( future ) ); + // fThreadNames.push_back( name ); + // return; + //} inline void KTProcessorToolbox::JoinRunThread() { diff --git a/Library/Data/KTApplyCut.cc b/Library/Data/KTApplyCut.cc index 3907a42..a4535ea 100644 --- a/Library/Data/KTApplyCut.cc +++ b/Library/Data/KTApplyCut.cc @@ -85,7 +85,7 @@ namespace Nymph void KTApplyCut::ApplyCut(KTDataPtr dataPtr) { - KTThreadReference* ref = fApplyCutSW->GetThreadRef(); + std::shared_ptr< KTThreadReference > ref = fApplyCutSW->GetThreadRef(); if (fCut == NULL) { diff --git a/Library/Data/KTCutFilter.cc b/Library/Data/KTCutFilter.cc index 7104a8b..af4fcb1 100644 --- a/Library/Data/KTCutFilter.cc +++ b/Library/Data/KTCutFilter.cc @@ -76,7 +76,7 @@ namespace Nymph void KTCutFilter::FilterData(KTDataPtr dataPtr) { - KTThreadReference* ref = fFilterDataSW->GetThreadRef(); + std::shared_ptr< KTThreadReference > ref = fFilterDataSW->GetThreadRef(); // all KTDataPtr's have KTData, so we won't bother checking diff --git a/Library/Processor/KTPrimaryProcessor.cc b/Library/Processor/KTPrimaryProcessor.cc index dda0ad4..cfce927 100644 --- a/Library/Processor/KTPrimaryProcessor.cc +++ b/Library/Processor/KTPrimaryProcessor.cc @@ -27,9 +27,9 @@ namespace Nymph { } - void KTPrimaryProcessor::operator ()( KTThreadReference&& ref, boost::condition_variable& startedCV, bool& startedFlag ) + void KTPrimaryProcessor::operator ()( std::shared_ptr< KTThreadReference > ref, boost::condition_variable& startedCV, bool& startedFlag ) { - fThreadRef = std::move( ref ); + fThreadRef = ref; // pass updated thread reference to downstream slots for( auto sigIt = fSignalsEmitted.begin(); sigIt != fSignalsEmitted.end(); ++sigIt ) @@ -39,7 +39,7 @@ namespace Nymph for( SigConnMapCIt sigConnIt = sigConnRange.first; sigConnIt != sigConnRange.second; ++sigConnIt ) { // pass the update on to the connected-to processor - sigConnIt->second.first->PassThreadRefUpdate( sigConnIt->second.second, &fThreadRef ); + sigConnIt->second.first->PassThreadRefUpdate( sigConnIt->second.second, fThreadRef ); } } @@ -52,16 +52,16 @@ namespace Nymph if( ! Run() ) { KTERROR( proclog, "An error occurred during processor running." ); - THROW_RETURN_EXCEPTION( fThreadRef.fDataPtrRet, KTException() << "An error occurred during processor running" ); + THROW_RETURN_EXCEPTION( fThreadRef->fDataPtrRet, KTException() << "An error occurred during processor running" ); } else { - fThreadRef.fDataPtrRet.set_value( KTDataPtr() ); + fThreadRef->fDataPtrRet.set_value( KTDataPtr() ); } } catch( ... ) { - fThreadRef.fDataPtrRet.set_exception( std::current_exception() ); + fThreadRef->fDataPtrRet.set_exception( std::current_exception() ); } return; } diff --git a/Library/Processor/KTPrimaryProcessor.hh b/Library/Processor/KTPrimaryProcessor.hh index b470303..2367e4d 100644 --- a/Library/Processor/KTPrimaryProcessor.hh +++ b/Library/Processor/KTPrimaryProcessor.hh @@ -28,25 +28,25 @@ namespace Nymph public: /// Callable function used by std::thread - void operator()( KTThreadReference&& ref, boost::condition_variable& startedCV, bool& startedFlag ); + void operator()( std::shared_ptr< KTThreadReference > ref, boost::condition_variable& startedCV, bool& startedFlag ); /// Starts the main action of the processor virtual bool Run() = 0; - KTThreadReference* GetThreadRef(); + std::shared_ptr< KTThreadReference > GetThreadRef(); MEMBERVARIABLE( bool, DoBreakpoint ); protected: std::vector< std::string > fSignalsEmitted; - KTThreadReference fThreadRef; + std::shared_ptr< KTThreadReference > fThreadRef; }; - inline KTThreadReference* KTPrimaryProcessor::GetThreadRef() + inline std::shared_ptr< KTThreadReference > KTPrimaryProcessor::GetThreadRef() { - return &fThreadRef; + return fThreadRef; } } /* namespace Nymph */ diff --git a/Library/Processor/KTProcessor.cc b/Library/Processor/KTProcessor.cc index cee44ed..c8df746 100644 --- a/Library/Processor/KTProcessor.cc +++ b/Library/Processor/KTProcessor.cc @@ -45,9 +45,9 @@ namespace Nymph } } - void KTProcessor::PassThreadRefUpdate(const std::string& slotName, KTThreadReference* threadRef) + void KTProcessor::PassThreadRefUpdate(const std::string& slotName, std::shared_ptr< KTThreadReference > threadRef) { - std::function< void(KTThreadReference*) > funcObj = [this, &slotName](KTThreadReference* ref){ GetSlot(slotName)->SetThreadRef(ref); }; + std::function< void(std::shared_ptr< KTThreadReference >) > funcObj = [this, &slotName](std::shared_ptr< KTThreadReference > ref){ GetSlot(slotName)->SetThreadRef(ref); }; PassToConnProcs(slotName, funcObj, threadRef); return; } diff --git a/Library/Processor/KTProcessor.hh b/Library/Processor/KTProcessor.hh index 735c863..c4365e0 100644 --- a/Library/Processor/KTProcessor.hh +++ b/Library/Processor/KTProcessor.hh @@ -68,7 +68,7 @@ namespace Nymph public: /// For a slot that is called, update the slot's ThreadRef, and pass the update to any slots that get called by signals emitted by this slot - void PassThreadRefUpdate(const std::string& slotName, KTThreadReference* threadRef); + void PassThreadRefUpdate(const std::string& slotName, std::shared_ptr< KTThreadReference > threadRef); void ConnectASlot(const std::string& signalName, KTProcessor* processor, const std::string& slotName, int groupNum=-1); void ConnectASignal(KTProcessor* processor, const std::string& signalName, const std::string& slotName, int groupNum=-1); diff --git a/Library/Processor/KTSlot.hh b/Library/Processor/KTSlot.hh index ac43597..6019dae 100644 --- a/Library/Processor/KTSlot.hh +++ b/Library/Processor/KTSlot.hh @@ -269,7 +269,7 @@ namespace Nymph { // Standard data slot pattern: - KTThreadReference* ref = fSlotWrapper->GetThreadRef(); + std::shared_ptr< KTThreadReference > ref = fSlotWrapper->GetThreadRef(); // Check to ensure that the required data type is present if( ! DataPresent< XDataTypes... >( dataPtr ) ) diff --git a/Library/Processor/KTSlotWrapper.hh b/Library/Processor/KTSlotWrapper.hh index 329619b..158316b 100644 --- a/Library/Processor/KTSlotWrapper.hh +++ b/Library/Processor/KTSlotWrapper.hh @@ -88,14 +88,14 @@ namespace Nymph KTConnection fConnection; public: - KTThreadReference* GetThreadRef() const; - void SetThreadRef(KTThreadReference* ref); + std::shared_ptr< KTThreadReference > GetThreadRef() const; + void SetThreadRef(std::shared_ptr< KTThreadReference > ref); bool GetDoBreakpoint() const; void SetDoBreakpoint(bool flag); private: - KTThreadReference* fThreadRef; + std::shared_ptr< KTThreadReference > fThreadRef; bool fDoBreakpoint; }; @@ -126,12 +126,12 @@ namespace Nymph return; } - inline KTThreadReference* KTSlotWrapper::GetThreadRef() const + inline std::shared_ptr< KTThreadReference > KTSlotWrapper::GetThreadRef() const { return fThreadRef; } - inline void KTSlotWrapper::SetThreadRef(KTThreadReference* ref) + inline void KTSlotWrapper::SetThreadRef(std::shared_ptr< KTThreadReference > ref) { fThreadRef = ref; return; diff --git a/Library/Processor/KTThreadReference.cc b/Library/Processor/KTThreadReference.cc index f439320..5d3a17f 100644 --- a/Library/Processor/KTThreadReference.cc +++ b/Library/Processor/KTThreadReference.cc @@ -7,45 +7,71 @@ #include "KTThreadReference.hh" +#include "KTException.hh" #include "KTLogger.hh" KTLOGGER( trlog, "KTThreadReference" ); namespace Nymph { - KTThreadIndicator::KTThreadIndicator() : - fBreakFlag( false ), - fContinueSignal(), - fCanceled( false ) - {} + //KTThreadIndicator::KTThreadIndicator() : + // fBreakFlag( false ), + // fContinueSignal(), + // fCanceled( false ) + //{} KTThreadReference::KTThreadReference() : + fName(), fDataPtrRet(), + fDataPtrRetFuture( fDataPtrRet.get_future() ), fInitiateBreakFunc( [](){return;} ), fRefreshFutureFunc( [](const std::string&, boost::shared_future< KTDataPtr >&&){return;} ), - fThreadIndicator( new KTThreadIndicator() ), + //fThreadIndicator( new KTThreadIndicator() ), + fBreakFlag( false ), + fContinueSignal(), + fCanceled( false ), fPrimaryProcName() - {} + { + if( ! fDataPtrRetFuture.valid() ) + { + KTERROR( trlog, "Invalid data-pointer-return future created" ); + throw KTException() << "Invalid data-pointer-return future created"; + } + } KTThreadReference::KTThreadReference( KTThreadReference&& orig ) : + fName( std::move( orig.fName ) ), fDataPtrRet( std::move( orig.fDataPtrRet ) ), + fDataPtrRetFuture( std::move( orig.fDataPtrRetFuture ) ), fInitiateBreakFunc( std::move( orig.fInitiateBreakFunc ) ), fRefreshFutureFunc( std::move( orig.fRefreshFutureFunc ) ), - fThreadIndicator( orig.fThreadIndicator ), + //fThreadIndicator( orig.fThreadIndicator ), + fBreakFlag( orig.fBreakFlag ), + fContinueSignal( std::move( orig.fContinueSignal ) ), + fCanceled( orig.fCanceled ), fPrimaryProcName( std::move( orig.fPrimaryProcName ) ) { - orig.fThreadIndicator = nullptr; + //orig.fThreadIndicator = nullptr; + orig.fBreakFlag = false; + orig.fCanceled = false; } KTThreadReference& KTThreadReference::operator=( KTThreadReference&& orig ) { + fName = std::move( orig.fName ); fDataPtrRet = std::move( orig.fDataPtrRet ); + fDataPtrRetFuture = std::move( orig.fDataPtrRetFuture ); fInitiateBreakFunc = std::move( orig.fInitiateBreakFunc ); fRefreshFutureFunc = std::move( orig.fRefreshFutureFunc ); - fThreadIndicator = orig.fThreadIndicator; + //fThreadIndicator = orig.fThreadIndicator; + fBreakFlag = orig.fBreakFlag; + fContinueSignal = std::move( orig.fContinueSignal ); + fCanceled = orig.fCanceled; fPrimaryProcName = std::move( orig.fPrimaryProcName ); - orig.fThreadIndicator = nullptr; + //orig.fThreadIndicator = nullptr; + orig.fBreakFlag = false; + orig.fCanceled = false; return *this; } @@ -54,22 +80,31 @@ namespace Nymph { if( doBreakpoint ) { - KTDEBUG( trlog, "Initiating break" ); + KTDEBUG( trlog, "Initiating break (" << fName << ")" ); fInitiateBreakFunc(); } - if( fThreadIndicator->fBreakFlag || doBreakpoint ) + if( fBreakFlag || doBreakpoint ) { - KTDEBUG( trlog, "Reacting to break" ); + KTDEBUG( trlog, "Reacting to break (" << fName << ")" ); // set the return for this thread + KTWARN( trlog, "Setting value of data-ptr-ret promise (" << fName << ")" ); fDataPtrRet.set_value( dataPtr ); // wait for continue signal - fThreadIndicator->fContinueSignal.wait(); + //fThreadIndicator->fContinueSignal.wait(); + fContinueSignal.wait(); // reset the promise - fDataPtrRet = KTDataPtrReturn(); + //fDataPtrRet = KTDataPtrReturn(); // pass the future back to the processor toolbox (if it's in use) - fRefreshFutureFunc( fPrimaryProcName, std::move( fDataPtrRet.get_future().share() ) ); + //fRefreshFutureFunc( fPrimaryProcName, std::move( fDataPtrRet.get_future().share() ) ); } return; } + void KTThreadReference::RefreshDataPtrRet() + { + fDataPtrRet = KTDataPtrReturn(); + fDataPtrRetFuture = fDataPtrRet.get_future(); + return; + } + } /* namespace Nymph */ diff --git a/Library/Processor/KTThreadReference.hh b/Library/Processor/KTThreadReference.hh index c77a175..5e1be14 100644 --- a/Library/Processor/KTThreadReference.hh +++ b/Library/Processor/KTThreadReference.hh @@ -16,20 +16,25 @@ namespace Nymph { - struct KTThreadIndicator - { - bool fBreakFlag; // only use outside of blocks protected by a mutex are reads, so we shouldn't need to make this an atomic - boost::shared_future< void > fContinueSignal; - bool fCanceled; - KTThreadIndicator(); - }; + //struct KTThreadIndicator + //{ + // bool fBreakFlag; // only use outside of blocks protected by a mutex are reads, so we shouldn't need to make this an atomic + // boost::shared_future< void > fContinueSignal; + // bool fCanceled; + // KTThreadIndicator(); + //}; struct KTThreadReference { + std::string fName; KTDataPtrReturn fDataPtrRet; + boost::unique_future< KTDataPtr > fDataPtrRetFuture; std::function< void() > fInitiateBreakFunc; std::function< void(const std::string&, boost::shared_future< KTDataPtr >&&) > fRefreshFutureFunc; - std::shared_ptr< KTThreadIndicator > fThreadIndicator; + //std::shared_ptr< KTThreadIndicator > fThreadIndicator; + bool fBreakFlag; // only use outside of blocks protected by a mutex are reads, so we shouldn't need to make this an atomic + boost::shared_future< void > fContinueSignal; + bool fCanceled; std::string fPrimaryProcName; KTThreadReference(); @@ -40,6 +45,8 @@ namespace Nymph KTThreadReference& operator=( KTThreadReference&& ); void Break( const KTDataPtr& dataPtr, bool doBreakpoint ); + + void RefreshDataPtrRet(); }; } /* namespace Nymph */ From 229b1adea428e3013bbd62f3213c75e7090ac058 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Thu, 25 May 2017 14:39:07 -0700 Subject: [PATCH 041/521] Massively-improved exception handling --- Executables/Validation/KTTestProcessor.cc | 2 +- Executables/Validation/TestExceptionInSlot.cc | 102 +++++++++--------- .../Validation/TestPrimaryProcessor.cc | 89 ++++++++------- .../TestPrimaryProcessorNoThreading.cc | 30 +++--- .../TestProcessorToolbox2Threads.cc | 5 - .../TestProcessorToolboxMultithreaded.cc | 5 - .../TestProcessorToolboxSinglethreaded.cc | 5 - Executables/Validation/TestSignalsAndSlots.cc | 48 ++++----- Executables/Validation/TestUseBreakpoint.cc | 4 - Library/Application/KTApplication.cc | 6 +- Library/Application/KTCommandLineHandler.cc | 6 +- Library/Application/KTCommandLineHandler.hh | 11 +- Library/Application/KTConfigurator.hh | 2 +- Library/Application/KTProcessorToolbox.cc | 91 ++++++++-------- Library/Application/KTProcessorToolbox.hh | 3 +- Library/Processor/KTProcessor.cc | 46 ++++---- Library/Processor/KTProcessor.hh | 10 +- Library/Processor/KTSignalWrapper.cc | 3 - Library/Processor/KTSignalWrapper.hh | 6 -- Library/Processor/KTSlotWrapper.cc | 7 +- Library/Processor/KTSlotWrapper.hh | 12 +-- Library/Processor/KTThreadReference.cc | 2 +- Library/Utility/KTException.cc | 15 ++- Library/Utility/KTException.hh | 83 ++++++++++++-- 24 files changed, 315 insertions(+), 278 deletions(-) diff --git a/Executables/Validation/KTTestProcessor.cc b/Executables/Validation/KTTestProcessor.cc index 5401600..20a169a 100644 --- a/Executables/Validation/KTTestProcessor.cc +++ b/Executables/Validation/KTTestProcessor.cc @@ -95,7 +95,7 @@ namespace Nymph std::shared_ptr< KTThreadReference > ref = fSlot1.GetSlotWrapper()->GetThreadRef(); KTINFO(testsiglog, "Slot1: input is " << input); - throw KTException() << "A HUGE problem occurred!!!! (just kidding, this is the expected result)"; + BOOST_THROW_EXCEPTION( KTException() << "A HUGE problem occurred!!!! (just kidding, this is the expected result)" << eom ); return; } diff --git a/Executables/Validation/TestExceptionInSlot.cc b/Executables/Validation/TestExceptionInSlot.cc index 6944424..f036428 100644 --- a/Executables/Validation/TestExceptionInSlot.cc +++ b/Executables/Validation/TestExceptionInSlot.cc @@ -20,76 +20,76 @@ KTLOGGER( testexclog, "TestExceptionInSlot" ) int main() { - KTTestProcessorA tpA; - KTTestProcessorC tpC; - - KTINFO( testexclog, "Connecting the-signal to first-slot" ); try { + KTTestProcessorA tpA; + KTTestProcessorC tpC; + + KTINFO( testexclog, "Connecting the-signal to first-slot" ); tpA.ConnectASlot( "the-signal", &tpC, "first-slot", 20 ); - } - catch( std::exception& e ) - { - KTERROR( testexclog, "A problem occurred while connecting the signal and slots:\n" << e.what() ); - return -1; - } - // setup to execute processors asynchronously - std::shared_ptr< KTThreadReference > exeThreadRef = std::make_shared< KTThreadReference >(); - //boost::shared_future< KTDataPtr > exeThreadFuture = exeThreadRef->fDataPtrRetFuture; - tpC.GetSlot( "first-slot" )->SetThreadRef( exeThreadRef ); + // setup to execute processors asynchronously + std::shared_ptr< KTThreadReference > exeThreadRef = std::make_shared< KTThreadReference >(); + //boost::shared_future< KTDataPtr > exeThreadFuture = exeThreadRef->fDataPtrRetFuture; + tpC.GetSlot( "first-slot" )->SetThreadRef( exeThreadRef ); - std::atomic< bool > canceled( false ); + std::atomic< bool > canceled( false ); - auto exeFunc = [&]() { - try - { - boost::this_thread::sleep_for( boost::chrono::milliseconds(1) ); // delay to let the main thread get to the std::future::wait() call + auto exeFunc = [&]() { + try + { + boost::this_thread::sleep_for( boost::chrono::milliseconds(1) ); // delay to let the main thread get to the std::future::wait() call + + KTINFO( testexclog, "Emitting signals" ); + + if( canceled.load() ) return; + KTINFO( testexclog, "First test signal: 5" ); + tpA.EmitSignals( 5 ); + + boost::this_thread::sleep_for( boost::chrono::milliseconds(1) ); // delay to let the main thread react to the exception - KTINFO( testexclog, "Emitting signals" ); + if( canceled.load() ) return; + KTINFO( testexclog, "Second test signal: 18" ); + tpA.EmitSignals( 18 ); + } + catch( boost::exception& e ) + { + exeThreadRef->fDataPtrRet.set_exception( boost::current_exception() ); + } - if( canceled.load() ) return; - KTINFO( testexclog, "First test signal: 5" ); - tpA.EmitSignals( 5 ); + return; + }; - boost::this_thread::sleep_for( boost::chrono::milliseconds(1) ); // delay to let the main thread react to the exception + // run the thread + boost::thread thread( exeFunc ); - if( canceled.load() ) return; - KTINFO( testexclog, "Second test signal: 18" ); - tpA.EmitSignals( 18 ); + // wait for a result to be set + exeThreadRef->fDataPtrRetFuture.wait(); + + try + { + exeThreadRef->fDataPtrRetFuture.get(); } - catch( ... ) + //catch( std::exception& e ) + //{ + // canceled = true; + // KTERROR( testexclog, "An error occurred while running a processor: " << e.what() ); + //} + catch( boost::exception& e ) { - exeThreadRef->fDataPtrRet.set_exception( boost::current_exception() ); + canceled = true; + KTERROR( testexclog, "An error occurred while running a processor: " << diagnostic_information( e ) ); } - return; - }; - - // run the thread - boost::thread thread( exeFunc ); - - // wait for a result to be set - exeThreadRef->fDataPtrRetFuture.wait(); + thread.join(); - try - { - exeThreadRef->fDataPtrRetFuture.get(); + KTINFO( testexclog, "Tests complete" ); } - //catch( std::exception& e ) - //{ - // canceled = true; - // KTERROR( testexclog, "An error occurred while running a processor: " << e.what() ); - //} catch( boost::exception& e ) { - canceled = true; - KTERROR( testexclog, "An error occurred while running a processor: " << diagnostic_information( e ) ); + KTERROR( testexclog, "An unexpected exception was caught: " << diagnostic_information( e ) ); + return -1; } - thread.join(); - - KTINFO( testexclog, "Tests complete" ); - return 0; } diff --git a/Executables/Validation/TestPrimaryProcessor.cc b/Executables/Validation/TestPrimaryProcessor.cc index e549215..219905e 100644 --- a/Executables/Validation/TestPrimaryProcessor.cc +++ b/Executables/Validation/TestPrimaryProcessor.cc @@ -19,61 +19,56 @@ KTLOGGER( testpplog, "TestPrimaryProcessor" ) int main() { - KTTestPrimaryProcessor tpp; - KTTestProcessorB tp; - - KTINFO( testpplog, "Connecting the-signal to first-slot" ); try { - tpp.ConnectASlot( "the-signal", &tp, "first-slot", 20 ); - } - catch( std::exception& e ) - { - KTERROR( testpplog, "A problem occurred while connecting the signal and slots:\n" << e.what() ); - return -1; - } - - // setup to execute processors asynchronously - //KTThreadReference exeThreadRef; - //auto exeThreadFuture = exeThreadRef.fDataPtrRet.get_future(); - std::shared_ptr< KTThreadReference > exeThreadRef = std::make_shared< KTThreadReference >(); - exeThreadRef->fName = std::string( "tpp" ); - - // run the thread - boost::condition_variable threadStartedCV; - boost::mutex threadStartedMutex; - bool threadStartedFlag = false; - - boost::unique_lock< boost::mutex > threadStartedLock( threadStartedMutex ); - boost::thread thread( [&](){ tpp( exeThreadRef, threadStartedCV, threadStartedFlag ); } ); - - while( ! threadStartedFlag ) - { - threadStartedCV.wait( threadStartedLock ); - } - KTDEBUG( testpplog, "Thread has started" ); + KTTestPrimaryProcessor tpp; + KTTestProcessorB tp; - // wait for a result to be set - exeThreadRef->fDataPtrRetFuture.wait(); + KTINFO( testpplog, "Connecting the-signal to first-slot" ); + tpp.ConnectASlot( "the-signal", &tp, "first-slot", 20 ); - try - { - exeThreadRef->fDataPtrRetFuture.get(); - } - catch( std::exception& e ) - { - exeThreadRef->fCanceled = true; - KTERROR( testpplog, "An error occurred while running a processor: " << e.what() ); + // setup to execute processors asynchronously + //KTThreadReference exeThreadRef; + //auto exeThreadFuture = exeThreadRef.fDataPtrRet.get_future(); + std::shared_ptr< KTThreadReference > exeThreadRef = std::make_shared< KTThreadReference >(); + exeThreadRef->fName = std::string( "tpp" ); + + // run the thread + boost::condition_variable threadStartedCV; + boost::mutex threadStartedMutex; + bool threadStartedFlag = false; + + boost::unique_lock< boost::mutex > threadStartedLock( threadStartedMutex ); + boost::thread thread( [&](){ tpp( exeThreadRef, threadStartedCV, threadStartedFlag ); } ); + + while( ! threadStartedFlag ) + { + threadStartedCV.wait( threadStartedLock ); + } + KTDEBUG( testpplog, "Thread has started" ); + + // wait for a result to be set + exeThreadRef->fDataPtrRetFuture.wait(); + + try + { + exeThreadRef->fDataPtrRetFuture.get(); + } + catch( boost::exception& e ) + { + exeThreadRef->fCanceled = true; + KTERROR( testpplog, "An error occurred while running a processor: " << diagnostic_information( e ) ); + } + + thread.join(); + + KTINFO( testpplog, "Tests complete" ); } catch( boost::exception& e ) { - exeThreadRef->fCanceled = true; - KTERROR( testpplog, "An error occurred while running a processor: " << diagnostic_information( e ) ); + KTERROR( testpplog, "Exception caught: " << diagnostic_information( e ) ); + return -1; } - thread.join(); - - KTINFO( testpplog, "Tests complete" ); - return 0; } diff --git a/Executables/Validation/TestPrimaryProcessorNoThreading.cc b/Executables/Validation/TestPrimaryProcessorNoThreading.cc index d35a22f..4ee12de 100644 --- a/Executables/Validation/TestPrimaryProcessorNoThreading.cc +++ b/Executables/Validation/TestPrimaryProcessorNoThreading.cc @@ -17,29 +17,29 @@ KTLOGGER( testpplog, "TestPrimaryProcessorNoThreading" ) int main() { - KTTestPrimaryProcessor tpp; - KTTestProcessorB tp; - - KTINFO( testpplog, "Connecting the-signal to first-slot" ); try { + KTTestPrimaryProcessor tpp; + KTTestProcessorB tp; + + KTINFO( testpplog, "Connecting the-signal to first-slot" ); tpp.ConnectASlot( "the-signal", &tp, "first-slot", 20 ); - } - catch( std::exception& e ) - { - KTERROR( testpplog, "A problem occurred while connecting the signal and slots:\n" << e.what() ); - return -1; - } - KTINFO( testpplog, "Running the primary processor" ) + KTINFO( testpplog, "Running the primary processor" ) + + if( ! tpp.Run() ) + { + KTERROR( testpplog, "Something went wrong while running the primary processor" ); + return -1; + } - if( ! tpp.Run() ) + KTINFO( testpplog, "Tests complete" ); + } + catch( boost::exception& e ) { - KTERROR( testpplog, "Something went wrong while running the primary processor" ); + KTERROR( testpplog, "An unexpected exception was caught: " << diagnostic_information( e ) ); return -1; } - KTINFO( testpplog, "Tests complete" ); - return 0; } diff --git a/Executables/Validation/TestProcessorToolbox2Threads.cc b/Executables/Validation/TestProcessorToolbox2Threads.cc index c43459f..65cb6dd 100644 --- a/Executables/Validation/TestProcessorToolbox2Threads.cc +++ b/Executables/Validation/TestProcessorToolbox2Threads.cc @@ -105,11 +105,6 @@ int main() KTINFO( testptlog, "Tests complete" ); } - catch( std::exception& e ) - { - KTERROR( testptlog, "Exception caught: " << e.what() ); - return -1; - } catch( boost::exception& e ) { KTERROR( testptlog, "Exception caught: " << diagnostic_information( e ) ); diff --git a/Executables/Validation/TestProcessorToolboxMultithreaded.cc b/Executables/Validation/TestProcessorToolboxMultithreaded.cc index 089407c..de583b9 100644 --- a/Executables/Validation/TestProcessorToolboxMultithreaded.cc +++ b/Executables/Validation/TestProcessorToolboxMultithreaded.cc @@ -67,11 +67,6 @@ int main() KTINFO( testptlog, "Tests complete" ); } - catch( std::exception& e ) - { - KTERROR( testptlog, "Exception caught: " << e.what() ); - return -1; - } catch( boost::exception& e ) { KTERROR( testptlog, "Exception caught: " << diagnostic_information( e ) ); diff --git a/Executables/Validation/TestProcessorToolboxSinglethreaded.cc b/Executables/Validation/TestProcessorToolboxSinglethreaded.cc index 65144ab..5e91926 100644 --- a/Executables/Validation/TestProcessorToolboxSinglethreaded.cc +++ b/Executables/Validation/TestProcessorToolboxSinglethreaded.cc @@ -67,11 +67,6 @@ int main() KTINFO( testptlog, "Tests complete" ); } - catch( std::exception& e ) - { - KTERROR( testptlog, "Exception caught: " << e.what() ); - return -1; - } catch( boost::exception& e ) { KTERROR( testptlog, "Exception caught: " << diagnostic_information( e ) ); diff --git a/Executables/Validation/TestSignalsAndSlots.cc b/Executables/Validation/TestSignalsAndSlots.cc index e026364..6d11dd2 100644 --- a/Executables/Validation/TestSignalsAndSlots.cc +++ b/Executables/Validation/TestSignalsAndSlots.cc @@ -15,43 +15,43 @@ KTLOGGER(testsiglog, "TestSignalsAndSlots") int main() { + try + { + KTTestProcessorA tpA; + KTTestProcessorB tpB; - KTTestProcessorA tpA; - KTTestProcessorB tpB; + /* Basic Test + KTSignalWrapper* signalPtr = tpA.GetSignal("the_signal"); + KTSlotWrapper* slot1Ptr = tpB.GetSlot("first_slot"); - /* Basic Test - KTSignalWrapper* signalPtr = tpA.GetSignal("the_signal"); - KTSlotWrapper* slot1Ptr = tpB.GetSlot("first_slot"); + slot1Ptr->SetConnection(signalPtr); - slot1Ptr->SetConnection(signalPtr); + tpA.EmitSignals(5); - tpA.EmitSignals(5); + slot1Ptr->Disconnect(); - slot1Ptr->Disconnect(); + return 0; + */ - return 0; - */ - - /* More Complicated Test */ - KTINFO(testsiglog, "Connecting the-signal to first-slot and second-slot"); - try - { + /* More Complicated Test */ + KTINFO(testsiglog, "Connecting the-signal to first-slot and second-slot"); tpA.ConnectASlot("the-signal", &tpB, "first-slot", 20); tpB.ConnectASignal(&tpA, "the-signal", "second-slot", 10); + + KTINFO(testsiglog, "Emitting signals"); + KTINFO(testsiglog, "First test signal: 5"); + tpA.EmitSignals(5); + KTINFO(testsiglog, "Second test signal: 18"); + tpA.EmitSignals(18); + + KTINFO(testsiglog, "Tests complete"); } - catch(std::exception& e) + catch( boost::exception& e ) { - KTERROR(testsiglog, "A problem occurred while connecting the signal and slots:\n" << e.what()); + KTERROR( testsiglog, "An exception was caught: " << diagnostic_information( e ) ); return -1; } - KTINFO(testsiglog, "Emitting signals"); - KTINFO(testsiglog, "First test signal: 5"); - tpA.EmitSignals(5); - KTINFO(testsiglog, "Second test signal: 18"); - tpA.EmitSignals(18); - - KTINFO(testsiglog, "Tests complete"); return 0; /**/ } diff --git a/Executables/Validation/TestUseBreakpoint.cc b/Executables/Validation/TestUseBreakpoint.cc index 738fd04..e9f76f4 100644 --- a/Executables/Validation/TestUseBreakpoint.cc +++ b/Executables/Validation/TestUseBreakpoint.cc @@ -84,10 +84,6 @@ int main() KTINFO( testptlog, "Tests complete" ); } - catch( std::exception& e ) - { - KTERROR( testptlog, "Caught exception: " << e.what() ); - } catch( boost::exception& e ) { KTERROR( testptlog, "Caught exception: " << diagnostic_information( e ) ); diff --git a/Library/Application/KTApplication.cc b/Library/Application/KTApplication.cc index 0dca130..f573527 100644 --- a/Library/Application/KTApplication.cc +++ b/Library/Application/KTApplication.cc @@ -70,11 +70,11 @@ namespace Nymph scarab::param* configFromFile = translator.read_file( configFilePath.native() ); if( configFromFile == NULL ) { - throw KTException() << "[KTApplication] error parsing config file"; + BOOST_THROW_EXCEPTION( KTException() << "[KTApplication] error parsing config file" << eom ); } if( ! configFromFile->is_node() ) { - throw KTException() << "[KTApplication] configuration file must consist of an object/node"; + BOOST_THROW_EXCEPTION( KTException() << "[KTApplication] configuration file must consist of an object/node" << eom ); } fConfigurator->Merge( configFromFile->as_node() ); delete configFromFile; @@ -87,7 +87,7 @@ namespace Nymph scarab::param* configFromJSON = inputJSON.read_string( clJSON ); if( ! configFromJSON->is_node() ) { - throw KTException() << "[KTApplication] command line json must be an object"; + BOOST_THROW_EXCEPTION( KTException() << "[KTApplication] command line json must be an object" << eom ); } fConfigurator->Merge( configFromJSON->as_node() ); delete configFromJSON; diff --git a/Library/Application/KTCommandLineHandler.cc b/Library/Application/KTCommandLineHandler.cc index 40ea9fc..3e72779 100644 --- a/Library/Application/KTCommandLineHandler.cc +++ b/Library/Application/KTCommandLineHandler.cc @@ -26,10 +26,6 @@ namespace Nymph { KTLOGGER(utillog, "KTCommandLineHandler"); - CommandLineHandlerException::CommandLineHandlerException (std::string const& why) - : std::logic_error(why) - {} - KTCommandLineHandler::KTCommandLineHandler() : fExecutableName("NONE"), fPackageString(STRINGIFY_2(PACKAGE_STRING)), @@ -389,7 +385,7 @@ namespace Nymph { KTERROR(utillog, "Exception caught while performing initial CL parsing:\n" << '\t' << e.what()); - throw std::logic_error(e.what()); + BOOST_THROW_EXCEPTION( KTException() << e.what() << eom ); } // Save the remaining command-line options for later parsing (after the full option list has been populated) fCommandLineParseLater = po::collect_unrecognized(tParsedOpts.options, po::include_positional); diff --git a/Library/Application/KTCommandLineHandler.hh b/Library/Application/KTCommandLineHandler.hh index ed76317..6aca4b9 100644 --- a/Library/Application/KTCommandLineHandler.hh +++ b/Library/Application/KTCommandLineHandler.hh @@ -9,6 +9,7 @@ #ifndef KTCOMMANDLINEHANDLER_H_ #define KTCOMMANDLINEHANDLER_H_ +#include "KTException.hh" #include "KTLogger.hh" #include "param.hh" @@ -19,7 +20,6 @@ namespace po = boost::program_options; #include #include -#include #include #include @@ -27,13 +27,6 @@ namespace Nymph { KTLOGGER(utillog_clh, "KTCommandLineHandler.hh"); - class CommandLineHandlerException : public std::logic_error - { - public: - CommandLineHandlerException(std::string const& why); - }; - - /*! @class KTCommandLineHandler @author N. S. Oblath @@ -287,7 +280,7 @@ namespace Nymph { KTWARN(utillog_clh, "Command line option <" << aCLOption << "> was not set!\n" "Next time check whether it's set before calling this function."); - throw CommandLineHandlerException("Command line option " + aCLOption + " was not set!"); + BOOST_THROW_EXCEPTION( KTException() << "Command line option " + aCLOption + " was not set!" << eom ); } return fCommandLineVarMap[aCLOption].as< XReturnType >(); } diff --git a/Library/Application/KTConfigurator.hh b/Library/Application/KTConfigurator.hh index d38872f..bbdcc49 100644 --- a/Library/Application/KTConfigurator.hh +++ b/Library/Application/KTConfigurator.hh @@ -60,7 +60,7 @@ namespace Nymph } catch( std::exception& e ) {} - throw KTException() << "configurator does not have a value for <" << aName << ">"; + BOOST_THROW_EXCEPTION( KTException() << "configurator does not have a value for <" << aName << ">" << eom ); } template< typename XReturnType > diff --git a/Library/Application/KTProcessorToolbox.cc b/Library/Application/KTProcessorToolbox.cc index 95bb39a..afe5bcc 100644 --- a/Library/Application/KTProcessorToolbox.cc +++ b/Library/Application/KTProcessorToolbox.cc @@ -410,12 +410,12 @@ namespace Nymph signalProc->ConnectASlot(signalName, slotProc, slotName); } } - catch (std::exception& e) + catch (boost::exception& e) { KTERROR(proclog, "An error occurred while connecting signals and slots:\n" << "\tSignal " << signalName << " from processor " << signalProcName << " (a.k.a. " << signalProc->GetConfigName() << ")" << '\n' << "\tSlot " << slotName << " from processor " << slotProcName << " (a.k.a. " << slotProc->GetConfigName() << ")" << '\n' - << '\t' << e.what()); + << '\t' << diagnostic_information( e )); return false; } @@ -448,9 +448,9 @@ namespace Nymph slotProc->SetDoBreakpoint(slotName, true); return true; } - catch (std::exception& e) + catch (boost::exception& e) { - KTERROR(proclog, "Unable to set breakpoint: " << e.what()); + KTERROR(proclog, "Unable to set breakpoint: " << diagnostic_information( e )); return false; } } @@ -481,9 +481,9 @@ namespace Nymph slotProc->SetDoBreakpoint(slotName, false); return true; } - catch (std::exception& e) + catch (boost::exception& e) { - KTERROR(proclog, "Unable to set breakpoint: " << e.what()); + KTERROR(proclog, "Unable to set breakpoint: " << diagnostic_information( e )); return false; } } @@ -606,7 +606,7 @@ namespace Nymph if( ! fMasterContSignal.valid() ) { KTERROR( proclog, "Invalid master continue-signal created" ); - throw KTException() << "Invalid master continue-signal created"; + BOOST_THROW_EXCEPTION( KTException() << "Invalid master continue-signal created" << eom ); } // copy for use in this function boost::shared_future< void > continueSignal = fMasterContSignal; @@ -633,7 +633,7 @@ namespace Nymph //if( ! fThreadFutures.back().valid() ) //{ // KTERROR( proclog, "Invalid thread future created" ); - // throw KTException() << "Invalid thread future created"; + // BOOST_THROW_EXCEPTION( KTException() << "Invalid thread future created"; //} //fThreadIndicators.emplace_back( new KTThreadIndicator() ); @@ -691,9 +691,8 @@ namespace Nymph } catch( boost::exception& e ) { - KTERROR( proclog, "Thread <" << fThreadReferences.back()->fName << "> threw an error: " << diagnostic_information( e ) ); - // this transfers an exception thrown by a processor to the outer catch block in this function - throw KTException() << "An error occurred while running processor <" << procName << ">: " << diagnostic_information( e ); + e << KTErrorMsgInfo( "There was an error while finishing thread <" + procName + "> and retrieving its results" ); + throw; } stillRunning = false; } @@ -712,15 +711,19 @@ namespace Nymph } catch( std::exception& e ) { - KTDEBUG( proclog, "Caught exception thrown in a processor or in the single-threaded run function: " << e.what() ); // exceptions thrown in this function or from within processors will end up here - fDoRunPromise.set_exception( std::current_exception() ); + KTERROR( proclog, "Caught std::exception thrown in a processor or in the single-threaded run function: " << e.what() ); + KTWARN( proclog, "Setting boost::exception of do-run-promise in StartSingleThreadedRun" ); + fDoRunPromise.set_exception( boost::current_exception() ); + return; } catch( boost::exception& e ) { - KTDEBUG( proclog, "Caught exception thrown in a processor or in the single-threaded run function: " << diagnostic_information( e ) ); // exceptions thrown in this function or from within processors will end up here - fDoRunPromise.set_exception( std::current_exception() ); + KTERROR( proclog, "Caught boost::exception thrown in a processor or in the single-threaded run function" ); + KTWARN( proclog, "Setting boost::exception of do-run-promise in StartSingleThreadedRun" ); + fDoRunPromise.set_exception( boost::current_exception() ); + return; } fDoRunPromise.set_value(); return; @@ -741,7 +744,7 @@ namespace Nymph if( ! fMasterContSignal.valid() ) { KTERROR( proclog, "Invalid master continue-signal created" ); - throw KTException() << "Invalid master continue-signal created"; + BOOST_THROW_EXCEPTION( KTException() << "Invalid master continue-signal created" << eom ); } // copy for use in this function boost::shared_future< void > continueSignal = fMasterContSignal; @@ -837,9 +840,8 @@ namespace Nymph } catch( boost::exception& e ) { - KTERROR( proclog, "Thread <" << threadName << "> threw an error: " << diagnostic_information( e ) ); - // this transfers an exception thrown by a processor to the outer catch block in this function - throw KTException() << "An error occurred while running processor <" << threadName << ">: " << diagnostic_information( e ); + e << KTErrorMsgInfo( "There was an error while finishing thread <" + threadName + "> and retrieving its results" ); + throw; } if( fThreadReferences.empty() ) stillRunning = false; @@ -869,7 +871,7 @@ namespace Nymph catch( boost::exception& e ) { // exceptions thrown in this function or from within processors will end up here - KTERROR( proclog, "Caught std::exception thrown in a processor or in the multi-threaded run function: " << diagnostic_information( e ) ); + KTERROR( proclog, "Caught boost::exception thrown in a processor or in the multi-threaded run function" ); KTWARN( proclog, "Setting boost::exception of do-run-promise in StartMultiThreadedRun" ); fDoRunPromise.set_exception( boost::current_exception() ); return; @@ -897,11 +899,12 @@ namespace Nymph boost::shared_future< void > doRunFuture = fDoRunFuture; if( ! doRunFuture.valid() ) { - throw KTException() << "Cannot wait for a break in the current state (the \"DoRun\" future does not have a valid shared state)"; + BOOST_THROW_EXCEPTION( KTException() << "Cannot wait for a break in the current state (the \"DoRun\" future does not have a valid shared state)" << eom ); } breakContLock.unlock(); + // block here until there's a break doRunFuture.wait(); if( fDoRunBreakFlag ) @@ -912,34 +915,30 @@ namespace Nymph try { - doRunFuture.get(); // TODO: do we really need this? NSO, 5/23/17 + doRunFuture.get(); KTDEBUG( proclog, "End-of-run reached (the wait-for-break is over)" ); return false; } - catch( std::exception& e ) + catch( boost::exception& e ) { - KTERROR( proclog, "An error occurred during processing: " << e.what() ); + KTERROR( proclog, "An error occurred during processing: " << boost::diagnostic_information( e ) ); return false; } } void KTProcessorToolbox::WaitForEndOfRun() { - try - { - KTDEBUG( proclog, "Waiting for end-of-run" ); - while( WaitForBreak() ) - { - KTDEBUG( proclog, "Reached breakpoint; waiting for continue" ); - WaitForContinue(); - KTDEBUG( proclog, "Processing resuming; waiting for end-of-run" ); - } - KTDEBUG( proclog, "End-of-run reached" ); - } - catch( std::exception& e ) + // WaitForBreak() and WaitForContinue() throw boost::exception for problems with the future or promise objects + + KTDEBUG( proclog, "Waiting for end-of-run" ); + while( WaitForBreak() ) { - throw; + KTDEBUG( proclog, "Reached breakpoint; waiting for continue" ); + WaitForContinue(); + KTDEBUG( proclog, "Processing resuming; waiting for end-of-run" ); } + KTDEBUG( proclog, "End-of-run reached" ); + return; } @@ -998,7 +997,7 @@ namespace Nymph if( tnIt == fThreadReferences.end() ) { KTWARN( proclog, "Did not find thread <" << threadName << ">" ); - throw KTException() << "Did not find thread <" << threadName << ">" ; + BOOST_THROW_EXCEPTION( KTException() << "Did not find thread <" << threadName << ">" << eom ); } return (*tnIt)->fDataPtrRetFuture.get(); @@ -1037,18 +1036,14 @@ namespace Nymph bool KTProcessorToolbox::Run() { - try - { - AsyncRun(); + // can throw boost::exception - WaitForEndOfRun(); + AsyncRun(); + + WaitForEndOfRun(); + + JoinRunThread(); - JoinRunThread(); - } - catch( std::exception& e ) - { - throw; - } return true; } diff --git a/Library/Application/KTProcessorToolbox.hh b/Library/Application/KTProcessorToolbox.hh index dfebeae..cf6c24d 100644 --- a/Library/Application/KTProcessorToolbox.hh +++ b/Library/Application/KTProcessorToolbox.hh @@ -213,8 +213,9 @@ namespace Nymph void WaitForContinue(); /// Returns when processing is completed or a breakpoint is reached - /// Throws an exception if an error occurred during processing + /// Throws a boost::exception if there's an error with the future object in use /// If the return is true, processing can continue after the break + /// If the return is false, processing has ended (either normally or due to an error) bool WaitForBreak(); void WaitForEndOfRun(); diff --git a/Library/Processor/KTProcessor.cc b/Library/Processor/KTProcessor.cc index c8df746..ff5eeaa 100644 --- a/Library/Processor/KTProcessor.cc +++ b/Library/Processor/KTProcessor.cc @@ -18,11 +18,6 @@ namespace Nymph { //KTLOGGER(proclog, "KTProcessor"); - ProcessorException::ProcessorException (std::string const& why) - : std::logic_error(why) - {} - - KTProcessor::KTProcessor(const string& name) : KTConfigurable(name), fSignalMap(), @@ -63,14 +58,28 @@ namespace Nymph // make the connection ConnectSignalToSlot(signal, slot, groupNum); } - catch (std::exception& e) + catch( KTSignalException& e ) + { + e << KTErrorMsgInfo( "Unable to connect signal <" + signalName + "> to slot <" + slotName + "> due to a problem with the signal." ); + e << KTErrorMsgInfo( "You may have the signal name wrong." ); + throw; + } + catch( KTSlotException& e ) + { + e << KTErrorMsgInfo( "Unable to connect signal <" + signalName + "> to slot <" + slotName + "> due to a problem with the slot." ); + e << KTErrorMsgInfo( "You may have the slot name wrong." ); + throw; + } + catch( KTConnectionException& e ) + { + e << KTErrorMsgInfo( "Unable to connect signal <" + signalName + "> to slot <" + slotName + "> due to a problem making the connection." ); + e << KTErrorMsgInfo( "Check that the signatures of the signal and slot match exactly." ); + throw; + } + catch( boost::exception& e ) { - string errorMsg = string("Exception caught in KTProcessor::ConnectASignal; signal: ") + - signalName + string(", slot: ") + slotName + string("\n") + e.what() + string("\n") + - string("\tIf the signal wrapper cannot be cast correctly, check that the signatures of the signal and slot match exactly.\n") + - string("\tIf the signal pointer is NULL, you may have the signal name wrong.\n") + - string("\tIf the slot pointer is NULL, you may have the slot name wrong."); - throw std::logic_error(errorMsg); + e << KTErrorMsgInfo( "Unable to connect signal <" + signalName + "> to slot <" + slotName + "> for an unknown reason." ); + throw; } // record the connection in the signal-connection map @@ -83,13 +92,13 @@ namespace Nymph void KTProcessor::ConnectSignalToSlot(KTSignalWrapper* signal, KTSlotWrapper* slot, int groupNum) { - if (signal == NULL) + if (signal == nullptr) { - throw ProcessorException("Signal pointer was NULL"); + BOOST_THROW_EXCEPTION( KTSignalException() << "Signal pointer was NULL" << eom ); } - if (slot == NULL) + if (slot == nullptr) { - throw ProcessorException("Slot pointer was NULL"); + BOOST_THROW_EXCEPTION( KTSlotException() << "Slot pointer was NULL" << eom ); } slot->SetConnection(signal, groupNum); @@ -124,7 +133,8 @@ namespace Nymph { return slot->GetDoBreakpoint(); } - throw KTException() << "Slot <" << slotName << "> was not found"; + BOOST_THROW_EXCEPTION( KTException() << "Slot <" << slotName << "> was not found" << eom ); + return false; } void KTProcessor::SetDoBreakpoint(const std::string& slotName, bool flag) @@ -134,7 +144,7 @@ namespace Nymph { return slot->SetDoBreakpoint(flag); } - throw KTException() << "Slot <" << slotName << "> was not found"; + BOOST_THROW_EXCEPTION( KTException() << "Slot <" << slotName << "> was not found" << eom ); return; } diff --git a/Library/Processor/KTProcessor.hh b/Library/Processor/KTProcessor.hh index c4365e0..aad8d20 100644 --- a/Library/Processor/KTProcessor.hh +++ b/Library/Processor/KTProcessor.hh @@ -30,11 +30,11 @@ namespace Nymph { KTLOGGER(processorlog, "KTProcessor.hh"); - class ProcessorException : public std::logic_error - { - public: - ProcessorException(std::string const& why); - }; + struct KTProcessorException : virtual public KTException + {}; + + struct KTSignalException : virtual public KTException {}; + struct KTSlotException : virtual public KTException {}; class KTThreadReference; diff --git a/Library/Processor/KTSignalWrapper.cc b/Library/Processor/KTSignalWrapper.cc index 42c629c..795fc2c 100644 --- a/Library/Processor/KTSignalWrapper.cc +++ b/Library/Processor/KTSignalWrapper.cc @@ -9,9 +9,6 @@ namespace Nymph { - SignalException::SignalException (std::string const& why) - : std::logic_error(why) - {} KTSignalWrapper::KTSignalWrapper() : fSignalWrapper(NULL) diff --git a/Library/Processor/KTSignalWrapper.hh b/Library/Processor/KTSignalWrapper.hh index 22ed542..aa4f658 100644 --- a/Library/Processor/KTSignalWrapper.hh +++ b/Library/Processor/KTSignalWrapper.hh @@ -23,12 +23,6 @@ namespace Nymph typedef typename boost::signals2::signal< Signature >::slot_type slot_type; }; - class SignalException : public std::logic_error - { - public: - SignalException(std::string const& why); - }; - class KTSignalWrapper : public boost::noncopyable { public: diff --git a/Library/Processor/KTSlotWrapper.cc b/Library/Processor/KTSlotWrapper.cc index 2eb5f4f..66e12f1 100644 --- a/Library/Processor/KTSlotWrapper.cc +++ b/Library/Processor/KTSlotWrapper.cc @@ -9,13 +9,12 @@ namespace Nymph { - SlotException::SlotException (std::string const& why) - : std::logic_error(why) - {} KTSlotWrapper::KTSlotWrapper() : fSlotWrapper(NULL), - fConnection() + fConnection(), + fThreadRef(), + fDoBreakpoint(false) { } diff --git a/Library/Processor/KTSlotWrapper.hh b/Library/Processor/KTSlotWrapper.hh index 158316b..86386f1 100644 --- a/Library/Processor/KTSlotWrapper.hh +++ b/Library/Processor/KTSlotWrapper.hh @@ -9,6 +9,7 @@ #define KTSLOTWRAPPER_HH_ #include "KTConnection.hh" +#include "KTException.hh" #include "KTSignalWrapper.hh" #include "KTThreadReference.hh" @@ -16,11 +17,8 @@ namespace Nymph { - class SlotException : public std::logic_error - { - public: - SlotException(std::string const& why); - }; + struct KTConnectionException : public KTException + {}; class KTSlotWrapper : public boost::noncopyable { @@ -56,7 +54,7 @@ namespace Nymph SignalWrapper* derivedSignalWrapper = dynamic_cast< SignalWrapper* >(internalSignalWrap); if (derivedSignalWrapper == NULL) { - throw SignalException("In KTSpecifiedInternalSlotWrapper::Connect:\nUnable to cast from KTInternalSignalWrapper* to derived type."); + BOOST_THROW_EXCEPTION( KTConnectionException() << "Cannot make connection: unable to cast from KTInternalSignalWrapper* to this slot's derived type." << eom ); } if (groupNum >= 0) { @@ -81,7 +79,7 @@ namespace Nymph public: void SetConnection(KTConnection conn); - void SetConnection(KTSignalWrapper* signalWrap, int groupNum=-1); + void SetConnection(KTSignalWrapper* signalWrap, int groupNum=-1); // can throw KTConnectionException void Disconnect(); private: diff --git a/Library/Processor/KTThreadReference.cc b/Library/Processor/KTThreadReference.cc index 5d3a17f..c64eaef 100644 --- a/Library/Processor/KTThreadReference.cc +++ b/Library/Processor/KTThreadReference.cc @@ -35,7 +35,7 @@ namespace Nymph if( ! fDataPtrRetFuture.valid() ) { KTERROR( trlog, "Invalid data-pointer-return future created" ); - throw KTException() << "Invalid data-pointer-return future created"; + BOOST_THROW_EXCEPTION( KTException() << "Invalid data-pointer-return future created" << eom ); } } diff --git a/Library/Utility/KTException.cc b/Library/Utility/KTException.cc index 55a7a5f..62d0810 100644 --- a/Library/Utility/KTException.cc +++ b/Library/Utility/KTException.cc @@ -11,13 +11,15 @@ namespace Nymph { KTException::KTException() : + boost::exception(), std::exception(), - fException( "" ) + fMsgBuffer( "" ) { } KTException::KTException( const KTException& an_exception ) : - std::exception(), - fException( an_exception.fException ) + boost::exception( an_exception ), + std::exception( an_exception ), + fMsgBuffer( an_exception.fMsgBuffer ) { } @@ -27,7 +29,12 @@ namespace Nymph const char* KTException::what() const throw () { - return fException.c_str(); + if( ! fMsgBuffer.empty() ) + { + *this << KTErrorMsgInfo{ fMsgBuffer }; + fMsgBuffer.clear(); + } + return this->std::exception::what(); } } diff --git a/Library/Utility/KTException.hh b/Library/Utility/KTException.hh index a599fbf..c2b256c 100644 --- a/Library/Utility/KTException.hh +++ b/Library/Utility/KTException.hh @@ -9,30 +9,86 @@ #ifndef KTEXCEPTION_HH_ #define KTEXCEPTION_HH_ +#include + #include #include #include namespace Nymph { + struct KTMessageEnd {}; + static const KTMessageEnd eom = KTMessageEnd(); + + typedef boost::error_info KTErrorMsgInfo; + + /*! + @class KTException + @author N.S. Oblath + + @brief Exception base class for Nymph and Nymph-based projects + + @details + + How to throw: + + BOOST_THROW_EXCEPTION( KTException() << "[error message here]" << eom ); + + Why do it like this? + - BOOST_THROW_EXCEPTION will record the location that the exception was thrown. This is incredibly useful in diagnosing problems. + - eom ensure that your error message is handled properly; until that's processed the message is stored in a buffer, and the eom takes that buffer and adds it to the boost::exception base class's storage. + - KTException can be replaced with whatever derived exception class you're using. + + How to catch, add information, and re-throw: + + try + { + // code that throws a KTException + } + catch( boost::exception& e ) + { + e << KTErrorMsgInfo( "Here's some information about the context in which the exception was thrown" ); + throw; + } + - class KTException : - public std::exception + How to do the final catch + + try + { + // code that throws a KTException + } + catch( boost::exception& e ) + { + KTERROR( my_log, "An exception was caught: " << diagnostic_information( e ) ): + } + */ + + class KTException : virtual public boost::exception, virtual public std::exception { public: KTException(); KTException( const KTException& ); ~KTException() throw (); + // adds to the message buffer template< class XStreamable > KTException& operator<<( XStreamable a_fragment ); + // adds to the message buffer KTException& operator<<( const std::string& a_fragment ); + // adds to the message buffer KTException& operator<<( const char* a_fragment ); + // adds the current contents of the message buffer as a KTErrorMsgInfo + KTException& operator<<( const KTMessageEnd& eom ); + + // overload for KTErrorMsgInfo to make sure error messages are streamed correctly, and not via the template function + const KTException& operator<<( KTErrorMsgInfo& emi ); + virtual const char* what() const throw(); private: - std::string fException; + mutable std::string fMsgBuffer; }; template< class XStreamable > @@ -40,22 +96,37 @@ namespace Nymph { std::stringstream stream; stream << a_fragment; - stream >> fException; + stream >> fMsgBuffer; return *this; } inline KTException& KTException::operator<<( const std::string& a_fragment ) { - fException += a_fragment; + fMsgBuffer += a_fragment; return *this; } inline KTException& KTException::operator<<( const char* a_fragment ) { - fException += std::string( a_fragment ); + fMsgBuffer += std::string( a_fragment ); return *this; } + inline KTException& KTException::operator<<( const KTMessageEnd& eom ) + { + if( ! fMsgBuffer.empty() ) + { + boost::operator<<( *this, KTErrorMsgInfo{ fMsgBuffer } ); + fMsgBuffer.clear(); + } + return *this; + } + + inline const KTException& KTException::operator<<( KTErrorMsgInfo& emi ) + { + return boost::operator<<( *this, emi ); + } + } #endif /* KTEXCEPTION_HH_ */ From 626260a51ec7a46539be2a0ad8213fb7865640ec Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Thu, 25 May 2017 16:04:45 -0700 Subject: [PATCH 042/521] Promoted KTThreadRef to a class and partial work on adapting to its encapsulation --- .../Validation/KTTestPrimaryProcessor.cc | 2 +- Executables/Validation/TestExceptionInSlot.cc | 6 +- .../Validation/TestPrimaryProcessor.cc | 10 +- Library/Application/KTProcessorToolbox.cc | 38 ++--- Library/Application/KTProcessorToolbox.hh | 2 +- Library/Data/KTApplyCut.cc | 2 +- Library/Data/KTData.hh | 8 -- Library/Processor/KTPrimaryProcessor.cc | 8 +- Library/Processor/KTSlot.hh | 4 +- Library/Processor/KTSlotWrapper.hh | 5 +- Library/Processor/KTThreadReference.cc | 43 ++---- Library/Processor/KTThreadReference.hh | 135 ++++++++++++++---- 12 files changed, 151 insertions(+), 112 deletions(-) diff --git a/Executables/Validation/KTTestPrimaryProcessor.cc b/Executables/Validation/KTTestPrimaryProcessor.cc index 42f8aab..d9270de 100644 --- a/Executables/Validation/KTTestPrimaryProcessor.cc +++ b/Executables/Validation/KTTestPrimaryProcessor.cc @@ -39,7 +39,7 @@ namespace Nymph // e.g. for a real processor, do some work here instead of sleeping boost::this_thread::sleep_for( boost::chrono::milliseconds(1) ); - if( fThreadRef->fCanceled ) break; + if( fThreadRef->GetCanceled() ) break; fTheSignal( iIteration ); } diff --git a/Executables/Validation/TestExceptionInSlot.cc b/Executables/Validation/TestExceptionInSlot.cc index f036428..2f889d0 100644 --- a/Executables/Validation/TestExceptionInSlot.cc +++ b/Executables/Validation/TestExceptionInSlot.cc @@ -54,7 +54,7 @@ int main() } catch( boost::exception& e ) { - exeThreadRef->fDataPtrRet.set_exception( boost::current_exception() ); + exeThreadRef->SetReturnException( boost::current_exception() ); } return; @@ -64,11 +64,11 @@ int main() boost::thread thread( exeFunc ); // wait for a result to be set - exeThreadRef->fDataPtrRetFuture.wait(); + exeThreadRef->GetDataPtrRetFuture().wait(); try { - exeThreadRef->fDataPtrRetFuture.get(); + exeThreadRef->GetReturnValue(); } //catch( std::exception& e ) //{ diff --git a/Executables/Validation/TestPrimaryProcessor.cc b/Executables/Validation/TestPrimaryProcessor.cc index 219905e..21a7aee 100644 --- a/Executables/Validation/TestPrimaryProcessor.cc +++ b/Executables/Validation/TestPrimaryProcessor.cc @@ -30,8 +30,8 @@ int main() // setup to execute processors asynchronously //KTThreadReference exeThreadRef; //auto exeThreadFuture = exeThreadRef.fDataPtrRet.get_future(); - std::shared_ptr< KTThreadReference > exeThreadRef = std::make_shared< KTThreadReference >(); - exeThreadRef->fName = std::string( "tpp" ); + std::shared_ptr< KTThreadReference > exeThreadRef( std::make_shared< KTThreadReference >() ); + exeThreadRef->Name() = std::string( "tpp" ); // run the thread boost::condition_variable threadStartedCV; @@ -48,15 +48,15 @@ int main() KTDEBUG( testpplog, "Thread has started" ); // wait for a result to be set - exeThreadRef->fDataPtrRetFuture.wait(); + exeThreadRef->GetDataPtrRetFuture().wait(); try { - exeThreadRef->fDataPtrRetFuture.get(); + exeThreadRef->GetReturnValue(); } catch( boost::exception& e ) { - exeThreadRef->fCanceled = true; + exeThreadRef->SetCanceled( true ); KTERROR( testpplog, "An error occurred while running a processor: " << diagnostic_information( e ) ); } diff --git a/Library/Application/KTProcessorToolbox.cc b/Library/Application/KTProcessorToolbox.cc index afe5bcc..839e355 100644 --- a/Library/Application/KTProcessorToolbox.cc +++ b/Library/Application/KTProcessorToolbox.cc @@ -624,7 +624,7 @@ namespace Nymph //KTThreadReference thisThreadRef; std::shared_ptr< KTThreadReference > thisThreadRef = std::make_shared< KTThreadReference >(); - thisThreadRef->fName = procName; + thisThreadRef->Name() = procName; //fThreadFutures.push_back( std::move( thisThreadRef.fDataPtrRet.get_future() ) ); //fThreadNames.push_back( procName ); @@ -638,10 +638,10 @@ namespace Nymph //fThreadIndicators.emplace_back( new KTThreadIndicator() ); //fThreadIndicators.back()->fContinueSignal = fMasterContSignal; - thisThreadRef->fContinueSignal = fMasterContSignal; + thisThreadRef->SetContinueSignal( fMasterContSignal ); //thisThreadRef->fThreadIndicator = fThreadIndicators.back(); - thisThreadRef->fInitiateBreakFunc = [&](){ this->InitiateBreak(); }; + thisThreadRef->SetInitiateBreakFunc( [&](){ this->InitiateBreak(); } ); //thisThreadRef->fRefreshFutureFunc = [&]( const std::string& name, Future&& ret ){ this->TakeFuture( name, std::move(ret) ); }; fThreadReferences.push_back( thisThreadRef ); @@ -669,13 +669,13 @@ namespace Nymph boost::future_status status; do { - status = fThreadReferences.back()->fDataPtrRetFuture.wait_for( boost::chrono::milliseconds(500) ); + status = fThreadReferences.back()->GetDataPtrRetFuture().wait_for( boost::chrono::milliseconds(500) ); } while (status != boost::future_status::ready); stillRunning = false; - if( fThreadReferences.back()->fBreakFlag ) + if( fThreadReferences.back()->GetBreakFlag() ) { - KTDEBUG( proclog, "Breakpoint reached (seen first in thread <" << fThreadReferences.back()->fName << ">; may not be where breakpoint is set)" ); + KTDEBUG( proclog, "Breakpoint reached (seen first in thread <" << procName << ">; may not be where breakpoint is set)" ); continueSignal.wait(); KTDEBUG( proclog, "Breakpoint finished" ); stillRunning = true; @@ -685,8 +685,8 @@ namespace Nymph { try { - fThreadReferences.back()->fDataPtrRetFuture.get(); - KTINFO( proclog, "Thread <" << fThreadReferences.back()->fName << "> has finished" ); + fThreadReferences.back()->GetReturnValue(); + KTINFO( proclog, "Thread <" << procName << "> has finished" ); fThreadReferences.pop_back(); } catch( boost::exception& e ) @@ -765,17 +765,17 @@ namespace Nymph //KTThreadReference thisThreadRef; std::shared_ptr< KTThreadReference > thisThreadRef = std::make_shared< KTThreadReference >(); - thisThreadRef->fName = procName; + thisThreadRef->Name() = procName; //fThreadFutures.push_back( std::move( thisThreadRef.fDataPtrRet.get_future() ) ); //fThreadNames.push_back( procName ); //fThreadIndicators.emplace_back( new KTThreadIndicator() ); //fThreadIndicators.back()->fContinueSignal = fMasterContSignal; - thisThreadRef->fContinueSignal = fMasterContSignal; + thisThreadRef->SetContinueSignal( fMasterContSignal ); //thisThreadRef->fThreadIndicator = fThreadIndicators.back(); - thisThreadRef->fInitiateBreakFunc = [&](){ this->InitiateBreak(); }; + thisThreadRef->SetInitiateBreakFunc( [&](){ this->InitiateBreak(); } ); //thisThreadRef->fRefreshFutureFunc = [&]( const std::string& name, Future&& ret ){ this->TakeFuture( name, std::move(ret) ); }; boost::condition_variable threadStartedCV; boost::mutex threadStartedMutex; @@ -807,9 +807,9 @@ namespace Nymph auto finishedFuturePtr = boost::wait_for_any( KTThreadRefFutureIterator(fThreadReferences.begin()), KTThreadRefFutureIterator(fThreadReferences.end()) ); size_t iThread = finishedFuturePtr - KTThreadRefFutureIterator(fThreadReferences.begin()); auto finishedReferencePtr = fThreadReferences.begin() + iThread; - std::string threadName( (*finishedReferencePtr)->fName ); + std::string threadName( (*finishedReferencePtr)->Name() ); //KTDEBUG( proclog, "Thread <" << iThread << " (" << threadName << ") > has stopped for some reason" ); - KTWARN( proclog, "Thread <" << iThread << " (" << threadName << ") > has stopped for some reason" ); // TODO: swtich this back to DEBUG + KTWARN( proclog, "Thread <" << iThread << " (" << threadName << ") > has stopped for some reason" ); // TODO: switch this back to DEBUG stillRunning = false; if( fDoRunBreakFlag ) @@ -960,7 +960,7 @@ namespace Nymph fDoRunBreakFlag = false; for( auto tiIt = fThreadReferences.begin(); tiIt != fThreadReferences.end(); ++tiIt ) { - (*tiIt)->fBreakFlag = false; + (*tiIt)->SetBreakFlag( false ); (*tiIt)->RefreshDataPtrRet(); } @@ -979,7 +979,7 @@ namespace Nymph fMasterContSignal = fContinueSignaler.get_future().share(); for( auto tiIt = fThreadReferences.begin(); tiIt != fThreadReferences.end(); ++tiIt ) { - (*tiIt)->fContinueSignal = fMasterContSignal; + (*tiIt)->SetContinueSignal( fMasterContSignal ); } return; @@ -992,7 +992,7 @@ namespace Nymph auto tnIt = fThreadReferences.begin(); for( ; tnIt != fThreadReferences.end(); ++tnIt ) { - if( (*tnIt)->fName == threadName ) break; + if( (*tnIt)->Name() == threadName ) break; } if( tnIt == fThreadReferences.end() ) { @@ -1000,7 +1000,7 @@ namespace Nymph BOOST_THROW_EXCEPTION( KTException() << "Did not find thread <" << threadName << ">" << eom ); } - return (*tnIt)->fDataPtrRetFuture.get(); + return (*tnIt)->GetReturnValue(); } void KTProcessorToolbox::InitiateBreak() @@ -1014,7 +1014,7 @@ namespace Nymph // thread break flags for( auto tiIt = fThreadReferences.begin(); tiIt != fThreadReferences.end(); ++tiIt ) { - (*tiIt)->fBreakFlag = true; + (*tiIt)->SetBreakFlag( true ); } // use the do-run promise to signal the break @@ -1029,7 +1029,7 @@ namespace Nymph boost::unique_lock< boost::mutex > breakContLock( fBreakContMutex ); for( auto tiIt = fThreadReferences.begin(); tiIt != fThreadReferences.end(); ++tiIt ) { - (*tiIt)->fCanceled = true; + (*tiIt)->SetCanceled( true ); } return; } diff --git a/Library/Application/KTProcessorToolbox.hh b/Library/Application/KTProcessorToolbox.hh index cf6c24d..b05cb6d 100644 --- a/Library/Application/KTProcessorToolbox.hh +++ b/Library/Application/KTProcessorToolbox.hh @@ -290,7 +290,7 @@ namespace Nymph Value& dereference() const { - return (*(this->base_reference()))->fDataPtrRetFuture; + return (*(this->base_reference()))->GetDataPtrRetFuture(); } }; diff --git a/Library/Data/KTApplyCut.cc b/Library/Data/KTApplyCut.cc index a4535ea..47b5e98 100644 --- a/Library/Data/KTApplyCut.cc +++ b/Library/Data/KTApplyCut.cc @@ -89,7 +89,7 @@ namespace Nymph if (fCut == NULL) { - ref->fDataPtrRet.set_exception( std::make_exception_ptr( KTException() << "No cut was specified" ) ); + THROW_THREADREF_EXCEPTION( ref, KTException() << "No cut was specified" ); return; } diff --git a/Library/Data/KTData.hh b/Library/Data/KTData.hh index 32838e9..1f93d4f 100644 --- a/Library/Data/KTData.hh +++ b/Library/Data/KTData.hh @@ -13,9 +13,6 @@ #include "KTCutStatus.hh" #include "KTMemberVariable.hh" -#include - -//#include #include #include @@ -75,10 +72,5 @@ namespace Nymph typedef std::shared_ptr< KTData > KTDataPtr; - typedef boost::promise< KTDataPtr > KTDataPtrReturn; - -#define THROW_RETURN_EXCEPTION( ret_promise, exception ) \ - ret_promise.set_exception( std::make_exception_ptr( exception ) ); - } /* namespace Nymph */ #endif /* KTDATA_HH_ */ diff --git a/Library/Processor/KTPrimaryProcessor.cc b/Library/Processor/KTPrimaryProcessor.cc index cfce927..9e16eaf 100644 --- a/Library/Processor/KTPrimaryProcessor.cc +++ b/Library/Processor/KTPrimaryProcessor.cc @@ -52,16 +52,16 @@ namespace Nymph if( ! Run() ) { KTERROR( proclog, "An error occurred during processor running." ); - THROW_RETURN_EXCEPTION( fThreadRef->fDataPtrRet, KTException() << "An error occurred during processor running" ); + THROW_THREADREF_EXCEPTION( fThreadRef, KTException() << "An error occurred during processor running" ); } else { - fThreadRef->fDataPtrRet.set_value( KTDataPtr() ); + fThreadRef->SetReturnValue( KTDataPtr() ); } } - catch( ... ) + catch( boost::exception& e ) { - fThreadRef->fDataPtrRet.set_exception( std::current_exception() ); + fThreadRef->SetReturnException( boost::current_exception() ); } return; } diff --git a/Library/Processor/KTSlot.hh b/Library/Processor/KTSlot.hh index 6019dae..9840131 100644 --- a/Library/Processor/KTSlot.hh +++ b/Library/Processor/KTSlot.hh @@ -275,7 +275,7 @@ namespace Nymph if( ! DataPresent< XDataTypes... >( dataPtr ) ) { KTERROR( slotlog, "Failed to find all of the necessary data types in slot <" << fName << ">. Aborting." ); - THROW_RETURN_EXCEPTION( ref->fDataPtrRet, KTException() << "Failed to find all of the necessary data types in slot <" << fName << ">. Aborting." ); + THROW_THREADREF_EXCEPTION( ref, KTException() << "Failed to find all of the necessary data types in slot <" << fName << ">. Aborting." ); return; } @@ -283,7 +283,7 @@ namespace Nymph if( ! fFunc( dataPtr->Of< XDataTypes >()... ) ) { KTERROR( slotlog, "Something went wrong in slot <" << fName << ">. Aborting." ); - THROW_RETURN_EXCEPTION( ref->fDataPtrRet, KTException() << "Something went wrong in slot <" << fName << ">. Aborting." ); + THROW_THREADREF_EXCEPTION( ref, KTException() << "Something went wrong in slot <" << fName << ">. Aborting." ); return; } diff --git a/Library/Processor/KTSlotWrapper.hh b/Library/Processor/KTSlotWrapper.hh index 86386f1..70d3f3f 100644 --- a/Library/Processor/KTSlotWrapper.hh +++ b/Library/Processor/KTSlotWrapper.hh @@ -102,9 +102,10 @@ namespace Nymph KTSlotWrapper::KTSlotWrapper(XSignature signalPtr, XTypeContainer* typeCont) : fSlotWrapper(new KTSpecifiedInternalSlotWrapper< XSignature, XTypeContainer >(signalPtr, typeCont)), fConnection(), - fThreadRef(), + fThreadRef( std::make_shared< KTThreadReference >() ), fDoBreakpoint(false) - {} + { + } inline void KTSlotWrapper::SetConnection(KTConnection conn) { diff --git a/Library/Processor/KTThreadReference.cc b/Library/Processor/KTThreadReference.cc index c64eaef..c934fd2 100644 --- a/Library/Processor/KTThreadReference.cc +++ b/Library/Processor/KTThreadReference.cc @@ -14,23 +14,15 @@ KTLOGGER( trlog, "KTThreadReference" ); namespace Nymph { - //KTThreadIndicator::KTThreadIndicator() : - // fBreakFlag( false ), - // fContinueSignal(), - // fCanceled( false ) - //{} KTThreadReference::KTThreadReference() : fName(), + fBreakFlag( false ), + fCanceled( false ), fDataPtrRet(), fDataPtrRetFuture( fDataPtrRet.get_future() ), fInitiateBreakFunc( [](){return;} ), - fRefreshFutureFunc( [](const std::string&, boost::shared_future< KTDataPtr >&&){return;} ), - //fThreadIndicator( new KTThreadIndicator() ), - fBreakFlag( false ), - fContinueSignal(), - fCanceled( false ), - fPrimaryProcName() + fContinueSignal() { if( ! fDataPtrRetFuture.valid() ) { @@ -41,17 +33,13 @@ namespace Nymph KTThreadReference::KTThreadReference( KTThreadReference&& orig ) : fName( std::move( orig.fName ) ), + fBreakFlag( orig.fBreakFlag ), + fCanceled( orig.fCanceled ), fDataPtrRet( std::move( orig.fDataPtrRet ) ), fDataPtrRetFuture( std::move( orig.fDataPtrRetFuture ) ), fInitiateBreakFunc( std::move( orig.fInitiateBreakFunc ) ), - fRefreshFutureFunc( std::move( orig.fRefreshFutureFunc ) ), - //fThreadIndicator( orig.fThreadIndicator ), - fBreakFlag( orig.fBreakFlag ), - fContinueSignal( std::move( orig.fContinueSignal ) ), - fCanceled( orig.fCanceled ), - fPrimaryProcName( std::move( orig.fPrimaryProcName ) ) + fContinueSignal( std::move( orig.fContinueSignal ) ) { - //orig.fThreadIndicator = nullptr; orig.fBreakFlag = false; orig.fCanceled = false; } @@ -59,17 +47,13 @@ namespace Nymph KTThreadReference& KTThreadReference::operator=( KTThreadReference&& orig ) { fName = std::move( orig.fName ); + fBreakFlag = orig.fBreakFlag; + fCanceled = orig.fCanceled; fDataPtrRet = std::move( orig.fDataPtrRet ); fDataPtrRetFuture = std::move( orig.fDataPtrRetFuture ); fInitiateBreakFunc = std::move( orig.fInitiateBreakFunc ); - fRefreshFutureFunc = std::move( orig.fRefreshFutureFunc ); - //fThreadIndicator = orig.fThreadIndicator; - fBreakFlag = orig.fBreakFlag; fContinueSignal = std::move( orig.fContinueSignal ); - fCanceled = orig.fCanceled; - fPrimaryProcName = std::move( orig.fPrimaryProcName ); - //orig.fThreadIndicator = nullptr; orig.fBreakFlag = false; orig.fCanceled = false; @@ -90,21 +74,10 @@ namespace Nymph KTWARN( trlog, "Setting value of data-ptr-ret promise (" << fName << ")" ); fDataPtrRet.set_value( dataPtr ); // wait for continue signal - //fThreadIndicator->fContinueSignal.wait(); fContinueSignal.wait(); - // reset the promise - //fDataPtrRet = KTDataPtrReturn(); - // pass the future back to the processor toolbox (if it's in use) - //fRefreshFutureFunc( fPrimaryProcName, std::move( fDataPtrRet.get_future().share() ) ); } return; } - void KTThreadReference::RefreshDataPtrRet() - { - fDataPtrRet = KTDataPtrReturn(); - fDataPtrRetFuture = fDataPtrRet.get_future(); - return; - } } /* namespace Nymph */ diff --git a/Library/Processor/KTThreadReference.hh b/Library/Processor/KTThreadReference.hh index 5e1be14..d15526e 100644 --- a/Library/Processor/KTThreadReference.hh +++ b/Library/Processor/KTThreadReference.hh @@ -16,39 +16,112 @@ namespace Nymph { - //struct KTThreadIndicator - //{ - // bool fBreakFlag; // only use outside of blocks protected by a mutex are reads, so we shouldn't need to make this an atomic - // boost::shared_future< void > fContinueSignal; - // bool fCanceled; - // KTThreadIndicator(); - //}; - - struct KTThreadReference - { - std::string fName; - KTDataPtrReturn fDataPtrRet; - boost::unique_future< KTDataPtr > fDataPtrRetFuture; - std::function< void() > fInitiateBreakFunc; - std::function< void(const std::string&, boost::shared_future< KTDataPtr >&&) > fRefreshFutureFunc; - //std::shared_ptr< KTThreadIndicator > fThreadIndicator; - bool fBreakFlag; // only use outside of blocks protected by a mutex are reads, so we shouldn't need to make this an atomic - boost::shared_future< void > fContinueSignal; - bool fCanceled; - std::string fPrimaryProcName; - - KTThreadReference(); - KTThreadReference( const KTThreadReference& ) = delete; - KTThreadReference( KTThreadReference&& orig ); - - KTThreadReference& operator=( const KTThreadReference& ) = delete; - KTThreadReference& operator=( KTThreadReference&& ); - - void Break( const KTDataPtr& dataPtr, bool doBreakpoint ); - - void RefreshDataPtrRet(); + typedef boost::promise< KTDataPtr > KTDataPtrReturn; + + class KTThreadReference + { + public: + KTThreadReference(); + KTThreadReference( const KTThreadReference& ) = delete; + KTThreadReference( KTThreadReference&& orig ); + + KTThreadReference& operator=( const KTThreadReference& ) = delete; + KTThreadReference& operator=( KTThreadReference&& ); + + public: + //************************** + // for use within the thread + //************************** + + void Break( const KTDataPtr& dataPtr, bool doBreakpoint ); + + void SetReturnException( boost::exception_ptr excPtr ); + void SetReturnValue( KTDataPtr dataPtr ); + + public: + //****************************** + // for use outside of the thread + //****************************** + + KTDataPtr GetReturnValue(); + boost::unique_future< KTDataPtr >& GetDataPtrRetFuture(); + const boost::unique_future< KTDataPtr >& GetDataPtrRetFuture() const; + + void RefreshDataPtrRet(); + + void SetContinueSignal( const boost::shared_future< void >& contSig ); + void SetInitiateBreakFunc( const std::function< void() >& initBreakFunc ); + + public: + MEMBERVARIABLEREF( std::string, Name ); + MEMBERVARIABLE( bool, BreakFlag ); + MEMBERVARIABLE( bool, Canceled ); + + private: + KTDataPtrReturn fDataPtrRet; + boost::unique_future< KTDataPtr > fDataPtrRetFuture; + std::function< void() > fInitiateBreakFunc; + boost::shared_future< void > fContinueSignal; }; + inline void KTThreadReference::SetReturnException( boost::exception_ptr excPtr ) + { + fDataPtrRet.set_exception( excPtr ); + return; + } + + inline void KTThreadReference::SetReturnValue( KTDataPtr dataPtr ) + { + fDataPtrRet.set_value( dataPtr ); + return; + } + + inline KTDataPtr KTThreadReference::GetReturnValue() + { + return fDataPtrRetFuture.get(); + } + + inline boost::unique_future< KTDataPtr >& KTThreadReference::GetDataPtrRetFuture() + { + return fDataPtrRetFuture; + } + + inline const boost::unique_future< KTDataPtr >& KTThreadReference::GetDataPtrRetFuture() const + { + return fDataPtrRetFuture; + } + + inline void KTThreadReference::RefreshDataPtrRet() + { + fDataPtrRet = KTDataPtrReturn(); + fDataPtrRetFuture = fDataPtrRet.get_future(); + return; + } + + inline void KTThreadReference::SetContinueSignal( const boost::shared_future< void >& contSig ) + { + fContinueSignal = contSig; + return; + } + + inline void KTThreadReference::SetInitiateBreakFunc( const std::function< void() >& initBreakFunc ) + { + fInitiateBreakFunc = initBreakFunc; + return; + } + +#ifndef THROW_THREADREF_EXCEPTION +#define THROW_THREADREF_EXCEPTION( ref, exc ) \ + try \ + { \ + BOOST_THROW_EXCEPTION( exc ); \ + } \ + catch( ::boost::exception& e ) \ + { \ + ref->SetReturnException( ::boost::current_exception() ); \ + } +#endif // THROW_THREADREF_EXCEPTION + } /* namespace Nymph */ #endif /* KTTHREADREFERENCE_HH_ */ From 141333d6345a903bbfcfbcfc1f529d674fefe71a Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Thu, 25 May 2017 16:34:06 -0700 Subject: [PATCH 043/521] Breaking changes to MemberVariable.hh: reference-type members now have const and non-const access functions instead of getters and setters --- Executables/Validation/KTTestCuts.cc | 4 ++-- Executables/Validation/TestApplyCut.cc | 2 +- Executables/Validation/TestCut.cc | 2 +- Executables/Validation/TestCutFilter.cc | 2 +- Executables/Validation/TestPrintData.cc | 4 ++-- Library/Application/KTPrintDataStructure.cc | 2 +- Library/Data/KTCutFilter.cc | 4 ++-- Library/Data/KTData.hh | 9 +------ Library/Utility/KTMemberVariable.hh | 26 ++++++++++----------- 9 files changed, 24 insertions(+), 31 deletions(-) diff --git a/Executables/Validation/KTTestCuts.cc b/Executables/Validation/KTTestCuts.cc index 99fb290..e66ff30 100644 --- a/Executables/Validation/KTTestCuts.cc +++ b/Executables/Validation/KTTestCuts.cc @@ -48,7 +48,7 @@ namespace Nymph bool isCut = ! testData.GetIsAwesome(); KTDEBUG(testlog, "Is data awesome? " << testData.GetIsAwesome()); KTDEBUG(testlog, "Is data cut? " << isCut); - data.GetCutStatus().AddCutResult< KTAwesomeCut::Result >(isCut); + data.CutStatus().AddCutResult< KTAwesomeCut::Result >(isCut); return isCut; } @@ -71,7 +71,7 @@ namespace Nymph KTDEBUG(testlog, "Is data awesome? " << testData.GetIsAwesome()); KTDEBUG(testlog, "Is data cut? " << isCut); // use the name-based AddCutResult - data.GetCutStatus().AddCutResult("not-awesome-cut", isCut); + data.CutStatus().AddCutResult("not-awesome-cut", isCut); return isCut; } diff --git a/Executables/Validation/TestApplyCut.cc b/Executables/Validation/TestApplyCut.cc index e808aeb..fbde4bb 100644 --- a/Executables/Validation/TestApplyCut.cc +++ b/Executables/Validation/TestApplyCut.cc @@ -20,7 +20,7 @@ int main() KTDataPtr dataPtr(new KTData()); KTTestData& testData = dataPtr->Of< KTTestData >(); - KTCutStatus& cutStatus = dataPtr->GetCutStatus(); + KTCutStatus& cutStatus = dataPtr->CutStatus(); KTINFO(testlog, "Initial cut state: " << cutStatus.IsCut()); KTApplyCut applyCut; diff --git a/Executables/Validation/TestCut.cc b/Executables/Validation/TestCut.cc index a507728..968f880 100644 --- a/Executables/Validation/TestCut.cc +++ b/Executables/Validation/TestCut.cc @@ -19,7 +19,7 @@ int main() KTData data; KTTestData& testData = data.Of< KTTestData >(); - KTCutStatus& cutStatus = data.GetCutStatus(); + KTCutStatus& cutStatus = data.CutStatus(); KTINFO(testlog, "Initial cut state: " << cutStatus.IsCut()); KTINFO(testlog, "Applying awesome cut"); diff --git a/Executables/Validation/TestCutFilter.cc b/Executables/Validation/TestCutFilter.cc index 718a8fa..d2306ec 100644 --- a/Executables/Validation/TestCutFilter.cc +++ b/Executables/Validation/TestCutFilter.cc @@ -21,7 +21,7 @@ int main() KTDataPtr dataPtr(new KTData()); KTTestData& testData = dataPtr->Of< KTTestData >(); - KTCutStatus& cutStatus = dataPtr->GetCutStatus(); + KTCutStatus& cutStatus = dataPtr->CutStatus(); KTINFO(testlog, "Initial cut state: " << cutStatus.IsCut()); KTApplyCut applyCut; diff --git a/Executables/Validation/TestPrintData.cc b/Executables/Validation/TestPrintData.cc index f37bf67..ed6fe50 100644 --- a/Executables/Validation/TestPrintData.cc +++ b/Executables/Validation/TestPrintData.cc @@ -53,7 +53,7 @@ namespace Nymph bool Apply(KTData& data, KTTestData& testData) { bool isCut = ! testData.GetIsAwesome(); - data.GetCutStatus().AddCutResult< KTAwesomeCut::Result >(isCut); + data.CutStatus().AddCutResult< KTAwesomeCut::Result >(isCut); return isCut; } @@ -90,7 +90,7 @@ namespace Nymph { bool isCut = testData.GetIsAwesome(); // use the name-based AddCutResult - data.GetCutStatus().AddCutResult("not-awesome-cut", isCut); + data.CutStatus().AddCutResult("not-awesome-cut", isCut); return isCut; } diff --git a/Library/Application/KTPrintDataStructure.cc b/Library/Application/KTPrintDataStructure.cc index dd04708..29c42e7 100644 --- a/Library/Application/KTPrintDataStructure.cc +++ b/Library/Application/KTPrintDataStructure.cc @@ -100,7 +100,7 @@ namespace Nymph { std::stringstream printbuf; - KTCutStatus& cutStatus = dataPtr->GetCutStatus(); + KTCutStatus& cutStatus = dataPtr->CutStatus(); printbuf << "\n" << cutStatus; const KTCutResult* cutResult = cutStatus.CutResults(); diff --git a/Library/Data/KTCutFilter.cc b/Library/Data/KTCutFilter.cc index af4fcb1..c8e6e9b 100644 --- a/Library/Data/KTCutFilter.cc +++ b/Library/Data/KTCutFilter.cc @@ -60,10 +60,10 @@ namespace Nymph { if (fAllBits) { - return data.GetCutStatus().IsCut(); + return data.CutStatus().IsCut(); } - KTCutStatus& cutStatus = data.GetCutStatus(); + KTCutStatus& cutStatus = data.CutStatus(); if (fConvertToBitset) { fCutMask = cutStatus.ToBitset(fCutMaskInt); diff --git a/Library/Data/KTData.hh b/Library/Data/KTData.hh index 1f93d4f..6b5a18c 100644 --- a/Library/Data/KTData.hh +++ b/Library/Data/KTData.hh @@ -57,19 +57,12 @@ namespace Nymph MEMBERVARIABLE(unsigned, Counter); MEMBERVARIABLE(bool, LastData); - MEMBERVARIABLEREF_NOSET(KTCutStatus, CutStatus); - // additional non-const get function - KTCutStatus& GetCutStatus(); + MEMBERVARIABLEREF(KTCutStatus, CutStatus); public: static const std::string sName; }; - inline KTCutStatus& KTData::GetCutStatus() - { - return fCutStatus; - } - typedef std::shared_ptr< KTData > KTDataPtr; } /* namespace Nymph */ diff --git a/Library/Utility/KTMemberVariable.hh b/Library/Utility/KTMemberVariable.hh index 4f36539..ded3ae2 100644 --- a/Library/Utility/KTMemberVariable.hh +++ b/Library/Utility/KTMemberVariable.hh @@ -54,8 +54,8 @@ /** - * Creates a member variable with type TYPE name f[NAME], plus getters and setters. - * MEMBERVARIABLEREF_NOSET will provide the variable and getter, but no setter, allowing you to provide a custom setter. + * Creates a member variable with type TYPE name f[NAME], const and non-const access functions. + * MEMBERVARIABLEREF_CONST will provide the variable and the const access function, but no non-const access function. * * Usage example, in a class header file: * MEMBERVARIABLEREF(std::string, MyVar) @@ -66,36 +66,36 @@ * private: * TYPE f[NAME]; * public: - * inline const TYPE& Get[NAME]() const + * inline const TYPE& [NAME]() const * { * return f[NAME]; * } - * inline void Set[NAME](const TYPE& var) + * inline TYPE& [NAME]() * { - * f[NAME] = var; + * return f[NAME]; * } */ -#define MEMBERVARIABLEREF_NOSET(TYPE, NAME) \ +#define MEMBERVARIABLEREF_CONST(TYPE, NAME) \ private: \ TYPE f##NAME; \ public: \ - inline const TYPE& Get##NAME() const {return f##NAME;} \ - inline TYPE& GET##NAME() {return f##NAME;} + inline const TYPE& NAME() const {return f##NAME;} \ + inline TYPE& NAME() {return f##NAME;} #define MEMBERVARIABLEREF(TYPE, NAME) \ - MEMBERVARIABLEREF_NOSET(TYPE, NAME) \ - inline void Set##NAME(const TYPE& var) {f##NAME = var; return;} + MEMBERVARIABLEREF_CONST(TYPE, NAME) \ + inline TYPE& NAME(const TYPE& var) {return f##NAME;} #define MEMBERVARIABLEREF_PROTECTED_NOSET(TYPE, NAME) \ protected: \ TYPE f##NAME; \ public: \ - inline const TYPE& Get##NAME() const {return f##NAME;} \ - inline TYPE& GET##NAME() {return f##NAME;} + inline const TYPE& NAME() const {return f##NAME;} \ + inline TYPE& NAME() {return f##NAME;} #define MEMBERVARIABLEREF_PROTECTED(TYPE, NAME) \ MEMBERVARIABLEREF_PROTECTED_NOSET(TYPE, NAME) \ - inline void Set##NAME(const TYPE& var) {f##NAME = var; return;} + inline TYPE& NAME() {return f##NAME;} #endif /* KTMEMBERVARIABLE_HH_ */ From 8503de9fd435461879f73ab11cbc11a49a96ba96 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Thu, 25 May 2017 16:47:51 -0700 Subject: [PATCH 044/521] Updating the scarab commit, and some cleanup --- Executables/Validation/TestExceptionInSlot.cc | 6 --- .../Validation/TestPrimaryProcessor.cc | 2 - Library/Application/KTProcessorToolbox.cc | 52 +++---------------- Library/Application/KTProcessorToolbox.hh | 19 +------ Scarab | 2 +- 5 files changed, 9 insertions(+), 72 deletions(-) diff --git a/Executables/Validation/TestExceptionInSlot.cc b/Executables/Validation/TestExceptionInSlot.cc index 2f889d0..6961c6b 100644 --- a/Executables/Validation/TestExceptionInSlot.cc +++ b/Executables/Validation/TestExceptionInSlot.cc @@ -30,7 +30,6 @@ int main() // setup to execute processors asynchronously std::shared_ptr< KTThreadReference > exeThreadRef = std::make_shared< KTThreadReference >(); - //boost::shared_future< KTDataPtr > exeThreadFuture = exeThreadRef->fDataPtrRetFuture; tpC.GetSlot( "first-slot" )->SetThreadRef( exeThreadRef ); std::atomic< bool > canceled( false ); @@ -70,11 +69,6 @@ int main() { exeThreadRef->GetReturnValue(); } - //catch( std::exception& e ) - //{ - // canceled = true; - // KTERROR( testexclog, "An error occurred while running a processor: " << e.what() ); - //} catch( boost::exception& e ) { canceled = true; diff --git a/Executables/Validation/TestPrimaryProcessor.cc b/Executables/Validation/TestPrimaryProcessor.cc index 21a7aee..0fc9499 100644 --- a/Executables/Validation/TestPrimaryProcessor.cc +++ b/Executables/Validation/TestPrimaryProcessor.cc @@ -28,8 +28,6 @@ int main() tpp.ConnectASlot( "the-signal", &tp, "first-slot", 20 ); // setup to execute processors asynchronously - //KTThreadReference exeThreadRef; - //auto exeThreadFuture = exeThreadRef.fDataPtrRet.get_future(); std::shared_ptr< KTThreadReference > exeThreadRef( std::make_shared< KTThreadReference >() ); exeThreadRef->Name() = std::string( "tpp" ); diff --git a/Library/Application/KTProcessorToolbox.cc b/Library/Application/KTProcessorToolbox.cc index 839e355..eb41286 100644 --- a/Library/Application/KTProcessorToolbox.cc +++ b/Library/Application/KTProcessorToolbox.cc @@ -33,8 +33,7 @@ namespace Nymph fRunQueue(), fProcMap(), fThreadReferences(), - fThreadFuturesMutex(), - //fThreadFutures(), + fThreadReferencesMutex(), fContinueSignaler(), fMasterContSignal(), fBreakContMutex(), @@ -617,32 +616,17 @@ namespace Nymph { for (ThreadGroup::iterator tgIter = rqIter->begin(); tgIter != rqIter->end(); ++tgIter) { - boost::unique_lock< boost::mutex > threadFuturesLock( fThreadFuturesMutex ); + boost::unique_lock< boost::mutex > threadFuturesLock( fThreadReferencesMutex ); std::string procName( tgIter->fName ); KTINFO( proclog, "Starting processor <" << procName << ">" ); - //KTThreadReference thisThreadRef; std::shared_ptr< KTThreadReference > thisThreadRef = std::make_shared< KTThreadReference >(); thisThreadRef->Name() = procName; - //fThreadFutures.push_back( std::move( thisThreadRef.fDataPtrRet.get_future() ) ); - //fThreadNames.push_back( procName ); - //auto& futureNameIndex = fThreadFutures.get<1>(); - - //if( ! fThreadFutures.back().valid() ) - //{ - // KTERROR( proclog, "Invalid thread future created" ); - // BOOST_THROW_EXCEPTION( KTException() << "Invalid thread future created"; - //} - - //fThreadIndicators.emplace_back( new KTThreadIndicator() ); - //fThreadIndicators.back()->fContinueSignal = fMasterContSignal; thisThreadRef->SetContinueSignal( fMasterContSignal ); - //thisThreadRef->fThreadIndicator = fThreadIndicators.back(); thisThreadRef->SetInitiateBreakFunc( [&](){ this->InitiateBreak(); } ); - //thisThreadRef->fRefreshFutureFunc = [&]( const std::string& name, Future&& ret ){ this->TakeFuture( name, std::move(ret) ); }; fThreadReferences.push_back( thisThreadRef ); @@ -702,8 +686,6 @@ namespace Nymph thread.join(); fThreadReferences.clear(); - //fThreadFutures.clear(); - //fThreadNames.clear(); } // end for loop over the thread group } // end for loop over the run-queue @@ -756,27 +738,19 @@ namespace Nymph boost::thread_group threads; { // scope for threadFuturesLock - boost::unique_lock< boost::mutex > threadFuturesLock( fThreadFuturesMutex ); + boost::unique_lock< boost::mutex > threadFuturesLock( fThreadReferencesMutex ); for (ThreadGroup::iterator tgIter = rqIter->begin(); tgIter != rqIter->end(); ++tgIter) { std::string procName( tgIter->fName ); KTINFO( proclog, "Starting processor <" << procName << ">" ); - //KTThreadReference thisThreadRef; std::shared_ptr< KTThreadReference > thisThreadRef = std::make_shared< KTThreadReference >(); thisThreadRef->Name() = procName; - //fThreadFutures.push_back( std::move( thisThreadRef.fDataPtrRet.get_future() ) ); - //fThreadNames.push_back( procName ); - - //fThreadIndicators.emplace_back( new KTThreadIndicator() ); - //fThreadIndicators.back()->fContinueSignal = fMasterContSignal; thisThreadRef->SetContinueSignal( fMasterContSignal ); - //thisThreadRef->fThreadIndicator = fThreadIndicators.back(); thisThreadRef->SetInitiateBreakFunc( [&](){ this->InitiateBreak(); } ); - //thisThreadRef->fRefreshFutureFunc = [&]( const std::string& name, Future&& ret ){ this->TakeFuture( name, std::move(ret) ); }; boost::condition_variable threadStartedCV; boost::mutex threadStartedMutex; bool threadStartedFlag = false; @@ -800,10 +774,7 @@ namespace Nymph bool stillRunning = true; // determines behavior that depends on whether a return from the thread was temporary or from the thread completing do { - boost::unique_lock< boost::mutex > threadFuturesLock( fThreadFuturesMutex ); - //KTThreadRefFutureIterator finishedFuturePtr( fThreadReferences.begin()); - //auto finishedFuturePtr = boost::wait_for_any( futureIndex.begin(), futureIndex.end() ); - //auto finishedFuturePtr = boost::wait_for_any( fThreadFutures.begin(), fThreadFutures.end() ); + boost::unique_lock< boost::mutex > threadFuturesLock( fThreadReferencesMutex ); auto finishedFuturePtr = boost::wait_for_any( KTThreadRefFutureIterator(fThreadReferences.begin()), KTThreadRefFutureIterator(fThreadReferences.end()) ); size_t iThread = finishedFuturePtr - KTThreadRefFutureIterator(fThreadReferences.begin()); auto finishedReferencePtr = fThreadReferences.begin() + iThread; @@ -830,13 +801,10 @@ namespace Nymph // we're finished a thread; get its results try { - //futureIndex.modify( finishedFuturePtr, [](LabeledFuture& lFuture){ lFuture.fFuture.get(); } ); //KTINFO( proclog, "Thread <" << threadName << "> has finished" ); KTWARN( proclog, "Thread <" << threadName << "> has finished" ); // TODO: switch this back to INFO finishedFuturePtr->get(); fThreadReferences.erase( finishedReferencePtr ); - //fThreadFutures.erase( finishedFuturePtr ); - //fThreadNames.erase( fThreadNames.begin() + iThread ); } catch( boost::exception& e ) { @@ -851,11 +819,8 @@ namespace Nymph KTDEBUG( proclog, "Joining threads" ); threads.join_all(); - //fThreadIndicators.clear(); - boost::unique_lock< boost::mutex > threadFuturesLock( fThreadFuturesMutex ); + boost::unique_lock< boost::mutex > threadFuturesLock( fThreadReferencesMutex ); fThreadReferences.clear(); - //fThreadFutures.clear(); - //fThreadNames.clear(); } // end for loop over the run-queue KTPROG( proclog, "Processing is complete (multi-threaded)" ); @@ -951,10 +916,7 @@ namespace Nymph } boost::unique_lock< boost::mutex > breakContLock( fBreakContMutex ); - boost::unique_lock< boost::mutex > threadFuturesLock( fThreadFuturesMutex ); - - // futures have been used; clear them to be replaced - //fThreadFutures.clear(); + boost::unique_lock< boost::mutex > threadFuturesLock( fThreadReferencesMutex ); // reset all break flags fDoRunBreakFlag = false; @@ -987,7 +949,7 @@ namespace Nymph KTDataPtr KTProcessorToolbox::GetData( const std::string& threadName ) { - boost::unique_lock< boost::mutex > threadFuturesLock( fThreadFuturesMutex ); + boost::unique_lock< boost::mutex > threadFuturesLock( fThreadReferencesMutex ); auto tnIt = fThreadReferences.begin(); for( ; tnIt != fThreadReferences.end(); ++tnIt ) diff --git a/Library/Application/KTProcessorToolbox.hh b/Library/Application/KTProcessorToolbox.hh index b05cb6d..bb7c5ce 100644 --- a/Library/Application/KTProcessorToolbox.hh +++ b/Library/Application/KTProcessorToolbox.hh @@ -239,19 +239,9 @@ namespace Nymph // called from ThreadPacket::Break void InitiateBreak(); // called from ThreadPacket::Break - //void TakeFuture( const std::string& name, Future&& future ); std::vector< std::shared_ptr< KTThreadReference > > fThreadReferences; - - //typedef std::vector< Future > ThreadFutures; - //typedef std::vector< std::string > ThreadNames; - - //ThreadFutures fThreadFutures; - //ThreadNames fThreadNames; - boost::mutex fThreadFuturesMutex; - - //typedef std::vector< std::shared_ptr< KTThreadIndicator > > ThreadIndicators; - //ThreadIndicators fThreadIndicators; + boost::mutex fThreadReferencesMutex; boost::promise< void > fContinueSignaler; boost::shared_future< void > fMasterContSignal; @@ -316,13 +306,6 @@ namespace Nymph return; } - //inline void KTProcessorToolbox::TakeFuture( const std::string& name, Future&& future ) - //{ - // fThreadFutures.push_back( std::move( future ) ); - // fThreadNames.push_back( name ); - // return; - //} - inline void KTProcessorToolbox::JoinRunThread() { if( fDoRunThread == nullptr ) return; diff --git a/Scarab b/Scarab index d6eb49f..6362897 160000 --- a/Scarab +++ b/Scarab @@ -1 +1 @@ -Subproject commit d6eb49f445a7d675e3e76b56ba12b175dca10d92 +Subproject commit 6362897c81362b0ad90e55f1d2c9bbd703f20b93 From 9b28f2d3229df7d2ae54ee7dcdb4fe7fafac7112 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Fri, 26 May 2017 15:44:33 -0700 Subject: [PATCH 045/521] Settled on method for adding messages to KTExceptions. Added a mutex to KTThreadReference. Use a condition_variable instead of a promise/future to indicate continuing processing. --- Executables/Validation/TestExceptionInSlot.cc | 4 + Library/Application/KTProcessorToolbox.cc | 140 +++++++----------- Library/Application/KTProcessorToolbox.hh | 21 ++- Library/Processor/KTProcessor.cc | 14 +- Library/Processor/KTThreadReference.cc | 11 +- Library/Processor/KTThreadReference.hh | 30 +++- Library/Utility/KTException.cc | 12 +- Library/Utility/KTException.hh | 21 +-- Scarab | 2 +- 9 files changed, 122 insertions(+), 133 deletions(-) diff --git a/Executables/Validation/TestExceptionInSlot.cc b/Executables/Validation/TestExceptionInSlot.cc index 6961c6b..bc4887c 100644 --- a/Executables/Validation/TestExceptionInSlot.cc +++ b/Executables/Validation/TestExceptionInSlot.cc @@ -8,6 +8,8 @@ */ #include "KTTestProcessor.hh" + +#include "KTException.hh" #include "KTLogger.hh" #include @@ -72,6 +74,8 @@ int main() catch( boost::exception& e ) { canceled = true; + //ADD_ERROR_MSG( e, "Added error message!" ); + e << KTErrorMsgInfo< struct testEIS_GetRetVal >( "Added error message!" ); KTERROR( testexclog, "An error occurred while running a processor: " << diagnostic_information( e ) ); } diff --git a/Library/Application/KTProcessorToolbox.cc b/Library/Application/KTProcessorToolbox.cc index eb41286..27ba8c2 100644 --- a/Library/Application/KTProcessorToolbox.cc +++ b/Library/Application/KTProcessorToolbox.cc @@ -33,9 +33,8 @@ namespace Nymph fRunQueue(), fProcMap(), fThreadReferences(), - fThreadReferencesMutex(), - fContinueSignaler(), - fMasterContSignal(), + fContinueCV(), + fDoContinue( false ), fBreakContMutex(), fDoRunThread( nullptr ), fDoRunPromise(), @@ -599,24 +598,13 @@ namespace Nymph { try { - // reset the continue signaler - fContinueSignaler = boost::promise< void >(); - fMasterContSignal = fContinueSignaler.get_future().share(); - if( ! fMasterContSignal.valid() ) - { - KTERROR( proclog, "Invalid master continue-signal created" ); - BOOST_THROW_EXCEPTION( KTException() << "Invalid master continue-signal created" << eom ); - } - // copy for use in this function - boost::shared_future< void > continueSignal = fMasterContSignal; - KTPROG( proclog, "Starting single-threaded processing" ); for (RunQueue::iterator rqIter = fRunQueue.begin(); rqIter != fRunQueue.end(); ++rqIter) { for (ThreadGroup::iterator tgIter = rqIter->begin(); tgIter != rqIter->end(); ++tgIter) { - boost::unique_lock< boost::mutex > threadFuturesLock( fThreadReferencesMutex ); + boost_unique_lock breakContLock( fBreakContMutex ); std::string procName( tgIter->fName ); KTINFO( proclog, "Starting processor <" << procName << ">" ); @@ -624,9 +612,8 @@ namespace Nymph std::shared_ptr< KTThreadReference > thisThreadRef = std::make_shared< KTThreadReference >(); thisThreadRef->Name() = procName; - thisThreadRef->SetContinueSignal( fMasterContSignal ); - thisThreadRef->SetInitiateBreakFunc( [&](){ this->InitiateBreak(); } ); + thisThreadRef->SetWaitForContinueFunc( [&]( boost_unique_lock& lock ){ this->WaitForContinue( lock ); } ); fThreadReferences.push_back( thisThreadRef ); @@ -634,7 +621,7 @@ namespace Nymph boost::mutex threadStartedMutex; bool threadStartedFlag = false; - boost::unique_lock< boost::mutex > threadStartedLock( threadStartedMutex ); + boost_unique_lock threadStartedLock( threadStartedMutex ); boost::thread thread( [&](){ tgIter->fProc->operator()( thisThreadRef, threadStartedCV, threadStartedFlag ); } ); KTDEBUG( proclog, "Thread ID is <" << thread.get_id() << ">; waiting for thread start" ); while( ! threadStartedFlag ) @@ -645,8 +632,6 @@ namespace Nymph KTDEBUG( proclog, "Thread ID is <" << thread.get_id() << ">" ); - threadFuturesLock.unlock(); - bool stillRunning = true; // determines behavior that depends on whether a return from the thread was temporary or from the thread completing do { @@ -660,10 +645,11 @@ namespace Nymph if( fThreadReferences.back()->GetBreakFlag() ) { KTDEBUG( proclog, "Breakpoint reached (seen first in thread <" << procName << ">; may not be where breakpoint is set)" ); - continueSignal.wait(); + + WaitForContinue( breakContLock ); + KTDEBUG( proclog, "Breakpoint finished" ); stillRunning = true; - continueSignal = fMasterContSignal; // refresh the local copy of the shared future } else { @@ -675,7 +661,7 @@ namespace Nymph } catch( boost::exception& e ) { - e << KTErrorMsgInfo( "There was an error while finishing thread <" + procName + "> and retrieving its results" ); + e << KTErrorMsgInfo< struct procTB_STRFinishing >( "There was an error while finishing thread <" + procName + "> and retrieving its results" ); throw; } stillRunning = false; @@ -720,17 +706,6 @@ namespace Nymph { try { - // reset the continue signaler - fContinueSignaler = boost::promise< void >(); - fMasterContSignal = fContinueSignaler.get_future().share(); - if( ! fMasterContSignal.valid() ) - { - KTERROR( proclog, "Invalid master continue-signal created" ); - BOOST_THROW_EXCEPTION( KTException() << "Invalid master continue-signal created" << eom ); - } - // copy for use in this function - boost::shared_future< void > continueSignal = fMasterContSignal; - KTPROG( proclog, "Starting multi-threaded processing" ); for (RunQueue::iterator rqIter = fRunQueue.begin(); rqIter != fRunQueue.end(); ++rqIter) @@ -738,7 +713,8 @@ namespace Nymph boost::thread_group threads; { // scope for threadFuturesLock - boost::unique_lock< boost::mutex > threadFuturesLock( fThreadReferencesMutex ); + boost_unique_lock breakContLock( fBreakContMutex ); + //boost_unique_lock threadFuturesLock( fThreadReferencesMutex ); for (ThreadGroup::iterator tgIter = rqIter->begin(); tgIter != rqIter->end(); ++tgIter) { @@ -748,16 +724,15 @@ namespace Nymph std::shared_ptr< KTThreadReference > thisThreadRef = std::make_shared< KTThreadReference >(); thisThreadRef->Name() = procName; - thisThreadRef->SetContinueSignal( fMasterContSignal ); - thisThreadRef->SetInitiateBreakFunc( [&](){ this->InitiateBreak(); } ); + thisThreadRef->SetWaitForContinueFunc( [&]( boost_unique_lock& lock ){ this->WaitForContinue( lock ); } ); + fThreadReferences.push_back( thisThreadRef ); + boost::condition_variable threadStartedCV; boost::mutex threadStartedMutex; bool threadStartedFlag = false; - fThreadReferences.push_back( thisThreadRef ); - - boost::unique_lock< boost::mutex > threadStartedLock( threadStartedMutex ); + boost_unique_lock threadStartedLock( threadStartedMutex ); boost::thread* thisThread = new boost::thread( [&](){ tgIter->fProc->operator()( thisThreadRef, threadStartedCV, threadStartedFlag ); } ); KTDEBUG( proclog, "Thread ID is <" << thisThread->get_id() << ">; waiting for thread start" ); while( ! threadStartedFlag ) @@ -774,41 +749,39 @@ namespace Nymph bool stillRunning = true; // determines behavior that depends on whether a return from the thread was temporary or from the thread completing do { - boost::unique_lock< boost::mutex > threadFuturesLock( fThreadReferencesMutex ); auto finishedFuturePtr = boost::wait_for_any( KTThreadRefFutureIterator(fThreadReferences.begin()), KTThreadRefFutureIterator(fThreadReferences.end()) ); + boost_unique_lock breakContLock( fBreakContMutex ); + size_t iThread = finishedFuturePtr - KTThreadRefFutureIterator(fThreadReferences.begin()); auto finishedReferencePtr = fThreadReferences.begin() + iThread; std::string threadName( (*finishedReferencePtr)->Name() ); - //KTDEBUG( proclog, "Thread <" << iThread << " (" << threadName << ") > has stopped for some reason" ); - KTWARN( proclog, "Thread <" << iThread << " (" << threadName << ") > has stopped for some reason" ); // TODO: switch this back to DEBUG + KTDEBUG( proclog, "Thread <" << iThread << " (" << threadName << ") > has stopped for some reason" ); stillRunning = false; if( fDoRunBreakFlag ) { // a breakpoint has been reached - //KTDEBUG( proclog, "Breakpoint reached (seen first in thread <" << threadName << ">; may not be where breakpoint is set)" ); - KTWARN( proclog, "Breakpoint reached (seen first in thread <" << threadName << ">; may not be where breakpoint is set)" ); //TODO: switch this back to debug - threadFuturesLock.unlock(); + KTDEBUG( proclog, "Breakpoint reached (seen first in thread <" << threadName << ">; may not be where breakpoint is set)" ); + // wait here for the user to continue - continueSignal.wait(); + WaitForContinue( breakContLock ); + KTDEBUG( proclog, "Breakpoint finished" ); - boost::unique_lock< boost::mutex > breakContLock( fBreakContMutex ); stillRunning = true; - continueSignal = fMasterContSignal; // refresh the local copy of the shared future + //continueSignal = fMasterContSignal; // refresh the local copy of the shared future } else { // we're finished a thread; get its results try { - //KTINFO( proclog, "Thread <" << threadName << "> has finished" ); - KTWARN( proclog, "Thread <" << threadName << "> has finished" ); // TODO: switch this back to INFO + KTINFO( proclog, "Thread <" << threadName << "> has finished" ); finishedFuturePtr->get(); fThreadReferences.erase( finishedReferencePtr ); } catch( boost::exception& e ) { - e << KTErrorMsgInfo( "There was an error while finishing thread <" + threadName + "> and retrieving its results" ); + e << KTErrorMsgInfo< struct procTB_MTRFinishing >( "There was an error while finishing thread <" + threadName + "> and retrieving its results" ); throw; } @@ -819,7 +792,7 @@ namespace Nymph KTDEBUG( proclog, "Joining threads" ); threads.join_all(); - boost::unique_lock< boost::mutex > threadFuturesLock( fThreadReferencesMutex ); + boost_unique_lock breakContLock( fBreakContMutex ); fThreadReferences.clear(); } // end for loop over the run-queue @@ -853,7 +826,7 @@ namespace Nymph bool KTProcessorToolbox::WaitForBreak() { - boost::unique_lock< boost::mutex > breakContLock( fBreakContMutex ); + boost_unique_lock breakContLock( fBreakContMutex ); if( fDoRunBreakFlag ) { @@ -899,7 +872,9 @@ namespace Nymph while( WaitForBreak() ) { KTDEBUG( proclog, "Reached breakpoint; waiting for continue" ); - WaitForContinue(); + boost::mutex localMutex; + boost_unique_lock localLock( localMutex ); + WaitForContinue( localLock ); KTDEBUG( proclog, "Processing resuming; waiting for end-of-run" ); } KTDEBUG( proclog, "End-of-run reached" ); @@ -915,15 +890,16 @@ namespace Nymph return; } - boost::unique_lock< boost::mutex > breakContLock( fBreakContMutex ); - boost::unique_lock< boost::mutex > threadFuturesLock( fThreadReferencesMutex ); + boost_unique_lock breakContLock( fBreakContMutex ); // reset all break flags fDoRunBreakFlag = false; - for( auto tiIt = fThreadReferences.begin(); tiIt != fThreadReferences.end(); ++tiIt ) + std::vector< boost_unique_lock > trLocks; + for( auto trIt = fThreadReferences.begin(); trIt != fThreadReferences.end(); ++trIt ) { - (*tiIt)->SetBreakFlag( false ); - (*tiIt)->RefreshDataPtrRet(); + trLocks.emplace_back( (*trIt)->Mutex() ); + (*trIt)->SetBreakFlag( false ); + (*trIt)->RefreshDataPtrRet(); } // reset the do-run promise and future @@ -932,51 +908,48 @@ namespace Nymph KTINFO( proclog, "Continuing from breakpoint" ); // signal everything to resume - KTWARN( proclog, "Setting value of continue-signaler promise" ); - fContinueSignaler.set_value(); - - // reset the signaler and all signals - // hopefully the delay of creating the new signaler and starting the for loop is enough that anything waiting on the old signal has already seen that signal and moved on - fContinueSignaler = boost::promise< void >(); - fMasterContSignal = fContinueSignaler.get_future().share(); - for( auto tiIt = fThreadReferences.begin(); tiIt != fThreadReferences.end(); ++tiIt ) - { - (*tiIt)->SetContinueSignal( fMasterContSignal ); - } + fDoContinue = true; + fContinueCV.notify_all(); return; } KTDataPtr KTProcessorToolbox::GetData( const std::string& threadName ) { - boost::unique_lock< boost::mutex > threadFuturesLock( fThreadReferencesMutex ); + //boost_unique_lock threadFuturesLock( fThreadReferencesMutex ); + boost_unique_lock breakContLock( fBreakContMutex ); - auto tnIt = fThreadReferences.begin(); - for( ; tnIt != fThreadReferences.end(); ++tnIt ) + auto trIt = fThreadReferences.begin(); + for( ; trIt != fThreadReferences.end(); ++trIt ) { - if( (*tnIt)->Name() == threadName ) break; + if( (*trIt)->Name() == threadName ) break; } - if( tnIt == fThreadReferences.end() ) + if( trIt == fThreadReferences.end() ) { KTWARN( proclog, "Did not find thread <" << threadName << ">" ); BOOST_THROW_EXCEPTION( KTException() << "Did not find thread <" << threadName << ">" << eom ); } - return (*tnIt)->GetReturnValue(); + boost_unique_lock lock( (*trIt)->Mutex() ); + return (*trIt)->GetReturnValue(); } void KTProcessorToolbox::InitiateBreak() { - boost::unique_lock< boost::mutex > breakContLock( fBreakContMutex ); + boost_unique_lock breakContLock( fBreakContMutex ); if( fDoRunBreakFlag ) return; + // set the continue flag to false so that things will wait for the continue + fDoContinue = false; + // set all break flags // master break flag fDoRunBreakFlag = true; // thread break flags - for( auto tiIt = fThreadReferences.begin(); tiIt != fThreadReferences.end(); ++tiIt ) + for( auto trIt = fThreadReferences.begin(); trIt != fThreadReferences.end(); ++trIt ) { - (*tiIt)->SetBreakFlag( true ); + boost_unique_lock lock( (*trIt)->Mutex() ); + (*trIt)->SetBreakFlag( true ); } // use the do-run promise to signal the break @@ -988,10 +961,11 @@ namespace Nymph void KTProcessorToolbox::CancelThreads() { - boost::unique_lock< boost::mutex > breakContLock( fBreakContMutex ); - for( auto tiIt = fThreadReferences.begin(); tiIt != fThreadReferences.end(); ++tiIt ) + boost_unique_lock breakContLock( fBreakContMutex ); + for( auto trIt = fThreadReferences.begin(); trIt != fThreadReferences.end(); ++trIt ) { - (*tiIt)->SetCanceled( true ); + boost_unique_lock lock( (*trIt)->Mutex() ); + (*trIt)->SetCanceled( true ); } return; } diff --git a/Library/Application/KTProcessorToolbox.hh b/Library/Application/KTProcessorToolbox.hh index bb7c5ce..59df4d2 100644 --- a/Library/Application/KTProcessorToolbox.hh +++ b/Library/Application/KTProcessorToolbox.hh @@ -85,6 +85,9 @@ namespace Nymph */ class KTProcessorToolbox : public KTConfigurable { + private: + typedef boost::unique_lock< boost::mutex > boost_unique_lock; + public: KTProcessorToolbox(const std::string& name = "processor-toolbox"); virtual ~KTProcessorToolbox(); @@ -210,7 +213,7 @@ namespace Nymph void AsyncRun(); - void WaitForContinue(); + void WaitForContinue( boost_unique_lock& lock ); /// Returns when processing is completed or a breakpoint is reached /// Throws a boost::exception if there's an error with the future object in use @@ -236,15 +239,13 @@ namespace Nymph void StartSingleThreadedRun(); void StartMultiThreadedRun(); - // called from ThreadPacket::Break + // called from KTThreadReference::Break void InitiateBreak(); - // called from ThreadPacket::Break std::vector< std::shared_ptr< KTThreadReference > > fThreadReferences; - boost::mutex fThreadReferencesMutex; - boost::promise< void > fContinueSignaler; - boost::shared_future< void > fMasterContSignal; + boost::condition_variable fContinueCV; + bool fDoContinue; boost::mutex fBreakContMutex; boost::thread* fDoRunThread; @@ -300,9 +301,13 @@ namespace Nymph return; } - inline void KTProcessorToolbox::WaitForContinue() + inline void KTProcessorToolbox::WaitForContinue( boost_unique_lock& lock ) { - fMasterContSignal.wait(); + //fMasterContSignal.wait(); + while( ! fDoContinue ) + { + fContinueCV.wait( lock ); + } return; } diff --git a/Library/Processor/KTProcessor.cc b/Library/Processor/KTProcessor.cc index ff5eeaa..0ba0806 100644 --- a/Library/Processor/KTProcessor.cc +++ b/Library/Processor/KTProcessor.cc @@ -60,25 +60,25 @@ namespace Nymph } catch( KTSignalException& e ) { - e << KTErrorMsgInfo( "Unable to connect signal <" + signalName + "> to slot <" + slotName + "> due to a problem with the signal." ); - e << KTErrorMsgInfo( "You may have the signal name wrong." ); + e << KTErrorMsgInfo< struct proc_Sig_0 >( "Unable to connect signal <" + signalName + "> to slot <" + slotName + "> due to a problem with the signal." ); + e << KTErrorMsgInfo< struct proc_Sig_1 >( "You may have the signal name wrong." ); throw; } catch( KTSlotException& e ) { - e << KTErrorMsgInfo( "Unable to connect signal <" + signalName + "> to slot <" + slotName + "> due to a problem with the slot." ); - e << KTErrorMsgInfo( "You may have the slot name wrong." ); + e << KTErrorMsgInfo< struct proc_Slot_0 >( "Unable to connect signal <" + signalName + "> to slot <" + slotName + "> due to a problem with the slot." ); + e << KTErrorMsgInfo< struct proc_Slot_1 >( "You may have the slot name wrong." ); throw; } catch( KTConnectionException& e ) { - e << KTErrorMsgInfo( "Unable to connect signal <" + signalName + "> to slot <" + slotName + "> due to a problem making the connection." ); - e << KTErrorMsgInfo( "Check that the signatures of the signal and slot match exactly." ); + e << KTErrorMsgInfo< struct proc_Conn_0 >( "Unable to connect signal <" + signalName + "> to slot <" + slotName + "> due to a problem making the connection." ); + e << KTErrorMsgInfo< struct proc_Conn_1 >( "Check that the signatures of the signal and slot match exactly." ); throw; } catch( boost::exception& e ) { - e << KTErrorMsgInfo( "Unable to connect signal <" + signalName + "> to slot <" + slotName + "> for an unknown reason." ); + e << KTErrorMsgInfo< struct proc_Unkn >( "Unable to connect signal <" + signalName + "> to slot <" + slotName + "> for an unknown reason." ); throw; } diff --git a/Library/Processor/KTThreadReference.cc b/Library/Processor/KTThreadReference.cc index c934fd2..c5de273 100644 --- a/Library/Processor/KTThreadReference.cc +++ b/Library/Processor/KTThreadReference.cc @@ -22,7 +22,8 @@ namespace Nymph fDataPtrRet(), fDataPtrRetFuture( fDataPtrRet.get_future() ), fInitiateBreakFunc( [](){return;} ), - fContinueSignal() + fWaitForContinueFunc( []( boost_unique_lock& ){return;} ), + fMutex() { if( ! fDataPtrRetFuture.valid() ) { @@ -38,7 +39,8 @@ namespace Nymph fDataPtrRet( std::move( orig.fDataPtrRet ) ), fDataPtrRetFuture( std::move( orig.fDataPtrRetFuture ) ), fInitiateBreakFunc( std::move( orig.fInitiateBreakFunc ) ), - fContinueSignal( std::move( orig.fContinueSignal ) ) + fWaitForContinueFunc( std::move( orig.fWaitForContinueFunc ) ), + fMutex() { orig.fBreakFlag = false; orig.fCanceled = false; @@ -52,7 +54,7 @@ namespace Nymph fDataPtrRet = std::move( orig.fDataPtrRet ); fDataPtrRetFuture = std::move( orig.fDataPtrRetFuture ); fInitiateBreakFunc = std::move( orig.fInitiateBreakFunc ); - fContinueSignal = std::move( orig.fContinueSignal ); + fWaitForContinueFunc = std::move( orig.fWaitForContinueFunc ); orig.fBreakFlag = false; orig.fCanceled = false; @@ -67,6 +69,7 @@ namespace Nymph KTDEBUG( trlog, "Initiating break (" << fName << ")" ); fInitiateBreakFunc(); } + boost_unique_lock lock( fMutex ); if( fBreakFlag || doBreakpoint ) { KTDEBUG( trlog, "Reacting to break (" << fName << ")" ); @@ -74,7 +77,7 @@ namespace Nymph KTWARN( trlog, "Setting value of data-ptr-ret promise (" << fName << ")" ); fDataPtrRet.set_value( dataPtr ); // wait for continue signal - fContinueSignal.wait(); + fWaitForContinueFunc( lock ); } return; } diff --git a/Library/Processor/KTThreadReference.hh b/Library/Processor/KTThreadReference.hh index d15526e..9a963b5 100644 --- a/Library/Processor/KTThreadReference.hh +++ b/Library/Processor/KTThreadReference.hh @@ -20,6 +20,9 @@ namespace Nymph class KTThreadReference { + private: + typedef boost::unique_lock< boost::mutex > boost_unique_lock; + public: KTThreadReference(); KTThreadReference( const KTThreadReference& ) = delete; @@ -49,8 +52,11 @@ namespace Nymph void RefreshDataPtrRet(); - void SetContinueSignal( const boost::shared_future< void >& contSig ); void SetInitiateBreakFunc( const std::function< void() >& initBreakFunc ); + void SetWaitForContinueFunc( const std::function< void( boost_unique_lock& ) >& waitForContFunc ); + + boost::mutex& Mutex(); + const boost::mutex& Mutex() const; public: MEMBERVARIABLEREF( std::string, Name ); @@ -61,7 +67,8 @@ namespace Nymph KTDataPtrReturn fDataPtrRet; boost::unique_future< KTDataPtr > fDataPtrRetFuture; std::function< void() > fInitiateBreakFunc; - boost::shared_future< void > fContinueSignal; + std::function< void( boost_unique_lock& ) > fWaitForContinueFunc; + boost::mutex fMutex; }; inline void KTThreadReference::SetReturnException( boost::exception_ptr excPtr ) @@ -98,18 +105,29 @@ namespace Nymph return; } - inline void KTThreadReference::SetContinueSignal( const boost::shared_future< void >& contSig ) + inline void KTThreadReference::SetInitiateBreakFunc( const std::function< void() >& initBreakFunc ) { - fContinueSignal = contSig; + fInitiateBreakFunc = initBreakFunc; return; } - inline void KTThreadReference::SetInitiateBreakFunc( const std::function< void() >& initBreakFunc ) + inline void KTThreadReference::SetWaitForContinueFunc( const std::function< void( boost_unique_lock& ) >& waitForContFunc ) { - fInitiateBreakFunc = initBreakFunc; + fWaitForContinueFunc = waitForContFunc; return; } + inline boost::mutex& KTThreadReference::Mutex() + { + return fMutex; + } + + inline const boost::mutex& KTThreadReference::Mutex() const + { + return fMutex; + } + + #ifndef THROW_THREADREF_EXCEPTION #define THROW_THREADREF_EXCEPTION( ref, exc ) \ try \ diff --git a/Library/Utility/KTException.cc b/Library/Utility/KTException.cc index 62d0810..96e8df5 100644 --- a/Library/Utility/KTException.cc +++ b/Library/Utility/KTException.cc @@ -13,7 +13,7 @@ namespace Nymph KTException::KTException() : boost::exception(), std::exception(), - fMsgBuffer( "" ) + fMsgBuffer() { } KTException::KTException( const KTException& an_exception ) : @@ -27,14 +27,4 @@ namespace Nymph { } - const char* KTException::what() const throw () - { - if( ! fMsgBuffer.empty() ) - { - *this << KTErrorMsgInfo{ fMsgBuffer }; - fMsgBuffer.clear(); - } - return this->std::exception::what(); - } - } diff --git a/Library/Utility/KTException.hh b/Library/Utility/KTException.hh index c2b256c..10ae966 100644 --- a/Library/Utility/KTException.hh +++ b/Library/Utility/KTException.hh @@ -9,6 +9,8 @@ #ifndef KTEXCEPTION_HH_ #define KTEXCEPTION_HH_ +#include "macros.hh" + #include #include @@ -20,7 +22,10 @@ namespace Nymph struct KTMessageEnd {}; static const KTMessageEnd eom = KTMessageEnd(); - typedef boost::error_info KTErrorMsgInfo; + //typedef boost::error_info KTErrorMsgInfo; + + template< class XLabel > + using KTErrorMsgInfo = boost::error_info< XLabel, std::string>; /*! @class KTException @@ -47,7 +52,7 @@ namespace Nymph } catch( boost::exception& e ) { - e << KTErrorMsgInfo( "Here's some information about the context in which the exception was thrown" ); + e << KTErrorMsgInfo< struct UniqueLocationTag >( "Here's some information about the context in which the exception was thrown" ); throw; } @@ -82,11 +87,6 @@ namespace Nymph // adds the current contents of the message buffer as a KTErrorMsgInfo KTException& operator<<( const KTMessageEnd& eom ); - // overload for KTErrorMsgInfo to make sure error messages are streamed correctly, and not via the template function - const KTException& operator<<( KTErrorMsgInfo& emi ); - - virtual const char* what() const throw(); - private: mutable std::string fMsgBuffer; }; @@ -116,17 +116,12 @@ namespace Nymph { if( ! fMsgBuffer.empty() ) { - boost::operator<<( *this, KTErrorMsgInfo{ fMsgBuffer } ); + boost::operator<<( *this, KTErrorMsgInfo< struct ExcpMsg >{ fMsgBuffer } ); fMsgBuffer.clear(); } return *this; } - inline const KTException& KTException::operator<<( KTErrorMsgInfo& emi ) - { - return boost::operator<<( *this, emi ); - } - } #endif /* KTEXCEPTION_HH_ */ diff --git a/Scarab b/Scarab index 6362897..003cbf4 160000 --- a/Scarab +++ b/Scarab @@ -1 +1 @@ -Subproject commit 6362897c81362b0ad90e55f1d2c9bbd703f20b93 +Subproject commit 003cbf4f802a0d1046fe599b18a39349de13f86f From 453970368f91600d4838ca4d330d39b916b56e72 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Fri, 26 May 2017 17:28:14 -0700 Subject: [PATCH 046/521] =?UTF-8?q?Refactored=20KTMemberVariable.hh=20so?= =?UTF-8?q?=20that=20it=20uses=20scarab=E2=80=99s=20=5Fmember=5Fvariable.h?= =?UTF-8?q?h.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Library/Data/KTCutResult.hh | 2 +- Library/Data/KTData.hh | 2 +- Library/Processor/KTThreadReference.hh | 2 +- Library/Utility/KTMemberVariable.hh | 143 ++++++++++++------------- Scarab | 2 +- 5 files changed, 70 insertions(+), 81 deletions(-) diff --git a/Library/Data/KTCutResult.hh b/Library/Data/KTCutResult.hh index e89f5f3..a0845be 100644 --- a/Library/Data/KTCutResult.hh +++ b/Library/Data/KTCutResult.hh @@ -26,7 +26,7 @@ namespace Nymph virtual const std::string& Name() const = 0; - MEMBERVARIABLE_PROTECTED(bool, State); + MEMBERVARIABLE(bool, State); }; typedef KTExtensibleStructCore< KTCutResultCore > KTCutResult; diff --git a/Library/Data/KTData.hh b/Library/Data/KTData.hh index 6b5a18c..688d7fe 100644 --- a/Library/Data/KTData.hh +++ b/Library/Data/KTData.hh @@ -57,7 +57,7 @@ namespace Nymph MEMBERVARIABLE(unsigned, Counter); MEMBERVARIABLE(bool, LastData); - MEMBERVARIABLEREF(KTCutStatus, CutStatus); + MEMBERVARIABLE_REF(KTCutStatus, CutStatus); public: static const std::string sName; diff --git a/Library/Processor/KTThreadReference.hh b/Library/Processor/KTThreadReference.hh index 9a963b5..8d403ea 100644 --- a/Library/Processor/KTThreadReference.hh +++ b/Library/Processor/KTThreadReference.hh @@ -59,7 +59,7 @@ namespace Nymph const boost::mutex& Mutex() const; public: - MEMBERVARIABLEREF( std::string, Name ); + MEMBERVARIABLE_REF( std::string, Name ); MEMBERVARIABLE( bool, BreakFlag ); MEMBERVARIABLE( bool, Canceled ); diff --git a/Library/Utility/KTMemberVariable.hh b/Library/Utility/KTMemberVariable.hh index ded3ae2..ef98764 100644 --- a/Library/Utility/KTMemberVariable.hh +++ b/Library/Utility/KTMemberVariable.hh @@ -8,94 +8,83 @@ #ifndef KTMEMBERVARIABLE_HH_ #define KTMEMBERVARIABLE_HH_ - /** - * Creates a member variable with type TYPE name f[NAME], plus getter and setter. - * MEMBERVARIABLE_NOSET will provide the variable and getter, but no setter, allowing you to provide a custom setter. + * Macros for class member variables * - * Usage example, in a class header file: - * MEMBERVARIABLE(double, MyVar) + * In all cases remember to initialize the variables! * - * You still need to initialize the variables in the class constructors. + * For "normal" variables + * Defines accessors [type GetMyVar() const], [void SetMyVar( type )], and member variable [type fMyVar] + * The Set function is not available if the _NOSET macros are used + * - MEMBERVARIABLE + * - MEMBERVARIABLE_NOSET + * - MEMBERVARIABLE_STATIC + * - MEMBERVARIABLE_STATIC_NOSET * - * The generated code is: - * private: - * TYPE f[NAME]; - * public: - * inline TYPE Get[NAME]() const - * { - * return f[NAME]; - * } - * inline void Set[NAME](TYPE var) - * { - * f[NAME] = var; - * } - */ -#define MEMBERVARIABLE_NOSET(TYPE, NAME) \ - private: \ - TYPE f##NAME; \ - public: \ - inline TYPE Get##NAME() const {return f##NAME;} \ - -#define MEMBERVARIABLE(TYPE, NAME) \ - MEMBERVARIABLE_NOSET(TYPE, NAME) \ - inline void Set##NAME(TYPE var) {f##NAME = var; return;} - -#define MEMBERVARIABLE_PROTECTED_NOSET(TYPE, NAME) \ - protected: \ - TYPE f##NAME; \ - public: \ - inline TYPE Get##NAME() const {return f##NAME;} \ - -#define MEMBERVARIABLE_PROTECTED(TYPE, NAME) \ - MEMBERVARIABLE_PROTECTED_NOSET(TYPE, NAME) \ - inline void Set##NAME(TYPE var) {f##NAME = var; return;} - - - -/** - * Creates a member variable with type TYPE name f[NAME], const and non-const access functions. - * MEMBERVARIABLEREF_CONST will provide the variable and the const access function, but no non-const access function. + * For variables accessed by reference + * Defines accessors [const type& MyVar() const], [type& MyVar()], and member variable [type fMyVar] + * The non-const function is not available if the _CONST macros are used + * - MEMBERVARIABLE_REF + * - MEMBERVARIABLE_REF_CONST + * - MEMBERVARIABLE_REF_STATIC + * - MEMBERVARIABLE_REF_STATIC_CONST + * + * For pointer variables + * Defines accessors [type* GetMyVar() const], [void SetMyVar( type* )], and member variable [type* fMyVar] + * The Set function is not available if the _NOSET macros are used + * - MEMBERVARIABLE_PTR + * - MEMBERVARIABLE_PTR_NOSET + * - MEMBERVARIABLE_PTR_STATIC + * - MEMBERVARIABLE_PTR_STATIC_NOSET * - * Usage example, in a class header file: - * MEMBERVARIABLEREF(std::string, MyVar) + * For shared_ptr's + * Defines accessors [const std::shared_ptr< type > MyVar() const], [std::shared_ptr< type > MyVar()], and member variable [std::shared_ptr< type > fMyVar] + * The non-const function is not available if the _CONST macros are used + * - MEMBERVARIABLE_SHARED_PTR + * - MEMBERVARIABLE_SHARED_PTR_CONST + * - MEMBERVARIABLE_SHARED_PTR_STATIC + * - MEMBERVARIABLE_SHARED_PTR_STATIC_CONST * - * You still need to initialize the variables in the class constructors. + * For atomic variables + * Defines accessors [type GetMyVar() const], [void SetMyVar( type )], and member variable [std::atomic< type > fMyVar] + * The Set function is not available if the _NOSET macros are used + * - MEMBERVARIABLE_ATOMIC + * - MEMBERVARIABLE_ATOMIC_NOSET + * - MEMBERVARIABLE_ATOMIC_STATIC + * - MEMBERVARIABLE_ATOMIC_STATIC_NOSET * - * The generated code is: - * private: - * TYPE f[NAME]; - * public: - * inline const TYPE& [NAME]() const - * { - * return f[NAME]; - * } - * inline TYPE& [NAME]() - * { - * return f[NAME]; - * } */ -#define MEMBERVARIABLEREF_CONST(TYPE, NAME) \ - private: \ - TYPE f##NAME; \ - public: \ - inline const TYPE& NAME() const {return f##NAME;} \ - inline TYPE& NAME() {return f##NAME;} -#define MEMBERVARIABLEREF(TYPE, NAME) \ - MEMBERVARIABLEREF_CONST(TYPE, NAME) \ - inline TYPE& NAME(const TYPE& var) {return f##NAME;} +#define set_prefix Set +#define get_prefix Get +#define var_prefix f +#define static_prefix s + +#include "_member_variables.hh" + +#define MEMBERVARIABLE mv_accessible +#define MEMBERVARIABLE_NOSET mv_accessible_noset +#define MEMBERVARIABLE_STATIC mv_accessible_static +#define MEMBERVARIABLE_STATIC_NOSET mv_accessible_static_noset + +#define MEMBERVARIABLE_REF mv_referrable +#define MEMBERVARIABLE_REF_CONST mv_referrable_const +#define MEMBERVARIABLE_REF_STATIC mv_referrable_static +#define MEMBERVARIABLE_REF_STATIC_CONST mv_referrable_static_const -#define MEMBERVARIABLEREF_PROTECTED_NOSET(TYPE, NAME) \ - protected: \ - TYPE f##NAME; \ - public: \ - inline const TYPE& NAME() const {return f##NAME;} \ - inline TYPE& NAME() {return f##NAME;} +#define MEMBERVARIABLE_PTR mv_assignable +#define MEMBERVARIABLE_PTR_NOSET mv_assignable_noset +#define MEMBERVARIABLE_PTR_STATIC mv_assignable_static +#define MEMBERVARIABLE_PTR_STATIC_NOSET mv_assignable_static_noset -#define MEMBERVARIABLEREF_PROTECTED(TYPE, NAME) \ - MEMBERVARIABLEREF_PROTECTED_NOSET(TYPE, NAME) \ - inline TYPE& NAME() {return f##NAME;} +#define MEMBERVARIABLE_SHARED_PTR mv_shared_ptr +#define MEMBERVARIABLE_SHARED_PTR_NOSET mv_shared_ptr_noset +#define MEMBERVARIABLE_SHARED_PTR_STATIC mv_shared_ptr_static +#define MEMBERVARIABLE_SHARED_PTR_STATIC_NOSET mv_shared_ptr_static_noset +#define MEMBERVARIABLE_ATOMIC mv_atomic +#define MEMBERVARIABLE_ATOMIC_NOSET mv_atomic_noset +#define MEMBERVARIABLE_ATOMIC_STATIC mv_atomic_static +#define MEMBERVARIABLE_ATOMIC_STATIC_NOSET mv_atomic_static_noset #endif /* KTMEMBERVARIABLE_HH_ */ diff --git a/Scarab b/Scarab index 003cbf4..1e8862c 160000 --- a/Scarab +++ b/Scarab @@ -1 +1 @@ -Subproject commit 003cbf4f802a0d1046fe599b18a39349de13f86f +Subproject commit 1e8862c00bed696e53dfbf2428d48f9fd5e56c9e From b8dd002775586a4a3aba449a09ab462240e46125 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Tue, 30 May 2017 17:27:04 -0700 Subject: [PATCH 047/521] Updated scarab to incorporate member variable changes, and updated KTMemberVariable.hh --- Library/Utility/KTMemberVariable.hh | 12 +++++++++--- Scarab | 2 +- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/Library/Utility/KTMemberVariable.hh b/Library/Utility/KTMemberVariable.hh index ef98764..d867381 100644 --- a/Library/Utility/KTMemberVariable.hh +++ b/Library/Utility/KTMemberVariable.hh @@ -66,25 +66,31 @@ #define MEMBERVARIABLE_NOSET mv_accessible_noset #define MEMBERVARIABLE_STATIC mv_accessible_static #define MEMBERVARIABLE_STATIC_NOSET mv_accessible_static_noset +#define MEMBERVARIABLE_MUTABLE mv_accessible_mutable +#define MEMBERVARIABLE_MUTABLE_NOSET mv_accessible_mutable_noset #define MEMBERVARIABLE_REF mv_referrable #define MEMBERVARIABLE_REF_CONST mv_referrable_const #define MEMBERVARIABLE_REF_STATIC mv_referrable_static -#define MEMBERVARIABLE_REF_STATIC_CONST mv_referrable_static_const +#define MEMBERVARIABLE_REF_MUTABLE mv_referrable_mutable #define MEMBERVARIABLE_PTR mv_assignable #define MEMBERVARIABLE_PTR_NOSET mv_assignable_noset #define MEMBERVARIABLE_PTR_STATIC mv_assignable_static #define MEMBERVARIABLE_PTR_STATIC_NOSET mv_assignable_static_noset +#define MEMBERVARIABLE_PTR_MUTABLE mv_assignable_mutable +#define MEMBERVARIABLE_PTR_MUTABLE_NOSET mv_assignable_mutable_noset #define MEMBERVARIABLE_SHARED_PTR mv_shared_ptr -#define MEMBERVARIABLE_SHARED_PTR_NOSET mv_shared_ptr_noset +#define MEMBERVARIABLE_SHARED_PTR_CONST mv_shared_ptr_const #define MEMBERVARIABLE_SHARED_PTR_STATIC mv_shared_ptr_static -#define MEMBERVARIABLE_SHARED_PTR_STATIC_NOSET mv_shared_ptr_static_noset +#define MEMBERVARIABLE_SHARED_PTR_MUTABLE mv_shared_ptr_mutable #define MEMBERVARIABLE_ATOMIC mv_atomic #define MEMBERVARIABLE_ATOMIC_NOSET mv_atomic_noset #define MEMBERVARIABLE_ATOMIC_STATIC mv_atomic_static #define MEMBERVARIABLE_ATOMIC_STATIC_NOSET mv_atomic_static_noset +#define MEMBERVARIABLE_ATOMIC_MUTABLE mv_atomic_mutable +#define MEMBERVARIABLE_ATOMIC_MUTABLE_NOSET mv_atomic_mutable_noset #endif /* KTMEMBERVARIABLE_HH_ */ diff --git a/Scarab b/Scarab index 1e8862c..da22e7f 160000 --- a/Scarab +++ b/Scarab @@ -1 +1 @@ -Subproject commit 1e8862c00bed696e53dfbf2428d48f9fd5e56c9e +Subproject commit da22e7f4ad38a02df699a947ff21c15baf0c2bfd From 1939d60ffbe6b115a75f98b578a47423fd9e95bc Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Tue, 30 May 2017 17:43:27 -0700 Subject: [PATCH 048/521] Add default of no signals in KTSlotWrapper::RegisterSlot() --- Library/Processor/KTProcessor.hh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Library/Processor/KTProcessor.hh b/Library/Processor/KTProcessor.hh index aad8d20..193cbe2 100644 --- a/Library/Processor/KTProcessor.hh +++ b/Library/Processor/KTProcessor.hh @@ -77,7 +77,7 @@ namespace Nymph KTSignalWrapper* RegisterSignal(std::string name, XProcessor* signalPtr); template< class XTarget, typename XReturn, typename... XArgs > - KTSlotWrapper* RegisterSlot(std::string name, XTarget* target, XReturn (XTarget::* funcPtr)(XArgs...), std::initializer_list< std::string > signals); + KTSlotWrapper* RegisterSlot(std::string name, XTarget* target, XReturn (XTarget::* funcPtr)(XArgs...), std::initializer_list< std::string > signals = {}); KTSignalWrapper* GetSignal(const std::string& name); From 6db37cc6222dbf1577e6b176a573f2016a7bf176 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Wed, 31 May 2017 11:45:43 -0700 Subject: [PATCH 049/521] Move KTProcessor::ConnectSignalToSlot() to a public static function --- Library/Processor/KTProcessor.hh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Library/Processor/KTProcessor.hh b/Library/Processor/KTProcessor.hh index 193cbe2..6b04e3b 100644 --- a/Library/Processor/KTProcessor.hh +++ b/Library/Processor/KTProcessor.hh @@ -70,6 +70,8 @@ namespace Nymph /// For a slot that is called, update the slot's ThreadRef, and pass the update to any slots that get called by signals emitted by this slot void PassThreadRefUpdate(const std::string& slotName, std::shared_ptr< KTThreadReference > threadRef); + static void ConnectSignalToSlot(KTSignalWrapper* signal, KTSlotWrapper* slot, int groupNum=-1); + void ConnectASlot(const std::string& signalName, KTProcessor* processor, const std::string& slotName, int groupNum=-1); void ConnectASignal(KTProcessor* processor, const std::string& signalName, const std::string& slotName, int groupNum=-1); @@ -90,8 +92,6 @@ namespace Nymph template< typename XReturn, typename... XArgs > void PassToConnProcs(const std::string& slotName, std::function< XReturn(XArgs...) > function, XArgs... args); - void ConnectSignalToSlot(KTSignalWrapper* signal, KTSlotWrapper* slot, int groupNum=-1); - SignalMap fSignalMap; SlotMap fSlotMap; From c589cd3427a889381bbf56bd386874e7668fcac4 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Thu, 1 Jun 2017 13:27:45 -0700 Subject: [PATCH 050/521] Scarab updated for param iterators; Nymph adapted to new iterators. --- Library/Application/KTApplication.cc | 2 +- Library/Application/KTProcessorToolbox.cc | 20 ++++++++++---------- Library/Data/KTApplyCut.cc | 6 +++--- Scarab | 2 +- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/Library/Application/KTApplication.cc b/Library/Application/KTApplication.cc index f573527..48ff2fc 100644 --- a/Library/Application/KTApplication.cc +++ b/Library/Application/KTApplication.cc @@ -152,7 +152,7 @@ namespace Nymph const scarab::param_node& paramNode = param.as_node(); for (scarab::param_node::const_iterator nodeIt = paramNode.begin(); nodeIt != paramNode.end(); ++nodeIt) { - AddConfigOptionsToCLHandler(*nodeIt->second, nextRootName + nodeIt->first); + AddConfigOptionsToCLHandler(*nodeIt, nextRootName + nodeIt.name()); } } diff --git a/Library/Application/KTProcessorToolbox.cc b/Library/Application/KTProcessorToolbox.cc index 27ba8c2..2e81a17 100644 --- a/Library/Application/KTProcessorToolbox.cc +++ b/Library/Application/KTProcessorToolbox.cc @@ -67,12 +67,12 @@ namespace Nymph const scarab::param_array& procArray = node->array_at( "processors" ); for( scarab::param_array::const_iterator procIt = procArray.begin(); procIt != procArray.end(); ++procIt ) { - if( ! (*procIt)->is_node() ) + if( ! procIt->is_node() ) { KTERROR( proclog, "Invalid processor entry: not a node" ); return false; } - const scarab::param_node* procNode = &( (*procIt)->as_node() ); + const scarab::param_node* procNode = &( procIt->as_node() ); if (! procNode->has("type")) { @@ -118,12 +118,12 @@ namespace Nymph const scarab::param_array& connArray = node->array_at( "connections" ); for( scarab::param_array::const_iterator connIt = connArray.begin(); connIt != connArray.end(); ++connIt ) { - if( ! (*connIt)->is_node() ) + if( ! connIt->is_node() ) { KTERROR( proclog, "Invalid connection entry: not a node" ); return false; } - const scarab::param_node* connNode = &( (*connIt)->as_node() ); + const scarab::param_node* connNode = &( connIt->as_node() ); if ( ! connNode->has("signal") || ! connNode->has("slot") ) { @@ -190,27 +190,27 @@ namespace Nymph const scarab::param_array& rqArray = node->array_at( "run-queue" ); for (scarab::param_array::const_iterator rqIt = rqArray.begin(); rqIt != rqArray.end(); ++rqIt) { - if ((*rqIt)->is_value()) + if (rqIt->is_value()) { - if (! PushBackToRunQueue((*rqIt)->as_value().as_string())) + if (! PushBackToRunQueue(rqIt->as_value().as_string())) { KTERROR(proclog, "Unable to process run-queue entry: could not add processor to the queue"); return false; } } - else if ((*rqIt)->is_array()) + else if (rqIt->is_array()) { - const scarab::param_array* rqNode = &( (*rqIt)->as_array() ); + const scarab::param_array* rqNode = &( rqIt->as_array() ); std::vector< std::string > names; for (scarab::param_array::const_iterator rqArrayIt = rqNode->begin(); rqArrayIt != rqNode->end(); ++rqArrayIt) { - if (! (*rqArrayIt)->is_value()) + if (! rqArrayIt->is_value()) { KTERROR(proclog, "Invalid run-queue array entry: not a value"); return false; } - names.push_back((*rqArrayIt)->as_value().as_string()); + names.push_back(rqArrayIt->as_value().as_string()); } if (! PushBackToRunQueue(names)) diff --git a/Library/Data/KTApplyCut.cc b/Library/Data/KTApplyCut.cc index 47b5e98..7bc975a 100644 --- a/Library/Data/KTApplyCut.cc +++ b/Library/Data/KTApplyCut.cc @@ -45,11 +45,11 @@ namespace Nymph // any remaining should be cut names // ignore any that don't work - if (SelectCut(nodeIt->first)) + if (SelectCut(nodeIt.name())) { - if (nodeIt->second->is_node()) + if (nodeIt->is_node()) { - fCut->Configure(&nodeIt->second->as_node()); + fCut->Configure(&nodeIt->as_node()); } continue; } diff --git a/Scarab b/Scarab index da22e7f..7af4d4a 160000 --- a/Scarab +++ b/Scarab @@ -1 +1 @@ -Subproject commit da22e7f4ad38a02df699a947ff21c15baf0c2bfd +Subproject commit 7af4d4ab2876e0672811ad908b6793c7488a143c From 738dccff145b18f1721c90c08f2901c53997cde1 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Thu, 1 Jun 2017 14:08:53 -0700 Subject: [PATCH 051/521] Minor notation improvement --- Library/Application/KTProcessorToolbox.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Library/Application/KTProcessorToolbox.cc b/Library/Application/KTProcessorToolbox.cc index 2e81a17..5b19a1e 100644 --- a/Library/Application/KTProcessorToolbox.cc +++ b/Library/Application/KTProcessorToolbox.cc @@ -192,7 +192,7 @@ namespace Nymph { if (rqIt->is_value()) { - if (! PushBackToRunQueue(rqIt->as_value().as_string())) + if (! PushBackToRunQueue((*rqIt)().as_string())) { KTERROR(proclog, "Unable to process run-queue entry: could not add processor to the queue"); return false; @@ -210,7 +210,7 @@ namespace Nymph KTERROR(proclog, "Invalid run-queue array entry: not a value"); return false; } - names.push_back(rqArrayIt->as_value().as_string()); + names.push_back((*rqArrayIt)().as_string()); } if (! PushBackToRunQueue(names)) From c80e9b9dacebb7a08bd5d7a45713a3612fd0b1cc Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Thu, 1 Jun 2017 14:21:20 -0700 Subject: [PATCH 052/521] Scarab update --- Scarab | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Scarab b/Scarab index 7af4d4a..5d1e21a 160000 --- a/Scarab +++ b/Scarab @@ -1 +1 @@ -Subproject commit 7af4d4ab2876e0672811ad908b6793c7488a143c +Subproject commit 5d1e21a03665d5feb8f8464f3a89826876933f4c From 186c4d6283d9d0e1d29b1c1706ab20448fbc6c9a Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Thu, 1 Jun 2017 16:00:58 -0700 Subject: [PATCH 053/521] Created KTTestData.hh/cc and make KTTestProcessorD with a slot for KTTestData --- Executables/Validation/CMakeLists.txt | 2 + Executables/Validation/KTTestCuts.cc | 12 +--- Executables/Validation/KTTestCuts.hh | 16 +----- Executables/Validation/KTTestData.cc | 42 ++++++++++++++ Executables/Validation/KTTestData.hh | 67 +++++++++++++++++++++++ Executables/Validation/KTTestProcessor.cc | 25 +++++++++ Executables/Validation/KTTestProcessor.hh | 20 +++++++ Executables/Validation/TestApplyCut.cc | 1 + Executables/Validation/TestCut.cc | 1 + Executables/Validation/TestCutFilter.cc | 1 + Executables/Validation/TestPrintData.cc | 20 +------ Library/Processor/KTSlot.hh | 16 +++--- 12 files changed, 171 insertions(+), 52 deletions(-) create mode 100644 Executables/Validation/KTTestData.cc create mode 100644 Executables/Validation/KTTestData.hh diff --git a/Executables/Validation/CMakeLists.txt b/Executables/Validation/CMakeLists.txt index 4b43ee9..ab270a3 100644 --- a/Executables/Validation/CMakeLists.txt +++ b/Executables/Validation/CMakeLists.txt @@ -15,6 +15,7 @@ if (Nymph_ENABLE_TESTING) set (VALIDATION_HEADERFILES KTTestConfigurable.hh KTTestCuts.hh + KTTestData.hh KTTestPrimaryProcessor.hh KTTestProcessor.hh ) @@ -22,6 +23,7 @@ if (Nymph_ENABLE_TESTING) set (VALIDATION_SOURCEFILES KTTestConfigurable.cc KTTestCuts.cc + KTTestData.cc KTTestPrimaryProcessor.cc KTTestProcessor.cc ) diff --git a/Executables/Validation/KTTestCuts.cc b/Executables/Validation/KTTestCuts.cc index e66ff30..dbc5758 100644 --- a/Executables/Validation/KTTestCuts.cc +++ b/Executables/Validation/KTTestCuts.cc @@ -8,13 +8,12 @@ #include "KTTestCuts.hh" #include "KTLogger.hh" +#include "KTTestData.hh" namespace Nymph { KTLOGGER(testlog, "KTTestCuts"); - const std::string KTTestData::sName = "test-data"; - const std::string KTAwesomeCut::Result::sName = "awesome-cut"; const std::string KTNotAwesomeCut::Result::sName = "not-awesome-cut"; @@ -22,15 +21,6 @@ namespace Nymph KT_REGISTER_CUT(KTNotAwesomeCut); - KTTestData::KTTestData() : - KTExtensibleData< KTTestData >(), - fIsAwesome(false) - {} - - KTTestData::~KTTestData() - {} - - KTAwesomeCut::KTAwesomeCut(const std::string& name) : KTCutOneArg(name) {} diff --git a/Executables/Validation/KTTestCuts.hh b/Executables/Validation/KTTestCuts.hh index cfa97c6..e1f159c 100644 --- a/Executables/Validation/KTTestCuts.hh +++ b/Executables/Validation/KTTestCuts.hh @@ -9,25 +9,13 @@ #define NYMPH_KTTESTCUTS_HH_ #include "KTCut.hh" -#include "KTData.hh" #include "KTMemberVariable.hh" +#include "KTData.hh" namespace Nymph { - - class KTTestData : public KTExtensibleData< KTTestData > - { - public: - KTTestData(); - virtual ~KTTestData(); - - MEMBERVARIABLE(bool, IsAwesome); - - public: - static const std::string sName; - - }; + class KTTestData; // Cuts data that is NOT awesome class KTAwesomeCut : public KTCutOneArg< KTTestData > diff --git a/Executables/Validation/KTTestData.cc b/Executables/Validation/KTTestData.cc new file mode 100644 index 0000000..11baaba --- /dev/null +++ b/Executables/Validation/KTTestData.cc @@ -0,0 +1,42 @@ +/* + * KTTestData.cc + * + * Created on: Jun 1, 2017 + * Author: obla999 + */ + +#include "KTTestData.hh" + +namespace Nymph +{ + KTTestData::KTTestData() : + KTExtensibleData< KTTestData >(), + fIsAwesome(false) + {} + + KTTestData::~KTTestData() + {} + + const std::string KTTestData::sName = "test-data"; + + + KTTestDerived1Data::KTTestDerived1Data() : + KTTestPolyDataBase< KTTestDerived1Data >() + {} + + KTTestDerived1Data::~KTTestDerived1Data() + {} + + const std::string KTTestDerived1Data::sName = "test-derived-1-data"; + + KTTestDerived2Data::KTTestDerived2Data() : + KTTestPolyDataBase< KTTestDerived2Data >() + {} + + KTTestDerived2Data::~KTTestDerived2Data() + {} + + const std::string KTTestDerived2Data::sName = "test-derived-2-data"; + +} /* namespace Nymph */ + diff --git a/Executables/Validation/KTTestData.hh b/Executables/Validation/KTTestData.hh new file mode 100644 index 0000000..42fa1fe --- /dev/null +++ b/Executables/Validation/KTTestData.hh @@ -0,0 +1,67 @@ +/* + * KTTestData.hh + * + * Created on: Jun 1, 2017 + * Author: obla999 + */ + +#ifndef NYMPH_KTTESTDATA_HH_ +#define NYMPH_KTTESTDATA_HH_ + +#include "KTData.hh" +#include "KTMemberVariable.hh" + + +namespace Nymph +{ + + class KTTestData : public KTExtensibleData< KTTestData > + { + public: + KTTestData(); + virtual ~KTTestData(); + + MEMBERVARIABLE(bool, IsAwesome); + + public: + static const std::string sName; + + }; + + + template< class XDerivedDataType > + class KTTestPolyDataBase : public KTExtensibleData< XDerivedDataType > + { + public: + KTTestPolyDataBase() : + KTExtensibleData< XDerivedDataType >(), + fFunniness(1000.) + {} + virtual ~KTTestPolyDataBase() {} + + MEMBERVARIABLE(double, Funniness); + }; + + class KTTestDerived1Data : public KTTestPolyDataBase< KTTestDerived1Data > + { + public: + KTTestDerived1Data(); + virtual ~KTTestDerived1Data(); + + public: + static const std::string sName; + }; + + class KTTestDerived2Data : public KTTestPolyDataBase< KTTestDerived2Data > + { + public: + KTTestDerived2Data(); + virtual ~KTTestDerived2Data(); + + public: + static const std::string sName; + }; + +} /* namespace Nymph */ + +#endif /* NYMPH_KTTESTDATA_HH_ */ diff --git a/Executables/Validation/KTTestProcessor.cc b/Executables/Validation/KTTestProcessor.cc index 20a169a..a5ed5a6 100644 --- a/Executables/Validation/KTTestProcessor.cc +++ b/Executables/Validation/KTTestProcessor.cc @@ -10,6 +10,8 @@ #include "KTException.hh" #include "KTLogger.hh" +#include "KTTestData.hh" + namespace Nymph { KTLOGGER(testsiglog, "KTTestProcessor") @@ -101,4 +103,27 @@ namespace Nymph } + KT_REGISTER_PROCESSOR(KTTestProcessorD, "test-proc-d"); + + KTTestProcessorD::KTTestProcessorD( const std::string& name ) : + KTProcessor( name ), + fSlot("test-data", this, &KTTestProcessorD::SlotFunc, {}) + { + } + + KTTestProcessorD::~KTTestProcessorD() + { + } + + bool KTTestProcessorD::Configure(const scarab::param_node*) + { + return true; + } + + bool KTTestProcessorD::SlotFunc(KTTestData& data) + { + KTINFO(testsiglog, "Is the data awesome? " << data.GetIsAwesome()); + return true; + } + } /* namespace Nymph */ diff --git a/Executables/Validation/KTTestProcessor.hh b/Executables/Validation/KTTestProcessor.hh index 689ccc0..5f80236 100644 --- a/Executables/Validation/KTTestProcessor.hh +++ b/Executables/Validation/KTTestProcessor.hh @@ -73,5 +73,25 @@ namespace Nymph }; + class KTTestData; + + /*! + * A simple test processor that has a slot for KTTestData + */ + class KTTestProcessorD : public KTProcessor + { + public: + KTTestProcessorD( const std::string& name = "test-proc-d" ); + virtual ~KTTestProcessorD(); + + bool Configure(const scarab::param_node* node); + + bool SlotFunc(KTTestData& data); + + private: + KTSlotData< KTTestData > fSlot; + }; + + } /* namespace Nymph */ #endif /* KTTESTPROCESSOR_HH_ */ diff --git a/Executables/Validation/TestApplyCut.cc b/Executables/Validation/TestApplyCut.cc index fbde4bb..030022c 100644 --- a/Executables/Validation/TestApplyCut.cc +++ b/Executables/Validation/TestApplyCut.cc @@ -9,6 +9,7 @@ #include "KTApplyCut.hh" #include "KTLogger.hh" +#include "KTTestData.hh" KTLOGGER(testlog, "TestApplyCut"); diff --git a/Executables/Validation/TestCut.cc b/Executables/Validation/TestCut.cc index 968f880..21bb358 100644 --- a/Executables/Validation/TestCut.cc +++ b/Executables/Validation/TestCut.cc @@ -8,6 +8,7 @@ #include "KTTestCuts.hh" #include "KTLogger.hh" +#include "KTTestData.hh" KTLOGGER(testlog, "TestCut"); diff --git a/Executables/Validation/TestCutFilter.cc b/Executables/Validation/TestCutFilter.cc index d2306ec..2f31103 100644 --- a/Executables/Validation/TestCutFilter.cc +++ b/Executables/Validation/TestCutFilter.cc @@ -10,6 +10,7 @@ #include "KTApplyCut.hh" #include "KTCutFilter.hh" #include "KTLogger.hh" +#include "KTTestData.hh" KTLOGGER(testlog, "TestCutFilter"); diff --git a/Executables/Validation/TestPrintData.cc b/Executables/Validation/TestPrintData.cc index ed6fe50..59d70ca 100644 --- a/Executables/Validation/TestPrintData.cc +++ b/Executables/Validation/TestPrintData.cc @@ -7,8 +7,8 @@ #include "KTCut.hh" #include "KTLogger.hh" -#include "KTMemberVariable.hh" #include "KTPrintDataStructure.hh" +#include "KTTestData.hh" #include "param.hh" @@ -16,22 +16,6 @@ namespace Nymph { KTLOGGER(testlog, "TestPrintData"); - class KTTestData : public KTExtensibleData< KTTestData > - { - public: - KTTestData() : - KTExtensibleData< KTTestData >(), - fIsAwesome(false) - {} - virtual ~KTTestData() {} - - MEMBERVARIABLE(bool, IsAwesome); - - public: - static const std::string sName; - - }; - // Cuts data that is NOT awesome class KTAwesomeCut : public KTCut { @@ -106,8 +90,6 @@ namespace Nymph }; - const std::string KTTestData::sName = "test-data"; - const std::string KTAwesomeCut::Result::sName = "awesome-cut"; const std::string KTNotAwesomeCut::Result::sName = "not-awesome-cut"; diff --git a/Library/Processor/KTSlot.hh b/Library/Processor/KTSlot.hh index 9840131..289ffb4 100644 --- a/Library/Processor/KTSlot.hh +++ b/Library/Processor/KTSlot.hh @@ -100,12 +100,12 @@ namespace Nymph public: /// Constructor for the case where the processor has the function that will be called by the slot - template< class XFuncOwnerType > - KTSlotData( const std::string& name, XFuncOwnerType* owner, bool (XFuncOwnerType::*func)( XDataTypes&... ), KTSignalData* signalPtr=nullptr ); + template< class XFuncOwnerType, class... XFuncDataTypes > + KTSlotData( const std::string& name, XFuncOwnerType* owner, bool (XFuncOwnerType::*func)( XFuncDataTypes&... ), KTSignalData* signalPtr=nullptr ); /// Constructor for the case where the processor and the object with the function that will be called are different - template< class XFuncOwnerType > - KTSlotData( const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, bool (XFuncOwnerType::*func)( XDataTypes&... ), KTSignalData* signalPtr=nullptr ); + template< class XFuncOwnerType, class... XFuncDataTypes > + KTSlotData( const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, bool (XFuncOwnerType::*func)( XFuncDataTypes&... ), KTSignalData* signalPtr=nullptr ); virtual ~KTSlotData(); @@ -242,8 +242,8 @@ namespace Nymph // KTSlotData template< class... XDataTypes > - template< class XFuncOwnerType > - KTSlotData< XDataTypes... >::KTSlotData(const std::string& name, XFuncOwnerType* owner, bool (XFuncOwnerType::*func)( XDataTypes&... ), KTSignalData* signalPtr) : + template< class XFuncOwnerType, class... XFuncDataTypes > + KTSlotData< XDataTypes... >::KTSlotData(const std::string& name, XFuncOwnerType* owner, bool (XFuncOwnerType::*func)( XFuncDataTypes&... ), KTSignalData* signalPtr) : KTSlot( name, owner, this, &KTSlotData::operator(), {signalPtr->GetName()} ), fFunc( [func, owner]( XDataTypes... args ){ return (owner->*func)(args...);} ), fSignalPtr( signalPtr ) @@ -251,8 +251,8 @@ namespace Nymph } template< class... XDataTypes > - template< class XFuncOwnerType > - KTSlotData< XDataTypes... >::KTSlotData(const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, bool (XFuncOwnerType::*func)( XDataTypes&... ), KTSignalData* signalPtr) : + template< class XFuncOwnerType, class... XFuncDataTypes > + KTSlotData< XDataTypes... >::KTSlotData(const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, bool (XFuncOwnerType::*func)( XFuncDataTypes&... ), KTSignalData* signalPtr) : KTSlot( name, proc, this, &KTSlotData::operator(), { signalPtr->GetName()} ), fFunc( [func, owner]( XDataTypes... args ){return (owner->*func) (args... );} ), fSignalPtr( signalPtr ) From 9d38ce53eaf19c88008b2448b7bfb6c4a3985b0c Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Fri, 2 Jun 2017 17:44:24 -0700 Subject: [PATCH 054/521] Enabled polymorphic slot functionality --- Executables/Validation/CMakeLists.txt | 2 + Executables/Validation/KTTestData.cc | 8 ++- Executables/Validation/KTTestProcessor.cc | 65 +++++++++++++++++-- Executables/Validation/KTTestProcessor.hh | 53 +++++++++++++-- .../Validation/TestPolymorphicSlotData.cc | 41 ++++++++++++ Executables/Validation/TestSlotData.cc | 43 ++++++++++++ Library/Processor/KTSlot.hh | 44 +++++++++---- 7 files changed, 231 insertions(+), 25 deletions(-) create mode 100644 Executables/Validation/TestPolymorphicSlotData.cc create mode 100644 Executables/Validation/TestSlotData.cc diff --git a/Executables/Validation/CMakeLists.txt b/Executables/Validation/CMakeLists.txt index ab270a3..fc41cfb 100644 --- a/Executables/Validation/CMakeLists.txt +++ b/Executables/Validation/CMakeLists.txt @@ -52,6 +52,7 @@ if (Nymph_ENABLE_TESTING) TestCutFilter TestExceptionInSlot TestLogger + TestPolymorphicSlotData TestPrimaryProcessor TestPrimaryProcessorNoThreading TestPrintData @@ -59,6 +60,7 @@ if (Nymph_ENABLE_TESTING) TestProcessorToolboxMultithreaded TestProcessorToolboxSinglethreaded TestSignalsAndSlots + TestSlotData TestThroughputProfiler TestUseBreakpoint ) diff --git a/Executables/Validation/KTTestData.cc b/Executables/Validation/KTTestData.cc index 11baaba..6aa5186 100644 --- a/Executables/Validation/KTTestData.cc +++ b/Executables/Validation/KTTestData.cc @@ -22,7 +22,9 @@ namespace Nymph KTTestDerived1Data::KTTestDerived1Data() : KTTestPolyDataBase< KTTestDerived1Data >() - {} + { + fFunniness = 500; + } KTTestDerived1Data::~KTTestDerived1Data() {} @@ -31,7 +33,9 @@ namespace Nymph KTTestDerived2Data::KTTestDerived2Data() : KTTestPolyDataBase< KTTestDerived2Data >() - {} + { + fFunniness = 1000000000000; + } KTTestDerived2Data::~KTTestDerived2Data() {} diff --git a/Executables/Validation/KTTestProcessor.cc b/Executables/Validation/KTTestProcessor.cc index a5ed5a6..c44d217 100644 --- a/Executables/Validation/KTTestProcessor.cc +++ b/Executables/Validation/KTTestProcessor.cc @@ -10,7 +10,7 @@ #include "KTException.hh" #include "KTLogger.hh" -#include "KTTestData.hh" +//#include "KTTestData.hh" namespace Nymph { @@ -44,8 +44,8 @@ namespace Nymph KTTestProcessorB::KTTestProcessorB( const std::string& name ) : KTProcessor( name ), - fSlot1("first-slot", this, &KTTestProcessorB::SlotFunc1, {}), - fSlot2("second-slot", this, &KTTestProcessorB::SlotFunc2, {}) + fSlot1("first-slot", this, &KTTestProcessorB::SlotFunc1), + fSlot2("second-slot", this, &KTTestProcessorB::SlotFunc2) { fSlot1Wrapper = GetSlot( "first-slot" ); fSlot2Wrapper = GetSlot( "second-slot" ); @@ -79,7 +79,7 @@ namespace Nymph KTTestProcessorC::KTTestProcessorC( const std::string& name ) : KTProcessor( name ), - fSlot1("first-slot", this, &KTTestProcessorC::SlotFunc1, {}) + fSlot1("first-slot", this, &KTTestProcessorC::SlotFunc1) { } @@ -107,7 +107,8 @@ namespace Nymph KTTestProcessorD::KTTestProcessorD( const std::string& name ) : KTProcessor( name ), - fSlot("test-data", this, &KTTestProcessorD::SlotFunc, {}) + fDataSlot("test-data-slot", this, &KTTestProcessorD::SlotFunc), + fDataSignal("test-data-signal", this) { } @@ -120,10 +121,64 @@ namespace Nymph return true; } + void KTTestProcessorD::EmitSignal(bool isAwesome) + { + KTDataPtr dataPtr = std::make_shared< KTData >(); + KTTestData& data = dataPtr->Of< KTTestData >(); + data.SetIsAwesome(isAwesome); + fDataSignal(dataPtr); + return; + } + bool KTTestProcessorD::SlotFunc(KTTestData& data) { KTINFO(testsiglog, "Is the data awesome? " << data.GetIsAwesome()); return true; } + + KT_REGISTER_PROCESSOR(KTTestProcessorE, "test-proc-e"); + + KTTestProcessorE::KTTestProcessorE( const std::string& name ) : + KTProcessor( name ), + fDerived1DataSlot("derived-1", this, &KTTestProcessorE::BaseSlotFunc< KTTestDerived1Data >), + fDerived2DataSlot("derived-2", this, &KTTestProcessorE::BaseSlotFunc< KTTestDerived2Data >), + fDerived1DataSignal("derived-1", this), + fDerived2DataSignal("derived-2", this) + { + } + + KTTestProcessorE::~KTTestProcessorE() + { + } + + bool KTTestProcessorE::Configure(const scarab::param_node*) + { + return true; + } + + void KTTestProcessorE::EmitSignals() + { + KTDataPtr dataPtr = std::make_shared< KTData >(); + + KTINFO(testsiglog, "Creating data objects"); + KTTestDerived1Data& data1 = dataPtr->Of< KTTestDerived1Data >(); + KTTestDerived2Data& data2 = dataPtr->Of< KTTestDerived2Data >(); + + KTINFO(testsiglog, "Emitting data-1 signal"); + fDerived1DataSignal( dataPtr ); + + KTINFO(testsiglog, "Emitting data-2 signal"); + fDerived2DataSignal( dataPtr ); + + return; + } + + void KTTestProcessorE::PrintFunniness( unsigned funniness) + { + KTINFO(testsiglog, "Data funniness measured to be: <" << funniness << ">"); + return; + } + + } /* namespace Nymph */ diff --git a/Executables/Validation/KTTestProcessor.hh b/Executables/Validation/KTTestProcessor.hh index 5f80236..5b6b507 100644 --- a/Executables/Validation/KTTestProcessor.hh +++ b/Executables/Validation/KTTestProcessor.hh @@ -9,10 +9,10 @@ #define KTTESTPROCESSOR_HH_ #include "KTProcessor.hh" - -#include "KTSignal.hh" #include "KTSlot.hh" +#include "KTTestData.hh" + namespace Nymph { @@ -73,7 +73,7 @@ namespace Nymph }; - class KTTestData; +// class KTTestData; /*! * A simple test processor that has a slot for KTTestData @@ -86,12 +86,57 @@ namespace Nymph bool Configure(const scarab::param_node* node); + // Creates a KTTestData object, sets the awesomeness to the given value, and emits fSignal + void EmitSignal(bool isAwesome = true); + bool SlotFunc(KTTestData& data); private: - KTSlotData< KTTestData > fSlot; + KTSlotData< KTTestData > fDataSlot; + + KTSignalData fDataSignal; + }; + + +// template< class XDerivedDataType > +// class KTTestPolyDataBase< XDerivedDataType >; +// class KTTestDerived1Data; +// class KTTestDerived2Data; + + /*! + * A simple test processor for testing polymorphic data, signals, and slots + */ + class KTTestProcessorE : public KTProcessor + { + public: + KTTestProcessorE( const std::string& name = "test-proc-d" ); + virtual ~KTTestProcessorE(); + + bool Configure(const scarab::param_node* node); + + void EmitSignals(); + + template< class XDerivedDataType > + bool BaseSlotFunc(KTTestPolyDataBase< XDerivedDataType >& data); + + private: + KTSlotData< KTTestDerived1Data > fDerived1DataSlot; + KTSlotData< KTTestDerived2Data > fDerived2DataSlot; + + KTSignalData fDerived1DataSignal; + KTSignalData fDerived2DataSignal; + + // utility function to avoid putting a logger in the header + void PrintFunniness( unsigned funniness ); }; + template< class XDerivedDataType > + bool KTTestProcessorE::BaseSlotFunc(KTTestPolyDataBase< XDerivedDataType >& data) + { + PrintFunniness( data.GetFunniness() ); + return true; + } + } /* namespace Nymph */ #endif /* KTTESTPROCESSOR_HH_ */ diff --git a/Executables/Validation/TestPolymorphicSlotData.cc b/Executables/Validation/TestPolymorphicSlotData.cc new file mode 100644 index 0000000..76b03e8 --- /dev/null +++ b/Executables/Validation/TestPolymorphicSlotData.cc @@ -0,0 +1,41 @@ +/* + * TestSlotData.cc + * + * Created on: Jun 1, 2017 + * Author: obla999 + */ + + +#include "KTTestData.hh" +#include "KTTestProcessor.hh" +#include "KTLogger.hh" + +using namespace Nymph; + +KTLOGGER(testslotdata, "TestPolymorphicSlotData") + +int main() +{ + try + { + KTTestProcessorE tpE; + + KTINFO(testslotdata, "Connecting derived-1 to derived-1 and derived-2 to derived-2"); + // for simplicity the signal and slot are in the same processor, but that need not be, of course + tpE.ConnectASlot("derived-1", &tpE, "derived-1" ); + tpE.ConnectASlot("derived-2", &tpE, "derived-2" ); + + KTINFO(testslotdata, "Emitting signals"); + tpE.EmitSignals(); + + KTINFO(testslotdata, "Tests complete"); + } + catch( boost::exception& e ) + { + KTERROR( testslotdata, "An exception was caught: " << diagnostic_information( e ) ); + return -1; + } + + return 0; +} + diff --git a/Executables/Validation/TestSlotData.cc b/Executables/Validation/TestSlotData.cc new file mode 100644 index 0000000..889bd03 --- /dev/null +++ b/Executables/Validation/TestSlotData.cc @@ -0,0 +1,43 @@ +/* + * TestSlotData.cc + * + * Created on: Jun 1, 2017 + * Author: obla999 + */ + + +#include "KTTestData.hh" +#include "KTTestProcessor.hh" +#include "KTLogger.hh" + +using namespace Nymph; + +KTLOGGER(testslotdata, "TestSlotData") + +int main() +{ + try + { + KTTestProcessorD tpD; + + KTINFO(testslotdata, "Connecting test-data-signal to test-data-slot"); + // for simplicity the signal and slot are in the same processor, but that need not be, of course + tpD.ConnectASlot("test-data-signal", &tpD, "test-data-slot" ); + + KTINFO(testslotdata, "Emitting signals"); + KTINFO(testslotdata, "First test signal: true"); + tpD.EmitSignal(true); + KTINFO(testslotdata, "Second test signal: false"); + tpD.EmitSignal(false); + + KTINFO(testslotdata, "Tests complete"); + } + catch( boost::exception& e ) + { + KTERROR( testslotdata, "An exception was caught: " << diagnostic_information( e ) ); + return -1; + } + + return 0; +} + diff --git a/Library/Processor/KTSlot.hh b/Library/Processor/KTSlot.hh index 289ffb4..75b43b8 100644 --- a/Library/Processor/KTSlot.hh +++ b/Library/Processor/KTSlot.hh @@ -42,11 +42,11 @@ namespace Nymph public: /// Constructor for the case where the processor has the function that will be called by the slot template< class XFuncOwnerType > - KTSlot( const std::string& name, XFuncOwnerType* owner, void (XFuncOwnerType::*func)( Args... ), std::initializer_list< std::string > signals ); + KTSlot( const std::string& name, XFuncOwnerType* owner, void (XFuncOwnerType::*func)( Args... ), std::initializer_list< std::string > signals = {} ); /// Constructor for the case where the processor and the object with the function that will be called are different template< class XFuncOwnerType > - KTSlot( const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, void (XFuncOwnerType::*func)( Args... ), std::initializer_list< std::string > signals ); + KTSlot( const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, void (XFuncOwnerType::*func)( Args... ), std::initializer_list< std::string > signals = {} ); virtual ~KTSlot(); @@ -93,19 +93,22 @@ namespace Nymph template< class... XDataTypes > class KTSlotData : public KTSlot< KTDataPtr > { - //public: - //typedef XDataType data_type; - //typedef std::function< bool( KTDataPtr ) > function_signature; - //typedef typename function_signature::result_type return_type; - public: /// Constructor for the case where the processor has the function that will be called by the slot template< class XFuncOwnerType, class... XFuncDataTypes > - KTSlotData( const std::string& name, XFuncOwnerType* owner, bool (XFuncOwnerType::*func)( XFuncDataTypes&... ), KTSignalData* signalPtr=nullptr ); + KTSlotData( const std::string& name, XFuncOwnerType* owner, bool (XFuncOwnerType::*func)( XFuncDataTypes&... ), KTSignalData* signalPtr ); + + /// Constructor for the case where the processor has the function that will be called by the slot + template< class XFuncOwnerType, class... XFuncDataTypes > + KTSlotData( const std::string& name, XFuncOwnerType* owner, bool (XFuncOwnerType::*func)( XFuncDataTypes&... ) ); + + /// Constructor for the case where the processor and the object with the function that will be called are different + template< class XFuncOwnerType, class... XFuncDataTypes > + KTSlotData( const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, bool (XFuncOwnerType::*func)( XFuncDataTypes&... ), KTSignalData* signalPtr ); /// Constructor for the case where the processor and the object with the function that will be called are different template< class XFuncOwnerType, class... XFuncDataTypes > - KTSlotData( const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, bool (XFuncOwnerType::*func)( XFuncDataTypes&... ), KTSignalData* signalPtr=nullptr ); + KTSlotData( const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, bool (XFuncOwnerType::*func)( XFuncDataTypes&... ) ); virtual ~KTSlotData(); @@ -115,11 +118,6 @@ namespace Nymph template< typename... DataTypes > bool DataPresent( KTDataPtr data ); - //template< > - //bool DataPresent( KTDataPtr data ); - //template< typename DataType, typename... DataTypes > - //bool DataPresent( KTDataPtr data ); - //function_signature fFunc; std::function< bool (XDataTypes&...) > fFunc; @@ -250,6 +248,15 @@ namespace Nymph { } + template< class... XDataTypes > + template< class XFuncOwnerType, class... XFuncDataTypes > + KTSlotData< XDataTypes... >::KTSlotData(const std::string& name, XFuncOwnerType* owner, bool (XFuncOwnerType::*func)( XFuncDataTypes&... )) : + KTSlot( name, owner, this, &KTSlotData::operator() ), + fFunc( [func, owner]( XDataTypes... args ){ return (owner->*func)(args...);} ), + fSignalPtr( nullptr ) + { + } + template< class... XDataTypes > template< class XFuncOwnerType, class... XFuncDataTypes > KTSlotData< XDataTypes... >::KTSlotData(const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, bool (XFuncOwnerType::*func)( XFuncDataTypes&... ), KTSignalData* signalPtr) : @@ -259,6 +266,15 @@ namespace Nymph { } + template< class... XDataTypes > + template< class XFuncOwnerType, class... XFuncDataTypes > + KTSlotData< XDataTypes... >::KTSlotData(const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, bool (XFuncOwnerType::*func)( XFuncDataTypes&... )) : + KTSlot( name, proc, this, &KTSlotData::operator() ), + fFunc( [func, owner]( XDataTypes... args ){return (owner->*func) (args... );} ), + fSignalPtr( nullptr ) + { + } + template< class... XDataTypes > KTSlotData< XDataTypes... >::~KTSlotData() { From 6f6e071a3b0b1d558cda09c66125310f2332a7eb Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Thu, 8 Jun 2017 15:03:06 -0700 Subject: [PATCH 055/521] =?UTF-8?q?Partial=20implementation=20of=20data=20?= =?UTF-8?q?changes=20(won=E2=80=99t=20compile)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Executables/Validation/KTTestCuts.cc | 4 +- Executables/Validation/KTTestCuts.hh | 6 +- Executables/Validation/KTTestData.cc | 29 +------ Executables/Validation/KTTestData.hh | 40 +++------- Executables/Validation/KTTestProcessor.cc | 33 ++++---- Executables/Validation/KTTestProcessor.hh | 17 +--- Executables/Validation/TestApplyCut.cc | 10 +-- Executables/Validation/TestCut.cc | 2 +- Executables/Validation/TestCutFilter.cc | 12 +-- Executables/Validation/TestPrintData.cc | 26 +++---- Library/Application/KTDataQueueProcessor.cc | 6 +- Library/Application/KTDataQueueProcessor.hh | 30 +++---- Library/Application/KTPrintDataStructure.cc | 38 ++++----- Library/Application/KTPrintDataStructure.hh | 24 +++--- Library/Application/KTProcessorToolbox.cc | 2 +- Library/Application/KTProcessorToolbox.hh | 8 +- Library/Application/KTThroughputProfiler.cc | 4 +- Library/Application/KTThroughputProfiler.hh | 8 +- Library/CMakeLists.txt | 2 + Library/Data/KTApplyCut.cc | 12 +-- Library/Data/KTApplyCut.hh | 10 +-- Library/Data/KTCoreData.cc | 37 +++++++++ Library/Data/KTCoreData.hh | 42 ++++++++++ Library/Data/KTCut.hh | 40 +++++----- Library/Data/KTCutFilter.cc | 16 ++-- Library/Data/KTCutFilter.hh | 14 ++-- Library/Data/KTCutStatus.hh | 2 +- Library/Data/KTData.cc | 21 ++--- Library/Data/KTData.hh | 57 ++++++-------- Library/Data/KTDataPy.hh | 8 +- Library/Processor/KTPrimaryProcessor.cc | 2 +- Library/Processor/KTPrimaryProcessor.hh | 2 +- Library/Processor/KTSignal.hh | 8 +- Library/Processor/KTSlot.hh | 86 +++++++++++---------- Library/Processor/KTThreadReference.cc | 4 +- Library/Processor/KTThreadReference.hh | 26 +++---- 36 files changed, 355 insertions(+), 333 deletions(-) create mode 100644 Library/Data/KTCoreData.cc create mode 100644 Library/Data/KTCoreData.hh diff --git a/Executables/Validation/KTTestCuts.cc b/Executables/Validation/KTTestCuts.cc index dbc5758..bc8e153 100644 --- a/Executables/Validation/KTTestCuts.cc +++ b/Executables/Validation/KTTestCuts.cc @@ -33,7 +33,7 @@ namespace Nymph return true; } - bool KTAwesomeCut::Apply(KTData& data, KTTestData& testData) + bool KTAwesomeCut::Apply(KTCoreData& data, KTTestData& testData) { bool isCut = ! testData.GetIsAwesome(); KTDEBUG(testlog, "Is data awesome? " << testData.GetIsAwesome()); @@ -55,7 +55,7 @@ namespace Nymph return true; } - bool KTNotAwesomeCut::Apply(KTData& data, KTTestData& testData) + bool KTNotAwesomeCut::Apply(KTCoreData& data, KTTestData& testData) { bool isCut = testData.GetIsAwesome(); KTDEBUG(testlog, "Is data awesome? " << testData.GetIsAwesome()); diff --git a/Executables/Validation/KTTestCuts.hh b/Executables/Validation/KTTestCuts.hh index e1f159c..a0541cb 100644 --- a/Executables/Validation/KTTestCuts.hh +++ b/Executables/Validation/KTTestCuts.hh @@ -10,7 +10,7 @@ #include "KTCut.hh" #include "KTMemberVariable.hh" -#include "KTData.hh" +#include "KTCoreData.hh" namespace Nymph @@ -32,7 +32,7 @@ namespace Nymph bool Configure(const scarab::param_node* node); - bool Apply(KTData& data, KTTestData& testData); + bool Apply(KTCoreData& data, KTTestData& testData); }; // Cuts data that is IS awesome @@ -50,7 +50,7 @@ namespace Nymph bool Configure(const scarab::param_node* node); - bool Apply(KTData& data, KTTestData& testData); + bool Apply(KTCoreData& data, KTTestData& testData); }; } diff --git a/Executables/Validation/KTTestData.cc b/Executables/Validation/KTTestData.cc index 6aa5186..d879bcf 100644 --- a/Executables/Validation/KTTestData.cc +++ b/Executables/Validation/KTTestData.cc @@ -10,37 +10,12 @@ namespace Nymph { KTTestData::KTTestData() : - KTExtensibleData< KTTestData >(), - fIsAwesome(false) + KTData( "test-data" ), + fIsAwesome( false ) {} KTTestData::~KTTestData() {} - const std::string KTTestData::sName = "test-data"; - - - KTTestDerived1Data::KTTestDerived1Data() : - KTTestPolyDataBase< KTTestDerived1Data >() - { - fFunniness = 500; - } - - KTTestDerived1Data::~KTTestDerived1Data() - {} - - const std::string KTTestDerived1Data::sName = "test-derived-1-data"; - - KTTestDerived2Data::KTTestDerived2Data() : - KTTestPolyDataBase< KTTestDerived2Data >() - { - fFunniness = 1000000000000; - } - - KTTestDerived2Data::~KTTestDerived2Data() - {} - - const std::string KTTestDerived2Data::sName = "test-derived-2-data"; - } /* namespace Nymph */ diff --git a/Executables/Validation/KTTestData.hh b/Executables/Validation/KTTestData.hh index 42fa1fe..288bf92 100644 --- a/Executables/Validation/KTTestData.hh +++ b/Executables/Validation/KTTestData.hh @@ -8,59 +8,39 @@ #ifndef NYMPH_KTTESTDATA_HH_ #define NYMPH_KTTESTDATA_HH_ -#include "KTData.hh" +#include "KTCoreData.hh" #include "KTMemberVariable.hh" namespace Nymph { - class KTTestData : public KTExtensibleData< KTTestData > + class KTTestData : public KTData { public: KTTestData(); virtual ~KTTestData(); MEMBERVARIABLE(bool, IsAwesome); - - public: - static const std::string sName; - }; + DEFINE_EXT_DATA( KTTestData ); // defines KTTestDataExt + - template< class XDerivedDataType > - class KTTestPolyDataBase : public KTExtensibleData< XDerivedDataType > + class KTTestBaseData : public KTData { public: - KTTestPolyDataBase() : - KTExtensibleData< XDerivedDataType >(), + KTTestBaseData() : + KTData( "poly-data" ), fFunniness(1000.) {} - virtual ~KTTestPolyDataBase() {} + virtual ~KTTestBaseData() {} MEMBERVARIABLE(double, Funniness); }; - class KTTestDerived1Data : public KTTestPolyDataBase< KTTestDerived1Data > - { - public: - KTTestDerived1Data(); - virtual ~KTTestDerived1Data(); - - public: - static const std::string sName; - }; - - class KTTestDerived2Data : public KTTestPolyDataBase< KTTestDerived2Data > - { - public: - KTTestDerived2Data(); - virtual ~KTTestDerived2Data(); - - public: - static const std::string sName; - }; + DEFINE_EXT_DATA_2( KTTestDerived1DataHandle, KTTestBaseData ); + DEFINE_EXT_DATA_2( KTTestDerived2DataHandle, KTTestBaseData ); } /* namespace Nymph */ diff --git a/Executables/Validation/KTTestProcessor.cc b/Executables/Validation/KTTestProcessor.cc index c44d217..396a5ab 100644 --- a/Executables/Validation/KTTestProcessor.cc +++ b/Executables/Validation/KTTestProcessor.cc @@ -63,14 +63,14 @@ namespace Nymph void KTTestProcessorB::SlotFunc1(int input) { KTINFO(testsiglog, "Slot1: input is " << input); - fSlot1Wrapper->GetThreadRef()->Break( KTDataPtr(), fSlot1Wrapper->GetDoBreakpoint()); + fSlot1Wrapper->GetThreadRef()->Break( KTDataHandle(), fSlot1Wrapper->GetDoBreakpoint()); return; } void KTTestProcessorB::SlotFunc2(int input) { KTINFO(testsiglog, "Slot2: twice input is " << 2 * input); - fSlot2Wrapper->GetThreadRef()->Break( KTDataPtr(), fSlot2Wrapper->GetDoBreakpoint()); + fSlot2Wrapper->GetThreadRef()->Break( KTDataHandle(), fSlot2Wrapper->GetDoBreakpoint()); return; } @@ -123,17 +123,17 @@ namespace Nymph void KTTestProcessorD::EmitSignal(bool isAwesome) { - KTDataPtr dataPtr = std::make_shared< KTData >(); - KTTestData& data = dataPtr->Of< KTTestData >(); + KTDataHandle dataHandle = std::make_shared< KTCoreData >(); + KTTestData& data = dataHandle->Of< KTTestData >(); data.SetIsAwesome(isAwesome); - fDataSignal(dataPtr); + fDataSignal(dataHandle); return; } - bool KTTestProcessorD::SlotFunc(KTTestData& data) + void KTTestProcessorD::SlotFunc(KTTestData& data) { KTINFO(testsiglog, "Is the data awesome? " << data.GetIsAwesome()); - return true; + return; } @@ -141,8 +141,8 @@ namespace Nymph KTTestProcessorE::KTTestProcessorE( const std::string& name ) : KTProcessor( name ), - fDerived1DataSlot("derived-1", this, &KTTestProcessorE::BaseSlotFunc< KTTestDerived1Data >), - fDerived2DataSlot("derived-2", this, &KTTestProcessorE::BaseSlotFunc< KTTestDerived2Data >), + fDerived1DataSlot("derived-1", this, &KTTestProcessorE::BaseSlotFunc), + fDerived2DataSlot("derived-2", this, &KTTestProcessorE::BaseSlotFunc), fDerived1DataSignal("derived-1", this), fDerived2DataSignal("derived-2", this) { @@ -159,26 +159,25 @@ namespace Nymph void KTTestProcessorE::EmitSignals() { - KTDataPtr dataPtr = std::make_shared< KTData >(); + KTDataHandle dataHandle = std::make_shared< KTCoreData >(); KTINFO(testsiglog, "Creating data objects"); - KTTestDerived1Data& data1 = dataPtr->Of< KTTestDerived1Data >(); - KTTestDerived2Data& data2 = dataPtr->Of< KTTestDerived2Data >(); + dataHandle->Of< KTTestDerived1DataHandle >(); + dataHandle->Of< KTTestDerived2DataHandle >(); KTINFO(testsiglog, "Emitting data-1 signal"); - fDerived1DataSignal( dataPtr ); + fDerived1DataSignal( dataHandle ); KTINFO(testsiglog, "Emitting data-2 signal"); - fDerived2DataSignal( dataPtr ); + fDerived2DataSignal( dataHandle ); return; } - void KTTestProcessorE::PrintFunniness( unsigned funniness) + void KTTestProcessorE::BaseSlotFunc(KTTestBaseData& data) { - KTINFO(testsiglog, "Data funniness measured to be: <" << funniness << ">"); + KTINFO(testsiglog, "Data funniness measured to be: <" << data.GetFunniness() << ">"); return; } - } /* namespace Nymph */ diff --git a/Executables/Validation/KTTestProcessor.hh b/Executables/Validation/KTTestProcessor.hh index 5b6b507..6d482e4 100644 --- a/Executables/Validation/KTTestProcessor.hh +++ b/Executables/Validation/KTTestProcessor.hh @@ -89,7 +89,7 @@ namespace Nymph // Creates a KTTestData object, sets the awesomeness to the given value, and emits fSignal void EmitSignal(bool isAwesome = true); - bool SlotFunc(KTTestData& data); + void SlotFunc(KTTestData& data); private: KTSlotData< KTTestData > fDataSlot; @@ -116,12 +116,11 @@ namespace Nymph void EmitSignals(); - template< class XDerivedDataType > - bool BaseSlotFunc(KTTestPolyDataBase< XDerivedDataType >& data); + void BaseSlotFunc(KTTestBaseData& data); private: - KTSlotData< KTTestDerived1Data > fDerived1DataSlot; - KTSlotData< KTTestDerived2Data > fDerived2DataSlot; + KTSlotData< KTTestDerived1DataHandle > fDerived1DataSlot; + KTSlotData< KTTestDerived2DataHandle > fDerived2DataSlot; KTSignalData fDerived1DataSignal; KTSignalData fDerived2DataSignal; @@ -130,13 +129,5 @@ namespace Nymph void PrintFunniness( unsigned funniness ); }; - template< class XDerivedDataType > - bool KTTestProcessorE::BaseSlotFunc(KTTestPolyDataBase< XDerivedDataType >& data) - { - PrintFunniness( data.GetFunniness() ); - return true; - } - - } /* namespace Nymph */ #endif /* KTTESTPROCESSOR_HH_ */ diff --git a/Executables/Validation/TestApplyCut.cc b/Executables/Validation/TestApplyCut.cc index 030022c..4d8e7a8 100644 --- a/Executables/Validation/TestApplyCut.cc +++ b/Executables/Validation/TestApplyCut.cc @@ -18,17 +18,17 @@ using namespace std; int main() { - KTDataPtr dataPtr(new KTData()); - KTTestData& testData = dataPtr->Of< KTTestData >(); + KTDataHandle dataHandle(new KTCoreData()); + KTTestData& testData = dataHandle->Of< KTTestData >(); - KTCutStatus& cutStatus = dataPtr->CutStatus(); + KTCutStatus& cutStatus = dataHandle->CutStatus(); KTINFO(testlog, "Initial cut state: " << cutStatus.IsCut()); KTApplyCut applyCut; KTINFO(testlog, "Applying awesome cut"); applyCut.SetCut(new KTAwesomeCut()); - applyCut.ApplyCut(dataPtr); + applyCut.ApplyCut(dataHandle); KTINFO(testlog, "Cuts present: " << cutStatus.CutResultsPresent()) KTINFO(testlog, "Has cut result \"awesome-cut\"? " << cutStatus.HasCutResult("awesome-cut")); @@ -40,7 +40,7 @@ int main() KTINFO(testlog, "Applying not-awesome cut"); applyCut.SelectCut("not-awesome-cut"); - applyCut.ApplyCut(dataPtr); + applyCut.ApplyCut(dataHandle); KTINFO(testlog, "Cuts present: " << cutStatus.CutResultsPresent()) KTINFO(testlog, "Has cut result \"awesome-cut\"? " << cutStatus.HasCutResult("awesome-cut")); diff --git a/Executables/Validation/TestCut.cc b/Executables/Validation/TestCut.cc index 21bb358..8497919 100644 --- a/Executables/Validation/TestCut.cc +++ b/Executables/Validation/TestCut.cc @@ -17,7 +17,7 @@ using namespace std; int main() { - KTData data; + KTCoreData data; KTTestData& testData = data.Of< KTTestData >(); KTCutStatus& cutStatus = data.CutStatus(); diff --git a/Executables/Validation/TestCutFilter.cc b/Executables/Validation/TestCutFilter.cc index 2f31103..8888e5a 100644 --- a/Executables/Validation/TestCutFilter.cc +++ b/Executables/Validation/TestCutFilter.cc @@ -19,17 +19,17 @@ using namespace std; int main() { - KTDataPtr dataPtr(new KTData()); - KTTestData& testData = dataPtr->Of< KTTestData >(); + KTDataHandle dataHandle(new KTCoreData()); + KTTestData& testData = dataHandle->Of< KTTestData >(); - KTCutStatus& cutStatus = dataPtr->CutStatus(); + KTCutStatus& cutStatus = dataHandle->CutStatus(); KTINFO(testlog, "Initial cut state: " << cutStatus.IsCut()); KTApplyCut applyCut; KTINFO(testlog, "Applying awesome cut"); applyCut.SetCut(new KTAwesomeCut()); - applyCut.ApplyCut(dataPtr); + applyCut.ApplyCut(dataHandle); KTINFO(testlog, "Cuts present: " << cutStatus.CutResultsPresent()) KTINFO(testlog, "Has cut result \"awesome-cut\"? " << cutStatus.HasCutResult("awesome-cut")); @@ -41,7 +41,7 @@ int main() KTINFO(testlog, "Applying not-awesome cut"); applyCut.SelectCut("not-awesome-cut"); - applyCut.ApplyCut(dataPtr); + applyCut.ApplyCut(dataHandle); KTINFO(testlog, "Cuts present: " << cutStatus.CutResultsPresent()) KTINFO(testlog, "Has cut result \"awesome-cut\"? " << cutStatus.HasCutResult("awesome-cut")); @@ -54,7 +54,7 @@ int main() KTINFO(testlog, "Cut state of is: " << cutStatus.GetCutState< KTNotAwesomeCut::Result >()); KTCutFilter cutFilter; - KTData& data = dataPtr->Of< KTData >(); + KTCoreData& data = dataHandle->Of< KTCoreData >(); KTINFO(testlog, "Filtering with all cuts"); cutFilter.SetCutMaskAll(); diff --git a/Executables/Validation/TestPrintData.cc b/Executables/Validation/TestPrintData.cc index 59d70ca..e73e9d0 100644 --- a/Executables/Validation/TestPrintData.cc +++ b/Executables/Validation/TestPrintData.cc @@ -34,21 +34,21 @@ namespace Nymph bool Configure(const scarab::param_node* node) {return true;} - bool Apply(KTData& data, KTTestData& testData) + bool Apply(KTCoreData& data, KTTestData& testData) { bool isCut = ! testData.GetIsAwesome(); data.CutStatus().AddCutResult< KTAwesomeCut::Result >(isCut); return isCut; } - bool Apply(KTDataPtr dataPtr) + bool Apply(KTDataHandle dataHandle) { - if (! dataPtr->Has< KTTestData >()) + if (! dataHandle->Has< KTTestDataExt >()) { KTERROR(testlog, "Data type was not present"); return false; } - return Apply(dataPtr->Of< KTData >(), dataPtr->Of< KTTestData >()); + return Apply(dataHandle->Of< KTCoreData >(), dataHandle->Of< KTTestDataExt >()); } }; @@ -70,7 +70,7 @@ namespace Nymph bool Configure(const scarab::param_node* node) {return true;} - bool Apply(KTData& data, KTTestData& testData) + bool Apply(KTCoreData& data, KTTestData& testData) { bool isCut = testData.GetIsAwesome(); // use the name-based AddCutResult @@ -78,14 +78,14 @@ namespace Nymph return isCut; } - bool Apply(KTDataPtr dataPtr) + bool Apply(KTDataHandle dataHandle) { - if (! dataPtr->Has< KTTestData >()) + if (! dataHandle->Has< KTTestData >()) { KTERROR(testlog, "Data type was not present"); return false; } - return Apply(dataPtr->Of< KTData >(), dataPtr->Of< KTTestData >()); + return Apply(dataHandle->Of< KTCoreData >(), dataHandle->Of< KTTestData >()); } }; @@ -103,9 +103,9 @@ using namespace std; int main() { - KTDataPtr dataPtr(new KTData()); - KTData& data = dataPtr->Of< KTData >(); - KTTestData& testData = dataPtr->Of< KTTestData >(); + KTDataHandle dataHandle(new KTCoreData()); + KTCoreDataExt& data = dataHandle->Of< KTCoreDataExt >(); + KTTestDataExt& testData = dataHandle->Of< KTTestDataExt >(); KTINFO(testlog, "Applying awesome cut"); KTAwesomeCut cut; @@ -118,10 +118,10 @@ int main() KTPrintDataStructure printer; KTINFO(testlog, "Printing data structure"); - printer.PrintDataStructure(dataPtr); + printer.PrintDataStructure(dataHandle); KTINFO(testlog, "Printing cut structure"); - printer.PrintCutStructure(dataPtr); + printer.PrintCutStructure(dataHandle); return 0; } diff --git a/Library/Application/KTDataQueueProcessor.cc b/Library/Application/KTDataQueueProcessor.cc index bca51fd..4a7975b 100644 --- a/Library/Application/KTDataQueueProcessor.cc +++ b/Library/Application/KTDataQueueProcessor.cc @@ -33,19 +33,19 @@ namespace Nymph return true; } - void KTDataQueueProcessor::EmitDataSignal(KTDataPtr data) + void KTDataQueueProcessor::EmitDataSignal(KTDataHandle data) { fDataSignal(data); return; } - void KTDataQueueProcessor::QueueData(KTDataPtr& data) + void KTDataQueueProcessor::QueueData(KTDataHandle& data) { fQueueDataSW->GetThreadRef()->Break(data, fQueueDataSW->GetDoBreakpoint()); return DoQueueData(data); } /* - void KTDataQueueProcessor::QueueDataList(list< KTDataPtr >* dataList) + void KTDataQueueProcessor::QueueDataList(list< KTDataHandle >* dataList) { return DoQueueDataList(dataList, &KTDataQueueProcessor::EmitDataSignal); } diff --git a/Library/Application/KTDataQueueProcessor.hh b/Library/Application/KTDataQueueProcessor.hh index 867efb8..bb2b54a 100644 --- a/Library/Application/KTDataQueueProcessor.hh +++ b/Library/Application/KTDataQueueProcessor.hh @@ -11,7 +11,7 @@ #include "KTPrimaryProcessor.hh" #include "KTConcurrentQueue.hh" -#include "KTData.hh" +#include "KTCoreData.hh" #include "KTLogger.hh" #include "KTSlot.hh" @@ -46,11 +46,11 @@ namespace Nymph class KTDataQueueProcessorTemplate : public KTPrimaryProcessor { public: - typedef void (XProcessorType::*FuncPtrType)(KTDataPtr); + typedef void (XProcessorType::*FuncPtrType)(KTDataHandle); struct DataAndFunc { - KTDataPtr fData; + KTDataHandle fData; FuncPtrType fFuncPtr; }; @@ -113,15 +113,15 @@ namespace Nymph protected: /// Queue an data object with a provided function /// Assumes ownership of the data; original shared pointer will be nullified - void DoQueueData(KTDataPtr& data, FuncPtrType func); + void DoQueueData(KTDataHandle& data, FuncPtrType func); /// Queue an data object with fFuncPtr /// Assumes ownership of the data; original shared pointer will be nullified - void DoQueueData(KTDataPtr& data); + void DoQueueData(KTDataHandle& data); /// Queue a list of data objects /// Assumes ownership of all data objects and the list; original shared pointers will be nullified - //void DoQueueDataList(std::list< KTDataPtr& >* dataList, void (XProcessorType::*fFuncPtr)(KTDataPtr)); + //void DoQueueDataList(std::list< KTDataHandle& >* dataList, void (XProcessorType::*fFuncPtr)(KTDataHandle)); //********* // Slots @@ -159,10 +159,10 @@ namespace Nymph Available configuration values: Slots: - - "data": void (KTDataPtr) -- Queue a data object for asynchronous processing; use signal "data" + - "data": void (KTDataHandle) -- Queue a data object for asynchronous processing; use signal "data" Signals: - - "data": void (KTDataPtr) -- Emitted for each data object in the queue + - "data": void (KTDataHandle) -- Emitted for each data object in the queue - "queue-done": void () -- Emitted when queue is emptied (inherited from KTDataQueueProcessorTemplate) */ class KTDataQueueProcessor : public KTDataQueueProcessorTemplate< KTDataQueueProcessor > @@ -174,7 +174,7 @@ namespace Nymph bool ConfigureSubClass(const scarab::param_node* node); public: - void EmitDataSignal(KTDataPtr data); + void EmitDataSignal(KTDataHandle data); //*************** // Signals @@ -189,12 +189,12 @@ namespace Nymph public: /// Queue an data object; will emit data signal /// Assumes ownership of the data; original shared pointer will be nullified - void QueueData(KTDataPtr& data); + void QueueData(KTDataHandle& data); KTSlotWrapper* fQueueDataSW; /// Queue a list of data objects; will emit data signal /// Assumes ownership of all data objects and the list; original shared pointers will be nullified - //void QueueDataList(std::list< KTDataPtr >* dataList); + //void QueueDataList(std::list< KTDataHandle >* dataList); }; @@ -303,7 +303,7 @@ namespace Nymph template< class XProcessorType > - void KTDataQueueProcessorTemplate< XProcessorType >::DoQueueData(KTDataPtr& data, FuncPtrType func) + void KTDataQueueProcessorTemplate< XProcessorType >::DoQueueData(KTDataHandle& data, FuncPtrType func) { KTDEBUG(eqplog, "Queueing data"); DataAndFunc daf; @@ -315,16 +315,16 @@ namespace Nymph } template< class XProcessorType > - void KTDataQueueProcessorTemplate< XProcessorType >::DoQueueData(KTDataPtr& data) + void KTDataQueueProcessorTemplate< XProcessorType >::DoQueueData(KTDataHandle& data) { DoQueueData(data, fFuncPtr); return; } /* template< class XProcessorType > - void KTDataQueueProcessorTemplate< XProcessorType >::DoQueueDataList(std::list< KTDataPtr& >* dataList, void (XProcessorType::*func)(KTDataPtr)) + void KTDataQueueProcessorTemplate< XProcessorType >::DoQueueDataList(std::list< KTDataHandle& >* dataList, void (XProcessorType::*func)(KTDataHandle)) { - typedef std::list< KTDataPtr > DataList; + typedef std::list< KTDataHandle > DataList; KTDEBUG(eqplog, "Queueing data objects"); DataAndFunc daf; diff --git a/Library/Application/KTPrintDataStructure.cc b/Library/Application/KTPrintDataStructure.cc index 29c42e7..48d6c70 100644 --- a/Library/Application/KTPrintDataStructure.cc +++ b/Library/Application/KTPrintDataStructure.cc @@ -38,52 +38,52 @@ namespace Nymph return true; } - void KTPrintDataStructure::PrintDataStructure(KTDataPtr dataPtr) + void KTPrintDataStructure::PrintDataStructure(KTDataHandle dataHandle) { - DoPrintDataStructure(dataPtr); + DoPrintDataStructure(dataHandle); KTSlotWrapper* slotWrap = fDataStructSlot.GetSlotWrapper(); - slotWrap->GetThreadRef()->Break( dataPtr, slotWrap->GetDoBreakpoint() ); + slotWrap->GetThreadRef()->Break( dataHandle, slotWrap->GetDoBreakpoint() ); - fDataSignal(dataPtr); + fDataSignal(dataHandle); return; } - void KTPrintDataStructure::PrintCutStructure(KTDataPtr dataPtr) + void KTPrintDataStructure::PrintCutStructure(KTDataHandle dataHandle) { - DoPrintCutStructure(dataPtr); + DoPrintCutStructure(dataHandle); KTSlotWrapper* slotWrap = fCutStructSlot.GetSlotWrapper(); - fCutStructSlot.GetSlotWrapper()->GetThreadRef()->Break( dataPtr, slotWrap->GetDoBreakpoint() ); + fCutStructSlot.GetSlotWrapper()->GetThreadRef()->Break( dataHandle, slotWrap->GetDoBreakpoint() ); - fDataSignal(dataPtr); + fDataSignal(dataHandle); return; } - void KTPrintDataStructure::PrintDataAndCutStructure(KTDataPtr dataPtr) + void KTPrintDataStructure::PrintDataAndCutStructure(KTDataHandle dataHandle) { - DoPrintDataStructure(dataPtr); - DoPrintCutStructure(dataPtr); + DoPrintDataStructure(dataHandle); + DoPrintCutStructure(dataHandle); KTSlotWrapper* slotWrap = fDataAndCutStructSlot.GetSlotWrapper(); - fDataAndCutStructSlot.GetSlotWrapper()->GetThreadRef()->Break( dataPtr, slotWrap->GetDoBreakpoint() ); + fDataAndCutStructSlot.GetSlotWrapper()->GetThreadRef()->Break( dataHandle, slotWrap->GetDoBreakpoint() ); - fDataSignal(dataPtr); + fDataSignal(dataHandle); return; } - void KTPrintDataStructure::DoPrintDataStructure(KTDataPtr dataPtr) + void KTPrintDataStructure::DoPrintDataStructure(KTDataHandle dataHandle) { std::stringstream printbuf; printbuf << "\nData Structure:\n"; - printbuf << "\t- " << dataPtr->Name() << '\n'; - KTDEBUG(datalog, "Found data type " << dataPtr->Name()); - KTExtensibleStructCore< KTDataCore >* nextData = dataPtr->Next(); + printbuf << "\t- " << dataHandle->Name() << '\n'; + KTDEBUG(datalog, "Found data type " << dataHandle->Name()); + KTExtensibleStructCore< KTDataCore >* nextData = dataHandle->Next(); while (nextData != NULL) { printbuf << "\t- " << nextData->Name() << '\n'; @@ -96,11 +96,11 @@ namespace Nymph return; } - void KTPrintDataStructure::DoPrintCutStructure(KTDataPtr dataPtr) + void KTPrintDataStructure::DoPrintCutStructure(KTDataHandle dataHandle) { std::stringstream printbuf; - KTCutStatus& cutStatus = dataPtr->CutStatus(); + KTCutStatus& cutStatus = dataHandle->CutStatus(); printbuf << "\n" << cutStatus; const KTCutResult* cutResult = cutStatus.CutResults(); diff --git a/Library/Application/KTPrintDataStructure.hh b/Library/Application/KTPrintDataStructure.hh index 204ab09..6df0a69 100644 --- a/Library/Application/KTPrintDataStructure.hh +++ b/Library/Application/KTPrintDataStructure.hh @@ -35,12 +35,12 @@ namespace Nymph Available configuration values: none Slots: - - "print-data": void (KTDataPtr) -- Prints the structure of the data object; Does not modify the data or cuts; Emits signal "data" - - "print-cuts": void (KTDataPtr) -- Prints the structure of the data's cuts; Does not modify the data or cuts; Emits signal "data" - - "print-data-and-cuts": void (KTDataPtr) -- Prints the structure of the data object and its cuts; Does not modify the data or cuts; Emits signal "data" + - "print-data": void (KTDataHandle) -- Prints the structure of the data object; Does not modify the data or cuts; Emits signal "data" + - "print-cuts": void (KTDataHandle) -- Prints the structure of the data's cuts; Does not modify the data or cuts; Emits signal "data" + - "print-data-and-cuts": void (KTDataHandle) -- Prints the structure of the data object and its cuts; Does not modify the data or cuts; Emits signal "data" Signals: - - "data": void (KTDataPtr) -- Emitted after structure information is printed + - "data": void (KTDataHandle) -- Emitted after structure information is printed */ class KTPrintDataStructure : public KTProcessor @@ -52,13 +52,13 @@ namespace Nymph bool Configure(const scarab::param_node* node); public: - void PrintDataStructure(KTDataPtr dataPtr); - void PrintCutStructure(KTDataPtr dataPtr); - void PrintDataAndCutStructure(KTDataPtr dataPtr); + void PrintDataStructure(KTDataHandle dataHandle); + void PrintCutStructure(KTDataHandle dataHandle); + void PrintDataAndCutStructure(KTDataHandle dataHandle); private: - void DoPrintDataStructure(KTDataPtr dataPtr); - void DoPrintCutStructure(KTDataPtr dataPtr); + void DoPrintDataStructure(KTDataHandle dataHandle); + void DoPrintCutStructure(KTDataHandle dataHandle); //*************** // Signals @@ -72,9 +72,9 @@ namespace Nymph //*************** private: - KTSlot< KTDataPtr > fDataStructSlot; - KTSlot< KTDataPtr > fCutStructSlot; - KTSlot< KTDataPtr > fDataAndCutStructSlot; + KTSlot< KTDataHandle > fDataStructSlot; + KTSlot< KTDataHandle > fCutStructSlot; + KTSlot< KTDataHandle > fDataAndCutStructSlot; }; } diff --git a/Library/Application/KTProcessorToolbox.cc b/Library/Application/KTProcessorToolbox.cc index 5b19a1e..1f18885 100644 --- a/Library/Application/KTProcessorToolbox.cc +++ b/Library/Application/KTProcessorToolbox.cc @@ -914,7 +914,7 @@ namespace Nymph return; } - KTDataPtr KTProcessorToolbox::GetData( const std::string& threadName ) + KTDataHandle KTProcessorToolbox::GetData( const std::string& threadName ) { //boost_unique_lock threadFuturesLock( fThreadReferencesMutex ); boost_unique_lock breakContLock( fBreakContMutex ); diff --git a/Library/Application/KTProcessorToolbox.hh b/Library/Application/KTProcessorToolbox.hh index 59df4d2..6e13edb 100644 --- a/Library/Application/KTProcessorToolbox.hh +++ b/Library/Application/KTProcessorToolbox.hh @@ -229,12 +229,12 @@ namespace Nymph void JoinRunThread(); - KTDataPtr GetData( const std::string& threadName ); + KTDataHandle GetData( const std::string& threadName ); private: friend class KTThreadReference; - typedef boost::shared_future< KTDataPtr > Future; + typedef boost::shared_future< KTDataHandle > Future; void StartSingleThreadedRun(); void StartMultiThreadedRun(); @@ -285,8 +285,8 @@ namespace Nymph } }; - typedef KTThreadRefFutureIter< boost::unique_future< KTDataPtr >, std::vector< std::shared_ptr< KTThreadReference > >::iterator > KTThreadRefFutureIterator; - typedef KTThreadRefFutureIter< const boost::unique_future< KTDataPtr >, std::vector< std::shared_ptr< KTThreadReference > >::const_iterator > KTThreadRefFutureConstIterator; + typedef KTThreadRefFutureIter< boost::unique_future< KTDataHandle >, std::vector< std::shared_ptr< KTThreadReference > >::iterator > KTThreadRefFutureIterator; + typedef KTThreadRefFutureIter< const boost::unique_future< KTDataHandle >, std::vector< std::shared_ptr< KTThreadReference > >::const_iterator > KTThreadRefFutureConstIterator; inline void KTProcessorToolbox::PopBackOfRunQueue() diff --git a/Library/Application/KTThroughputProfiler.cc b/Library/Application/KTThroughputProfiler.cc index 19e43fa..700e940 100644 --- a/Library/Application/KTThroughputProfiler.cc +++ b/Library/Application/KTThroughputProfiler.cc @@ -64,7 +64,7 @@ namespace Nymph return Diff(fTimeStart, fTimeEnd); } - void KTThroughputProfiler::StartProfiling(KTDataPtr header) + void KTThroughputProfiler::StartProfiling(KTDataHandle header) { KTINFO(proflog, "Profiling started"); fNDataProcessed = 0; @@ -72,7 +72,7 @@ namespace Nymph return; } - void KTThroughputProfiler::Data(KTDataPtr data) + void KTThroughputProfiler::Data(KTDataHandle data) { (void)data; fNDataProcessed++; diff --git a/Library/Application/KTThroughputProfiler.hh b/Library/Application/KTThroughputProfiler.hh index afd4ea5..1fcdd03 100644 --- a/Library/Application/KTThroughputProfiler.hh +++ b/Library/Application/KTThroughputProfiler.hh @@ -14,7 +14,7 @@ #include "KTProcessor.hh" -#include "KTData.hh" +#include "KTCoreData.hh" #include #include @@ -70,7 +70,7 @@ namespace Nymph Slots: - "start": void (KTEggHeader*) -- Start the timer - - "data": void (KTDataPtr) -- Increment the counter on the number of data slices + - "data": void (KTDataHandle) -- Increment the counter on the number of data slices - "stop": void () -- Stop the timer */ @@ -86,9 +86,9 @@ namespace Nymph void Start(); void Stop(); - void StartProfiling(KTDataPtr data); + void StartProfiling(KTDataHandle data); - void Data(KTDataPtr data); + void Data(KTDataHandle data); void Finish(); diff --git a/Library/CMakeLists.txt b/Library/CMakeLists.txt index 28a7e8d..c0692b4 100644 --- a/Library/CMakeLists.txt +++ b/Library/CMakeLists.txt @@ -23,6 +23,7 @@ set( NYMPH_HEADERFILES ${UTIL_DIR}/KTTIFactory.hh ${UTIL_DIR}/KTTime.hh ${DATA_DIR}/KTApplyCut.hh + ${DATA_DIR}/KTCoreData.hh ${DATA_DIR}/KTCut.hh ${DATA_DIR}/KTCutFilter.hh ${DATA_DIR}/KTCutResult.hh @@ -58,6 +59,7 @@ set( NYMPH_SOURCEFILES ${UTIL_DIR}/KTException.cc ${UTIL_DIR}/KTTime.cc ${DATA_DIR}/KTApplyCut.cc + ${DATA_DIR}/KTCoreData.cc ${DATA_DIR}/KTCut.cc ${DATA_DIR}/KTCutFilter.cc ${DATA_DIR}/KTCutStatus.cc diff --git a/Library/Data/KTApplyCut.cc b/Library/Data/KTApplyCut.cc index 7bc975a..14fad8b 100644 --- a/Library/Data/KTApplyCut.cc +++ b/Library/Data/KTApplyCut.cc @@ -83,7 +83,7 @@ namespace Nymph } - void KTApplyCut::ApplyCut(KTDataPtr dataPtr) + void KTApplyCut::ApplyCut(KTDataHandle dataHandle) { std::shared_ptr< KTThreadReference > ref = fApplyCutSW->GetThreadRef(); @@ -93,19 +93,19 @@ namespace Nymph return; } - bool cutFailed = fCut->Apply(dataPtr); + bool cutFailed = fCut->Apply(dataHandle); - ref->Break( dataPtr, fApplyCutSW->GetDoBreakpoint() ); + ref->Break( dataHandle, fApplyCutSW->GetDoBreakpoint() ); if (cutFailed) { - fAfterCutFailSignal(dataPtr); + fAfterCutFailSignal(dataHandle); } else { - fAfterCutPassSignal(dataPtr); + fAfterCutPassSignal(dataHandle); } - fAfterCutSignal(dataPtr); + fAfterCutSignal(dataHandle); return; } diff --git a/Library/Data/KTApplyCut.hh b/Library/Data/KTApplyCut.hh index 79be604..72564b0 100644 --- a/Library/Data/KTApplyCut.hh +++ b/Library/Data/KTApplyCut.hh @@ -43,12 +43,12 @@ namespace Nymph - "[cut name]": subtree -- specifies the cut to be used; parent node for the cut configuration Slots: - - "apply": void (KTDataPtr) -- Applies the cut to the received data; Requirements are set by the cut; No data is added. + - "apply": void (KTDataHandle) -- Applies the cut to the received data; Requirements are set by the cut; No data is added. Signals: - - "all": void (KTDataPtr) -- Emitted upon application of the cut regardless of cut result. - - "pass": void (KTDataPtr) -- Emitted upon application of the cut if the cut passed. - - "fail": void (KTDataPtr) -- Emitted upon application of the cut if the cut failed. + - "all": void (KTDataHandle) -- Emitted upon application of the cut regardless of cut result. + - "pass": void (KTDataHandle) -- Emitted upon application of the cut if the cut passed. + - "fail": void (KTDataHandle) -- Emitted upon application of the cut if the cut failed. */ class KTApplyCut : public KTProcessor @@ -67,7 +67,7 @@ namespace Nymph KTCut* fCut; public: - void ApplyCut(KTDataPtr dataPtr); + void ApplyCut(KTDataHandle dataHandle); //*************** diff --git a/Library/Data/KTCoreData.cc b/Library/Data/KTCoreData.cc new file mode 100644 index 0000000..70f817d --- /dev/null +++ b/Library/Data/KTCoreData.cc @@ -0,0 +1,37 @@ +/* + * KTCoreData.cc + * + * Created on: Aug 24, 2012 + * Author: nsoblath + */ + +#include "KTCoreData.hh" + +namespace Nymph +{ + KTCoreData::KTCoreData() : + KTData( "data" ), + fCounter( 0 ), + fLastData( false ), + fCutStatus() + { + } + + KTCoreData::KTCoreData( const KTCoreData& orig ) : + KTData( orig ), + fCounter( orig.fCounter ), + fLastData( orig.fLastData ), + fCutStatus( orig.fCutStatus ) + {} + + KTCoreData::KTCoreData( KTCoreData&& orig ) : + KTData( orig ), + fCounter( std::move( orig.fCounter ) ), + fLastData( std::move( orig.fLastData ) ), + fCutStatus( std::move( orig.fCutStatus ) ) + {} + + KTCoreData::~KTCoreData() + {} + +} /* namespace Nymph */ diff --git a/Library/Data/KTCoreData.hh b/Library/Data/KTCoreData.hh new file mode 100644 index 0000000..bf4b520 --- /dev/null +++ b/Library/Data/KTCoreData.hh @@ -0,0 +1,42 @@ +/* + * KTCoreData.hh + * + * Created on: Aug 24, 2012 + * Author: nsoblath + */ + +#ifndef KTCOREDATA_HH_ +#define KTCOREDATA_HH_ + +#include "KTData.hh" + +#include "KTCutStatus.hh" +#include "KTMemberVariable.hh" + +#include +#include + +namespace Nymph +{ + + class KTCoreData : public KTData + { + public: + KTCoreData(); + KTCoreData( const KTCoreData& orig ); + KTCoreData( KTCoreData&& orig ); + virtual ~KTCoreData(); + + MEMBERVARIABLE( unsigned, Counter ); + MEMBERVARIABLE( bool, LastData ); + + MEMBERVARIABLE_REF( KTCutStatus, CutStatus ); + + }; + + DEFINE_EXT_DATA( KTCoreData ) + + typedef std::shared_ptr< KTCoreData > KTDataHandle; + +} /* namespace Nymph */ +#endif /* KTCOREDATA_HH_ */ diff --git a/Library/Data/KTCut.hh b/Library/Data/KTCut.hh index c6ecfc5..c68246b 100644 --- a/Library/Data/KTCut.hh +++ b/Library/Data/KTCut.hh @@ -10,7 +10,7 @@ #include "KTConfigurable.hh" #include "KTCutResult.hh" -#include "KTData.hh" +#include "KTCoreData.hh" #include "KTExtensibleStructFactory.hh" #include "KTLogger.hh" #include "KTMemberVariable.hh" @@ -33,13 +33,13 @@ namespace Nymph - Public nested class called Result, inheriting from KTExtensibleCutResult< Result >, and containing a public static std::string name sName. - Cut registration using the macro KT_REGISTER_CUT([class name]) - Implementation of bool Configure(const scarab::param_node*) - - Implementation of bool Apply(KTData&, ) + - Implementation of bool Apply(KTCoreData&, ) Your cut class should inherit from KTCutOneArg or KTCutTwoArgs, depending on the number of data types involved in your cut. The existence of [class name]::Result and [class name]::Result::sName are enforces at compile time by the KT_REGISTER_CUT macro. - The functions bool Configure(const scarab::param_node*) and void Apply(KTData&, ) are abstract in the base classes, and therefore must be implemented. + The functions bool Configure(const scarab::param_node*) and void Apply(KTCoreData&, ) are abstract in the base classes, and therefore must be implemented. Boolean return value interpretation: - TRUE means the cut was failed @@ -69,7 +69,7 @@ namespace Nymph MEMBERVARIABLE(double, AwesomenessThreshold); public: - bool Apply(KTData& data, KTSomeData& data); + bool Apply(KTCoreData& data, KTSomeData& data); }; @@ -96,7 +96,7 @@ namespace Nymph return true; } - bool KTAwesomenessCut::Apply(KTData& data, KTSomeData& someData) + bool KTAwesomenessCut::Apply(KTCoreData& data, KTSomeData& someData) { bool isCut = someData.Awesomeness() < fAwesomenessThreshold; data.GetCutStatus().AddCutResult< KTAwesomenessCut::Result >(isCut); @@ -115,7 +115,7 @@ namespace Nymph KTCut(const std::string& name = "default-cut-name"); virtual ~KTCut(); - virtual bool Apply(KTDataPtr) = 0; + virtual bool Apply(KTDataHandle) = 0; }; @@ -130,9 +130,9 @@ namespace Nymph KTCutOneArg(const std::string& name = "default-cut-name"); virtual ~KTCutOneArg(); - virtual bool Apply(KTData& data, XDataType& dataType) = 0; + virtual bool Apply(KTCoreData& data, XDataType& dataType) = 0; - virtual bool Apply(KTDataPtr dataPtr); + virtual bool Apply(KTDataHandle dataHandle); }; @@ -147,9 +147,9 @@ namespace Nymph KTCutTwoArgs(const std::string& name = "default-cut-name"); virtual ~KTCutTwoArgs(); - virtual bool Apply(KTData& data, XDataType1& dataType1, XDataType2& dataType2) = 0; + virtual bool Apply(KTCoreData& data, XDataType1& dataType1, XDataType2& dataType2) = 0; - virtual bool Apply(KTDataPtr dataPtr); + virtual bool Apply(KTDataHandle dataHandle); }; @@ -168,14 +168,14 @@ namespace Nymph {} template< class XDataType > - bool KTCutOneArg< XDataType >::Apply(KTDataPtr dataPtr) + bool KTCutOneArg< XDataType >::Apply(KTDataHandle dataHandle) { - if (! dataPtr->Has< XDataType >()) + if (! dataHandle->Has< XDataType >()) { KTERROR(cutlog_h, "Data type <" << scarab::type(XDataType()) << "> was not present"); return false; } - return Apply(dataPtr->Of< KTData >(), dataPtr->Of< XDataType >()); + return Apply(dataHandle->Of< KTCoreData >(), dataHandle->Of< XDataType >()); } @@ -190,23 +190,23 @@ namespace Nymph {} template< class XDataType1, class XDataType2 > - bool KTCutTwoArgs< XDataType1, XDataType2 >::Apply(KTDataPtr dataPtr) + bool KTCutTwoArgs< XDataType1, XDataType2 >::Apply(KTDataHandle dataHandle) { - if (! dataPtr->Has< XDataType1 >()) + if (! dataHandle->Has< XDataType1 >()) { KTERROR(cutlog_h, "Data type <" << scarab::type(XDataType1()) << "> was not present"); return false; } - if (! dataPtr->Has< XDataType2 >()) + if (! dataHandle->Has< XDataType2 >()) { KTERROR(cutlog_h, "Data type <" << scarab::type(XDataType2()) << "> was not present"); return false; } - return Apply(dataPtr->Of< KTData >(), dataPtr->Of< XDataType1 >(), dataPtr->Of< XDataType2 >()); + return Apply(dataHandle->Of< KTCoreData >(), dataHandle->Of< XDataType1 >(), dataHandle->Of< XDataType2 >()); } /* Playing around: wouldn't it be cool if this could be done with variadic tmeplates? - * Unfortunately we'll need to be able to iterate over the types in the template pack in the Apply(KTDataPtr) function. + * Unfortunately we'll need to be able to iterate over the types in the template pack in the Apply(KTDataHandle) function. * template< class ... DataTypes > class KTCutOnData : public KTCut @@ -217,7 +217,7 @@ namespace Nymph virtual bool Apply(DataTypes ...) = 0; - virtual bool Apply(KTDataPtr dataPtr); + virtual bool Apply(KTDataHandle dataHandle); }; template< class ... DataTypes > @@ -231,7 +231,7 @@ namespace Nymph {} template< class ... DataTypes > - bool KTCutOnData< DataTypes... >::Apply(KTDataPtr dataPtr) + bool KTCutOnData< DataTypes... >::Apply(KTDataHandle dataHandle) { } diff --git a/Library/Data/KTCutFilter.cc b/Library/Data/KTCutFilter.cc index c8e6e9b..8cb9e6a 100644 --- a/Library/Data/KTCutFilter.cc +++ b/Library/Data/KTCutFilter.cc @@ -56,7 +56,7 @@ namespace Nymph return true; } - bool KTCutFilter::Filter(KTData& data) + bool KTCutFilter::Filter(KTCoreData& data) { if (fAllBits) { @@ -74,25 +74,25 @@ namespace Nymph return cutStatus.IsCut(fCutMask); } - void KTCutFilter::FilterData(KTDataPtr dataPtr) + void KTCutFilter::FilterData(KTDataHandle dataHandle) { std::shared_ptr< KTThreadReference > ref = fFilterDataSW->GetThreadRef(); - // all KTDataPtr's have KTData, so we won't bother checking + // all KTDataHandle's have KTCoreData, so we won't bother checking - bool failCut = Filter(dataPtr->Of< KTData >()); + bool failCut = Filter(dataHandle->Of< KTCoreData >()); - ref->Break( dataPtr, fFilterDataSW->GetDoBreakpoint() ); + ref->Break( dataHandle, fFilterDataSW->GetDoBreakpoint() ); if (failCut) { - fAfterCutFailSignal(dataPtr); + fAfterCutFailSignal(dataHandle); } else { - fAfterCutPassSignal(dataPtr); + fAfterCutPassSignal(dataHandle); } - fAfterCutSignal(dataPtr); + fAfterCutSignal(dataHandle); return; } diff --git a/Library/Data/KTCutFilter.hh b/Library/Data/KTCutFilter.hh index 89522b4..7d0ff0a 100644 --- a/Library/Data/KTCutFilter.hh +++ b/Library/Data/KTCutFilter.hh @@ -33,7 +33,7 @@ namespace Nymph KTCutFilter checks the status of cuts that have already been applied to a data. If the bitwise AND of the cut status with the configurable cut mask is non-zero, than the data fails the filter. - Interpretation of the boolean returned by Filter(KTData&): + Interpretation of the boolean returned by Filter(KTCoreData&): - TRUE means the data failed the cut filter. - FALSE means the data passed the cut filter. @@ -46,12 +46,12 @@ namespace Nymph - "cut-mask-int": unsigned int -- Set the cut mask with an unsigned integer's bit values. Slots: - - "filter": void (KTDataPtr) -- Checks the cut status of the received data ANDed with the cut mask; No data is added. + - "filter": void (KTDataHandle) -- Checks the cut status of the received data ANDed with the cut mask; No data is added. Signals: - - "all": void (KTDataPtr) -- Emitted after cut status is checked for all data. - - "pass": void (KTDataPtr) -- Emitted after cut status is checked if the cut filter passed. - - "fail": void (KTDataPtr) -- Emitted after cut status is checked if the cut filter failed. + - "all": void (KTDataHandle) -- Emitted after cut status is checked for all data. + - "pass": void (KTDataHandle) -- Emitted after cut status is checked if the cut filter passed. + - "fail": void (KTDataHandle) -- Emitted after cut status is checked if the cut filter failed. */ class KTCutFilter : public KTProcessor @@ -78,9 +78,9 @@ namespace Nymph bool fAllBits; public: - bool Filter(KTData& data); + bool Filter(KTCoreData& data); - void FilterData(KTDataPtr dataPtr); + void FilterData(KTDataHandle dataHandle); //*************** diff --git a/Library/Data/KTCutStatus.hh b/Library/Data/KTCutStatus.hh index 24d31bb..9642575 100644 --- a/Library/Data/KTCutStatus.hh +++ b/Library/Data/KTCutStatus.hh @@ -25,7 +25,7 @@ namespace Nymph @brief Provides easy access to cut information. @details - KTCutStatus is typically used as a member variable of KTData, the top-level data object. + KTCutStatus is typically used as a member variable of KTCoreData, the top-level data object. KTCutStatus owns the set of cut results that have been added to a data object. It also owns a summary of those cuts (implemented with boost::dynamic_bitset). diff --git a/Library/Data/KTData.cc b/Library/Data/KTData.cc index 4dfd079..3b284a2 100644 --- a/Library/Data/KTData.cc +++ b/Library/Data/KTData.cc @@ -9,21 +9,16 @@ namespace Nymph { - const std::string KTData::sName("data"); + KTData::KTData( const std::string& name ) : + fName( name ) + {} - KTData::KTData() : - KTExtensibleData< KTData >(), - fCounter(0), - fLastData(false), - fCutStatus() - { - } + KTData::KTData( const KTData& orig ) : + fName( orig.fName ) + {} - KTData::KTData(const KTData& orig) : - KTExtensibleData< KTData >(orig), - fCounter(orig.fCounter), - fLastData(orig.fLastData), - fCutStatus(orig.fCutStatus) + KTData::KTData( KTData&& orig ) : + fName( std::move( orig.fName ) ) {} KTData::~KTData() diff --git a/Library/Data/KTData.hh b/Library/Data/KTData.hh index 688d7fe..13efcf2 100644 --- a/Library/Data/KTData.hh +++ b/Library/Data/KTData.hh @@ -10,60 +10,53 @@ #include "KTExtensibleStruct.hh" -#include "KTCutStatus.hh" #include "KTMemberVariable.hh" -#include #include namespace Nymph { - class KTDataCore + + class KTData { public: - KTDataCore() {} - virtual ~KTDataCore() {} - - virtual const std::string& Name() const = 0; + KTData() = delete; + KTData( const std::string& name ); + KTData( const KTData& orig ); + KTData( KTData&& orig ); + virtual ~KTData(); + MEMBERVARIABLE_REF( std::string, Name ); }; - template< class XDerivedType > - class KTExtensibleData : public KTExtensibleStruct< XDerivedType, KTDataCore > + class KTDataRider { public: - KTExtensibleData() {} - virtual ~KTExtensibleData() {} - - const std::string& Name() const; + KTDataRider() {} + virtual ~KTDataRider() {} }; template< class XDerivedType > - inline const std::string& KTExtensibleData< XDerivedType >::Name() const - { - return XDerivedType::sName; - } - - - - class KTData : public KTExtensibleData< KTData > + class KTExtensibleDataRider : public KTExtensibleStruct< XDerivedType, KTDataRider > { public: - KTData(); - KTData(const KTData& orig); - ~KTData(); - - MEMBERVARIABLE(unsigned, Counter); - MEMBERVARIABLE(bool, LastData); + KTExtensibleDataRider() {} + virtual ~KTExtensibleDataRider() {} - MEMBERVARIABLE_REF(KTCutStatus, CutStatus); - - public: - static const std::string sName; }; - typedef std::shared_ptr< KTData > KTDataPtr; +#define DEFINE_EXT_DATA_2( ex_data_class_name, data_class_name ) \ + class ex_data_class_name : public data_class_name, public KTExtensibleDataRider< ex_data_class_name > \ + { \ + public: \ + ex_data_class_name() : data_class_name(), KTExtensibleDataRider< ex_data_class_name >() {} \ + ex_data_class_name( const ex_data_class_name& orig ) : data_class_name( orig ), KTExtensibleDataRider< ex_data_class_name >( orig ) {} \ + ex_data_class_name( ex_data_class_name&& orig ) : data_class_name( orig ), KTExtensibleDataRider< ex_data_class_name >( orig ) {} \ + virtual ~ex_data_class_name() {} \ + }; + +#define DEFINE_EXT_DATA( data_class_name ) DEFINE_EXT_DATA_2( PASTE(data_class_name, Ext), data_class_name ) } /* namespace Nymph */ #endif /* KTDATA_HH_ */ diff --git a/Library/Data/KTDataPy.hh b/Library/Data/KTDataPy.hh index 2e0ae06..2b853eb 100644 --- a/Library/Data/KTDataPy.hh +++ b/Library/Data/KTDataPy.hh @@ -8,15 +8,15 @@ #ifndef KTDATAPY_HH_ #define KTDATAPY_HH_ -#include "KTData.hh" +#include "KTCoreData.hh" void export_DataPy() { using namespace Nymph; using namespace boost::python; - class_("KTData", init<>()) - .add_property("Counter", &KTData::GetCounter, &KTData::SetCounter) - .add_property("LastData", &KTData::GetLastData, &KTData::SetLastData) + class_("KTCoreData", init<>()) + .add_property("Counter", &KTCoreData::GetCounter, &KTCoreData::SetCounter) + .add_property("LastData", &KTCoreData::GetLastData, &KTCoreData::SetLastData) ; } diff --git a/Library/Processor/KTPrimaryProcessor.cc b/Library/Processor/KTPrimaryProcessor.cc index 9e16eaf..babcccd 100644 --- a/Library/Processor/KTPrimaryProcessor.cc +++ b/Library/Processor/KTPrimaryProcessor.cc @@ -56,7 +56,7 @@ namespace Nymph } else { - fThreadRef->SetReturnValue( KTDataPtr() ); + fThreadRef->SetReturnValue( KTDataHandle() ); } } catch( boost::exception& e ) diff --git a/Library/Processor/KTPrimaryProcessor.hh b/Library/Processor/KTPrimaryProcessor.hh index 2367e4d..218eb0f 100644 --- a/Library/Processor/KTPrimaryProcessor.hh +++ b/Library/Processor/KTPrimaryProcessor.hh @@ -10,7 +10,7 @@ #include "KTProcessor.hh" -#include "KTData.hh" +#include "KTCoreData.hh" #include "KTThreadReference.hh" #include diff --git a/Library/Processor/KTSignal.hh b/Library/Processor/KTSignal.hh index cad637f..f4dc7e8 100644 --- a/Library/Processor/KTSignal.hh +++ b/Library/Processor/KTSignal.hh @@ -10,7 +10,7 @@ #include "KTProcessor.hh" -#include "KTData.hh" +#include "KTCoreData.hh" #include @@ -75,10 +75,10 @@ namespace Nymph @class KTSignalData @author N. S. Oblath - @brief Creates a signal that takes a KTDataPtr object as its argument. + @brief Creates a signal that takes a KTDataHandle object as its argument. @details - The purpose of the signal is for passing KTData pointers between Processors. + The purpose of the signal is for passing KTCoreData pointers between Processors. The signal is emitted by calling operator(). If a KTDataSlot is being used, and the Slot has been given a pointer to this signal, the Slot will emit the Signal. @@ -89,7 +89,7 @@ namespace Nymph That's it! */ - typedef KTSignal< KTDataPtr > KTSignalData; + typedef KTSignal< KTDataHandle > KTSignalData; //******************* diff --git a/Library/Processor/KTSlot.hh b/Library/Processor/KTSlot.hh index 75b43b8..e77c778 100644 --- a/Library/Processor/KTSlot.hh +++ b/Library/Processor/KTSlot.hh @@ -74,13 +74,13 @@ namespace Nymph @class KTSlotData @author N. S. Oblath - @brief Creates a slot that takes a KTDataPtr object as the argument; the function that gets called should take 0 or more DataType&'s as its argument. + @brief Creates a slot that takes a KTDataHandle object as the argument; the function that gets called should take 0 or more DataType&'s as its argument. @details Usage: - This slot type adds the slot function (signature void (KTDataPtr). + This slot type adds the slot function (signature void (KTDataHandle). Your processor (or, optionally, a different object) must have a member function with the signature bool (DataType1&, . . .). - The slot function checks that the provided KTData object contains data of type DataType, and then calls the member function. + The slot function checks that the provided KTCoreData object contains data of type DataType, and then calls the member function. In your Processor's header add a member variable of type KTSlotOneArg< DataType >. The variable may be private. @@ -90,36 +90,36 @@ namespace Nymph Also optionally, a signal to be emitted after the return of the member function can be specified as the last argument. */ - template< class... XDataTypes > - class KTSlotData : public KTSlot< KTDataPtr > + template< class XReturnType, class... XDataArgs > + class KTSlotData : public KTSlot< KTDataHandle > { public: /// Constructor for the case where the processor has the function that will be called by the slot template< class XFuncOwnerType, class... XFuncDataTypes > - KTSlotData( const std::string& name, XFuncOwnerType* owner, bool (XFuncOwnerType::*func)( XFuncDataTypes&... ), KTSignalData* signalPtr ); + KTSlotData( const std::string& name, XFuncOwnerType* owner, XReturnType (XFuncOwnerType::*func)( XFuncDataTypes&... ), KTSignalData* signalPtr ); /// Constructor for the case where the processor has the function that will be called by the slot template< class XFuncOwnerType, class... XFuncDataTypes > - KTSlotData( const std::string& name, XFuncOwnerType* owner, bool (XFuncOwnerType::*func)( XFuncDataTypes&... ) ); + KTSlotData( const std::string& name, XFuncOwnerType* owner, XReturnType (XFuncOwnerType::*func)( XFuncDataTypes&... ) ); /// Constructor for the case where the processor and the object with the function that will be called are different template< class XFuncOwnerType, class... XFuncDataTypes > - KTSlotData( const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, bool (XFuncOwnerType::*func)( XFuncDataTypes&... ), KTSignalData* signalPtr ); + KTSlotData( const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, XReturnType (XFuncOwnerType::*func)( XFuncDataTypes&... ), KTSignalData* signalPtr ); /// Constructor for the case where the processor and the object with the function that will be called are different template< class XFuncOwnerType, class... XFuncDataTypes > - KTSlotData( const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, bool (XFuncOwnerType::*func)( XFuncDataTypes&... ) ); + KTSlotData( const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, XReturnType (XFuncOwnerType::*func)( XFuncDataTypes&... ) ); virtual ~KTSlotData(); - void operator()( KTDataPtr data ); + void operator()( KTDataHandle data ); protected: template< typename... DataTypes > - bool DataPresent( KTDataPtr data ); + bool DataPresent( KTDataHandle data ); //function_signature fFunc; - std::function< bool (XDataTypes&...) > fFunc; + std::function< XReturnType (XDataArgs&...) > fFunc; KTSignalData* fSignalPtr; }; @@ -128,7 +128,7 @@ namespace Nymph template< typename... DataTypes > struct DataPresentHelper { - static bool DataPresent( KTDataPtr ) + static bool DataPresent( KTDataHandle ) { return true; } @@ -137,7 +137,7 @@ namespace Nymph template< typename DataType, typename... DataTypes > struct DataPresentHelper< DataType, DataTypes... > { - static bool DataPresent( KTDataPtr data ) + static bool DataPresent( KTDataHandle data ) { if( ! data->Has< DataType >() ) { @@ -151,11 +151,11 @@ namespace Nymph // Typedefs for backwards compatibility - template< typename XDataType1 > - using KTSlotDataOneType = KTSlotData< XDataType1 >; + //template< typename XDataType1 > + //using KTSlotDataOneType = KTSlotData< XDataType1 >; - template< typename XDataType1, typename XDataType2 > - using KTSlotDataTwoTypes = KTSlotData< XDataType1, XDataType2 >; + //template< typename XDataType1, typename XDataType2 > + //using KTSlotDataTwoTypes = KTSlotData< XDataType1, XDataType2 >; /*! @@ -239,56 +239,56 @@ namespace Nymph // KTSlotData - template< class... XDataTypes > + template< class XReturnType, class... XDataTypes > template< class XFuncOwnerType, class... XFuncDataTypes > - KTSlotData< XDataTypes... >::KTSlotData(const std::string& name, XFuncOwnerType* owner, bool (XFuncOwnerType::*func)( XFuncDataTypes&... ), KTSignalData* signalPtr) : + KTSlotData< XReturnType, XDataTypes... >::KTSlotData(const std::string& name, XFuncOwnerType* owner, XReturnType (XFuncOwnerType::*func)( XFuncDataTypes&... ), KTSignalData* signalPtr) : KTSlot( name, owner, this, &KTSlotData::operator(), {signalPtr->GetName()} ), fFunc( [func, owner]( XDataTypes... args ){ return (owner->*func)(args...);} ), fSignalPtr( signalPtr ) { } - template< class... XDataTypes > + template< class XReturnType, class... XDataTypes > template< class XFuncOwnerType, class... XFuncDataTypes > - KTSlotData< XDataTypes... >::KTSlotData(const std::string& name, XFuncOwnerType* owner, bool (XFuncOwnerType::*func)( XFuncDataTypes&... )) : + KTSlotData< XReturnType, XDataTypes... >::KTSlotData(const std::string& name, XFuncOwnerType* owner, XReturnType (XFuncOwnerType::*func)( XFuncDataTypes&... )) : KTSlot( name, owner, this, &KTSlotData::operator() ), fFunc( [func, owner]( XDataTypes... args ){ return (owner->*func)(args...);} ), fSignalPtr( nullptr ) { } - template< class... XDataTypes > + template< class XReturnType, class... XDataTypes > template< class XFuncOwnerType, class... XFuncDataTypes > - KTSlotData< XDataTypes... >::KTSlotData(const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, bool (XFuncOwnerType::*func)( XFuncDataTypes&... ), KTSignalData* signalPtr) : + KTSlotData< XReturnType, XDataTypes... >::KTSlotData(const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, XReturnType (XFuncOwnerType::*func)( XFuncDataTypes&... ), KTSignalData* signalPtr) : KTSlot( name, proc, this, &KTSlotData::operator(), { signalPtr->GetName()} ), fFunc( [func, owner]( XDataTypes... args ){return (owner->*func) (args... );} ), fSignalPtr( signalPtr ) { } - template< class... XDataTypes > + template< class XReturnType, class... XDataTypes > template< class XFuncOwnerType, class... XFuncDataTypes > - KTSlotData< XDataTypes... >::KTSlotData(const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, bool (XFuncOwnerType::*func)( XFuncDataTypes&... )) : + KTSlotData< XReturnType, XDataTypes... >::KTSlotData(const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, XReturnType (XFuncOwnerType::*func)( XFuncDataTypes&... )) : KTSlot( name, proc, this, &KTSlotData::operator() ), fFunc( [func, owner]( XDataTypes... args ){return (owner->*func) (args... );} ), fSignalPtr( nullptr ) { } - template< class... XDataTypes > - KTSlotData< XDataTypes... >::~KTSlotData() + template< class XReturnType, class... XDataTypes > + KTSlotData< XReturnType, XDataTypes... >::~KTSlotData() { } - template< class... XDataTypes > - void KTSlotData< XDataTypes... >::operator()( KTDataPtr dataPtr ) + template< class XReturnType, class... XDataTypes > + void KTSlotData< XReturnType, XDataTypes... >::operator()( KTDataHandle dataHandle ) { // Standard data slot pattern: std::shared_ptr< KTThreadReference > ref = fSlotWrapper->GetThreadRef(); // Check to ensure that the required data type is present - if( ! DataPresent< XDataTypes... >( dataPtr ) ) + if( ! DataPresent< XDataTypes... >( dataHandle ) ) { KTERROR( slotlog, "Failed to find all of the necessary data types in slot <" << fName << ">. Aborting." ); THROW_THREADREF_EXCEPTION( ref, KTException() << "Failed to find all of the necessary data types in slot <" << fName << ">. Aborting." ); @@ -296,7 +296,15 @@ namespace Nymph } // Call the function - if( ! fFunc( dataPtr->Of< XDataTypes >()... ) ) + try + { + dataHandle-> + } + catch( ... ) + { + ref->SetReturnException( boost::current_exception() ); + } + if( ! fFunc( dataHandle->Of< XDataTypes >()... ) ) { KTERROR( slotlog, "Something went wrong in slot <" << fName << ">. Aborting." ); THROW_THREADREF_EXCEPTION( ref, KTException() << "Something went wrong in slot <" << fName << ">. Aborting." ); @@ -304,20 +312,20 @@ namespace Nymph } // Perform breakpoint here if necessary (either if initiated here or if stopping here due to a breakpoint elsewhere) - // Sets the dataPtr into the return - ref->Break( dataPtr, fSlotWrapper->GetDoBreakpoint() ); + // Sets the dataHandle into the return + ref->Break( dataHandle, fSlotWrapper->GetDoBreakpoint() ); // If there's a signal pointer, emit the signal if( fSignalPtr != nullptr ) { - (*fSignalPtr)( dataPtr ); + (*fSignalPtr)( dataHandle ); } return; } - template< class... XDataTypes > + template< class XReturnType, class... XDataTypes > template< typename... DataTypes > - bool KTSlotData< XDataTypes... >::DataPresent( KTDataPtr data ) + bool KTSlotData< XReturnType, XDataTypes... >::DataPresent( KTDataHandle data ) { return DataPresentHelper< DataTypes... >::DataPresent( data ); } @@ -351,8 +359,8 @@ namespace Nymph fFunc(); // Perform breakpoint here if necessary (either if initiated here or if stopping here due to a breakpoint elsewhere) - // Sets the dataPtr into the return - fSlotWrapper->GetThreadRef()->Break( KTDataPtr(), fSlotWrapper->GetDoBreakpoint() ); + // Sets the dataHandle into the return + fSlotWrapper->GetThreadRef()->Break( KTDataHandle(), fSlotWrapper->GetDoBreakpoint() ); // If there's a signal pointer, emit the signal if( fSignalPtr != nullptr ) diff --git a/Library/Processor/KTThreadReference.cc b/Library/Processor/KTThreadReference.cc index c5de273..e42a16c 100644 --- a/Library/Processor/KTThreadReference.cc +++ b/Library/Processor/KTThreadReference.cc @@ -62,7 +62,7 @@ namespace Nymph return *this; } - void KTThreadReference::Break( const KTDataPtr& dataPtr, bool doBreakpoint ) + void KTThreadReference::Break( const KTDataHandle& dataHandle, bool doBreakpoint ) { if( doBreakpoint ) { @@ -75,7 +75,7 @@ namespace Nymph KTDEBUG( trlog, "Reacting to break (" << fName << ")" ); // set the return for this thread KTWARN( trlog, "Setting value of data-ptr-ret promise (" << fName << ")" ); - fDataPtrRet.set_value( dataPtr ); + fDataPtrRet.set_value( dataHandle ); // wait for continue signal fWaitForContinueFunc( lock ); } diff --git a/Library/Processor/KTThreadReference.hh b/Library/Processor/KTThreadReference.hh index 8d403ea..05f6cca 100644 --- a/Library/Processor/KTThreadReference.hh +++ b/Library/Processor/KTThreadReference.hh @@ -8,7 +8,7 @@ #ifndef KTTHREADREFERENCE_HH_ #define KTTHREADREFERENCE_HH_ -#include "KTData.hh" +#include "KTCoreData.hh" #include @@ -16,7 +16,7 @@ namespace Nymph { - typedef boost::promise< KTDataPtr > KTDataPtrReturn; + typedef boost::promise< KTDataHandle > KTDataPtrReturn; class KTThreadReference { @@ -36,19 +36,19 @@ namespace Nymph // for use within the thread //************************** - void Break( const KTDataPtr& dataPtr, bool doBreakpoint ); + void Break( const KTDataHandle& dataHandle, bool doBreakpoint ); void SetReturnException( boost::exception_ptr excPtr ); - void SetReturnValue( KTDataPtr dataPtr ); + void SetReturnValue( KTDataHandle dataHandle ); public: //****************************** // for use outside of the thread //****************************** - KTDataPtr GetReturnValue(); - boost::unique_future< KTDataPtr >& GetDataPtrRetFuture(); - const boost::unique_future< KTDataPtr >& GetDataPtrRetFuture() const; + KTDataHandle GetReturnValue(); + boost::unique_future< KTDataHandle >& GetDataPtrRetFuture(); + const boost::unique_future< KTDataHandle >& GetDataPtrRetFuture() const; void RefreshDataPtrRet(); @@ -65,7 +65,7 @@ namespace Nymph private: KTDataPtrReturn fDataPtrRet; - boost::unique_future< KTDataPtr > fDataPtrRetFuture; + boost::unique_future< KTDataHandle > fDataPtrRetFuture; std::function< void() > fInitiateBreakFunc; std::function< void( boost_unique_lock& ) > fWaitForContinueFunc; boost::mutex fMutex; @@ -77,23 +77,23 @@ namespace Nymph return; } - inline void KTThreadReference::SetReturnValue( KTDataPtr dataPtr ) + inline void KTThreadReference::SetReturnValue( KTDataHandle dataHandle ) { - fDataPtrRet.set_value( dataPtr ); + fDataPtrRet.set_value( dataHandle ); return; } - inline KTDataPtr KTThreadReference::GetReturnValue() + inline KTDataHandle KTThreadReference::GetReturnValue() { return fDataPtrRetFuture.get(); } - inline boost::unique_future< KTDataPtr >& KTThreadReference::GetDataPtrRetFuture() + inline boost::unique_future< KTDataHandle >& KTThreadReference::GetDataPtrRetFuture() { return fDataPtrRetFuture; } - inline const boost::unique_future< KTDataPtr >& KTThreadReference::GetDataPtrRetFuture() const + inline const boost::unique_future< KTDataHandle >& KTThreadReference::GetDataPtrRetFuture() const { return fDataPtrRetFuture; } From eceb6f09f2941c40dc3c0f073c6337f1cdb5f0dd Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Thu, 8 Jun 2017 17:58:40 -0700 Subject: [PATCH 056/521] It builds! --- Executables/Validation/KTTestCuts.cc | 4 +- Executables/Validation/KTTestCuts.hh | 10 +- Executables/Validation/KTTestData.cc | 2 +- Executables/Validation/KTTestData.hh | 8 +- Executables/Validation/KTTestProcessor.cc | 18 +-- Executables/Validation/KTTestProcessor.hh | 13 +- Executables/Validation/TestApplyCut.cc | 4 +- Executables/Validation/TestCut.cc | 4 +- Executables/Validation/TestCutFilter.cc | 6 +- Executables/Validation/TestPrintData.cc | 89 +----------- Library/Application/KTPrintDataStructure.cc | 2 +- Library/Data/KTCoreData.cc | 20 +-- Library/Data/KTCoreData.hh | 7 +- Library/Data/KTCut.hh | 8 +- Library/Data/KTCutFilter.cc | 6 +- Library/Data/KTCutFilter.hh | 2 +- Library/Data/KTData.cc | 12 +- Library/Data/KTData.hh | 23 ++- Library/Processor/KTSlot.hh | 151 +++++++++++++++++--- 19 files changed, 204 insertions(+), 185 deletions(-) diff --git a/Executables/Validation/KTTestCuts.cc b/Executables/Validation/KTTestCuts.cc index bc8e153..f0eed69 100644 --- a/Executables/Validation/KTTestCuts.cc +++ b/Executables/Validation/KTTestCuts.cc @@ -33,7 +33,7 @@ namespace Nymph return true; } - bool KTAwesomeCut::Apply(KTCoreData& data, KTTestData& testData) + bool KTAwesomeCut::Apply(KTCoreDataExt& data, KTTestDataExt& testData) { bool isCut = ! testData.GetIsAwesome(); KTDEBUG(testlog, "Is data awesome? " << testData.GetIsAwesome()); @@ -55,7 +55,7 @@ namespace Nymph return true; } - bool KTNotAwesomeCut::Apply(KTCoreData& data, KTTestData& testData) + bool KTNotAwesomeCut::Apply(KTCoreDataExt& data, KTTestDataExt& testData) { bool isCut = testData.GetIsAwesome(); KTDEBUG(testlog, "Is data awesome? " << testData.GetIsAwesome()); diff --git a/Executables/Validation/KTTestCuts.hh b/Executables/Validation/KTTestCuts.hh index a0541cb..9bfd6fc 100644 --- a/Executables/Validation/KTTestCuts.hh +++ b/Executables/Validation/KTTestCuts.hh @@ -15,10 +15,10 @@ namespace Nymph { - class KTTestData; + class KTTestDataExt; // Cuts data that is NOT awesome - class KTAwesomeCut : public KTCutOneArg< KTTestData > + class KTAwesomeCut : public KTCutOneArg< KTTestDataExt > { public: struct Result : KTExtensibleCutResult< Result > @@ -32,11 +32,11 @@ namespace Nymph bool Configure(const scarab::param_node* node); - bool Apply(KTCoreData& data, KTTestData& testData); + bool Apply(KTCoreDataExt& data, KTTestDataExt& testData); }; // Cuts data that is IS awesome - class KTNotAwesomeCut : public KTCutOneArg< KTTestData > + class KTNotAwesomeCut : public KTCutOneArg< KTTestDataExt > { public: struct Result : KTExtensibleCutResult< Result > @@ -50,7 +50,7 @@ namespace Nymph bool Configure(const scarab::param_node* node); - bool Apply(KTCoreData& data, KTTestData& testData); + bool Apply(KTCoreDataExt& data, KTTestDataExt& testData); }; } diff --git a/Executables/Validation/KTTestData.cc b/Executables/Validation/KTTestData.cc index d879bcf..b5a7180 100644 --- a/Executables/Validation/KTTestData.cc +++ b/Executables/Validation/KTTestData.cc @@ -10,7 +10,7 @@ namespace Nymph { KTTestData::KTTestData() : - KTData( "test-data" ), + KTData(), fIsAwesome( false ) {} diff --git a/Executables/Validation/KTTestData.hh b/Executables/Validation/KTTestData.hh index 288bf92..4386b19 100644 --- a/Executables/Validation/KTTestData.hh +++ b/Executables/Validation/KTTestData.hh @@ -24,14 +24,14 @@ namespace Nymph MEMBERVARIABLE(bool, IsAwesome); }; - DEFINE_EXT_DATA( KTTestData ); // defines KTTestDataExt + DEFINE_EXT_DATA( KTTestData, "test" ); // defines KTTestDataExt class KTTestBaseData : public KTData { public: KTTestBaseData() : - KTData( "poly-data" ), + KTData(), fFunniness(1000.) {} virtual ~KTTestBaseData() {} @@ -39,8 +39,8 @@ namespace Nymph MEMBERVARIABLE(double, Funniness); }; - DEFINE_EXT_DATA_2( KTTestDerived1DataHandle, KTTestBaseData ); - DEFINE_EXT_DATA_2( KTTestDerived2DataHandle, KTTestBaseData ); + DEFINE_EXT_DATA_2( KTTestDerived1DataExt, KTTestBaseData, "test-derived-1" ); + DEFINE_EXT_DATA_2( KTTestDerived2DataExt, KTTestBaseData, "test-derived-2" ); } /* namespace Nymph */ diff --git a/Executables/Validation/KTTestProcessor.cc b/Executables/Validation/KTTestProcessor.cc index 396a5ab..232f164 100644 --- a/Executables/Validation/KTTestProcessor.cc +++ b/Executables/Validation/KTTestProcessor.cc @@ -107,8 +107,8 @@ namespace Nymph KTTestProcessorD::KTTestProcessorD( const std::string& name ) : KTProcessor( name ), - fDataSlot("test-data-slot", this, &KTTestProcessorD::SlotFunc), - fDataSignal("test-data-signal", this) + fDataSlot("test", this, &KTTestProcessorD::SlotFunc), + fDataSignal("test", this) { } @@ -123,14 +123,14 @@ namespace Nymph void KTTestProcessorD::EmitSignal(bool isAwesome) { - KTDataHandle dataHandle = std::make_shared< KTCoreData >(); - KTTestData& data = dataHandle->Of< KTTestData >(); + KTDataHandle dataHandle = CreateNewDataHandle(); + KTTestDataExt& data = dataHandle->Of< KTTestDataExt >(); data.SetIsAwesome(isAwesome); fDataSignal(dataHandle); return; } - void KTTestProcessorD::SlotFunc(KTTestData& data) + void KTTestProcessorD::SlotFunc(const KTTestData& data) { KTINFO(testsiglog, "Is the data awesome? " << data.GetIsAwesome()); return; @@ -159,11 +159,11 @@ namespace Nymph void KTTestProcessorE::EmitSignals() { - KTDataHandle dataHandle = std::make_shared< KTCoreData >(); + KTDataHandle dataHandle = CreateNewDataHandle(); KTINFO(testsiglog, "Creating data objects"); - dataHandle->Of< KTTestDerived1DataHandle >(); - dataHandle->Of< KTTestDerived2DataHandle >(); + dataHandle->Of< KTTestDerived1DataExt >(); + dataHandle->Of< KTTestDerived2DataExt >(); KTINFO(testsiglog, "Emitting data-1 signal"); fDerived1DataSignal( dataHandle ); @@ -174,7 +174,7 @@ namespace Nymph return; } - void KTTestProcessorE::BaseSlotFunc(KTTestBaseData& data) + void KTTestProcessorE::BaseSlotFunc(const KTTestBaseData& data) { KTINFO(testsiglog, "Data funniness measured to be: <" << data.GetFunniness() << ">"); return; diff --git a/Executables/Validation/KTTestProcessor.hh b/Executables/Validation/KTTestProcessor.hh index 6d482e4..d539668 100644 --- a/Executables/Validation/KTTestProcessor.hh +++ b/Executables/Validation/KTTestProcessor.hh @@ -89,10 +89,10 @@ namespace Nymph // Creates a KTTestData object, sets the awesomeness to the given value, and emits fSignal void EmitSignal(bool isAwesome = true); - void SlotFunc(KTTestData& data); + void SlotFunc(const KTTestData& data); private: - KTSlotData< KTTestData > fDataSlot; + KTSlotData< void, KTTestDataExt > fDataSlot; KTSignalData fDataSignal; }; @@ -116,17 +116,14 @@ namespace Nymph void EmitSignals(); - void BaseSlotFunc(KTTestBaseData& data); + void BaseSlotFunc(const KTTestBaseData& data); private: - KTSlotData< KTTestDerived1DataHandle > fDerived1DataSlot; - KTSlotData< KTTestDerived2DataHandle > fDerived2DataSlot; + KTSlotData< void, KTTestDerived1DataExt > fDerived1DataSlot; + KTSlotData< void, KTTestDerived2DataExt > fDerived2DataSlot; KTSignalData fDerived1DataSignal; KTSignalData fDerived2DataSignal; - - // utility function to avoid putting a logger in the header - void PrintFunniness( unsigned funniness ); }; } /* namespace Nymph */ diff --git a/Executables/Validation/TestApplyCut.cc b/Executables/Validation/TestApplyCut.cc index 4d8e7a8..c3fe237 100644 --- a/Executables/Validation/TestApplyCut.cc +++ b/Executables/Validation/TestApplyCut.cc @@ -18,8 +18,8 @@ using namespace std; int main() { - KTDataHandle dataHandle(new KTCoreData()); - KTTestData& testData = dataHandle->Of< KTTestData >(); + KTDataHandle dataHandle = CreateNewDataHandle(); + KTTestData& testData = dataHandle->Of< KTTestDataExt >(); KTCutStatus& cutStatus = dataHandle->CutStatus(); KTINFO(testlog, "Initial cut state: " << cutStatus.IsCut()); diff --git a/Executables/Validation/TestCut.cc b/Executables/Validation/TestCut.cc index 8497919..0e4403e 100644 --- a/Executables/Validation/TestCut.cc +++ b/Executables/Validation/TestCut.cc @@ -17,8 +17,8 @@ using namespace std; int main() { - KTCoreData data; - KTTestData& testData = data.Of< KTTestData >(); + KTCoreDataExt data; + KTTestDataExt& testData = data.Of< KTTestDataExt >(); KTCutStatus& cutStatus = data.CutStatus(); KTINFO(testlog, "Initial cut state: " << cutStatus.IsCut()); diff --git a/Executables/Validation/TestCutFilter.cc b/Executables/Validation/TestCutFilter.cc index 8888e5a..4b770cc 100644 --- a/Executables/Validation/TestCutFilter.cc +++ b/Executables/Validation/TestCutFilter.cc @@ -19,8 +19,8 @@ using namespace std; int main() { - KTDataHandle dataHandle(new KTCoreData()); - KTTestData& testData = dataHandle->Of< KTTestData >(); + KTDataHandle dataHandle = CreateNewDataHandle(); + KTTestData& testData = dataHandle->Of< KTTestDataExt >(); KTCutStatus& cutStatus = dataHandle->CutStatus(); KTINFO(testlog, "Initial cut state: " << cutStatus.IsCut()); @@ -54,7 +54,7 @@ int main() KTINFO(testlog, "Cut state of is: " << cutStatus.GetCutState< KTNotAwesomeCut::Result >()); KTCutFilter cutFilter; - KTCoreData& data = dataHandle->Of< KTCoreData >(); + KTCoreDataExt& data = dataHandle->Of< KTCoreDataExt >(); KTINFO(testlog, "Filtering with all cuts"); cutFilter.SetCutMaskAll(); diff --git a/Executables/Validation/TestPrintData.cc b/Executables/Validation/TestPrintData.cc index e73e9d0..9684420 100644 --- a/Executables/Validation/TestPrintData.cc +++ b/Executables/Validation/TestPrintData.cc @@ -8,94 +8,13 @@ #include "KTCut.hh" #include "KTLogger.hh" #include "KTPrintDataStructure.hh" + +#include "KTTestCuts.hh" #include "KTTestData.hh" #include "param.hh" -namespace Nymph -{ - KTLOGGER(testlog, "TestPrintData"); - - // Cuts data that is NOT awesome - class KTAwesomeCut : public KTCut - { - public: - struct Result : KTExtensibleCutResult< Result > - { - static const std::string sName; - }; - - public: - KTAwesomeCut(const std::string& name = "default-awesome-cut") : - KTCut(name) - {} - ~KTAwesomeCut() {} - - bool Configure(const scarab::param_node* node) - {return true;} - - bool Apply(KTCoreData& data, KTTestData& testData) - { - bool isCut = ! testData.GetIsAwesome(); - data.CutStatus().AddCutResult< KTAwesomeCut::Result >(isCut); - return isCut; - } - - bool Apply(KTDataHandle dataHandle) - { - if (! dataHandle->Has< KTTestDataExt >()) - { - KTERROR(testlog, "Data type was not present"); - return false; - } - return Apply(dataHandle->Of< KTCoreData >(), dataHandle->Of< KTTestDataExt >()); - } - }; - - // Cuts data that is IS awesome - class KTNotAwesomeCut : public KTCut - { - public: - struct Result : KTExtensibleCutResult< Result > - { - static const std::string sName; - }; - - public: - KTNotAwesomeCut(const std::string& name = "default-not-awesome-cut") : - KTCut(name) - {} - ~KTNotAwesomeCut() {} - - bool Configure(const scarab::param_node* node) - {return true;} - - bool Apply(KTCoreData& data, KTTestData& testData) - { - bool isCut = testData.GetIsAwesome(); - // use the name-based AddCutResult - data.CutStatus().AddCutResult("not-awesome-cut", isCut); - return isCut; - } - - bool Apply(KTDataHandle dataHandle) - { - if (! dataHandle->Has< KTTestData >()) - { - KTERROR(testlog, "Data type was not present"); - return false; - } - return Apply(dataHandle->Of< KTCoreData >(), dataHandle->Of< KTTestData >()); - } - }; - - - const std::string KTAwesomeCut::Result::sName = "awesome-cut"; - const std::string KTNotAwesomeCut::Result::sName = "not-awesome-cut"; - - KT_REGISTER_CUT(KTAwesomeCut); - KT_REGISTER_CUT(KTNotAwesomeCut); -} +KTLOGGER(testlog, "TestPrintData"); using namespace Nymph; @@ -103,7 +22,7 @@ using namespace std; int main() { - KTDataHandle dataHandle(new KTCoreData()); + KTDataHandle dataHandle = CreateNewDataHandle(); KTCoreDataExt& data = dataHandle->Of< KTCoreDataExt >(); KTTestDataExt& testData = dataHandle->Of< KTTestDataExt >(); diff --git a/Library/Application/KTPrintDataStructure.cc b/Library/Application/KTPrintDataStructure.cc index 48d6c70..fede0a2 100644 --- a/Library/Application/KTPrintDataStructure.cc +++ b/Library/Application/KTPrintDataStructure.cc @@ -83,7 +83,7 @@ namespace Nymph printbuf << "\nData Structure:\n"; printbuf << "\t- " << dataHandle->Name() << '\n'; KTDEBUG(datalog, "Found data type " << dataHandle->Name()); - KTExtensibleStructCore< KTDataCore >* nextData = dataHandle->Next(); + KTExtensibleStructCore< KTDataRider >* nextData = dataHandle->Next(); while (nextData != NULL) { printbuf << "\t- " << nextData->Name() << '\n'; diff --git a/Library/Data/KTCoreData.cc b/Library/Data/KTCoreData.cc index 70f817d..ecc198e 100644 --- a/Library/Data/KTCoreData.cc +++ b/Library/Data/KTCoreData.cc @@ -10,28 +10,20 @@ namespace Nymph { KTCoreData::KTCoreData() : - KTData( "data" ), + KTData(), fCounter( 0 ), fLastData( false ), fCutStatus() { } - KTCoreData::KTCoreData( const KTCoreData& orig ) : - KTData( orig ), - fCounter( orig.fCounter ), - fLastData( orig.fLastData ), - fCutStatus( orig.fCutStatus ) + KTCoreData::~KTCoreData() {} - KTCoreData::KTCoreData( KTCoreData&& orig ) : - KTData( orig ), - fCounter( std::move( orig.fCounter ) ), - fLastData( std::move( orig.fLastData ) ), - fCutStatus( std::move( orig.fCutStatus ) ) - {} - KTCoreData::~KTCoreData() - {} + KTDataHandle CreateNewDataHandle() + { + return std::make_shared< KTCoreDataExt >(); + } } /* namespace Nymph */ diff --git a/Library/Data/KTCoreData.hh b/Library/Data/KTCoreData.hh index bf4b520..1c42382 100644 --- a/Library/Data/KTCoreData.hh +++ b/Library/Data/KTCoreData.hh @@ -23,8 +23,6 @@ namespace Nymph { public: KTCoreData(); - KTCoreData( const KTCoreData& orig ); - KTCoreData( KTCoreData&& orig ); virtual ~KTCoreData(); MEMBERVARIABLE( unsigned, Counter ); @@ -34,9 +32,10 @@ namespace Nymph }; - DEFINE_EXT_DATA( KTCoreData ) + DEFINE_EXT_DATA( KTCoreData, "core" ) - typedef std::shared_ptr< KTCoreData > KTDataHandle; + typedef std::shared_ptr< KTCoreDataExt > KTDataHandle; + KTDataHandle CreateNewDataHandle(); } /* namespace Nymph */ #endif /* KTCOREDATA_HH_ */ diff --git a/Library/Data/KTCut.hh b/Library/Data/KTCut.hh index c68246b..72a6844 100644 --- a/Library/Data/KTCut.hh +++ b/Library/Data/KTCut.hh @@ -130,7 +130,7 @@ namespace Nymph KTCutOneArg(const std::string& name = "default-cut-name"); virtual ~KTCutOneArg(); - virtual bool Apply(KTCoreData& data, XDataType& dataType) = 0; + virtual bool Apply(KTCoreDataExt& data, XDataType& dataType) = 0; virtual bool Apply(KTDataHandle dataHandle); }; @@ -147,7 +147,7 @@ namespace Nymph KTCutTwoArgs(const std::string& name = "default-cut-name"); virtual ~KTCutTwoArgs(); - virtual bool Apply(KTCoreData& data, XDataType1& dataType1, XDataType2& dataType2) = 0; + virtual bool Apply(KTCoreDataExt& data, XDataType1& dataType1, XDataType2& dataType2) = 0; virtual bool Apply(KTDataHandle dataHandle); }; @@ -175,7 +175,7 @@ namespace Nymph KTERROR(cutlog_h, "Data type <" << scarab::type(XDataType()) << "> was not present"); return false; } - return Apply(dataHandle->Of< KTCoreData >(), dataHandle->Of< XDataType >()); + return Apply(dataHandle->Of< KTCoreDataExt >(), dataHandle->Of< XDataType >()); } @@ -202,7 +202,7 @@ namespace Nymph KTERROR(cutlog_h, "Data type <" << scarab::type(XDataType2()) << "> was not present"); return false; } - return Apply(dataHandle->Of< KTCoreData >(), dataHandle->Of< XDataType1 >(), dataHandle->Of< XDataType2 >()); + return Apply(dataHandle->Of< KTCoreDataExt >(), dataHandle->Of< XDataType1 >(), dataHandle->Of< XDataType2 >()); } /* Playing around: wouldn't it be cool if this could be done with variadic tmeplates? diff --git a/Library/Data/KTCutFilter.cc b/Library/Data/KTCutFilter.cc index 8cb9e6a..e4dff78 100644 --- a/Library/Data/KTCutFilter.cc +++ b/Library/Data/KTCutFilter.cc @@ -56,14 +56,14 @@ namespace Nymph return true; } - bool KTCutFilter::Filter(KTCoreData& data) + bool KTCutFilter::Filter(const KTCoreData& data) { if (fAllBits) { return data.CutStatus().IsCut(); } - KTCutStatus& cutStatus = data.CutStatus(); + const KTCutStatus& cutStatus = data.CutStatus(); if (fConvertToBitset) { fCutMask = cutStatus.ToBitset(fCutMaskInt); @@ -80,7 +80,7 @@ namespace Nymph // all KTDataHandle's have KTCoreData, so we won't bother checking - bool failCut = Filter(dataHandle->Of< KTCoreData >()); + bool failCut = Filter(dataHandle->Of< KTCoreDataExt >()); ref->Break( dataHandle, fFilterDataSW->GetDoBreakpoint() ); diff --git a/Library/Data/KTCutFilter.hh b/Library/Data/KTCutFilter.hh index 7d0ff0a..d7f6982 100644 --- a/Library/Data/KTCutFilter.hh +++ b/Library/Data/KTCutFilter.hh @@ -78,7 +78,7 @@ namespace Nymph bool fAllBits; public: - bool Filter(KTCoreData& data); + bool Filter(const KTCoreData& data); void FilterData(KTDataHandle dataHandle); diff --git a/Library/Data/KTData.cc b/Library/Data/KTData.cc index 3b284a2..9294aab 100644 --- a/Library/Data/KTData.cc +++ b/Library/Data/KTData.cc @@ -9,19 +9,17 @@ namespace Nymph { - KTData::KTData( const std::string& name ) : - fName( name ) + KTData::KTData() {} - KTData::KTData( const KTData& orig ) : - fName( orig.fName ) + KTData::~KTData() {} - KTData::KTData( KTData&& orig ) : - fName( std::move( orig.fName ) ) + KTDataRider::KTDataRider() : + fName() {} - KTData::~KTData() + KTDataRider::~KTDataRider() {} } /* namespace Nymph */ diff --git a/Library/Data/KTData.hh b/Library/Data/KTData.hh index 13efcf2..19a6d1c 100644 --- a/Library/Data/KTData.hh +++ b/Library/Data/KTData.hh @@ -20,43 +20,38 @@ namespace Nymph class KTData { public: - KTData() = delete; - KTData( const std::string& name ); - KTData( const KTData& orig ); - KTData( KTData&& orig ); + KTData(); virtual ~KTData(); - - MEMBERVARIABLE_REF( std::string, Name ); }; class KTDataRider { public: - KTDataRider() {} - virtual ~KTDataRider() {} + KTDataRider(); + virtual ~KTDataRider(); + MEMBERVARIABLE_REF( std::string, Name ); }; template< class XDerivedType > class KTExtensibleDataRider : public KTExtensibleStruct< XDerivedType, KTDataRider > { public: - KTExtensibleDataRider() {} + KTExtensibleDataRider() = delete; + KTExtensibleDataRider( const std::string& name ) { KTDataRider::fName = name; } virtual ~KTExtensibleDataRider() {} }; -#define DEFINE_EXT_DATA_2( ex_data_class_name, data_class_name ) \ +#define DEFINE_EXT_DATA_2( ex_data_class_name, data_class_name, label ) \ class ex_data_class_name : public data_class_name, public KTExtensibleDataRider< ex_data_class_name > \ { \ public: \ - ex_data_class_name() : data_class_name(), KTExtensibleDataRider< ex_data_class_name >() {} \ - ex_data_class_name( const ex_data_class_name& orig ) : data_class_name( orig ), KTExtensibleDataRider< ex_data_class_name >( orig ) {} \ - ex_data_class_name( ex_data_class_name&& orig ) : data_class_name( orig ), KTExtensibleDataRider< ex_data_class_name >( orig ) {} \ + ex_data_class_name() : data_class_name(), KTExtensibleDataRider< ex_data_class_name >( label ) {} \ virtual ~ex_data_class_name() {} \ }; -#define DEFINE_EXT_DATA( data_class_name ) DEFINE_EXT_DATA_2( PASTE(data_class_name, Ext), data_class_name ) +#define DEFINE_EXT_DATA( data_class_name, label ) DEFINE_EXT_DATA_2( PASTE(data_class_name, Ext), data_class_name, label ) } /* namespace Nymph */ #endif /* KTDATA_HH_ */ diff --git a/Library/Processor/KTSlot.hh b/Library/Processor/KTSlot.hh index e77c778..87af964 100644 --- a/Library/Processor/KTSlot.hh +++ b/Library/Processor/KTSlot.hh @@ -96,19 +96,19 @@ namespace Nymph public: /// Constructor for the case where the processor has the function that will be called by the slot template< class XFuncOwnerType, class... XFuncDataTypes > - KTSlotData( const std::string& name, XFuncOwnerType* owner, XReturnType (XFuncOwnerType::*func)( XFuncDataTypes&... ), KTSignalData* signalPtr ); + KTSlotData( const std::string& name, XFuncOwnerType* owner, void (XFuncOwnerType::*func)( const XFuncDataTypes&..., XReturnType& ), KTSignalData* signalPtr ); /// Constructor for the case where the processor has the function that will be called by the slot template< class XFuncOwnerType, class... XFuncDataTypes > - KTSlotData( const std::string& name, XFuncOwnerType* owner, XReturnType (XFuncOwnerType::*func)( XFuncDataTypes&... ) ); + KTSlotData( const std::string& name, XFuncOwnerType* owner, void (XFuncOwnerType::*func)( const XFuncDataTypes&..., XReturnType& ) ); /// Constructor for the case where the processor and the object with the function that will be called are different template< class XFuncOwnerType, class... XFuncDataTypes > - KTSlotData( const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, XReturnType (XFuncOwnerType::*func)( XFuncDataTypes&... ), KTSignalData* signalPtr ); + KTSlotData( const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, void (XFuncOwnerType::*func)( const XFuncDataTypes&..., XReturnType& ), KTSignalData* signalPtr ); /// Constructor for the case where the processor and the object with the function that will be called are different template< class XFuncOwnerType, class... XFuncDataTypes > - KTSlotData( const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, XReturnType (XFuncOwnerType::*func)( XFuncDataTypes&... ) ); + KTSlotData( const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, void (XFuncOwnerType::*func)( const XFuncDataTypes&..., XReturnType& ) ); virtual ~KTSlotData(); @@ -119,7 +119,42 @@ namespace Nymph bool DataPresent( KTDataHandle data ); //function_signature fFunc; - std::function< XReturnType (XDataArgs&...) > fFunc; + std::function< XReturnType (const XDataArgs&..., XReturnType&) > fFunc; + + KTSignalData* fSignalPtr; + }; + + // partial specialization for no new data type + template< class... XDataArgs > + class KTSlotData< void, XDataArgs... > : public KTSlot< KTDataHandle > + { + public: + /// Constructor for the case where the processor has the function that will be called by the slot + template< class XFuncOwnerType, class... XFuncDataTypes > + KTSlotData( const std::string& name, XFuncOwnerType* owner, void (XFuncOwnerType::*func)( const XFuncDataTypes&... ), KTSignalData* signalPtr ); + + /// Constructor for the case where the processor has the function that will be called by the slot + template< class XFuncOwnerType, class... XFuncDataTypes > + KTSlotData( const std::string& name, XFuncOwnerType* owner, void (XFuncOwnerType::*func)( const XFuncDataTypes&... ) ); + + /// Constructor for the case where the processor and the object with the function that will be called are different + template< class XFuncOwnerType, class... XFuncDataTypes > + KTSlotData( const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, void (XFuncOwnerType::*func)( const XFuncDataTypes&... ), KTSignalData* signalPtr ); + + /// Constructor for the case where the processor and the object with the function that will be called are different + template< class XFuncOwnerType, class... XFuncDataTypes > + KTSlotData( const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, void (XFuncOwnerType::*func)( const XFuncDataTypes&... ) ); + + virtual ~KTSlotData(); + + void operator()( KTDataHandle data ); + + protected: + template< typename... DataTypes > + bool DataPresent( KTDataHandle data ); + + //function_signature fFunc; + std::function< void (XDataArgs&...) > fFunc; KTSignalData* fSignalPtr; }; @@ -241,7 +276,7 @@ namespace Nymph template< class XReturnType, class... XDataTypes > template< class XFuncOwnerType, class... XFuncDataTypes > - KTSlotData< XReturnType, XDataTypes... >::KTSlotData(const std::string& name, XFuncOwnerType* owner, XReturnType (XFuncOwnerType::*func)( XFuncDataTypes&... ), KTSignalData* signalPtr) : + KTSlotData< XReturnType, XDataTypes... >::KTSlotData(const std::string& name, XFuncOwnerType* owner, void (XFuncOwnerType::*func)( const XFuncDataTypes&..., XReturnType& ), KTSignalData* signalPtr) : KTSlot( name, owner, this, &KTSlotData::operator(), {signalPtr->GetName()} ), fFunc( [func, owner]( XDataTypes... args ){ return (owner->*func)(args...);} ), fSignalPtr( signalPtr ) @@ -250,7 +285,7 @@ namespace Nymph template< class XReturnType, class... XDataTypes > template< class XFuncOwnerType, class... XFuncDataTypes > - KTSlotData< XReturnType, XDataTypes... >::KTSlotData(const std::string& name, XFuncOwnerType* owner, XReturnType (XFuncOwnerType::*func)( XFuncDataTypes&... )) : + KTSlotData< XReturnType, XDataTypes... >::KTSlotData(const std::string& name, XFuncOwnerType* owner, void (XFuncOwnerType::*func)( const XFuncDataTypes&..., XReturnType& )) : KTSlot( name, owner, this, &KTSlotData::operator() ), fFunc( [func, owner]( XDataTypes... args ){ return (owner->*func)(args...);} ), fSignalPtr( nullptr ) @@ -259,7 +294,7 @@ namespace Nymph template< class XReturnType, class... XDataTypes > template< class XFuncOwnerType, class... XFuncDataTypes > - KTSlotData< XReturnType, XDataTypes... >::KTSlotData(const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, XReturnType (XFuncOwnerType::*func)( XFuncDataTypes&... ), KTSignalData* signalPtr) : + KTSlotData< XReturnType, XDataTypes... >::KTSlotData(const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, void (XFuncOwnerType::*func)( const XFuncDataTypes&..., XReturnType& ), KTSignalData* signalPtr) : KTSlot( name, proc, this, &KTSlotData::operator(), { signalPtr->GetName()} ), fFunc( [func, owner]( XDataTypes... args ){return (owner->*func) (args... );} ), fSignalPtr( signalPtr ) @@ -268,7 +303,7 @@ namespace Nymph template< class XReturnType, class... XDataTypes > template< class XFuncOwnerType, class... XFuncDataTypes > - KTSlotData< XReturnType, XDataTypes... >::KTSlotData(const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, XReturnType (XFuncOwnerType::*func)( XFuncDataTypes&... )) : + KTSlotData< XReturnType, XDataTypes... >::KTSlotData(const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, void (XFuncOwnerType::*func)( const XFuncDataTypes&..., XReturnType& )) : KTSlot( name, proc, this, &KTSlotData::operator() ), fFunc( [func, owner]( XDataTypes... args ){return (owner->*func) (args... );} ), fSignalPtr( nullptr ) @@ -298,19 +333,103 @@ namespace Nymph // Call the function try { - dataHandle-> + fFunc( dataHandle->Of< XDataTypes >()... , dataHandle->Of< XReturnType >() ); } - catch( ... ) + catch( boost::exception& e ) { + e << KTErrorMsgInfo< struct slotData_RunFunc >( "Something went wrong in slot <" + fName + ">. Aborting." ); ref->SetReturnException( boost::current_exception() ); } - if( ! fFunc( dataHandle->Of< XDataTypes >()... ) ) + + // Perform breakpoint here if necessary (either if initiated here or if stopping here due to a breakpoint elsewhere) + // Sets the dataHandle into the return + ref->Break( dataHandle, fSlotWrapper->GetDoBreakpoint() ); + + // If there's a signal pointer, emit the signal + if( fSignalPtr != nullptr ) { - KTERROR( slotlog, "Something went wrong in slot <" << fName << ">. Aborting." ); - THROW_THREADREF_EXCEPTION( ref, KTException() << "Something went wrong in slot <" << fName << ">. Aborting." ); + (*fSignalPtr)( dataHandle ); + } + return; + } + + template< class XReturnType, class... XDataTypes > + template< typename... DataTypes > + bool KTSlotData< XReturnType, XDataTypes... >::DataPresent( KTDataHandle data ) + { + return DataPresentHelper< DataTypes... >::DataPresent( data ); + } + + + // KTSlotData with no return type + + template< class... XDataTypes > + template< class XFuncOwnerType, class... XFuncDataTypes > + KTSlotData< void, XDataTypes... >::KTSlotData(const std::string& name, XFuncOwnerType* owner, void (XFuncOwnerType::*func)( const XFuncDataTypes&... ), KTSignalData* signalPtr) : + KTSlot( name, owner, this, &KTSlotData::operator(), {signalPtr->GetName()} ), + fFunc( [func, owner]( XDataTypes... args ){ return (owner->*func)(args...);} ), + fSignalPtr( signalPtr ) + { + } + + template< class... XDataTypes > + template< class XFuncOwnerType, class... XFuncDataTypes > + KTSlotData< void, XDataTypes... >::KTSlotData(const std::string& name, XFuncOwnerType* owner, void (XFuncOwnerType::*func)( const XFuncDataTypes&... )) : + KTSlot( name, owner, this, &KTSlotData::operator() ), + fFunc( [func, owner]( XDataTypes... args ){ return (owner->*func)(args...);} ), + fSignalPtr( nullptr ) + { + } + + template< class... XDataTypes > + template< class XFuncOwnerType, class... XFuncDataTypes > + KTSlotData< void, XDataTypes... >::KTSlotData(const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, void (XFuncOwnerType::*func)( const XFuncDataTypes&... ), KTSignalData* signalPtr) : + KTSlot( name, proc, this, &KTSlotData::operator(), { signalPtr->GetName()} ), + fFunc( [func, owner]( XDataTypes... args ){return (owner->*func) (args... );} ), + fSignalPtr( signalPtr ) + { + } + + template< class... XDataTypes > + template< class XFuncOwnerType, class... XFuncDataTypes > + KTSlotData< void, XDataTypes... >::KTSlotData(const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, void (XFuncOwnerType::*func)( const XFuncDataTypes&... )) : + KTSlot( name, proc, this, &KTSlotData::operator() ), + fFunc( [func, owner]( XDataTypes... args ){return (owner->*func) (args... );} ), + fSignalPtr( nullptr ) + { + } + + template< class... XDataTypes > + KTSlotData< void, XDataTypes... >::~KTSlotData() + { + } + + template< class... XDataTypes > + void KTSlotData< void, XDataTypes... >::operator()( KTDataHandle dataHandle ) + { + // Standard data slot pattern: + + std::shared_ptr< KTThreadReference > ref = fSlotWrapper->GetThreadRef(); + + // Check to ensure that the required data type is present + if( ! DataPresent< XDataTypes... >( dataHandle ) ) + { + KTERROR( slotlog, "Failed to find all of the necessary data types in slot <" << fName << ">. Aborting." ); + THROW_THREADREF_EXCEPTION( ref, KTException() << "Failed to find all of the necessary data types in slot <" << fName << ">. Aborting." ); return; } + // Call the function + try + { + fFunc( dataHandle->Of< XDataTypes >()... ); + } + catch( boost::exception& e ) + { + e << KTErrorMsgInfo< struct slotData_RunFunc >( "Something went wrong in slot <" + fName + ">. Aborting." ); + ref->SetReturnException( boost::current_exception() ); + } + // Perform breakpoint here if necessary (either if initiated here or if stopping here due to a breakpoint elsewhere) // Sets the dataHandle into the return ref->Break( dataHandle, fSlotWrapper->GetDoBreakpoint() ); @@ -323,9 +442,9 @@ namespace Nymph return; } - template< class XReturnType, class... XDataTypes > + template< class... XDataTypes > template< typename... DataTypes > - bool KTSlotData< XReturnType, XDataTypes... >::DataPresent( KTDataHandle data ) + bool KTSlotData< void, XDataTypes... >::DataPresent( KTDataHandle data ) { return DataPresentHelper< DataTypes... >::DataPresent( data ); } From ab3a68ca248a807f7f884f526b7b06e227c4f912 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Fri, 9 Jun 2017 12:00:46 -0700 Subject: [PATCH 057/521] Moved the DataPresent helper structs to KTCoreData.hh --- Library/Data/KTCoreData.cc | 1 + Library/Data/KTCoreData.hh | 38 +++++++++++++++++++++++++++++++++++++ Library/Processor/KTSlot.hh | 27 +------------------------- 3 files changed, 40 insertions(+), 26 deletions(-) diff --git a/Library/Data/KTCoreData.cc b/Library/Data/KTCoreData.cc index ecc198e..96aa004 100644 --- a/Library/Data/KTCoreData.cc +++ b/Library/Data/KTCoreData.cc @@ -26,4 +26,5 @@ namespace Nymph return std::make_shared< KTCoreDataExt >(); } + } /* namespace Nymph */ diff --git a/Library/Data/KTCoreData.hh b/Library/Data/KTCoreData.hh index 1c42382..a85a778 100644 --- a/Library/Data/KTCoreData.hh +++ b/Library/Data/KTCoreData.hh @@ -11,6 +11,7 @@ #include "KTData.hh" #include "KTCutStatus.hh" +#include "KTLogger.hh" #include "KTMemberVariable.hh" #include @@ -18,6 +19,7 @@ namespace Nymph { + LOGGER( cdlog_h, "KTCoreData.hh" ) class KTCoreData : public KTData { @@ -34,8 +36,44 @@ namespace Nymph DEFINE_EXT_DATA( KTCoreData, "core" ) + + // Define KTDataHandle and a convenience function to create new handles typedef std::shared_ptr< KTCoreDataExt > KTDataHandle; KTDataHandle CreateNewDataHandle(); + + // Recursive helper structs for determining if data objects are present + + // End of the recursion; this will only be used if NoOtherDataTypes has nothing in it + template< class... NoOtherDataTypes > + struct DataPresentHelper + { + static bool DataPresent( KTDataHandle ); + }; + + template< class DataType, class... OtherDataTypes > + struct DataPresentHelper< DataType, OtherDataTypes... > + { + static bool DataPresent( KTDataHandle data ); + }; + + template< class... NoOtherDataTypes > + bool DataPresentHelper< NoOtherDataTypes... >::DataPresent( KTDataHandle ) + { + return true; + } + + template< class DataType, class... OtherDataTypes > + bool DataPresentHelper< DataType, OtherDataTypes... >::DataPresent( KTDataHandle data ) + { + if( ! data->Has< DataType >() ) + { + KTERROR( cdlog_h, "Data not found with type <" << typeid( DataType ).name() << ">" ); + return false; + } + return DataPresentHelper< OtherDataTypes... >::DataPresent( data ); + } + + } /* namespace Nymph */ #endif /* KTCOREDATA_HH_ */ diff --git a/Library/Processor/KTSlot.hh b/Library/Processor/KTSlot.hh index 87af964..6d486d6 100644 --- a/Library/Processor/KTSlot.hh +++ b/Library/Processor/KTSlot.hh @@ -154,36 +154,11 @@ namespace Nymph bool DataPresent( KTDataHandle data ); //function_signature fFunc; - std::function< void (XDataArgs&...) > fFunc; + std::function< void (const XDataArgs&...) > fFunc; KTSignalData* fSignalPtr; }; - // helper structs (have to be defined outside the templated KTSlot class to use specialization - template< typename... DataTypes > - struct DataPresentHelper - { - static bool DataPresent( KTDataHandle ) - { - return true; - } - }; - - template< typename DataType, typename... DataTypes > - struct DataPresentHelper< DataType, DataTypes... > - { - static bool DataPresent( KTDataHandle data ) - { - if( ! data->Has< DataType >() ) - { - KTERROR( slotlog, "Data not found with type <" << typeid( DataType ).name() << ">" ); - return false; - } - return DataPresentHelper< DataTypes... >::DataPresent( data ); - } - }; - - // Typedefs for backwards compatibility //template< typename XDataType1 > From ea9a619c13925826124563c1845fc7a53acca919 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Fri, 9 Jun 2017 12:01:09 -0700 Subject: [PATCH 058/521] Function renaming for improved consistency --- Executables/Validation/KTTestProcessor.cc | 10 +++++----- Executables/Validation/KTTestProcessor.hh | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Executables/Validation/KTTestProcessor.cc b/Executables/Validation/KTTestProcessor.cc index 232f164..0f6d014 100644 --- a/Executables/Validation/KTTestProcessor.cc +++ b/Executables/Validation/KTTestProcessor.cc @@ -107,7 +107,7 @@ namespace Nymph KTTestProcessorD::KTTestProcessorD( const std::string& name ) : KTProcessor( name ), - fDataSlot("test", this, &KTTestProcessorD::SlotFunc), + fDataSlot("test", this, &KTTestProcessorD::AnalysisFunc), fDataSignal("test", this) { } @@ -130,7 +130,7 @@ namespace Nymph return; } - void KTTestProcessorD::SlotFunc(const KTTestData& data) + void KTTestProcessorD::AnalysisFunc(const KTTestData& data) { KTINFO(testsiglog, "Is the data awesome? " << data.GetIsAwesome()); return; @@ -141,8 +141,8 @@ namespace Nymph KTTestProcessorE::KTTestProcessorE( const std::string& name ) : KTProcessor( name ), - fDerived1DataSlot("derived-1", this, &KTTestProcessorE::BaseSlotFunc), - fDerived2DataSlot("derived-2", this, &KTTestProcessorE::BaseSlotFunc), + fDerived1DataSlot("derived-1", this, &KTTestProcessorE::BaseAnalysisFunc), + fDerived2DataSlot("derived-2", this, &KTTestProcessorE::BaseAnalysisFunc), fDerived1DataSignal("derived-1", this), fDerived2DataSignal("derived-2", this) { @@ -174,7 +174,7 @@ namespace Nymph return; } - void KTTestProcessorE::BaseSlotFunc(const KTTestBaseData& data) + void KTTestProcessorE::BaseAnalysisFunc(const KTTestBaseData& data) { KTINFO(testsiglog, "Data funniness measured to be: <" << data.GetFunniness() << ">"); return; diff --git a/Executables/Validation/KTTestProcessor.hh b/Executables/Validation/KTTestProcessor.hh index d539668..be68835 100644 --- a/Executables/Validation/KTTestProcessor.hh +++ b/Executables/Validation/KTTestProcessor.hh @@ -89,7 +89,7 @@ namespace Nymph // Creates a KTTestData object, sets the awesomeness to the given value, and emits fSignal void EmitSignal(bool isAwesome = true); - void SlotFunc(const KTTestData& data); + void AnalysisFunc(const KTTestData& data); private: KTSlotData< void, KTTestDataExt > fDataSlot; @@ -116,7 +116,7 @@ namespace Nymph void EmitSignals(); - void BaseSlotFunc(const KTTestBaseData& data); + void BaseAnalysisFunc(const KTTestBaseData& data); private: KTSlotData< void, KTTestDerived1DataExt > fDerived1DataSlot; From 032478b5affec4310087cbeb467f9893e08f52d7 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Fri, 9 Jun 2017 12:03:21 -0700 Subject: [PATCH 059/521] Cuts now act on KTData objects, while KTCutOnData is templated with the extensible data class(es). KTCutOnData (with variadic templates) now works, and should be used instead of the one- and two-type cuts --- Executables/Validation/KTTestCuts.cc | 16 ++++--- Executables/Validation/KTTestCuts.hh | 9 ++-- Library/Data/KTCut.hh | 68 +++++++++++++++++++++------- 3 files changed, 67 insertions(+), 26 deletions(-) diff --git a/Executables/Validation/KTTestCuts.cc b/Executables/Validation/KTTestCuts.cc index f0eed69..497b481 100644 --- a/Executables/Validation/KTTestCuts.cc +++ b/Executables/Validation/KTTestCuts.cc @@ -22,8 +22,10 @@ namespace Nymph KTAwesomeCut::KTAwesomeCut(const std::string& name) : - KTCutOneArg(name) - {} + KTCutOnData(name) + { + fFunc = [this]( KTCoreDataExt& data, const KTTestData& testData )->bool {return this->Apply(data, testData);}; + } KTAwesomeCut::~KTAwesomeCut() {} @@ -33,7 +35,7 @@ namespace Nymph return true; } - bool KTAwesomeCut::Apply(KTCoreDataExt& data, KTTestDataExt& testData) + bool KTAwesomeCut::Apply(KTCoreData& data, const KTTestData& testData) { bool isCut = ! testData.GetIsAwesome(); KTDEBUG(testlog, "Is data awesome? " << testData.GetIsAwesome()); @@ -44,8 +46,10 @@ namespace Nymph KTNotAwesomeCut::KTNotAwesomeCut(const std::string& name) : - KTCutOneArg(name) - {} + KTCutOnData(name) + { + fFunc = [this]( KTCoreDataExt& data, const KTTestData& testData )->bool {return this->Apply(data, testData);}; + } KTNotAwesomeCut::~KTNotAwesomeCut() {} @@ -55,7 +59,7 @@ namespace Nymph return true; } - bool KTNotAwesomeCut::Apply(KTCoreDataExt& data, KTTestDataExt& testData) + bool KTNotAwesomeCut::Apply(KTCoreData& data, const KTTestData& testData) { bool isCut = testData.GetIsAwesome(); KTDEBUG(testlog, "Is data awesome? " << testData.GetIsAwesome()); diff --git a/Executables/Validation/KTTestCuts.hh b/Executables/Validation/KTTestCuts.hh index 9bfd6fc..7d344f3 100644 --- a/Executables/Validation/KTTestCuts.hh +++ b/Executables/Validation/KTTestCuts.hh @@ -15,10 +15,11 @@ namespace Nymph { + class KTTestData; class KTTestDataExt; // Cuts data that is NOT awesome - class KTAwesomeCut : public KTCutOneArg< KTTestDataExt > + class KTAwesomeCut : public KTCutOnData< KTTestDataExt > { public: struct Result : KTExtensibleCutResult< Result > @@ -32,11 +33,11 @@ namespace Nymph bool Configure(const scarab::param_node* node); - bool Apply(KTCoreDataExt& data, KTTestDataExt& testData); + bool Apply(KTCoreData& data, const KTTestData& testData); }; // Cuts data that is IS awesome - class KTNotAwesomeCut : public KTCutOneArg< KTTestDataExt > + class KTNotAwesomeCut : public KTCutOnData< KTTestDataExt > { public: struct Result : KTExtensibleCutResult< Result > @@ -50,7 +51,7 @@ namespace Nymph bool Configure(const scarab::param_node* node); - bool Apply(KTCoreDataExt& data, KTTestDataExt& testData); + bool Apply(KTCoreData& data, const KTTestData& testData); }; } diff --git a/Library/Data/KTCut.hh b/Library/Data/KTCut.hh index 72a6844..69aa656 100644 --- a/Library/Data/KTCut.hh +++ b/Library/Data/KTCut.hh @@ -11,6 +11,7 @@ #include "KTConfigurable.hh" #include "KTCutResult.hh" #include "KTCoreData.hh" +#include "KTException.hh" #include "KTExtensibleStructFactory.hh" #include "KTLogger.hh" #include "KTMemberVariable.hh" @@ -18,6 +19,8 @@ #include "factory.hh" #include "typename.hh" +#include + namespace Nymph { KTLOGGER(cutlog_h, "KTCut.h"); @@ -116,6 +119,7 @@ namespace Nymph virtual ~KTCut(); virtual bool Apply(KTDataHandle) = 0; + }; @@ -130,9 +134,12 @@ namespace Nymph KTCutOneArg(const std::string& name = "default-cut-name"); virtual ~KTCutOneArg(); - virtual bool Apply(KTCoreDataExt& data, XDataType& dataType) = 0; + //virtual bool Apply(KTCoreData& data, XDataType& dataType) = 0; virtual bool Apply(KTDataHandle dataHandle); + + private: + std::function< bool (KTCoreData& data, const XDataType& dataType) > fFunc; }; @@ -147,7 +154,7 @@ namespace Nymph KTCutTwoArgs(const std::string& name = "default-cut-name"); virtual ~KTCutTwoArgs(); - virtual bool Apply(KTCoreDataExt& data, XDataType1& dataType1, XDataType2& dataType2) = 0; + virtual bool Apply(KTCoreData& data, XDataType1& dataType1, XDataType2& dataType2) = 0; virtual bool Apply(KTDataHandle dataHandle); }; @@ -159,7 +166,8 @@ namespace Nymph template< class XDataType > KTCutOneArg< XDataType >::KTCutOneArg(const std::string& name) : - KTCut(name) + KTCut(name), + fFunc(nullptr) { } @@ -175,7 +183,7 @@ namespace Nymph KTERROR(cutlog_h, "Data type <" << scarab::type(XDataType()) << "> was not present"); return false; } - return Apply(dataHandle->Of< KTCoreDataExt >(), dataHandle->Of< XDataType >()); + return fFunc(dataHandle->Of< KTCoreDataExt >(), dataHandle->Of< XDataType >()); } @@ -207,35 +215,63 @@ namespace Nymph /* Playing around: wouldn't it be cool if this could be done with variadic tmeplates? * Unfortunately we'll need to be able to iterate over the types in the template pack in the Apply(KTDataHandle) function. - * - template< class ... DataTypes > + */ + template< class ... XDataTypes > class KTCutOnData : public KTCut { public: - KTCutOnData(const std::string& name = "default-cut-name"); + KTCutOnData( const std::string& name = "default-cut-name" ); virtual ~KTCutOnData(); - virtual bool Apply(DataTypes ...) = 0; + virtual bool Apply( KTDataHandle dataHandle ); + + protected: + template< typename... SomeDataTypes > + bool DataPresent( KTDataHandle data ); + + std::function< bool ( KTCoreDataExt& data, const XDataTypes&... dataType ) > fFunc; - virtual bool Apply(KTDataHandle dataHandle); }; - template< class ... DataTypes > - KTCutOnData< DataTypes... >::KTCutOnData(const std::string& name) : + template< class ... XDataTypes > + KTCutOnData< XDataTypes... >::KTCutOnData( const std::string& name ) : KTCut(name) { } - template< class ... DataTypes > - KTCutOnData< DataTypes... >::~KTCutOnData() + template< class ... XDataTypes > + KTCutOnData< XDataTypes... >::~KTCutOnData() {} - template< class ... DataTypes > - bool KTCutOnData< DataTypes... >::Apply(KTDataHandle dataHandle) + template< class ... XDataTypes > + bool KTCutOnData< XDataTypes... >::Apply( KTDataHandle dataHandle ) { + // Check to ensure that the required data type is present + if( ! DataPresent< XDataTypes... >( dataHandle ) ) + { + KTERROR( cutlog_h, "Failed to find all of the necessary data types in slot <" << fConfigName << ">. Aborting." ); + BOOST_THROW_EXCEPTION( KTException() << "Failed to find all of the necessary data types in slot <" << fConfigName << ">. Aborting." << eom ); + } + + try + { + return fFunc( dataHandle->Of< KTCoreDataExt >() , dataHandle->Of< XDataTypes >()... ); + } + catch( boost::exception& e ) + { + e << KTErrorMsgInfo< struct slotData_RunFunc >( "Something went wrong in slot <" + fConfigName + ">. Aborting." ); + throw; + } + } + template< class... XDataTypes > + template< typename... SomeDataTypes > + bool KTCutOnData< XDataTypes... >::DataPresent( KTDataHandle data ) + { + return DataPresentHelper< SomeDataTypes... >::DataPresent( data ); } -*/ + + // this macro enforces the existence of cut_class::Result and cut_class::Result::sName at compile time #define KT_REGISTER_CUT(cut_class) \ From cb6b7b57e1d0a160577a9db54bedd06a9e2a1bde Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Fri, 9 Jun 2017 15:33:05 -0700 Subject: [PATCH 060/521] Cleanup and adding SetApplyFunc function --- Executables/Validation/KTTestCuts.cc | 4 +- Library/Data/KTCut.hh | 153 +++++++-------------------- 2 files changed, 42 insertions(+), 115 deletions(-) diff --git a/Executables/Validation/KTTestCuts.cc b/Executables/Validation/KTTestCuts.cc index 497b481..944bc71 100644 --- a/Executables/Validation/KTTestCuts.cc +++ b/Executables/Validation/KTTestCuts.cc @@ -24,7 +24,7 @@ namespace Nymph KTAwesomeCut::KTAwesomeCut(const std::string& name) : KTCutOnData(name) { - fFunc = [this]( KTCoreDataExt& data, const KTTestData& testData )->bool {return this->Apply(data, testData);}; + SetApplyFunc( this, &KTAwesomeCut::Apply ); } KTAwesomeCut::~KTAwesomeCut() @@ -48,7 +48,7 @@ namespace Nymph KTNotAwesomeCut::KTNotAwesomeCut(const std::string& name) : KTCutOnData(name) { - fFunc = [this]( KTCoreDataExt& data, const KTTestData& testData )->bool {return this->Apply(data, testData);}; + SetApplyFunc( this, &KTNotAwesomeCut::Apply ); } KTNotAwesomeCut::~KTNotAwesomeCut() diff --git a/Library/Data/KTCut.hh b/Library/Data/KTCut.hh index 69aa656..4cd3d8f 100644 --- a/Library/Data/KTCut.hh +++ b/Library/Data/KTCut.hh @@ -53,9 +53,10 @@ namespace Nymph -------------------------------------- class KTSomeData; + class KTSomeDataExt; // Data must be at least as awesome as fAwesomenessThreshold to pass this cut - class KTAwesomenessCut : public KTCutOneArg< KTSomeData > + class KTAwesomenessCut : public KTCutOnData< KTSomeDataExt > { public: struct Result : KTExtensibleCutResult< Result > @@ -80,14 +81,16 @@ namespace Nymph ------- Example Implementation ------- -------------------------------------- - const std::string KTExampleCut::Result::sName = "awesomeness-cut"; + const std::string KTAwesomenessCut::Result::sName = "awesomeness-cut"; - KT_REGISTER_CUT(KTExampleCut); + KT_REGISTER_CUT(KTAwesomenessCut); KTAwesomenessCut::KTAwesomenessCut(const std::string& name) : - KTCutOneArg(name), + KTCutOnData(name), fAwesomenessThreshold(1000000.) - {} + { + SetApplyFunc( this, &KTAwesomeCut::Apply ); + } KTAwesomenessCut::~KTExampleCut() {} @@ -122,101 +125,11 @@ namespace Nymph }; + //******************************************************* + // KTCutOnData -- cut applied to one or more data objects + //******************************************************* - //***************************************************************** - // KTCutOneArg -- base class for cuts operating on one data type - //***************************************************************** - - template< class XDataType > - class KTCutOneArg : public KTCut - { - public: - KTCutOneArg(const std::string& name = "default-cut-name"); - virtual ~KTCutOneArg(); - - //virtual bool Apply(KTCoreData& data, XDataType& dataType) = 0; - - virtual bool Apply(KTDataHandle dataHandle); - - private: - std::function< bool (KTCoreData& data, const XDataType& dataType) > fFunc; - }; - - - //******************************************************************* - // KTCutTwoArgs -- base class for cuts operating on two data types - //******************************************************************* - - template< class XDataType1, class XDataType2 > - class KTCutTwoArgs : public KTCut - { - public: - KTCutTwoArgs(const std::string& name = "default-cut-name"); - virtual ~KTCutTwoArgs(); - - virtual bool Apply(KTCoreData& data, XDataType1& dataType1, XDataType2& dataType2) = 0; - - virtual bool Apply(KTDataHandle dataHandle); - }; - - - //******************* - // Implementations - //******************* - - template< class XDataType > - KTCutOneArg< XDataType >::KTCutOneArg(const std::string& name) : - KTCut(name), - fFunc(nullptr) - { - } - - template< class XDataType > - KTCutOneArg< XDataType >::~KTCutOneArg() - {} - - template< class XDataType > - bool KTCutOneArg< XDataType >::Apply(KTDataHandle dataHandle) - { - if (! dataHandle->Has< XDataType >()) - { - KTERROR(cutlog_h, "Data type <" << scarab::type(XDataType()) << "> was not present"); - return false; - } - return fFunc(dataHandle->Of< KTCoreDataExt >(), dataHandle->Of< XDataType >()); - } - - - template< class XDataType1, class XDataType2 > - KTCutTwoArgs< XDataType1, XDataType2 >::KTCutTwoArgs(const std::string& name) : - KTCut(name) - { - } - - template< class XDataType1, class XDataType2 > - KTCutTwoArgs< XDataType1, XDataType2 >::~KTCutTwoArgs() - {} - - template< class XDataType1, class XDataType2 > - bool KTCutTwoArgs< XDataType1, XDataType2 >::Apply(KTDataHandle dataHandle) - { - if (! dataHandle->Has< XDataType1 >()) - { - KTERROR(cutlog_h, "Data type <" << scarab::type(XDataType1()) << "> was not present"); - return false; - } - if (! dataHandle->Has< XDataType2 >()) - { - KTERROR(cutlog_h, "Data type <" << scarab::type(XDataType2()) << "> was not present"); - return false; - } - return Apply(dataHandle->Of< KTCoreDataExt >(), dataHandle->Of< XDataType1 >(), dataHandle->Of< XDataType2 >()); - } - -/* Playing around: wouldn't it be cool if this could be done with variadic tmeplates? - * Unfortunately we'll need to be able to iterate over the types in the template pack in the Apply(KTDataHandle) function. - */ - template< class ... XDataTypes > + template< class ... XExtDataTypes > class KTCutOnData : public KTCut { public: @@ -226,28 +139,36 @@ namespace Nymph virtual bool Apply( KTDataHandle dataHandle ); protected: - template< typename... SomeDataTypes > + template< class... SomeExtDataTypes > bool DataPresent( KTDataHandle data ); - std::function< bool ( KTCoreDataExt& data, const XDataTypes&... dataType ) > fFunc; + template< class XFuncOwnerType, class... XFuncDataTypes > + void SetApplyFunc( XFuncOwnerType* owner, bool (XFuncOwnerType::*func)( KTCoreData&, const XFuncDataTypes&... ) ); + + std::function< bool ( KTCoreDataExt& data, const XExtDataTypes&... dataType ) > fFunc; }; - template< class ... XDataTypes > - KTCutOnData< XDataTypes... >::KTCutOnData( const std::string& name ) : + + //******************* + // Implementations + //******************* + + template< class ... XExtDataTypes > + KTCutOnData< XExtDataTypes... >::KTCutOnData( const std::string& name ) : KTCut(name) { } - template< class ... XDataTypes > - KTCutOnData< XDataTypes... >::~KTCutOnData() + template< class ... XExtDataTypes > + KTCutOnData< XExtDataTypes... >::~KTCutOnData() {} - template< class ... XDataTypes > - bool KTCutOnData< XDataTypes... >::Apply( KTDataHandle dataHandle ) + template< class ... XExtDataTypes > + bool KTCutOnData< XExtDataTypes... >::Apply( KTDataHandle dataHandle ) { // Check to ensure that the required data type is present - if( ! DataPresent< XDataTypes... >( dataHandle ) ) + if( ! DataPresent< XExtDataTypes... >( dataHandle ) ) { KTERROR( cutlog_h, "Failed to find all of the necessary data types in slot <" << fConfigName << ">. Aborting." ); BOOST_THROW_EXCEPTION( KTException() << "Failed to find all of the necessary data types in slot <" << fConfigName << ">. Aborting." << eom ); @@ -255,7 +176,7 @@ namespace Nymph try { - return fFunc( dataHandle->Of< KTCoreDataExt >() , dataHandle->Of< XDataTypes >()... ); + return fFunc( dataHandle->Of< KTCoreDataExt >() , dataHandle->Of< XExtDataTypes >()... ); } catch( boost::exception& e ) { @@ -264,13 +185,19 @@ namespace Nymph } } - template< class... XDataTypes > - template< typename... SomeDataTypes > - bool KTCutOnData< XDataTypes... >::DataPresent( KTDataHandle data ) + template< class... XExtDataTypes > + template< typename... SomeExtDataTypes > + bool KTCutOnData< XExtDataTypes... >::DataPresent( KTDataHandle data ) { - return DataPresentHelper< SomeDataTypes... >::DataPresent( data ); + return DataPresentHelper< SomeExtDataTypes... >::DataPresent( data ); } + template< class... XExtDataTypes > + template< class XFuncOwnerType, class... XFuncDataTypes > + void KTCutOnData< XExtDataTypes... >::SetApplyFunc( XFuncOwnerType* owner, bool (XFuncOwnerType::*func)( KTCoreData&, const XFuncDataTypes&... ) ) + { + fFunc = [func, owner]( KTCoreDataExt& data, const XExtDataTypes&... testData )->bool {return (owner->*func)(data, testData...);}; + } // this macro enforces the existence of cut_class::Result and cut_class::Result::sName at compile time From 99ce5b4070b83e8f9c4cd6e9f5086677b0933d0a Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Fri, 9 Jun 2017 15:38:05 -0700 Subject: [PATCH 061/521] fixed test signal and slot names --- Executables/Validation/TestSlotData.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Executables/Validation/TestSlotData.cc b/Executables/Validation/TestSlotData.cc index 889bd03..52853d8 100644 --- a/Executables/Validation/TestSlotData.cc +++ b/Executables/Validation/TestSlotData.cc @@ -22,7 +22,7 @@ int main() KTINFO(testslotdata, "Connecting test-data-signal to test-data-slot"); // for simplicity the signal and slot are in the same processor, but that need not be, of course - tpD.ConnectASlot("test-data-signal", &tpD, "test-data-slot" ); + tpD.ConnectASlot("test", &tpD, "test" ); KTINFO(testslotdata, "Emitting signals"); KTINFO(testslotdata, "First test signal: true"); From 38a4164c10d1cbbbb1e72c22d808339f6f776b18 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Sun, 16 Jul 2017 19:02:30 -0700 Subject: [PATCH 062/521] Switched configure signature to use const param_node& instead of a pointer. --- Executables/Validation/KTTestConfigurable.cc | 25 ++++++++--------- Executables/Validation/KTTestConfigurable.hh | 2 +- Executables/Validation/KTTestCuts.cc | 4 +-- Executables/Validation/KTTestCuts.hh | 4 +-- .../Validation/KTTestPrimaryProcessor.cc | 6 ++-- .../Validation/KTTestPrimaryProcessor.hh | 2 +- Executables/Validation/KTTestProcessor.cc | 10 +++---- Executables/Validation/KTTestProcessor.hh | 10 +++---- Executables/Validation/TestApplication.cc | 2 +- Library/Application/KTApplication.cc | 4 +-- Library/Application/KTApplication.hh | 2 +- Library/Application/KTDataQueueProcessor.cc | 2 +- Library/Application/KTDataQueueProcessor.hh | 10 +++---- Library/Application/KTPrintDataStructure.cc | 2 +- Library/Application/KTPrintDataStructure.hh | 2 +- Library/Application/KTProcessorToolbox.cc | 28 +++++++++---------- Library/Application/KTProcessorToolbox.hh | 4 +-- Library/Application/KTRunNymph.cc | 6 ++-- Library/Application/KTThroughputProfiler.cc | 6 ++-- Library/Application/KTThroughputProfiler.hh | 2 +- Library/Data/KTApplyCut.cc | 7 ++--- Library/Data/KTApplyCut.hh | 2 +- Library/Data/KTCutFilter.cc | 14 ++++------ Library/Data/KTCutFilter.hh | 2 +- Library/Utility/KTCacheDirectory.cc | 6 ++-- Library/Utility/KTCacheDirectory.hh | 2 +- Library/Utility/KTConfigurable.cc | 4 +-- Library/Utility/KTConfigurable.hh | 4 +-- 28 files changed, 81 insertions(+), 93 deletions(-) diff --git a/Executables/Validation/KTTestConfigurable.cc b/Executables/Validation/KTTestConfigurable.cc index 057097a..c5598b9 100644 --- a/Executables/Validation/KTTestConfigurable.cc +++ b/Executables/Validation/KTTestConfigurable.cc @@ -31,25 +31,22 @@ namespace Nymph { } - bool KTTestConfigurable::Configure(const scarab::param_node* node) + bool KTTestConfigurable::Configure(const scarab::param_node& node) { // Config-file options - if (node != NULL) + // option: check for data before getting it from the node + if (node.has("int-data")) { - // option: check for data before getting it from the node - if (node->has("int-data")) - { - fIntData = node->get_value< int >("int-data", fIntData); - KTINFO(testparamlog, "Configured integer (= existing value if not provided): " << fIntData); - } - - // option: don't check for data before getting it from the node; rely on the default if it's not there. - fDoubleData = node->get_value< double >("double-data", fDoubleData); - KTINFO(testparamlog, "Configured double (= existing value if not provided): " << fDoubleData); - fStringData = node->get_value("string-data", fStringData); - KTINFO(testparamlog, "Configured string (= existing value if not provided): " << fStringData); + fIntData = node.get_value< int >("int-data", fIntData); + KTINFO(testparamlog, "Configured integer (= existing value if not provided): " << fIntData); } + // option: don't check for data before getting it from the node; rely on the default if it's not there. + fDoubleData = node.get_value< double >("double-data", fDoubleData); + KTINFO(testparamlog, "Configured double (= existing value if not provided): " << fDoubleData); + fStringData = node.get_value("string-data", fStringData); + KTINFO(testparamlog, "Configured string (= existing value if not provided): " << fStringData); + // Command-line options fIntData = fCLHandler->GetCommandLineValue< int >("int-data", fIntData); KTINFO(testparamlog, "Configured integer from CL (= existing value if not provided): " << fIntData); diff --git a/Executables/Validation/KTTestConfigurable.hh b/Executables/Validation/KTTestConfigurable.hh index 5cc7836..44c473f 100644 --- a/Executables/Validation/KTTestConfigurable.hh +++ b/Executables/Validation/KTTestConfigurable.hh @@ -19,7 +19,7 @@ namespace Nymph virtual ~KTTestConfigurable(); public: - bool Configure(const scarab::param_node* node); + bool Configure(const scarab::param_node& node); public: int GetIntData() const; diff --git a/Executables/Validation/KTTestCuts.cc b/Executables/Validation/KTTestCuts.cc index 944bc71..345ed5f 100644 --- a/Executables/Validation/KTTestCuts.cc +++ b/Executables/Validation/KTTestCuts.cc @@ -30,7 +30,7 @@ namespace Nymph KTAwesomeCut::~KTAwesomeCut() {} - bool KTAwesomeCut::Configure(const scarab::param_node* node) + bool KTAwesomeCut::Configure(const scarab::param_node&) { return true; } @@ -54,7 +54,7 @@ namespace Nymph KTNotAwesomeCut::~KTNotAwesomeCut() {} - bool KTNotAwesomeCut::Configure(const scarab::param_node* node) + bool KTNotAwesomeCut::Configure(const scarab::param_node&) { return true; } diff --git a/Executables/Validation/KTTestCuts.hh b/Executables/Validation/KTTestCuts.hh index 7d344f3..6fc12e6 100644 --- a/Executables/Validation/KTTestCuts.hh +++ b/Executables/Validation/KTTestCuts.hh @@ -31,7 +31,7 @@ namespace Nymph KTAwesomeCut(const std::string& name = "default-awesome-cut"); virtual ~KTAwesomeCut(); - bool Configure(const scarab::param_node* node); + bool Configure(const scarab::param_node& node); bool Apply(KTCoreData& data, const KTTestData& testData); }; @@ -49,7 +49,7 @@ namespace Nymph KTNotAwesomeCut(const std::string& name = "default-not-awesome-cut"); virtual ~KTNotAwesomeCut(); - bool Configure(const scarab::param_node* node); + bool Configure(const scarab::param_node& node); bool Apply(KTCoreData& data, const KTTestData& testData); }; diff --git a/Executables/Validation/KTTestPrimaryProcessor.cc b/Executables/Validation/KTTestPrimaryProcessor.cc index d9270de..897a728 100644 --- a/Executables/Validation/KTTestPrimaryProcessor.cc +++ b/Executables/Validation/KTTestPrimaryProcessor.cc @@ -23,11 +23,9 @@ namespace Nymph { } - bool KTTestPrimaryProcessor::Configure( const scarab::param_node* node ) + bool KTTestPrimaryProcessor::Configure( const scarab::param_node& node ) { - if( node == nullptr ) return true; - - SetIterations( node->get_value( "iterations", GetIterations() ) ); + SetIterations( node.get_value( "iterations", GetIterations() ) ); return true; } diff --git a/Executables/Validation/KTTestPrimaryProcessor.hh b/Executables/Validation/KTTestPrimaryProcessor.hh index 6cc104a..4eb7639 100644 --- a/Executables/Validation/KTTestPrimaryProcessor.hh +++ b/Executables/Validation/KTTestPrimaryProcessor.hh @@ -23,7 +23,7 @@ namespace Nymph virtual ~KTTestPrimaryProcessor(); public: - bool Configure( const scarab::param_node* node ); + bool Configure( const scarab::param_node& node ); MEMBERVARIABLE( unsigned, Iterations ); diff --git a/Executables/Validation/KTTestProcessor.cc b/Executables/Validation/KTTestProcessor.cc index 0f6d014..f045160 100644 --- a/Executables/Validation/KTTestProcessor.cc +++ b/Executables/Validation/KTTestProcessor.cc @@ -28,7 +28,7 @@ namespace Nymph { } - bool KTTestProcessorA::Configure(const scarab::param_node*) + bool KTTestProcessorA::Configure(const scarab::param_node&) { return true; } @@ -55,7 +55,7 @@ namespace Nymph { } - bool KTTestProcessorB::Configure(const scarab::param_node*) + bool KTTestProcessorB::Configure(const scarab::param_node&) { return true; } @@ -87,7 +87,7 @@ namespace Nymph { } - bool KTTestProcessorC::Configure(const scarab::param_node*) + bool KTTestProcessorC::Configure(const scarab::param_node&) { return true; } @@ -116,7 +116,7 @@ namespace Nymph { } - bool KTTestProcessorD::Configure(const scarab::param_node*) + bool KTTestProcessorD::Configure(const scarab::param_node&) { return true; } @@ -152,7 +152,7 @@ namespace Nymph { } - bool KTTestProcessorE::Configure(const scarab::param_node*) + bool KTTestProcessorE::Configure(const scarab::param_node&) { return true; } diff --git a/Executables/Validation/KTTestProcessor.hh b/Executables/Validation/KTTestProcessor.hh index be68835..8dace64 100644 --- a/Executables/Validation/KTTestProcessor.hh +++ b/Executables/Validation/KTTestProcessor.hh @@ -25,7 +25,7 @@ namespace Nymph KTTestProcessorA( const std::string& name = "test-proc-a" ); virtual ~KTTestProcessorA(); - bool Configure(const scarab::param_node* node); + bool Configure(const scarab::param_node& node); void EmitSignals(int); @@ -42,7 +42,7 @@ namespace Nymph KTTestProcessorB( const std::string& name = "test-proc-b" ); virtual ~KTTestProcessorB(); - bool Configure(const scarab::param_node* node); + bool Configure(const scarab::param_node& node); void SlotFunc1(int); void SlotFunc2(int); @@ -64,7 +64,7 @@ namespace Nymph KTTestProcessorC( const std::string& name = "test-proc-c" ); virtual ~KTTestProcessorC(); - bool Configure(const scarab::param_node* node); + bool Configure(const scarab::param_node& node); void SlotFunc1(int); @@ -84,7 +84,7 @@ namespace Nymph KTTestProcessorD( const std::string& name = "test-proc-d" ); virtual ~KTTestProcessorD(); - bool Configure(const scarab::param_node* node); + bool Configure(const scarab::param_node& node); // Creates a KTTestData object, sets the awesomeness to the given value, and emits fSignal void EmitSignal(bool isAwesome = true); @@ -112,7 +112,7 @@ namespace Nymph KTTestProcessorE( const std::string& name = "test-proc-d" ); virtual ~KTTestProcessorE(); - bool Configure(const scarab::param_node* node); + bool Configure(const scarab::param_node& node); void EmitSignals(); diff --git a/Executables/Validation/TestApplication.cc b/Executables/Validation/TestApplication.cc index 810fada..37d4539 100644 --- a/Executables/Validation/TestApplication.cc +++ b/Executables/Validation/TestApplication.cc @@ -84,7 +84,7 @@ int main(int argc, char** argv) const scarab::param_node& topNode = app->GetConfigurator()->Config(); - if (testObj->Configure(&topNode.node_at(testObj->GetConfigName()))) + if (testObj->Configure(topNode.node_at(testObj->GetConfigName()))) { KTINFO(testapplog, "Configuration complete:\n" << "\tInt data: " << testObj->GetIntData() << '\n' diff --git a/Library/Application/KTApplication.cc b/Library/Application/KTApplication.cc index 48ff2fc..2ff51e2 100644 --- a/Library/Application/KTApplication.cc +++ b/Library/Application/KTApplication.cc @@ -159,10 +159,8 @@ namespace Nymph return; } - bool KTApplication::Configure(const scarab::param_node* node) + bool KTApplication::Configure(const scarab::param_node&) { - //if (node == NULL) return true; - return true; } diff --git a/Library/Application/KTApplication.hh b/Library/Application/KTApplication.hh index 677bbbc..57ec7a8 100644 --- a/Library/Application/KTApplication.hh +++ b/Library/Application/KTApplication.hh @@ -65,7 +65,7 @@ namespace Nymph void AddConfigOptionsToCLHandler(const scarab::param& param, const std::string& rootName); public: - virtual bool Configure(const scarab::param_node* node); + virtual bool Configure(const scarab::param_node& node); public: KTCommandLineHandler* GetCommandLineHandler() const; diff --git a/Library/Application/KTDataQueueProcessor.cc b/Library/Application/KTDataQueueProcessor.cc index 4a7975b..4354dfd 100644 --- a/Library/Application/KTDataQueueProcessor.cc +++ b/Library/Application/KTDataQueueProcessor.cc @@ -28,7 +28,7 @@ namespace Nymph } - bool KTDataQueueProcessor::ConfigureSubClass(const scarab::param_node*) + bool KTDataQueueProcessor::ConfigureSubClass(const scarab::param_node&) { return true; } diff --git a/Library/Application/KTDataQueueProcessor.hh b/Library/Application/KTDataQueueProcessor.hh index bb2b54a..8ce93cf 100644 --- a/Library/Application/KTDataQueueProcessor.hh +++ b/Library/Application/KTDataQueueProcessor.hh @@ -69,8 +69,8 @@ namespace Nymph KTDataQueueProcessorTemplate(const std::string& name = "default-data-queue-proc-template-name"); virtual ~KTDataQueueProcessorTemplate(); - bool Configure(const scarab::param_node* node); - virtual bool ConfigureSubClass(const scarab::param_node* node) = 0; + bool Configure(const scarab::param_node& node); + virtual bool ConfigureSubClass(const scarab::param_node& node) = 0; Status GetStatus() const; void SetStatus(KTDataQueueProcessorTemplate< XProcessorType >::Status); @@ -171,7 +171,7 @@ namespace Nymph KTDataQueueProcessor(const std::string& name = "data-queue"); virtual ~KTDataQueueProcessor(); - bool ConfigureSubClass(const scarab::param_node* node); + bool ConfigureSubClass(const scarab::param_node& node); public: void EmitDataSignal(KTDataHandle data); @@ -225,9 +225,9 @@ namespace Nymph } template< class XProcessorType > - bool KTDataQueueProcessorTemplate< XProcessorType >::Configure(const scarab::param_node* node) + bool KTDataQueueProcessorTemplate< XProcessorType >::Configure(const scarab::param_node& node) { - fQueue.set_timeout(node->get_value< unsigned >("timeout", fQueue.get_timeout())); + fQueue.set_timeout(node.get_value< unsigned >("timeout", fQueue.get_timeout())); if (! ConfigureSubClass(node)) return false; return true; diff --git a/Library/Application/KTPrintDataStructure.cc b/Library/Application/KTPrintDataStructure.cc index fede0a2..749324e 100644 --- a/Library/Application/KTPrintDataStructure.cc +++ b/Library/Application/KTPrintDataStructure.cc @@ -33,7 +33,7 @@ namespace Nymph { } - bool KTPrintDataStructure::Configure(const scarab::param_node* node) + bool KTPrintDataStructure::Configure(const scarab::param_node&) { return true; } diff --git a/Library/Application/KTPrintDataStructure.hh b/Library/Application/KTPrintDataStructure.hh index 6df0a69..10c171c 100644 --- a/Library/Application/KTPrintDataStructure.hh +++ b/Library/Application/KTPrintDataStructure.hh @@ -49,7 +49,7 @@ namespace Nymph KTPrintDataStructure(const std::string& name = "print-data-structure"); virtual ~KTPrintDataStructure(); - bool Configure(const scarab::param_node* node); + bool Configure(const scarab::param_node& node); public: void PrintDataStructure(KTDataHandle dataHandle); diff --git a/Library/Application/KTProcessorToolbox.cc b/Library/Application/KTProcessorToolbox.cc index 1f18885..2d94c57 100644 --- a/Library/Application/KTProcessorToolbox.cc +++ b/Library/Application/KTProcessorToolbox.cc @@ -51,20 +51,20 @@ namespace Nymph ClearProcessors(); } - bool KTProcessorToolbox::Configure(const scarab::param_node* node) + bool KTProcessorToolbox::Configure(const scarab::param_node& node) { KTPROG(proclog, "Configuring . . ."); - SetRunSingleThreaded( node->get_value( "single-threaded", fRunSingleThreaded ) ); + SetRunSingleThreaded( node.get_value( "single-threaded", fRunSingleThreaded ) ); // Deal with "processor" blocks - if (! node->has("processors")) + if (! node.has("processors")) { KTWARN(proclog, "No processors were specified"); } else { - const scarab::param_array& procArray = node->array_at( "processors" ); + const scarab::param_array& procArray = node.array_at( "processors" ); for( scarab::param_array::const_iterator procIt = procArray.begin(); procIt != procArray.end(); ++procIt ) { if( ! procIt->is_node() ) @@ -109,13 +109,13 @@ namespace Nymph // Then deal with connections" - if (! node->has("connections")) + if (! node.has("connections")) { KTWARN(proclog, "No connections were specified"); } else { - const scarab::param_array& connArray = node->array_at( "connections" ); + const scarab::param_array& connArray = node.array_at( "connections" ); for( scarab::param_array::const_iterator connIt = connArray.begin(); connIt != connArray.end(); ++connIt ) { if( ! connIt->is_node() ) @@ -181,13 +181,13 @@ namespace Nymph // The run queue is an array of processor names, or groups of names, which will be run sequentially. // If names are grouped (in another array), those in that group will be run in parallel. // In single threaded mode all threads will be run sequentially in the order they were specified. - if (! node->has("run-queue")) + if (! node.has("run-queue")) { KTWARN(proclog, "Run queue was not specified"); } else { - const scarab::param_array& rqArray = node->array_at( "run-queue" ); + const scarab::param_array& rqArray = node.array_at( "run-queue" ); for (scarab::param_array::const_iterator rqIt = rqArray.begin(); rqIt != rqArray.end(); ++rqIt) { if (rqIt->is_value()) @@ -230,25 +230,25 @@ namespace Nymph return true; } - bool KTProcessorToolbox::ConfigureProcessors(const scarab::param_node* node) + bool KTProcessorToolbox::ConfigureProcessors(const scarab::param_node& node) { for (ProcMapIt iter = fProcMap.begin(); iter != fProcMap.end(); iter++) { KTDEBUG(proclog, "Attempting to configure processor <" << iter->first << ">"); string procName = iter->first; string nameUsed(procName); - if (! node->has(nameUsed)) + if (! node.has(nameUsed)) { nameUsed = iter->second.fProc->GetConfigName(); - if (! node->has(nameUsed)) + if (! node.has(nameUsed)) { KTWARN(proclog, "Did not find a parameter node <" << procName << "> or <" << nameUsed << ">\n" "\tProcessor <" << procName << "> was not configured."); continue; } } - const scarab::param_node& subNode = node->node_at(nameUsed); - if (! iter->second.fProc->Configure(&subNode)) + const scarab::param_node& subNode = node.node_at(nameUsed); + if (! iter->second.fProc->Configure(subNode)) { KTERROR(proclog, "An error occurred while configuring processor <" << procName << "> with parameter node <" << nameUsed << ">"); return false; @@ -262,7 +262,7 @@ namespace Nymph scarab::param_translator translator; scarab::param_node optNode; optNode.add( "encoding", new scarab::param_value( "json" ) ); - return ConfigureProcessors( &translator.read_string( config, &optNode )->as_node() ); + return ConfigureProcessors( translator.read_string( config, &optNode )->as_node() ); } KTProcessor* KTProcessorToolbox::GetProcessor(const std::string& procName) diff --git a/Library/Application/KTProcessorToolbox.hh b/Library/Application/KTProcessorToolbox.hh index 6e13edb..5d5ccda 100644 --- a/Library/Application/KTProcessorToolbox.hh +++ b/Library/Application/KTProcessorToolbox.hh @@ -98,10 +98,10 @@ namespace Nymph public: /// Configure the toolbox: create the processors; connnect signals and slots; and setup the run queue. - bool Configure(const scarab::param_node* node); + bool Configure(const scarab::param_node& node); /// Configure processors (only those specified in the toolbox) - bool ConfigureProcessors(const scarab::param_node* node); + bool ConfigureProcessors(const scarab::param_node& node); /// Configure processors from a json-encoding of their configurations bool ConfigureProcessors(const std::string& config); diff --git a/Library/Application/KTRunNymph.cc b/Library/Application/KTRunNymph.cc index 4f7ea90..26594c4 100644 --- a/Library/Application/KTRunNymph.cc +++ b/Library/Application/KTRunNymph.cc @@ -23,7 +23,7 @@ namespace Nymph { const scarab::param_node& parentConfigNode = app->GetConfigurator()->Config(); - if( ! app->Configure(&parentConfigNode.node_at(app->GetConfigName() ) ) ) + if( ! app->Configure(parentConfigNode.node_at(app->GetConfigName() ) ) ) { KTERROR( nlog, "Unable to configure the application. Aborting."); return -2; @@ -33,14 +33,14 @@ namespace Nymph // This will create all of the requested processors, connect their signals and slots, and fill the run queue. KTProcessorToolbox procTB; - if ( ! procTB.Configure( &parentConfigNode.node_at( procTB.GetConfigName() ) ) ) + if ( ! procTB.Configure( parentConfigNode.node_at( procTB.GetConfigName() ) ) ) { KTERROR( nlog, "Unable to configure processor toolbox. Aborting." ); return -3; } // Configure the processors - if ( ! procTB.ConfigureProcessors( &parentConfigNode ) ) + if ( ! procTB.ConfigureProcessors( parentConfigNode ) ) { KTERROR( nlog, "Unable to configure processors. Aborting." ); return -4; diff --git a/Library/Application/KTThroughputProfiler.cc b/Library/Application/KTThroughputProfiler.cc index 700e940..2dc9fcd 100644 --- a/Library/Application/KTThroughputProfiler.cc +++ b/Library/Application/KTThroughputProfiler.cc @@ -37,10 +37,10 @@ namespace Nymph { }; - bool KTThroughputProfiler::Configure(const scarab::param_node* node) + bool KTThroughputProfiler::Configure(const scarab::param_node& node) { - SetOutputFileFlag(node->get_value< bool >("output-file-flag", fOutputFileFlag)); - SetOutputFilename(node->get_value("output-filename-base", fOutputFilename)); + SetOutputFileFlag(node.get_value< bool >("output-file-flag", fOutputFileFlag)); + SetOutputFilename(node.get_value("output-filename-base", fOutputFilename)); return true; } diff --git a/Library/Application/KTThroughputProfiler.hh b/Library/Application/KTThroughputProfiler.hh index 1fcdd03..0d7509f 100644 --- a/Library/Application/KTThroughputProfiler.hh +++ b/Library/Application/KTThroughputProfiler.hh @@ -81,7 +81,7 @@ namespace Nymph KTThroughputProfiler(const std::string& name = "throughput-profiler"); virtual ~KTThroughputProfiler(); - bool Configure(const scarab::param_node* node); + bool Configure(const scarab::param_node& node); void Start(); void Stop(); diff --git a/Library/Data/KTApplyCut.cc b/Library/Data/KTApplyCut.cc index 14fad8b..fc57302 100644 --- a/Library/Data/KTApplyCut.cc +++ b/Library/Data/KTApplyCut.cc @@ -33,12 +33,11 @@ namespace Nymph delete fCut; } - bool KTApplyCut::Configure(const scarab::param_node* node) + bool KTApplyCut::Configure(const scarab::param_node& node) { // Config-file settings - if (node == NULL) return false; - for (scarab::param_node::const_iterator nodeIt = node->begin(); nodeIt != node->end(); ++nodeIt) + for (scarab::param_node::const_iterator nodeIt = node.begin(); nodeIt != node.end(); ++nodeIt) { // first do configuration values we know about // as it happens, there aren't any @@ -49,7 +48,7 @@ namespace Nymph { if (nodeIt->is_node()) { - fCut->Configure(&nodeIt->as_node()); + fCut->Configure(nodeIt->as_node()); } continue; } diff --git a/Library/Data/KTApplyCut.hh b/Library/Data/KTApplyCut.hh index 72564b0..e9d3b7e 100644 --- a/Library/Data/KTApplyCut.hh +++ b/Library/Data/KTApplyCut.hh @@ -57,7 +57,7 @@ namespace Nymph KTApplyCut(const std::string& name = "apply-cut"); virtual ~KTApplyCut(); - bool Configure(const scarab::param_node* node); + bool Configure(const scarab::param_node& node); KTCut* GetCut() const; void SetCut(KTCut* cut); diff --git a/Library/Data/KTCutFilter.cc b/Library/Data/KTCutFilter.cc index e4dff78..7be973e 100644 --- a/Library/Data/KTCutFilter.cc +++ b/Library/Data/KTCutFilter.cc @@ -35,20 +35,18 @@ namespace Nymph { } - bool KTCutFilter::Configure(const scarab::param_node* node) + bool KTCutFilter::Configure(const scarab::param_node& node) { // Config-file settings - if (node == NULL) return true; - - if (node->has("cut-mask-int")) + if (node.has("cut-mask-int")) { - SetCutMask(node->get_value< unsigned long long >("cut-mask-int")); + SetCutMask(node.get_value< unsigned long long >("cut-mask-int")); } - if (node->has("cut-mask")) + if (node.has("cut-mask")) { - SetCutMask(KTCutStatus::bitset_type(node->get_value("cut-mask"))); + SetCutMask(KTCutStatus::bitset_type(node.get_value("cut-mask"))); } - if (node->get_value("cut-mask-all", false)) + if (node.get_value("cut-mask-all", false)) { SetCutMaskAll(); } diff --git a/Library/Data/KTCutFilter.hh b/Library/Data/KTCutFilter.hh index d7f6982..dacd571 100644 --- a/Library/Data/KTCutFilter.hh +++ b/Library/Data/KTCutFilter.hh @@ -60,7 +60,7 @@ namespace Nymph KTCutFilter(const std::string& name = "cut-filter"); virtual ~KTCutFilter(); - bool Configure(const scarab::param_node* node); + bool Configure(const scarab::param_node& node); void SetCutMask(KTCutStatus::bitset_type mask); void SetCutMask(unsigned long long mask); diff --git a/Library/Utility/KTCacheDirectory.cc b/Library/Utility/KTCacheDirectory.cc index 8dad0be..d36f6e8 100644 --- a/Library/Utility/KTCacheDirectory.cc +++ b/Library/Utility/KTCacheDirectory.cc @@ -26,11 +26,9 @@ namespace Nymph { } - bool KTCacheDirectory::Configure(const scarab::param_node* node) + bool KTCacheDirectory::Configure(const scarab::param_node& node) { - if (node == NULL) return false; - - return SetPath(node->get_value("path", fPath.string())); + return SetPath(node.get_value("path", fPath.string())); } } /* namespace Nymph */ diff --git a/Library/Utility/KTCacheDirectory.hh b/Library/Utility/KTCacheDirectory.hh index 0db2553..d8d362d 100644 --- a/Library/Utility/KTCacheDirectory.hh +++ b/Library/Utility/KTCacheDirectory.hh @@ -27,7 +27,7 @@ namespace Nymph public: using KTSelfConfigurable::Configure; - bool Configure(const scarab::param_node* node); + bool Configure(const scarab::param_node& node); bool IsReady() const; diff --git a/Library/Utility/KTConfigurable.cc b/Library/Utility/KTConfigurable.cc index e2f6acc..b79d9fd 100644 --- a/Library/Utility/KTConfigurable.cc +++ b/Library/Utility/KTConfigurable.cc @@ -39,7 +39,7 @@ namespace Nymph scarab::param_translator translator; scarab::param_node optNode; optNode.add( "encoding", new scarab::param_value( "json" ) ); - return Configure( &translator.read_string( config, &optNode )->as_node() );; + return Configure( translator.read_string( config, &optNode )->as_node() );; } @@ -61,7 +61,7 @@ namespace Nymph { if (fIsConfigured) return true; - if (! this->Configure(&KTConfigurator::get_instance()->Config())) + if (! this->Configure(KTConfigurator::get_instance()->Config())) { KTERROR(conflog, "An error occurred while configuring <" << fConfigName << ">"); return false; diff --git a/Library/Utility/KTConfigurable.hh b/Library/Utility/KTConfigurable.hh index 6b29145..c93d6b8 100644 --- a/Library/Utility/KTConfigurable.hh +++ b/Library/Utility/KTConfigurable.hh @@ -28,7 +28,7 @@ namespace Nymph virtual ~KTConfigurable(); /// Should perform parameter store and command-line configurations - virtual bool Configure(const scarab::param_node* node) = 0; + virtual bool Configure(const scarab::param_node& node) = 0; /// Implement the option for calling Configure without passing a parameter store node. //virtual bool Configure(); /// Configure from a JSON string @@ -73,7 +73,7 @@ namespace Nymph virtual ~KTSelfConfigurable(); /// Should perform parameter store and command-line configurations - virtual bool Configure(const scarab::param_node* node) = 0; + virtual bool Configure(const scarab::param_node& node) = 0; /// Configure by getting the top-level node from the parameter store virtual bool Configure(); From 412bd0312d317e588725e63602fc9756cafe0f2f Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Tue, 23 Jan 2018 17:48:31 -0800 Subject: [PATCH 063/521] Added Cereal submodule and tested build --- .gitmodules | 3 +++ CMakeLists.txt | 8 ++++++++ External/cereal | 1 + 3 files changed, 12 insertions(+) create mode 160000 External/cereal diff --git a/.gitmodules b/.gitmodules index 5e77012..4a11728 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "Scarab"] path = Scarab url = https://github.com/project8/scarab +[submodule "External/cereal"] + path = External/cereal + url = https://github.com/USCiLab/cereal.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 7db1ed0..39ab538 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -91,6 +91,14 @@ if (Nymph_ENABLE_PYTHON) python_package_find_python( 2.7 ) endif (Nymph_ENABLE_PYTHON) +######## +# Cereal +######## + +set( JUST_INSTALL_CEREAL ON CACHE BOOL "Cereal option: only install library" FORCE) +add_subdirectory( External/cereal ) +include_directories( External/cereal/include ) + ############### # Build Nymph # diff --git a/External/cereal b/External/cereal new file mode 160000 index 0000000..51cbda5 --- /dev/null +++ b/External/cereal @@ -0,0 +1 @@ +Subproject commit 51cbda5f30e56c801c07fe3d3aba5d7fb9e6cca4 From 6833f1a071e42bf4bce3f0d4e40e32588b2708d0 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Wed, 24 Jan 2018 11:41:10 -0800 Subject: [PATCH 064/521] Simple serialization of data objects --- Executables/Validation/CMakeLists.txt | 1 + Executables/Validation/KTTestData.hh | 14 +++++ Executables/Validation/TestSerialization.cc | 68 +++++++++++++++++++++ Library/Data/KTCoreData.hh | 10 +++ Library/Data/KTData.hh | 40 +++++++++++- 5 files changed, 132 insertions(+), 1 deletion(-) create mode 100644 Executables/Validation/TestSerialization.cc diff --git a/Executables/Validation/CMakeLists.txt b/Executables/Validation/CMakeLists.txt index fc41cfb..718fc89 100644 --- a/Executables/Validation/CMakeLists.txt +++ b/Executables/Validation/CMakeLists.txt @@ -59,6 +59,7 @@ if (Nymph_ENABLE_TESTING) TestProcessorToolbox2Threads TestProcessorToolboxMultithreaded TestProcessorToolboxSinglethreaded + TestSerialization TestSignalsAndSlots TestSlotData TestThroughputProfiler diff --git a/Executables/Validation/KTTestData.hh b/Executables/Validation/KTTestData.hh index 4386b19..b771114 100644 --- a/Executables/Validation/KTTestData.hh +++ b/Executables/Validation/KTTestData.hh @@ -22,6 +22,12 @@ namespace Nymph virtual ~KTTestData(); MEMBERVARIABLE(bool, IsAwesome); + + private: + friend class cereal::access; + + template< class Archive > + void serialize( Archive& ar ); }; DEFINE_EXT_DATA( KTTestData, "test" ); // defines KTTestDataExt @@ -42,6 +48,14 @@ namespace Nymph DEFINE_EXT_DATA_2( KTTestDerived1DataExt, KTTestBaseData, "test-derived-1" ); DEFINE_EXT_DATA_2( KTTestDerived2DataExt, KTTestBaseData, "test-derived-2" ); + + template< class Archive > + void KTTestData::serialize( Archive& ar ) + { + std::cout << "### serialize for KTTestData" << std::endl; + ar( cereal::base_class< KTData >( this ), fIsAwesome ); + } + } /* namespace Nymph */ #endif /* NYMPH_KTTESTDATA_HH_ */ diff --git a/Executables/Validation/TestSerialization.cc b/Executables/Validation/TestSerialization.cc new file mode 100644 index 0000000..df35a4d --- /dev/null +++ b/Executables/Validation/TestSerialization.cc @@ -0,0 +1,68 @@ +/* + * TestSerialization.cc + * + * Created on: Jan 24, 2018 + * Author: obla999 + */ + +#include "KTLogger.hh" + +#include "KTTestData.hh" + +#include "cereal/archives/json.hpp" + +#include + +LOGGER( testlog, "TestSerialization" ); + +using namespace Nymph; + +int main() +{ + const std::string filename( "test_serialization_output.json" ); + + // save data to archive + { + KTCoreData coreData; + KTTestData testData; + + // change data values from their defaults + coreData.SetCounter( 5 ); + testData.SetIsAwesome( true ); + + KTINFO( testlog, "KTCoreData counter: " << coreData.GetCounter() ); + KTINFO( testlog, "KTTestData is-awesome: " << testData.GetIsAwesome() ); + + // create and open a file for output + std::ofstream fileOut( filename ); + + cereal::JSONOutputArchive archiveOut( fileOut ); + + KTINFO( testlog, "Writing data to JSON archive" ); + archiveOut( coreData, testData ); + + // archive and stream closed when destructors are called + } + + // ... some time later restore the class instance to its original state + { + KTCoreData newCoreData; + KTTestData newTestData; + + // create and open an archive for input + std::ifstream fileIn( filename ); + + cereal::JSONInputArchive archiveIn( fileIn ); + + KTINFO( testlog, "Reading data from JSON archive" ); + archiveIn( newCoreData, newTestData ); + + KTINFO(testlog, "KTCoreData counter: " << newCoreData.GetCounter()); + KTINFO(testlog, "KTTestData is-awesome: " << newTestData.GetIsAwesome()); + + // archive and stream closed when destructors are called + } + + return 0; +} + diff --git a/Library/Data/KTCoreData.hh b/Library/Data/KTCoreData.hh index a85a778..e81bf5a 100644 --- a/Library/Data/KTCoreData.hh +++ b/Library/Data/KTCoreData.hh @@ -32,6 +32,16 @@ namespace Nymph MEMBERVARIABLE_REF( KTCutStatus, CutStatus ); + private: + friend class cereal::access; + + template< class Archive > + void serialize( Archive& ar ) + { + std::cout << "### serialize for KTCoreData" << std::endl; + ar( cereal::base_class< KTData >( this ), fCounter, fLastData ); + //ar( cereal::base_class< KTData >( this ), fCounter, fLastData, fCutStatus ); + } }; DEFINE_EXT_DATA( KTCoreData, "core" ) diff --git a/Library/Data/KTData.hh b/Library/Data/KTData.hh index 19a6d1c..f1aa67d 100644 --- a/Library/Data/KTData.hh +++ b/Library/Data/KTData.hh @@ -12,6 +12,10 @@ #include "KTMemberVariable.hh" +#include "cereal/types/polymorphic.hpp" // required to avoid compile error +#include "cereal/types/base_class.hpp" // required for base-class specification +#include "cereal/access.hpp" // required for private member access + #include namespace Nymph @@ -22,6 +26,12 @@ namespace Nymph public: KTData(); virtual ~KTData(); + + template< class Archive > + void serialize( Archive& ar ) + { + std::cout << "### serialize for KTData" << std::endl; + } }; class KTDataRider @@ -31,6 +41,17 @@ namespace Nymph virtual ~KTDataRider(); MEMBERVARIABLE_REF( std::string, Name ); +/* + private: + friend class cereal::access; + + template< class Archive > + void serialize( Archive& ar ) + { + std::cout << "### serialize for KTDataRider" << std::endl; + ar( fName ); + } +*/ }; template< class XDerivedType > @@ -40,7 +61,14 @@ namespace Nymph KTExtensibleDataRider() = delete; KTExtensibleDataRider( const std::string& name ) { KTDataRider::fName = name; } virtual ~KTExtensibleDataRider() {} - +/* + template< class Archive > + void serialize( Archive& ar ) + { + std::cout << "### serialize for KTExtensibleStruct< XDerivedType, KTDataRider >" << std::endl; + ar( cereal::base_class< KTExtensibleStruct< XDerivedType, KTDataRider > >( this ) ); + } +*/ }; #define DEFINE_EXT_DATA_2( ex_data_class_name, data_class_name, label ) \ @@ -49,8 +77,18 @@ namespace Nymph public: \ ex_data_class_name() : data_class_name(), KTExtensibleDataRider< ex_data_class_name >( label ) {} \ virtual ~ex_data_class_name() {} \ + \ }; +/* + template< class Archive > \ + void serialize( Archive& ar ) \ + { \ + std::cout << "### serialize for ex_data_class_name" << std::endl; + ar( cereal::base_class< data_class_name >( this ), cereal::base_class< KTExtensibleDataRider< ex_data_class_name > >( this ) ); \ + } \ +*/ + #define DEFINE_EXT_DATA( data_class_name, label ) DEFINE_EXT_DATA_2( PASTE(data_class_name, Ext), data_class_name, label ) } /* namespace Nymph */ From c41fa487f945fd2f2504eba9e8039e41c6daaa3a Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Wed, 24 Jan 2018 13:44:50 -0800 Subject: [PATCH 065/521] Add pybind11 as an external package --- .gitmodules | 3 +++ CMakeLists.txt | 13 +++++++++++++ External/pybind11 | 1 + 3 files changed, 17 insertions(+) create mode 160000 External/pybind11 diff --git a/.gitmodules b/.gitmodules index 5e77012..dd1605b 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "Scarab"] path = Scarab url = https://github.com/project8/scarab +[submodule "External/pybind11"] + path = External/pybind11 + url = https://github.com/pybind/pybind11.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 7db1ed0..0e433a2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,6 +34,9 @@ option( Nymph_BUILD_NYMPH_EXE "Flag to build the Nymph executable; also requires # Build python bindings (requires boost::python) option( Nymph_ENABLE_PYTHON "Build python bindings (NymphPy)" OFF ) +# Build python bindings via pybind11 (this should be renamed Nymph_ENABLE_PYTHON if we choose to go with pybind11 over boost::python) +option( Nymph_ENABLE_PYBIND11 "Build python bindings via pybind11" OFF ) + # Add a "Standard" build type #set (CMAKE_BUILD_TYPE standard) set (CMAKE_CXX_FLAGS_STANDARD "-O1 -DNDEBUG -DSTANDARD" CACHE STRING "Flags used by the compiler during standard builds.") @@ -91,6 +94,16 @@ if (Nymph_ENABLE_PYTHON) python_package_find_python( 2.7 ) endif (Nymph_ENABLE_PYTHON) +########## +# Pybind11 +########## + +if( Nymph_ENABLE_PYBIND11 ) + set( PYBIND11_INSTALL ON CACHE BOOL "Pybind11 option to install itself" FORCE ) + add_subdirectory( External/pybind11 ) + include_directories( External/pybind11/include ) +endif( Nymph_ENABLE_PYBIND11 ) + ############### # Build Nymph # diff --git a/External/pybind11 b/External/pybind11 new file mode 160000 index 0000000..add56cc --- /dev/null +++ b/External/pybind11 @@ -0,0 +1 @@ +Subproject commit add56ccdcac23a6c522a2c1174a866e293c61dab From 1d06a9636c34f34ea2967d6b2234779408370428 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Wed, 24 Jan 2018 13:45:52 -0800 Subject: [PATCH 066/521] Fix warning when building nymph by itself --- CMakeLists.txt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0e433a2..9d97bb7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -71,7 +71,12 @@ pbuilder_add_submodule( Scarab Scarab/library ) # this is needed for anything that wants to read or write JSON files get_directory_property( RAPIDJSON_FILE_BUFFER_SIZE DIRECTORY Scarab/library DEFINITION RAPIDJSON_FILE_BUFFER_SIZE ) -set( RAPIDJSON_FILE_BUFFER_SIZE ${RAPIDJSON_FILE_BUFFER_SIZE} PARENT_SCOPE ) +message( STATUS "is standalone? ${PBUILDER_STANDALONE}" ) +if( PBUILDER_STANDALONE ) + set( RAPIDJSON_FILE_BUFFER_SIZE ${RAPIDJSON_FILE_BUFFER_SIZE} ) +else( PBUILDER_STANDALONE ) + set( RAPIDJSON_FILE_BUFFER_SIZE ${RAPIDJSON_FILE_BUFFER_SIZE} PARENT_SCOPE ) +endif( PBUILDER_STANDALONE ) ####### # Boost From 77f1b4d8fadc3f94bf1472e11d760c14bc91192f Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Wed, 24 Jan 2018 16:42:40 -0800 Subject: [PATCH 067/521] Added a basic test program for pybind11 --- Executables/Validation/CMakeLists.txt | 12 +++++++++ Executables/Validation/TestPythonBasics.cc | 25 +++++++++++++++++++ Executables/Validation/TestPythonBasics.py.in | 6 +++++ 3 files changed, 43 insertions(+) create mode 100644 Executables/Validation/TestPythonBasics.cc create mode 100644 Executables/Validation/TestPythonBasics.py.in diff --git a/Executables/Validation/CMakeLists.txt b/Executables/Validation/CMakeLists.txt index fc41cfb..8a5e66f 100644 --- a/Executables/Validation/CMakeLists.txt +++ b/Executables/Validation/CMakeLists.txt @@ -66,5 +66,17 @@ if (Nymph_ENABLE_TESTING) ) pbuilder_executables( TEST_PROGRAMS LIB_DEPENDENCIES ) + + + # Python bindings + set( VALIDATION_PYBINDING_FILES + TestPythonBasics.cc + ) + + pybind11_add_module( nymph_validation MODULE ${VALIDATION_PYBINDING_FILES} ) + pbuilder_install_libraries( nymph_validation ) + + configure_file( TestPythonBasics.py.in TestPythonBasics.py @ONLY) + install( FILES ${CMAKE_CURRENT_BINARY_DIR}/TestPythonBasics.py DESTINATION ${BIN_INSTALL_DIR} ) endif (Nymph_ENABLE_TESTING) diff --git a/Executables/Validation/TestPythonBasics.cc b/Executables/Validation/TestPythonBasics.cc new file mode 100644 index 0000000..c7551f4 --- /dev/null +++ b/Executables/Validation/TestPythonBasics.cc @@ -0,0 +1,25 @@ +/* + * TestPythonBasics.hh + * + * Created on: Jan 24, 2018 + * Author: obla999 + */ + +#include "pybind11/pybind11.h" + + +namespace Nymph +{ + namespace PyTest + { + int add( int i, int j ) + { + return i + j; + } + } +} + +PYBIND11_MODULE( nymph_validation, mod ) +{ + mod.def( "add", &Nymph::PyTest::add, "A function that adds two integers" ); +} diff --git a/Executables/Validation/TestPythonBasics.py.in b/Executables/Validation/TestPythonBasics.py.in new file mode 100644 index 0000000..0aaf4a4 --- /dev/null +++ b/Executables/Validation/TestPythonBasics.py.in @@ -0,0 +1,6 @@ +import sys +sys.path.append('@LIB_INSTALL_DIR@') + +import nymph_validation + +print( '1 + 2 =', nymph_validation.add(1, 2) ) From 32de2d5698b0bcff1d3bf618f7788ad831793508 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Wed, 24 Jan 2018 17:24:14 -0800 Subject: [PATCH 068/521] Refining the python setup a bit --- Executables/Validation/CMakeLists.txt | 10 ++++++++-- .../{TestPythonBasics.py.in => TestPythonBasics.py} | 3 +-- Library/AddLibPythonPath.sh.in | 3 +++ Library/CMakeLists.txt | 5 +++++ 4 files changed, 17 insertions(+), 4 deletions(-) rename Executables/Validation/{TestPythonBasics.py.in => TestPythonBasics.py} (51%) create mode 100644 Library/AddLibPythonPath.sh.in diff --git a/Executables/Validation/CMakeLists.txt b/Executables/Validation/CMakeLists.txt index 8a5e66f..0c43b6c 100644 --- a/Executables/Validation/CMakeLists.txt +++ b/Executables/Validation/CMakeLists.txt @@ -68,15 +68,21 @@ if (Nymph_ENABLE_TESTING) pbuilder_executables( TEST_PROGRAMS LIB_DEPENDENCIES ) + # Python Interface + # Python bindings set( VALIDATION_PYBINDING_FILES TestPythonBasics.cc ) + + # Python scripts + set( VALIDATION_PY_SCRIPTS + TestPythonBasics.py + ) pybind11_add_module( nymph_validation MODULE ${VALIDATION_PYBINDING_FILES} ) pbuilder_install_libraries( nymph_validation ) - configure_file( TestPythonBasics.py.in TestPythonBasics.py @ONLY) - install( FILES ${CMAKE_CURRENT_BINARY_DIR}/TestPythonBasics.py DESTINATION ${BIN_INSTALL_DIR} ) + install( FILES ${VALIDATION_PY_SCRIPTS} DESTINATION ${BIN_INSTALL_DIR} ) endif (Nymph_ENABLE_TESTING) diff --git a/Executables/Validation/TestPythonBasics.py.in b/Executables/Validation/TestPythonBasics.py similarity index 51% rename from Executables/Validation/TestPythonBasics.py.in rename to Executables/Validation/TestPythonBasics.py index 0aaf4a4..ea9dbcd 100644 --- a/Executables/Validation/TestPythonBasics.py.in +++ b/Executables/Validation/TestPythonBasics.py @@ -1,5 +1,4 @@ -import sys -sys.path.append('@LIB_INSTALL_DIR@') +# Uses Nymph::PyTest::add(), which is defined in TestPythonBasics.cc import nymph_validation diff --git a/Library/AddLibPythonPath.sh.in b/Library/AddLibPythonPath.sh.in new file mode 100644 index 0000000..68aff4b --- /dev/null +++ b/Library/AddLibPythonPath.sh.in @@ -0,0 +1,3 @@ +# Adds the lib install directory to the python path + +export PYTHONPATH=@LIB_INSTALL_DIR@:$PYTHONPATH diff --git a/Library/CMakeLists.txt b/Library/CMakeLists.txt index c0692b4..6eabc5c 100644 --- a/Library/CMakeLists.txt +++ b/Library/CMakeLists.txt @@ -96,3 +96,8 @@ pbuilder_install_headers( ${NYMPH_HEADERFILES} ) if (Nymph_ENABLE_PYTHON) python_package_add_module(NymphPy.cc) endif (Nymph_ENABLE_PYTHON) + +if( Nymph_ENABLE_PYBIND11 ) + configure_file( AddLibPythonPath.sh.in AddLibPythonPath.sh @ONLY) + install( FILES ${CMAKE_CURRENT_BINARY_DIR}/AddLibPythonPath.sh DESTINATION ${BIN_INSTALL_DIR} ) +endif( Nymph_ENABLE_PYBIND11 ) From f14fb50cca62be2bff69e3345b1532bcf00e7ec1 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Sat, 27 Jan 2018 18:03:02 -0800 Subject: [PATCH 069/521] Ok, now we're getting our ducks in a row. Added KTPyTestClass and its binding, and setup things in the Validation folder to make a single module with multiple contributions that also is linked to the other Nymph and external libraries. --- Executables/Validation/CMakeLists.txt | 17 +++++-- Executables/Validation/KTPyTestClass.cc | 22 ++++++++++ Executables/Validation/KTPyTestClass.hh | 44 +++++++++++++++++++ Executables/Validation/KTPyTestClassPybind.hh | 22 ++++++++++ Executables/Validation/NymphValidationPy.cc | 18 ++++++++ Executables/Validation/TestPyTestClass.py | 9 ++++ ...estPythonBasics.cc => TestPythonBasics.hh} | 2 +- 7 files changed, 130 insertions(+), 4 deletions(-) create mode 100644 Executables/Validation/KTPyTestClass.cc create mode 100644 Executables/Validation/KTPyTestClass.hh create mode 100644 Executables/Validation/KTPyTestClassPybind.hh create mode 100644 Executables/Validation/NymphValidationPy.cc create mode 100644 Executables/Validation/TestPyTestClass.py rename Executables/Validation/{TestPythonBasics.cc => TestPythonBasics.hh} (86%) diff --git a/Executables/Validation/CMakeLists.txt b/Executables/Validation/CMakeLists.txt index 0c43b6c..3b97912 100644 --- a/Executables/Validation/CMakeLists.txt +++ b/Executables/Validation/CMakeLists.txt @@ -13,6 +13,7 @@ if (Nymph_ENABLE_TESTING) # Headers for any test classes set (VALIDATION_HEADERFILES + KTPyTestClass.hh KTTestConfigurable.hh KTTestCuts.hh KTTestData.hh @@ -21,6 +22,7 @@ if (Nymph_ENABLE_TESTING) ) set (VALIDATION_SOURCEFILES + KTPyTestclass.cc KTTestConfigurable.cc KTTestCuts.cc KTTestData.cc @@ -70,18 +72,27 @@ if (Nymph_ENABLE_TESTING) # Python Interface + # Python binding headers + set( VALIDATION_PYBINDING_HEADERFILES + KTPyTestClassPybind.hh + TestPythonBasics.hh + ) + # Python bindings - set( VALIDATION_PYBINDING_FILES - TestPythonBasics.cc + set( VALIDATION_PYBINDING_SOURCEFILES + NymphValidationPy.cc ) # Python scripts set( VALIDATION_PY_SCRIPTS + TestPyTestClass.py TestPythonBasics.py ) - pybind11_add_module( nymph_validation MODULE ${VALIDATION_PYBINDING_FILES} ) + pybind11_add_module( nymph_validation MODULE ${VALIDATION_PYBINDING_SOURCEFILES} ) + target_link_libraries( nymph_validation PRIVATE ${LIB_DEPENDENCIES} ${EXTERNAL_LIBRARIES} ) pbuilder_install_libraries( nymph_validation ) + pbuilder_install_headers( ${VALIDATION_PYBINDING_HEADERFILES} ) install( FILES ${VALIDATION_PY_SCRIPTS} DESTINATION ${BIN_INSTALL_DIR} ) diff --git a/Executables/Validation/KTPyTestClass.cc b/Executables/Validation/KTPyTestClass.cc new file mode 100644 index 0000000..43c8f3b --- /dev/null +++ b/Executables/Validation/KTPyTestClass.cc @@ -0,0 +1,22 @@ +/* + * KTPyTestClass.cc + * + * Created on: Jan 24, 2018 + * Author: obla999 + */ + +#include "KTPyTestClass.hh" + +namespace Nymph +{ + + KTPyTestClass::KTPyTestClass() : + fValue( 5 ) + { + } + + KTPyTestClass::~KTPyTestClass() + { + } + +} /* namespace Nymph */ diff --git a/Executables/Validation/KTPyTestClass.hh b/Executables/Validation/KTPyTestClass.hh new file mode 100644 index 0000000..9e6ad27 --- /dev/null +++ b/Executables/Validation/KTPyTestClass.hh @@ -0,0 +1,44 @@ +/* + * KTPyTestClass.hh + * + * Created on: Jan 24, 2018 + * Author: obla999 + */ + +#ifndef NYMPH_KTPYTESTCLASS_HH_ +#define NYMPH_KTPYTESTCLASS_HH_ + +#include + +namespace Nymph +{ + + class KTPyTestClass + { + public: + KTPyTestClass(); + ~KTPyTestClass(); + + void SayHello() + { + std::cout << "Hello" << std::endl; + } + + int GetValue() + { + return fValue; + } + + void SetValue( int value ) + { + fValue = value; + return; + } + + private: + int fValue; + }; + +} /* namespace Nymph */ + +#endif /* NYMPH_KTPYTESTCLASS_HH_ */ diff --git a/Executables/Validation/KTPyTestClassPybind.hh b/Executables/Validation/KTPyTestClassPybind.hh new file mode 100644 index 0000000..7520725 --- /dev/null +++ b/Executables/Validation/KTPyTestClassPybind.hh @@ -0,0 +1,22 @@ +/* + * KTPyTestClassPybind.cc + * + * Created on: Jan 24, 2018 + * Author: obla999 + */ + +#include "KTPyTestClass.hh" + +#include "pybind11/pybind11.h" + +void ExportKTPyTestClass( pybind11::module& mod ) +{ + pybind11::class_< Nymph::KTPyTestClass >( mod, "KTPyTestClass" ) + .def( pybind11::init<>() ) + .def( "SayHello", &Nymph::KTPyTestClass::SayHello ) + .def( "GetValue", &Nymph::KTPyTestClass::GetValue ) + .def( "SetValue", &Nymph::KTPyTestClass::SetValue ) + ; +} + + diff --git a/Executables/Validation/NymphValidationPy.cc b/Executables/Validation/NymphValidationPy.cc new file mode 100644 index 0000000..99bcfee --- /dev/null +++ b/Executables/Validation/NymphValidationPy.cc @@ -0,0 +1,18 @@ +/* + * NymphValidationPy.cc + * + * Created on: Jan 25, 2018 + * Author: obla999 + */ + +#include "KTPyTestClassPybind.hh" +#include "TestPythonBasics.hh" + +PYBIND11_MODULE( nymph_validation, mod ) +{ + ExportKTPyTestClass( mod ); + ExportTestPythonBasics( mod ); +} + + + diff --git a/Executables/Validation/TestPyTestClass.py b/Executables/Validation/TestPyTestClass.py new file mode 100644 index 0000000..150fc38 --- /dev/null +++ b/Executables/Validation/TestPyTestClass.py @@ -0,0 +1,9 @@ +# Demonstrates access to KTPyTestClass + +import nymph_validation as nv + +ptc = nv.KTPyTestClass() + +print( 'Ok, KTPyTestClass, say hello . . .' ) +print( ptc.SayHello() ) +print( 'This should print the default value of KTPyTestClass::fValue, which is 5:', ptc.GetValue() ) diff --git a/Executables/Validation/TestPythonBasics.cc b/Executables/Validation/TestPythonBasics.hh similarity index 86% rename from Executables/Validation/TestPythonBasics.cc rename to Executables/Validation/TestPythonBasics.hh index c7551f4..7911acd 100644 --- a/Executables/Validation/TestPythonBasics.cc +++ b/Executables/Validation/TestPythonBasics.hh @@ -19,7 +19,7 @@ namespace Nymph } } -PYBIND11_MODULE( nymph_validation, mod ) +void ExportTestPythonBasics( pybind11::module& mod ) { mod.def( "add", &Nymph::PyTest::add, "A function that adds two integers" ); } From 86e874692e572a39326825cf3e06465c829bf3f2 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Mon, 29 Jan 2018 17:40:59 -0800 Subject: [PATCH 070/521] Added bindings for KTProcessorToolbox. Added dummy python processor base class KTPyProcessor. Added test script for the proc toolbox, TestProcessorToolbox.py. --- Executables/Validation/CMakeLists.txt | 52 +++++----- Executables/Validation/KTPyTestClassPybind.hh | 19 ++-- ...lidationPy.cc => NymphValidationPybind.cc} | 6 +- .../Validation/TestProcessorToolbox.py | 23 +++++ Executables/Validation/TestPyTestClass.py | 2 +- Executables/Validation/TestPythonBasics.hh | 9 +- Executables/Validation/TestPythonBasics.py | 2 +- Library/Application/KTProcessorToolbox.hh | 9 +- .../Application/KTProcessorToolboxPybind.hh | 98 +++++++++++++++++++ Library/CMakeLists.txt | 20 ++++ Library/NymphPybind.cc | 20 ++++ Library/Processor/KTProcessorPybind.hh | 38 +++++++ Library/Processor/KTPyProcessor.hh | 32 ++++++ Library/Utility/KTConfigurablePybind.hh | 29 ++++++ 14 files changed, 316 insertions(+), 43 deletions(-) rename Executables/Validation/{NymphValidationPy.cc => NymphValidationPybind.cc} (56%) create mode 100644 Executables/Validation/TestProcessorToolbox.py create mode 100644 Library/Application/KTProcessorToolboxPybind.hh create mode 100644 Library/NymphPybind.cc create mode 100644 Library/Processor/KTProcessorPybind.hh create mode 100644 Library/Processor/KTPyProcessor.hh create mode 100644 Library/Utility/KTConfigurablePybind.hh diff --git a/Executables/Validation/CMakeLists.txt b/Executables/Validation/CMakeLists.txt index 3b97912..cb562e7 100644 --- a/Executables/Validation/CMakeLists.txt +++ b/Executables/Validation/CMakeLists.txt @@ -70,30 +70,34 @@ if (Nymph_ENABLE_TESTING) pbuilder_executables( TEST_PROGRAMS LIB_DEPENDENCIES ) - # Python Interface - - # Python binding headers - set( VALIDATION_PYBINDING_HEADERFILES - KTPyTestClassPybind.hh - TestPythonBasics.hh - ) - - # Python bindings - set( VALIDATION_PYBINDING_SOURCEFILES - NymphValidationPy.cc - ) - - # Python scripts - set( VALIDATION_PY_SCRIPTS - TestPyTestClass.py - TestPythonBasics.py - ) - - pybind11_add_module( nymph_validation MODULE ${VALIDATION_PYBINDING_SOURCEFILES} ) - target_link_libraries( nymph_validation PRIVATE ${LIB_DEPENDENCIES} ${EXTERNAL_LIBRARIES} ) - pbuilder_install_libraries( nymph_validation ) - pbuilder_install_headers( ${VALIDATION_PYBINDING_HEADERFILES} ) + if( Nymph_ENABLE_PYBIND11 ) + # Python Interface + + # Python binding headers + set( VALIDATION_PYBINDING_HEADERFILES + KTPyTestClassPybind.hh + TestPythonBasics.hh + ) + + # Python bindings + set( VALIDATION_PYBINDING_SOURCEFILES + NymphValidationPybind.cc + ) + + # Python scripts + set( VALIDATION_PY_SCRIPTS + TestProcessorToolbox.py + TestPyTestClass.py + TestPythonBasics.py + ) + + pybind11_add_module( py_nymph_validation MODULE ${VALIDATION_PYBINDING_SOURCEFILES} ) + target_link_libraries( py_nymph_validation PRIVATE ${LIB_DEPENDENCIES} ${EXTERNAL_LIBRARIES} ) + pbuilder_install_libraries( py_nymph_validation ) + pbuilder_install_headers( ${VALIDATION_PYBINDING_HEADERFILES} ) + + install( FILES ${VALIDATION_PY_SCRIPTS} DESTINATION ${BIN_INSTALL_DIR} ) - install( FILES ${VALIDATION_PY_SCRIPTS} DESTINATION ${BIN_INSTALL_DIR} ) + endif( Nymph_ENABLE_PYBIND11 ) endif (Nymph_ENABLE_TESTING) diff --git a/Executables/Validation/KTPyTestClassPybind.hh b/Executables/Validation/KTPyTestClassPybind.hh index 7520725..bda9d69 100644 --- a/Executables/Validation/KTPyTestClassPybind.hh +++ b/Executables/Validation/KTPyTestClassPybind.hh @@ -9,14 +9,17 @@ #include "pybind11/pybind11.h" -void ExportKTPyTestClass( pybind11::module& mod ) +namespace Nymph { - pybind11::class_< Nymph::KTPyTestClass >( mod, "KTPyTestClass" ) - .def( pybind11::init<>() ) - .def( "SayHello", &Nymph::KTPyTestClass::SayHello ) - .def( "GetValue", &Nymph::KTPyTestClass::GetValue ) - .def( "SetValue", &Nymph::KTPyTestClass::SetValue ) - ; -} + void ExportKTPyTestClass( pybind11::module& mod ) + { + pybind11::class_< Nymph::KTPyTestClass >( mod, "KTPyTestClass" ) + .def( pybind11::init<>() ) + .def( "SayHello", &Nymph::KTPyTestClass::SayHello ) + .def( "GetValue", &Nymph::KTPyTestClass::GetValue ) + .def( "SetValue", &Nymph::KTPyTestClass::SetValue ) + ; + } +} /* namespace Nymph */ diff --git a/Executables/Validation/NymphValidationPy.cc b/Executables/Validation/NymphValidationPybind.cc similarity index 56% rename from Executables/Validation/NymphValidationPy.cc rename to Executables/Validation/NymphValidationPybind.cc index 99bcfee..0f2bad2 100644 --- a/Executables/Validation/NymphValidationPy.cc +++ b/Executables/Validation/NymphValidationPybind.cc @@ -8,10 +8,10 @@ #include "KTPyTestClassPybind.hh" #include "TestPythonBasics.hh" -PYBIND11_MODULE( nymph_validation, mod ) +PYBIND11_MODULE( py_nymph_validation, mod ) { - ExportKTPyTestClass( mod ); - ExportTestPythonBasics( mod ); + Nymph::ExportKTPyTestClass( mod ); + Nymph::ExportTestPythonBasics( mod ); } diff --git a/Executables/Validation/TestProcessorToolbox.py b/Executables/Validation/TestProcessorToolbox.py new file mode 100644 index 0000000..e2c4bb5 --- /dev/null +++ b/Executables/Validation/TestProcessorToolbox.py @@ -0,0 +1,23 @@ +# TestProcessorToolbox.py +# Created on: Jan 29, 2018 +# Author: N.S. Oblath +# +# Tests the ability to use the processor toolbox from a Python script + +import py_nymph as nymph +import py_nymph_validation as nv + +ptb = nymph.KTProcessorToolbox('pt') + +print('Configuring') + +ptb.AddProcessor('test-p-proc', 'tpp') +ptb.AddProcessor('test-proc-b', 'tp') +ptb.MakeConnection('tpp:the-signal', 'tp:first-slot') +ptb.PushBackToRunQueue('tpp') + +print('Running') + +ptb.Run() + +print('All done') diff --git a/Executables/Validation/TestPyTestClass.py b/Executables/Validation/TestPyTestClass.py index 150fc38..3520ef9 100644 --- a/Executables/Validation/TestPyTestClass.py +++ b/Executables/Validation/TestPyTestClass.py @@ -1,6 +1,6 @@ # Demonstrates access to KTPyTestClass -import nymph_validation as nv +import py_nymph_validation as nv ptc = nv.KTPyTestClass() diff --git a/Executables/Validation/TestPythonBasics.hh b/Executables/Validation/TestPythonBasics.hh index 7911acd..f1f6ef0 100644 --- a/Executables/Validation/TestPythonBasics.hh +++ b/Executables/Validation/TestPythonBasics.hh @@ -17,9 +17,10 @@ namespace Nymph return i + j; } } -} -void ExportTestPythonBasics( pybind11::module& mod ) -{ - mod.def( "add", &Nymph::PyTest::add, "A function that adds two integers" ); + void ExportTestPythonBasics( pybind11::module& mod ) + { + mod.def( "add", &PyTest::add, "A function that adds two integers" ); + } + } diff --git a/Executables/Validation/TestPythonBasics.py b/Executables/Validation/TestPythonBasics.py index ea9dbcd..0014f12 100644 --- a/Executables/Validation/TestPythonBasics.py +++ b/Executables/Validation/TestPythonBasics.py @@ -1,5 +1,5 @@ # Uses Nymph::PyTest::add(), which is defined in TestPythonBasics.cc -import nymph_validation +import py_nymph_validation print( '1 + 2 =', nymph_validation.add(1, 2) ) diff --git a/Library/Application/KTProcessorToolbox.hh b/Library/Application/KTProcessorToolbox.hh index 5d5ccda..42d97fd 100644 --- a/Library/Application/KTProcessorToolbox.hh +++ b/Library/Application/KTProcessorToolbox.hh @@ -144,14 +144,19 @@ namespace Nymph public: + // for the MakeConnection overloading, extra overloading is used instead of default parameters so that the python interface works + /// Make a connection between the signal from one processor and the slot from another processor /// Both processors should already have been added to the Toolbox /// Signal and slot strings should be formatted as: [processor name]:[signal/slot name] - bool MakeConnection(const std::string& signal, const std::string& slot, int order = std::numeric_limits< int >::min()); + bool MakeConnection(const std::string& signal, const std::string& slot, int order); + bool MakeConnection(const std::string& signal, const std::string& slot) {return MakeConnection(signal, slot, std::numeric_limits< int >::min());} /// Make a connection between the signal from one processor and the slot from another processor /// Both processors should already have been added to the Toolbox - bool MakeConnection(const std::string& signalProcName, const std::string& signalName, const std::string& slotProcName, const std::string& slotName, int order = std::numeric_limits< int >::min()); + bool MakeConnection(const std::string& signalProcName, const std::string& signalName, const std::string& slotProcName, const std::string& slotName, int order); + bool MakeConnection(const std::string& signalProcName, const std::string& signalName, const std::string& slotProcName, const std::string& slotName) + {return MakeConnection(signalProcName, signalName, slotProcName, slotName, std::numeric_limits< int >::min());} /// Set a breakpoint on a slot /// Slot string should be formatted as: [processor name]:[slot name] diff --git a/Library/Application/KTProcessorToolboxPybind.hh b/Library/Application/KTProcessorToolboxPybind.hh new file mode 100644 index 0000000..678a374 --- /dev/null +++ b/Library/Application/KTProcessorToolboxPybind.hh @@ -0,0 +1,98 @@ +/* + * KTProcessorToolboxPybind.hh + * + * Created on: Jan 29, 2018 + * Author: N.S. Oblath + */ + +#ifndef NYMPH_KTPROCESSORTOOLBOXPYBIND_HH_ +#define NYMPH_KTPROCESSORTOOLBOXPYBIND_HH_ + +#include "KTProcessorToolbox.hh" + +#include "pybind11/pybind11.h" +#include "pybind11/stl.h" + +namespace Nymph +{ + void ExportKTProcessorToolbox( pybind11::module& mod ) + { + + pybind11::class_< KTProcessorToolbox >( mod, "KTProcessorToolbox" ) + .def( pybind11::init< const std::string & >() ) + + // members related to configuration + .def( "ConfigureProcessors", (bool (KTProcessorToolbox::*)(const std::string&)) &KTProcessorToolbox::ConfigureProcessors, + "Configure processors from a json dictionary. Top-level keys are processor names, values are dictionaries with their configurations" ) + + // processor access + // GetProcessor skipped because raw pointers are not supported by pybind11 + .def( "AddProcessor", (bool (KTProcessorToolbox::*)(const std::string&, const std::string&)) &KTProcessorToolbox::AddProcessor, + "Create a processor by name and add it to the toolbox" ) + // skipping AddProcessor(const std::string&, KTProcessor*) + .def( "RemoveProcessor", &KTProcessorToolbox::RemoveProcessor, + "Remove a processor from the toolbox" ) + // skipping ReleaseProcessor + .def( "ClearProcessor", &KTProcessorToolbox::ClearProcessors, + "Remove all processors from the toolbox" ) + + // processor connections + .def( "MakeConnection", (bool (KTProcessorToolbox::*)(const std::string&, const std::string&, int)) &KTProcessorToolbox::MakeConnection, + "Make a connection between the signal of one processor and the slot of another processor; the signal and slot strings should be formatted as: [processor name]:[signal/slot name]" ) + .def( "MakeConnection", (bool (KTProcessorToolbox::*)(const std::string&, const std::string&)) &KTProcessorToolbox::MakeConnection, + "Make a connection between the signal of one processor and the slot of another processor; the signal and slot strings should be formatted as: [processor name]:[signal/slot name]" ) + .def( "MakeConnection", (bool (KTProcessorToolbox::*)(const std::string&, const std::string&, const std::string&, const std::string&, int)) &KTProcessorToolbox::MakeConnection, + "Make a connection between the signal of one processor and the slot of another processor" ) + .def( "MakeConnection", (bool (KTProcessorToolbox::*)(const std::string&, const std::string&, const std::string&, const std::string&)) &KTProcessorToolbox::MakeConnection, + "Make a connection between the signal of one processor and the slot of another processor" ) + + // breakpoints + .def( "SetBreakpoint", (bool (KTProcessorToolbox::*)(const std::string&)) &KTProcessorToolbox::SetBreakpoint, + "Set a breakpoint at a specific slot; slot string should be formatted as: [processor name]:[slot name]" ) + .def( "SetBreakpoint", (bool (KTProcessorToolbox::*)(const std::string&, const std::string&)) &KTProcessorToolbox::SetBreakpoint, + "Set a breakpoint at a specific slot" ) + + .def( "RemoveBreakpoint", (bool (KTProcessorToolbox::*)(const std::string&)) &KTProcessorToolbox::RemoveBreakpoint, + "Remove a breakpoint; slot string should be formatted as: [processor name]:[slot name]" ) + .def( "RemoveBreakpoint", (bool (KTProcessorToolbox::*)(const std::string&, const std::string&)) &KTProcessorToolbox::RemoveBreakpoint, + "Remove a breakpoint" ) + + // run queue + .def( "PushBackToRunQueue", (bool (KTProcessorToolbox::*)(const std::string&)) &KTProcessorToolbox::PushBackToRunQueue, + "Push one or more processors to the back of the run queue using a comma-separated string" ) + .def( "PushBackToRunQueue", (bool (KTProcessorToolbox::*)(std::vector< std::string >)) &KTProcessorToolbox::PushBackToRunQueue, + "Push one or more processors to the back of the run queue using a vector of strings" ) + + .def( "PopBackOfRunQueue", &KTProcessorToolbox::PopBackOfRunQueue, + "Remove the last item in the run queue, whether it's a single processor or a group" ) + .def( "ClearRunQueue", &KTProcessorToolbox::ClearRunQueue, + "Remove all items from the run queue" ) + + // run methods + .def( "Run", &KTProcessorToolbox::Run, "Start the processors listed in the run queue (blocking)" ) + .def( "AsyncRun", &KTProcessorToolbox::AsyncRun, "Non-blocking call to Run()" ) + .def( "WaitForBreak", &KTProcessorToolbox::WaitForBreak, "Blocking call that waits until a breakpoint is reached; you must manually Continue() to proceed" ) + .def( "WaitForEndOfRun", &KTProcessorToolbox::WaitForEndOfRun, "Blocking call to Continue() execution until the end of the run is reached; you must manually Continue() to proceed" ) + .def( "Continue", &KTProcessorToolbox::Continue, "Resume execution (non-blocking)" ) + .def( "CancelThreads", &KTProcessorToolbox::CancelThreads, "Kill any running thread at the next breakpoint check" ) + .def( "JoinRunThread", &KTProcessorToolbox::JoinRunThread, "Blocking call to wait until Run() is complete; this should only be done by the owner of the thread (typically whoever called Run())" ) + + .def( "GetData", &KTProcessorToolbox::GetData, "Retrieve the data handle from a slot by thread name (i.e. the name of the primary processor for that thread)" ) + + /* + // these are implemented in the boost::python version but not yet here + + PROPERTYMEMBER(KTProcessorToolbox, RunSingleThreaded) + + // Processor access + .def("GetProcessor", GetProcessor_wrap, return_value_policy(), "Get a pointer to a processor in the toolbox") + .def("AddProcessor", AddProcessor_Ref, "add a processor to the toolbox, toolbox takes ownership") + // TODO: Not 100% certain that the reference count for this processor is now correct, given the return_value_policy + .def("ReleaseProcessor", &KTProcessorToolbox::ReleaseProcessor, return_value_policy(), "Remove a processor from the toolbox and return it to the user, ownership is passed") + */ + ; + + } +} + +#endif /* NYMPH_KTPROCESSORTOOLBOXPYBIND_HH_ */ diff --git a/Library/CMakeLists.txt b/Library/CMakeLists.txt index 6eabc5c..f9c7f14 100644 --- a/Library/CMakeLists.txt +++ b/Library/CMakeLists.txt @@ -88,6 +88,18 @@ set( NYMPH_PY_HEADERFILES ${APPL_DIR}/KTProcessorToolboxPy.hh ) +# Python binding headers +set( NYMPH_PYBINDING_HEADERFILES + #${UTIL_DIR}/KTConfigurablePybind.hh + ${PROC_DIR}/KTProcessorPybind.hh + ${PROC_DIR}/KTPyProcessor.hh +) + +# Python bindings +set( NYMPH_PYBINDING_SOURCEFILES + NymphPybind.cc +) + ################################################## pbuilder_library( Nymph NYMPH_SOURCEFILES "" ) @@ -98,6 +110,14 @@ if (Nymph_ENABLE_PYTHON) endif (Nymph_ENABLE_PYTHON) if( Nymph_ENABLE_PYBIND11 ) + set( LIB_DEPENDENCIES Nymph ) + configure_file( AddLibPythonPath.sh.in AddLibPythonPath.sh @ONLY) install( FILES ${CMAKE_CURRENT_BINARY_DIR}/AddLibPythonPath.sh DESTINATION ${BIN_INSTALL_DIR} ) + + pybind11_add_module( py_nymph MODULE ${NYMPH_PYBINDING_SOURCEFILES} ) + target_link_libraries( py_nymph PRIVATE ${LIB_DEPENDENCIES} ${EXTERNAL_LIBRARIES} ) + pbuilder_install_libraries( py_nymph ) + pbuilder_install_headers( ${NYMPH_PYBINDING_HEADERFILES} ) + endif( Nymph_ENABLE_PYBIND11 ) diff --git a/Library/NymphPybind.cc b/Library/NymphPybind.cc new file mode 100644 index 0000000..dc99ee8 --- /dev/null +++ b/Library/NymphPybind.cc @@ -0,0 +1,20 @@ +/* + * NymphPybind.cc + * + * Created on: Jan 27, 2018 + * Author: obla999 + */ + +#include "Application/KTProcessorToolboxPybind.hh" +#include "Processor/KTProcessorPybind.hh" +//#include "Utility/KTConfigurablePybind.hh" + +PYBIND11_MODULE( py_nymph, mod ) +{ + //Nymph::ExportKTConfigurable( mod ); + Nymph::ExportKTProcessor( mod ); + Nymph::ExportKTProcessorToolbox( mod ); +} + + + diff --git a/Library/Processor/KTProcessorPybind.hh b/Library/Processor/KTProcessorPybind.hh new file mode 100644 index 0000000..fcfee1e --- /dev/null +++ b/Library/Processor/KTProcessorPybind.hh @@ -0,0 +1,38 @@ +/* + * KTProcessorPybind.cc + * + * Created on: Jan 24, 2018 + * Author: obla999 + */ + +#ifndef NYMPH_KTPROCESSORPYBIND_HH_ +#define NYMPH_KTPROCESSORPYBIND_HH_ + +#include "KTPyProcessor.hh" + +#include "pybind11/pybind11.h" + +namespace Nymph +{ + + void ExportKTProcessor( pybind11::module& mod ) + { +/* pybind11::class_< KTProcessor, KTConfigurable >( mod, "KTProcessor" ) + .def( pybind11::init< const std::string & >() ) + + .def( "ConnectASlot", &Nymph::KTProcessor::ConnectASlot ) + .def( "ConnectASignal", &Nymph::KTProcessor::ConnectASignal ) + + .def( "GetDoBreakpoint", &Nymph::KTProcessor::GetDoBreakpoint ) + .def( "SetDoBreakpoint", &Nymph::KTProcessor::SetDoBreakpoint ) + ; +*/ + pybind11::class_< KTPyProcessor >( mod, "KTPyProcessor" ) + .def( pybind11::init< const std::string & >() ) + ; + + } + +} /* namespace Nymph */ + +#endif /* NYMPH_KTPROCESSORPYBIND_HH_ */ diff --git a/Library/Processor/KTPyProcessor.hh b/Library/Processor/KTPyProcessor.hh new file mode 100644 index 0000000..52f27b1 --- /dev/null +++ b/Library/Processor/KTPyProcessor.hh @@ -0,0 +1,32 @@ +/* + * KTPyProcessor.hh + * + * Created on: Jan 29, 2018 + * Author: N.S. Oblath + */ + +#ifndef NYMPH_KTPYPROCESSOR_HH_ +#define NYMPH_KTPYPROCESSOR_HH_ + +#include "KTProcessor.hh" + +namespace Nymph +{ + + class KTPyProcessor : public KTProcessor + { + public: + using KTProcessor::KTProcessor; // inherit constructors + + // for now, override KTConfigurable::Configure(const scarab::param_node&) with a non-functional function + bool Configure(const scarab::param_node& ) + { + return true; + } + }; + + + +} /* namespace Nymph */ + +#endif /* NYMPH_KTPYPROCESSOR_HH_ */ diff --git a/Library/Utility/KTConfigurablePybind.hh b/Library/Utility/KTConfigurablePybind.hh new file mode 100644 index 0000000..585a33f --- /dev/null +++ b/Library/Utility/KTConfigurablePybind.hh @@ -0,0 +1,29 @@ +/* + * KTConfigurablePybind.cc + * + * Created on: Jan 27, 2018 + * Author: N. Oblath + */ + +#include "KTConfigurable.hh" + +#include "pybind11/pybind11.h" + +namespace Nymph +{ + + void ExportKTConfigurable( pybind11::module& mod ) + { +/* pybind11::class_< KTConfigurable >( mod, "KTConfigurable" ) + .def( pybind11::init< const std::string & >() ) + + .def( "Configure", (bool (KTConfigurable::*)(const std::string&)) &KTConfigurable::Configure ) + //.def( "Configure", (void (KTConfigurable::*)(const scarab::param_node&)) &KTConfigurable::Configure ) + + .def( "GetConfigName", &KTConfigurable::GetConfigName ) + .def( "SetConfigName", &KTConfigurable::SetConfigName ) + ; +*/ + } + +} /* namespace Nymph */ From e7875d1d2ad5eed65b63c58c6607589e30cfb37f Mon Sep 17 00:00:00 2001 From: cclaessens Date: Thu, 1 Feb 2018 16:43:06 +0100 Subject: [PATCH 071/521] changed KTPyTestclass.cc to KTPyTestClass.cc in Executables/Validation/CMakeLists.txt --- Executables/Validation/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Executables/Validation/CMakeLists.txt b/Executables/Validation/CMakeLists.txt index cb562e7..72c3ba6 100644 --- a/Executables/Validation/CMakeLists.txt +++ b/Executables/Validation/CMakeLists.txt @@ -22,7 +22,7 @@ if (Nymph_ENABLE_TESTING) ) set (VALIDATION_SOURCEFILES - KTPyTestclass.cc + KTPyTestClass.cc KTTestConfigurable.cc KTTestCuts.cc KTTestData.cc From 06468c6d85236c4acb1187ce3635d1c99c4d3cf6 Mon Sep 17 00:00:00 2001 From: lgladstone Date: Thu, 1 Feb 2018 08:16:50 -0800 Subject: [PATCH 072/521] add py_ prefix --- Executables/Validation/TestPythonBasics.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Executables/Validation/TestPythonBasics.py b/Executables/Validation/TestPythonBasics.py index 0014f12..5702fe7 100644 --- a/Executables/Validation/TestPythonBasics.py +++ b/Executables/Validation/TestPythonBasics.py @@ -2,4 +2,4 @@ import py_nymph_validation -print( '1 + 2 =', nymph_validation.add(1, 2) ) +print( '1 + 2 =', py_nymph_validation.add(1, 2) ) From fbe2a5a8295e425f9a27d150d4ef4e64c789550e Mon Sep 17 00:00:00 2001 From: Evan Zayas Date: Thu, 1 Feb 2018 12:17:25 -0500 Subject: [PATCH 073/521] drafted serial writer class --- Executables/Validation/CMakeLists.txt | 2 + Executables/Validation/KTSerialWriter.cc | 55 ++++++++++++++++ Executables/Validation/KTSerialWriter.hh | 83 ++++++++++++++++++++++++ 3 files changed, 140 insertions(+) create mode 100644 Executables/Validation/KTSerialWriter.cc create mode 100644 Executables/Validation/KTSerialWriter.hh diff --git a/Executables/Validation/CMakeLists.txt b/Executables/Validation/CMakeLists.txt index 718fc89..051e661 100644 --- a/Executables/Validation/CMakeLists.txt +++ b/Executables/Validation/CMakeLists.txt @@ -13,6 +13,7 @@ if (Nymph_ENABLE_TESTING) # Headers for any test classes set (VALIDATION_HEADERFILES + KTSerialWriter.hh KTTestConfigurable.hh KTTestCuts.hh KTTestData.hh @@ -21,6 +22,7 @@ if (Nymph_ENABLE_TESTING) ) set (VALIDATION_SOURCEFILES + KTSerialWriter.cc KTTestConfigurable.cc KTTestCuts.cc KTTestData.cc diff --git a/Executables/Validation/KTSerialWriter.cc b/Executables/Validation/KTSerialWriter.cc new file mode 100644 index 0000000..3bcd385 --- /dev/null +++ b/Executables/Validation/KTSerialWriter.cc @@ -0,0 +1,55 @@ +/* + * KTSerialWriter.cc + * + * Created on: Feb 1, 2018 + * Author: E Zayas + * +*/ + +#include "KTSerialWriter.hh" + +#include "KTLogger.hh" + +LOGGER( avlog_hh, "KTSerialWriter" ); + +namespace Nymph +{ + KTSerialWriter::KTSerialWriter( const std::string& name ) : + KTProcessor( name ), + fFileName( "placeholder.json" ), + fStreamOutPtr(nullptr), + fArchiveOutPtr(nullptr) + { + // Register slots here + } + + KTSerialWriter::~KTSerialWriter() + { + //delete fStreamOutPtr; + //delete fArchiveOutPtr; + } + + bool KTSerialWriter::Configure( const scarab::param_node* node ) + { + if (node == NULL) return false; + + SetFileName( node->get_value< std::string >( "file-name", fFileName ) ); + + *fStreamOutPtr = std::ofstream( fFileName ); + cereal::JSONOutputArchive fStupid( *fStreamOutPtr ); + fArchiveOutPtr = &fStupid; + + return true; + } + + template< class XDataType > + void KTSerialWriter::SlotFunction( const XDataType& data ) + { + // Write to JSON archive + KTINFO( avlog_hh, "Writing data to JSON acrhive" ); + *fArchiveOutPtr( data ); + + KTINFO( avlog_hh, "Successfully wrote data to archive" ); + return; + } +} diff --git a/Executables/Validation/KTSerialWriter.hh b/Executables/Validation/KTSerialWriter.hh new file mode 100644 index 0000000..35d630c --- /dev/null +++ b/Executables/Validation/KTSerialWriter.hh @@ -0,0 +1,83 @@ +/* + * KTSerialWriter.hh + * + * Created on: Feb 1, 2018 + * Author: E Zayas + * +*/ + +#ifndef KTSERIALWRITER_HH_ +#define KTSERIALWRITER_HH_ + +#include "KTData.hh" +#include "KTProcessor.hh" +#include "KTSlot.hh" + +#include "cereal/archives/json.hpp" +#include + +namespace Nymph +{ + class KTSerialWriter : public KTProcessor + { + public: + KTSerialWriter( const std::string& name = "serial-writer" ); + virtual ~KTSerialWriter(); + + private: + std::string fFileName; + std::ofstream* fStreamOutPtr; + cereal::JSONOutputArchive* fArchiveOutPtr; + + public: + bool Configure( const scarab::param_node* node ); + + std::string GetFileName() const; + void SetFileName( std::string file ); + + std::ofstream* GetStreamOutPtr() const; + void SetStreamOutPtr( std::ofstream stream ); + + cereal::JSONOutputArchive* GetArchiveOutPtr() const; + void SetArchiveOutPtr( cereal::JSONOutputArchive archive ); + + template< class XDataType > + void SlotFunction( const XDataType& data ); + }; + + inline std::string KTSerialWriter::GetFileName() const + { + return fFileName; + } + + inline void KTSerialWriter::SetFileName( std::string file ) + { + fFileName = file; + return; + } + + inline std::ofstream* KTSerialWriter::GetStreamOutPtr() const + { + return fStreamOutPtr; + } + + inline void KTSerialWriter::SetStreamOutPtr( std::ofstream stream ) + { + fStreamOutPtr = &stream; + return; + } + + inline cereal::JSONOutputArchive* KTSerialWriter::GetArchiveOutPtr() const + { + return fArchiveOutPtr; + } + + inline void KTSerialWriter::SetArchiveOutPtr( cereal::JSONOutputArchive archive ) + { + fArchiveOutPtr = &archive; + return; + } + +} // namespace Nymph + +#endif // KTSERIALWRITER_HH_ From 4dd15f41222f888c751568d8b24df146c634865f Mon Sep 17 00:00:00 2001 From: Evan Zayas Date: Thu, 1 Feb 2018 12:34:42 -0500 Subject: [PATCH 074/521] tabs -> spaces --- Executables/Validation/KTSerialWriter.cc | 70 ++++++------- Executables/Validation/KTSerialWriter.hh | 124 +++++++++++------------ 2 files changed, 97 insertions(+), 97 deletions(-) diff --git a/Executables/Validation/KTSerialWriter.cc b/Executables/Validation/KTSerialWriter.cc index 3bcd385..53e96cd 100644 --- a/Executables/Validation/KTSerialWriter.cc +++ b/Executables/Validation/KTSerialWriter.cc @@ -1,8 +1,8 @@ /* - * KTSerialWriter.cc + * KTSerialWriter.cc * - * Created on: Feb 1, 2018 - * Author: E Zayas + * Created on: Feb 1, 2018 + * Author: E Zayas * */ @@ -14,42 +14,42 @@ LOGGER( avlog_hh, "KTSerialWriter" ); namespace Nymph { - KTSerialWriter::KTSerialWriter( const std::string& name ) : - KTProcessor( name ), - fFileName( "placeholder.json" ), - fStreamOutPtr(nullptr), - fArchiveOutPtr(nullptr) - { - // Register slots here - } - - KTSerialWriter::~KTSerialWriter() - { - //delete fStreamOutPtr; - //delete fArchiveOutPtr; - } - - bool KTSerialWriter::Configure( const scarab::param_node* node ) - { - if (node == NULL) return false; - - SetFileName( node->get_value< std::string >( "file-name", fFileName ) ); - - *fStreamOutPtr = std::ofstream( fFileName ); - cereal::JSONOutputArchive fStupid( *fStreamOutPtr ); - fArchiveOutPtr = &fStupid; - - return true; - } - - template< class XDataType > - void KTSerialWriter::SlotFunction( const XDataType& data ) - { + KTSerialWriter::KTSerialWriter( const std::string& name ) : + KTProcessor( name ), + fFileName( "placeholder.json" ), + fStreamOutPtr(nullptr), + fArchiveOutPtr(nullptr) + { + // Register slots here + } + + KTSerialWriter::~KTSerialWriter() + { + //delete fStreamOutPtr; + //delete fArchiveOutPtr; + } + + bool KTSerialWriter::Configure( const scarab::param_node* node ) + { + if (node == NULL) return false; + + SetFileName( node->get_value< std::string >( "file-name", fFileName ) ); + + *fStreamOutPtr = std::ofstream( fFileName ); + cereal::JSONOutputArchive fStupid( *fStreamOutPtr ); + fArchiveOutPtr = &fStupid; + + return true; + } + + template< class XDataType > + void KTSerialWriter::SlotFunction( const XDataType& data ) + { // Write to JSON archive KTINFO( avlog_hh, "Writing data to JSON acrhive" ); *fArchiveOutPtr( data ); KTINFO( avlog_hh, "Successfully wrote data to archive" ); return; - } + } } diff --git a/Executables/Validation/KTSerialWriter.hh b/Executables/Validation/KTSerialWriter.hh index 35d630c..971925c 100644 --- a/Executables/Validation/KTSerialWriter.hh +++ b/Executables/Validation/KTSerialWriter.hh @@ -1,8 +1,8 @@ /* - * KTSerialWriter.hh + * KTSerialWriter.hh * - * Created on: Feb 1, 2018 - * Author: E Zayas + * Created on: Feb 1, 2018 + * Author: E Zayas * */ @@ -18,65 +18,65 @@ namespace Nymph { - class KTSerialWriter : public KTProcessor - { - public: - KTSerialWriter( const std::string& name = "serial-writer" ); - virtual ~KTSerialWriter(); - - private: - std::string fFileName; - std::ofstream* fStreamOutPtr; - cereal::JSONOutputArchive* fArchiveOutPtr; - - public: - bool Configure( const scarab::param_node* node ); - - std::string GetFileName() const; - void SetFileName( std::string file ); - - std::ofstream* GetStreamOutPtr() const; - void SetStreamOutPtr( std::ofstream stream ); - - cereal::JSONOutputArchive* GetArchiveOutPtr() const; - void SetArchiveOutPtr( cereal::JSONOutputArchive archive ); - - template< class XDataType > - void SlotFunction( const XDataType& data ); - }; - - inline std::string KTSerialWriter::GetFileName() const - { - return fFileName; - } - - inline void KTSerialWriter::SetFileName( std::string file ) - { - fFileName = file; - return; - } - - inline std::ofstream* KTSerialWriter::GetStreamOutPtr() const - { - return fStreamOutPtr; - } - - inline void KTSerialWriter::SetStreamOutPtr( std::ofstream stream ) - { - fStreamOutPtr = &stream; - return; - } - - inline cereal::JSONOutputArchive* KTSerialWriter::GetArchiveOutPtr() const - { - return fArchiveOutPtr; - } - - inline void KTSerialWriter::SetArchiveOutPtr( cereal::JSONOutputArchive archive ) - { - fArchiveOutPtr = &archive; - return; - } + class KTSerialWriter : public KTProcessor + { + public: + KTSerialWriter( const std::string& name = "serial-writer" ); + virtual ~KTSerialWriter(); + + private: + std::string fFileName; + std::ofstream* fStreamOutPtr; + cereal::JSONOutputArchive* fArchiveOutPtr; + + public: + bool Configure( const scarab::param_node* node ); + + std::string GetFileName() const; + void SetFileName( std::string file ); + + std::ofstream* GetStreamOutPtr() const; + void SetStreamOutPtr( std::ofstream stream ); + + cereal::JSONOutputArchive* GetArchiveOutPtr() const; + void SetArchiveOutPtr( cereal::JSONOutputArchive archive ); + + template< class XDataType > + void SlotFunction( const XDataType& data ); + }; + + inline std::string KTSerialWriter::GetFileName() const + { + return fFileName; + } + + inline void KTSerialWriter::SetFileName( std::string file ) + { + fFileName = file; + return; + } + + inline std::ofstream* KTSerialWriter::GetStreamOutPtr() const + { + return fStreamOutPtr; + } + + inline void KTSerialWriter::SetStreamOutPtr( std::ofstream stream ) + { + fStreamOutPtr = &stream; + return; + } + + inline cereal::JSONOutputArchive* KTSerialWriter::GetArchiveOutPtr() const + { + return fArchiveOutPtr; + } + + inline void KTSerialWriter::SetArchiveOutPtr( cereal::JSONOutputArchive archive ) + { + fArchiveOutPtr = &archive; + return; + } } // namespace Nymph From e78b80be6e0bca20c0ea243f5410e1c2ad31c188 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Thu, 1 Feb 2018 10:22:07 -0800 Subject: [PATCH 075/521] Added test json reader --- Executables/Validation/CMakeLists.txt | 2 + Executables/Validation/KTJSONReader.cc | 37 ++++++++++++++++ Executables/Validation/KTJSONReader.hh | 59 ++++++++++++++++++++++++++ 3 files changed, 98 insertions(+) create mode 100644 Executables/Validation/KTJSONReader.cc create mode 100644 Executables/Validation/KTJSONReader.hh diff --git a/Executables/Validation/CMakeLists.txt b/Executables/Validation/CMakeLists.txt index 718fc89..5e4568f 100644 --- a/Executables/Validation/CMakeLists.txt +++ b/Executables/Validation/CMakeLists.txt @@ -13,6 +13,7 @@ if (Nymph_ENABLE_TESTING) # Headers for any test classes set (VALIDATION_HEADERFILES + kTJSONReader.hh KTTestConfigurable.hh KTTestCuts.hh KTTestData.hh @@ -21,6 +22,7 @@ if (Nymph_ENABLE_TESTING) ) set (VALIDATION_SOURCEFILES + KTJSONReader.cc KTTestConfigurable.cc KTTestCuts.cc KTTestData.cc diff --git a/Executables/Validation/KTJSONReader.cc b/Executables/Validation/KTJSONReader.cc new file mode 100644 index 0000000..e3449ca --- /dev/null +++ b/Executables/Validation/KTJSONReader.cc @@ -0,0 +1,37 @@ +/* + * KTJSONReader.cc + * + * Created on: Feb 1, 2018 + * Author: N.S. Oblath + */ + +// Data classes need to be included before the archive header +#include "KTTestData.hh" + +#include "KTJSONReader.hh" + + +namespace Nymph +{ + + KTJSONReader::KTJSONReader() : + fFilename( "json-reader-default-file.json" ), + fStreamInPtr( nullptr ), + fArchiveInPtr( nullptr ) + { + } + + KTJSONReader::~KTJSONReader() + { + delete fArchiveInPtr; + delete fStreamInPtr; + } + + bool KTJSONReader::Configure( const scarab::param_node& node ) + { + SetFilename( node.get_value( "filename" , fFilename )); + + return true; + } + +} /* namespace Nymph */ diff --git a/Executables/Validation/KTJSONReader.hh b/Executables/Validation/KTJSONReader.hh new file mode 100644 index 0000000..6b5664b --- /dev/null +++ b/Executables/Validation/KTJSONReader.hh @@ -0,0 +1,59 @@ +/* + * KTJSONReader.hh + * + * Created on: Feb 1, 2018 + * Author: N.S. Oblath + */ + +#ifndef NYMPH_KTJSONREADER_HH_ +#define NYMPH_KTJSONREADER_HH_ + +#include "KTProcessor.hh" + +#include "KTLogger.hh" + +#include "cereal/archives/json.hpp" + + +KTLOGGER( jsrlog_hh, "KTJSONReader" ) + + +namespace Nymph +{ + + class KTJSONReader : public KTProcessor + { + public: + KTJSONReader(); + virtual ~KTJSONReader(); + + bool Configure( const scarab::param_node& node ); + + MEMBERVARIABLE( std::string, Filename ); + + private: + std::ifstream* fStreamInPtr; + cereal::JSONInputArchive* fArchiveInPtr; + + template< class XDataType > + void ReadData( XDataType& data ); + }; + + template< class XDataType > + void KTJSONReader::ReadData( XDataType& data ) + { + if( fStreamInPtr == nullptr ) + { + KTDEBUG( jsrlog_hh, "Creating stream and archive" ); + fStreamInPtr = new std::ifstream( fFilename ); + fArchiveInPtr = new cereal::JSONInputArchive( *fStreamInPtr ); + } + + *fArchiveInPtr( data ); + + return; + } + +} /* namespace Nymph */ + +#endif /* NYMPH_KTJSONREADER_HH_ */ From 5858bdc4a46bc4948588c565fa0b60ede920bd45 Mon Sep 17 00:00:00 2001 From: Evan Zayas Date: Thu, 1 Feb 2018 13:32:50 -0500 Subject: [PATCH 076/521] some small refactoring and val script for serial writer --- Executables/Validation/CMakeLists.txt | 1 + Executables/Validation/KTSerialWriter.cc | 21 ++++++++----- Executables/Validation/KTSerialWriter.hh | 8 +++-- Executables/Validation/TestSerialWriter.cc | 34 ++++++++++++++++++++++ 4 files changed, 54 insertions(+), 10 deletions(-) create mode 100644 Executables/Validation/TestSerialWriter.cc diff --git a/Executables/Validation/CMakeLists.txt b/Executables/Validation/CMakeLists.txt index 051e661..7323009 100644 --- a/Executables/Validation/CMakeLists.txt +++ b/Executables/Validation/CMakeLists.txt @@ -62,6 +62,7 @@ if (Nymph_ENABLE_TESTING) TestProcessorToolboxMultithreaded TestProcessorToolboxSinglethreaded TestSerialization + TestSerialWriter TestSignalsAndSlots TestSlotData TestThroughputProfiler diff --git a/Executables/Validation/KTSerialWriter.cc b/Executables/Validation/KTSerialWriter.cc index 53e96cd..638fe49 100644 --- a/Executables/Validation/KTSerialWriter.cc +++ b/Executables/Validation/KTSerialWriter.cc @@ -17,10 +17,11 @@ namespace Nymph KTSerialWriter::KTSerialWriter( const std::string& name ) : KTProcessor( name ), fFileName( "placeholder.json" ), - fStreamOutPtr(nullptr), - fArchiveOutPtr(nullptr) + fStreamOutPtr( nullptr ), + fArchiveOutPtr( nullptr ) { // Register slots here + RegisterSlot( "test-data", this, &KTSerialWriter::SlotFunction< KTTestData > ); } KTSerialWriter::~KTSerialWriter() @@ -29,25 +30,29 @@ namespace Nymph //delete fArchiveOutPtr; } - bool KTSerialWriter::Configure( const scarab::param_node* node ) + bool KTSerialWriter::Configure( const scarab::param_node& node ) { - if (node == NULL) return false; + SetFileName( node.get_value< std::string >( "file-name", fFileName ) ); + Initialize(); - SetFileName( node->get_value< std::string >( "file-name", fFileName ) ); + return true; + } + void KTSerialWriter::Initialize() + { *fStreamOutPtr = std::ofstream( fFileName ); cereal::JSONOutputArchive fStupid( *fStreamOutPtr ); fArchiveOutPtr = &fStupid; - return true; + return; } template< class XDataType > - void KTSerialWriter::SlotFunction( const XDataType& data ) + void KTSerialWriter::SlotFunction( XDataType& data ) { // Write to JSON archive KTINFO( avlog_hh, "Writing data to JSON acrhive" ); - *fArchiveOutPtr( data ); + (*fArchiveOutPtr)( data ); KTINFO( avlog_hh, "Successfully wrote data to archive" ); return; diff --git a/Executables/Validation/KTSerialWriter.hh b/Executables/Validation/KTSerialWriter.hh index 971925c..165acc1 100644 --- a/Executables/Validation/KTSerialWriter.hh +++ b/Executables/Validation/KTSerialWriter.hh @@ -13,6 +13,8 @@ #include "KTProcessor.hh" #include "KTSlot.hh" +#include "KTTestData.hh" + #include "cereal/archives/json.hpp" #include @@ -30,7 +32,9 @@ namespace Nymph cereal::JSONOutputArchive* fArchiveOutPtr; public: - bool Configure( const scarab::param_node* node ); + bool Configure( const scarab::param_node& node ); + + void Initialize(); std::string GetFileName() const; void SetFileName( std::string file ); @@ -42,7 +46,7 @@ namespace Nymph void SetArchiveOutPtr( cereal::JSONOutputArchive archive ); template< class XDataType > - void SlotFunction( const XDataType& data ); + void SlotFunction( XDataType& data ); }; inline std::string KTSerialWriter::GetFileName() const diff --git a/Executables/Validation/TestSerialWriter.cc b/Executables/Validation/TestSerialWriter.cc new file mode 100644 index 0000000..b0046bf --- /dev/null +++ b/Executables/Validation/TestSerialWriter.cc @@ -0,0 +1,34 @@ +/* + * TestSerialWriter.cc + * + * Created on: Feb 1, 2018 + * Author: E Zayas + * +*/ + +#include "KTLogger.hh" +#include "KTSerialWriter.hh" +#include "KTTestData.hh" + +LOGGER( testlog, "TestSerialWriter" ); + +using namespace Nymph; + +int main() +{ + // Create the test data + KTTestData testData; + testData.SetIsAwesome( true ); // because it isn't by default :( + + KTINFO( testlog, "KTTestData is awesome? " << testData.GetIsAwesome() ); + + // Create the writer + KTSerialWriter writer; + writer.SetFileName( "test_serial_writer_output.json" ); + writer.Initialize(); + + writer.SlotFunction< KTTestData >( testData ); + + KTINFO( testlog, "Validation script concluded" ); + return 0; +} From ead66638b444e6ac5dc8970dc71f165df133a462 Mon Sep 17 00:00:00 2001 From: cclaessens Date: Thu, 1 Feb 2018 20:01:08 +0100 Subject: [PATCH 077/521] made KTWrapProcessor and try to bind it with pybind. status: it builds --- Executables/Validation/KTPyTestClassPybind.hh | 29 +++++++++++- Executables/Validation/KTTestProcessor.cc | 31 +++++++++++++ Executables/Validation/KTTestProcessor.hh | 44 +++++++++++++++++++ .../Validation/TestProcessorToolbox.py | 2 + 4 files changed, 105 insertions(+), 1 deletion(-) diff --git a/Executables/Validation/KTPyTestClassPybind.hh b/Executables/Validation/KTPyTestClassPybind.hh index bda9d69..718b6c0 100644 --- a/Executables/Validation/KTPyTestClassPybind.hh +++ b/Executables/Validation/KTPyTestClassPybind.hh @@ -6,6 +6,7 @@ */ #include "KTPyTestClass.hh" +#include "KTTestProcessor.hh" #include "pybind11/pybind11.h" @@ -20,6 +21,32 @@ namespace Nymph .def( "GetValue", &Nymph::KTPyTestClass::GetValue ) .def( "SetValue", &Nymph::KTPyTestClass::SetValue ) ; - } + }; + + class KTPyWrapProcessor: public KTWrapProcessor + { + public: + // Inherit the constructors + using KTWrapProcessor::KTWrapProcessor; + + // Trampoline (need one for each virtual function) + void WrapFunction(int input) override { + PYBIND11_OVERLOAD_PURE( + void, // Return type + KTWrapProcessor, // Parent class + WrapFunction, // Name of function in C++ (must match Python name) + input // Argument(s) + ); + } + }; + + PYBIND11_MODULE(pywrapper, m) { + pybind11::class_ pythonwrap(m, "PythonWrap"); + pythonwrap + .def(pybind11::init<>()) + .def("WrapFunction", &KTWrapProcessor::WrapFunction); + }; + + } /* namespace Nymph */ diff --git a/Executables/Validation/KTTestProcessor.cc b/Executables/Validation/KTTestProcessor.cc index f045160..c9521fe 100644 --- a/Executables/Validation/KTTestProcessor.cc +++ b/Executables/Validation/KTTestProcessor.cc @@ -180,4 +180,35 @@ namespace Nymph return; } + KT_REGISTER_PROCESSOR(KTWrapProcessor, "test-proc-python-wrap"); + + KTWrapProcessor::KTWrapProcessor( const std::string& name ) : + KTProcessor( name ), + fSlot("wrap-slot", this, &KTWrapProcessor::SlotFunc) + + { + } + + KTWrapProcessor::~KTWrapProcessor() + { + } + + bool KTWrapProcessor::Configure(const scarab::param_node&) + { + return true; + } + + void KTWrapProcessor::SlotFunc(int input) + { + KTINFO(testsiglog, "Calling wrap function "); + this->WrapFunction(input); + return; + } + + void KTWrapProcessor::WrapFunction(int input) + { + KTINFO(testsiglog, "Hey, I'm base class"); + return; + } + } /* namespace Nymph */ diff --git a/Executables/Validation/KTTestProcessor.hh b/Executables/Validation/KTTestProcessor.hh index 8dace64..2bc3aee 100644 --- a/Executables/Validation/KTTestProcessor.hh +++ b/Executables/Validation/KTTestProcessor.hh @@ -10,6 +10,10 @@ #include "KTProcessor.hh" #include "KTSlot.hh" +//#include "pybind11/pybind11.h" + + +//using namespace py; #include "KTTestData.hh" @@ -126,5 +130,45 @@ namespace Nymph KTSignalData fDerived2DataSignal; }; + + class KTWrapProcessor : public KTProcessor + { + public: + KTWrapProcessor( const std::string& name = "base-wrap-processor" ); + virtual ~KTWrapProcessor(); + + bool Configure(const scarab::param_node& node); + + void SlotFunc(int); + virtual void WrapFunction(int input); + + private: + KTSlot< int > fSlot; + + }; + +/* PYBIND11_MODULE(pywrapper, m) { + pybind11::class_ pythonwrap(m, "PythonWrap"); + pythonwrap + .def(py::init<>()) + .def("WrapFunction", &KTWrapProcessor::WrapFunction); + } + + class KTPyWrapProcessor: public KTWrapProcessor + { + public: + // Inherit the constructors + using KTWrapProcessor::KTWrapProcessor; + + // Trampoline (need one for each virtual function) + void WrapFunction(int input) override { + PYBIND11_OVERLOAD_PURE( + void, // Return type + KTWrapProcessor, // Parent class + WrapFunction, // Name of function in C++ (must match Python name) + input // Argument(s) + ); + } + };*/ } /* namespace Nymph */ #endif /* KTTESTPROCESSOR_HH_ */ diff --git a/Executables/Validation/TestProcessorToolbox.py b/Executables/Validation/TestProcessorToolbox.py index e2c4bb5..0538ee9 100644 --- a/Executables/Validation/TestProcessorToolbox.py +++ b/Executables/Validation/TestProcessorToolbox.py @@ -14,6 +14,8 @@ ptb.AddProcessor('test-p-proc', 'tpp') ptb.AddProcessor('test-proc-b', 'tp') ptb.MakeConnection('tpp:the-signal', 'tp:first-slot') +ptb.AddProcessor('test-proc-python-wrap', 'pw') +ptb.MakeConnection('tpp:the-signal', 'pw:wrap-slot') ptb.PushBackToRunQueue('tpp') print('Running') From 3d6c8fc36c8596f5923297794eabfeeea8f7715e Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Thu, 1 Feb 2018 11:35:08 -0800 Subject: [PATCH 078/521] Moved serial writer to json writer and fixed some things --- Executables/Validation/KTJSONReader.cc | 5 +- Executables/Validation/KTJSONReader.hh | 11 ++-- Executables/Validation/KTJSONWriter.cc | 42 +++---------- Executables/Validation/KTJSONWriter.hh | 80 +++++++++--------------- Executables/Validation/TestJSONWriter.cc | 45 +++++++++---- 5 files changed, 82 insertions(+), 101 deletions(-) diff --git a/Executables/Validation/KTJSONReader.cc b/Executables/Validation/KTJSONReader.cc index e3449ca..126bb07 100644 --- a/Executables/Validation/KTJSONReader.cc +++ b/Executables/Validation/KTJSONReader.cc @@ -14,8 +14,9 @@ namespace Nymph { - KTJSONReader::KTJSONReader() : - fFilename( "json-reader-default-file.json" ), + KTJSONReader::KTJSONReader( const std::string& name) : + KTProcessor( name ), + fFilename( "json_reader_default_file.json" ), fStreamInPtr( nullptr ), fArchiveInPtr( nullptr ) { diff --git a/Executables/Validation/KTJSONReader.hh b/Executables/Validation/KTJSONReader.hh index 6b5664b..ca6506d 100644 --- a/Executables/Validation/KTJSONReader.hh +++ b/Executables/Validation/KTJSONReader.hh @@ -24,19 +24,21 @@ namespace Nymph class KTJSONReader : public KTProcessor { public: - KTJSONReader(); + KTJSONReader( const std::string& name = "json-reader" ); virtual ~KTJSONReader(); bool Configure( const scarab::param_node& node ); MEMBERVARIABLE( std::string, Filename ); + public: + template< class XDataType > + void ReadData( XDataType& data ); + private: std::ifstream* fStreamInPtr; cereal::JSONInputArchive* fArchiveInPtr; - template< class XDataType > - void ReadData( XDataType& data ); }; template< class XDataType > @@ -49,7 +51,8 @@ namespace Nymph fArchiveInPtr = new cereal::JSONInputArchive( *fStreamInPtr ); } - *fArchiveInPtr( data ); + KTDEBUG( jsrlog_hh, "Reading an object from JSON" ); + (*fArchiveInPtr)( data ); return; } diff --git a/Executables/Validation/KTJSONWriter.cc b/Executables/Validation/KTJSONWriter.cc index 638fe49..23bac0a 100644 --- a/Executables/Validation/KTJSONWriter.cc +++ b/Executables/Validation/KTJSONWriter.cc @@ -1,60 +1,38 @@ /* - * KTSerialWriter.cc + * KTJSONWriter.cc * * Created on: Feb 1, 2018 * Author: E Zayas * */ -#include "KTSerialWriter.hh" - +#include "KTJSONWriter.hh" #include "KTLogger.hh" -LOGGER( avlog_hh, "KTSerialWriter" ); namespace Nymph { - KTSerialWriter::KTSerialWriter( const std::string& name ) : + KTJSONWriter::KTJSONWriter( const std::string& name ) : KTProcessor( name ), - fFileName( "placeholder.json" ), + fFilename( "json_writer_default_file.json" ), fStreamOutPtr( nullptr ), fArchiveOutPtr( nullptr ) { // Register slots here - RegisterSlot( "test-data", this, &KTSerialWriter::SlotFunction< KTTestData > ); + RegisterSlot( "test-data", this, &KTJSONWriter::WriteData< KTTestData > ); } - KTSerialWriter::~KTSerialWriter() + KTJSONWriter::~KTJSONWriter() { - //delete fStreamOutPtr; - //delete fArchiveOutPtr; + delete fStreamOutPtr; + delete fArchiveOutPtr; } - bool KTSerialWriter::Configure( const scarab::param_node& node ) + bool KTJSONWriter::Configure( const scarab::param_node& node ) { - SetFileName( node.get_value< std::string >( "file-name", fFileName ) ); - Initialize(); + SetFilename( node.get_value( "file-name", fFilename ) ); return true; } - void KTSerialWriter::Initialize() - { - *fStreamOutPtr = std::ofstream( fFileName ); - cereal::JSONOutputArchive fStupid( *fStreamOutPtr ); - fArchiveOutPtr = &fStupid; - - return; - } - - template< class XDataType > - void KTSerialWriter::SlotFunction( XDataType& data ) - { - // Write to JSON archive - KTINFO( avlog_hh, "Writing data to JSON acrhive" ); - (*fArchiveOutPtr)( data ); - - KTINFO( avlog_hh, "Successfully wrote data to archive" ); - return; - } } diff --git a/Executables/Validation/KTJSONWriter.hh b/Executables/Validation/KTJSONWriter.hh index 165acc1..6dad8e9 100644 --- a/Executables/Validation/KTJSONWriter.hh +++ b/Executables/Validation/KTJSONWriter.hh @@ -1,13 +1,13 @@ /* - * KTSerialWriter.hh + * KTJSONWriter.hh * * Created on: Feb 1, 2018 * Author: E Zayas * */ -#ifndef KTSERIALWRITER_HH_ -#define KTSERIALWRITER_HH_ +#ifndef KTJSONWRITER_HH_ +#define KTJSONWRITER_HH_ #include "KTData.hh" #include "KTProcessor.hh" @@ -15,73 +15,53 @@ #include "KTTestData.hh" +#include "KTLogger.hh" + #include "cereal/archives/json.hpp" + #include +KTLOGGER( avlog_hh, "KTJSONWriter" ); + namespace Nymph { - class KTSerialWriter : public KTProcessor + class KTJSONWriter : public KTProcessor { public: - KTSerialWriter( const std::string& name = "serial-writer" ); - virtual ~KTSerialWriter(); - - private: - std::string fFileName; - std::ofstream* fStreamOutPtr; - cereal::JSONOutputArchive* fArchiveOutPtr; + KTJSONWriter( const std::string& name = "serial-writer" ); + virtual ~KTJSONWriter(); - public: bool Configure( const scarab::param_node& node ); - void Initialize(); - - std::string GetFileName() const; - void SetFileName( std::string file ); - - std::ofstream* GetStreamOutPtr() const; - void SetStreamOutPtr( std::ofstream stream ); - - cereal::JSONOutputArchive* GetArchiveOutPtr() const; - void SetArchiveOutPtr( cereal::JSONOutputArchive archive ); + MEMBERVARIABLE( std::string, Filename ); + public: template< class XDataType > - void SlotFunction( XDataType& data ); - }; - - inline std::string KTSerialWriter::GetFileName() const - { - return fFileName; - } + void WriteData( XDataType& data ); - inline void KTSerialWriter::SetFileName( std::string file ) - { - fFileName = file; - return; - } + private: + std::ofstream* fStreamOutPtr; + cereal::JSONOutputArchive* fArchiveOutPtr; - inline std::ofstream* KTSerialWriter::GetStreamOutPtr() const - { - return fStreamOutPtr; - } + }; - inline void KTSerialWriter::SetStreamOutPtr( std::ofstream stream ) + template< class XDataType > + void KTJSONWriter::WriteData( XDataType& data ) { - fStreamOutPtr = &stream; - return; - } + if( fStreamOutPtr == nullptr ) + { + fStreamOutPtr = new std::ofstream( fFilename ); + fArchiveOutPtr = new cereal::JSONOutputArchive( *fStreamOutPtr ); + } - inline cereal::JSONOutputArchive* KTSerialWriter::GetArchiveOutPtr() const - { - return fArchiveOutPtr; - } + // Write to JSON archive + KTINFO( avlog_hh, "Writing data to JSON acrhive" ); + (*fArchiveOutPtr)( data ); - inline void KTSerialWriter::SetArchiveOutPtr( cereal::JSONOutputArchive archive ) - { - fArchiveOutPtr = &archive; + KTINFO( avlog_hh, "Successfully wrote data to archive" ); return; } } // namespace Nymph -#endif // KTSERIALWRITER_HH_ +#endif // KTJSONWRITER_HH_ diff --git a/Executables/Validation/TestJSONWriter.cc b/Executables/Validation/TestJSONWriter.cc index b0046bf..c6320f0 100644 --- a/Executables/Validation/TestJSONWriter.cc +++ b/Executables/Validation/TestJSONWriter.cc @@ -6,29 +6,48 @@ * */ -#include "KTLogger.hh" -#include "KTSerialWriter.hh" +#include "KTJSONWriter.hh" +#include "KTJSONReader.hh" + #include "KTTestData.hh" -LOGGER( testlog, "TestSerialWriter" ); +KTLOGGER( testlog, "TestJSONWriter" ); using namespace Nymph; int main() { - // Create the test data - KTTestData testData; - testData.SetIsAwesome( true ); // because it isn't by default :( + std::string filename( "test_json_writer_output.json" ); + + { + // Create the test data + KTTestData testData; + testData.SetIsAwesome( true ); // because it isn't by default :( + + KTINFO( testlog, "KTTestData is awesome? " << testData.GetIsAwesome() ); + + // Create the writer + KTJSONWriter writer; + writer.SetFilename( filename ); + + KTINFO( testlog, "Writing data" ); + + writer.WriteData< KTTestData >( testData ); + + // destruction of the stream and archive (in the writer's destructor) properly closes the file + } + + { + KTTestData newTestData; - KTINFO( testlog, "KTTestData is awesome? " << testData.GetIsAwesome() ); + KTJSONReader reader; + reader.SetFilename( filename ); - // Create the writer - KTSerialWriter writer; - writer.SetFileName( "test_serial_writer_output.json" ); - writer.Initialize(); + reader.ReadData< KTTestData >( newTestData ); - writer.SlotFunction< KTTestData >( testData ); + KTINFO( testlog, "Is the read data awesome? " << newTestData.GetIsAwesome() ); + } - KTINFO( testlog, "Validation script concluded" ); + KTINFO( testlog, "Validation script concluded" ); return 0; } From faf7f646f5947f5e1a6ac7552b51d936d98608f9 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Thu, 1 Feb 2018 11:37:37 -0800 Subject: [PATCH 079/521] Correct deletion order --- Executables/Validation/KTJSONReader.cc | 1 + Executables/Validation/KTJSONWriter.cc | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Executables/Validation/KTJSONReader.cc b/Executables/Validation/KTJSONReader.cc index 126bb07..2da348b 100644 --- a/Executables/Validation/KTJSONReader.cc +++ b/Executables/Validation/KTJSONReader.cc @@ -24,6 +24,7 @@ namespace Nymph KTJSONReader::~KTJSONReader() { + // archive must be delete before the stream! delete fArchiveInPtr; delete fStreamInPtr; } diff --git a/Executables/Validation/KTJSONWriter.cc b/Executables/Validation/KTJSONWriter.cc index 23bac0a..7272c49 100644 --- a/Executables/Validation/KTJSONWriter.cc +++ b/Executables/Validation/KTJSONWriter.cc @@ -24,8 +24,9 @@ namespace Nymph KTJSONWriter::~KTJSONWriter() { - delete fStreamOutPtr; + // archive must be delete before the stream! delete fArchiveOutPtr; + delete fStreamOutPtr; } bool KTJSONWriter::Configure( const scarab::param_node& node ) From 41796a16491ee384213333f44193ee378a13d71c Mon Sep 17 00:00:00 2001 From: cclaessens Date: Thu, 1 Feb 2018 20:59:18 +0100 Subject: [PATCH 080/521] made the new processor part of the py_nymph_validation module --- Executables/Validation/KTPyTestClassPybind.hh | 8 ------- Executables/Validation/KTTestProcessor.hh | 23 ------------------- .../Validation/NymphValidationPybind.cc | 7 +++++- .../Validation/TestProcessorToolbox.py | 2 -- Executables/Validation/TestWrapProcessor.py | 9 ++++++++ 5 files changed, 15 insertions(+), 34 deletions(-) create mode 100644 Executables/Validation/TestWrapProcessor.py diff --git a/Executables/Validation/KTPyTestClassPybind.hh b/Executables/Validation/KTPyTestClassPybind.hh index 718b6c0..6057a0e 100644 --- a/Executables/Validation/KTPyTestClassPybind.hh +++ b/Executables/Validation/KTPyTestClassPybind.hh @@ -40,13 +40,5 @@ namespace Nymph } }; - PYBIND11_MODULE(pywrapper, m) { - pybind11::class_ pythonwrap(m, "PythonWrap"); - pythonwrap - .def(pybind11::init<>()) - .def("WrapFunction", &KTWrapProcessor::WrapFunction); - }; - - } /* namespace Nymph */ diff --git a/Executables/Validation/KTTestProcessor.hh b/Executables/Validation/KTTestProcessor.hh index 2bc3aee..e6108f1 100644 --- a/Executables/Validation/KTTestProcessor.hh +++ b/Executables/Validation/KTTestProcessor.hh @@ -147,28 +147,5 @@ namespace Nymph }; -/* PYBIND11_MODULE(pywrapper, m) { - pybind11::class_ pythonwrap(m, "PythonWrap"); - pythonwrap - .def(py::init<>()) - .def("WrapFunction", &KTWrapProcessor::WrapFunction); - } - - class KTPyWrapProcessor: public KTWrapProcessor - { - public: - // Inherit the constructors - using KTWrapProcessor::KTWrapProcessor; - - // Trampoline (need one for each virtual function) - void WrapFunction(int input) override { - PYBIND11_OVERLOAD_PURE( - void, // Return type - KTWrapProcessor, // Parent class - WrapFunction, // Name of function in C++ (must match Python name) - input // Argument(s) - ); - } - };*/ } /* namespace Nymph */ #endif /* KTTESTPROCESSOR_HH_ */ diff --git a/Executables/Validation/NymphValidationPybind.cc b/Executables/Validation/NymphValidationPybind.cc index 0f2bad2..60cc171 100644 --- a/Executables/Validation/NymphValidationPybind.cc +++ b/Executables/Validation/NymphValidationPybind.cc @@ -7,12 +7,17 @@ #include "KTPyTestClassPybind.hh" #include "TestPythonBasics.hh" +#include "pybind11/pybind11.h" PYBIND11_MODULE( py_nymph_validation, mod ) { Nymph::ExportKTPyTestClass( mod ); Nymph::ExportTestPythonBasics( mod ); -} + pybind11::class_ wrap_processor(mod, "WrapProcessor"); + wrap_processor + .def(pybind11::init<>()) + .def("WrapFunction", &Nymph::KTWrapProcessor::WrapFunction); +} diff --git a/Executables/Validation/TestProcessorToolbox.py b/Executables/Validation/TestProcessorToolbox.py index 0538ee9..e2c4bb5 100644 --- a/Executables/Validation/TestProcessorToolbox.py +++ b/Executables/Validation/TestProcessorToolbox.py @@ -14,8 +14,6 @@ ptb.AddProcessor('test-p-proc', 'tpp') ptb.AddProcessor('test-proc-b', 'tp') ptb.MakeConnection('tpp:the-signal', 'tp:first-slot') -ptb.AddProcessor('test-proc-python-wrap', 'pw') -ptb.MakeConnection('tpp:the-signal', 'pw:wrap-slot') ptb.PushBackToRunQueue('tpp') print('Running') diff --git a/Executables/Validation/TestWrapProcessor.py b/Executables/Validation/TestWrapProcessor.py new file mode 100644 index 0000000..81a6d22 --- /dev/null +++ b/Executables/Validation/TestWrapProcessor.py @@ -0,0 +1,9 @@ +# TestWrapProcessor.py +# Created on: Feb 1, 2018 +# Author: C. Claessens +# +# Tests the ability to overwrite processor functions + +import py_nymph as nymph +import py_nymph_validation as nv +print(dir(nv)) \ No newline at end of file From d974b7b751c6f4dad1af07589caeb575e7d8a608 Mon Sep 17 00:00:00 2001 From: cclaessens Date: Thu, 1 Feb 2018 22:01:40 +0100 Subject: [PATCH 081/521] Configure of KTWrapProcessor is overwritable in python, but still has a default implementation. --- Executables/Validation/KTPyTestClassPybind.hh | 10 ++++++- Executables/Validation/KTTestProcessor.cc | 2 +- Executables/Validation/KTTestProcessor.hh | 2 +- .../Validation/NymphValidationPybind.cc | 3 +- .../Validation/TestProcessorToolbox.py | 15 +++++++++- Executables/Validation/TestWrapProcessor.py | 29 ++++++++++++++++++- 6 files changed, 55 insertions(+), 6 deletions(-) diff --git a/Executables/Validation/KTPyTestClassPybind.hh b/Executables/Validation/KTPyTestClassPybind.hh index 6057a0e..db3e5b6 100644 --- a/Executables/Validation/KTPyTestClassPybind.hh +++ b/Executables/Validation/KTPyTestClassPybind.hh @@ -37,7 +37,15 @@ namespace Nymph WrapFunction, // Name of function in C++ (must match Python name) input // Argument(s) ); - } + } + bool Configure(const scarab::param_node& node) override { + PYBIND11_OVERLOAD( + bool, // Return type + KTWrapProcessor, // Parent class + Configure, // Name of function in C++ (must match Python name) + node // Argument(s) + ); + } }; diff --git a/Executables/Validation/KTTestProcessor.cc b/Executables/Validation/KTTestProcessor.cc index c9521fe..65bccd0 100644 --- a/Executables/Validation/KTTestProcessor.cc +++ b/Executables/Validation/KTTestProcessor.cc @@ -180,7 +180,7 @@ namespace Nymph return; } - KT_REGISTER_PROCESSOR(KTWrapProcessor, "test-proc-python-wrap"); + KT_REGISTER_PROCESSOR(KTWrapProcessor, "base-wrap-proc"); KTWrapProcessor::KTWrapProcessor( const std::string& name ) : KTProcessor( name ), diff --git a/Executables/Validation/KTTestProcessor.hh b/Executables/Validation/KTTestProcessor.hh index e6108f1..4ba76d5 100644 --- a/Executables/Validation/KTTestProcessor.hh +++ b/Executables/Validation/KTTestProcessor.hh @@ -134,7 +134,7 @@ namespace Nymph class KTWrapProcessor : public KTProcessor { public: - KTWrapProcessor( const std::string& name = "base-wrap-processor" ); + KTWrapProcessor( const std::string& name = "base-wrap-proc" ); virtual ~KTWrapProcessor(); bool Configure(const scarab::param_node& node); diff --git a/Executables/Validation/NymphValidationPybind.cc b/Executables/Validation/NymphValidationPybind.cc index 60cc171..657eb48 100644 --- a/Executables/Validation/NymphValidationPybind.cc +++ b/Executables/Validation/NymphValidationPybind.cc @@ -17,7 +17,8 @@ PYBIND11_MODULE( py_nymph_validation, mod ) pybind11::class_ wrap_processor(mod, "WrapProcessor"); wrap_processor .def(pybind11::init<>()) - .def("WrapFunction", &Nymph::KTWrapProcessor::WrapFunction); + .def("WrapFunction", &Nymph::KTWrapProcessor::WrapFunction) + .def("Configure", &Nymph::KTWrapProcessor::Configure); } diff --git a/Executables/Validation/TestProcessorToolbox.py b/Executables/Validation/TestProcessorToolbox.py index e2c4bb5..31868de 100644 --- a/Executables/Validation/TestProcessorToolbox.py +++ b/Executables/Validation/TestProcessorToolbox.py @@ -7,13 +7,26 @@ import py_nymph as nymph import py_nymph_validation as nv +class WrappedProcessor(nv.WrapProcessor): + pass + ptb = nymph.KTProcessorToolbox('pt') print('Configuring') ptb.AddProcessor('test-p-proc', 'tpp') ptb.AddProcessor('test-proc-b', 'tp') -ptb.MakeConnection('tpp:the-signal', 'tp:first-slot') +ptb.AddProcessor('base-wrap-proc', 'bwp') + + + +#ptb.MakeConnection('tpp:the-signal', 'tp:first-slot') +#ptb.MakeConnection('tpp:the-signal', 'tp:first-slot') +ptb.MakeConnection('tpp:the-signal', 'bwp:wrap-slot') + +p = WrappedProcessor() +p.WrapFunction = lambda x: print("Hey, I'm python") + ptb.PushBackToRunQueue('tpp') print('Running') diff --git a/Executables/Validation/TestWrapProcessor.py b/Executables/Validation/TestWrapProcessor.py index 81a6d22..82e1778 100644 --- a/Executables/Validation/TestWrapProcessor.py +++ b/Executables/Validation/TestWrapProcessor.py @@ -6,4 +6,31 @@ import py_nymph as nymph import py_nymph_validation as nv -print(dir(nv)) \ No newline at end of file + +class WrappedProcessor(nv.WrapProcessor): + pass + +ptb = nymph.KTProcessorToolbox('pt') + +print('Configuring') + +ptb.AddProcessor('test-p-proc', 'tpp') +ptb.AddProcessor('test-proc-b', 'tp') +ptb.AddProcessor('base-wrap-proc', 'bwp') + + + +#ptb.MakeConnection('tpp:the-signal', 'tp:first-slot') +#ptb.MakeConnection('tpp:the-signal', 'tp:first-slot') +ptb.MakeConnection('tpp:the-signal', 'bwp:wrap-slot') + +p = WrappedProcessor() +p.WrapFunction = lambda x: print("Hey, I'm python") + +ptb.PushBackToRunQueue('tpp') + +print('Running') + +ptb.Run() + +print('All done') \ No newline at end of file From 2b99fc9a3d0340087950c1a4ebda6b6a749d6471 Mon Sep 17 00:00:00 2001 From: Evan Zayas Date: Thu, 1 Feb 2018 16:20:13 -0500 Subject: [PATCH 082/521] I did something idk --- Library/Data/KTData.hh | 18 +++++++++--------- Library/Utility/KTExtensibleStruct.hh | 20 ++++++++++++++++++++ 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/Library/Data/KTData.hh b/Library/Data/KTData.hh index f1aa67d..d15673f 100644 --- a/Library/Data/KTData.hh +++ b/Library/Data/KTData.hh @@ -41,19 +41,19 @@ namespace Nymph virtual ~KTDataRider(); MEMBERVARIABLE_REF( std::string, Name ); -/* - private: - friend class cereal::access; + private: template< class Archive > - void serialize( Archive& ar ) - { - std::cout << "### serialize for KTDataRider" << std::endl; - ar( fName ); - } -*/ + void serialize( Archive& ar ); }; + template< class Archive > + void KTDataRider::serialize( Archive& ar ) + { + std::cout << "### serialize for KTDataRider" << std::endl; + ar( fName ); + } + template< class XDerivedType > class KTExtensibleDataRider : public KTExtensibleStruct< XDerivedType, KTDataRider > { diff --git a/Library/Utility/KTExtensibleStruct.hh b/Library/Utility/KTExtensibleStruct.hh index 557f83d..4fc78e4 100644 --- a/Library/Utility/KTExtensibleStruct.hh +++ b/Library/Utility/KTExtensibleStruct.hh @@ -9,6 +9,8 @@ #ifndef KTEXTENSIBLESTRUCT_HH_ #define KTEXTENSIBLESTRUCT_HH_ +#include + namespace Nymph { @@ -55,6 +57,12 @@ namespace Nymph void SetPrevPtrInNext(); mutable KTExtensibleStructCore* fNext; mutable KTExtensibleStructCore* fPrev; + + private: + friend class cereal::access; + + template< class Archive > + void serialize( Archive& ar ); }; @@ -231,6 +239,18 @@ namespace Nymph return; } + template< class XBaseType > + template< class Archive > + void KTExtensibleStructCore::serialize( Archive& ar ) + { + std::cout << "### serialize for " << typeid(XBaseType).name() << std::endl; + ar( this ); + + if( fNext == 0 ){ return; } + + // archive pointer ( fNext )? + } + template From 6f7f1c5c51e445294544a76b8fa463cfa90d2dfc Mon Sep 17 00:00:00 2001 From: Evan Zayas Date: Thu, 1 Feb 2018 16:47:54 -0500 Subject: [PATCH 083/521] hmmm --- Library/Data/KTData.hh | 2 ++ Library/Utility/KTExtensibleStruct.hh | 13 +++++++++++++ 2 files changed, 15 insertions(+) diff --git a/Library/Data/KTData.hh b/Library/Data/KTData.hh index d15673f..330e840 100644 --- a/Library/Data/KTData.hh +++ b/Library/Data/KTData.hh @@ -43,6 +43,8 @@ namespace Nymph MEMBERVARIABLE_REF( std::string, Name ); private: + friend class cereal::access; + template< class Archive > void serialize( Archive& ar ); }; diff --git a/Library/Utility/KTExtensibleStruct.hh b/Library/Utility/KTExtensibleStruct.hh index 4fc78e4..fae2704 100644 --- a/Library/Utility/KTExtensibleStruct.hh +++ b/Library/Utility/KTExtensibleStruct.hh @@ -85,6 +85,9 @@ namespace Nymph void SetIsCopyDisabled(bool flag); private: bool fIsCopyDisabled; + + template< class Archive > + void serialize( Archive& ar ); }; @@ -253,6 +256,16 @@ namespace Nymph + template< class XInstanceType, class XBaseType > + template< class Archive > + void KTExtensibleStruct::serialize( Archive& ar ) + { + std::cout << "### serialize for " << typeid(XBaseType).name() << std::endl; + ar( cereal::base_class< KTExtensibleStructCore< XBaseType > >( this ), fIsCopyDisabled ); + + return; + } + template KTExtensibleStruct::KTExtensibleStruct(void) { From 0d10512a2b7844baabab1b11d8a0ea89a780cc20 Mon Sep 17 00:00:00 2001 From: cclaessens Date: Thu, 1 Feb 2018 22:50:02 +0100 Subject: [PATCH 084/521] swapped KTProcessor* by std::shared_ptr< KTProcessor > in KTProcessorToolbox --- Library/Application/KTProcessorToolbox.cc | 42 +++++++++++------------ Library/Application/KTProcessorToolbox.hh | 11 +++--- Library/Processor/KTProcessor.hh | 1 + 3 files changed, 28 insertions(+), 26 deletions(-) diff --git a/Library/Application/KTProcessorToolbox.cc b/Library/Application/KTProcessorToolbox.cc index 2d94c57..f1589a3 100644 --- a/Library/Application/KTProcessorToolbox.cc +++ b/Library/Application/KTProcessorToolbox.cc @@ -91,7 +91,7 @@ namespace Nymph { procName = procNode->get_value("name"); } - KTProcessor* newProc = fProcFactory->create(procType, procType); + std::shared_ptr< KTProcessor > newProc ( fProcFactory->create(procType, procType)); if (newProc == NULL) { KTERROR(proclog, "Unable to create processor of type <" << procType << ">"); @@ -101,7 +101,7 @@ namespace Nymph if (! AddProcessor(procName, newProc)) { KTERROR(proclog, "Unable to add processor <" << procName << ">"); - delete newProc; + //delete newProc; //not required for smart pointers return false; } } @@ -265,7 +265,7 @@ namespace Nymph return ConfigureProcessors( translator.read_string( config, &optNode )->as_node() ); } - KTProcessor* KTProcessorToolbox::GetProcessor(const std::string& procName) + std::shared_ptr< KTProcessor > KTProcessorToolbox::GetProcessor(const std::string& procName) { ProcMapIt it = fProcMap.find(procName); if (it == fProcMap.end()) @@ -276,7 +276,7 @@ namespace Nymph return it->second.fProc; } - const KTProcessor* KTProcessorToolbox::GetProcessor(const std::string& procName) const + const std::shared_ptr< KTProcessor > KTProcessorToolbox::GetProcessor(const std::string& procName) const { ProcMapCIt it = fProcMap.find(procName); if (it == fProcMap.end()) @@ -287,7 +287,7 @@ namespace Nymph return it->second.fProc; } - bool KTProcessorToolbox::AddProcessor(const std::string& procName, KTProcessor* proc) + bool KTProcessorToolbox::AddProcessor(const std::string& procName, std::shared_ptr< KTProcessor > proc) { ProcMapIt it = fProcMap.find(procName); if (it == fProcMap.end()) @@ -307,7 +307,7 @@ namespace Nymph ProcMapIt it = fProcMap.find(procName); if (it == fProcMap.end()) { - KTProcessor* newProc = fProcFactory->create(procType, procType); + std::shared_ptr< KTProcessor > newProc ( fProcFactory->create(procType, procType)); if (newProc == NULL) { KTERROR(proclog, "Unable to create processor of type <" << procType << ">"); @@ -316,7 +316,7 @@ namespace Nymph if (! AddProcessor(procName, newProc)) { KTERROR(proclog, "Unable to add processor <" << procName << ">"); - delete newProc; + //delete newProc; return false; } return true; @@ -327,17 +327,17 @@ namespace Nymph bool KTProcessorToolbox::RemoveProcessor(const std::string& procName) { - KTProcessor* procToRemove = ReleaseProcessor(procName); + std::shared_ptr< KTProcessor > procToRemove = ReleaseProcessor(procName); if (procToRemove == NULL) { return false; } - delete procToRemove; + //delete procToRemove; KTDEBUG(proclog, "Processor <" << procName << "> deleted."); return true; } - KTProcessor* KTProcessorToolbox::ReleaseProcessor(const std::string& procName) + std::shared_ptr< KTProcessor > KTProcessorToolbox::ReleaseProcessor(const std::string& procName) { ProcMapIt it = fProcMap.find(procName); if (it == fProcMap.end()) @@ -345,17 +345,17 @@ namespace Nymph KTWARN(proclog, "Processor <" << procName << "> was not found."); return NULL; } - KTProcessor* procToRelease = it->second.fProc; + std::shared_ptr< KTProcessor > procToRelease = it->second.fProc; fProcMap.erase(it); return procToRelease; } void KTProcessorToolbox::ClearProcessors() { - for (ProcMapIt it = fProcMap.begin(); it != fProcMap.end(); it++) + /*for (ProcMapIt it = fProcMap.begin(); it != fProcMap.end(); it++) { delete it->second.fProc; - } + }*/ //not required for smart pointers fProcMap.clear(); fRunQueue.clear(); return; @@ -383,14 +383,14 @@ namespace Nymph bool KTProcessorToolbox::MakeConnection(const std::string& signalProcName, const std::string& signalName, const std::string& slotProcName, const std::string& slotName, int order) { - KTProcessor* signalProc = GetProcessor(signalProcName); + std::shared_ptr< KTProcessor > signalProc = GetProcessor(signalProcName); if (signalProc == NULL) { KTERROR(proclog, "Processor named <" << signalProcName << "> was not found!"); return false; } - KTProcessor* slotProc = GetProcessor(slotProcName); + std::shared_ptr< KTProcessor > slotProc = GetProcessor(slotProcName); if (slotProc == NULL) { KTERROR(proclog, "Processor named <" << slotProcName << "> was not found!"); @@ -401,11 +401,11 @@ namespace Nymph { if (order != std::numeric_limits< int >::min()) { - signalProc->ConnectASlot(signalName, slotProc, slotName, order); + signalProc->ConnectASlot(signalName, slotProc.get(), slotName, order); } else { - signalProc->ConnectASlot(signalName, slotProc, slotName); + signalProc->ConnectASlot(signalName, slotProc.get(), slotName); } } catch (boost::exception& e) @@ -434,7 +434,7 @@ namespace Nymph bool KTProcessorToolbox::SetBreakpoint(const std::string& slotProcName, const std::string& slotName) { - KTProcessor* slotProc = GetProcessor(slotProcName); + std::shared_ptr< KTProcessor > slotProc = GetProcessor(slotProcName); if (slotProc == NULL) { KTERROR(proclog, "Processor named <" << slotProcName << "> was not found!"); @@ -467,7 +467,7 @@ namespace Nymph bool KTProcessorToolbox::RemoveBreakpoint(const std::string& slotProcName, const std::string& slotName) { - KTProcessor* slotProc = GetProcessor(slotProcName); + std::shared_ptr< KTProcessor > slotProc = GetProcessor(slotProcName); if (slotProc == NULL) { KTERROR(proclog, "Processor named <" << slotProcName << "> was not found!"); @@ -545,7 +545,7 @@ namespace Nymph bool KTProcessorToolbox::AddProcessorToThreadGroup(const std::string& name, ThreadGroup& group) { - KTProcessor* procForRunQueue = GetProcessor(name); + std::shared_ptr< KTProcessor > procForRunQueue = GetProcessor(name); KTDEBUG(proclog, "Attempting to add processor <" << name << "> to the run queue"); if (procForRunQueue == NULL) { @@ -553,7 +553,7 @@ namespace Nymph return false; } - KTPrimaryProcessor* primaryProc = dynamic_cast< KTPrimaryProcessor* >(procForRunQueue); + KTPrimaryProcessor* primaryProc = dynamic_cast< KTPrimaryProcessor* >(procForRunQueue.get()); if (primaryProc == NULL) { KTERROR(proclog, "Processor <" << name << "> is not a primary processor."); diff --git a/Library/Application/KTProcessorToolbox.hh b/Library/Application/KTProcessorToolbox.hh index 42d97fd..829e3f6 100644 --- a/Library/Application/KTProcessorToolbox.hh +++ b/Library/Application/KTProcessorToolbox.hh @@ -28,6 +28,7 @@ #include #include #include +#include namespace Nymph @@ -110,7 +111,7 @@ namespace Nymph private: struct ProcessorInfo { - KTProcessor* fProc; + std::shared_ptr< KTProcessor > fProc; }; typedef std::map< std::string, ProcessorInfo > ProcessorMap; typedef ProcessorMap::iterator ProcMapIt; @@ -119,13 +120,13 @@ namespace Nymph public: /// Get a pointer to a processor in the toolbox - KTProcessor* GetProcessor(const std::string& procName); + std::shared_ptr< KTProcessor > GetProcessor(const std::string& procName); /// Get a pointer to a processor in the toolbox - const KTProcessor* GetProcessor(const std::string& procName) const; + const std::shared_ptr< KTProcessor > GetProcessor(const std::string& procName) const; /// Add a processor to the toolbox /// Toolbox takes ownership of the processor - bool AddProcessor(const std::string& procName, KTProcessor* proc); + bool AddProcessor(const std::string& procName, std::shared_ptr< KTProcessor > proc); bool AddProcessor(const std::string& procType, const std::string& procName); /// Remove a processor from the toolbox @@ -133,7 +134,7 @@ namespace Nymph /// Remove a processor from the toolbox and return it to the user /// Ownership is passed to the user - KTProcessor* ReleaseProcessor(const std::string& procName); + std::shared_ptr< KTProcessor > ReleaseProcessor(const std::string& procName); /// Remove all processors from the toolbox /// Also clears the run queue diff --git a/Library/Processor/KTProcessor.hh b/Library/Processor/KTProcessor.hh index 6b04e3b..c2e143a 100644 --- a/Library/Processor/KTProcessor.hh +++ b/Library/Processor/KTProcessor.hh @@ -25,6 +25,7 @@ #include #include #include +#include namespace Nymph { From 03472de74ba69e0cf5e486f62f587ee7bd69106a Mon Sep 17 00:00:00 2001 From: Evan Zayas Date: Thu, 1 Feb 2018 16:52:42 -0500 Subject: [PATCH 085/521] made a new friend --- Library/Utility/KTExtensibleStruct.hh | 1 + 1 file changed, 1 insertion(+) diff --git a/Library/Utility/KTExtensibleStruct.hh b/Library/Utility/KTExtensibleStruct.hh index fae2704..5eaaf81 100644 --- a/Library/Utility/KTExtensibleStruct.hh +++ b/Library/Utility/KTExtensibleStruct.hh @@ -85,6 +85,7 @@ namespace Nymph void SetIsCopyDisabled(bool flag); private: bool fIsCopyDisabled; + friend class cereal::access; template< class Archive > void serialize( Archive& ar ); From 5fa37739310e3885940151839b864fc0561760bc Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Thu, 1 Feb 2018 14:23:57 -0800 Subject: [PATCH 086/521] Some incomplete work on extending serialization into the extensible structs --- Library/Data/KTCutStatus.cc | 8 +-- Library/Data/KTCutStatus.hh | 30 +++++------ Library/Utility/KTExtensibleStruct.hh | 72 +++++++++++++-------------- 3 files changed, 56 insertions(+), 54 deletions(-) diff --git a/Library/Data/KTCutStatus.cc b/Library/Data/KTCutStatus.cc index 788eed7..ee371bd 100644 --- a/Library/Data/KTCutStatus.cc +++ b/Library/Data/KTCutStatus.cc @@ -102,7 +102,7 @@ namespace Nymph return cut->GetState(); } - const KTCutResult* KTCutStatus::GetCutResult(const std::string& cutName) const + const KTCutResult& KTCutStatus::GetCutResult(const std::string& cutName) const { const KTCutResult* cut = fCutResults.get()->Next(); // skip over KTCutResultHandle while (cut != NULL) @@ -110,10 +110,10 @@ namespace Nymph if (cut->Name() == cutName) return cut; cut = cut->Next(); } - return NULL; + throw KTException() << "Cannot find cut result"; } - KTCutResult* KTCutStatus::GetCutResult(const std::string& cutName) + KTCutResult& KTCutStatus::GetCutResult(const std::string& cutName) { KTCutResult* cut = fCutResults.get()->Next(); // skip over KTCutResultHandle while (cut != NULL) @@ -121,7 +121,7 @@ namespace Nymph if (cut->Name() == cutName) return cut; cut = cut->Next(); } - return NULL; + throw KTException() << "Cannot find cut result"; } bool KTCutStatus::SetCutState(const std::string& cutName, bool state, bool doUpdateStatus) diff --git a/Library/Data/KTCutStatus.hh b/Library/Data/KTCutStatus.hh index 9642575..80bb33d 100644 --- a/Library/Data/KTCutStatus.hh +++ b/Library/Data/KTCutStatus.hh @@ -11,9 +11,11 @@ #include "KTCutResult.hh" +#include "KTException.hh" + #include -#include +#include #include namespace Nymph @@ -75,7 +77,7 @@ namespace Nymph KTCutStatus& operator=(const KTCutStatus& rhs); - const KTCutResult* CutResults() const; + const std::shared_ptr< KTCutResult > CutResults() const; void UpdateStatus(); @@ -96,12 +98,12 @@ namespace Nymph bool GetCutState(const std::string& cutName) const; template< typename XCutType > - const KTCutResult* GetCutResult() const; - const KTCutResult* GetCutResult(const std::string& cutName) const; + const KTCutResult& GetCutResult() const; + const KTCutResult& GetCutResult(const std::string& cutName) const; template< typename XCutType > - KTCutResult* GetCutResult(); - KTCutResult* GetCutResult(const std::string& cutName); + KTCutResult& GetCutResult(); + KTCutResult& GetCutResult(const std::string& cutName); template< typename XCutType > bool SetCutState(bool state, bool doUpdateStatus=true); @@ -119,7 +121,7 @@ namespace Nymph private: friend std::ostream& operator<<(std::ostream& out, const KTCutStatus& status); - boost::scoped_ptr< KTCutResultHandle > fCutResults; + std::unique_ptr< KTCutResultHandle > fCutResults; bitset_type fSummary; @@ -137,7 +139,7 @@ namespace Nymph std::ostream& operator<<(std::ostream& out, const KTCutStatus& status); - inline const KTCutResult* KTCutStatus::CutResults() const + inline const std::shared_ptr< KTCutResult > KTCutStatus::CutResults() const { return fCutResults.get()->Next(); } @@ -188,23 +190,23 @@ namespace Nymph } template< typename XCutType > - const KTCutResult* KTCutStatus::GetCutResult() const + const KTCutResult& KTCutStatus::GetCutResult() const { if (HasCutResult< XCutType >()) { - return &(fCutResults.get()->Of< XCutType >()); + return fCutResults.get()->Of< XCutType >(); } - return NULL; + throw KTException() << "Cannot find cut result"; } template< typename XCutType > - KTCutResult* KTCutStatus::GetCutResult() + KTCutResult& KTCutStatus::GetCutResult() { if (HasCutResult< XCutType >()) { - return &(fCutResults.get()->Of< XCutType >()); + return fCutResults.get()->Of< XCutType >(); } - return NULL; + throw KTException() << "Cannot find cut result"; } template< typename XCutType > diff --git a/Library/Utility/KTExtensibleStruct.hh b/Library/Utility/KTExtensibleStruct.hh index fae2704..f74a5ea 100644 --- a/Library/Utility/KTExtensibleStruct.hh +++ b/Library/Utility/KTExtensibleStruct.hh @@ -11,6 +11,8 @@ #include +#include + namespace Nymph { @@ -42,21 +44,21 @@ namespace Nymph /// Extracts object of type XStructType template< class XStructType > inline XStructType* Detatch(void); /// Duplicates the extended object - virtual KTExtensibleStructCore* Clone(void) const = 0; + virtual std::shared_ptr< XBaseType > Clone(void) const = 0; /// Duplicates object only virtual void Pull(const KTExtensibleStructCore< XBaseType >& object) = 0; /// Returns the pointer to the next field - KTExtensibleStructCore* Next() const; + std::shared_ptr< KTExtensibleStructCore > Next() const; /// Returns the pointer to the previous field - KTExtensibleStructCore* Prev() const; + std::shared_ptr< KTExtensibleStructCore > Prev() const; /// Returns the pointer to the last field - KTExtensibleStructCore* Last() const; + std::shared_ptr< KTExtensibleStructCore > Last() const; /// Returns the pointer to the first field - KTExtensibleStructCore* First() const; + std::shared_ptr< KTExtensibleStructCore > First() const; protected: void SetPrevPtrInNext(); - mutable KTExtensibleStructCore* fNext; - mutable KTExtensibleStructCore* fPrev; + mutable std::shared_ptr< KTExtensibleStructCore > fNext; + mutable std::shared_ptr< KTExtensibleStructCore > fPrev; private: friend class cereal::access; @@ -79,7 +81,7 @@ namespace Nymph /// Duplicates the extended object KTExtensibleStruct& operator=(const KTExtensibleStruct& object); /// Duplicates the extended object - virtual KTExtensibleStructCore< XBaseType >* Clone(void) const; + virtual std::shared_ptr< XBaseType > Clone(void) const; /// Duplicates object only virtual void Pull(const KTExtensibleStructCore< XBaseType >& object); void SetIsCopyDisabled(bool flag); @@ -93,38 +95,36 @@ namespace Nymph template - KTExtensibleStructCore::KTExtensibleStructCore(void) + KTExtensibleStructCore::KTExtensibleStructCore(void) : + fNext(), + fPrev() { - fPrev = 0; - fNext = 0; } template - KTExtensibleStructCore::KTExtensibleStructCore(const KTExtensibleStructCore&) + KTExtensibleStructCore::KTExtensibleStructCore(const KTExtensibleStructCore&) : + fNext(), + fPrev() { - fPrev = 0; - fNext = 0; } template KTExtensibleStructCore::~KTExtensibleStructCore() { - delete fNext; - fNext = 0; + fNext.reset(); } template KTExtensibleStructCore& KTExtensibleStructCore::operator=(const KTExtensibleStructCore&) { - fNext = 0; + fNext.reset(); return *this; } template void KTExtensibleStructCore::Clear(void) { - delete fNext; - fNext = 0; + fNext.reset(); } template @@ -143,7 +143,7 @@ namespace Nymph fNext->fPrev = this; } - return fNext->Of(); + return fNext->template Of(); } template @@ -156,13 +156,13 @@ namespace Nymph return *target; } - if (fNext == 0) + if (! fNext) { fNext = new XStructType(); fNext->fPrev = const_cast< KTExtensibleStructCore< XBaseType >* >(this); } - return fNext->Of(); + return fNext->template Of(); } @@ -177,7 +177,7 @@ namespace Nymph } if (fNext) { - return fNext->Has(); + return fNext->template Has(); } return false; @@ -200,45 +200,45 @@ namespace Nymph { fNext = next->fNext; fNext->fPrev = this; - next->fNext = 0; + next->fNext.reset(); } - next->fPrev = 0; + next->fPrev.reset(); return next; } - return fNext->Detatch(); + return fNext->template Detatch(); } template - inline KTExtensibleStructCore* KTExtensibleStructCore::Next() const + inline std::shared_ptr< KTExtensibleStructCore > KTExtensibleStructCore::Next() const { return fNext; } template - inline KTExtensibleStructCore* KTExtensibleStructCore::Prev() const + inline std::shared_ptr< KTExtensibleStructCore > KTExtensibleStructCore::Prev() const { return fPrev; } template - inline KTExtensibleStructCore* KTExtensibleStructCore::Last() const + inline std::shared_ptr< KTExtensibleStructCore > KTExtensibleStructCore::Last() const { - if (fNext == 0) return this; + if (fNext) return this; return fNext->Last(); } template - inline KTExtensibleStructCore* KTExtensibleStructCore::First() const + inline std::shared_ptr< KTExtensibleStructCore > KTExtensibleStructCore::First() const { - if (fPrev == 0) return this; + if (fPrev) return this; return fPrev->First(); } template inline void KTExtensibleStructCore::SetPrevPtrInNext() { - fNext->fPrev = this; + fNext->fPrev.reset( this ); return; } @@ -287,7 +287,7 @@ namespace Nymph if (object.fNext) { - this->fNext = object.fNext->Clone(); + this->fNext.reset( object.fNext->Clone() ); } } @@ -314,14 +314,14 @@ namespace Nymph } template - KTExtensibleStructCore* KTExtensibleStruct::Clone(void) const + std::shared_ptr< XBaseType > KTExtensibleStruct::Clone(void) const { // assume CRTP is used properly, // otherwise compiling fails here (intended behavior) XInstanceType* instance = new XInstanceType(dynamic_cast(*this)); if (this->fNext) { - instance->fNext = this->fNext->Clone(); + instance->fNext.reset( this->fNext->Clone() ); instance->SetPrevPtrInNext(); //instance->fNext->fPrev = instance->fNext; } From 618f5c6fe77215a0aaa33025d37da481f8bdf2b5 Mon Sep 17 00:00:00 2001 From: lgladstone Date: Thu, 1 Feb 2018 14:32:44 -0800 Subject: [PATCH 087/521] Workshop work: paramnode and paramvalue pybindings They're not quite finished, but it's partway there. This version compiles. --- Executables/Validation/CMakeLists.txt | 1 + Executables/Validation/TestPythonBindings.py | 28 +++++++++++ Library/CMakeLists.txt | 1 + Library/NymphPybind.cc | 2 + Library/Utility/KTParamNodePybind.hh | 53 ++++++++++++++++++++ 5 files changed, 85 insertions(+) create mode 100644 Executables/Validation/TestPythonBindings.py create mode 100644 Library/Utility/KTParamNodePybind.hh diff --git a/Executables/Validation/CMakeLists.txt b/Executables/Validation/CMakeLists.txt index 72c3ba6..2d14ffa 100644 --- a/Executables/Validation/CMakeLists.txt +++ b/Executables/Validation/CMakeLists.txt @@ -89,6 +89,7 @@ if (Nymph_ENABLE_TESTING) TestProcessorToolbox.py TestPyTestClass.py TestPythonBasics.py + TestPythonBindings.py ) pybind11_add_module( py_nymph_validation MODULE ${VALIDATION_PYBINDING_SOURCEFILES} ) diff --git a/Executables/Validation/TestPythonBindings.py b/Executables/Validation/TestPythonBindings.py new file mode 100644 index 0000000..e6f2e4d --- /dev/null +++ b/Executables/Validation/TestPythonBindings.py @@ -0,0 +1,28 @@ +# Demonstrates access to KTPyTestClass + +import py_nymph as nymph + +# want to instantiate this will enough values to test all types: +# # TypeError: get_value(): incompatible function arguments. The following argument types are supported: +# 1. (self: py_nymph.ParamNodePybind, arg0: str) -> bool +# 2. (self: py_nymph.ParamNodePybind, arg0: str) -> int +# 3. (self: py_nymph.ParamNodePybind, arg0: str) -> int +# 4. (self: py_nymph.ParamNodePybind, arg0: str) -> float +# 5. (self: py_nymph.ParamNodePybind, arg0: str) -> str +# 6. (self: py_nymph.ParamNodePybind, arg0: str, arg1: bool) -> bool +# 7. (self: py_nymph.ParamNodePybind, arg0: str, arg1: int) -> int +# 8. (self: py_nymph.ParamNodePybind, arg0: str, arg1: int) -> int +# 9. (self: py_nymph.ParamNodePybind, arg0: str, arg1: float) -> float +# 10. (self: py_nymph.ParamNodePybind, arg0: str, arg1: str) -> str + +a_value = nymph.ParamValue(True) +print("Get a bool set to True: ", a_value.get()) + +# print(pnp.get_value()) + + + + +a_node = nymph.ParamNode() +# Test the "get_value" function for all the different types: +# a_node.get_value("myKey") \ No newline at end of file diff --git a/Library/CMakeLists.txt b/Library/CMakeLists.txt index f9c7f14..05e92ca 100644 --- a/Library/CMakeLists.txt +++ b/Library/CMakeLists.txt @@ -93,6 +93,7 @@ set( NYMPH_PYBINDING_HEADERFILES #${UTIL_DIR}/KTConfigurablePybind.hh ${PROC_DIR}/KTProcessorPybind.hh ${PROC_DIR}/KTPyProcessor.hh + ${UTIL_DIR}/KTParamNodePybind.hh ) # Python bindings diff --git a/Library/NymphPybind.cc b/Library/NymphPybind.cc index dc99ee8..b579c6d 100644 --- a/Library/NymphPybind.cc +++ b/Library/NymphPybind.cc @@ -8,12 +8,14 @@ #include "Application/KTProcessorToolboxPybind.hh" #include "Processor/KTProcessorPybind.hh" //#include "Utility/KTConfigurablePybind.hh" +#include "Utility/KTParamNodePybind.hh" PYBIND11_MODULE( py_nymph, mod ) { //Nymph::ExportKTConfigurable( mod ); Nymph::ExportKTProcessor( mod ); Nymph::ExportKTProcessorToolbox( mod ); + Nymph::ExportParamNodePybind( mod ); } diff --git a/Library/Utility/KTParamNodePybind.hh b/Library/Utility/KTParamNodePybind.hh new file mode 100644 index 0000000..ff6b284 --- /dev/null +++ b/Library/Utility/KTParamNodePybind.hh @@ -0,0 +1,53 @@ +/* + * KTPyNymph.cc + * + * Created on: Feb 1, 2018 + * Author: N. Oblath, L. Gladstone + */ + +#include "param_node.hh" +#include "pybind11/pybind11.h" + +namespace Nymph +{ + + void ExportParamNodePybind( pybind11::module& mod ) + { + pybind11::class_< scarab::param_value >(mod, "ParamValue") + .def(pybind11::init()) + .def("get",(bool (scarab::param_value::*)() const) &scarab::param_value::get,"Get parameter value") + ; + + pybind11::class_< scarab::param_node >(mod, "ParamNode") + .def(pybind11::init<>()) + + .def("add",(bool (scarab::param_node::*)(const scarab::param_value&) const) &scarab::param_value::get,"Add a parameter value to a node") + + // Get value of the parameter, when no default is set + .def("get_value", (bool (scarab::param_node::*)(const std::string&) const) &scarab::param_node::get_value, "Get parameter node value") + .def("get_value", (uint (scarab::param_node::*)(const std::string &) const) + &scarab::param_node::get_value, "Get parameter node value") + .def("get_value", (int (scarab::param_node::*)(const std::string &) const) + &scarab::param_node::get_value, "Get parameter node value") + .def("get_value", (double (scarab::param_node::*)(const std::string &) const) + &scarab::param_node::get_value, "Get parameter node value") + .def("get_value", (std::string (scarab::param_node::*)(const std::string &) const) + &scarab::param_node::get_value, "Get parameter node value") + + // Get value of the parameter, bringing along the default value + .def("get_value", (bool (scarab::param_node::*)(const std::string&, bool) const) &scarab::param_node::get_value, "Get parameter node value") + .def("get_value", (uint (scarab::param_node::*)(const std::string &, uint) const) + &scarab::param_node::get_value, "Get parameter node value") + .def("get_value", (int (scarab::param_node::*)(const std::string &, int) const) + &scarab::param_node::get_value, "Get parameter node value") + .def("get_value", (double (scarab::param_node::*)(const std::string &, double) const) + &scarab::param_node::get_value, "Get parameter node value") + .def("get_value", (std::string (scarab::param_node::*)(const std::string &, const std::string & ) const) + &scarab::param_node::get_value, "Get parameter node value") + ; + + + + } + +} /* namespace Nymph */ From 1fd20aace26c841f522873ee6645c16ff243b464 Mon Sep 17 00:00:00 2001 From: cclaessens Date: Fri, 2 Feb 2018 00:24:33 +0100 Subject: [PATCH 088/521] added binding for AddProcessor in KTProcessorToolboxPybind --- Executables/Validation/TestProcessorToolbox.py | 13 ++----------- Executables/Validation/TestWrapProcessor.py | 10 ++++++---- Library/Application/KTProcessorToolboxPybind.hh | 8 +++++--- 3 files changed, 13 insertions(+), 18 deletions(-) diff --git a/Executables/Validation/TestProcessorToolbox.py b/Executables/Validation/TestProcessorToolbox.py index 31868de..8453a79 100644 --- a/Executables/Validation/TestProcessorToolbox.py +++ b/Executables/Validation/TestProcessorToolbox.py @@ -7,8 +7,6 @@ import py_nymph as nymph import py_nymph_validation as nv -class WrappedProcessor(nv.WrapProcessor): - pass ptb = nymph.KTProcessorToolbox('pt') @@ -16,17 +14,10 @@ class WrappedProcessor(nv.WrapProcessor): ptb.AddProcessor('test-p-proc', 'tpp') ptb.AddProcessor('test-proc-b', 'tp') -ptb.AddProcessor('base-wrap-proc', 'bwp') +ptb.MakeConnection('tpp:the-signal', 'tp:first-slot') +ptb.MakeConnection('tpp:the-signal', 'tp:first-slot') - -#ptb.MakeConnection('tpp:the-signal', 'tp:first-slot') -#ptb.MakeConnection('tpp:the-signal', 'tp:first-slot') -ptb.MakeConnection('tpp:the-signal', 'bwp:wrap-slot') - -p = WrappedProcessor() -p.WrapFunction = lambda x: print("Hey, I'm python") - ptb.PushBackToRunQueue('tpp') print('Running') diff --git a/Executables/Validation/TestWrapProcessor.py b/Executables/Validation/TestWrapProcessor.py index 82e1778..517af2b 100644 --- a/Executables/Validation/TestWrapProcessor.py +++ b/Executables/Validation/TestWrapProcessor.py @@ -15,17 +15,19 @@ class WrappedProcessor(nv.WrapProcessor): print('Configuring') ptb.AddProcessor('test-p-proc', 'tpp') -ptb.AddProcessor('test-proc-b', 'tp') -ptb.AddProcessor('base-wrap-proc', 'bwp') +#ptb.AddProcessor('test-proc-b', 'tp') +p = WrappedProcessor() +print('type of WrappedProcessor in python is: {}'.format( type(p))) +p.WrapFunction = lambda x: print("Hey, I'm python") +ptb.AddProcessor('bwp', p) #ptb.MakeConnection('tpp:the-signal', 'tp:first-slot') #ptb.MakeConnection('tpp:the-signal', 'tp:first-slot') ptb.MakeConnection('tpp:the-signal', 'bwp:wrap-slot') -p = WrappedProcessor() -p.WrapFunction = lambda x: print("Hey, I'm python") + ptb.PushBackToRunQueue('tpp') diff --git a/Library/Application/KTProcessorToolboxPybind.hh b/Library/Application/KTProcessorToolboxPybind.hh index 678a374..a0dc85d 100644 --- a/Library/Application/KTProcessorToolboxPybind.hh +++ b/Library/Application/KTProcessorToolboxPybind.hh @@ -17,7 +17,6 @@ namespace Nymph { void ExportKTProcessorToolbox( pybind11::module& mod ) { - pybind11::class_< KTProcessorToolbox >( mod, "KTProcessorToolbox" ) .def( pybind11::init< const std::string & >() ) @@ -29,7 +28,8 @@ namespace Nymph // GetProcessor skipped because raw pointers are not supported by pybind11 .def( "AddProcessor", (bool (KTProcessorToolbox::*)(const std::string&, const std::string&)) &KTProcessorToolbox::AddProcessor, "Create a processor by name and add it to the toolbox" ) - // skipping AddProcessor(const std::string&, KTProcessor*) + .def("AddProcessor", (bool (KTProcessorToolbox::*)(const std::string&, std::shared_ptr< KTProcessor > proc)) &KTProcessorToolbox::AddProcessor, + "Create a processor and add it to the toolbox" ) .def( "RemoveProcessor", &KTProcessorToolbox::RemoveProcessor, "Remove a processor from the toolbox" ) // skipping ReleaseProcessor @@ -77,7 +77,8 @@ namespace Nymph .def( "CancelThreads", &KTProcessorToolbox::CancelThreads, "Kill any running thread at the next breakpoint check" ) .def( "JoinRunThread", &KTProcessorToolbox::JoinRunThread, "Blocking call to wait until Run() is complete; this should only be done by the owner of the thread (typically whoever called Run())" ) - .def( "GetData", &KTProcessorToolbox::GetData, "Retrieve the data handle from a slot by thread name (i.e. the name of the primary processor for that thread)" ) + .def( "GetData", &KTProcessorToolbox::GetData, "Retrieve the data handle from a slot by thread name (i.e. the name of the primary processor for that thread)" ); + /* // these are implemented in the boost::python version but not yet here @@ -93,6 +94,7 @@ namespace Nymph ; } + } #endif /* NYMPH_KTPROCESSORTOOLBOXPYBIND_HH_ */ From def217ff9ba0c23d487892bd7f3d87dd89505330 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Thu, 1 Feb 2018 21:47:39 -0800 Subject: [PATCH 089/521] Further partial work in fixing the extensible struct system to be serializable --- Library/Data/KTCutStatus.hh | 2 +- Library/Utility/KTExtensibleStruct.hh | 100 ++++++++++++++------------ 2 files changed, 56 insertions(+), 46 deletions(-) diff --git a/Library/Data/KTCutStatus.hh b/Library/Data/KTCutStatus.hh index 80bb33d..f90a847 100644 --- a/Library/Data/KTCutStatus.hh +++ b/Library/Data/KTCutStatus.hh @@ -141,7 +141,7 @@ namespace Nymph inline const std::shared_ptr< KTCutResult > KTCutStatus::CutResults() const { - return fCutResults.get()->Next(); + return fCutResults->Next(); } template< typename XCutType > diff --git a/Library/Utility/KTExtensibleStruct.hh b/Library/Utility/KTExtensibleStruct.hh index 60c6bb3..c439d6a 100644 --- a/Library/Utility/KTExtensibleStruct.hh +++ b/Library/Utility/KTExtensibleStruct.hh @@ -25,40 +25,47 @@ namespace Nymph template< class XBaseType > struct KTExtensibleStructCore : public XBaseType { + public: + typedef std::shared_ptr< XBaseType > BasePtr; + public: /// Default constructor - KTExtensibleStructCore(void); + KTExtensibleStructCore(); /// Copy constructor; duplicates the extended object - KTExtensibleStructCore(const KTExtensibleStructCore&); + KTExtensibleStructCore( const KTExtensibleStructCore& ); virtual ~KTExtensibleStructCore(); /// Duplicates the extended object - KTExtensibleStructCore& operator=(const KTExtensibleStructCore&); + KTExtensibleStructCore& operator=( const KTExtensibleStructCore& ); /// Removes extended fields - virtual void Clear(void); + virtual void Clear(); /// Returns a reference to the object of type XStructType; creates that object if it doesn't exist - template< class XStructType > inline XStructType& Of(void); + template< class XStructType > + inline XStructType& Of(); /// Returns a const reference to the object of type XStructType; creates that object if it doesn't exist - template< class XStructType > inline const XStructType& Of(void) const; + template< class XStructType > + inline const XStructType& Of() const; /// Returns true if XStructType is or is below this object - template< class XStructType > inline bool Has(void) const; + template< class XStructType > + inline bool Has() const; /// Extracts object of type XStructType - template< class XStructType > inline XStructType* Detatch(void); + template< class XStructType > + inline std::shared_ptr< XStructType > Detatch(); /// Duplicates the extended object - virtual std::shared_ptr< XBaseType > Clone(void) const = 0; + virtual BasePtr Clone() const = 0; /// Duplicates object only - virtual void Pull(const KTExtensibleStructCore< XBaseType >& object) = 0; + virtual void Pull( const KTExtensibleStructCore< XBaseType >& object ) = 0; /// Returns the pointer to the next field - std::shared_ptr< KTExtensibleStructCore > Next() const; + BasePtr Next() const; /// Returns the pointer to the previous field - std::shared_ptr< KTExtensibleStructCore > Prev() const; + BasePtr Prev() const; /// Returns the pointer to the last field - std::shared_ptr< KTExtensibleStructCore > Last() const; + BasePtr Last() const; /// Returns the pointer to the first field - std::shared_ptr< KTExtensibleStructCore > First() const; + BasePtr First() const; protected: void SetPrevPtrInNext(); - mutable std::shared_ptr< KTExtensibleStructCore > fNext; - mutable std::shared_ptr< KTExtensibleStructCore > fPrev; + mutable BasePtr fNext; + mutable BasePtr fPrev; private: friend class cereal::access; @@ -72,19 +79,22 @@ namespace Nymph template< class XInstanceType, class XBaseType > struct KTExtensibleStruct : KTExtensibleStructCore< XBaseType > { + public: + typedef typename KTExtensibleStructCore< XBaseType >::BasePtr BasePtr; + public: /// Default constructor - KTExtensibleStruct(void); + KTExtensibleStruct(); /// Copy constructor; duplicates the extended object - KTExtensibleStruct(const KTExtensibleStruct& object); + KTExtensibleStruct( const KTExtensibleStruct& object ); virtual ~KTExtensibleStruct(); /// Duplicates the extended object - KTExtensibleStruct& operator=(const KTExtensibleStruct& object); + KTExtensibleStruct& operator=( const KTExtensibleStruct& object ); /// Duplicates the extended object - virtual std::shared_ptr< XBaseType > Clone(void) const; + virtual BasePtr Clone() const; /// Duplicates object only - virtual void Pull(const KTExtensibleStructCore< XBaseType >& object); - void SetIsCopyDisabled(bool flag); + virtual void Pull( const KTExtensibleStructCore< XBaseType >& object ); + void SetIsCopyDisabled( bool flag ); private: bool fIsCopyDisabled; friend class cereal::access; @@ -103,7 +113,7 @@ namespace Nymph } template - KTExtensibleStructCore::KTExtensibleStructCore(const KTExtensibleStructCore&) : + KTExtensibleStructCore::KTExtensibleStructCore( const KTExtensibleStructCore& ) : fNext(), fPrev() { @@ -116,21 +126,21 @@ namespace Nymph } template - KTExtensibleStructCore& KTExtensibleStructCore::operator=(const KTExtensibleStructCore&) + KTExtensibleStructCore& KTExtensibleStructCore::operator=( const KTExtensibleStructCore& ) { fNext.reset(); return *this; } template - void KTExtensibleStructCore::Clear(void) + void KTExtensibleStructCore::Clear() { fNext.reset(); } template template - inline XStructType& KTExtensibleStructCore::Of(void) + inline XStructType& KTExtensibleStructCore::Of() { XStructType* target = dynamic_cast(this); if (target) @@ -140,8 +150,8 @@ namespace Nymph if (! fNext) { - fNext = new XStructType(); - fNext->fPrev = this; + fNext = std::make_shared< XStructType >(); + fNext->fPrev.reset( this ); } return fNext->template Of(); @@ -149,7 +159,7 @@ namespace Nymph template template - inline const XStructType& KTExtensibleStructCore::Of(void) const + inline const XStructType& KTExtensibleStructCore::Of() const { const XStructType* target = dynamic_cast(this); if (target) @@ -159,8 +169,8 @@ namespace Nymph if (! fNext) { - fNext = new XStructType(); - fNext->fPrev = const_cast< KTExtensibleStructCore< XBaseType >* >(this); + fNext = std::make_shared< XStructType >(); + fNext->fPrev.reset( const_cast< KTExtensibleStructCore< XBaseType >* >(this) ); } return fNext->template Of(); @@ -170,7 +180,7 @@ namespace Nymph template template - inline bool KTExtensibleStructCore::Has(void) const + inline bool KTExtensibleStructCore::Has() const { if (dynamic_cast(this)) { @@ -188,13 +198,13 @@ namespace Nymph template template - inline XStructType* KTExtensibleStructCore::Detatch(void) + inline std::shared_ptr< XStructType > KTExtensibleStructCore::Detatch() { if (! fNext) { - return 0; + return std::shared_ptr< XStructType >(); } - XStructType* next = dynamic_cast(fNext); + std::shared_ptr< XStructType > next = std::dynamic_pointer_cast< XStructType >(fNext); if (next) { if (next->fNext) @@ -211,26 +221,26 @@ namespace Nymph template - inline std::shared_ptr< KTExtensibleStructCore > KTExtensibleStructCore::Next() const + inline typename KTExtensibleStructCore::BasePtr KTExtensibleStructCore::Next() const { return fNext; } template - inline std::shared_ptr< KTExtensibleStructCore > KTExtensibleStructCore::Prev() const + inline typename KTExtensibleStructCore::BasePtr KTExtensibleStructCore::Prev() const { return fPrev; } template - inline std::shared_ptr< KTExtensibleStructCore > KTExtensibleStructCore::Last() const + inline typename KTExtensibleStructCore::BasePtr KTExtensibleStructCore::Last() const { if (fNext) return this; return fNext->Last(); } template - inline std::shared_ptr< KTExtensibleStructCore > KTExtensibleStructCore::First() const + inline typename KTExtensibleStructCore::BasePtr KTExtensibleStructCore::First() const { if (fPrev) return this; return fPrev->First(); @@ -268,9 +278,10 @@ namespace Nymph } template - KTExtensibleStruct::KTExtensibleStruct(void) + KTExtensibleStruct::KTExtensibleStruct() : + KTExtensibleStructCore< XBaseType >(), + fIsCopyDisabled( false ) { - fIsCopyDisabled = false; } template @@ -301,8 +312,7 @@ namespace Nymph return *this; } - delete this->fNext; - this->fNext = 0; + this->fNext.reset(); if (object.fNext) { @@ -315,11 +325,11 @@ namespace Nymph } template - std::shared_ptr< XBaseType > KTExtensibleStruct::Clone(void) const + typename KTExtensibleStruct::BasePtr KTExtensibleStruct::Clone() const { // assume CRTP is used properly, // otherwise compiling fails here (intended behavior) - XInstanceType* instance = new XInstanceType(dynamic_cast(*this)); + BasePtr instance = std::make_shared< XBaseType >( XInstanceType(dynamic_cast(*this)) ); if (this->fNext) { instance->fNext.reset( this->fNext->Clone() ); From 72fc7dc9c3b38206cc58a86872e021db7fbce956 Mon Sep 17 00:00:00 2001 From: cclaessens Date: Fri, 2 Feb 2018 15:52:45 +0100 Subject: [PATCH 090/521] included shared_ptr in py_nymph_validation --- Executables/Validation/NymphValidationPybind.cc | 4 ++++ Executables/Validation/TestWrapProcessor.py | 7 +++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Executables/Validation/NymphValidationPybind.cc b/Executables/Validation/NymphValidationPybind.cc index 657eb48..411d198 100644 --- a/Executables/Validation/NymphValidationPybind.cc +++ b/Executables/Validation/NymphValidationPybind.cc @@ -8,6 +8,7 @@ #include "KTPyTestClassPybind.hh" #include "TestPythonBasics.hh" #include "pybind11/pybind11.h" +#include PYBIND11_MODULE( py_nymph_validation, mod ) { @@ -19,6 +20,9 @@ PYBIND11_MODULE( py_nymph_validation, mod ) .def(pybind11::init<>()) .def("WrapFunction", &Nymph::KTWrapProcessor::WrapFunction) .def("Configure", &Nymph::KTWrapProcessor::Configure); + + pybind11::class_< Nymph::KTProcessor, std::shared_ptr>( mod, "KTProcessor" ); + } diff --git a/Executables/Validation/TestWrapProcessor.py b/Executables/Validation/TestWrapProcessor.py index 517af2b..181b9f0 100644 --- a/Executables/Validation/TestWrapProcessor.py +++ b/Executables/Validation/TestWrapProcessor.py @@ -10,6 +10,8 @@ class WrappedProcessor(nv.WrapProcessor): pass + + ptb = nymph.KTProcessorToolbox('pt') print('Configuring') @@ -18,17 +20,14 @@ class WrappedProcessor(nv.WrapProcessor): #ptb.AddProcessor('test-proc-b', 'tp') p = WrappedProcessor() +p.WrapFunction = lambda x: print("Hey, I'm python") print('type of WrappedProcessor in python is: {}'.format( type(p))) -p.WrapFunction = lambda x: print("Hey, I'm python") ptb.AddProcessor('bwp', p) -#ptb.MakeConnection('tpp:the-signal', 'tp:first-slot') -#ptb.MakeConnection('tpp:the-signal', 'tp:first-slot') ptb.MakeConnection('tpp:the-signal', 'bwp:wrap-slot') - ptb.PushBackToRunQueue('tpp') print('Running') From 586a4373ffea3eb0bcddebfc1ccdca82f8a40f85 Mon Sep 17 00:00:00 2001 From: cclaessens Date: Wed, 7 Feb 2018 10:29:09 +0100 Subject: [PATCH 091/521] moved wrappable processor from py_nymph_validation to py_nymph. --- Executables/Validation/KTPyTestClassPybind.hh | 4 +- Executables/Validation/KTTestProcessor.cc | 4 +- Executables/Validation/KTTestProcessor.hh | 4 +- .../Validation/NymphValidationPybind.cc | 6 +- Executables/Validation/TestWrapProcessor.py | 5 +- Library/CMakeLists.txt | 1 + Library/NymphPybind.cc | 12 +++- Library/Processor/KTProcessorPybind.cc | 48 ++++++++++++++++ Library/Processor/KTProcessorPybind.hh | 57 +++++++++++++++++-- 9 files changed, 124 insertions(+), 17 deletions(-) create mode 100644 Library/Processor/KTProcessorPybind.cc diff --git a/Executables/Validation/KTPyTestClassPybind.hh b/Executables/Validation/KTPyTestClassPybind.hh index db3e5b6..e016939 100644 --- a/Executables/Validation/KTPyTestClassPybind.hh +++ b/Executables/Validation/KTPyTestClassPybind.hh @@ -23,7 +23,7 @@ namespace Nymph ; }; - class KTPyWrapProcessor: public KTWrapProcessor +/* class KTPyWrapProcessor: public KTWrapProcessor { public: // Inherit the constructors @@ -46,7 +46,7 @@ namespace Nymph node // Argument(s) ); } - }; + };*/ } /* namespace Nymph */ diff --git a/Executables/Validation/KTTestProcessor.cc b/Executables/Validation/KTTestProcessor.cc index 65bccd0..cd151cd 100644 --- a/Executables/Validation/KTTestProcessor.cc +++ b/Executables/Validation/KTTestProcessor.cc @@ -180,7 +180,7 @@ namespace Nymph return; } - KT_REGISTER_PROCESSOR(KTWrapProcessor, "base-wrap-proc"); + /* KT_REGISTER_PROCESSOR(KTWrapProcessor, "base-wrap-proc"); KTWrapProcessor::KTWrapProcessor( const std::string& name ) : KTProcessor( name ), @@ -209,6 +209,6 @@ namespace Nymph { KTINFO(testsiglog, "Hey, I'm base class"); return; - } + }*/ } /* namespace Nymph */ diff --git a/Executables/Validation/KTTestProcessor.hh b/Executables/Validation/KTTestProcessor.hh index 4ba76d5..d14930f 100644 --- a/Executables/Validation/KTTestProcessor.hh +++ b/Executables/Validation/KTTestProcessor.hh @@ -131,7 +131,7 @@ namespace Nymph }; - class KTWrapProcessor : public KTProcessor + /* class KTWrapProcessor : public KTProcessor { public: KTWrapProcessor( const std::string& name = "base-wrap-proc" ); @@ -145,7 +145,7 @@ namespace Nymph private: KTSlot< int > fSlot; - }; + };*/ } /* namespace Nymph */ #endif /* KTTESTPROCESSOR_HH_ */ diff --git a/Executables/Validation/NymphValidationPybind.cc b/Executables/Validation/NymphValidationPybind.cc index 411d198..2c4281e 100644 --- a/Executables/Validation/NymphValidationPybind.cc +++ b/Executables/Validation/NymphValidationPybind.cc @@ -15,13 +15,13 @@ PYBIND11_MODULE( py_nymph_validation, mod ) Nymph::ExportKTPyTestClass( mod ); Nymph::ExportTestPythonBasics( mod ); - pybind11::class_ wrap_processor(mod, "WrapProcessor"); + /*pybind11::class_ wrap_processor(mod, "WrapProcessor"); wrap_processor .def(pybind11::init<>()) .def("WrapFunction", &Nymph::KTWrapProcessor::WrapFunction) .def("Configure", &Nymph::KTWrapProcessor::Configure); - - pybind11::class_< Nymph::KTProcessor, std::shared_ptr>( mod, "KTProcessor" ); +*/ + //pybind11::class_< Nymph::KTProcessor, std::shared_ptr>( mod, "KTProcessor" ); } diff --git a/Executables/Validation/TestWrapProcessor.py b/Executables/Validation/TestWrapProcessor.py index 181b9f0..fd53b8b 100644 --- a/Executables/Validation/TestWrapProcessor.py +++ b/Executables/Validation/TestWrapProcessor.py @@ -7,11 +7,12 @@ import py_nymph as nymph import py_nymph_validation as nv -class WrappedProcessor(nv.WrapProcessor): +class WrappedProcessor(nymph.WrapProcessor): + def __init__(self): + super(WrappedProcessor, self).__init__() pass - ptb = nymph.KTProcessorToolbox('pt') print('Configuring') diff --git a/Library/CMakeLists.txt b/Library/CMakeLists.txt index f9c7f14..c9a33b8 100644 --- a/Library/CMakeLists.txt +++ b/Library/CMakeLists.txt @@ -97,6 +97,7 @@ set( NYMPH_PYBINDING_HEADERFILES # Python bindings set( NYMPH_PYBINDING_SOURCEFILES + ${PROC_DIR}/KTProcessorPybind.cc NymphPybind.cc ) diff --git a/Library/NymphPybind.cc b/Library/NymphPybind.cc index dc99ee8..d3397ac 100644 --- a/Library/NymphPybind.cc +++ b/Library/NymphPybind.cc @@ -7,13 +7,23 @@ #include "Application/KTProcessorToolboxPybind.hh" #include "Processor/KTProcessorPybind.hh" +#include //#include "Utility/KTConfigurablePybind.hh" PYBIND11_MODULE( py_nymph, mod ) { //Nymph::ExportKTConfigurable( mod ); - Nymph::ExportKTProcessor( mod ); + //Nymph::ExportKTProcessor( mod ); Nymph::ExportKTProcessorToolbox( mod ); + + pybind11::class_< Nymph::KTProcessor, std::shared_ptr>( mod, "KTProcessor" ); + + pybind11::class_ wrap_processor(mod, "WrapProcessor"); + wrap_processor + .def(pybind11::init<>()) + .def("WrapFunction", &Nymph::KTWrapProcessor::WrapFunction) + .def("Configure", &Nymph::KTWrapProcessor::Configure); + } diff --git a/Library/Processor/KTProcessorPybind.cc b/Library/Processor/KTProcessorPybind.cc new file mode 100644 index 0000000..04cc151 --- /dev/null +++ b/Library/Processor/KTProcessorPybind.cc @@ -0,0 +1,48 @@ +/* + * KTProcessorPybind.cc + * + * Created on: Feb 06, 2018 + * Author: cclaessens + */ + +#include "KTProcessor.hh" +#include "KTProcessorPybind.hh" + + +#include "KTLogger.hh" + +namespace Nymph +{ + + KTLOGGER(procpylog, "KTProcessorPybind"); + KT_REGISTER_PROCESSOR(KTWrapProcessor, "base-wrap-proc"); + + KTWrapProcessor::KTWrapProcessor( const std::string& name ) : + KTProcessor( name ), + fSlot("wrap-slot", this, &KTWrapProcessor::SlotFunc) + + { + } + + KTWrapProcessor::~KTWrapProcessor() + { + } + + bool KTWrapProcessor::Configure(const scarab::param_node&) + { + return true; + } + + void KTWrapProcessor::SlotFunc(int input) + { + KTINFO(procpylog, "Calling wrap function "); + this->WrapFunction(input); + return; + } + + void KTWrapProcessor::WrapFunction(int input) + { + KTINFO(procpylog, "Hey, I'm base class"); + return; + } +} /* namespace Nymph */ diff --git a/Library/Processor/KTProcessorPybind.hh b/Library/Processor/KTProcessorPybind.hh index fcfee1e..8cccc6f 100644 --- a/Library/Processor/KTProcessorPybind.hh +++ b/Library/Processor/KTProcessorPybind.hh @@ -1,5 +1,5 @@ /* - * KTProcessorPybind.cc + * KTProcessorPybind.hh * * Created on: Jan 24, 2018 * Author: obla999 @@ -9,15 +9,17 @@ #define NYMPH_KTPROCESSORPYBIND_HH_ #include "KTPyProcessor.hh" +#include "KTProcessor.hh" +#include "KTSlot.hh" #include "pybind11/pybind11.h" namespace Nymph { - void ExportKTProcessor( pybind11::module& mod ) +/* void ExportKTProcessor( pybind11::module& mod ) { -/* pybind11::class_< KTProcessor, KTConfigurable >( mod, "KTProcessor" ) + pybind11::class_< KTProcessor, KTConfigurable >( mod, "KTProcessor" ) .def( pybind11::init< const std::string & >() ) .def( "ConnectASlot", &Nymph::KTProcessor::ConnectASlot ) @@ -26,12 +28,57 @@ namespace Nymph .def( "GetDoBreakpoint", &Nymph::KTProcessor::GetDoBreakpoint ) .def( "SetDoBreakpoint", &Nymph::KTProcessor::SetDoBreakpoint ) ; -*/ + pybind11::class_< KTPyProcessor >( mod, "KTPyProcessor" ) .def( pybind11::init< const std::string & >() ) ; - } + + + }*/ + + // processor with wrapfunction + class KTWrapProcessor : public KTProcessor + { + public: + KTWrapProcessor( const std::string& name = "base-wrap-proc" ); + virtual ~KTWrapProcessor(); + + bool Configure(const scarab::param_node& node); + + void SlotFunc(int); + virtual void WrapFunction(int input); + + private: + KTSlot< int > fSlot; + + }; + + // helper class + class KTPyWrapProcessor: public KTWrapProcessor + { + public: + // Inherit the constructors + using KTWrapProcessor::KTWrapProcessor; + + // Trampoline (need one for each virtual function) + void WrapFunction(int input) override { + PYBIND11_OVERLOAD_PURE( + void, // Return type + KTWrapProcessor, // Parent class + WrapFunction, // Name of function in C++ (must match Python name) + input // Argument(s) + ); + } + bool Configure(const scarab::param_node& node) override { + PYBIND11_OVERLOAD( + bool, // Return type + KTWrapProcessor, // Parent class + Configure, // Name of function in C++ (must match Python name) + node // Argument(s) + ); + } + }; } /* namespace Nymph */ From fae39d9d9630c9984dbcbd0ce07f302eba113917 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Wed, 7 Feb 2018 15:27:44 -0800 Subject: [PATCH 092/521] Preserving some partial progress --- Library/Data/KTCutResult.hh | 53 +++++----- Library/Data/KTCutStatus.cc | 106 +------------------- Library/Data/KTCutStatus.hh | 134 +++++++++++++++----------- Library/Data/KTData.cc | 4 + Library/Data/KTData.hh | 9 ++ Library/Utility/KTExtensibleStruct.hh | 26 ++--- 6 files changed, 142 insertions(+), 190 deletions(-) diff --git a/Library/Data/KTCutResult.hh b/Library/Data/KTCutResult.hh index a0845be..666a147 100644 --- a/Library/Data/KTCutResult.hh +++ b/Library/Data/KTCutResult.hh @@ -8,45 +8,50 @@ #ifndef KTCUTRESULT_HH_ #define KTCUTRESULT_HH_ -#include "KTExtensibleStruct.hh" +//#include "KTExtensibleStruct.hh" -#include "KTMemberVariable.hh" +//#include "KTMemberVariable.hh" #include namespace Nymph { - class KTCutResultCore + struct KTCutResult { - public: - KTCutResultCore() : - fState(false) - {} - virtual ~KTCutResultCore() {} - - virtual const std::string& Name() const = 0; - - MEMBERVARIABLE(bool, State); + bool fState; + KTCutResult( bool state ) { fState = state; } + virtual ~KTCutResult() {} + virtual const std::string& Name() const = 0; }; - typedef KTExtensibleStructCore< KTCutResultCore > KTCutResult; - - template< class XDerivedType > - class KTExtensibleCutResult : public KTExtensibleStruct< XDerivedType, KTCutResultCore > + template< class XCutType > + struct KTTypedCutResult : KTCutResult { - public: - KTExtensibleCutResult() {} - virtual ~KTExtensibleCutResult() {} - - const std::string& Name() const; + KTTypedCutResult( bool state ) : KTCutResult( state ) {} + virtual ~KTTypedCutResult() {} + virtual const std::string& Name() const + { + return XCutType::GetName(); + } }; - template< class XDerivedType > - inline const std::string& KTExtensibleCutResult< XDerivedType >::Name() const + template< class XCutType > + bool CheckCutResultType( std::shared_ptr< KTCutResult > result ) { - return XDerivedType::sName; + return std::dynamic_pointer_cast< KTTypedCutResult< XCutType > >( result ); + } + struct CheckCutResultName + { + std::string fName; + CheckCutResultName( const std::string& name ) : fName( name ) {} + bool operator()( std::shared_ptr< KTCutResult > result ) + { + return result->Name() == fName; + } + }; + } /* namespace Nymph */ #endif /* KTCUTRESULT_HH_ */ diff --git a/Library/Data/KTCutStatus.cc b/Library/Data/KTCutStatus.cc index ee371bd..06e6873 100644 --- a/Library/Data/KTCutStatus.cc +++ b/Library/Data/KTCutStatus.cc @@ -15,7 +15,7 @@ namespace Nymph KTLOGGER(cutlog, "KTCut"); KTCutStatus::KTCutStatus() : - fCutResults(new KTCutResultHandle()), + fCutResults(), fSummary() { } @@ -68,99 +68,16 @@ namespace Nymph return; } - bool KTCutStatus::AddCutResult(const std::string& cutName, bool state, bool doUpdateStatus) - { - if (! HasCutResult(cutName)) - { - KTExtensibleStructFactory< KTCutResultCore >* factory = KTExtensibleStructFactory< KTCutResultCore >::get_instance(); - KTCutResult* newCut = factory->Create(cutName, fCutResults.get()); - if (newCut == NULL) - { - KTERROR(cutlog, "Could not create cut of type <" << cutName << ">"); - return false; - } - newCut->SetState(state); - - if (doUpdateStatus) UpdateStatus(); - return true; - } - return false; - - } - - bool KTCutStatus::HasCutResult(const std::string& cutName) const - { - if (GetCutResult(cutName) == NULL) return false; - return true; - - } - - bool KTCutStatus::GetCutState(const std::string& cutName) const - { - const KTCutResult* cut = GetCutResult(cutName); - if (cut == NULL) return false; - return cut->GetState(); - } - - const KTCutResult& KTCutStatus::GetCutResult(const std::string& cutName) const - { - const KTCutResult* cut = fCutResults.get()->Next(); // skip over KTCutResultHandle - while (cut != NULL) - { - if (cut->Name() == cutName) return cut; - cut = cut->Next(); - } - throw KTException() << "Cannot find cut result"; - } - - KTCutResult& KTCutStatus::GetCutResult(const std::string& cutName) - { - KTCutResult* cut = fCutResults.get()->Next(); // skip over KTCutResultHandle - while (cut != NULL) - { - if (cut->Name() == cutName) return cut; - cut = cut->Next(); - } - throw KTException() << "Cannot find cut result"; - } - - bool KTCutStatus::SetCutState(const std::string& cutName, bool state, bool doUpdateStatus) - { - KTCutResult* cut = GetCutResult(cutName); - if (cut == NULL) - { - KTWARN(cutlog, "Cut <" << cutName << "> not found"); - return false; - } - cut->SetState(state); - - if (doUpdateStatus) UpdateStatus(); - return true; - } - - /* - void KTCutStatus::RemoveCutResult(const std::string& cutName, bool doUpdateStatus) - { - KTCutResult* cut = fCutResults.get(); // don't skip over KTCutResultHandle - KTCutResult* nextCut = cut->Next(); - while (nextCut != NULL) - { - if (nextCut->Name() == cutName) - { - // problem: can't pass nextCut->Next() to cut->Next() - if (doUpdateStatus) UpdateStatus(); - } - } - return; - } - */ - std::string KTCutStatus::CutResultsPresent() const { KTCutResult* cut = fCutResults.get()->Next(); // skip over KTCutResultHandle if (cut == NULL ) return ""; std::string cutsPresent; + for (auto cutIt = fCutResults.cbegin(); cutIt != fCutResults.cend(); ++cutIt) + { + cutsPresent = cutIt->Name() + cutsPresent; + } while (true) { cutsPresent = cut->Name() + cutsPresent; @@ -171,19 +88,6 @@ namespace Nymph return cutsPresent; } - // private class KTCutStatus::KTCutResultHandle - // purposefully not registered with the cut factory - KTCutStatus::KTCutResultHandle::KTCutResultHandle() : - KTExtensibleCutResult< KTCutStatus::KTCutResultHandle >() - { - fState = false; - } - KTCutStatus::KTCutResultHandle::~KTCutResultHandle() - {} - - const std::string KTCutStatus::KTCutResultHandle::sName("top"); - - std::ostream& operator<<(std::ostream& out, const KTCutStatus& status) { out << "Cut summary: " << status.fSummary << '\n'; diff --git a/Library/Data/KTCutStatus.hh b/Library/Data/KTCutStatus.hh index f90a847..cf9d7b9 100644 --- a/Library/Data/KTCutStatus.hh +++ b/Library/Data/KTCutStatus.hh @@ -15,8 +15,9 @@ #include +#include #include -#include +#include namespace Nymph { @@ -58,17 +59,11 @@ namespace Nymph public: typedef boost::dynamic_bitset< > bitset_type; - private: - // private class KTCutStatus::KTCutResultHandle - // purposefully not registered with the cut factory - class KTCutResultHandle : public KTExtensibleCutResult< KTCutResultHandle > - { - public: - KTCutResultHandle(); - ~KTCutResultHandle(); + typedef std::shared_ptr< KTCutResult > CutResultPtr; + typedef std::vector< CutResultPtr > CutResults_t; - static const std::string sName; - }; + typedef CutResults_t::iterator CutResultsIt; + typedef CutResults_t::const_iterator CutResultsCIt; public: KTCutStatus(); @@ -77,33 +72,33 @@ namespace Nymph KTCutStatus& operator=(const KTCutStatus& rhs); - const std::shared_ptr< KTCutResult > CutResults() const; + const CutResults_t& CutResults() const; void UpdateStatus(); template< typename XCutType > bool AddCutResult(bool state, bool doUpdateStatus=true); - bool AddCutResult(const std::string& cutName, bool state, bool doUpdateStatus=true); - // overload for const char* to avoid specializing the templated function below - bool AddCutResult(const char* cutName, bool state, bool doUpdateStatus=true); template< typename XCutType > - bool AddCutResult(const XCutType& cut, bool doUpdateStatus=true); + bool AddCutResult(const XCutType& cut, bool state, bool doUpdateStatus=true); template< typename XCutType > - bool HasCutResult() const; - bool HasCutResult(const std::string& cutName) const; + CutResultsIt FindCutResult(); + CutResultsIt FindCutResult(const std::string& cutName); template< typename XCutType > - bool GetCutState() const; - bool GetCutState(const std::string& cutName) const; + CutResultsCIt FindCutResultC() const; + CutResultsCIt FindCutResultC(const std::string& cutName) const; + + CutResultsIt CutResultsEnd(); + CutResultsCIt CutResultsEndC() const; template< typename XCutType > - const KTCutResult& GetCutResult() const; - const KTCutResult& GetCutResult(const std::string& cutName) const; + bool HasCutResult() const; + bool HasCutResult(const std::string& cutName) const; template< typename XCutType > - KTCutResult& GetCutResult(); - KTCutResult& GetCutResult(const std::string& cutName); + bool GetCutState() const; + bool GetCutState(const std::string& cutName) const; template< typename XCutType > bool SetCutState(bool state, bool doUpdateStatus=true); @@ -111,8 +106,7 @@ namespace Nymph template< typename XCutType > void RemoveCutResult(bool doUpdateStatus=true); - // cannot currently update by cut name - //void RemoveCutResult(const std::string& cutName, bool doUpdateStatus=true); + void RemoveCutResult(const std::string& cutName, bool doUpdateStatus=true); /// Returns a string with the names of the cuts that are present in bitset order std::string CutResultsPresent() const; @@ -121,7 +115,7 @@ namespace Nymph private: friend std::ostream& operator<<(std::ostream& out, const KTCutStatus& status); - std::unique_ptr< KTCutResultHandle > fCutResults; + CutResults_t fCutResults; bitset_type fSummary; @@ -139,9 +133,9 @@ namespace Nymph std::ostream& operator<<(std::ostream& out, const KTCutStatus& status); - inline const std::shared_ptr< KTCutResult > KTCutStatus::CutResults() const + inline const KTCutStatus::CutResults_t& KTCutStatus::CutResults() const { - return fCutResults->Next(); + return fCutResults; } template< typename XCutType > @@ -149,70 +143,102 @@ namespace Nymph { if (! HasCutResult< XCutType >()) { - fCutResults.get()->Of< XCutType >().SetState(state); + fCutResults.emplace_back( state ); if (doUpdateStatus) UpdateStatus(); return true; } return false; } - inline bool KTCutStatus::AddCutResult(const char* cutName, bool state, bool doUpdateStatus) - { - return AddCutResult(std::string(cutName), state, doUpdateStatus); - } - template< typename XCutType > - bool KTCutStatus::AddCutResult(const XCutType& cut, bool doUpdateStatus) + bool KTCutStatus::AddCutResult(const XCutType&, bool state, bool doUpdateStatus) { if (! HasCutResult< XCutType >()) { - fCutResults.get()->Of< XCutType >() = cut; + fCutResults.emplace_back( state ); if (doUpdateStatus) UpdateStatus(); return true; } return false; } + template< typename XCutType > + inline KTCutStatus::CutResultsIt KTCutStatus::FindCutResult() + { + return std::find_if( fCutResults.begin(), fCutResults.end(), CheckCutResultType< XCutType > ); + } + + inline KTCutStatus::CutResultsIt KTCutStatus::FindCutResult( const std::string& name ) + { + return std::find_if( fCutResults.begin(), fCutResults.end(), CheckCutResultName(name) ); + } + + template< typename XCutType > + inline KTCutStatus::CutResultsCIt KTCutStatus::FindCutResultC() const + { + return std::find_if( fCutResults.cbegin(), fCutResults.cend(), CheckCutResultType< XCutType > ); + } + + inline KTCutStatus::CutResultsCIt KTCutStatus::FindCutResultC( const std::string& name ) const + { + return std::find_if( fCutResults.cbegin(), fCutResults.cend(), CheckCutResultName(name) ); + } + + inline KTCutStatus::CutResultsIt KTCutStatus::CutResultsEnd() + { + return fCutResults.end(); + } + + inline KTCutStatus::CutResultsCIt KTCutStatus::CutResultsEndC() const + { + return fCutResults.cend(); + } + template< typename XCutType > inline bool KTCutStatus::HasCutResult() const { - return fCutResults.get()->Has< XCutType >(); + return FindCutResultC< XCutType >() != std::end(fCutResults); + } + + inline bool KTCutStatus::HasCutResult( const std::string& name) const + { + return FindCutResultC(name) != std::end(fCutResults); } template< typename XCutType > bool KTCutStatus::GetCutState() const { - if (HasCutResult< XCutType >()) + auto cutIt = FindCutResult< XCutType >(); + if (cutIt != fCutResults.cend()) { - return fCutResults.get()->Of< XCutType >().GetState(); + return cutIt->fState; } return false; } - template< typename XCutType > - const KTCutResult& KTCutStatus::GetCutResult() const + bool KTCutStatus::GetCutState( const std::string& name ) const { - if (HasCutResult< XCutType >()) + CutResultsCIt cutIt = FindCutResultC(name); + if (cutIt != fCutResults.cend()) { - return fCutResults.get()->Of< XCutType >(); + return (*cutIt)->fState; } - throw KTException() << "Cannot find cut result"; + return false; } template< typename XCutType > - KTCutResult& KTCutStatus::GetCutResult() + inline void KTCutStatus::RemoveCutResult(bool doUpdateStatus) { - if (HasCutResult< XCutType >()) - { - return fCutResults.get()->Of< XCutType >(); - } - throw KTException() << "Cannot find cut result"; + auto cutIt = FindCutResult< XCutType >(); + if (cutIt != fCutResults.end()) fCutResults.erase(cutIt); + if (doUpdateStatus) UpdateStatus(); + return; } - template< typename XCutType > - inline void KTCutStatus::RemoveCutResult(bool doUpdateStatus) + inline void KTCutStatus::RemoveCutResult(const std::string& name, bool doUpdateStatus) { - delete fCutResults.get()->Detatch< XCutType >(); + auto cutIt = FindCutResult(name); + if (cutIt != fCutResults.end()) fCutResults.erase(cutIt); if (doUpdateStatus) UpdateStatus(); return; } diff --git a/Library/Data/KTData.cc b/Library/Data/KTData.cc index 9294aab..9cc427c 100644 --- a/Library/Data/KTData.cc +++ b/Library/Data/KTData.cc @@ -19,6 +19,10 @@ namespace Nymph fName() {} + KTDataRider::KTDataRider( const KTDataRider& orig ) : + fName( orig.fName ) + {} + KTDataRider::~KTDataRider() {} diff --git a/Library/Data/KTData.hh b/Library/Data/KTData.hh index 330e840..3e8f34e 100644 --- a/Library/Data/KTData.hh +++ b/Library/Data/KTData.hh @@ -38,6 +38,7 @@ namespace Nymph { public: KTDataRider(); + KTDataRider( const KTDataRider& orig ); virtual ~KTDataRider(); MEMBERVARIABLE_REF( std::string, Name ); @@ -62,7 +63,9 @@ namespace Nymph public: KTExtensibleDataRider() = delete; KTExtensibleDataRider( const std::string& name ) { KTDataRider::fName = name; } + KTExtensibleDataRider( const KTExtensibleDataRider< XDerivedType >& orig ) : KTExtensibleStruct< XDerivedType, KTDataRider >( *this ) {} virtual ~KTExtensibleDataRider() {} + /* template< class Archive > void serialize( Archive& ar ) @@ -78,8 +81,14 @@ namespace Nymph { \ public: \ ex_data_class_name() : data_class_name(), KTExtensibleDataRider< ex_data_class_name >( label ) {} \ + ex_data_class_name( const ex_data_class_name& orig ) : data_class_name( *this ), KTExtensibleDataRider< ex_data_class_name >( *this ) {} \ virtual ~ex_data_class_name() {} \ \ + std::shared_ptr< KTExtensibleStructCore< KTDataRider > > Clone() const \ + { \ + std::shared_ptr< ex_data_class_name > copy = std::make_shared< ex_data_class_name >( *this ); \ + return std::static_pointer_cast< KTExtensibleStructCore< KTDataRider >, ex_data_class_name >( copy ); \ + } \ }; /* diff --git a/Library/Utility/KTExtensibleStruct.hh b/Library/Utility/KTExtensibleStruct.hh index c439d6a..f2dc0c2 100644 --- a/Library/Utility/KTExtensibleStruct.hh +++ b/Library/Utility/KTExtensibleStruct.hh @@ -26,7 +26,8 @@ namespace Nymph struct KTExtensibleStructCore : public XBaseType { public: - typedef std::shared_ptr< XBaseType > BasePtr; + typedef KTExtensibleStructCore< XBaseType > BasePtrType; + typedef std::shared_ptr< BasePtrType > BasePtr; public: /// Default constructor @@ -53,7 +54,7 @@ namespace Nymph /// Duplicates the extended object virtual BasePtr Clone() const = 0; /// Duplicates object only - virtual void Pull( const KTExtensibleStructCore< XBaseType >& object ) = 0; + virtual void Pull( const BasePtrType& object ) = 0; /// Returns the pointer to the next field BasePtr Next() const; /// Returns the pointer to the previous field @@ -80,6 +81,7 @@ namespace Nymph struct KTExtensibleStruct : KTExtensibleStructCore< XBaseType > { public: + typedef typename KTExtensibleStructCore< XBaseType >::BasePtrType BasePtrType; typedef typename KTExtensibleStructCore< XBaseType >::BasePtr BasePtr; public: @@ -93,7 +95,7 @@ namespace Nymph /// Duplicates the extended object virtual BasePtr Clone() const; /// Duplicates object only - virtual void Pull( const KTExtensibleStructCore< XBaseType >& object ); + virtual void Pull( const BasePtrType& object ); void SetIsCopyDisabled( bool flag ); private: bool fIsCopyDisabled; @@ -170,7 +172,7 @@ namespace Nymph if (! fNext) { fNext = std::make_shared< XStructType >(); - fNext->fPrev.reset( const_cast< KTExtensibleStructCore< XBaseType >* >(this) ); + fNext->fPrev.reset( const_cast< BasePtrType* >(this) ); } return fNext->template Of(); @@ -272,7 +274,7 @@ namespace Nymph void KTExtensibleStruct::serialize( Archive& ar ) { std::cout << "### serialize for " << typeid(XBaseType).name() << std::endl; - ar( cereal::base_class< KTExtensibleStructCore< XBaseType > >( this ), fIsCopyDisabled ); + ar( cereal::base_class< BasePtrType >( this ), fIsCopyDisabled ); return; } @@ -299,7 +301,7 @@ namespace Nymph if (object.fNext) { - this->fNext.reset( object.fNext->Clone() ); + this->fNext = object.fNext->Clone(); } } @@ -317,7 +319,7 @@ namespace Nymph if (object.fNext) { this->fNext = object.fNext->Clone(); - this->KTExtensibleStructCore< XBaseType >::SetPrevPtrInNext(); + this->BasePtrType::SetPrevPtrInNext(); //this->fNext->fPrev = this; } @@ -329,18 +331,20 @@ namespace Nymph { // assume CRTP is used properly, // otherwise compiling fails here (intended behavior) - BasePtr instance = std::make_shared< XBaseType >( XInstanceType(dynamic_cast(*this)) ); + typedef KTExtensibleStruct< XInstanceType, XBaseType > InstancePtrType; + typedef std::shared_ptr< InstancePtrType > InstancePtr; + InstancePtr instance = std::make_shared< InstancePtrType >( XInstanceType(dynamic_cast(*this)) ); if (this->fNext) { - instance->fNext.reset( this->fNext->Clone() ); + instance->fNext = this->fNext->Clone(); instance->SetPrevPtrInNext(); //instance->fNext->fPrev = instance->fNext; } - return instance; + return std::static_pointer_cast< BasePtrType, InstancePtrType >( instance ); } template - void KTExtensibleStruct::Pull(const KTExtensibleStructCore& object) + void KTExtensibleStruct::Pull(const BasePtrType& object) { if (&object == this) { From b0f3c7c365097958b722cf673022e1f1641cca0f Mon Sep 17 00:00:00 2001 From: cclaessens Date: Fri, 9 Feb 2018 13:36:04 +0100 Subject: [PATCH 093/521] It works! KTWrapProcessor can be used as base class in python and added to the processor toolbox. Methods can be overwritten in python and called by the slot function. --- Executables/Validation/TestWrapProcessor.py | 21 ++++++++++++--------- Library/NymphPybind.cc | 2 +- Library/Processor/KTProcessorPybind.hh | 4 ++++ 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/Executables/Validation/TestWrapProcessor.py b/Executables/Validation/TestWrapProcessor.py index fd53b8b..d05fe79 100644 --- a/Executables/Validation/TestWrapProcessor.py +++ b/Executables/Validation/TestWrapProcessor.py @@ -8,23 +8,26 @@ import py_nymph_validation as nv class WrappedProcessor(nymph.WrapProcessor): - def __init__(self): - super(WrappedProcessor, self).__init__() +# def WrapFunction(self, x): +# self.fThreshold = 0 +# print("Hey, I'm a python processor. And by the way: fThreshold is {}".format(self.fThreshold)) pass +print("Making instace in python of class WrappedProcessor that inherits from nymph.WrapProcessor") +p = WrappedProcessor() + +print("Overwriting WrapFunction that will be called from the slot function") +p.WrapFunction = lambda x: print("Hey, I'm a python processor. And by the way: fThreshold is {}".format(p.fThreshold)) +print("Adding a new variable to the processor") +p.fThreshold = 6 + +print('property fThreshold from python processor is {}'.format(p.fThreshold)) ptb = nymph.KTProcessorToolbox('pt') print('Configuring') ptb.AddProcessor('test-p-proc', 'tpp') -#ptb.AddProcessor('test-proc-b', 'tp') - -p = WrappedProcessor() -p.WrapFunction = lambda x: print("Hey, I'm python") -print('type of WrappedProcessor in python is: {}'.format( type(p))) - - ptb.AddProcessor('bwp', p) ptb.MakeConnection('tpp:the-signal', 'bwp:wrap-slot') diff --git a/Library/NymphPybind.cc b/Library/NymphPybind.cc index d3397ac..e569bba 100644 --- a/Library/NymphPybind.cc +++ b/Library/NymphPybind.cc @@ -18,7 +18,7 @@ PYBIND11_MODULE( py_nymph, mod ) pybind11::class_< Nymph::KTProcessor, std::shared_ptr>( mod, "KTProcessor" ); - pybind11::class_ wrap_processor(mod, "WrapProcessor"); + pybind11::class_> wrap_processor(mod, "WrapProcessor", pybind11::dynamic_attr()); wrap_processor .def(pybind11::init<>()) .def("WrapFunction", &Nymph::KTWrapProcessor::WrapFunction) diff --git a/Library/Processor/KTProcessorPybind.hh b/Library/Processor/KTProcessorPybind.hh index 8cccc6f..e82faf2 100644 --- a/Library/Processor/KTProcessorPybind.hh +++ b/Library/Processor/KTProcessorPybind.hh @@ -63,6 +63,10 @@ namespace Nymph // Trampoline (need one for each virtual function) void WrapFunction(int input) override { + // I dont know what these two lines do, + // but at least the first one is necessary or nymph hangs when calling this as python method + pybind11::gil_scoped_release release; + pybind11::gil_scoped_acquire acquire; PYBIND11_OVERLOAD_PURE( void, // Return type KTWrapProcessor, // Parent class From a5b7ff2cb4dbb6ba479bdeaca57b5caef9c1248c Mon Sep 17 00:00:00 2001 From: cclaessens Date: Fri, 9 Feb 2018 13:57:23 +0100 Subject: [PATCH 094/521] Configure method can be overwritten too. --- Executables/Validation/TestWrapProcessor.py | 34 +++++++++++++-------- 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/Executables/Validation/TestWrapProcessor.py b/Executables/Validation/TestWrapProcessor.py index d05fe79..75337ad 100644 --- a/Executables/Validation/TestWrapProcessor.py +++ b/Executables/Validation/TestWrapProcessor.py @@ -8,32 +8,42 @@ import py_nymph_validation as nv class WrappedProcessor(nymph.WrapProcessor): -# def WrapFunction(self, x): -# self.fThreshold = 0 -# print("Hey, I'm a python processor. And by the way: fThreshold is {}".format(self.fThreshold)) pass -print("Making instace in python of class WrappedProcessor that inherits from nymph.WrapProcessor") +print("\nMaking instace in python of class WrappedProcessor that inherits from nymph.WrapProcessor.\n") p = WrappedProcessor() -print("Overwriting WrapFunction that will be called from the slot function") -p.WrapFunction = lambda x: print("Hey, I'm a python processor. And by the way: fThreshold is {}".format(p.fThreshold)) - -print("Adding a new variable to the processor") -p.fThreshold = 6 -print('property fThreshold from python processor is {}'.format(p.fThreshold)) ptb = nymph.KTProcessorToolbox('pt') print('Configuring') - ptb.AddProcessor('test-p-proc', 'tpp') ptb.AddProcessor('bwp', p) ptb.MakeConnection('tpp:the-signal', 'bwp:wrap-slot') - ptb.PushBackToRunQueue('tpp') + +print("\nBefore running: Overwrite WrapFunction that will be called from the slot function.\n") +p.WrapFunction = lambda x: print("Hey, I'm a python processor. And by the way: fThreshold is {}".format(p.fThreshold)) + + +print("Add a new variable to the processor.\n") +p.fThreshold = 6 +print('Property fThreshold from python processor is {}.\n'.format(p.fThreshold)) + + +print('Define new Configure method to set self.fThreshold.\n') +def Configure(self, a): + print('In Configure: Setting new fThreshold.\n') + self.fThreshold = a + +p.Configure = Configure +p.Configure(p, 7) + + + + print('Running') ptb.Run() From 1e82c9675a39d968c9e90e014c648fc383c89f99 Mon Sep 17 00:00:00 2001 From: cclaessens Date: Fri, 9 Feb 2018 14:09:21 +0100 Subject: [PATCH 095/521] Removed commented processors for pybind from KTTestProcessors, KTPyTestClassPybind.hh and NymphValidationPybind.cc --- Executables/Validation/KTPyTestClassPybind.hh | 26 ---------------- Executables/Validation/KTTestProcessor.cc | 31 ------------------- Executables/Validation/KTTestProcessor.hh | 19 ------------ .../Validation/NymphValidationPybind.cc | 8 ----- 4 files changed, 84 deletions(-) diff --git a/Executables/Validation/KTPyTestClassPybind.hh b/Executables/Validation/KTPyTestClassPybind.hh index e016939..459ecce 100644 --- a/Executables/Validation/KTPyTestClassPybind.hh +++ b/Executables/Validation/KTPyTestClassPybind.hh @@ -23,30 +23,4 @@ namespace Nymph ; }; -/* class KTPyWrapProcessor: public KTWrapProcessor - { - public: - // Inherit the constructors - using KTWrapProcessor::KTWrapProcessor; - - // Trampoline (need one for each virtual function) - void WrapFunction(int input) override { - PYBIND11_OVERLOAD_PURE( - void, // Return type - KTWrapProcessor, // Parent class - WrapFunction, // Name of function in C++ (must match Python name) - input // Argument(s) - ); - } - bool Configure(const scarab::param_node& node) override { - PYBIND11_OVERLOAD( - bool, // Return type - KTWrapProcessor, // Parent class - Configure, // Name of function in C++ (must match Python name) - node // Argument(s) - ); - } - };*/ - - } /* namespace Nymph */ diff --git a/Executables/Validation/KTTestProcessor.cc b/Executables/Validation/KTTestProcessor.cc index cd151cd..f045160 100644 --- a/Executables/Validation/KTTestProcessor.cc +++ b/Executables/Validation/KTTestProcessor.cc @@ -180,35 +180,4 @@ namespace Nymph return; } - /* KT_REGISTER_PROCESSOR(KTWrapProcessor, "base-wrap-proc"); - - KTWrapProcessor::KTWrapProcessor( const std::string& name ) : - KTProcessor( name ), - fSlot("wrap-slot", this, &KTWrapProcessor::SlotFunc) - - { - } - - KTWrapProcessor::~KTWrapProcessor() - { - } - - bool KTWrapProcessor::Configure(const scarab::param_node&) - { - return true; - } - - void KTWrapProcessor::SlotFunc(int input) - { - KTINFO(testsiglog, "Calling wrap function "); - this->WrapFunction(input); - return; - } - - void KTWrapProcessor::WrapFunction(int input) - { - KTINFO(testsiglog, "Hey, I'm base class"); - return; - }*/ - } /* namespace Nymph */ diff --git a/Executables/Validation/KTTestProcessor.hh b/Executables/Validation/KTTestProcessor.hh index d14930f..c274ee9 100644 --- a/Executables/Validation/KTTestProcessor.hh +++ b/Executables/Validation/KTTestProcessor.hh @@ -10,8 +10,6 @@ #include "KTProcessor.hh" #include "KTSlot.hh" -//#include "pybind11/pybind11.h" - //using namespace py; @@ -130,22 +128,5 @@ namespace Nymph KTSignalData fDerived2DataSignal; }; - - /* class KTWrapProcessor : public KTProcessor - { - public: - KTWrapProcessor( const std::string& name = "base-wrap-proc" ); - virtual ~KTWrapProcessor(); - - bool Configure(const scarab::param_node& node); - - void SlotFunc(int); - virtual void WrapFunction(int input); - - private: - KTSlot< int > fSlot; - - };*/ - } /* namespace Nymph */ #endif /* KTTESTPROCESSOR_HH_ */ diff --git a/Executables/Validation/NymphValidationPybind.cc b/Executables/Validation/NymphValidationPybind.cc index 2c4281e..f281181 100644 --- a/Executables/Validation/NymphValidationPybind.cc +++ b/Executables/Validation/NymphValidationPybind.cc @@ -15,14 +15,6 @@ PYBIND11_MODULE( py_nymph_validation, mod ) Nymph::ExportKTPyTestClass( mod ); Nymph::ExportTestPythonBasics( mod ); - /*pybind11::class_ wrap_processor(mod, "WrapProcessor"); - wrap_processor - .def(pybind11::init<>()) - .def("WrapFunction", &Nymph::KTWrapProcessor::WrapFunction) - .def("Configure", &Nymph::KTWrapProcessor::Configure); -*/ - //pybind11::class_< Nymph::KTProcessor, std::shared_ptr>( mod, "KTProcessor" ); - } From 54604a21d62bf26a26de134ef3ccf1dfc939264c Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Fri, 9 Feb 2018 14:01:59 -0800 Subject: [PATCH 096/521] Better cut setup. Compiles but test programs segfault. --- Executables/Validation/KTTestCuts.cc | 12 +- Executables/Validation/KTTestCuts.hh | 12 -- Executables/Validation/TestApplyCut.cc | 30 ++-- Executables/Validation/TestCut.cc | 33 +++-- Executables/Validation/TestCutFilter.cc | 30 ++-- Library/Application/KTPrintDataStructure.cc | 13 +- Library/Data/KTCut.hh | 5 +- Library/Data/KTCutResult.hh | 33 +---- Library/Data/KTCutStatus.cc | 54 +++---- Library/Data/KTCutStatus.hh | 153 ++++++++++---------- 10 files changed, 171 insertions(+), 204 deletions(-) diff --git a/Executables/Validation/KTTestCuts.cc b/Executables/Validation/KTTestCuts.cc index 345ed5f..e486445 100644 --- a/Executables/Validation/KTTestCuts.cc +++ b/Executables/Validation/KTTestCuts.cc @@ -14,11 +14,8 @@ namespace Nymph { KTLOGGER(testlog, "KTTestCuts"); - const std::string KTAwesomeCut::Result::sName = "awesome-cut"; - const std::string KTNotAwesomeCut::Result::sName = "not-awesome-cut"; - - KT_REGISTER_CUT(KTAwesomeCut); - KT_REGISTER_CUT(KTNotAwesomeCut); + KT_REGISTER_CUT(KTAwesomeCut, "awesome-cut"); + KT_REGISTER_CUT(KTNotAwesomeCut, "not-awesome-cut"); KTAwesomeCut::KTAwesomeCut(const std::string& name) : @@ -40,7 +37,7 @@ namespace Nymph bool isCut = ! testData.GetIsAwesome(); KTDEBUG(testlog, "Is data awesome? " << testData.GetIsAwesome()); KTDEBUG(testlog, "Is data cut? " << isCut); - data.CutStatus().AddCutResult< KTAwesomeCut::Result >(isCut); + data.CutStatus().SetCutState(fConfigName, isCut); return isCut; } @@ -64,8 +61,7 @@ namespace Nymph bool isCut = testData.GetIsAwesome(); KTDEBUG(testlog, "Is data awesome? " << testData.GetIsAwesome()); KTDEBUG(testlog, "Is data cut? " << isCut); - // use the name-based AddCutResult - data.CutStatus().AddCutResult("not-awesome-cut", isCut); + data.CutStatus().SetCutState(fConfigName, isCut); return isCut; } diff --git a/Executables/Validation/KTTestCuts.hh b/Executables/Validation/KTTestCuts.hh index 6fc12e6..5ebe0d6 100644 --- a/Executables/Validation/KTTestCuts.hh +++ b/Executables/Validation/KTTestCuts.hh @@ -21,12 +21,6 @@ namespace Nymph // Cuts data that is NOT awesome class KTAwesomeCut : public KTCutOnData< KTTestDataExt > { - public: - struct Result : KTExtensibleCutResult< Result > - { - static const std::string sName; - }; - public: KTAwesomeCut(const std::string& name = "default-awesome-cut"); virtual ~KTAwesomeCut(); @@ -39,12 +33,6 @@ namespace Nymph // Cuts data that is IS awesome class KTNotAwesomeCut : public KTCutOnData< KTTestDataExt > { - public: - struct Result : KTExtensibleCutResult< Result > - { - static const std::string sName; - }; - public: KTNotAwesomeCut(const std::string& name = "default-not-awesome-cut"); virtual ~KTNotAwesomeCut(); diff --git a/Executables/Validation/TestApplyCut.cc b/Executables/Validation/TestApplyCut.cc index c3fe237..8998ac9 100644 --- a/Executables/Validation/TestApplyCut.cc +++ b/Executables/Validation/TestApplyCut.cc @@ -22,6 +22,12 @@ int main() KTTestData& testData = dataHandle->Of< KTTestDataExt >(); KTCutStatus& cutStatus = dataHandle->CutStatus(); + unsigned awesomeCutPos = 0; + string awesomeCutName("awesome-cut"); + unsigned notAwesomeCutPos = 1; + string notAwesomeCutName("not-awesome-cut"); + cutStatus.AssignCutResult(awesomeCutPos, awesomeCutName); + cutStatus.AssignCutResult(notAwesomeCutPos, notAwesomeCutName); KTINFO(testlog, "Initial cut state: " << cutStatus.IsCut()); KTApplyCut applyCut; @@ -31,10 +37,10 @@ int main() applyCut.ApplyCut(dataHandle); KTINFO(testlog, "Cuts present: " << cutStatus.CutResultsPresent()) - KTINFO(testlog, "Has cut result \"awesome-cut\"? " << cutStatus.HasCutResult("awesome-cut")); - KTINFO(testlog, "Has cut result ? " << cutStatus.HasCutResult< KTAwesomeCut::Result >()); - KTINFO(testlog, "Cut state of \"awesome-cut\" is: " << cutStatus.GetCutState("awesome-cut")); - KTINFO(testlog, "Cut state of is: " << cutStatus.GetCutState< KTAwesomeCut::Result >()); + KTINFO(testlog, "Has cut result <" << awesomeCutName << ">? " << cutStatus.HasCutResult(awesomeCutName)); + KTINFO(testlog, "Has cut result at " << awesomeCutPos << "? " << cutStatus.HasCutResult(awesomeCutPos)); + KTINFO(testlog, "Cut state of <" << awesomeCutName << ">is: " << cutStatus.GetCutState(awesomeCutName)); + KTINFO(testlog, "Cut state at " << awesomeCutPos << " is: " << cutStatus.GetCutState(awesomeCutPos)); KTINFO(testlog, "Is cut (all results)? " << cutStatus.IsCut()); KTINFO(testlog, "Is cut (with mask \"0\")? " << cutStatus.IsCut("0")); @@ -43,14 +49,14 @@ int main() applyCut.ApplyCut(dataHandle); KTINFO(testlog, "Cuts present: " << cutStatus.CutResultsPresent()) - KTINFO(testlog, "Has cut result \"awesome-cut\"? " << cutStatus.HasCutResult("awesome-cut")); - KTINFO(testlog, "Has cut result ? " << cutStatus.HasCutResult< KTAwesomeCut::Result >()); - KTINFO(testlog, "Cut state of \"awesome-cut\" is: " << cutStatus.GetCutState("awesome-cut")); - KTINFO(testlog, "Cut state of is: " << cutStatus.GetCutState< KTAwesomeCut::Result >()); - KTINFO(testlog, "Has cut result \"not-awesome-cut\"? " << cutStatus.HasCutResult("not-awesome-cut")); - KTINFO(testlog, "Has cut result ? " << cutStatus.HasCutResult< KTNotAwesomeCut::Result >()); - KTINFO(testlog, "Cut state of \"not-awesome-cut\" is: " << cutStatus.GetCutState("not-awesome-cut")); - KTINFO(testlog, "Cut state of is: " << cutStatus.GetCutState< KTNotAwesomeCut::Result >()); + KTINFO(testlog, "Has cut result <" << awesomeCutName << ">? " << cutStatus.HasCutResult(awesomeCutName)); + KTINFO(testlog, "Has cut result at " << awesomeCutPos << "? " << cutStatus.HasCutResult(awesomeCutPos)); + KTINFO(testlog, "Cut state of <" << awesomeCutName << "> is: " << cutStatus.GetCutState(awesomeCutName)); + KTINFO(testlog, "Cut state at " << awesomeCutPos << " is: " << cutStatus.GetCutState(awesomeCutPos)); + KTINFO(testlog, "Has cut result <" << notAwesomeCutName << ">? " << cutStatus.HasCutResult(notAwesomeCutName)); + KTINFO(testlog, "Has cut result at " << notAwesomeCutPos << "? " << cutStatus.HasCutResult(notAwesomeCutPos)); + KTINFO(testlog, "Cut state of <" << notAwesomeCutName << "> is: " << cutStatus.GetCutState(notAwesomeCutName)); + KTINFO(testlog, "Cut state at " << notAwesomeCutPos << " is: " << cutStatus.GetCutState(notAwesomeCutPos)); KTINFO(testlog, "Is cut (all results)? " << cutStatus.IsCut()); KTINFO(testlog, "Is cut with mask \"00\"? " << cutStatus.IsCut("00")); KTINFO(testlog, "Is cut with mask \"01\"? " << cutStatus.IsCut("01")); diff --git a/Executables/Validation/TestCut.cc b/Executables/Validation/TestCut.cc index 0e4403e..ac9f6a0 100644 --- a/Executables/Validation/TestCut.cc +++ b/Executables/Validation/TestCut.cc @@ -21,6 +21,15 @@ int main() KTTestDataExt& testData = data.Of< KTTestDataExt >(); KTCutStatus& cutStatus = data.CutStatus(); + + KTINFO(testlog, "Assigning cuts"); + unsigned awesomeCutPos = 0; + string awesomeCutName("awesome-cut"); + unsigned notAwesomeCutPos = 1; + string notAwesomeCutName("not-awesome-cut"); + cutStatus.AssignCutResult(awesomeCutPos, awesomeCutName); + cutStatus.AssignCutResult(notAwesomeCutPos, notAwesomeCutName); + KTINFO(testlog, "Initial cut state: " << cutStatus.IsCut()); KTINFO(testlog, "Applying awesome cut"); @@ -28,10 +37,10 @@ int main() cut.Apply(data, testData); KTINFO(testlog, "Cuts present: " << cutStatus.CutResultsPresent()) - KTINFO(testlog, "Has cut result \"awesome-cut\"? " << cutStatus.HasCutResult("awesome-cut")); - KTINFO(testlog, "Has cut result ? " << cutStatus.HasCutResult< KTAwesomeCut::Result >()); - KTINFO(testlog, "Cut state of \"awesome-cut\" is: " << cutStatus.GetCutState("awesome-cut")); - KTINFO(testlog, "Cut state of is: " << cutStatus.GetCutState< KTAwesomeCut::Result >()); + KTINFO(testlog, "Has cut result <" << awesomeCutName << ">? " << cutStatus.HasCutResult(awesomeCutName)); + KTINFO(testlog, "Has cut result at " << awesomeCutPos << "? " << cutStatus.HasCutResult(awesomeCutPos)); + KTINFO(testlog, "Cut state of <" << awesomeCutName << ">is: " << cutStatus.GetCutState(awesomeCutName)); + KTINFO(testlog, "Cut state at " << awesomeCutPos << " is: " << cutStatus.GetCutState(awesomeCutPos)); KTINFO(testlog, "Is cut (all results)? " << cutStatus.IsCut()); KTINFO(testlog, "Is cut (with mask \"0\")? " << cutStatus.IsCut("0")); @@ -40,14 +49,14 @@ int main() naCut.Apply(data, testData); KTINFO(testlog, "Cuts present: " << cutStatus.CutResultsPresent()) - KTINFO(testlog, "Has cut result \"awesome-cut\"? " << cutStatus.HasCutResult("awesome-cut")); - KTINFO(testlog, "Has cut result ? " << cutStatus.HasCutResult< KTAwesomeCut::Result >()); - KTINFO(testlog, "Cut state of \"awesome-cut\" is: " << cutStatus.GetCutState("awesome-cut")); - KTINFO(testlog, "Cut state of is: " << cutStatus.GetCutState< KTAwesomeCut::Result >()); - KTINFO(testlog, "Has cut result \"not-awesome-cut\"? " << cutStatus.HasCutResult("not-awesome-cut")); - KTINFO(testlog, "Has cut result ? " << cutStatus.HasCutResult< KTNotAwesomeCut::Result >()); - KTINFO(testlog, "Cut state of \"not-awesome-cut\" is: " << cutStatus.GetCutState("not-awesome-cut")); - KTINFO(testlog, "Cut state of is: " << cutStatus.GetCutState< KTNotAwesomeCut::Result >()); + KTINFO(testlog, "Has cut result <" << awesomeCutName << ">? " << cutStatus.HasCutResult(awesomeCutName)); + KTINFO(testlog, "Has cut result at " << awesomeCutPos << "? " << cutStatus.HasCutResult(awesomeCutPos)); + KTINFO(testlog, "Cut state of <" << awesomeCutName << "> is: " << cutStatus.GetCutState(awesomeCutName)); + KTINFO(testlog, "Cut state at " << awesomeCutPos << " is: " << cutStatus.GetCutState(awesomeCutPos)); + KTINFO(testlog, "Has cut result <" << notAwesomeCutName << ">? " << cutStatus.HasCutResult(notAwesomeCutName)); + KTINFO(testlog, "Has cut result at " << notAwesomeCutPos << "? " << cutStatus.HasCutResult(notAwesomeCutPos)); + KTINFO(testlog, "Cut state of <" << notAwesomeCutName << "> is: " << cutStatus.GetCutState(notAwesomeCutName)); + KTINFO(testlog, "Cut state at " << notAwesomeCutPos << " is: " << cutStatus.GetCutState(notAwesomeCutPos)); KTINFO(testlog, "Is cut (all results)? " << cutStatus.IsCut()); KTINFO(testlog, "Is cut with mask \"00\"? " << cutStatus.IsCut("00")); KTINFO(testlog, "Is cut with mask \"01\"? " << cutStatus.IsCut("01")); diff --git a/Executables/Validation/TestCutFilter.cc b/Executables/Validation/TestCutFilter.cc index 4b770cc..04a96df 100644 --- a/Executables/Validation/TestCutFilter.cc +++ b/Executables/Validation/TestCutFilter.cc @@ -23,6 +23,12 @@ int main() KTTestData& testData = dataHandle->Of< KTTestDataExt >(); KTCutStatus& cutStatus = dataHandle->CutStatus(); + unsigned awesomeCutPos = 0; + string awesomeCutName("awesome-cut"); + unsigned notAwesomeCutPos = 1; + string notAwesomeCutName("not-awesome-cut"); + cutStatus.AssignCutResult(awesomeCutPos, awesomeCutName); + cutStatus.AssignCutResult(notAwesomeCutPos, notAwesomeCutName); KTINFO(testlog, "Initial cut state: " << cutStatus.IsCut()); KTApplyCut applyCut; @@ -32,10 +38,10 @@ int main() applyCut.ApplyCut(dataHandle); KTINFO(testlog, "Cuts present: " << cutStatus.CutResultsPresent()) - KTINFO(testlog, "Has cut result \"awesome-cut\"? " << cutStatus.HasCutResult("awesome-cut")); - KTINFO(testlog, "Has cut result ? " << cutStatus.HasCutResult< KTAwesomeCut::Result >()); - KTINFO(testlog, "Cut state of \"awesome-cut\" is: " << cutStatus.GetCutState("awesome-cut")); - KTINFO(testlog, "Cut state of is: " << cutStatus.GetCutState< KTAwesomeCut::Result >()); + KTINFO(testlog, "Has cut result <" << awesomeCutName << ">? " << cutStatus.HasCutResult(awesomeCutName)); + KTINFO(testlog, "Has cut result at " << awesomeCutPos << "? " << cutStatus.HasCutResult(awesomeCutPos)); + KTINFO(testlog, "Cut state of <" << awesomeCutName << ">is: " << cutStatus.GetCutState(awesomeCutName)); + KTINFO(testlog, "Cut state at " << awesomeCutPos << " is: " << cutStatus.GetCutState(awesomeCutPos)); KTINFO(testlog, "Is cut (all results)? " << cutStatus.IsCut()); KTINFO(testlog, "Is cut (with mask \"0\")? " << cutStatus.IsCut("0")); @@ -44,14 +50,14 @@ int main() applyCut.ApplyCut(dataHandle); KTINFO(testlog, "Cuts present: " << cutStatus.CutResultsPresent()) - KTINFO(testlog, "Has cut result \"awesome-cut\"? " << cutStatus.HasCutResult("awesome-cut")); - KTINFO(testlog, "Has cut result ? " << cutStatus.HasCutResult< KTAwesomeCut::Result >()); - KTINFO(testlog, "Cut state of \"awesome-cut\" is: " << cutStatus.GetCutState("awesome-cut")); - KTINFO(testlog, "Cut state of is: " << cutStatus.GetCutState< KTAwesomeCut::Result >()); - KTINFO(testlog, "Has cut result \"not-awesome-cut\"? " << cutStatus.HasCutResult("not-awesome-cut")); - KTINFO(testlog, "Has cut result ? " << cutStatus.HasCutResult< KTNotAwesomeCut::Result >()); - KTINFO(testlog, "Cut state of \"not-awesome-cut\" is: " << cutStatus.GetCutState("not-awesome-cut")); - KTINFO(testlog, "Cut state of is: " << cutStatus.GetCutState< KTNotAwesomeCut::Result >()); + KTINFO(testlog, "Has cut result <" << awesomeCutName << ">? " << cutStatus.HasCutResult(awesomeCutName)); + KTINFO(testlog, "Has cut result at " << awesomeCutPos << "? " << cutStatus.HasCutResult(awesomeCutPos)); + KTINFO(testlog, "Cut state of <" << awesomeCutName << "> is: " << cutStatus.GetCutState(awesomeCutName)); + KTINFO(testlog, "Cut state at " << awesomeCutPos << " is: " << cutStatus.GetCutState(awesomeCutPos)); + KTINFO(testlog, "Has cut result <" << notAwesomeCutName << ">? " << cutStatus.HasCutResult(notAwesomeCutName)); + KTINFO(testlog, "Has cut result at " << notAwesomeCutPos << "? " << cutStatus.HasCutResult(notAwesomeCutPos)); + KTINFO(testlog, "Cut state of <" << notAwesomeCutName << "> is: " << cutStatus.GetCutState(notAwesomeCutName)); + KTINFO(testlog, "Cut state at " << notAwesomeCutPos << " is: " << cutStatus.GetCutState(notAwesomeCutPos)); KTCutFilter cutFilter; KTCoreDataExt& data = dataHandle->Of< KTCoreDataExt >(); diff --git a/Library/Application/KTPrintDataStructure.cc b/Library/Application/KTPrintDataStructure.cc index 749324e..d48aa52 100644 --- a/Library/Application/KTPrintDataStructure.cc +++ b/Library/Application/KTPrintDataStructure.cc @@ -83,7 +83,7 @@ namespace Nymph printbuf << "\nData Structure:\n"; printbuf << "\t- " << dataHandle->Name() << '\n'; KTDEBUG(datalog, "Found data type " << dataHandle->Name()); - KTExtensibleStructCore< KTDataRider >* nextData = dataHandle->Next(); + KTExtensibleStructCore< KTDataRider >::BasePtr nextData = dataHandle->Next(); while (nextData != NULL) { printbuf << "\t- " << nextData->Name() << '\n'; @@ -103,13 +103,14 @@ namespace Nymph KTCutStatus& cutStatus = dataHandle->CutStatus(); printbuf << "\n" << cutStatus; - const KTCutResult* cutResult = cutStatus.CutResults(); + const KTCutStatus::CutResults_t cutResults = cutStatus.CutResults(); printbuf << "Cut Structure:\n"; - while (cutResult != NULL) + unsigned nCuts = cutResults.size(); + for (unsigned iCut = 0; iCut < nCuts; ++iCut) { - printbuf << "\t- " << cutResult->Name() << " -- is cut: " << cutResult->GetState() << '\n'; - KTDEBUG(datalog, "Found cut type " << cutResult->Name()); - cutResult = cutResult->Next(); + if (! cutResults[iCut].fAssigned) continue; + printbuf << "\t" << iCut << " -- " << cutResults[iCut].fName << " -- is cut: " << cutResults[iCut].fState << '\n'; + KTDEBUG(datalog, "Found cut type " << cutResults[iCut].fName << " at mask position " << iCut); } KTINFO(datalog, printbuf.str()); diff --git a/Library/Data/KTCut.hh b/Library/Data/KTCut.hh index 4cd3d8f..753d83a 100644 --- a/Library/Data/KTCut.hh +++ b/Library/Data/KTCut.hh @@ -201,9 +201,8 @@ namespace Nymph // this macro enforces the existence of cut_class::Result and cut_class::Result::sName at compile time -#define KT_REGISTER_CUT(cut_class) \ - static ::scarab::registrar< ::Nymph::KTCut, cut_class, const std::string& > sCut##cut_class##Registrar( cut_class::Result::sName ); \ - static ::Nymph::KTExtensibleStructRegistrar< ::Nymph::KTCutResultCore, cut_class::Result > sCut##cut_class##ResultRegistrar( cut_class::Result::sName ); +#define KT_REGISTER_CUT(cut_class, cut_name) \ + static ::scarab::registrar< ::Nymph::KTCut, cut_class, const std::string& > sCut##cut_class##Registrar( cut_name ); } /* namespace Nymph */ diff --git a/Library/Data/KTCutResult.hh b/Library/Data/KTCutResult.hh index 666a147..dbc0438 100644 --- a/Library/Data/KTCutResult.hh +++ b/Library/Data/KTCutResult.hh @@ -8,47 +8,26 @@ #ifndef KTCUTRESULT_HH_ #define KTCUTRESULT_HH_ -//#include "KTExtensibleStruct.hh" - -//#include "KTMemberVariable.hh" - #include namespace Nymph { struct KTCutResult { + std::string fName; bool fState; - KTCutResult( bool state ) { fState = state; } - virtual ~KTCutResult() {} - virtual const std::string& Name() const = 0; + bool fAssigned; + KTCutResult() : fName(), fState( false ), fAssigned( false ) {} + KTCutResult( const std::string& name, bool state ) : fName( name ), fState( state ), fAssigned( true ) {} }; - template< class XCutType > - struct KTTypedCutResult : KTCutResult - { - KTTypedCutResult( bool state ) : KTCutResult( state ) {} - virtual ~KTTypedCutResult() {} - virtual const std::string& Name() const - { - return XCutType::GetName(); - } - }; - - template< class XCutType > - bool CheckCutResultType( std::shared_ptr< KTCutResult > result ) - { - return std::dynamic_pointer_cast< KTTypedCutResult< XCutType > >( result ); - - } - struct CheckCutResultName { std::string fName; CheckCutResultName( const std::string& name ) : fName( name ) {} - bool operator()( std::shared_ptr< KTCutResult > result ) + bool operator()( const KTCutResult& result ) { - return result->Name() == fName; + return result.fName == fName; } }; diff --git a/Library/Data/KTCutStatus.cc b/Library/Data/KTCutStatus.cc index 06e6873..d1c1f52 100644 --- a/Library/Data/KTCutStatus.cc +++ b/Library/Data/KTCutStatus.cc @@ -21,7 +21,7 @@ namespace Nymph } KTCutStatus::KTCutStatus(const KTCutStatus& orig) : - fCutResults(dynamic_cast< KTCutResultHandle* >(orig.fCutResults->Clone())), + fCutResults(orig.fCutResults), fSummary() { UpdateStatus(); @@ -32,37 +32,34 @@ namespace Nymph KTCutStatus& KTCutStatus::operator=(const KTCutStatus& rhs) { - fCutResults.reset(dynamic_cast< KTCutResultHandle* >(rhs.fCutResults->Clone())); + fCutResults = rhs.fCutResults; UpdateStatus(); return *this; } - void KTCutStatus::UpdateStatus() + void KTCutStatus::AssignCutResult(unsigned maskPos, const std::string& name, bool state, bool doUpdateStatus) { - KTDEBUG(cutlog, "Updating cut summary"); - KTCutResult* cut = fCutResults.get()->Next(); // skip over KTCutResultHandle - if (cut == NULL) + if( fCutResults[maskPos].fAssigned ) { - KTDEBUG(cutlog, "No cuts"); - fSummary.resize(1, false); - return; + throw KTException() << "Mask position <" << maskPos << "> has already been assigned"; } + fCutResults[maskPos].fName = name; + fCutResults[maskPos].fState = state; + fCutResults[maskPos].fAssigned = true; + if( doUpdateStatus ) UpdateStatus(); + return; + } - // loop through once to count cuts - unsigned nCuts = 0; - while (cut != NULL) - { - ++nCuts; - cut = cut->Next(); - } - KTDEBUG(cutlog, nCuts << " cuts"); + void KTCutStatus::UpdateStatus() + { + KTDEBUG(cutlog, "Updating cut summary"); + unsigned nCuts = fCutResults.size(); fSummary.resize(nCuts, false); - // loop through again to set cuts - cut = fCutResults.get()->Next(); // skip over KTCutResultHandle + + // loop through to set cuts for (unsigned iCut = 0; iCut < nCuts; ++iCut) { - fSummary[iCut] = cut->GetState(); - cut = cut->Next(); + fSummary[iCut] = fCutResults[iCut].fAssigned && fCutResults[iCut].fState; } KTDEBUG(cutlog, "Cut summary bitset: " << fSummary); return; @@ -70,20 +67,13 @@ namespace Nymph std::string KTCutStatus::CutResultsPresent() const { - KTCutResult* cut = fCutResults.get()->Next(); // skip over KTCutResultHandle - if (cut == NULL ) return ""; - std::string cutsPresent; for (auto cutIt = fCutResults.cbegin(); cutIt != fCutResults.cend(); ++cutIt) { - cutsPresent = cutIt->Name() + cutsPresent; - } - while (true) - { - cutsPresent = cut->Name() + cutsPresent; - cut = cut->Next(); - if (cut != NULL) cutsPresent = " " + cutsPresent; - else break; + if (! cutIt->fName.empty()) + { + cutsPresent = cutIt->fName + " " + cutsPresent; + } } return cutsPresent; } diff --git a/Library/Data/KTCutStatus.hh b/Library/Data/KTCutStatus.hh index cf9d7b9..2f69f08 100644 --- a/Library/Data/KTCutStatus.hh +++ b/Library/Data/KTCutStatus.hh @@ -59,8 +59,7 @@ namespace Nymph public: typedef boost::dynamic_bitset< > bitset_type; - typedef std::shared_ptr< KTCutResult > CutResultPtr; - typedef std::vector< CutResultPtr > CutResults_t; + typedef std::vector< KTCutResult > CutResults_t; typedef CutResults_t::iterator CutResultsIt; typedef CutResults_t::const_iterator CutResultsCIt; @@ -72,46 +71,48 @@ namespace Nymph KTCutStatus& operator=(const KTCutStatus& rhs); + /// Returns the size of the cut results vector + size_t size() const; + + /// Returns a reference to the cut results vector const CutResults_t& CutResults() const; + /// Updates the summary bitset from the cut results vector void UpdateStatus(); - template< typename XCutType > - bool AddCutResult(bool state, bool doUpdateStatus=true); - template< typename XCutType > - bool AddCutResult(const XCutType& cut, bool state, bool doUpdateStatus=true); + /// Adds a new cut result if it doesn't exist, and assigns the specified name and state at maskPos; throws KTException if maskPos is already assigned + void AssignCutResult(unsigned maskPos, const std::string& name, bool state=false, bool doUpdateStatus=true); - template< typename XCutType > - CutResultsIt FindCutResult(); - CutResultsIt FindCutResult(const std::string& cutName); + /// Removes the cut by erasing the name and setting the state to false + void RemoveCutResult(const std::string& cutName, bool doUpdateStatus=true); + /// Removes the cut by erasing the name and setting the state to false + void RemoveCutResult(unsigned maskPos, bool doUpdateStatus=true); - template< typename XCutType > - CutResultsCIt FindCutResultC() const; + CutResultsIt FindCutResult(const std::string& cutName); CutResultsCIt FindCutResultC(const std::string& cutName) const; CutResultsIt CutResultsEnd(); CutResultsCIt CutResultsEndC() const; - template< typename XCutType > - bool HasCutResult() const; + /// Returns whether or not the specified cut is present bool HasCutResult(const std::string& cutName) const; + /// Returns whether or not the specified cut is present (whether or not it has been explicitly assigned) + bool HasCutResult(unsigned maskPos) const; - template< typename XCutType > - bool GetCutState() const; + /// Returns the state of the named cut; throws KTException if it doesn't exist bool GetCutState(const std::string& cutName) const; + /// Returns the state of the specified cut; throws KTException if it doesn't exist + bool GetCutState(unsigned maskPos) const; - template< typename XCutType > - bool SetCutState(bool state, bool doUpdateStatus=true); - bool SetCutState(const std::string& cutName, bool state, bool doUpdateStatus=true); - - template< typename XCutType > - void RemoveCutResult(bool doUpdateStatus=true); - void RemoveCutResult(const std::string& cutName, bool doUpdateStatus=true); + /// Sets the state of the specified cut; throws KTException if it doesn't exist + void SetCutState(const std::string& cutName, bool state, bool doUpdateStatus=true); + /// Sets the state of the specified cut; throws KTException if it doesn't exist + void SetCutState(unsigned maskPos, bool state, bool doUpdateStatus=true); /// Returns a string with the names of the cuts that are present in bitset order std::string CutResultsPresent() const; - size_t size() const; + private: friend std::ostream& operator<<(std::ostream& out, const KTCutStatus& status); @@ -138,49 +139,15 @@ namespace Nymph return fCutResults; } - template< typename XCutType > - bool KTCutStatus::AddCutResult(bool state, bool doUpdateStatus) - { - if (! HasCutResult< XCutType >()) - { - fCutResults.emplace_back( state ); - if (doUpdateStatus) UpdateStatus(); - return true; - } - return false; - } - - template< typename XCutType > - bool KTCutStatus::AddCutResult(const XCutType&, bool state, bool doUpdateStatus) - { - if (! HasCutResult< XCutType >()) - { - fCutResults.emplace_back( state ); - if (doUpdateStatus) UpdateStatus(); - return true; - } - return false; - } - - template< typename XCutType > - inline KTCutStatus::CutResultsIt KTCutStatus::FindCutResult() - { - return std::find_if( fCutResults.begin(), fCutResults.end(), CheckCutResultType< XCutType > ); - } - inline KTCutStatus::CutResultsIt KTCutStatus::FindCutResult( const std::string& name ) { + if( name.empty() ) return fCutResults.end(); return std::find_if( fCutResults.begin(), fCutResults.end(), CheckCutResultName(name) ); } - template< typename XCutType > - inline KTCutStatus::CutResultsCIt KTCutStatus::FindCutResultC() const - { - return std::find_if( fCutResults.cbegin(), fCutResults.cend(), CheckCutResultType< XCutType > ); - } - inline KTCutStatus::CutResultsCIt KTCutStatus::FindCutResultC( const std::string& name ) const { + if( name.empty() ) return fCutResults.cend(); return std::find_if( fCutResults.cbegin(), fCutResults.cend(), CheckCutResultName(name) ); } @@ -194,51 +161,77 @@ namespace Nymph return fCutResults.cend(); } - template< typename XCutType > - inline bool KTCutStatus::HasCutResult() const + inline bool KTCutStatus::HasCutResult( const std::string& name ) const { - return FindCutResultC< XCutType >() != std::end(fCutResults); + return FindCutResultC(name) != std::end(fCutResults); } - inline bool KTCutStatus::HasCutResult( const std::string& name) const + inline bool KTCutStatus::HasCutResult( unsigned maskPos ) const { - return FindCutResultC(name) != std::end(fCutResults); + return maskPos < fCutResults.size() && fCutResults[maskPos].fAssigned; } - template< typename XCutType > - bool KTCutStatus::GetCutState() const + inline bool KTCutStatus::GetCutState( const std::string& name ) const { - auto cutIt = FindCutResult< XCutType >(); + CutResultsCIt cutIt = FindCutResultC(name); if (cutIt != fCutResults.cend()) { return cutIt->fState; } - return false; + throw KTException() << "Unable to find cut <" << name << ">"; } - bool KTCutStatus::GetCutState( const std::string& name ) const + inline bool KTCutStatus::GetCutState( unsigned maskPos ) const { - CutResultsCIt cutIt = FindCutResultC(name); - if (cutIt != fCutResults.cend()) + if (maskPos < fCutResults.size()) { - return (*cutIt)->fState; + return fCutResults[maskPos].fState; + } + throw KTException() << "Mask position <" << maskPos << "> is out of range (only " << size() << " cuts are present)"; + } + + inline void KTCutStatus::SetCutState(const std::string& name, bool state, bool doUpdateStatus) + { + CutResultsIt cutIt = FindCutResult(name); + if (cutIt != fCutResults.end()) + { + cutIt->fState = state; + if (doUpdateStatus) UpdateStatus(); + return; } - return false; + throw KTException() << "Unable to find cut <" << name << ">"; } - template< typename XCutType > - inline void KTCutStatus::RemoveCutResult(bool doUpdateStatus) + inline void KTCutStatus::SetCutState(unsigned maskPos, bool state, bool doUpdateStatus) { - auto cutIt = FindCutResult< XCutType >(); - if (cutIt != fCutResults.end()) fCutResults.erase(cutIt); + if (maskPos < fCutResults.size()) + { + fCutResults[maskPos].fState = state; + if (doUpdateStatus) UpdateStatus(); + return; + } + throw KTException() << "Mask position <" << maskPos << "> is out of range (only "<< size() << " cuts are present)"; + } + + inline void KTCutStatus::RemoveCutResult(const std::string& name, bool doUpdateStatus) + { + CutResultsIt cutIt = FindCutResult(name); + if (cutIt != fCutResults.end()) + { + cutIt->fName = ""; + cutIt->fState = false; + } if (doUpdateStatus) UpdateStatus(); return; } - inline void KTCutStatus::RemoveCutResult(const std::string& name, bool doUpdateStatus) + inline void KTCutStatus::RemoveCutResult(unsigned maskPos, bool doUpdateStatus) { - auto cutIt = FindCutResult(name); - if (cutIt != fCutResults.end()) fCutResults.erase(cutIt); + if (maskPos < fCutResults.size()) + { + fCutResults[maskPos].fName = ""; + fCutResults[maskPos].fState = false; + } if (doUpdateStatus) UpdateStatus(); return; } From d8e36eb665200d61afc8966f86e80fbabf23cb49 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Tue, 13 Feb 2018 17:49:12 -0800 Subject: [PATCH 097/521] Work on cuts. KTExtensibleStruct has issues, so I'm redeveloping in KTExtTest. --- Executables/Validation/CMakeLists.txt | 5 + Executables/Validation/KTExtTest.cc | 18 ++ Executables/Validation/KTExtTest.hh | 327 ++++++++++++++++++++++++++ Executables/Validation/KTTestCuts.cc | 2 +- Executables/Validation/KTTestData.cc | 8 +- Executables/Validation/TestCut.cc | 94 ++++---- Executables/Validation/TestData.cc | 25 ++ Executables/Validation/TestExt.cc | 78 ++++++ Library/Data/KTCoreData.cc | 5 +- Library/Data/KTCutStatus.cc | 6 + Library/Data/KTData.cc | 8 +- Library/Utility/KTExtensibleStruct.hh | 26 +- 12 files changed, 543 insertions(+), 59 deletions(-) create mode 100644 Executables/Validation/KTExtTest.cc create mode 100644 Executables/Validation/KTExtTest.hh create mode 100644 Executables/Validation/TestData.cc create mode 100644 Executables/Validation/TestExt.cc diff --git a/Executables/Validation/CMakeLists.txt b/Executables/Validation/CMakeLists.txt index d7ea68f..c15aa51 100644 --- a/Executables/Validation/CMakeLists.txt +++ b/Executables/Validation/CMakeLists.txt @@ -20,6 +20,8 @@ if (Nymph_ENABLE_TESTING) KTTestData.hh KTTestPrimaryProcessor.hh KTTestProcessor.hh + + KTExtTest.hh ) set (VALIDATION_SOURCEFILES @@ -54,6 +56,7 @@ if (Nymph_ENABLE_TESTING) TestCacheDirectory TestCut TestCutFilter + TestData TestExceptionInSlot TestJSONWriter TestLogger @@ -69,6 +72,8 @@ if (Nymph_ENABLE_TESTING) TestSlotData TestThroughputProfiler TestUseBreakpoint + + TestExt ) pbuilder_executables( TEST_PROGRAMS LIB_DEPENDENCIES ) diff --git a/Executables/Validation/KTExtTest.cc b/Executables/Validation/KTExtTest.cc new file mode 100644 index 0000000..69d59b1 --- /dev/null +++ b/Executables/Validation/KTExtTest.cc @@ -0,0 +1,18 @@ +/* + * KTExtTest.cc + * + * Created on: Feb 11, 2018 + * Author: N.S. Oblath + */ + +#include "KTExtTest.hh" + +#include + +namespace Nymph +{ + + + + +} /* namespace Nymph */ diff --git a/Executables/Validation/KTExtTest.hh b/Executables/Validation/KTExtTest.hh new file mode 100644 index 0000000..76fe6ff --- /dev/null +++ b/Executables/Validation/KTExtTest.hh @@ -0,0 +1,327 @@ +/* + * KTExtTest.hh + * + * Created on: Feb 11, 2018 + * Author: N.S. Oblath + */ + +#ifndef NYMPH_VALIDATION_KTEXTTEST_HH_ +#define NYMPH_VALIDATION_KTEXTTEST_HH_ + +#include "KTException.hh" + +#include +#include + +namespace Nymph +{ + + template< class XBaseType > + class KTExtensibleCore : public XBaseType, public std::enable_shared_from_this< KTExtensibleCore< XBaseType > > + { + private: + typedef std::enable_shared_from_this< KTExtensibleCore< XBaseType > > ESFTBaseType; + + public: + KTExtensibleCore(); + KTExtensibleCore( const KTExtensibleCore< XBaseType >& orig ) = delete; // deleted because copy of KTExtensibleCore is done using operator=() + virtual ~KTExtensibleCore(); + + /// Copies extended object + KTExtensibleCore& operator=( const KTExtensibleCore< XBaseType >& orig ); + + /// Copies the current object and only extended fields already present + virtual KTExtensibleCore& Pull( const KTExtensibleCore< XBaseType >& orig ) = 0; // implemented in KTExtensible because it requires knowing the extended field type + + /// Clones the extended object + virtual std::shared_ptr< KTExtensibleCore< XBaseType > > Clone() const = 0; // implemented in KTExtensible because it requires knowing the extended field type + + /// Returns the size of the extended object, including this field and any extended below it + unsigned size() const; + + /// Returns the object of the requested type or creates a new one if it's not present + template< class XRequestedType > + XRequestedType& Of(); + + /// Returns the object of the requested type or throws KTException if it's not present + template< class XRequestedType > + const XRequestedType& Of() const; + + /// Checks whether the requested type is present + template< class XRequestedType > + bool Has() const; + + /// Extracts the data object of the requested type if it's present; returns an empty pointer if not + /// Note that if you detatch the first field without holding a pointer to any other extended fields, those fields will be destroyed. + template< class XRequestedType > + std::shared_ptr< XRequestedType > Detatch(); + + protected: + template< class XRequestedType > + std::shared_ptr< XRequestedType > _Detatch( std::shared_ptr< KTExtensibleCore< XBaseType > > prev = std::shared_ptr< KTExtensibleCore< XBaseType > >() ); + //void SetPrevInNext( std::shared_ptr< KTExtensibleCore< XBaseType > > ptr ); + + //std::weak_ptr< KTExtensibleCore< XBaseType > > fPrev; + std::shared_ptr< KTExtensibleCore< XBaseType > > fNext; + + bool fDisableExtendedCopy; // internal variable used to determine whether operator= copies extended fields + }; + + template< class XInstanceType, class XBaseType > + class KTExtensible : public KTExtensibleCore< XBaseType > + { + public: + KTExtensible(); + KTExtensible( const KTExtensible< XInstanceType, XBaseType >& orig ); + virtual ~KTExtensible(); + + /// Copies the extended object + KTExtensible& operator=( const KTExtensible< XInstanceType, XBaseType >& orig ); + + /// Copies the current object and only extended fields already present + virtual KTExtensibleCore< XBaseType >& Pull( const KTExtensibleCore< XBaseType >& orig ); + + /// Clones the extended object + virtual std::shared_ptr< KTExtensibleCore< XBaseType > > Clone() const; + }; + + + + //************** + // KTExtensibleCore implementation + //************** + + template< class XBaseType > + KTExtensibleCore< XBaseType >::KTExtensibleCore() : + XBaseType(), + //fPrev(), + fNext(), + fDisableExtendedCopy( false ) + { + } + + template< class XBaseType > + KTExtensibleCore< XBaseType >::~KTExtensibleCore() + { + } + + template< class XBaseType > + KTExtensibleCore< XBaseType >& KTExtensibleCore< XBaseType >::operator=( const KTExtensibleCore< XBaseType >& orig ) + { + // must not call virtual functions on this because it's used in the copy constructor + + std::cout << "KTExtensibleCore::operator=()" << std::endl; + if( this == &orig ) return *this; + + fDisableExtendedCopy = false; + + // remove any extended fields + fNext.reset(); + + // copy extended fields + // only do this if orig.fDisableExtendedCopy is false + std::cout << "do we copy extended fields? ! " << orig.fDisableExtendedCopy << " && " << orig.fNext.operator bool() << " = " << bool(! orig.fDisableExtendedCopy && orig.fNext) << std::endl; + if( ! orig.fDisableExtendedCopy && orig.fNext ) + { + std::cout << "duplicating extended fields" << std::endl; + // duplicate extended fields with Clone() + fNext = orig.fNext->Clone(); // this's fNext points to the copy of orig's fNext + //SetPrevInNext( ESFTBaseType::shared_from_this() ); // this's fNext's fPrev points back to this + } + + // duplicate base class + this->XBaseType::operator=( *this ); + + return *this; + } + + template< class XBaseType > + unsigned KTExtensibleCore< XBaseType >::size() const + { + return fNext.operator bool() ? 1 + fNext->size() : 1; + } + + template< class XBaseType > + template< class XRequestedType > + XRequestedType& KTExtensibleCore< XBaseType >::Of() + { + std::cout << "in KTExtensibleCore::Of()" << std::endl; + XRequestedType* requested = dynamic_cast< XRequestedType* >(this); + if( requested != nullptr ) + { + std::cout << "type match" << std::endl; + return *requested; + } + + if( ! fNext ) + { + std::cout << "creating a new ext test core" << std::endl; + std::shared_ptr< XRequestedType > requestedShared = std::make_shared< XRequestedType >(); + fNext = requestedShared; + //SetPrevInNext( ESFTBaseType::shared_from_this() ); + return *requestedShared; + } + std::cout << "moving on to the next test core: " << fNext.operator bool() << std::endl; + return fNext->template Of< XRequestedType >(); + } + + template< class XBaseType > + template< class XRequestedType > + const XRequestedType& KTExtensibleCore< XBaseType >::Of() const + { + std::cout << "in KTExtensibleCore::Of() const" << std::endl; + const XRequestedType* requested = dynamic_cast< const XRequestedType* >(this); + if( requested != nullptr ) + { + return *requested; + } + + if( ! fNext ) + { + throw KTException() << "Cannot add to a const extensible object"; + } + return fNext->template Of< XRequestedType >(); + } + + template< class XBaseType > + template< class XRequestedType > + bool KTExtensibleCore< XBaseType >::Has() const + { + if( dynamic_cast< const XRequestedType* >( this ) ) + { + return true; + } + if( fNext ) + { + return fNext->template Has< XRequestedType >(); + } + return false; + } + + template< class XBaseType > + template< class XRequestedType > + std::shared_ptr< XRequestedType > KTExtensibleCore< XBaseType >::Detatch() + { + return _Detatch< XRequestedType >(); + } + + template< class XBaseType > + template< class XRequestedType > + std::shared_ptr< XRequestedType > KTExtensibleCore< XBaseType >::_Detatch( std::shared_ptr< KTExtensibleCore< XBaseType > > prev ) + { + if( dynamic_cast< XRequestedType* >( this ) ) + { + // create a shared pointer to this here, so that when we reset prev.fNext (if it exists), that won't be the last reference to this + std::shared_ptr< XRequestedType > detatched = std::static_pointer_cast< XRequestedType >( ESFTBaseType::shared_from_this() ); + if( prev ) + { + // link prev and fNext if fNext exists; otherwise resets prev.fNext + prev->fNext = this->fNext; + } + fNext.reset(); + return detatched; + } + + if( fNext ) + { + return fNext->template _Detatch< XRequestedType >( ESFTBaseType::shared_from_this() ); + } + + return std::shared_ptr< XRequestedType >(); + } + + + + //template< class XBaseType > + //void KTExtensibleCore< XBaseType >::SetPrevInNext( std::shared_ptr< KTExtensibleCore< XBaseType > > ptr ) + //{ + // fNext->fPrev = ptr; + // return; + //} + + + //************** + // KTExtensible implementation + //************** + + template< class XInstanceType, class XBaseType > + KTExtensible< XInstanceType, XBaseType >::KTExtensible() : + KTExtensibleCore< XBaseType >() + {} + + template< class XInstanceType, class XBaseType > + KTExtensible< XInstanceType, XBaseType >::KTExtensible( const KTExtensible< XInstanceType, XBaseType >& orig ) : + KTExtensibleCore< XBaseType >() // copy of KTExtensibleCore is done from operator=() + { + *this = orig; + } + + template< class XInstanceType, class XBaseType > + KTExtensible< XInstanceType, XBaseType >::~KTExtensible() + {} + + template< class XInstanceType, class XBaseType > + KTExtensible< XInstanceType, XBaseType >& KTExtensible< XInstanceType, XBaseType >::operator=( const KTExtensible< XInstanceType, XBaseType >& orig ) + { + // must not call any virtual functions on `this` because it's called from the copy constructor + + std::cout << "KTExtensible::operator=()" << std::endl; + if( this == &orig ) return *this; + + this->KTExtensibleCore< XBaseType >::operator=( orig ); + + return *this; + } + + template< class XInstanceType, class XBaseType > + KTExtensibleCore< XBaseType >& KTExtensible< XInstanceType, XBaseType >::Pull( const KTExtensibleCore< XBaseType >& orig ) + { + // copies information out from orig based on this's instance type and any extended fields present + std::cout << "KTExtensible::Pull()" << std::endl; + + if( this == &orig ) return *this; + + this->fDisableExtendedCopy = true; // we're going to use operator=, so we need to disable copying of extended fields to only get the instance type + XInstanceType* instance = static_cast< XInstanceType* >( this ); // guaranteed to be ok by CRTP + // orig is const, so Of() will throw an exception if XInstanceType is not present + // in that case, make a copy of a new object + try + { + instance->operator=( orig.template Of< XInstanceType >() ); + } + catch( KTException& ) + { + instance->operator=( XInstanceType() ); + } + this->fDisableExtendedCopy = false; + + // continue the pull process for any extended fields present in this + if( this->fNext ) + { + this->fNext->Pull( orig ); + } + + return *this; + } + + template< class XInstanceType, class XBaseType > + std::shared_ptr< KTExtensibleCore< XBaseType > > KTExtensible< XInstanceType, XBaseType >::Clone() const + { + std::cout << "KTExtensible::Clone()" << std::endl; + + std::shared_ptr< XInstanceType > instancePtr = std::make_shared< XInstanceType >(); + instancePtr->Pull(*this); // extracts just XInstanceType from this because instancePtr doesn't have any extended fields + + // if there are extended fields, clone them + if( this->fNext ) + { + instancePtr->fNext = this->fNext->Clone(); // instancePtr's fNext is a clone of this's fNext + //instancePtr->SetPrevInNext( instancePtr ); // instancePtr's fNext's fPrev points back to instance pointer + } + + return instancePtr; + } + +} /* namespace Nymph */ + +#endif /* NYMPH_VALIDATION_KTEXTTEST_HH_ */ diff --git a/Executables/Validation/KTTestCuts.cc b/Executables/Validation/KTTestCuts.cc index e486445..d78aeba 100644 --- a/Executables/Validation/KTTestCuts.cc +++ b/Executables/Validation/KTTestCuts.cc @@ -15,7 +15,7 @@ namespace Nymph KTLOGGER(testlog, "KTTestCuts"); KT_REGISTER_CUT(KTAwesomeCut, "awesome-cut"); - KT_REGISTER_CUT(KTNotAwesomeCut, "not-awesome-cut"); + KT_REGISTER_CUT(KTNotAwesomeCut, "not-awesome-cut" ); KTAwesomeCut::KTAwesomeCut(const std::string& name) : diff --git a/Executables/Validation/KTTestData.cc b/Executables/Validation/KTTestData.cc index b5a7180..72d3576 100644 --- a/Executables/Validation/KTTestData.cc +++ b/Executables/Validation/KTTestData.cc @@ -12,10 +12,14 @@ namespace Nymph KTTestData::KTTestData() : KTData(), fIsAwesome( false ) - {} + { + std::cout << "### KTTestData constructor" << std::endl; + } KTTestData::~KTTestData() - {} + { + std::cout << "### KTTestData destructor" << std::endl; + } } /* namespace Nymph */ diff --git a/Executables/Validation/TestCut.cc b/Executables/Validation/TestCut.cc index ac9f6a0..37b55cd 100644 --- a/Executables/Validation/TestCut.cc +++ b/Executables/Validation/TestCut.cc @@ -17,55 +17,65 @@ using namespace std; int main() { - KTCoreDataExt data; - KTTestDataExt& testData = data.Of< KTTestDataExt >(); + try + { + KTCoreDataExt data; + KTTestDataExt& testData = data.Of< KTTestDataExt >(); - KTCutStatus& cutStatus = data.CutStatus(); + KTCutStatus& cutStatus = data.CutStatus(); - KTINFO(testlog, "Assigning cuts"); - unsigned awesomeCutPos = 0; - string awesomeCutName("awesome-cut"); - unsigned notAwesomeCutPos = 1; - string notAwesomeCutName("not-awesome-cut"); - cutStatus.AssignCutResult(awesomeCutPos, awesomeCutName); - cutStatus.AssignCutResult(notAwesomeCutPos, notAwesomeCutName); + KTINFO(testlog, "Assigning awesome-cut"); + unsigned awesomeCutPos = 0; + string awesomeCutName("awesome-cut"); + cutStatus.AssignCutResult(awesomeCutPos, awesomeCutName); - KTINFO(testlog, "Initial cut state: " << cutStatus.IsCut()); + KTINFO(testlog, "Initial cut state: " << cutStatus.IsCut()); - KTINFO(testlog, "Applying awesome cut"); - KTAwesomeCut cut; - cut.Apply(data, testData); + KTINFO(testlog, "Applying awesome cut"); + KTAwesomeCut cut(awesomeCutName); + cut.Apply(data, testData); - KTINFO(testlog, "Cuts present: " << cutStatus.CutResultsPresent()) - KTINFO(testlog, "Has cut result <" << awesomeCutName << ">? " << cutStatus.HasCutResult(awesomeCutName)); - KTINFO(testlog, "Has cut result at " << awesomeCutPos << "? " << cutStatus.HasCutResult(awesomeCutPos)); - KTINFO(testlog, "Cut state of <" << awesomeCutName << ">is: " << cutStatus.GetCutState(awesomeCutName)); - KTINFO(testlog, "Cut state at " << awesomeCutPos << " is: " << cutStatus.GetCutState(awesomeCutPos)); - KTINFO(testlog, "Is cut (all results)? " << cutStatus.IsCut()); - KTINFO(testlog, "Is cut (with mask \"0\")? " << cutStatus.IsCut("0")); + KTINFO(testlog, "Cuts present: " << cutStatus.CutResultsPresent()) + KTINFO(testlog, "Has cut result <" << awesomeCutName << ">? " << cutStatus.HasCutResult(awesomeCutName)); + KTINFO(testlog, "Has cut result at " << awesomeCutPos << "? " << cutStatus.HasCutResult(awesomeCutPos)); + KTINFO(testlog, "Cut state of <" << awesomeCutName << ">is: " << cutStatus.GetCutState(awesomeCutName)); + KTINFO(testlog, "Cut state at " << awesomeCutPos << " is: " << cutStatus.GetCutState(awesomeCutPos)); + KTINFO(testlog, "Is cut (all results)? " << cutStatus.IsCut()); + KTINFO(testlog, "Current cut status: " << cutStatus); + KTINFO(testlog, "Is cut (with mask \"0\")? " << cutStatus.IsCut("0")); - KTINFO(testlog, "Applying not-awesome cut"); - KTNotAwesomeCut naCut; - naCut.Apply(data, testData); + KTINFO(testlog, "Assigning not-awesome-cut"); + unsigned notAwesomeCutPos = 1; + string notAwesomeCutName("not-awesome-cut"); + cutStatus.AssignCutResult(notAwesomeCutPos, notAwesomeCutName); - KTINFO(testlog, "Cuts present: " << cutStatus.CutResultsPresent()) - KTINFO(testlog, "Has cut result <" << awesomeCutName << ">? " << cutStatus.HasCutResult(awesomeCutName)); - KTINFO(testlog, "Has cut result at " << awesomeCutPos << "? " << cutStatus.HasCutResult(awesomeCutPos)); - KTINFO(testlog, "Cut state of <" << awesomeCutName << "> is: " << cutStatus.GetCutState(awesomeCutName)); - KTINFO(testlog, "Cut state at " << awesomeCutPos << " is: " << cutStatus.GetCutState(awesomeCutPos)); - KTINFO(testlog, "Has cut result <" << notAwesomeCutName << ">? " << cutStatus.HasCutResult(notAwesomeCutName)); - KTINFO(testlog, "Has cut result at " << notAwesomeCutPos << "? " << cutStatus.HasCutResult(notAwesomeCutPos)); - KTINFO(testlog, "Cut state of <" << notAwesomeCutName << "> is: " << cutStatus.GetCutState(notAwesomeCutName)); - KTINFO(testlog, "Cut state at " << notAwesomeCutPos << " is: " << cutStatus.GetCutState(notAwesomeCutPos)); - KTINFO(testlog, "Is cut (all results)? " << cutStatus.IsCut()); - KTINFO(testlog, "Is cut with mask \"00\"? " << cutStatus.IsCut("00")); - KTINFO(testlog, "Is cut with mask \"01\"? " << cutStatus.IsCut("01")); - KTINFO(testlog, "Is cut with mask \"10\"? " << cutStatus.IsCut("10")); - KTINFO(testlog, "Is cut with mask \"11\"? " << cutStatus.IsCut("11")); - KTINFO(testlog, "Is cut with mask 0? " << cutStatus.IsCut(0)); - KTINFO(testlog, "Is cut with mask 1? " << cutStatus.IsCut(1)); - KTINFO(testlog, "Is cut with mask 2? " << cutStatus.IsCut(2)); - KTINFO(testlog, "Is cut with mask 3? " << cutStatus.IsCut(3)); + KTINFO(testlog, "Applying not-awesome cut"); + KTNotAwesomeCut naCut(notAwesomeCutName); + naCut.Apply(data, testData); + + KTINFO(testlog, "Cuts present: " << cutStatus.CutResultsPresent()) + KTINFO(testlog, "Has cut result <" << awesomeCutName << ">? " << cutStatus.HasCutResult(awesomeCutName)); + KTINFO(testlog, "Has cut result at " << awesomeCutPos << "? " << cutStatus.HasCutResult(awesomeCutPos)); + KTINFO(testlog, "Cut state of <" << awesomeCutName << "> is: " << cutStatus.GetCutState(awesomeCutName)); + KTINFO(testlog, "Cut state at " << awesomeCutPos << " is: " << cutStatus.GetCutState(awesomeCutPos)); + KTINFO(testlog, "Has cut result <" << notAwesomeCutName << ">? " << cutStatus.HasCutResult(notAwesomeCutName)); + KTINFO(testlog, "Has cut result at " << notAwesomeCutPos << "? " << cutStatus.HasCutResult(notAwesomeCutPos)); + KTINFO(testlog, "Cut state of <" << notAwesomeCutName << "> is: " << cutStatus.GetCutState(notAwesomeCutName)); + KTINFO(testlog, "Cut state at " << notAwesomeCutPos << " is: " << cutStatus.GetCutState(notAwesomeCutPos)); + KTINFO(testlog, "Is cut (all results)? " << cutStatus.IsCut()); + KTINFO(testlog, "Is cut with mask \"00\"? " << cutStatus.IsCut("00")); + KTINFO(testlog, "Is cut with mask \"01\"? " << cutStatus.IsCut("01")); + KTINFO(testlog, "Is cut with mask \"10\"? " << cutStatus.IsCut("10")); + KTINFO(testlog, "Is cut with mask \"11\"? " << cutStatus.IsCut("11")); + KTINFO(testlog, "Is cut with mask 0? " << cutStatus.IsCut(0)); + KTINFO(testlog, "Is cut with mask 1? " << cutStatus.IsCut(1)); + KTINFO(testlog, "Is cut with mask 2? " << cutStatus.IsCut(2)); + KTINFO(testlog, "Is cut with mask 3? " << cutStatus.IsCut(3)); + } + catch(std::exception& e) + { + KTERROR(testlog, "Exception caught: " << e.what()); + } return 0; } diff --git a/Executables/Validation/TestData.cc b/Executables/Validation/TestData.cc new file mode 100644 index 0000000..18ea6be --- /dev/null +++ b/Executables/Validation/TestData.cc @@ -0,0 +1,25 @@ +/* + * TestData.cc + * + * Created on: Feb 10, 2018 + * Author: obla999 + */ + +#include "KTTestData.hh" + +#include "KTLogger.hh" + +using namespace Nymph; + +LOGGER(testlog, "TestData") + +int main() +{ + + KTCoreDataExt data; + KTTestDataExt& testData = data.Of< KTTestDataExt >(); + KTINFO(testlog, data.Name()); + KTINFO(testlog, testData.Name()); + + return 0; +} diff --git a/Executables/Validation/TestExt.cc b/Executables/Validation/TestExt.cc new file mode 100644 index 0000000..f7f724d --- /dev/null +++ b/Executables/Validation/TestExt.cc @@ -0,0 +1,78 @@ +/* + * TestExt.cc + * + * Created on: Feb 11, 2018 + * Author: N.S. Oblath + */ + +#include "KTExtTest.hh" + +#include "KTLogger.hh" + +#include + +KTLOGGER( testlog, "KTExtTest" ); + +using namespace Nymph; + +namespace Nymph +{ + class MyBaseClass + { + public: + MyBaseClass() {} + virtual ~MyBaseClass() {} + }; + + class MyClass1 : public KTExtensible< MyClass1, MyBaseClass > + { + public: + MyClass1() : KTExtensible< MyClass1, MyBaseClass >(), fValue() {} + MyClass1( const MyClass1& orig ) : KTExtensible< MyClass1, MyBaseClass >( orig ), fValue( orig.fValue ) {} + virtual ~MyClass1() {}; + public: + int fValue; + }; + + class MyClass2 : public KTExtensible< MyClass2, MyBaseClass > + { + public: + MyClass2() : KTExtensible< MyClass2, MyBaseClass >(), fValue() {} + MyClass2( const MyClass2& orig ) : KTExtensible< MyClass2, MyBaseClass >( orig ), fValue( orig.fValue ) {} + virtual ~MyClass2() {}; + public: + int fValue; + }; + +} + +int main() +{ + std::shared_ptr< MyClass1 > data1 = std::make_shared< MyClass1 >(); + data1->fValue = 5; + + MyClass2& data2 = data1->Of< MyClass2 >(); + data2.fValue = 3; + + KTINFO( testlog, "data1 has data1: " << data1->Has< MyClass1 >() ); + KTINFO( testlog, "data1 has data2: " << data1->Has< MyClass2 >() ); + KTINFO( testlog, "data2 has data1: " << data2.Has< MyClass1 >() ); + KTINFO( testlog, "data2 has data2: " << data2.Has< MyClass2 >() ); + KTINFO( testlog, "Value of data1: " << data1->fValue ); + KTINFO( testlog, "Value of data2: " << data2.fValue ); + KTINFO( testlog, "Size of data1: " << data1->size() ); + KTINFO( testlog, "Size of data2: " << data2.size() ); + + std::shared_ptr< MyClass1 > copyOfData1 = std::make_shared< MyClass1 >( *data1 ); + MyClass2& copyOfData2 = copyOfData1->Of< MyClass2 >(); + + KTINFO( testlog, "Value of data1's copy: " << copyOfData1->fValue ); + KTINFO( testlog, "Value of data2's copy: " << copyOfData2.fValue ); + + std::shared_ptr< MyClass2 > detatchedCoypOfData2 = copyOfData1->Detatch< MyClass2 >(); + + KTINFO( testlog, "Size of copy of data1 after detatch: " << copyOfData1->size() ); + KTINFO( testlog, "Size of detatched copy of data2: " << detatchedCoypOfData2->size() ); + + return 0; +} diff --git a/Library/Data/KTCoreData.cc b/Library/Data/KTCoreData.cc index 96aa004..9b80e3b 100644 --- a/Library/Data/KTCoreData.cc +++ b/Library/Data/KTCoreData.cc @@ -15,10 +15,13 @@ namespace Nymph fLastData( false ), fCutStatus() { + std::cout << "### KTCoreData constructor" << std::endl; } KTCoreData::~KTCoreData() - {} + { + std::cout << "### KTCoreData destrutor" << std::endl; + } KTDataHandle CreateNewDataHandle() diff --git a/Library/Data/KTCutStatus.cc b/Library/Data/KTCutStatus.cc index d1c1f52..9396e76 100644 --- a/Library/Data/KTCutStatus.cc +++ b/Library/Data/KTCutStatus.cc @@ -39,6 +39,12 @@ namespace Nymph void KTCutStatus::AssignCutResult(unsigned maskPos, const std::string& name, bool state, bool doUpdateStatus) { + KTDEBUG(cutlog, "Assigning cut result <" << name << "> to position <" << maskPos << "> with state <" << state << ">"); + if( maskPos >= fCutResults.size() ) + { + fCutResults.resize( maskPos + 1 ); + } + KTDEBUG(cutlog, "Cut result size is now <" << fCutResults.size() << ">"); if( fCutResults[maskPos].fAssigned ) { throw KTException() << "Mask position <" << maskPos << "> has already been assigned"; diff --git a/Library/Data/KTData.cc b/Library/Data/KTData.cc index 9cc427c..7c7df99 100644 --- a/Library/Data/KTData.cc +++ b/Library/Data/KTData.cc @@ -17,13 +17,17 @@ namespace Nymph KTDataRider::KTDataRider() : fName() - {} + { + std::cout << "### KTDataRider for <" << fName << "> constructor" << std::endl; + } KTDataRider::KTDataRider( const KTDataRider& orig ) : fName( orig.fName ) {} KTDataRider::~KTDataRider() - {} + { + std::cout << "### KTDataRider for <" << fName << "> destructor" << std::endl; + } } /* namespace Nymph */ diff --git a/Library/Utility/KTExtensibleStruct.hh b/Library/Utility/KTExtensibleStruct.hh index f2dc0c2..63deb64 100644 --- a/Library/Utility/KTExtensibleStruct.hh +++ b/Library/Utility/KTExtensibleStruct.hh @@ -9,6 +9,8 @@ #ifndef KTEXTENSIBLESTRUCT_HH_ #define KTEXTENSIBLESTRUCT_HH_ +#include "KTException.hh" + #include #include @@ -23,11 +25,15 @@ namespace Nymph */ template< class XBaseType > - struct KTExtensibleStructCore : public XBaseType + struct KTExtensibleStructCore : public XBaseType, public std::enable_shared_from_this< KTExtensibleStructCore< XBaseType > > { public: typedef KTExtensibleStructCore< XBaseType > BasePtrType; typedef std::shared_ptr< BasePtrType > BasePtr; + typedef std::weak_ptr< BasePtrType > WeakBasePtr; + + private: + typedef std::enable_shared_from_this< KTExtensibleStructCore< XBaseType > > ESFTType; public: /// Default constructor @@ -66,7 +72,7 @@ namespace Nymph protected: void SetPrevPtrInNext(); mutable BasePtr fNext; - mutable BasePtr fPrev; + mutable WeakBasePtr fPrev; private: friend class cereal::access; @@ -124,7 +130,6 @@ namespace Nymph template KTExtensibleStructCore::~KTExtensibleStructCore() { - fNext.reset(); } template @@ -153,7 +158,7 @@ namespace Nymph if (! fNext) { fNext = std::make_shared< XStructType >(); - fNext->fPrev.reset( this ); + fNext->fPrev = ESFTType::shared_from_this(); } return fNext->template Of(); @@ -171,8 +176,7 @@ namespace Nymph if (! fNext) { - fNext = std::make_shared< XStructType >(); - fNext->fPrev.reset( const_cast< BasePtrType* >(this) ); + throw KTException() << "Requested component of (const) extensible struct not present"; } return fNext->template Of(); @@ -212,7 +216,7 @@ namespace Nymph if (next->fNext) { fNext = next->fNext; - fNext->fPrev = this; + fNext->fPrev = ESFTType::shared_from_this(); next->fNext.reset(); } next->fPrev.reset(); @@ -231,7 +235,7 @@ namespace Nymph template inline typename KTExtensibleStructCore::BasePtr KTExtensibleStructCore::Prev() const { - return fPrev; + return fPrev.lock(); } template @@ -244,14 +248,14 @@ namespace Nymph template inline typename KTExtensibleStructCore::BasePtr KTExtensibleStructCore::First() const { - if (fPrev) return this; - return fPrev->First(); + if (! fPrev) return BasePtr(this); + return fPrev.lock()->First(); } template inline void KTExtensibleStructCore::SetPrevPtrInNext() { - fNext->fPrev.reset( this ); + fNext->fPrev = ESFTType::shared_from_this(); return; } From b4863c6a54dd2129d15f2c041fa81a8886e3ddd4 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Wed, 14 Feb 2018 17:14:53 -0800 Subject: [PATCH 098/521] Added Share() functions and some typedefs --- Executables/Validation/KTExtTest.hh | 85 ++++++++++++++++++++++++----- Executables/Validation/TestExt.cc | 3 + 2 files changed, 75 insertions(+), 13 deletions(-) diff --git a/Executables/Validation/KTExtTest.hh b/Executables/Validation/KTExtTest.hh index 76fe6ff..f05741d 100644 --- a/Executables/Validation/KTExtTest.hh +++ b/Executables/Validation/KTExtTest.hh @@ -19,22 +19,26 @@ namespace Nymph template< class XBaseType > class KTExtensibleCore : public XBaseType, public std::enable_shared_from_this< KTExtensibleCore< XBaseType > > { + public: + typedef KTExtensibleCore< XBaseType > ExtCoreType; + typedef std::shared_ptr< ExtCoreType > BasePtrType; + private: typedef std::enable_shared_from_this< KTExtensibleCore< XBaseType > > ESFTBaseType; public: KTExtensibleCore(); - KTExtensibleCore( const KTExtensibleCore< XBaseType >& orig ) = delete; // deleted because copy of KTExtensibleCore is done using operator=() + KTExtensibleCore( const ExtCoreType& orig ) = delete; // deleted because copy of KTExtensibleCore is done using operator=() virtual ~KTExtensibleCore(); /// Copies extended object - KTExtensibleCore& operator=( const KTExtensibleCore< XBaseType >& orig ); + ExtCoreType& operator=( const ExtCoreType& orig ); /// Copies the current object and only extended fields already present - virtual KTExtensibleCore& Pull( const KTExtensibleCore< XBaseType >& orig ) = 0; // implemented in KTExtensible because it requires knowing the extended field type + virtual ExtCoreType& Pull( const ExtCoreType& orig ) = 0; // implemented in KTExtensible because it requires knowing the extended field type /// Clones the extended object - virtual std::shared_ptr< KTExtensibleCore< XBaseType > > Clone() const = 0; // implemented in KTExtensible because it requires knowing the extended field type + virtual BasePtrType Clone() const = 0; // implemented in KTExtensible because it requires knowing the extended field type /// Returns the size of the extended object, including this field and any extended below it unsigned size() const; @@ -47,6 +51,14 @@ namespace Nymph template< class XRequestedType > const XRequestedType& Of() const; + /// Returns a pointer to the object of the requested type or creates a new one if it's not present + template< class XRequestedType > + std::shared_ptr< XRequestedType > Share(); + + /// Returns a pointer to the object of the requested type or throws KTException if it's not present + template< class XRequestedType > + const std::shared_ptr< XRequestedType > Share() const; + /// Checks whether the requested type is present template< class XRequestedType > bool Has() const; @@ -58,11 +70,11 @@ namespace Nymph protected: template< class XRequestedType > - std::shared_ptr< XRequestedType > _Detatch( std::shared_ptr< KTExtensibleCore< XBaseType > > prev = std::shared_ptr< KTExtensibleCore< XBaseType > >() ); + std::shared_ptr< XRequestedType > _Detatch( BasePtrType prev = BasePtrType() ); //void SetPrevInNext( std::shared_ptr< KTExtensibleCore< XBaseType > > ptr ); //std::weak_ptr< KTExtensibleCore< XBaseType > > fPrev; - std::shared_ptr< KTExtensibleCore< XBaseType > > fNext; + BasePtrType fNext; bool fDisableExtendedCopy; // internal variable used to determine whether operator= copies extended fields }; @@ -70,19 +82,24 @@ namespace Nymph template< class XInstanceType, class XBaseType > class KTExtensible : public KTExtensibleCore< XBaseType > { + public: + typedef KTExtensible< XInstanceType, XBaseType > ExtType; + typedef KTExtensibleCore< XBaseType > ExtCoreType; + typedef std::shared_ptr< KTExtensibleCore< XBaseType > > BasePtrType; + public: KTExtensible(); - KTExtensible( const KTExtensible< XInstanceType, XBaseType >& orig ); + KTExtensible( const ExtType& orig ); virtual ~KTExtensible(); /// Copies the extended object - KTExtensible& operator=( const KTExtensible< XInstanceType, XBaseType >& orig ); + ExtType& operator=( const ExtType& orig ); /// Copies the current object and only extended fields already present - virtual KTExtensibleCore< XBaseType >& Pull( const KTExtensibleCore< XBaseType >& orig ); + virtual ExtCoreType& Pull( const ExtCoreType& orig ); /// Clones the extended object - virtual std::shared_ptr< KTExtensibleCore< XBaseType > > Clone() const; + virtual BasePtrType Clone() const; }; @@ -146,7 +163,7 @@ namespace Nymph XRequestedType& KTExtensibleCore< XBaseType >::Of() { std::cout << "in KTExtensibleCore::Of()" << std::endl; - XRequestedType* requested = dynamic_cast< XRequestedType* >(this); + XRequestedType* requested = dynamic_cast< XRequestedType* >( this ); if( requested != nullptr ) { std::cout << "type match" << std::endl; @@ -170,7 +187,7 @@ namespace Nymph const XRequestedType& KTExtensibleCore< XBaseType >::Of() const { std::cout << "in KTExtensibleCore::Of() const" << std::endl; - const XRequestedType* requested = dynamic_cast< const XRequestedType* >(this); + const XRequestedType* requested = dynamic_cast< const XRequestedType* >( this ); if( requested != nullptr ) { return *requested; @@ -183,6 +200,48 @@ namespace Nymph return fNext->template Of< XRequestedType >(); } + template< class XBaseType > + template< class XRequestedType > + std::shared_ptr< XRequestedType > KTExtensibleCore< XBaseType >::Share() + { + std::cout << "in KTExtensibleCore::Share()" << std::endl; + std::shared_ptr< XRequestedType > requested = std::dynamic_pointer_cast< XRequestedType >( ESFTBaseType::shared_from_this() ); + if( requested ) + { + std::cout << "type match" << std::endl; + return requested; + } + + if( ! fNext ) + { + std::cout << "creating a new ext test core" << std::endl; + requested = std::make_shared< XRequestedType >(); + fNext = requested; + //SetPrevInNext( ESFTBaseType::shared_from_this() ); + return requested; + } + std::cout << "moving on to the next test core: " << fNext.operator bool() << std::endl; + return fNext->template Share< XRequestedType >(); + } + + template< class XBaseType > + template< class XRequestedType > + const std::shared_ptr< XRequestedType > KTExtensibleCore< XBaseType >::Share() const + { + std::cout << "in KTExtensibleCore::Share() const" << std::endl; + const std::shared_ptr< XRequestedType > requested = std::dynamic_pointer_cast< const XRequestedType >( ESFTBaseType::shared_from_this() ); + if( requested ) + { + return requested; + } + + if( ! fNext ) + { + throw KTException() << "Cannot add to a const extensible object"; + } + return fNext->template Share< XRequestedType >(); + } + template< class XBaseType > template< class XRequestedType > bool KTExtensibleCore< XBaseType >::Has() const @@ -207,7 +266,7 @@ namespace Nymph template< class XBaseType > template< class XRequestedType > - std::shared_ptr< XRequestedType > KTExtensibleCore< XBaseType >::_Detatch( std::shared_ptr< KTExtensibleCore< XBaseType > > prev ) + std::shared_ptr< XRequestedType > KTExtensibleCore< XBaseType >::_Detatch( KTExtensibleCore< XBaseType >::BasePtrType prev ) { if( dynamic_cast< XRequestedType* >( this ) ) { diff --git a/Executables/Validation/TestExt.cc b/Executables/Validation/TestExt.cc index f7f724d..b8c0d31 100644 --- a/Executables/Validation/TestExt.cc +++ b/Executables/Validation/TestExt.cc @@ -54,12 +54,15 @@ int main() MyClass2& data2 = data1->Of< MyClass2 >(); data2.fValue = 3; + std::shared_ptr< MyClass2 > data2Shared = data1->Share< MyClass2 >(); + KTINFO( testlog, "data1 has data1: " << data1->Has< MyClass1 >() ); KTINFO( testlog, "data1 has data2: " << data1->Has< MyClass2 >() ); KTINFO( testlog, "data2 has data1: " << data2.Has< MyClass1 >() ); KTINFO( testlog, "data2 has data2: " << data2.Has< MyClass2 >() ); KTINFO( testlog, "Value of data1: " << data1->fValue ); KTINFO( testlog, "Value of data2: " << data2.fValue ); + KTINFO( testlog, "Value of data2Shared: " << data2Shared->fValue ); KTINFO( testlog, "Size of data1: " << data1->size() ); KTINFO( testlog, "Size of data2: " << data2.size() ); From 11fbddbc9e88ac7fdc3f5cd7b36aba334ba044b4 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Wed, 14 Feb 2018 17:28:12 -0800 Subject: [PATCH 099/521] Removed debugging output --- Executables/Validation/KTExtTest.hh | 32 ----------------------------- 1 file changed, 32 deletions(-) diff --git a/Executables/Validation/KTExtTest.hh b/Executables/Validation/KTExtTest.hh index f05741d..4f68284 100644 --- a/Executables/Validation/KTExtTest.hh +++ b/Executables/Validation/KTExtTest.hh @@ -71,9 +71,7 @@ namespace Nymph protected: template< class XRequestedType > std::shared_ptr< XRequestedType > _Detatch( BasePtrType prev = BasePtrType() ); - //void SetPrevInNext( std::shared_ptr< KTExtensibleCore< XBaseType > > ptr ); - //std::weak_ptr< KTExtensibleCore< XBaseType > > fPrev; BasePtrType fNext; bool fDisableExtendedCopy; // internal variable used to determine whether operator= copies extended fields @@ -111,7 +109,6 @@ namespace Nymph template< class XBaseType > KTExtensibleCore< XBaseType >::KTExtensibleCore() : XBaseType(), - //fPrev(), fNext(), fDisableExtendedCopy( false ) { @@ -127,7 +124,6 @@ namespace Nymph { // must not call virtual functions on this because it's used in the copy constructor - std::cout << "KTExtensibleCore::operator=()" << std::endl; if( this == &orig ) return *this; fDisableExtendedCopy = false; @@ -137,13 +133,10 @@ namespace Nymph // copy extended fields // only do this if orig.fDisableExtendedCopy is false - std::cout << "do we copy extended fields? ! " << orig.fDisableExtendedCopy << " && " << orig.fNext.operator bool() << " = " << bool(! orig.fDisableExtendedCopy && orig.fNext) << std::endl; if( ! orig.fDisableExtendedCopy && orig.fNext ) { - std::cout << "duplicating extended fields" << std::endl; // duplicate extended fields with Clone() fNext = orig.fNext->Clone(); // this's fNext points to the copy of orig's fNext - //SetPrevInNext( ESFTBaseType::shared_from_this() ); // this's fNext's fPrev points back to this } // duplicate base class @@ -162,23 +155,18 @@ namespace Nymph template< class XRequestedType > XRequestedType& KTExtensibleCore< XBaseType >::Of() { - std::cout << "in KTExtensibleCore::Of()" << std::endl; XRequestedType* requested = dynamic_cast< XRequestedType* >( this ); if( requested != nullptr ) { - std::cout << "type match" << std::endl; return *requested; } if( ! fNext ) { - std::cout << "creating a new ext test core" << std::endl; std::shared_ptr< XRequestedType > requestedShared = std::make_shared< XRequestedType >(); fNext = requestedShared; - //SetPrevInNext( ESFTBaseType::shared_from_this() ); return *requestedShared; } - std::cout << "moving on to the next test core: " << fNext.operator bool() << std::endl; return fNext->template Of< XRequestedType >(); } @@ -186,7 +174,6 @@ namespace Nymph template< class XRequestedType > const XRequestedType& KTExtensibleCore< XBaseType >::Of() const { - std::cout << "in KTExtensibleCore::Of() const" << std::endl; const XRequestedType* requested = dynamic_cast< const XRequestedType* >( this ); if( requested != nullptr ) { @@ -204,7 +191,6 @@ namespace Nymph template< class XRequestedType > std::shared_ptr< XRequestedType > KTExtensibleCore< XBaseType >::Share() { - std::cout << "in KTExtensibleCore::Share()" << std::endl; std::shared_ptr< XRequestedType > requested = std::dynamic_pointer_cast< XRequestedType >( ESFTBaseType::shared_from_this() ); if( requested ) { @@ -214,13 +200,10 @@ namespace Nymph if( ! fNext ) { - std::cout << "creating a new ext test core" << std::endl; requested = std::make_shared< XRequestedType >(); fNext = requested; - //SetPrevInNext( ESFTBaseType::shared_from_this() ); return requested; } - std::cout << "moving on to the next test core: " << fNext.operator bool() << std::endl; return fNext->template Share< XRequestedType >(); } @@ -228,7 +211,6 @@ namespace Nymph template< class XRequestedType > const std::shared_ptr< XRequestedType > KTExtensibleCore< XBaseType >::Share() const { - std::cout << "in KTExtensibleCore::Share() const" << std::endl; const std::shared_ptr< XRequestedType > requested = std::dynamic_pointer_cast< const XRequestedType >( ESFTBaseType::shared_from_this() ); if( requested ) { @@ -290,15 +272,6 @@ namespace Nymph } - - //template< class XBaseType > - //void KTExtensibleCore< XBaseType >::SetPrevInNext( std::shared_ptr< KTExtensibleCore< XBaseType > > ptr ) - //{ - // fNext->fPrev = ptr; - // return; - //} - - //************** // KTExtensible implementation //************** @@ -324,7 +297,6 @@ namespace Nymph { // must not call any virtual functions on `this` because it's called from the copy constructor - std::cout << "KTExtensible::operator=()" << std::endl; if( this == &orig ) return *this; this->KTExtensibleCore< XBaseType >::operator=( orig ); @@ -336,7 +308,6 @@ namespace Nymph KTExtensibleCore< XBaseType >& KTExtensible< XInstanceType, XBaseType >::Pull( const KTExtensibleCore< XBaseType >& orig ) { // copies information out from orig based on this's instance type and any extended fields present - std::cout << "KTExtensible::Pull()" << std::endl; if( this == &orig ) return *this; @@ -366,8 +337,6 @@ namespace Nymph template< class XInstanceType, class XBaseType > std::shared_ptr< KTExtensibleCore< XBaseType > > KTExtensible< XInstanceType, XBaseType >::Clone() const { - std::cout << "KTExtensible::Clone()" << std::endl; - std::shared_ptr< XInstanceType > instancePtr = std::make_shared< XInstanceType >(); instancePtr->Pull(*this); // extracts just XInstanceType from this because instancePtr doesn't have any extended fields @@ -375,7 +344,6 @@ namespace Nymph if( this->fNext ) { instancePtr->fNext = this->fNext->Clone(); // instancePtr's fNext is a clone of this's fNext - //instancePtr->SetPrevInNext( instancePtr ); // instancePtr's fNext's fPrev points back to instance pointer } return instancePtr; From 86900a22c4af0d4fbeac3ef14975b353bb2fcaa7 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Wed, 14 Feb 2018 18:36:48 -0800 Subject: [PATCH 100/521] Switch extended data classes to KTExtensible. Added TestExtSerialization, but it currently doesn't fully work. --- Executables/Validation/CMakeLists.txt | 6 +- Executables/Validation/KTExtTest.cc | 18 ----- Executables/Validation/TestExt.cc | 4 +- .../Validation/TestExtSerialization.cc | 69 +++++++++++++++++++ Library/Application/KTPrintDataStructure.cc | 2 +- Library/CMakeLists.txt | 1 + Library/Data/KTData.hh | 24 ++----- .../Utility/KTExtensible.hh | 49 +++++++++++-- 8 files changed, 125 insertions(+), 48 deletions(-) delete mode 100644 Executables/Validation/KTExtTest.cc create mode 100644 Executables/Validation/TestExtSerialization.cc rename Executables/Validation/KTExtTest.hh => Library/Utility/KTExtensible.hh (89%) diff --git a/Executables/Validation/CMakeLists.txt b/Executables/Validation/CMakeLists.txt index c15aa51..e7d8423 100644 --- a/Executables/Validation/CMakeLists.txt +++ b/Executables/Validation/CMakeLists.txt @@ -20,8 +20,6 @@ if (Nymph_ENABLE_TESTING) KTTestData.hh KTTestPrimaryProcessor.hh KTTestProcessor.hh - - KTExtTest.hh ) set (VALIDATION_SOURCEFILES @@ -58,6 +56,8 @@ if (Nymph_ENABLE_TESTING) TestCutFilter TestData TestExceptionInSlot + TestExt + TestExtSerialization TestJSONWriter TestLogger TestPolymorphicSlotData @@ -72,8 +72,6 @@ if (Nymph_ENABLE_TESTING) TestSlotData TestThroughputProfiler TestUseBreakpoint - - TestExt ) pbuilder_executables( TEST_PROGRAMS LIB_DEPENDENCIES ) diff --git a/Executables/Validation/KTExtTest.cc b/Executables/Validation/KTExtTest.cc deleted file mode 100644 index 69d59b1..0000000 --- a/Executables/Validation/KTExtTest.cc +++ /dev/null @@ -1,18 +0,0 @@ -/* - * KTExtTest.cc - * - * Created on: Feb 11, 2018 - * Author: N.S. Oblath - */ - -#include "KTExtTest.hh" - -#include - -namespace Nymph -{ - - - - -} /* namespace Nymph */ diff --git a/Executables/Validation/TestExt.cc b/Executables/Validation/TestExt.cc index b8c0d31..7dcbdbb 100644 --- a/Executables/Validation/TestExt.cc +++ b/Executables/Validation/TestExt.cc @@ -5,11 +5,9 @@ * Author: N.S. Oblath */ -#include "KTExtTest.hh" - #include "KTLogger.hh" -#include +#include "KTExtensible.hh" KTLOGGER( testlog, "KTExtTest" ); diff --git a/Executables/Validation/TestExtSerialization.cc b/Executables/Validation/TestExtSerialization.cc new file mode 100644 index 0000000..d47d470 --- /dev/null +++ b/Executables/Validation/TestExtSerialization.cc @@ -0,0 +1,69 @@ +/* + * TestSerialization.cc + * + * Created on: Jan 24, 2018 + * Author: obla999 + */ + +#include "KTLogger.hh" + +#include "KTTestData.hh" + +#include "cereal/archives/json.hpp" + +#include + +LOGGER( testlog, "TestSerialization" ); + +using namespace Nymph; + +int main() +{ + const std::string filename( "test_serialization_output.json" ); + + // save data to archive + { + std::shared_ptr< KTCoreDataExt > coreData = std::make_shared< KTCoreDataExt >(); + std::shared_ptr< KTTestDataExt > testData = coreData->Share< KTTestDataExt >(); + + // change data values from their defaults + coreData->SetCounter( 5 ); + testData->SetIsAwesome( true ); + + KTINFO( testlog, "KTCoreData counter: " << coreData->GetCounter() ); + KTINFO( testlog, "KTTestData is-awesome: " << testData->GetIsAwesome() ); + + // create and open a file for output + std::ofstream fileOut( filename ); + + cereal::JSONOutputArchive archiveOut( fileOut ); + + KTINFO( testlog, "Writing data to JSON archive" ); + archiveOut( coreData ); + + // archive and stream closed when destructors are called + } + + // ... some time later restore the class instance to its original state + { + std::shared_ptr< KTCoreDataExt > newCoreData = std::make_shared< KTCoreDataExt >(); + + // create and open an archive for input + std::ifstream fileIn( filename ); + + cereal::JSONInputArchive archiveIn( fileIn ); + + KTINFO( testlog, "Reading data from JSON archive" ); + archiveIn( newCoreData ); + + std::shared_ptr< KTTestDataExt > newTestData = newCoreData->Share< KTTestDataExt >(); + + KTINFO(testlog, "KTCoreData counter: " << newCoreData->GetCounter()); + KTINFO(testlog, "KTTestData is-awesome: " << newTestData->GetIsAwesome()); + + // archive and stream closed when destructors are called + } + + return 0; +} + diff --git a/Library/Application/KTPrintDataStructure.cc b/Library/Application/KTPrintDataStructure.cc index d48aa52..c05e518 100644 --- a/Library/Application/KTPrintDataStructure.cc +++ b/Library/Application/KTPrintDataStructure.cc @@ -83,7 +83,7 @@ namespace Nymph printbuf << "\nData Structure:\n"; printbuf << "\t- " << dataHandle->Name() << '\n'; KTDEBUG(datalog, "Found data type " << dataHandle->Name()); - KTExtensibleStructCore< KTDataRider >::BasePtr nextData = dataHandle->Next(); + KTExtensibleCore< KTDataRider >::BasePtrType nextData = dataHandle->Next(); while (nextData != NULL) { printbuf << "\t- " << nextData->Name() << '\n'; diff --git a/Library/CMakeLists.txt b/Library/CMakeLists.txt index c0692b4..b89cec1 100644 --- a/Library/CMakeLists.txt +++ b/Library/CMakeLists.txt @@ -16,6 +16,7 @@ set( NYMPH_HEADERFILES ${UTIL_DIR}/KTDirectory.hh ${UTIL_DIR}/KTEventLoop.hh ${UTIL_DIR}/KTException.hh + ${UTIL_DIR}/KTExtensible.hh ${UTIL_DIR}/KTExtensibleStruct.hh ${UTIL_DIR}/KTExtensibleStructFactory.hh ${UTIL_DIR}/KTLogger.hh diff --git a/Library/Data/KTData.hh b/Library/Data/KTData.hh index 3e8f34e..90b3b6a 100644 --- a/Library/Data/KTData.hh +++ b/Library/Data/KTData.hh @@ -8,7 +8,7 @@ #ifndef KTDATA_HH_ #define KTDATA_HH_ -#include "KTExtensibleStruct.hh" +#include "KTExtensible.hh" #include "KTMemberVariable.hh" @@ -58,22 +58,20 @@ namespace Nymph } template< class XDerivedType > - class KTExtensibleDataRider : public KTExtensibleStruct< XDerivedType, KTDataRider > + class KTExtensibleDataRider : public KTExtensible< XDerivedType, KTDataRider > { public: KTExtensibleDataRider() = delete; KTExtensibleDataRider( const std::string& name ) { KTDataRider::fName = name; } - KTExtensibleDataRider( const KTExtensibleDataRider< XDerivedType >& orig ) : KTExtensibleStruct< XDerivedType, KTDataRider >( *this ) {} + KTExtensibleDataRider( const KTExtensibleDataRider< XDerivedType >& orig ) : KTExtensible< XDerivedType, KTDataRider >( *this ) {} virtual ~KTExtensibleDataRider() {} -/* template< class Archive > void serialize( Archive& ar ) { - std::cout << "### serialize for KTExtensibleStruct< XDerivedType, KTDataRider >" << std::endl; - ar( cereal::base_class< KTExtensibleStruct< XDerivedType, KTDataRider > >( this ) ); + std::cout << "### serialize for KTExtensibleDataRider< XDerivedType >" << std::endl; + ar( cereal::base_class< KTExtensible< XDerivedType, KTDataRider > >( this ) ); } -*/ }; #define DEFINE_EXT_DATA_2( ex_data_class_name, data_class_name, label ) \ @@ -84,21 +82,13 @@ namespace Nymph ex_data_class_name( const ex_data_class_name& orig ) : data_class_name( *this ), KTExtensibleDataRider< ex_data_class_name >( *this ) {} \ virtual ~ex_data_class_name() {} \ \ - std::shared_ptr< KTExtensibleStructCore< KTDataRider > > Clone() const \ - { \ - std::shared_ptr< ex_data_class_name > copy = std::make_shared< ex_data_class_name >( *this ); \ - return std::static_pointer_cast< KTExtensibleStructCore< KTDataRider >, ex_data_class_name >( copy ); \ - } \ - }; - -/* template< class Archive > \ void serialize( Archive& ar ) \ { \ - std::cout << "### serialize for ex_data_class_name" << std::endl; + std::cout << "### serialize for ex_data_class_name" << std::endl; \ ar( cereal::base_class< data_class_name >( this ), cereal::base_class< KTExtensibleDataRider< ex_data_class_name > >( this ) ); \ } \ -*/ + }; #define DEFINE_EXT_DATA( data_class_name, label ) DEFINE_EXT_DATA_2( PASTE(data_class_name, Ext), data_class_name, label ) diff --git a/Executables/Validation/KTExtTest.hh b/Library/Utility/KTExtensible.hh similarity index 89% rename from Executables/Validation/KTExtTest.hh rename to Library/Utility/KTExtensible.hh index 4f68284..73fe331 100644 --- a/Executables/Validation/KTExtTest.hh +++ b/Library/Utility/KTExtensible.hh @@ -1,16 +1,17 @@ /* - * KTExtTest.hh + * KTExtensible.hh * * Created on: Feb 11, 2018 * Author: N.S. Oblath */ -#ifndef NYMPH_VALIDATION_KTEXTTEST_HH_ -#define NYMPH_VALIDATION_KTEXTTEST_HH_ +#ifndef NYMPH_KTEXTENSIBLE_HH_ +#define NYMPH_KTEXTENSIBLE_HH_ #include "KTException.hh" -#include +#include + #include namespace Nymph @@ -68,6 +69,9 @@ namespace Nymph template< class XRequestedType > std::shared_ptr< XRequestedType > Detatch(); + /// Returns a pointer to the next extended field + BasePtrType Next(); + protected: template< class XRequestedType > std::shared_ptr< XRequestedType > _Detatch( BasePtrType prev = BasePtrType() ); @@ -75,6 +79,12 @@ namespace Nymph BasePtrType fNext; bool fDisableExtendedCopy; // internal variable used to determine whether operator= copies extended fields + + private: + friend class cereal::access; + + template< class Archive > + void serialize( Archive& ar ); }; template< class XInstanceType, class XBaseType > @@ -98,6 +108,12 @@ namespace Nymph /// Clones the extended object virtual BasePtrType Clone() const; + + private: + friend class cereal::access; + + template< class Archive > + void serialize( Archive& ar ); }; @@ -246,6 +262,12 @@ namespace Nymph return _Detatch< XRequestedType >(); } + template< class XBaseType > + std::shared_ptr< KTExtensibleCore< XBaseType > > KTExtensibleCore< XBaseType >::Next() + { + return fNext; + } + template< class XBaseType > template< class XRequestedType > std::shared_ptr< XRequestedType > KTExtensibleCore< XBaseType >::_Detatch( KTExtensibleCore< XBaseType >::BasePtrType prev ) @@ -271,6 +293,14 @@ namespace Nymph return std::shared_ptr< XRequestedType >(); } + template< class XBaseType > + template< class Archive > + void KTExtensibleCore< XBaseType >::serialize( Archive& ar ) + { + std::cout << "### serialize for " << typeid(KTExtensibleCore< XBaseType >).name() << std::endl; + ar( cereal::base_class< XBaseType >( this ), fNext ); + } + //************** // KTExtensible implementation @@ -349,6 +379,15 @@ namespace Nymph return instancePtr; } + template< class XInstanceType, class XBaseType > + template< class Archive > + void KTExtensible< XInstanceType, XBaseType >::serialize( Archive& ar ) + { + std::cout << "### serialize for " << typeid(KTExtensible< XInstanceType, XBaseType >).name() << std::endl; + ar( cereal::base_class< ExtCoreType >( this ) ); + return; + } + } /* namespace Nymph */ -#endif /* NYMPH_VALIDATION_KTEXTTEST_HH_ */ +#endif /* NYMPH_KTEXTENSIBLE_HH_ */ From 62f062281e85c2b4595164bbc9681cdc12482064 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Sat, 17 Feb 2018 18:36:28 -0600 Subject: [PATCH 101/521] Added registration of data classes, and things work. Nice. --- Executables/Validation/TestExtSerialization.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Executables/Validation/TestExtSerialization.cc b/Executables/Validation/TestExtSerialization.cc index d47d470..b4ac89b 100644 --- a/Executables/Validation/TestExtSerialization.cc +++ b/Executables/Validation/TestExtSerialization.cc @@ -17,6 +17,11 @@ LOGGER( testlog, "TestSerialization" ); using namespace Nymph; +// register the data classes so they can be serialized from base-class pointers. +// json archive is already included, so it has been registered before these classes. +CEREAL_REGISTER_TYPE( KTCoreDataExt ); +CEREAL_REGISTER_TYPE( KTTestDataExt ); + int main() { const std::string filename( "test_serialization_output.json" ); From 2190b3eb863cc666249fe745219cec2e24cbc98c Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Sat, 17 Feb 2018 19:33:23 -0600 Subject: [PATCH 102/521] Added KTRegisterNymphExtData.hh --- .../Validation/TestExtSerialization.cc | 3 +- Library/CMakeLists.txt | 1 + Library/Data/KTRegisterNymphExtData.hh | 29 +++++++++++++++++++ 3 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 Library/Data/KTRegisterNymphExtData.hh diff --git a/Executables/Validation/TestExtSerialization.cc b/Executables/Validation/TestExtSerialization.cc index b4ac89b..2668eef 100644 --- a/Executables/Validation/TestExtSerialization.cc +++ b/Executables/Validation/TestExtSerialization.cc @@ -11,6 +11,8 @@ #include "cereal/archives/json.hpp" +#include "KTRegisterNymphExtData.hh" + #include LOGGER( testlog, "TestSerialization" ); @@ -19,7 +21,6 @@ using namespace Nymph; // register the data classes so they can be serialized from base-class pointers. // json archive is already included, so it has been registered before these classes. -CEREAL_REGISTER_TYPE( KTCoreDataExt ); CEREAL_REGISTER_TYPE( KTTestDataExt ); int main() diff --git a/Library/CMakeLists.txt b/Library/CMakeLists.txt index b89cec1..0c4dc89 100644 --- a/Library/CMakeLists.txt +++ b/Library/CMakeLists.txt @@ -30,6 +30,7 @@ set( NYMPH_HEADERFILES ${DATA_DIR}/KTCutResult.hh ${DATA_DIR}/KTCutStatus.hh ${DATA_DIR}/KTData.hh + ${DATA_DIR}/KTRegisterNymphExtData.hh ${PROC_DIR}/KTConnection.hh ${PROC_DIR}/KTPrimaryProcessor.hh ${PROC_DIR}/KTProcessor.hh diff --git a/Library/Data/KTRegisterNymphExtData.hh b/Library/Data/KTRegisterNymphExtData.hh new file mode 100644 index 0000000..cc2c479 --- /dev/null +++ b/Library/Data/KTRegisterNymphExtData.hh @@ -0,0 +1,29 @@ +/* + * KTRegisterNymphExtData.hh + * + * Created on: Feb 17, 2018 + * Author: N.S. Oblath + */ + +#ifndef NYMPH_KTREGISTERNYMPHEXTDATA_HH_ +#define NYMPH_KTREGISTERNYMPHEXTDATA_HH_ + +/** + * @file KTRegisterNymphExtData.hh + * + * Register the extensible data objects that live in Nymph here. + * This file should be included with registration headers packages using Nymph's extensible data setup. + * + * This header should be included _after_ the relevant archives are registered (after #include'ing the headers, generally) + * + */ + + +#include + +#include "KTCoreData.hh" + +CEREAL_REGISTER_TYPE( Nymph::KTCoreDataExt ); + + +#endif /* NYMPH_KTREGISTERNYMPHEXTDATA_HH_ */ From acc058ba2be478bf8bd42b44885ee24dc48b75a9 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Sat, 17 Feb 2018 21:32:40 -0600 Subject: [PATCH 103/521] JSON Writer outputs data. Added typist for validation. --- Executables/Validation/CMakeLists.txt | 4 ++- Executables/Validation/KTJSONWriter.cc | 10 +++--- Executables/Validation/KTJSONWriter.hh | 32 +++++++++++-------- .../Validation/KTJSONWriterValidation.cc | 29 +++++++++++++++++ .../Validation/KTJSONWriterValidation.hh | 32 +++++++++++++++++++ .../KTRegisterNymphValidationExtData.hh | 19 +++++++++++ Executables/Validation/KTTestData.hh | 13 ++++++++ Executables/Validation/TestJSONWriter.cc | 6 ++-- 8 files changed, 123 insertions(+), 22 deletions(-) create mode 100644 Executables/Validation/KTJSONWriterValidation.cc create mode 100644 Executables/Validation/KTJSONWriterValidation.hh create mode 100644 Executables/Validation/KTRegisterNymphValidationExtData.hh diff --git a/Executables/Validation/CMakeLists.txt b/Executables/Validation/CMakeLists.txt index e7d8423..5c1d43f 100644 --- a/Executables/Validation/CMakeLists.txt +++ b/Executables/Validation/CMakeLists.txt @@ -13,8 +13,9 @@ if (Nymph_ENABLE_TESTING) # Headers for any test classes set (VALIDATION_HEADERFILES - kTJSONReader.hh + KTJSONReader.hh KTJSONWriter.hh + KTJSONWriterValidation.hh KTTestConfigurable.hh KTTestCuts.hh KTTestData.hh @@ -25,6 +26,7 @@ if (Nymph_ENABLE_TESTING) set (VALIDATION_SOURCEFILES KTJSONReader.cc KTJSONWriter.cc + KTJSONWriterValidation.cc KTTestConfigurable.cc KTTestCuts.cc KTTestData.cc diff --git a/Executables/Validation/KTJSONWriter.cc b/Executables/Validation/KTJSONWriter.cc index 7272c49..6b8f489 100644 --- a/Executables/Validation/KTJSONWriter.cc +++ b/Executables/Validation/KTJSONWriter.cc @@ -2,24 +2,24 @@ * KTJSONWriter.cc * * Created on: Feb 1, 2018 - * Author: E Zayas + * Author: N.S. Oblath * */ #include "KTJSONWriter.hh" + #include "KTLogger.hh" namespace Nymph { KTJSONWriter::KTJSONWriter( const std::string& name ) : - KTProcessor( name ), + KTWriterWithTypists< KTJSONWriter, KTJSONWriterTypist >( name ), fFilename( "json_writer_default_file.json" ), fStreamOutPtr( nullptr ), - fArchiveOutPtr( nullptr ) + fArchiveOutPtr( nullptr ), + fCoreDataSlot( "core", this, &KTJSONWriter::WriteData< KTCoreDataExt > ) { - // Register slots here - RegisterSlot( "test-data", this, &KTJSONWriter::WriteData< KTTestData > ); } KTJSONWriter::~KTJSONWriter() diff --git a/Executables/Validation/KTJSONWriter.hh b/Executables/Validation/KTJSONWriter.hh index 6dad8e9..6122d5b 100644 --- a/Executables/Validation/KTJSONWriter.hh +++ b/Executables/Validation/KTJSONWriter.hh @@ -2,33 +2,37 @@ * KTJSONWriter.hh * * Created on: Feb 1, 2018 - * Author: E Zayas + * Author: N.S. Oblath * */ -#ifndef KTJSONWRITER_HH_ -#define KTJSONWRITER_HH_ +#ifndef NYMPH_KTJSONWRITER_HH_ +#define NYMPH_KTJSONWRITER_HH_ -#include "KTData.hh" -#include "KTProcessor.hh" +// included first so that the archive is registered before the data classes +#include "cereal/archives/json.hpp" + +#include "KTWriter.hh" #include "KTSlot.hh" -#include "KTTestData.hh" +#include "KTRegisterNymphValidationExtData.hh" #include "KTLogger.hh" -#include "cereal/archives/json.hpp" - #include KTLOGGER( avlog_hh, "KTJSONWriter" ); namespace Nymph { - class KTJSONWriter : public KTProcessor + class KTJSONWriter; + + typedef KTDerivedTypeWriter< KTJSONWriter > KTJSONWriterTypist; + + class KTJSONWriter : public KTWriterWithTypists< KTJSONWriter, KTJSONWriterTypist > { public: - KTJSONWriter( const std::string& name = "serial-writer" ); + KTJSONWriter( const std::string& name = "json-writer" ); virtual ~KTJSONWriter(); bool Configure( const scarab::param_node& node ); @@ -37,16 +41,18 @@ namespace Nymph public: template< class XDataType > - void WriteData( XDataType& data ); + void WriteData( const XDataType& data ); private: std::ofstream* fStreamOutPtr; cereal::JSONOutputArchive* fArchiveOutPtr; + private: + KTSlotData< void, KTCoreDataExt > fCoreDataSlot; }; template< class XDataType > - void KTJSONWriter::WriteData( XDataType& data ) + void KTJSONWriter::WriteData( const XDataType& data ) { if( fStreamOutPtr == nullptr ) { @@ -64,4 +70,4 @@ namespace Nymph } // namespace Nymph -#endif // KTJSONWRITER_HH_ +#endif // NYMPH_KTJSONWRITER_HH_ diff --git a/Executables/Validation/KTJSONWriterValidation.cc b/Executables/Validation/KTJSONWriterValidation.cc new file mode 100644 index 0000000..4de7df4 --- /dev/null +++ b/Executables/Validation/KTJSONWriterValidation.cc @@ -0,0 +1,29 @@ +/* + * KTJSONWriterValidation.cc + * + * Created on: Feb 17, 2018 + * Author: N.S. Oblath + */ + +#include "KTJSONWriterValidation.hh" + +#include "KTTestData.hh" + +namespace Nymph +{ + + KTJSONWriterValidation::KTJSONWriterValidation() : + KTJSONWriterTypist(), + fTestDataSlot( "test", fWriter, &KTJSONWriter::WriteData< KTTestDataExt > ) + { + } + + KTJSONWriterValidation::~KTJSONWriterValidation() + { + } + + void KTJSONWriterValidation::RegisterSlots() + { + } + +} /* namespace Nymph */ diff --git a/Executables/Validation/KTJSONWriterValidation.hh b/Executables/Validation/KTJSONWriterValidation.hh new file mode 100644 index 0000000..4141e80 --- /dev/null +++ b/Executables/Validation/KTJSONWriterValidation.hh @@ -0,0 +1,32 @@ +/* + * KTJSONWriterValidation.hh + * + * Created on: Feb 17, 2018 + * Author: N.S. Oblath + */ + +#ifndef NYMPH_KTJSONWRITERVALIDATION_HH_ +#define NYMPH_KTJSONWRITERVALIDATION_HH_ + +#include "KTJSONWriter.hh" + +namespace Nymph +{ + class KTTestDataExt; + + class KTJSONWriterValidation : public KTJSONWriterTypist + { + public: + KTJSONWriterValidation(); + virtual ~KTJSONWriterValidation(); + + virtual void RegisterSlots(); + + private: + KTSlotData< void, KTTestDataExt > fTestDataSlot; + + }; + +} /* namespace Nymph */ + +#endif /* NYMPH_KTJSONWRITERVALIDATION_HH_ */ diff --git a/Executables/Validation/KTRegisterNymphValidationExtData.hh b/Executables/Validation/KTRegisterNymphValidationExtData.hh new file mode 100644 index 0000000..efa5da6 --- /dev/null +++ b/Executables/Validation/KTRegisterNymphValidationExtData.hh @@ -0,0 +1,19 @@ +/* + * KTRegisterNymphValidationExtData.hh + * + * Created on: Feb 17, 2018 + * Author: N.S. Oblath + */ + +#ifndef NYMPH_KTREGISTERNYMPHVALIDATIONEXTDATA_HH_ +#define NYMPH_KTREGISTERNYMPHVALIDATIONEXTDATA_HH_ + +#include "KTRegisterNymphExtData.hh" + +#include "KTTestData.hh" + +CEREAL_REGISTER_TYPE( Nymph::KTTestDataExt ); +CEREAL_REGISTER_TYPE( Nymph::KTTestDerived1DataExt ); +CEREAL_REGISTER_TYPE( Nymph::KTTestDerived2DataExt ); + +#endif /* NYMPH_KTREGISTERNYMPHVALIDATIONEXTDATA_HH_ */ diff --git a/Executables/Validation/KTTestData.hh b/Executables/Validation/KTTestData.hh index b771114..e2fdc00 100644 --- a/Executables/Validation/KTTestData.hh +++ b/Executables/Validation/KTTestData.hh @@ -43,6 +43,12 @@ namespace Nymph virtual ~KTTestBaseData() {} MEMBERVARIABLE(double, Funniness); + + private: + friend class cereal::access; + + template< class Archive > + void serialize( Archive& ar ); }; DEFINE_EXT_DATA_2( KTTestDerived1DataExt, KTTestBaseData, "test-derived-1" ); @@ -56,6 +62,13 @@ namespace Nymph ar( cereal::base_class< KTData >( this ), fIsAwesome ); } + template< class Archive > + void KTTestBaseData::serialize( Archive& ar ) + { + std::cout << "### serialize for KTTestBaseData" << std::endl; + ar( cereal::base_class< KTData >( this ), fFunniness ); + } + } /* namespace Nymph */ #endif /* NYMPH_KTTESTDATA_HH_ */ diff --git a/Executables/Validation/TestJSONWriter.cc b/Executables/Validation/TestJSONWriter.cc index c6320f0..3a6d567 100644 --- a/Executables/Validation/TestJSONWriter.cc +++ b/Executables/Validation/TestJSONWriter.cc @@ -6,8 +6,8 @@ * */ -#include "KTJSONWriter.hh" #include "KTJSONReader.hh" +#include "KTJSONWriter.hh" #include "KTTestData.hh" @@ -36,7 +36,7 @@ int main() // destruction of the stream and archive (in the writer's destructor) properly closes the file } - +/* { KTTestData newTestData; @@ -47,7 +47,7 @@ int main() KTINFO( testlog, "Is the read data awesome? " << newTestData.GetIsAwesome() ); } - +*/ KTINFO( testlog, "Validation script concluded" ); return 0; } From df94bbb09e4c3c96a1dfb001d11429621c136fe3 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Sat, 17 Feb 2018 21:45:46 -0600 Subject: [PATCH 104/521] Added KTTestDataPrimaryProcessor to Validation --- Executables/Validation/CMakeLists.txt | 2 + .../Validation/KTTestDataPrimaryProcessor.cc | 53 +++++++++++++++++++ .../Validation/KTTestDataPrimaryProcessor.hh | 40 ++++++++++++++ 3 files changed, 95 insertions(+) create mode 100644 Executables/Validation/KTTestDataPrimaryProcessor.cc create mode 100644 Executables/Validation/KTTestDataPrimaryProcessor.hh diff --git a/Executables/Validation/CMakeLists.txt b/Executables/Validation/CMakeLists.txt index 5c1d43f..3585fc8 100644 --- a/Executables/Validation/CMakeLists.txt +++ b/Executables/Validation/CMakeLists.txt @@ -19,6 +19,7 @@ if (Nymph_ENABLE_TESTING) KTTestConfigurable.hh KTTestCuts.hh KTTestData.hh + KTTestDataPrimaryProcessor.hh KTTestPrimaryProcessor.hh KTTestProcessor.hh ) @@ -30,6 +31,7 @@ if (Nymph_ENABLE_TESTING) KTTestConfigurable.cc KTTestCuts.cc KTTestData.cc + KTTestDataPrimaryProcessor.cc KTTestPrimaryProcessor.cc KTTestProcessor.cc ) diff --git a/Executables/Validation/KTTestDataPrimaryProcessor.cc b/Executables/Validation/KTTestDataPrimaryProcessor.cc new file mode 100644 index 0000000..0a7753a --- /dev/null +++ b/Executables/Validation/KTTestDataPrimaryProcessor.cc @@ -0,0 +1,53 @@ +/* + * KTTestDataPrimaryProcessor.cc + * + * Created on: Feb 17, 2018 + * Author: N.S. Oblath + */ + +#include "KTTestDataPrimaryProcessor.hh" + +#include "KTTestData.hh" + +namespace Nymph +{ + + KT_REGISTER_PROCESSOR(KTTestDataPrimaryProcessor, "test-data-p-proc"); + + KTTestDataPrimaryProcessor::KTTestDataPrimaryProcessor( const std::string& name ) : + KTPrimaryProcessor( {"derived-1"}, name ), + fIterations(10), + fTheSignal("derived-1", this) + { + } + + KTTestDataPrimaryProcessor::~KTTestDataPrimaryProcessor() + { + } + + bool KTTestDataPrimaryProcessor::Configure( const scarab::param_node& node ) + { + SetIterations( node.get_value( "iterations", GetIterations() ) ); + + return true; + } + + bool KTTestDataPrimaryProcessor::Run() + { + for( unsigned iIteration = 0; iIteration < fIterations; ++iIteration ) + { + // e.g. for a real processor, do some work here instead of sleeping + boost::this_thread::sleep_for( boost::chrono::milliseconds(1) ); + + if( fThreadRef->GetCanceled() ) break; + + KTDataHandle handle = CreateNewDataHandle(); + KTTestDerived1DataExt& testData = handle->Of< KTTestDerived1DataExt >(); + testData.SetFunniness( 867 ); + + fTheSignal( handle ); + } + return true; + } + +} /* namespace Nymph */ diff --git a/Executables/Validation/KTTestDataPrimaryProcessor.hh b/Executables/Validation/KTTestDataPrimaryProcessor.hh new file mode 100644 index 0000000..96b6955 --- /dev/null +++ b/Executables/Validation/KTTestDataPrimaryProcessor.hh @@ -0,0 +1,40 @@ +/* + * KTTestPrimaryProcessor.hh + * + * Created on: Feb 17, 2018 + * Author: N.S. Oblath + */ + +#ifndef KTTESTDATAPRIMARYPROCESSOR_HH_ +#define KTTESTDATAPRIMARYPROCESSOR_HH_ + +#include "KTPrimaryProcessor.hh" + +#include "KTMemberVariable.hh" +#include "KTSignal.hh" + +namespace Nymph +{ + + class KTTestDataPrimaryProcessor : public KTPrimaryProcessor + { + public: + KTTestDataPrimaryProcessor( const std::string& name = "test-data-p-proc" ); + virtual ~KTTestDataPrimaryProcessor(); + + public: + bool Configure( const scarab::param_node& node ); + + MEMBERVARIABLE( unsigned, Iterations ); + + public: + virtual bool Run(); + + private: + KTSignalData fTheSignal; + + }; + +} /* namespace Nymph */ + +#endif /* KTTESTDATAPRIMARYPROCESSOR_HH_ */ From 3c2b0b00b26c5c0098b920ae0b875e70cb6a0ccf Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Sat, 17 Feb 2018 23:19:57 -0600 Subject: [PATCH 105/521] Added constructor argumnts to KTTIFactory --- Library/Utility/KTTIFactory.hh | 221 +++++++++++++++++++++++++++++---- 1 file changed, 199 insertions(+), 22 deletions(-) diff --git a/Library/Utility/KTTIFactory.hh b/Library/Utility/KTTIFactory.hh index c2c0ccf..294bafe 100644 --- a/Library/Utility/KTTIFactory.hh +++ b/Library/Utility/KTTIFactory.hh @@ -21,11 +21,90 @@ namespace Nymph { KTLOGGER(utillog_ti_factory, "KTTIFactory"); - template< class XBaseType > + //******************** + // Class definitions + //******************** + + template< class XBaseType, typename ... XArgs > class KTTIFactory; - template< class XBaseType > + template< class XBaseType, typename ... XArgs > class KTTIRegistrarBase + { + public: + KTTIRegistrarBase() {} + virtual ~KTTIRegistrarBase() {} + + public: + friend class KTTIFactory< XBaseType, XArgs... >; + + protected: + virtual XBaseType* Create(XArgs ... args) const = 0; + + }; + + template< class XBaseType, class XDerivedType, typename ... XArgs > + class KTTIRegistrar : public KTTIRegistrarBase< XBaseType, XArgs... > + { + public: + KTTIRegistrar(); + virtual ~KTTIRegistrar(); + + protected: + void Register() const; + + XBaseType* Create(XArgs ... args) const; + + }; + + + template< class XBaseType, typename ... XArgs > + class KTTIFactory : public scarab::singleton< KTTIFactory< XBaseType, XArgs... > > + { + public: + struct CompareTypeInfo + { + bool operator() (const std::type_info* lhs, const std::type_info* rhs) + { + return lhs->before(*rhs); + } + }; + + public: + typedef std::map< const std::type_info*, const KTTIRegistrarBase< XBaseType, XArgs... >* > FactoryMap; + typedef typename FactoryMap::value_type FactoryEntry; + typedef typename FactoryMap::iterator FactoryIt; + typedef typename FactoryMap::const_iterator FactoryCIt; + + public: + template< class XDerivedType > + XBaseType* Create(XArgs ... args); + + XBaseType* Create(const FactoryCIt& iter, XArgs ... args); + + template< class XDerivedType > + void Register(const KTTIRegistrarBase< XBaseType, XArgs... >* registrar); + + FactoryCIt GetFactoryMapBegin() const; + FactoryCIt GetFactoryMapEnd() const; + + protected: + FactoryMap* fMap; + + + protected: + friend class scarab::singleton< KTTIFactory >; + friend class scarab::destroyer< KTTIFactory >; + KTTIFactory(); + ~KTTIFactory(); + }; + + //***************************************** + // Partial specialization for empty XArgs + //***************************************** + + template< class XBaseType > + class KTTIRegistrarBase< XBaseType, void > { public: KTTIRegistrarBase() {} @@ -40,7 +119,7 @@ namespace Nymph }; template< class XBaseType, class XDerivedType > - class KTTIRegistrar : public KTTIRegistrarBase< XBaseType > + class KTTIRegistrar< XBaseType, XDerivedType, void > : public KTTIRegistrarBase< XBaseType, void > { public: KTTIRegistrar(); @@ -55,7 +134,7 @@ namespace Nymph template< class XBaseType > - class KTTIFactory : public scarab::singleton< KTTIFactory< XBaseType > > + class KTTIFactory< XBaseType, void > : public scarab::singleton< KTTIFactory< XBaseType, void > > { public: struct CompareTypeInfo @@ -67,7 +146,7 @@ namespace Nymph }; public: - typedef std::map< const std::type_info*, const KTTIRegistrarBase< XBaseType >* > FactoryMap; + typedef std::map< const std::type_info*, const KTTIRegistrarBase< XBaseType, void >* > FactoryMap; typedef typename FactoryMap::value_type FactoryEntry; typedef typename FactoryMap::iterator FactoryIt; typedef typename FactoryMap::const_iterator FactoryCIt; @@ -79,7 +158,7 @@ namespace Nymph XBaseType* Create(const FactoryCIt& iter); template< class XDerivedType > - void Register(const KTTIRegistrarBase< XBaseType >* registrar); + void Register(const KTTIRegistrarBase< XBaseType, void >* registrar); FactoryCIt GetFactoryMapBegin() const; FactoryCIt GetFactoryMapEnd() const; @@ -95,9 +174,108 @@ namespace Nymph ~KTTIFactory(); }; + + //****************** + // Implementations + //****************** + + // Factory + + template< class XBaseType, typename ... XArgs > + template< class XDerivedType > + XBaseType* KTTIFactory< XBaseType, XArgs... >::Create(XArgs ... args) + { + FactoryCIt it = fMap->find(&typeid(XDerivedType)); + if (it == fMap->end()) + { + KTERROR(utillog_ti_factory, "Did not find factory with type <" << typeid(XDerivedType).name() << ">."); + return NULL; + } + + return it->second->Create(args...); + } + + template< class XBaseType, typename ... XArgs > + XBaseType* KTTIFactory< XBaseType, XArgs... >::Create(const FactoryCIt& iter, XArgs ... args) + { + return iter->second->Create(args...); + } + + template< class XBaseType, typename ... XArgs > + template< class XDerivedType > + void KTTIFactory< XBaseType, XArgs... >::Register(const KTTIRegistrarBase< XBaseType, XArgs... >* registrar) + { + // A local (static) logger is created inside this function to avoid static initialization order problems + KTLOGGER(utillog_ti_factory_reg, "KTTIFactory-Register"); + + FactoryCIt it = fMap->find(&typeid(XDerivedType)); + if (it != fMap->end()) + { + KTERROR(utillog_ti_factory_reg, "Already have factory registered for type <" << typeid(XDerivedType).name() << ">."); + return; + } + fMap->insert(std::pair< const std::type_info*, const KTTIRegistrarBase< XBaseType, XArgs... >* >(&typeid(XDerivedType), registrar)); + KTDEBUG(utillog_ti_factory_reg, "Registered a factory for class type " << typeid(XDerivedType).name() << ", factory #" << fMap->size()-1); + } + + template< class XBaseType, typename ... XArgs > + KTTIFactory< XBaseType, XArgs... >::KTTIFactory() : + fMap(new FactoryMap()) + {} + + template< class XBaseType, typename ... XArgs > + KTTIFactory< XBaseType, XArgs... >::~KTTIFactory() + { + delete fMap; + } + + template< class XBaseType, typename ... XArgs > + typename KTTIFactory< XBaseType, XArgs... >::FactoryCIt KTTIFactory< XBaseType, XArgs... >::GetFactoryMapBegin() const + { + return fMap->begin(); + } + + template< class XBaseType, typename ... XArgs > + typename KTTIFactory< XBaseType, XArgs... >::FactoryCIt KTTIFactory< XBaseType, XArgs... >::GetFactoryMapEnd() const + { + return fMap->end(); + } + + // Registrar + + template< class XBaseType, class XDerivedType, typename ... XArgs > + KTTIRegistrar< XBaseType, XDerivedType, XArgs... >::KTTIRegistrar() : + KTTIRegistrarBase< XBaseType, XArgs... >() + { + Register(); + } + + template< class XBaseType, class XDerivedType, typename ... XArgs > + KTTIRegistrar< XBaseType, XDerivedType, XArgs... >::~KTTIRegistrar() + {} + + template< class XBaseType, class XDerivedType, typename ... XArgs > + void KTTIRegistrar< XBaseType, XDerivedType, XArgs... >::Register() const + { + KTTIFactory< XBaseType, XArgs... >::get_instance()->template Register(this); + return; + } + + template< class XBaseType, class XDerivedType, typename ... XArgs > + XBaseType* KTTIRegistrar< XBaseType, XDerivedType, XArgs... >::Create(XArgs ... args) const + { + return dynamic_cast< XBaseType* >(new XDerivedType(args...)); + } + + //******************************************* + // Implementations (partial specialization) + //******************************************* + + // Factory + template< class XBaseType > template< class XDerivedType > - XBaseType* KTTIFactory< XBaseType >::Create() + XBaseType* KTTIFactory< XBaseType, void >::Create() { FactoryCIt it = fMap->find(&typeid(XDerivedType)); if (it == fMap->end()) @@ -110,14 +288,14 @@ namespace Nymph } template< class XBaseType > - XBaseType* KTTIFactory< XBaseType >::Create(const FactoryCIt& iter) + XBaseType* KTTIFactory< XBaseType, void >::Create(const FactoryCIt& iter) { return iter->second->Create(); } template< class XBaseType > template< class XDerivedType > - void KTTIFactory< XBaseType >::Register(const KTTIRegistrarBase< XBaseType >* registrar) + void KTTIFactory< XBaseType, void >::Register(const KTTIRegistrarBase< XBaseType, void >* registrar) { // A local (static) logger is created inside this function to avoid static initialization order problems KTLOGGER(utillog_ti_factory_reg, "KTTIFactory-Register"); @@ -128,56 +306,55 @@ namespace Nymph KTERROR(utillog_ti_factory_reg, "Already have factory registered for type <" << typeid(XDerivedType).name() << ">."); return; } - fMap->insert(std::pair< const std::type_info*, const KTTIRegistrarBase< XBaseType >* >(&typeid(XDerivedType), registrar)); + fMap->insert(std::pair< const std::type_info*, const KTTIRegistrarBase< XBaseType, void >* >(&typeid(XDerivedType), registrar)); KTDEBUG(utillog_ti_factory_reg, "Registered a factory for class type " << typeid(XDerivedType).name() << ", factory #" << fMap->size()-1); } template< class XBaseType > - KTTIFactory< XBaseType >::KTTIFactory() : + KTTIFactory< XBaseType, void >::KTTIFactory() : fMap(new FactoryMap()) {} template< class XBaseType > - KTTIFactory< XBaseType >::~KTTIFactory() + KTTIFactory< XBaseType, void >::~KTTIFactory() { delete fMap; } template< class XBaseType > - typename KTTIFactory< XBaseType >::FactoryCIt KTTIFactory< XBaseType >::GetFactoryMapBegin() const + typename KTTIFactory< XBaseType, void >::FactoryCIt KTTIFactory< XBaseType, void >::GetFactoryMapBegin() const { return fMap->begin(); } template< class XBaseType > - typename KTTIFactory< XBaseType >::FactoryCIt KTTIFactory< XBaseType >::GetFactoryMapEnd() const + typename KTTIFactory< XBaseType, void >::FactoryCIt KTTIFactory< XBaseType, void >::GetFactoryMapEnd() const { return fMap->end(); } - - + // Registrar template< class XBaseType, class XDerivedType > - KTTIRegistrar< XBaseType, XDerivedType >::KTTIRegistrar() : - KTTIRegistrarBase< XBaseType >() + KTTIRegistrar< XBaseType, XDerivedType, void >::KTTIRegistrar() : + KTTIRegistrarBase< XBaseType, void >() { Register(); } template< class XBaseType, class XDerivedType > - KTTIRegistrar< XBaseType, XDerivedType >::~KTTIRegistrar() + KTTIRegistrar< XBaseType, XDerivedType, void >::~KTTIRegistrar() {} template< class XBaseType, class XDerivedType > - void KTTIRegistrar< XBaseType, XDerivedType >::Register() const + void KTTIRegistrar< XBaseType, XDerivedType, void >::Register() const { - KTTIFactory< XBaseType >::get_instance()->template Register(this); + KTTIFactory< XBaseType, void >::get_instance()->template Register(this); return; } template< class XBaseType, class XDerivedType > - XBaseType* KTTIRegistrar< XBaseType, XDerivedType >::Create() const + XBaseType* KTTIRegistrar< XBaseType, XDerivedType, void >::Create() const { return dynamic_cast< XBaseType* >(new XDerivedType()); } From 9739b6eca909a49b2d9cd80fadc1aff3d95f43e6 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Sat, 17 Feb 2018 23:21:45 -0600 Subject: [PATCH 106/521] Added type writer registration macro and TestJSONWriterViaSlot.cc --- Executables/Validation/CMakeLists.txt | 1 + Executables/Validation/KTJSONWriter.cc | 2 +- Executables/Validation/KTJSONWriter.hh | 4 +- .../Validation/KTJSONWriterValidation.cc | 14 ++++-- .../Validation/KTJSONWriterValidation.hh | 12 +++-- .../Validation/KTTestDataPrimaryProcessor.cc | 4 +- .../Validation/TestJSONWriterViaSlot.cc | 46 +++++++++++++++++++ Library/IO/KTWriter.hh | 16 ++++--- 8 files changed, 78 insertions(+), 21 deletions(-) create mode 100644 Executables/Validation/TestJSONWriterViaSlot.cc diff --git a/Executables/Validation/CMakeLists.txt b/Executables/Validation/CMakeLists.txt index 3585fc8..7cc7e0e 100644 --- a/Executables/Validation/CMakeLists.txt +++ b/Executables/Validation/CMakeLists.txt @@ -63,6 +63,7 @@ if (Nymph_ENABLE_TESTING) TestExt TestExtSerialization TestJSONWriter + TestJSONWriterViaSlot TestLogger TestPolymorphicSlotData TestPrimaryProcessor diff --git a/Executables/Validation/KTJSONWriter.cc b/Executables/Validation/KTJSONWriter.cc index 6b8f489..6723611 100644 --- a/Executables/Validation/KTJSONWriter.cc +++ b/Executables/Validation/KTJSONWriter.cc @@ -14,7 +14,7 @@ namespace Nymph { KTJSONWriter::KTJSONWriter( const std::string& name ) : - KTWriterWithTypists< KTJSONWriter, KTJSONWriterTypist >( name ), + KTWriterWithTypists< KTJSONWriter, KTJSONTypeWriter >( name ), fFilename( "json_writer_default_file.json" ), fStreamOutPtr( nullptr ), fArchiveOutPtr( nullptr ), diff --git a/Executables/Validation/KTJSONWriter.hh b/Executables/Validation/KTJSONWriter.hh index 6122d5b..b16e8fa 100644 --- a/Executables/Validation/KTJSONWriter.hh +++ b/Executables/Validation/KTJSONWriter.hh @@ -27,9 +27,9 @@ namespace Nymph { class KTJSONWriter; - typedef KTDerivedTypeWriter< KTJSONWriter > KTJSONWriterTypist; + typedef KTDerivedTypeWriter< KTJSONWriter > KTJSONTypeWriter; - class KTJSONWriter : public KTWriterWithTypists< KTJSONWriter, KTJSONWriterTypist > + class KTJSONWriter : public KTWriterWithTypists< KTJSONWriter, KTJSONTypeWriter > { public: KTJSONWriter( const std::string& name = "json-writer" ); diff --git a/Executables/Validation/KTJSONWriterValidation.cc b/Executables/Validation/KTJSONWriterValidation.cc index 4de7df4..3279a6c 100644 --- a/Executables/Validation/KTJSONWriterValidation.cc +++ b/Executables/Validation/KTJSONWriterValidation.cc @@ -11,18 +11,22 @@ namespace Nymph { + KT_REGISTER_TYPE_WRITER( KTJSONWriter, KTJSONTypeWriter, Validation ); - KTJSONWriterValidation::KTJSONWriterValidation() : - KTJSONWriterTypist(), - fTestDataSlot( "test", fWriter, &KTJSONWriter::WriteData< KTTestDataExt > ) + KTJSONTypeWriterValidation::KTJSONTypeWriterValidation( KTJSONWriter* writer) : + KTJSONTypeWriter( writer ), + fTestSlot( "test", fWriter, &KTJSONWriter::WriteData< KTTestDataExt > ), + fTestDerived1Slot( "test-derived-1", fWriter, &KTJSONWriter::WriteData< KTTestDerived1DataExt > ), + fTestDerived2Slot( "test-derived-2", fWriter, &KTJSONWriter::WriteData< KTTestDerived2DataExt > ) { + std::cout << "Created a KTJSONWriterValidation" << std::endl; } - KTJSONWriterValidation::~KTJSONWriterValidation() + KTJSONTypeWriterValidation::~KTJSONTypeWriterValidation() { } - void KTJSONWriterValidation::RegisterSlots() + void KTJSONTypeWriterValidation::RegisterSlots() { } diff --git a/Executables/Validation/KTJSONWriterValidation.hh b/Executables/Validation/KTJSONWriterValidation.hh index 4141e80..49ed6cc 100644 --- a/Executables/Validation/KTJSONWriterValidation.hh +++ b/Executables/Validation/KTJSONWriterValidation.hh @@ -13,17 +13,21 @@ namespace Nymph { class KTTestDataExt; + class KTTestDerived1DataExt; + class KTTestDerived2DataExt; - class KTJSONWriterValidation : public KTJSONWriterTypist + class KTJSONTypeWriterValidation : public KTJSONTypeWriter { public: - KTJSONWriterValidation(); - virtual ~KTJSONWriterValidation(); + KTJSONTypeWriterValidation( KTJSONWriter* writer ); + virtual ~KTJSONTypeWriterValidation(); virtual void RegisterSlots(); private: - KTSlotData< void, KTTestDataExt > fTestDataSlot; + KTSlotData< void, KTTestDataExt > fTestSlot; + KTSlotData< void, KTTestDerived1DataExt > fTestDerived1Slot; + KTSlotData< void, KTTestDerived2DataExt > fTestDerived2Slot; }; diff --git a/Executables/Validation/KTTestDataPrimaryProcessor.cc b/Executables/Validation/KTTestDataPrimaryProcessor.cc index 0a7753a..f6d3cd3 100644 --- a/Executables/Validation/KTTestDataPrimaryProcessor.cc +++ b/Executables/Validation/KTTestDataPrimaryProcessor.cc @@ -15,9 +15,9 @@ namespace Nymph KT_REGISTER_PROCESSOR(KTTestDataPrimaryProcessor, "test-data-p-proc"); KTTestDataPrimaryProcessor::KTTestDataPrimaryProcessor( const std::string& name ) : - KTPrimaryProcessor( {"derived-1"}, name ), + KTPrimaryProcessor( {"test-derived-1"}, name ), fIterations(10), - fTheSignal("derived-1", this) + fTheSignal("test-derived-1", this) { } diff --git a/Executables/Validation/TestJSONWriterViaSlot.cc b/Executables/Validation/TestJSONWriterViaSlot.cc new file mode 100644 index 0000000..66ced7e --- /dev/null +++ b/Executables/Validation/TestJSONWriterViaSlot.cc @@ -0,0 +1,46 @@ +/* + * TestJSONWriterViaSlot.cc + * + * Created on: Feb 17, 2018 + * Author: N.S. Oblath + */ + +#include "KTTestDataPrimaryProcessor.hh" +#include "KTJSONWriterValidation.hh" + +#include "KTLogger.hh" + +using namespace Nymph; + +KTLOGGER( testlog, "TestJSONWriterViaSlot" ) + +int main() +{ + + try + { + KTINFO( testlog, "Creating processors" ); + KTTestDataPrimaryProcessor tdpp; + KTJSONWriter jw; + + KTINFO( testlog, "Connecting the-signal to first-slot" ); + tdpp.ConnectASlot( "test-derived-1", &jw, "test-derived-1", 20 ); + + KTINFO( testlog, "Running the primary processor" ) + + if( ! tdpp.Run() ) + { + KTERROR( testlog, "Something went wrong while running the primary processor" ); + return -1; + } + + KTINFO( testlog, "Tests complete" ); + } + catch( boost::exception& e ) + { + KTERROR( testlog, "An unexpected exception was caught: " << diagnostic_information( e ) ); + return -1; + } + + return 0; +} diff --git a/Library/IO/KTWriter.hh b/Library/IO/KTWriter.hh index e89b677..278e680 100644 --- a/Library/IO/KTWriter.hh +++ b/Library/IO/KTWriter.hh @@ -33,7 +33,7 @@ namespace Nymph class KTDerivedTypeWriter : public KTTypeWriter { public: - KTDerivedTypeWriter(); + KTDerivedTypeWriter(XWriter* writer); virtual ~KTDerivedTypeWriter(); void SetWriter(XWriter* writer); @@ -44,9 +44,9 @@ namespace Nymph template< class XWriter > - KTDerivedTypeWriter< XWriter >::KTDerivedTypeWriter() : + KTDerivedTypeWriter< XWriter >::KTDerivedTypeWriter(XWriter* writer) : KTTypeWriter(), - fWriter(NULL) + fWriter(writer) { } @@ -96,13 +96,13 @@ namespace Nymph KTWriter(name), fTypeWriters() { - KTTIFactory< XTypist >* twFactory = KTTIFactory< XTypist >::get_instance(); - for (typename KTTIFactory< XTypist >::FactoryCIt factoryIt = twFactory->GetFactoryMapBegin(); + KTTIFactory< XTypist, XWriter* >* twFactory = KTTIFactory< XTypist, XWriter* >::get_instance(); + for (typename KTTIFactory< XTypist, XWriter* >::FactoryCIt factoryIt = twFactory->GetFactoryMapBegin(); factoryIt != twFactory->GetFactoryMapEnd(); factoryIt++) { - XTypist* newTypeWriter = twFactory->Create(factoryIt); - newTypeWriter->SetWriter(static_cast< XWriter* >(this)); + XTypist* newTypeWriter = twFactory->Create(factoryIt, static_cast< XWriter* >(this)); + //newTypeWriter->SetWriter(static_cast< XWriter* >(this)); newTypeWriter->RegisterSlots(); fTypeWriters.insert(typename TypeWriterMap::value_type(factoryIt->first, newTypeWriter)); } @@ -130,6 +130,8 @@ namespace Nymph return static_cast< XTypeWriter* >(it->second); } +#define KT_REGISTER_TYPE_WRITER(writer_class, type_writer_base_class, typist) \ + static ::Nymph::KTTIRegistrar< type_writer_base_class, type_writer_base_class##typist, writer_class* > s##type_writer_base_class##typist##Registrar; #define KT_REGISTER_WRITER(writer_class, writer_name) \ static ::scarab::registrar< ::Nymph::KTWriter, writer_class, const std::string& > s##writer_class##WriterRegistrar(writer_name); From 04c28e9eb0b3389493e8240f63c5e149fb593afa Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Sat, 17 Feb 2018 23:36:55 -0600 Subject: [PATCH 107/521] Fix issue with checking non-existant thread ref --- Executables/Validation/KTTestDataPrimaryProcessor.cc | 2 +- Executables/Validation/KTTestPrimaryProcessor.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Executables/Validation/KTTestDataPrimaryProcessor.cc b/Executables/Validation/KTTestDataPrimaryProcessor.cc index f6d3cd3..528d059 100644 --- a/Executables/Validation/KTTestDataPrimaryProcessor.cc +++ b/Executables/Validation/KTTestDataPrimaryProcessor.cc @@ -39,7 +39,7 @@ namespace Nymph // e.g. for a real processor, do some work here instead of sleeping boost::this_thread::sleep_for( boost::chrono::milliseconds(1) ); - if( fThreadRef->GetCanceled() ) break; + if( fThreadRef && fThreadRef->GetCanceled() ) break; KTDataHandle handle = CreateNewDataHandle(); KTTestDerived1DataExt& testData = handle->Of< KTTestDerived1DataExt >(); diff --git a/Executables/Validation/KTTestPrimaryProcessor.cc b/Executables/Validation/KTTestPrimaryProcessor.cc index 897a728..43692c1 100644 --- a/Executables/Validation/KTTestPrimaryProcessor.cc +++ b/Executables/Validation/KTTestPrimaryProcessor.cc @@ -37,7 +37,7 @@ namespace Nymph // e.g. for a real processor, do some work here instead of sleeping boost::this_thread::sleep_for( boost::chrono::milliseconds(1) ); - if( fThreadRef->GetCanceled() ) break; + if( fThreadRef && fThreadRef->GetCanceled() ) break; fTheSignal( iIteration ); } From 2acf6f08903ce122713e5a2c7bf61da518ed6015 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Mon, 19 Feb 2018 16:40:39 -0800 Subject: [PATCH 108/521] Testing name-value pairs --- Executables/Validation/KTTestData.hh | 4 ++-- Executables/Validation/TestSerialization.cc | 13 +++++++++---- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/Executables/Validation/KTTestData.hh b/Executables/Validation/KTTestData.hh index e2fdc00..a181bfb 100644 --- a/Executables/Validation/KTTestData.hh +++ b/Executables/Validation/KTTestData.hh @@ -59,14 +59,14 @@ namespace Nymph void KTTestData::serialize( Archive& ar ) { std::cout << "### serialize for KTTestData" << std::endl; - ar( cereal::base_class< KTData >( this ), fIsAwesome ); + ar( cereal::base_class< KTData >( this ), CEREAL_NVP(fIsAwesome) ); } template< class Archive > void KTTestBaseData::serialize( Archive& ar ) { std::cout << "### serialize for KTTestBaseData" << std::endl; - ar( cereal::base_class< KTData >( this ), fFunniness ); + ar( cereal::base_class< KTData >( this ), CEREAL_NVP(fFunniness) ); } } /* namespace Nymph */ diff --git a/Executables/Validation/TestSerialization.cc b/Executables/Validation/TestSerialization.cc index df35a4d..ab97d7b 100644 --- a/Executables/Validation/TestSerialization.cc +++ b/Executables/Validation/TestSerialization.cc @@ -25,13 +25,16 @@ int main() { KTCoreData coreData; KTTestData testData; + KTTestBaseData testBaseData; // change data values from their defaults coreData.SetCounter( 5 ); testData.SetIsAwesome( true ); + testBaseData.SetFunniness( 923 ); KTINFO( testlog, "KTCoreData counter: " << coreData.GetCounter() ); KTINFO( testlog, "KTTestData is-awesome: " << testData.GetIsAwesome() ); + KTINFO( testlog, "KTTestBaseData funniness: " << testBaseData.GetFunniness() ); // create and open a file for output std::ofstream fileOut( filename ); @@ -39,7 +42,7 @@ int main() cereal::JSONOutputArchive archiveOut( fileOut ); KTINFO( testlog, "Writing data to JSON archive" ); - archiveOut( coreData, testData ); + archiveOut( CEREAL_NVP(coreData), CEREAL_NVP(testData), CEREAL_NVP(testBaseData) ); // archive and stream closed when destructors are called } @@ -48,6 +51,7 @@ int main() { KTCoreData newCoreData; KTTestData newTestData; + KTTestBaseData newTestBaseData; // create and open an archive for input std::ifstream fileIn( filename ); @@ -55,10 +59,11 @@ int main() cereal::JSONInputArchive archiveIn( fileIn ); KTINFO( testlog, "Reading data from JSON archive" ); - archiveIn( newCoreData, newTestData ); + archiveIn( newCoreData, newTestData, newTestBaseData ); - KTINFO(testlog, "KTCoreData counter: " << newCoreData.GetCounter()); - KTINFO(testlog, "KTTestData is-awesome: " << newTestData.GetIsAwesome()); + KTINFO( testlog, "KTCoreData counter: " << newCoreData.GetCounter() ); + KTINFO( testlog, "KTTestData is-awesome: " << newTestData.GetIsAwesome() ); + KTINFO( testlog, "KTTestBaseData funniness: " << newTestBaseData.GetFunniness() ); // archive and stream closed when destructors are called } From 32228884f542273660be014f81c8bf60bca54a3f Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Mon, 19 Feb 2018 17:07:04 -0800 Subject: [PATCH 109/521] Extended serialization to cut results and status, and updated the documentation in KTCutStatus --- Library/Data/KTCoreData.hh | 3 +- Library/Data/KTCutStatus.hh | 62 ++++++++++++++++++++++++++++++------- 2 files changed, 52 insertions(+), 13 deletions(-) diff --git a/Library/Data/KTCoreData.hh b/Library/Data/KTCoreData.hh index e81bf5a..f6d6901 100644 --- a/Library/Data/KTCoreData.hh +++ b/Library/Data/KTCoreData.hh @@ -39,8 +39,7 @@ namespace Nymph void serialize( Archive& ar ) { std::cout << "### serialize for KTCoreData" << std::endl; - ar( cereal::base_class< KTData >( this ), fCounter, fLastData ); - //ar( cereal::base_class< KTData >( this ), fCounter, fLastData, fCutStatus ); + ar( cereal::base_class< KTData >( this ), CEREAL_NVP(fCounter), CEREAL_NVP(fLastData), CEREAL_NVP(fCutStatus) ); } }; diff --git a/Library/Data/KTCutStatus.hh b/Library/Data/KTCutStatus.hh index 2f69f08..77c41ee 100644 --- a/Library/Data/KTCutStatus.hh +++ b/Library/Data/KTCutStatus.hh @@ -13,6 +13,10 @@ #include "KTException.hh" +#include "cereal/access.hpp" +#include "cereal/types/string.hpp" +#include "cereal/types/vector.hpp" + #include #include @@ -25,12 +29,16 @@ namespace Nymph @class KTCutStatus @author N. S. Oblath - @brief Provides easy access to cut information. + @brief Provides easy access to cut result information. @details + The cut results can be imagined as an array of booleans, specifying whether the cut was passed: [true, false, false, true, . . . ]. + + Cuts are assigned both an array position (non-negative integer) and a name (string) before or when the results are set. + KTCutStatus is typically used as a member variable of KTCoreData, the top-level data object. - KTCutStatus owns the set of cut results that have been added to a data object. + KTCutStatus owns the set of KTCutResults that have been added to a data object. It also owns a summary of those cuts (implemented with boost::dynamic_bitset). You can check if the data has been cut with the IsCut functions. @@ -44,16 +52,25 @@ namespace Nymph - std::string masks are strings with each character either a 0 or 1. With KTCutStatus you can interact with individual cut results in the following ways: - - Add cut results to a data object with AddCutResult, - - Check to see if a particular cut result is present using HasCutResult, - - Get the value of a cut result with GetCutState, - - Set the value of a cut result with SetCutState, - - Directly access the cut result with GetCutResult, and - - Remove a cut result with RemoveCutResult. - - For all except KTCutStatus::RemoveCutResult, the cut result can be identified by type or string name. + - Get the number of cut results with size(), + - Get a reference to the cut results with CutResults(), + - If you need to manually update the cut status bitset, use UpdateStatus(), + - Add cut results to a data object with AssignCutResult(), + - Remove a cut result with RemoveCutResult(), + - Check to see if a particular cut result is present using HasCutResult(), + - Get the value of a cut result with GetCutState(), and + - Set the value of a cut result with SetCutState(), + + Cut results can typically be accessed by either name or mask position. */ + // external serialization function for KTCutResult + template< class Archive > + void serialize( Archive & archive, KTCutResult& cutResult ) + { + archive( CEREAL_NVP(cutResult.fName), CEREAL_NVP(cutResult.fState), CEREAL_NVP(cutResult.fAssigned) ); + } + class KTCutStatus { public: @@ -112,7 +129,6 @@ namespace Nymph /// Returns a string with the names of the cuts that are present in bitset order std::string CutResultsPresent() const; - private: friend std::ostream& operator<<(std::ostream& out, const KTCutStatus& status); @@ -129,6 +145,15 @@ namespace Nymph bitset_type ToBitset(unsigned long long mask) const; bitset_type ToBitset(const std::string& mask) const; + private: + friend class cereal::access; + + template< class Archive > + void save( Archive& ar ) const; + + template< class Archive > + void load( Archive& ar ); + }; std::ostream& operator<<(std::ostream& out, const KTCutStatus& status); @@ -271,6 +296,21 @@ namespace Nymph return bitset_type(mask); } + template< class Archive > + void KTCutStatus::save( Archive& ar ) const + { + std::cout << "### save for KTCutStatus" << std::endl; + ar( CEREAL_NVP(fCutResults) ); + } + + template< class Archive > + void KTCutStatus::load( Archive& ar ) + { + std::cout << "### load for KTCutStatus" << std::endl; + ar( CEREAL_NVP(fCutResults) ); + UpdateStatus(); + } + } /* namespace Nymph */ #endif /* KTCUTSTATUS_HH_ */ From daed1294528ff02a8ec2fffed66b15ab14bf0e00 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Mon, 19 Feb 2018 17:56:52 -0800 Subject: [PATCH 110/521] More testing! --- Executables/Validation/TestExtSerialization.cc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Executables/Validation/TestExtSerialization.cc b/Executables/Validation/TestExtSerialization.cc index 2668eef..ae14d30 100644 --- a/Executables/Validation/TestExtSerialization.cc +++ b/Executables/Validation/TestExtSerialization.cc @@ -25,19 +25,22 @@ CEREAL_REGISTER_TYPE( KTTestDataExt ); int main() { - const std::string filename( "test_serialization_output.json" ); + const std::string filename( "test_ext_serialization_output.json" ); // save data to archive { std::shared_ptr< KTCoreDataExt > coreData = std::make_shared< KTCoreDataExt >(); std::shared_ptr< KTTestDataExt > testData = coreData->Share< KTTestDataExt >(); + std::shared_ptr< KTTestDerived1DataExt > testD1Data = coreData->Share< KTTestDerived1DataExt >(); // change data values from their defaults coreData->SetCounter( 5 ); testData->SetIsAwesome( true ); + testD1Data->SetFunniness( 924 ); KTINFO( testlog, "KTCoreData counter: " << coreData->GetCounter() ); KTINFO( testlog, "KTTestData is-awesome: " << testData->GetIsAwesome() ); + KTINFO( testlog, "KTTestDerived1Data funniness: " << testD1Data->GetFunniness() ); // create and open a file for output std::ofstream fileOut( filename ); @@ -63,9 +66,11 @@ int main() archiveIn( newCoreData ); std::shared_ptr< KTTestDataExt > newTestData = newCoreData->Share< KTTestDataExt >(); + std::shared_ptr< KTTestDerived1DataExt > newD1Data = newCoreData->Share< KTTestDerived1DataExt >(); KTINFO(testlog, "KTCoreData counter: " << newCoreData->GetCounter()); KTINFO(testlog, "KTTestData is-awesome: " << newTestData->GetIsAwesome()); + KTINFO( testlog, "KTTestDerived1Data funniness: " << newD1Data->GetFunniness() ); // archive and stream closed when destructors are called } From 242f45b0c4b1bdfa7f583610e7ef19420e287242 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Tue, 20 Feb 2018 14:02:42 -0800 Subject: [PATCH 111/521] Fixed bug in data-slot classes that caused duplication instead of reference passing --- Library/Processor/KTSlot.hh | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/Library/Processor/KTSlot.hh b/Library/Processor/KTSlot.hh index 6d486d6..8058273 100644 --- a/Library/Processor/KTSlot.hh +++ b/Library/Processor/KTSlot.hh @@ -159,14 +159,6 @@ namespace Nymph KTSignalData* fSignalPtr; }; - // Typedefs for backwards compatibility - - //template< typename XDataType1 > - //using KTSlotDataOneType = KTSlotData< XDataType1 >; - - //template< typename XDataType1, typename XDataType2 > - //using KTSlotDataTwoTypes = KTSlotData< XDataType1, XDataType2 >; - /*! @class KTSlotDone @@ -202,7 +194,7 @@ namespace Nymph void operator()(); protected: - boost::function< void () > fFunc; + std::function< void () > fFunc; KTSignalDone* fSignalPtr; }; @@ -253,7 +245,7 @@ namespace Nymph template< class XFuncOwnerType, class... XFuncDataTypes > KTSlotData< XReturnType, XDataTypes... >::KTSlotData(const std::string& name, XFuncOwnerType* owner, void (XFuncOwnerType::*func)( const XFuncDataTypes&..., XReturnType& ), KTSignalData* signalPtr) : KTSlot( name, owner, this, &KTSlotData::operator(), {signalPtr->GetName()} ), - fFunc( [func, owner]( XDataTypes... args ){ return (owner->*func)(args...);} ), + fFunc( [func, owner]( const XDataTypes&... args ){ return (owner->*func)(args...);} ), fSignalPtr( signalPtr ) { } @@ -262,7 +254,7 @@ namespace Nymph template< class XFuncOwnerType, class... XFuncDataTypes > KTSlotData< XReturnType, XDataTypes... >::KTSlotData(const std::string& name, XFuncOwnerType* owner, void (XFuncOwnerType::*func)( const XFuncDataTypes&..., XReturnType& )) : KTSlot( name, owner, this, &KTSlotData::operator() ), - fFunc( [func, owner]( XDataTypes... args ){ return (owner->*func)(args...);} ), + fFunc( [func, owner]( const XDataTypes&... args ){ return (owner->*func)(args...);} ), fSignalPtr( nullptr ) { } @@ -271,7 +263,7 @@ namespace Nymph template< class XFuncOwnerType, class... XFuncDataTypes > KTSlotData< XReturnType, XDataTypes... >::KTSlotData(const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, void (XFuncOwnerType::*func)( const XFuncDataTypes&..., XReturnType& ), KTSignalData* signalPtr) : KTSlot( name, proc, this, &KTSlotData::operator(), { signalPtr->GetName()} ), - fFunc( [func, owner]( XDataTypes... args ){return (owner->*func) (args... );} ), + fFunc( [func, owner]( const XDataTypes&... args ){return (owner->*func) (args... );} ), fSignalPtr( signalPtr ) { } @@ -280,7 +272,7 @@ namespace Nymph template< class XFuncOwnerType, class... XFuncDataTypes > KTSlotData< XReturnType, XDataTypes... >::KTSlotData(const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, void (XFuncOwnerType::*func)( const XFuncDataTypes&..., XReturnType& )) : KTSlot( name, proc, this, &KTSlotData::operator() ), - fFunc( [func, owner]( XDataTypes... args ){return (owner->*func) (args... );} ), + fFunc( [func, owner]( const XDataTypes&... args ){return (owner->*func) (args... );} ), fSignalPtr( nullptr ) { } @@ -342,7 +334,7 @@ namespace Nymph template< class XFuncOwnerType, class... XFuncDataTypes > KTSlotData< void, XDataTypes... >::KTSlotData(const std::string& name, XFuncOwnerType* owner, void (XFuncOwnerType::*func)( const XFuncDataTypes&... ), KTSignalData* signalPtr) : KTSlot( name, owner, this, &KTSlotData::operator(), {signalPtr->GetName()} ), - fFunc( [func, owner]( XDataTypes... args ){ return (owner->*func)(args...);} ), + fFunc( [func, owner]( const XDataTypes&... args ){ return (owner->*func)(args...);} ), fSignalPtr( signalPtr ) { } @@ -351,7 +343,7 @@ namespace Nymph template< class XFuncOwnerType, class... XFuncDataTypes > KTSlotData< void, XDataTypes... >::KTSlotData(const std::string& name, XFuncOwnerType* owner, void (XFuncOwnerType::*func)( const XFuncDataTypes&... )) : KTSlot( name, owner, this, &KTSlotData::operator() ), - fFunc( [func, owner]( XDataTypes... args ){ return (owner->*func)(args...);} ), + fFunc( [func, owner]( const XDataTypes&... args ){ return (owner->*func)(args...);} ), fSignalPtr( nullptr ) { } @@ -360,7 +352,7 @@ namespace Nymph template< class XFuncOwnerType, class... XFuncDataTypes > KTSlotData< void, XDataTypes... >::KTSlotData(const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, void (XFuncOwnerType::*func)( const XFuncDataTypes&... ), KTSignalData* signalPtr) : KTSlot( name, proc, this, &KTSlotData::operator(), { signalPtr->GetName()} ), - fFunc( [func, owner]( XDataTypes... args ){return (owner->*func) (args... );} ), + fFunc( [func, owner]( const XDataTypes&... args ){return (owner->*func) (args... );} ), fSignalPtr( signalPtr ) { } @@ -369,7 +361,7 @@ namespace Nymph template< class XFuncOwnerType, class... XFuncDataTypes > KTSlotData< void, XDataTypes... >::KTSlotData(const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, void (XFuncOwnerType::*func)( const XFuncDataTypes&... )) : KTSlot( name, proc, this, &KTSlotData::operator() ), - fFunc( [func, owner]( XDataTypes... args ){return (owner->*func) (args... );} ), + fFunc( [func, owner]( const XDataTypes&... args ){return (owner->*func) (args... );} ), fSignalPtr( nullptr ) { } From dad17aab755ab2904a0632279fa526528a486df4 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Tue, 20 Feb 2018 14:03:24 -0800 Subject: [PATCH 112/521] Minor changes --- Executables/Validation/KTJSONWriter.hh | 4 +++- Executables/Validation/KTTestDataPrimaryProcessor.cc | 7 ++++++- Library/Data/KTData.cc | 8 ++++++-- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/Executables/Validation/KTJSONWriter.hh b/Executables/Validation/KTJSONWriter.hh index b16e8fa..66cda6c 100644 --- a/Executables/Validation/KTJSONWriter.hh +++ b/Executables/Validation/KTJSONWriter.hh @@ -21,6 +21,8 @@ #include +#include "KTTestData.hh" + KTLOGGER( avlog_hh, "KTJSONWriter" ); namespace Nymph @@ -61,7 +63,7 @@ namespace Nymph } // Write to JSON archive - KTINFO( avlog_hh, "Writing data to JSON acrhive" ); + KTINFO( avlog_hh, "Writing data to JSON archive" ); (*fArchiveOutPtr)( data ); KTINFO( avlog_hh, "Successfully wrote data to archive" ); diff --git a/Executables/Validation/KTTestDataPrimaryProcessor.cc b/Executables/Validation/KTTestDataPrimaryProcessor.cc index 528d059..ee0ed4e 100644 --- a/Executables/Validation/KTTestDataPrimaryProcessor.cc +++ b/Executables/Validation/KTTestDataPrimaryProcessor.cc @@ -9,10 +9,14 @@ #include "KTTestData.hh" +#include "KTLogger.hh" + +LOGGER( testlog, "KTTestDataPrimaryProcessor" ); + namespace Nymph { - KT_REGISTER_PROCESSOR(KTTestDataPrimaryProcessor, "test-data-p-proc"); + KT_REGISTER_PROCESSOR( KTTestDataPrimaryProcessor, "test-data-p-proc" ); KTTestDataPrimaryProcessor::KTTestDataPrimaryProcessor( const std::string& name ) : KTPrimaryProcessor( {"test-derived-1"}, name ), @@ -44,6 +48,7 @@ namespace Nymph KTDataHandle handle = CreateNewDataHandle(); KTTestDerived1DataExt& testData = handle->Of< KTTestDerived1DataExt >(); testData.SetFunniness( 867 ); + KTINFO( testlog, "Test derived1 data funniness: " << testData.GetFunniness() ); fTheSignal( handle ); } diff --git a/Library/Data/KTData.cc b/Library/Data/KTData.cc index 7c7df99..536cb8e 100644 --- a/Library/Data/KTData.cc +++ b/Library/Data/KTData.cc @@ -10,10 +10,14 @@ namespace Nymph { KTData::KTData() - {} + { + std::cout << "### KTData constructor" << std::endl; + } KTData::~KTData() - {} + { + std::cout << "### KTData destructor" << std::endl; + } KTDataRider::KTDataRider() : fName() From d0611d209fbbe10e8f0ecdfba88e8fc57627b1a2 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Tue, 20 Feb 2018 14:12:46 -0800 Subject: [PATCH 113/521] Move KTJSONWriter to Library/IO --- Executables/Validation/CMakeLists.txt | 2 -- Executables/Validation/KTJSONWriterValidation.cc | 2 +- Executables/Validation/TestJSONWriter.cc | 3 +-- Library/CMakeLists.txt | 2 ++ {Executables/Validation => Library/IO}/KTJSONWriter.cc | 2 +- {Executables/Validation => Library/IO}/KTJSONWriter.hh | 7 +++---- 6 files changed, 8 insertions(+), 10 deletions(-) rename {Executables/Validation => Library/IO}/KTJSONWriter.cc (94%) rename {Executables/Validation => Library/IO}/KTJSONWriter.hh (95%) diff --git a/Executables/Validation/CMakeLists.txt b/Executables/Validation/CMakeLists.txt index 7cc7e0e..d36d0fb 100644 --- a/Executables/Validation/CMakeLists.txt +++ b/Executables/Validation/CMakeLists.txt @@ -14,7 +14,6 @@ if (Nymph_ENABLE_TESTING) # Headers for any test classes set (VALIDATION_HEADERFILES KTJSONReader.hh - KTJSONWriter.hh KTJSONWriterValidation.hh KTTestConfigurable.hh KTTestCuts.hh @@ -26,7 +25,6 @@ if (Nymph_ENABLE_TESTING) set (VALIDATION_SOURCEFILES KTJSONReader.cc - KTJSONWriter.cc KTJSONWriterValidation.cc KTTestConfigurable.cc KTTestCuts.cc diff --git a/Executables/Validation/KTJSONWriterValidation.cc b/Executables/Validation/KTJSONWriterValidation.cc index 3279a6c..1cdc86d 100644 --- a/Executables/Validation/KTJSONWriterValidation.cc +++ b/Executables/Validation/KTJSONWriterValidation.cc @@ -7,7 +7,7 @@ #include "KTJSONWriterValidation.hh" -#include "KTTestData.hh" +#include "KTRegisterNymphValidationExtData.hh" namespace Nymph { diff --git a/Executables/Validation/TestJSONWriter.cc b/Executables/Validation/TestJSONWriter.cc index 3a6d567..79f27bd 100644 --- a/Executables/Validation/TestJSONWriter.cc +++ b/Executables/Validation/TestJSONWriter.cc @@ -6,9 +6,8 @@ * */ +#include "../../Library/IO/KTJSONWriter.hh" #include "KTJSONReader.hh" -#include "KTJSONWriter.hh" - #include "KTTestData.hh" KTLOGGER( testlog, "TestJSONWriter" ); diff --git a/Library/CMakeLists.txt b/Library/CMakeLists.txt index 0c4dc89..4ba155e 100644 --- a/Library/CMakeLists.txt +++ b/Library/CMakeLists.txt @@ -39,6 +39,7 @@ set( NYMPH_HEADERFILES ${PROC_DIR}/KTSlot.hh ${PROC_DIR}/KTSlotWrapper.hh ${PROC_DIR}/KTThreadReference.hh + ${IO_DIR}/KTJSONWriter.hh ${IO_DIR}/KTReader.hh ${IO_DIR}/KTWriter.hh ${APPL_DIR}/KTApplication.hh @@ -71,6 +72,7 @@ set( NYMPH_SOURCEFILES ${PROC_DIR}/KTSignalWrapper.cc ${PROC_DIR}/KTSlotWrapper.cc ${PROC_DIR}/KTThreadReference.cc + ${IO_DIR}/KTJSONWriter.cc ${IO_DIR}/KTReader.cc ${IO_DIR}/KTWriter.cc ${APPL_DIR}/KTApplication.cc diff --git a/Executables/Validation/KTJSONWriter.cc b/Library/IO/KTJSONWriter.cc similarity index 94% rename from Executables/Validation/KTJSONWriter.cc rename to Library/IO/KTJSONWriter.cc index 6723611..62f12f5 100644 --- a/Executables/Validation/KTJSONWriter.cc +++ b/Library/IO/KTJSONWriter.cc @@ -6,7 +6,7 @@ * */ -#include "KTJSONWriter.hh" +#include "../../Library/IO/KTJSONWriter.hh" #include "KTLogger.hh" diff --git a/Executables/Validation/KTJSONWriter.hh b/Library/IO/KTJSONWriter.hh similarity index 95% rename from Executables/Validation/KTJSONWriter.hh rename to Library/IO/KTJSONWriter.hh index 66cda6c..635ec3d 100644 --- a/Executables/Validation/KTJSONWriter.hh +++ b/Library/IO/KTJSONWriter.hh @@ -11,18 +11,17 @@ // included first so that the archive is registered before the data classes #include "cereal/archives/json.hpp" +// then register the nymph extensible data classes +#include "KTRegisterNymphExtData.hh" + #include "KTWriter.hh" #include "KTSlot.hh" -#include "KTRegisterNymphValidationExtData.hh" - #include "KTLogger.hh" #include -#include "KTTestData.hh" - KTLOGGER( avlog_hh, "KTJSONWriter" ); namespace Nymph From f0fa5adeece53186099add80725b4fdb67f0d94b Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Tue, 20 Feb 2018 14:56:39 -0800 Subject: [PATCH 114/521] Added function to KTJSONWriter to write extensible data objects. For some reason it sometimes doesn't write out the data; I'm not sure what's going on there. --- Executables/Validation/CMakeLists.txt | 4 +- ...ation.cc => KTJSONTypeWriterValidation.cc} | 3 +- ...ation.hh => KTJSONTypeWriterValidation.hh} | 8 ++-- Executables/Validation/KTTestData.cc | 13 ++++++ Executables/Validation/KTTestData.hh | 7 +-- .../Validation/KTTestDataPrimaryProcessor.cc | 6 ++- .../Validation/TestJSONWriterViaSlot.cc | 44 +++++++++++++++++-- Library/IO/KTJSONWriter.cc | 18 +++++++- Library/IO/KTJSONWriter.hh | 7 ++- Library/Processor/KTSlot.hh | 2 +- 10 files changed, 91 insertions(+), 21 deletions(-) rename Executables/Validation/{KTJSONWriterValidation.cc => KTJSONTypeWriterValidation.cc} (95%) rename Executables/Validation/{KTJSONWriterValidation.hh => KTJSONTypeWriterValidation.hh} (80%) diff --git a/Executables/Validation/CMakeLists.txt b/Executables/Validation/CMakeLists.txt index d36d0fb..7f30232 100644 --- a/Executables/Validation/CMakeLists.txt +++ b/Executables/Validation/CMakeLists.txt @@ -14,7 +14,7 @@ if (Nymph_ENABLE_TESTING) # Headers for any test classes set (VALIDATION_HEADERFILES KTJSONReader.hh - KTJSONWriterValidation.hh + KTJSONTypeWriterValidation.hh KTTestConfigurable.hh KTTestCuts.hh KTTestData.hh @@ -25,7 +25,7 @@ if (Nymph_ENABLE_TESTING) set (VALIDATION_SOURCEFILES KTJSONReader.cc - KTJSONWriterValidation.cc + KTJSONTypeWriterValidation.cc KTTestConfigurable.cc KTTestCuts.cc KTTestData.cc diff --git a/Executables/Validation/KTJSONWriterValidation.cc b/Executables/Validation/KTJSONTypeWriterValidation.cc similarity index 95% rename from Executables/Validation/KTJSONWriterValidation.cc rename to Executables/Validation/KTJSONTypeWriterValidation.cc index 1cdc86d..3e9cc28 100644 --- a/Executables/Validation/KTJSONWriterValidation.cc +++ b/Executables/Validation/KTJSONTypeWriterValidation.cc @@ -5,8 +5,7 @@ * Author: N.S. Oblath */ -#include "KTJSONWriterValidation.hh" - +#include "KTJSONTypeWriterValidation.hh" #include "KTRegisterNymphValidationExtData.hh" namespace Nymph diff --git a/Executables/Validation/KTJSONWriterValidation.hh b/Executables/Validation/KTJSONTypeWriterValidation.hh similarity index 80% rename from Executables/Validation/KTJSONWriterValidation.hh rename to Executables/Validation/KTJSONTypeWriterValidation.hh index 49ed6cc..80436e5 100644 --- a/Executables/Validation/KTJSONWriterValidation.hh +++ b/Executables/Validation/KTJSONTypeWriterValidation.hh @@ -1,12 +1,12 @@ /* - * KTJSONWriterValidation.hh + * KTJSONTypeWriterValidation.hh * * Created on: Feb 17, 2018 * Author: N.S. Oblath */ -#ifndef NYMPH_KTJSONWRITERVALIDATION_HH_ -#define NYMPH_KTJSONWRITERVALIDATION_HH_ +#ifndef NYMPH_KTJSONTYPEWRITERVALIDATION_HH_ +#define NYMPH_KTJSONTYPEWRITERVALIDATION_HH_ #include "KTJSONWriter.hh" @@ -33,4 +33,4 @@ namespace Nymph } /* namespace Nymph */ -#endif /* NYMPH_KTJSONWRITERVALIDATION_HH_ */ +#endif /* NYMPH_KTJSONTYPEWRITERVALIDATION_HH_ */ diff --git a/Executables/Validation/KTTestData.cc b/Executables/Validation/KTTestData.cc index 72d3576..3bc6f32 100644 --- a/Executables/Validation/KTTestData.cc +++ b/Executables/Validation/KTTestData.cc @@ -21,5 +21,18 @@ namespace Nymph std::cout << "### KTTestData destructor" << std::endl; } + KTTestBaseData::KTTestBaseData() : + KTData(), + fFunniness(1000.) + { + std::cout << "### KTTestBaseData constructor" << std::endl; + } + + KTTestBaseData::~KTTestBaseData() + { + std::cout << "### KTTestBaseData destructor" << std::endl; + } + + } /* namespace Nymph */ diff --git a/Executables/Validation/KTTestData.hh b/Executables/Validation/KTTestData.hh index a181bfb..c28bf55 100644 --- a/Executables/Validation/KTTestData.hh +++ b/Executables/Validation/KTTestData.hh @@ -36,11 +36,8 @@ namespace Nymph class KTTestBaseData : public KTData { public: - KTTestBaseData() : - KTData(), - fFunniness(1000.) - {} - virtual ~KTTestBaseData() {} + KTTestBaseData(); + virtual ~KTTestBaseData(); MEMBERVARIABLE(double, Funniness); diff --git a/Executables/Validation/KTTestDataPrimaryProcessor.cc b/Executables/Validation/KTTestDataPrimaryProcessor.cc index ee0ed4e..218f495 100644 --- a/Executables/Validation/KTTestDataPrimaryProcessor.cc +++ b/Executables/Validation/KTTestDataPrimaryProcessor.cc @@ -38,8 +38,12 @@ namespace Nymph bool KTTestDataPrimaryProcessor::Run() { + unsigned funniness = 867; + for( unsigned iIteration = 0; iIteration < fIterations; ++iIteration ) { + KTINFO( testlog, "Beginning iteration " << iIteration ); + // e.g. for a real processor, do some work here instead of sleeping boost::this_thread::sleep_for( boost::chrono::milliseconds(1) ); @@ -47,7 +51,7 @@ namespace Nymph KTDataHandle handle = CreateNewDataHandle(); KTTestDerived1DataExt& testData = handle->Of< KTTestDerived1DataExt >(); - testData.SetFunniness( 867 ); + testData.SetFunniness( funniness++ ); KTINFO( testlog, "Test derived1 data funniness: " << testData.GetFunniness() ); fTheSignal( handle ); diff --git a/Executables/Validation/TestJSONWriterViaSlot.cc b/Executables/Validation/TestJSONWriterViaSlot.cc index 66ced7e..d757587 100644 --- a/Executables/Validation/TestJSONWriterViaSlot.cc +++ b/Executables/Validation/TestJSONWriterViaSlot.cc @@ -5,9 +5,8 @@ * Author: N.S. Oblath */ +#include "KTJSONTypeWriterValidation.hh" #include "KTTestDataPrimaryProcessor.hh" -#include "KTJSONWriterValidation.hh" - #include "KTLogger.hh" using namespace Nymph; @@ -19,10 +18,17 @@ int main() try { + KTPROG( testlog, "Testing single-data-object writing" ); + KTINFO( testlog, "Creating processors" ); KTTestDataPrimaryProcessor tdpp; KTJSONWriter jw; + KTINFO( testlog, "Configuring processors" ); + scarab::param_node jwConfig; + jwConfig.add( "filename", scarab::param_value( "test_jsonwriter_slot_singleobj.json" ) ); + jw.Configure( jwConfig ); + KTINFO( testlog, "Connecting the-signal to first-slot" ); tdpp.ConnectASlot( "test-derived-1", &jw, "test-derived-1", 20 ); @@ -34,7 +40,39 @@ int main() return -1; } - KTINFO( testlog, "Tests complete" ); + KTINFO( testlog, "Test complete" ); + } + catch( boost::exception& e ) + { + KTERROR( testlog, "An unexpected exception was caught: " << diagnostic_information( e ) ); + return -1; + } + + try + { + KTPROG( testlog, "Testing extensible-data-object writing" ); + + KTINFO( testlog, "Creating processors" ); + KTTestDataPrimaryProcessor tdpp; + KTJSONWriter jw; + + KTINFO( testlog, "Configuring processors" ); + scarab::param_node jwConfig; + jwConfig.add( "filename", scarab::param_value( "test_jsonwriter_slot_extdata.json" ) ); + jw.Configure( jwConfig ); + + KTINFO( testlog, "Connecting the-signal to first-slot" ); + tdpp.ConnectASlot( "test-derived-1", &jw, "ext-data", 20 ); + + KTINFO( testlog, "Running the primary processor" ) + + if( ! tdpp.Run() ) + { + KTERROR( testlog, "Something went wrong while running the primary processor" ); + return -1; + } + + KTINFO( testlog, "Test complete" ); } catch( boost::exception& e ) { diff --git a/Library/IO/KTJSONWriter.cc b/Library/IO/KTJSONWriter.cc index 62f12f5..cb9754d 100644 --- a/Library/IO/KTJSONWriter.cc +++ b/Library/IO/KTJSONWriter.cc @@ -18,6 +18,7 @@ namespace Nymph fFilename( "json_writer_default_file.json" ), fStreamOutPtr( nullptr ), fArchiveOutPtr( nullptr ), + fExtDataSlot( "ext-data", this, &KTJSONWriter::WriteExtData ), fCoreDataSlot( "core", this, &KTJSONWriter::WriteData< KTCoreDataExt > ) { } @@ -31,9 +32,24 @@ namespace Nymph bool KTJSONWriter::Configure( const scarab::param_node& node ) { - SetFilename( node.get_value( "file-name", fFilename ) ); + SetFilename( node.get_value( "filename", fFilename ) ); return true; } + void KTJSONWriter::WriteExtData( KTDataHandle handle ) + { + if( fStreamOutPtr == nullptr ) + { + fStreamOutPtr = new std::ofstream( fFilename ); + fArchiveOutPtr = new cereal::JSONOutputArchive( *fStreamOutPtr ); + } + + // Write to JSON archive + KTDEBUG( avlog_hh, "Writing extensible data to JSON archive" ); + (*fArchiveOutPtr)( handle ); + + return; + } + } diff --git a/Library/IO/KTJSONWriter.hh b/Library/IO/KTJSONWriter.hh index 635ec3d..ce2766d 100644 --- a/Library/IO/KTJSONWriter.hh +++ b/Library/IO/KTJSONWriter.hh @@ -44,11 +44,15 @@ namespace Nymph template< class XDataType > void WriteData( const XDataType& data ); + void WriteExtData( KTDataHandle handle ); + private: std::ofstream* fStreamOutPtr; cereal::JSONOutputArchive* fArchiveOutPtr; private: + KTSlot< KTDataHandle > fExtDataSlot; + KTSlotData< void, KTCoreDataExt > fCoreDataSlot; }; @@ -62,10 +66,9 @@ namespace Nymph } // Write to JSON archive - KTINFO( avlog_hh, "Writing data to JSON archive" ); + KTDEBUG( avlog_hh, "Writing data to JSON archive" ); (*fArchiveOutPtr)( data ); - KTINFO( avlog_hh, "Successfully wrote data to archive" ); return; } diff --git a/Library/Processor/KTSlot.hh b/Library/Processor/KTSlot.hh index 8058273..7f374a9 100644 --- a/Library/Processor/KTSlot.hh +++ b/Library/Processor/KTSlot.hh @@ -28,7 +28,7 @@ namespace Nymph @details Usage: To use this slot type the function to be called by the slot must exist in an object of type FuncOwnerType. - The function should have the signature ReturnType (Args). + The function should have the signature void (Args). In your Processor's header add a member variable of type KTSlot< ProcessorType, ReturnType, Args >. The variable may be private. From e3128b29ad72b3ea3a2c306dea47d18f638d0406 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Tue, 20 Feb 2018 15:07:49 -0800 Subject: [PATCH 115/521] Register KTJSONWriter as a processor and add documentation --- Library/IO/KTJSONWriter.cc | 4 +++- Library/IO/KTJSONWriter.hh | 30 ++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/Library/IO/KTJSONWriter.cc b/Library/IO/KTJSONWriter.cc index cb9754d..36add47 100644 --- a/Library/IO/KTJSONWriter.cc +++ b/Library/IO/KTJSONWriter.cc @@ -6,13 +6,15 @@ * */ -#include "../../Library/IO/KTJSONWriter.hh" +#include "KTJSONWriter.hh" #include "KTLogger.hh" namespace Nymph { + KT_REGISTER_PROCESSOR( KTJSONWriter, "json-writer" ); + KTJSONWriter::KTJSONWriter( const std::string& name ) : KTWriterWithTypists< KTJSONWriter, KTJSONTypeWriter >( name ), fFilename( "json_writer_default_file.json" ), diff --git a/Library/IO/KTJSONWriter.hh b/Library/IO/KTJSONWriter.hh index ce2766d..b6ba7a8 100644 --- a/Library/IO/KTJSONWriter.hh +++ b/Library/IO/KTJSONWriter.hh @@ -30,6 +30,36 @@ namespace Nymph typedef KTDerivedTypeWriter< KTJSONWriter > KTJSONTypeWriter; + /*! + @class KTJSONWriter + @author N. S. Oblath + + @brief Writes data to a JSON file + + @details + Can write single data objects or full extensible data objects. + + The Cereal serialization library is used for this writer. + Data objects must have a serial or save function to be successfully serialized. + + The slots for this writer can be extended in other compilation units using the type-writer system. + As an example, see Executables/Validation/KTJSONTypeWriterValidation and KTRegisterNymphValidationExtData. + + Data objects must be registered after the Cereal JSON archive is included, and before any serialization takes place. + As an example when extending the writer, see KTRegisterNymphValidationExtData. + + Configuration name: "json-writer" + + Available configuration options: + - "filename": string -- JSON filename to write to + + Signals: N/A + + Slots: + - "ext-data": void (KTDataHandle) -- write a full extensible data object + - "core" void (KTDataHandle) -- write a KTCoreData object; requires KTCoreData + + */ class KTJSONWriter : public KTWriterWithTypists< KTJSONWriter, KTJSONTypeWriter > { public: From fae8778f89b391748c18ffd287709761e2107afc Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Tue, 20 Feb 2018 15:34:54 -0800 Subject: [PATCH 116/521] Minor aesthetic changes --- Executables/Validation/TestPyTestClass.py | 4 ++++ Executables/Validation/TestPythonBasics.py | 5 +++++ Library/NymphPybind.cc | 20 +++++++++++--------- Library/Processor/KTProcessorPybind.hh | 6 +++--- 4 files changed, 23 insertions(+), 12 deletions(-) diff --git a/Executables/Validation/TestPyTestClass.py b/Executables/Validation/TestPyTestClass.py index 3520ef9..1db0264 100644 --- a/Executables/Validation/TestPyTestClass.py +++ b/Executables/Validation/TestPyTestClass.py @@ -1,3 +1,7 @@ +# TestPyTestClass.py +# Created on: Feb 1, 2018 +# Author: C. Claessens +# # Demonstrates access to KTPyTestClass import py_nymph_validation as nv diff --git a/Executables/Validation/TestPythonBasics.py b/Executables/Validation/TestPythonBasics.py index 0014f12..06cf75d 100644 --- a/Executables/Validation/TestPythonBasics.py +++ b/Executables/Validation/TestPythonBasics.py @@ -1,3 +1,8 @@ +# TestPythonBasics.py +# Created on: Jan 29, 2018 +# Author: N.S. Oblath +# +# Verifies that we can import Nymph python modules and call wrapped functions. # Uses Nymph::PyTest::add(), which is defined in TestPythonBasics.cc import py_nymph_validation diff --git a/Library/NymphPybind.cc b/Library/NymphPybind.cc index e569bba..204ba88 100644 --- a/Library/NymphPybind.cc +++ b/Library/NymphPybind.cc @@ -2,12 +2,14 @@ * NymphPybind.cc * * Created on: Jan 27, 2018 - * Author: obla999 + * Author: N.S. Oblath */ -#include "Application/KTProcessorToolboxPybind.hh" -#include "Processor/KTProcessorPybind.hh" +#include "KTProcessorToolboxPybind.hh" +#include "KTProcessorPybind.hh" + #include + //#include "Utility/KTConfigurablePybind.hh" PYBIND11_MODULE( py_nymph, mod ) @@ -16,13 +18,13 @@ PYBIND11_MODULE( py_nymph, mod ) //Nymph::ExportKTProcessor( mod ); Nymph::ExportKTProcessorToolbox( mod ); - pybind11::class_< Nymph::KTProcessor, std::shared_ptr>( mod, "KTProcessor" ); + pybind11::class_< Nymph::KTProcessor, std::shared_ptr >( mod, "KTProcessor" ); - pybind11::class_> wrap_processor(mod, "WrapProcessor", pybind11::dynamic_attr()); - wrap_processor - .def(pybind11::init<>()) - .def("WrapFunction", &Nymph::KTWrapProcessor::WrapFunction) - .def("Configure", &Nymph::KTWrapProcessor::Configure); + pybind11::class_< Nymph::KTWrapProcessor, Nymph::KTPyWrapProcessor, Nymph::KTProcessor, std::shared_ptr > wrap_processor(mod, "WrapProcessor", pybind11::dynamic_attr()); + wrap_processor + .def(pybind11::init<>()) + .def("WrapFunction", &Nymph::KTWrapProcessor::WrapFunction) + .def("Configure", &Nymph::KTWrapProcessor::Configure); } diff --git a/Library/Processor/KTProcessorPybind.hh b/Library/Processor/KTProcessorPybind.hh index e82faf2..41bed4c 100644 --- a/Library/Processor/KTProcessorPybind.hh +++ b/Library/Processor/KTProcessorPybind.hh @@ -2,7 +2,7 @@ * KTProcessorPybind.hh * * Created on: Jan 24, 2018 - * Author: obla999 + * Author: N.S. Oblath */ #ifndef NYMPH_KTPROCESSORPYBIND_HH_ @@ -72,7 +72,7 @@ namespace Nymph KTWrapProcessor, // Parent class WrapFunction, // Name of function in C++ (must match Python name) input // Argument(s) - ); + ); } bool Configure(const scarab::param_node& node) override { PYBIND11_OVERLOAD( @@ -80,7 +80,7 @@ namespace Nymph KTWrapProcessor, // Parent class Configure, // Name of function in C++ (must match Python name) node // Argument(s) - ); + ); } }; From 06903e3776c43535110ee0f95e7a9026b161fb4e Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Tue, 20 Feb 2018 15:55:10 -0800 Subject: [PATCH 117/521] Renamed a python script --- Executables/Validation/CMakeLists.txt | 2 +- .../Validation/{TestPythonBindings.py => TestParamBindings.py} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename Executables/Validation/{TestPythonBindings.py => TestParamBindings.py} (100%) diff --git a/Executables/Validation/CMakeLists.txt b/Executables/Validation/CMakeLists.txt index d445190..d3b7b41 100644 --- a/Executables/Validation/CMakeLists.txt +++ b/Executables/Validation/CMakeLists.txt @@ -98,10 +98,10 @@ if (Nymph_ENABLE_TESTING) # Python scripts set( VALIDATION_PY_SCRIPTS + TestParamBindings.py TestProcessorToolbox.py TestPyTestClass.py TestPythonBasics.py - TestPythonBindings.py TestWrapProcessor.py ) diff --git a/Executables/Validation/TestPythonBindings.py b/Executables/Validation/TestParamBindings.py similarity index 100% rename from Executables/Validation/TestPythonBindings.py rename to Executables/Validation/TestParamBindings.py From fea8d39ae7afec335e4f9e56403eb4acb1c1af82 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Wed, 21 Feb 2018 10:58:33 -0800 Subject: [PATCH 118/521] Some additional scarab::param_value bindings, and a successful test script --- Executables/Validation/TestParamBindings.py | 11 ++-- Library/CMakeLists.txt | 2 +- Library/NymphPybind.cc | 4 +- Library/Utility/KTParamNodePybind.hh | 53 --------------- Library/Utility/KTParamPybind.hh | 72 +++++++++++++++++++++ 5 files changed, 82 insertions(+), 60 deletions(-) delete mode 100644 Library/Utility/KTParamNodePybind.hh create mode 100644 Library/Utility/KTParamPybind.hh diff --git a/Executables/Validation/TestParamBindings.py b/Executables/Validation/TestParamBindings.py index e6f2e4d..c906fb5 100644 --- a/Executables/Validation/TestParamBindings.py +++ b/Executables/Validation/TestParamBindings.py @@ -1,4 +1,4 @@ -# Demonstrates access to KTPyTestClass +# Demonstrates access to param classes import py_nymph as nymph @@ -15,14 +15,17 @@ # 9. (self: py_nymph.ParamNodePybind, arg0: str, arg1: float) -> float # 10. (self: py_nymph.ParamNodePybind, arg0: str, arg1: str) -> str -a_value = nymph.ParamValue(True) -print("Get a bool set to True: ", a_value.get()) +int_value = nymph.param_value(5) +print("Get value set to 5: ", int_value.as_int()) + +string_value = nymph.param_value("Hello!") +print("Get value set to \"Hello!\"", string_value.as_string()) # print(pnp.get_value()) -a_node = nymph.ParamNode() +#a_node = nymph.ParamNode() # Test the "get_value" function for all the different types: # a_node.get_value("myKey") \ No newline at end of file diff --git a/Library/CMakeLists.txt b/Library/CMakeLists.txt index 44b2e33..11ee82f 100644 --- a/Library/CMakeLists.txt +++ b/Library/CMakeLists.txt @@ -95,9 +95,9 @@ set( NYMPH_PY_HEADERFILES # Python binding headers set( NYMPH_PYBINDING_HEADERFILES #${UTIL_DIR}/KTConfigurablePybind.hh + ${UTIL_DIR}/KTParamPybind.hh ${PROC_DIR}/KTProcessorPybind.hh ${PROC_DIR}/KTPyProcessor.hh - ${UTIL_DIR}/KTParamNodePybind.hh ) # Python bindings diff --git a/Library/NymphPybind.cc b/Library/NymphPybind.cc index 8a9adb9..39ceb7c 100644 --- a/Library/NymphPybind.cc +++ b/Library/NymphPybind.cc @@ -5,7 +5,7 @@ * Author: N.S. Oblath */ -#include "KTParamNodePybind.hh" +#include "KTParamPybind.hh" #include "KTProcessorToolboxPybind.hh" #include "KTProcessorPybind.hh" @@ -19,7 +19,7 @@ PYBIND11_MODULE( py_nymph, mod ) //Nymph::ExportKTConfigurable( mod ); //Nymph::ExportKTProcessor( mod ); Nymph::ExportKTProcessorToolbox( mod ); - Nymph::ExportParamNodePybind( mod ); + Nymph::ExportParamPybind( mod ); pybind11::class_< Nymph::KTProcessor, std::shared_ptr >( mod, "KTProcessor" ); diff --git a/Library/Utility/KTParamNodePybind.hh b/Library/Utility/KTParamNodePybind.hh deleted file mode 100644 index ff6b284..0000000 --- a/Library/Utility/KTParamNodePybind.hh +++ /dev/null @@ -1,53 +0,0 @@ -/* - * KTPyNymph.cc - * - * Created on: Feb 1, 2018 - * Author: N. Oblath, L. Gladstone - */ - -#include "param_node.hh" -#include "pybind11/pybind11.h" - -namespace Nymph -{ - - void ExportParamNodePybind( pybind11::module& mod ) - { - pybind11::class_< scarab::param_value >(mod, "ParamValue") - .def(pybind11::init()) - .def("get",(bool (scarab::param_value::*)() const) &scarab::param_value::get,"Get parameter value") - ; - - pybind11::class_< scarab::param_node >(mod, "ParamNode") - .def(pybind11::init<>()) - - .def("add",(bool (scarab::param_node::*)(const scarab::param_value&) const) &scarab::param_value::get,"Add a parameter value to a node") - - // Get value of the parameter, when no default is set - .def("get_value", (bool (scarab::param_node::*)(const std::string&) const) &scarab::param_node::get_value, "Get parameter node value") - .def("get_value", (uint (scarab::param_node::*)(const std::string &) const) - &scarab::param_node::get_value, "Get parameter node value") - .def("get_value", (int (scarab::param_node::*)(const std::string &) const) - &scarab::param_node::get_value, "Get parameter node value") - .def("get_value", (double (scarab::param_node::*)(const std::string &) const) - &scarab::param_node::get_value, "Get parameter node value") - .def("get_value", (std::string (scarab::param_node::*)(const std::string &) const) - &scarab::param_node::get_value, "Get parameter node value") - - // Get value of the parameter, bringing along the default value - .def("get_value", (bool (scarab::param_node::*)(const std::string&, bool) const) &scarab::param_node::get_value, "Get parameter node value") - .def("get_value", (uint (scarab::param_node::*)(const std::string &, uint) const) - &scarab::param_node::get_value, "Get parameter node value") - .def("get_value", (int (scarab::param_node::*)(const std::string &, int) const) - &scarab::param_node::get_value, "Get parameter node value") - .def("get_value", (double (scarab::param_node::*)(const std::string &, double) const) - &scarab::param_node::get_value, "Get parameter node value") - .def("get_value", (std::string (scarab::param_node::*)(const std::string &, const std::string & ) const) - &scarab::param_node::get_value, "Get parameter node value") - ; - - - - } - -} /* namespace Nymph */ diff --git a/Library/Utility/KTParamPybind.hh b/Library/Utility/KTParamPybind.hh new file mode 100644 index 0000000..b849585 --- /dev/null +++ b/Library/Utility/KTParamPybind.hh @@ -0,0 +1,72 @@ +/* + * KTPyNymph.cc + * + * Created on: Feb 1, 2018 + * Author: N. Oblath, L. Gladstone + */ + +#include "param.hh" + +#include "pybind11/pybind11.h" + +namespace Nymph +{ + + void ExportParamPybind( pybind11::module& mod ) + { + pybind11::class_< scarab::param_value >( mod, "param_value" ) + .def( pybind11::init< bool >() ) + .def( pybind11::init< unsigned >() ) + .def( pybind11::init< int >() ) + .def( pybind11::init< double >() ) + .def( pybind11::init< const std::string& >() ) + + .def( "as_bool", (bool (scarab::param_value::*)() const) &scarab::param_value::as_bool, "Get parameter value as a bool" ) + .def( "as_uint", (unsigned (scarab::param_value::*)() const) &scarab::param_value::as_uint, "Get parameter value as an unsigned integer" ) + .def( "as_int", (int (scarab::param_value::*)() const) &scarab::param_value::as_int, "Get parameter value as a signed integer" ) + .def( "as_double", (double (scarab::param_value::*)() const) &scarab::param_value::as_double, "Get parameter value as a float" ) + .def( "as_string", (std::string (scarab::param_value::*)() const) &scarab::param_value::as_string, "Get parameter value as a string" ) + + .def( "set", (void (scarab::param_value::*)(bool)) &scarab::param_value::set, "Set a bool value" ) + .def( "set", (void (scarab::param_value::*)(unsigned)) &scarab::param_value::set, "Set an unsigned integer value" ) + .def( "set", (void (scarab::param_value::*)(int)) &scarab::param_value::set, "Set a signed integer value" ) + .def( "set", (void (scarab::param_value::*)(double)) &scarab::param_value::set, "Set an float value" ) + .def( "set", (void (scarab::param_value::*)(const std::string&)) &scarab::param_value::set, "Set an string value" ) + ; + + pybind11::class_< scarab::param_node >( mod, "param_node" ) + .def( pybind11::init<>() ) + + .def( "add",(bool (scarab::param_node::*)(const scarab::param_value&) const) &scarab::param_value::get, + "Add a parameter value to a node" ) + + // Get value of the parameter, when no default is set + .def( "get_value", (bool (scarab::param_node::*)(const std::string&) const) &scarab::param_node::get_value, + "Get parameter node value as a bool" ) + .def( "get_value", (unsigned (scarab::param_node::*)(const std::string &) const) &scarab::param_node::get_value, + "Get parameter node value as an unsigned integer" ) + .def( "get_value", (int (scarab::param_node::*)(const std::string &) const) &scarab::param_node::get_value, + "Get parameter node value as a signed integer" ) + .def( "get_value", (double (scarab::param_node::*)(const std::string &) const) &scarab::param_node::get_value, + "Get parameter node value as a float" ) + .def( "get_value", (std::string (scarab::param_node::*)(const std::string &) const) &scarab::param_node::get_value, + "Get parameter node value as a string" ) + + // Get value of the parameter, bringing along the default value + .def( "get_value", (bool (scarab::param_node::*)(const std::string&, bool) const) &scarab::param_node::get_value, + "Get parameter node value as a bool" ) + .def( "get_value", (unsigned (scarab::param_node::*)(const std::string &, unsigned) const) &scarab::param_node::get_value, + "Get parameter node value as an unsigned integer" ) + .def( "get_value", (int (scarab::param_node::*)(const std::string &, int) const) &scarab::param_node::get_value, + "Get parameter node value as a signed integer" ) + .def( "get_value", (double (scarab::param_node::*)(const std::string &, double) const) &scarab::param_node::get_value, + "Get parameter node value as a float" ) + .def( "get_value", (std::string (scarab::param_node::*)(const std::string &, const std::string& ) const) &scarab::param_node::get_value, + "Get parameter node value as a string" ) + ; + + + + } + +} /* namespace Nymph */ From d31b4ca77b7154c2000065f432f64a2994db659b Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Wed, 21 Feb 2018 13:06:14 -0800 Subject: [PATCH 119/521] Progress on param_node bindings --- Executables/Validation/TestParamBindings.py | 14 +++++++-- Library/Utility/KTParamPybind.hh | 35 +++++++++++++-------- 2 files changed, 33 insertions(+), 16 deletions(-) diff --git a/Executables/Validation/TestParamBindings.py b/Executables/Validation/TestParamBindings.py index c906fb5..a36fa1a 100644 --- a/Executables/Validation/TestParamBindings.py +++ b/Executables/Validation/TestParamBindings.py @@ -16,16 +16,24 @@ # 10. (self: py_nymph.ParamNodePybind, arg0: str, arg1: str) -> str int_value = nymph.param_value(5) -print("Get value set to 5: ", int_value.as_int()) +print("What type of value is stored? (bool, uint, int, double, string): ", int_value.is_bool(), int_value.is_uint(), int_value.is_int(), int_value.is_double(), int_value.is_string()) +print("Get value set to 5:", int_value.as_int()) string_value = nymph.param_value("Hello!") -print("Get value set to \"Hello!\"", string_value.as_string()) +print("What type of value is stored? (bool, uint, int, double, string): ", string_value.is_bool(), string_value.is_uint(), string_value.is_int(), string_value.is_double(), string_value.is_string()) +print("Get value set to \"Hello!\":", string_value.as_string()) # print(pnp.get_value()) -#a_node = nymph.ParamNode() +a_node = nymph.param_node() +a_node.add("int-value", int_value) +a_node.add("string-value", string_value) + +print("Int value from node:", a_node.get_value_int("int-value")) +print("String value from node:", a_node.get_value_string("string-value")) + # Test the "get_value" function for all the different types: # a_node.get_value("myKey") \ No newline at end of file diff --git a/Library/Utility/KTParamPybind.hh b/Library/Utility/KTParamPybind.hh index b849585..c75a79e 100644 --- a/Library/Utility/KTParamPybind.hh +++ b/Library/Utility/KTParamPybind.hh @@ -14,6 +14,9 @@ namespace Nymph void ExportParamPybind( pybind11::module& mod ) { + // param + + // param_value pybind11::class_< scarab::param_value >( mod, "param_value" ) .def( pybind11::init< bool >() ) .def( pybind11::init< unsigned >() ) @@ -21,6 +24,12 @@ namespace Nymph .def( pybind11::init< double >() ) .def( pybind11::init< const std::string& >() ) + .def( "is_bool", (bool (scarab::param_value::*)() const) &scarab::param_value::is_bool, "Return whether the param_value stores a boolean value" ) + .def( "is_uint", (bool (scarab::param_value::*)() const) &scarab::param_value::is_uint, "Return whether the param_value stores an unsigned integer value" ) + .def( "is_int", (bool (scarab::param_value::*)() const) &scarab::param_value::is_int, "Return whether the param_value stores a signed integer value" ) + .def( "is_double", (bool (scarab::param_value::*)() const) &scarab::param_value::is_double, "Return whether the param_value stores a double value" ) + .def( "is_string", (bool (scarab::param_value::*)() const) &scarab::param_value::is_string, "Return whether the param_value stores a string value" ) + .def( "as_bool", (bool (scarab::param_value::*)() const) &scarab::param_value::as_bool, "Get parameter value as a bool" ) .def( "as_uint", (unsigned (scarab::param_value::*)() const) &scarab::param_value::as_uint, "Get parameter value as an unsigned integer" ) .def( "as_int", (int (scarab::param_value::*)() const) &scarab::param_value::as_int, "Get parameter value as a signed integer" ) @@ -34,39 +43,39 @@ namespace Nymph .def( "set", (void (scarab::param_value::*)(const std::string&)) &scarab::param_value::set, "Set an string value" ) ; + // param_node pybind11::class_< scarab::param_node >( mod, "param_node" ) .def( pybind11::init<>() ) - .def( "add",(bool (scarab::param_node::*)(const scarab::param_value&) const) &scarab::param_value::get, - "Add a parameter value to a node" ) + .def( "add",(bool (scarab::param_node::*)(const std::string&, const scarab::param&)) &scarab::param_node::add, + "Add a param object to a node" ) // Get value of the parameter, when no default is set - .def( "get_value", (bool (scarab::param_node::*)(const std::string&) const) &scarab::param_node::get_value, + .def( "get_value_bool", (bool (scarab::param_node::*)(const std::string&) const) &scarab::param_node::get_value, "Get parameter node value as a bool" ) - .def( "get_value", (unsigned (scarab::param_node::*)(const std::string &) const) &scarab::param_node::get_value, + .def( "get_value_uint", (unsigned (scarab::param_node::*)(const std::string&) const) &scarab::param_node::get_value, "Get parameter node value as an unsigned integer" ) - .def( "get_value", (int (scarab::param_node::*)(const std::string &) const) &scarab::param_node::get_value, + .def( "get_value_int", (int (scarab::param_node::*)(const std::string&) const) &scarab::param_node::get_value, "Get parameter node value as a signed integer" ) - .def( "get_value", (double (scarab::param_node::*)(const std::string &) const) &scarab::param_node::get_value, + .def( "get_value_double", (double (scarab::param_node::*)(const std::string&) const) &scarab::param_node::get_value, "Get parameter node value as a float" ) - .def( "get_value", (std::string (scarab::param_node::*)(const std::string &) const) &scarab::param_node::get_value, + .def( "get_value_string", (std::string (scarab::param_node::*)(const std::string&) const) &scarab::param_node::get_value, "Get parameter node value as a string" ) // Get value of the parameter, bringing along the default value .def( "get_value", (bool (scarab::param_node::*)(const std::string&, bool) const) &scarab::param_node::get_value, "Get parameter node value as a bool" ) - .def( "get_value", (unsigned (scarab::param_node::*)(const std::string &, unsigned) const) &scarab::param_node::get_value, + .def( "get_value", (unsigned (scarab::param_node::*)(const std::string&, unsigned) const) &scarab::param_node::get_value, "Get parameter node value as an unsigned integer" ) - .def( "get_value", (int (scarab::param_node::*)(const std::string &, int) const) &scarab::param_node::get_value, + .def( "get_value", (int (scarab::param_node::*)(const std::string&, int) const) &scarab::param_node::get_value, "Get parameter node value as a signed integer" ) - .def( "get_value", (double (scarab::param_node::*)(const std::string &, double) const) &scarab::param_node::get_value, + .def( "get_value", (double (scarab::param_node::*)(const std::string&, double) const) &scarab::param_node::get_value, "Get parameter node value as a float" ) - .def( "get_value", (std::string (scarab::param_node::*)(const std::string &, const std::string& ) const) &scarab::param_node::get_value, + .def( "get_value", (std::string (scarab::param_node::*)(const std::string&, const std::string& ) const) &scarab::param_node::get_value, "Get parameter node value as a string" ) ; - - + // param_array } } /* namespace Nymph */ From fda41f46800c943c869fae9b94d3fa563940d209 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Mon, 25 Jun 2018 12:42:05 -0700 Subject: [PATCH 120/521] Fixed as_string py binding and added initializer with const char* --- Library/Utility/KTParamPybind.hh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Library/Utility/KTParamPybind.hh b/Library/Utility/KTParamPybind.hh index c75a79e..a1d633a 100644 --- a/Library/Utility/KTParamPybind.hh +++ b/Library/Utility/KTParamPybind.hh @@ -23,6 +23,7 @@ namespace Nymph .def( pybind11::init< int >() ) .def( pybind11::init< double >() ) .def( pybind11::init< const std::string& >() ) + .def( pybind11::init< const char* >() ) .def( "is_bool", (bool (scarab::param_value::*)() const) &scarab::param_value::is_bool, "Return whether the param_value stores a boolean value" ) .def( "is_uint", (bool (scarab::param_value::*)() const) &scarab::param_value::is_uint, "Return whether the param_value stores an unsigned integer value" ) @@ -34,7 +35,7 @@ namespace Nymph .def( "as_uint", (unsigned (scarab::param_value::*)() const) &scarab::param_value::as_uint, "Get parameter value as an unsigned integer" ) .def( "as_int", (int (scarab::param_value::*)() const) &scarab::param_value::as_int, "Get parameter value as a signed integer" ) .def( "as_double", (double (scarab::param_value::*)() const) &scarab::param_value::as_double, "Get parameter value as a float" ) - .def( "as_string", (std::string (scarab::param_value::*)() const) &scarab::param_value::as_string, "Get parameter value as a string" ) + .def( "as_string", (const std::string& (scarab::param_value::*)() const) &scarab::param_value::as_string, "Get parameter value as a string" ) .def( "set", (void (scarab::param_value::*)(bool)) &scarab::param_value::set, "Set a bool value" ) .def( "set", (void (scarab::param_value::*)(unsigned)) &scarab::param_value::set, "Set an unsigned integer value" ) From e39fa1090ac46a85ff50730cce312d6428a5f08f Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Mon, 25 Jun 2018 13:09:24 -0700 Subject: [PATCH 121/521] Added binding of param and specification of inheritance of param_value and param_node from param --- Library/Utility/KTParamPybind.hh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Library/Utility/KTParamPybind.hh b/Library/Utility/KTParamPybind.hh index a1d633a..915941b 100644 --- a/Library/Utility/KTParamPybind.hh +++ b/Library/Utility/KTParamPybind.hh @@ -15,9 +15,10 @@ namespace Nymph void ExportParamPybind( pybind11::module& mod ) { // param + pybind11::class_< scarab::param >( mod, "param" ); // param_value - pybind11::class_< scarab::param_value >( mod, "param_value" ) + pybind11::class_< scarab::param_value, scarab::param >( mod, "param_value" ) .def( pybind11::init< bool >() ) .def( pybind11::init< unsigned >() ) .def( pybind11::init< int >() ) @@ -45,7 +46,7 @@ namespace Nymph ; // param_node - pybind11::class_< scarab::param_node >( mod, "param_node" ) + pybind11::class_< scarab::param_node, scarab::param >( mod, "param_node" ) .def( pybind11::init<>() ) .def( "add",(bool (scarab::param_node::*)(const std::string&, const scarab::param&)) &scarab::param_node::add, From 0bd645c83c3485d6fc069757e7bcd269aa71a79b Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Mon, 25 Jun 2018 13:36:30 -0700 Subject: [PATCH 122/521] Added initial param_array binding and test functionality --- Executables/Validation/TestParamBindings.py | 22 ++++++++++--- Library/Utility/KTParamPybind.hh | 36 +++++++++++++++++++++ 2 files changed, 53 insertions(+), 5 deletions(-) diff --git a/Executables/Validation/TestParamBindings.py b/Executables/Validation/TestParamBindings.py index a36fa1a..5608755 100644 --- a/Executables/Validation/TestParamBindings.py +++ b/Executables/Validation/TestParamBindings.py @@ -15,6 +15,8 @@ # 9. (self: py_nymph.ParamNodePybind, arg0: str, arg1: float) -> float # 10. (self: py_nymph.ParamNodePybind, arg0: str, arg1: str) -> str + +# Value testing int_value = nymph.param_value(5) print("What type of value is stored? (bool, uint, int, double, string): ", int_value.is_bool(), int_value.is_uint(), int_value.is_int(), int_value.is_double(), int_value.is_string()) print("Get value set to 5:", int_value.as_int()) @@ -23,11 +25,8 @@ print("What type of value is stored? (bool, uint, int, double, string): ", string_value.is_bool(), string_value.is_uint(), string_value.is_int(), string_value.is_double(), string_value.is_string()) print("Get value set to \"Hello!\":", string_value.as_string()) -# print(pnp.get_value()) - - - +# Node testing a_node = nymph.param_node() a_node.add("int-value", int_value) a_node.add("string-value", string_value) @@ -36,4 +35,17 @@ print("String value from node:", a_node.get_value_string("string-value")) # Test the "get_value" function for all the different types: -# a_node.get_value("myKey") \ No newline at end of file +print("Get int value from the node as different types (bool, uint, int, double, string): ", a_node.get_value_bool("int-value"), a_node.get_value_uint("int-value"), a_node.get_value_int("int-value"), a_node.get_value_double("int-value"), a_node.get_value_string("int-value")) + + +# Array testing +an_array = nymph.param_array() +an_array.resize(2) +an_array.assign(0, int_value) +an_array.assign(1, string_value) + +print("Int value from array:", an_array.get_value_int(0)) +print("String value from array:", an_array.get_value_string(1)) + +# Test the "get_value" function for all the different types: +print("Get int value from the array as different types (bool, uint, int, double, string): ", an_array.get_value_bool(0), an_array.get_value_uint(0), an_array.get_value_int(0), an_array.get_value_double(0), an_array.get_value_string(0)) diff --git a/Library/Utility/KTParamPybind.hh b/Library/Utility/KTParamPybind.hh index 915941b..e55db88 100644 --- a/Library/Utility/KTParamPybind.hh +++ b/Library/Utility/KTParamPybind.hh @@ -78,6 +78,42 @@ namespace Nymph ; // param_array + pybind11::class_< scarab::param_array, scarab::param >( mod, "param_array" ) + .def( pybind11::init<>() ) + + .def( "size", (unsigned (scarab::param_array::*)() const) &scarab::param_array::size, + "Returns the size of the array" ) + + .def( "resize", (void (scarab::param_array::*)(unsigned)) &scarab::param_array::resize, + "Sets the size of the array; if smaller than the current size, the extra elements are deleted") + + .def( "assign", (void (scarab::param_array::*)(unsigned, const scarab::param&)) &scarab::param_array::assign, + "Add a param object to the specified index in a array" ) + + // Get value of the parameter, when no default is set + .def( "get_value_bool", (bool (scarab::param_array::*)(unsigned) const) &scarab::param_array::get_value, + "Get parameter array value as a bool" ) + .def( "get_value_uint", (unsigned (scarab::param_array::*)(unsigned) const) &scarab::param_array::get_value, + "Get parameter array value as an unsigned integer" ) + .def( "get_value_int", (int (scarab::param_array::*)(unsigned) const) &scarab::param_array::get_value, + "Get parameter array value as a signed integer" ) + .def( "get_value_double", (double (scarab::param_array::*)(unsigned) const) &scarab::param_array::get_value, + "Get parameter array value as a float" ) + .def( "get_value_string", (std::string (scarab::param_array::*)(unsigned) const) &scarab::param_array::get_value, + "Get parameter array value as a string" ) + + // Get value of the parameter, bringing along the default value + .def( "get_value", (bool (scarab::param_array::*)(unsigned, bool) const) &scarab::param_array::get_value, + "Get parameter array value as a bool" ) + .def( "get_value", (unsigned (scarab::param_array::*)(unsigned, unsigned) const) &scarab::param_array::get_value, + "Get parameter array value as an unsigned integer" ) + .def( "get_value", (int (scarab::param_array::*)(unsigned, int) const) &scarab::param_array::get_value, + "Get parameter array value as a signed integer" ) + .def( "get_value", (double (scarab::param_array::*)(unsigned, double) const) &scarab::param_array::get_value, + "Get parameter array value as a float" ) + .def( "get_value", (std::string (scarab::param_array::*)(unsigned, const std::string& ) const) &scarab::param_array::get_value, + "Get parameter array value as a string" ) + ; } } /* namespace Nymph */ From 298c3725185c7aa830acb0c2aefc352d98dacba8 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Mon, 25 Jun 2018 13:49:30 -0700 Subject: [PATCH 123/521] Updated Scarab to new version of scarab2/develop --- Scarab | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Scarab b/Scarab index b3999e8..ada7716 160000 --- a/Scarab +++ b/Scarab @@ -1 +1 @@ -Subproject commit b3999e86e72be1aeea6a84c5d464c3d4869211fd +Subproject commit ada7716f64c9c33b9c1c07ebb1d4074462603f98 From 23cbf3ec6957bb6275a97887b23871628afc6e81 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Fri, 22 Feb 2019 21:13:14 -0800 Subject: [PATCH 124/521] Bumped Scarab to v2.4.3 --- Scarab | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Scarab b/Scarab index ada7716..ae05d4c 160000 --- a/Scarab +++ b/Scarab @@ -1 +1 @@ -Subproject commit ada7716f64c9c33b9c1c07ebb1d4074462603f98 +Subproject commit ae05d4c5c157c6cc569b1f3855a8b2599abbdd70 From f60ca6b9fa7989ab9a49e8540d4db8f298ea2f5a Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Fri, 22 Feb 2019 21:26:54 -0800 Subject: [PATCH 125/521] Stripped boost python --- CMakeLists.txt | 18 +--- Executables/Validation/CMakeLists.txt | 4 +- Library/Application/KTProcessorToolboxPy.hh | 98 --------------------- Library/CMakeLists.txt | 15 +--- Library/Data/KTDataPy.hh | 23 ----- Library/NymphPy.cc | 14 --- Library/Processor/KTProcessorPy.hh | 47 ---------- 7 files changed, 7 insertions(+), 212 deletions(-) delete mode 100644 Library/Application/KTProcessorToolboxPy.hh delete mode 100644 Library/Data/KTDataPy.hh delete mode 100644 Library/NymphPy.cc delete mode 100644 Library/Processor/KTProcessorPy.hh diff --git a/CMakeLists.txt b/CMakeLists.txt index d76b9bd..46e13d1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,10 +32,7 @@ set_option( USE_CPP11 TRUE ) option( Nymph_BUILD_NYMPH_EXE "Flag to build the Nymph executable; also requires Nymph_ENABLE_EXECUTABLES" ON ) # Build python bindings (requires boost::python) -option( Nymph_ENABLE_PYTHON "Build python bindings (NymphPy)" OFF ) - -# Build python bindings via pybind11 (this should be renamed Nymph_ENABLE_PYTHON if we choose to go with pybind11 over boost::python) -option( Nymph_ENABLE_PYBIND11 "Build python bindings via pybind11" OFF ) +option( Nymph_ENABLE_PYTHON "Build python bindings" OFF ) # Add a "Standard" build type #set (CMAKE_BUILD_TYPE standard) @@ -84,30 +81,21 @@ endif( PBUILDER_STANDALONE ) # Boost (1.46 required for filesystem version 3) list (APPEND Boost_COMPONENTS chrono date_time filesystem program_options system thread) -if (Nymph_ENABLE_PYTHON) - list(APPEND Boost_COMPONENTS python) -endif (Nymph_ENABLE_PYTHON) find_package (Boost 1.46.0 REQUIRED COMPONENTS ${Boost_COMPONENTS}) # make sure dynamic linking is assumed for all boost libraries add_definitions (-DBOOST_ALL_DYN_LINK) include_directories (${Boost_INCLUDE_DIRS}) pbuilder_add_ext_libraries (${Boost_LIBRARIES}) -# python deps -if (Nymph_ENABLE_PYTHON) - include (PythonPackage) - python_package_find_python( 2.7 ) -endif (Nymph_ENABLE_PYTHON) - ########## # Pybind11 ########## -if( Nymph_ENABLE_PYBIND11 ) +if( Nymph_ENABLE_PYTHON ) set( PYBIND11_INSTALL ON CACHE BOOL "Pybind11 option to install itself" FORCE ) add_subdirectory( External/pybind11 ) include_directories( External/pybind11/include ) -endif( Nymph_ENABLE_PYBIND11 ) +endif( Nymph_ENABLE_PYTHON ) ######## # Cereal diff --git a/Executables/Validation/CMakeLists.txt b/Executables/Validation/CMakeLists.txt index d3b7b41..22f0e06 100644 --- a/Executables/Validation/CMakeLists.txt +++ b/Executables/Validation/CMakeLists.txt @@ -82,7 +82,7 @@ if (Nymph_ENABLE_TESTING) pbuilder_executables( TEST_PROGRAMS LIB_DEPENDENCIES ) - if( Nymph_ENABLE_PYBIND11 ) + if( Nymph_ENABLE_PYTHON ) # Python Interface # Python binding headers @@ -112,6 +112,6 @@ if (Nymph_ENABLE_TESTING) install( FILES ${VALIDATION_PY_SCRIPTS} DESTINATION ${BIN_INSTALL_DIR} ) - endif( Nymph_ENABLE_PYBIND11 ) + endif( Nymph_ENABLE_PYTHON ) endif (Nymph_ENABLE_TESTING) diff --git a/Library/Application/KTProcessorToolboxPy.hh b/Library/Application/KTProcessorToolboxPy.hh deleted file mode 100644 index 16dc109..0000000 --- a/Library/Application/KTProcessorToolboxPy.hh +++ /dev/null @@ -1,98 +0,0 @@ -/** - @file KTProcessorToolboxPy.hh - @brief Contains KTProcessorToolbox python bindings - @details Manages processors requested by the user at run time. - @author: B. H. LaRoque - @date: April 20, 2017 - */ - -#ifndef KTPROCESSORTOOLBOXPY_HH_ -#define KTPROCESSORTOOLBOXPY_HH_ - -#include "KTProcessorToolbox.hh" -#include "KTPythonMacros.hh" - -// Make connection overloads - /* need two macros to cover all signatures*/ -bool (Nymph::KTProcessorToolbox::*MakeConnection_2names)(const std::string&, const std::string&, int order) = &Nymph::KTProcessorToolbox::MakeConnection; -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(MakeConnection_2names_overloads, Nymph::KTProcessorToolbox::MakeConnection, 2, 3) -bool (Nymph::KTProcessorToolbox::*MakeConnection_4names)(const std::string&, const std::string&, const std::string&, const std::string&, int order) = &Nymph::KTProcessorToolbox::MakeConnection; -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(MakeConnection_4names_overloads, Nymph::KTProcessorToolbox::MakeConnection, 4, 5) - -// Set and Remove breakpoint overloads -bool (Nymph::KTProcessorToolbox::*SetBreakpoint_1arg)(const std::string&) = &Nymph::KTProcessorToolbox::SetBreakpoint; -bool (Nymph::KTProcessorToolbox::*SetBreakpoint_2arg)(const std::string&, const std::string&) = &Nymph::KTProcessorToolbox::SetBreakpoint; -bool (Nymph::KTProcessorToolbox::*RemoveBreakpoint_1arg)(const std::string&) = &Nymph::KTProcessorToolbox::RemoveBreakpoint; -bool (Nymph::KTProcessorToolbox::*RemoveBreakpoint_2arg)(const std::string&, const std::string&) = &Nymph::KTProcessorToolbox::RemoveBreakpoint; -//BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(SetBreakpoint_overloads, Nymph::KTProcessorToolbox::SetBreakpoint, 1, 2) -//BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(RemoveBreakpoint_overloads, Nymph::KTProcessorToolbox::SetBreakpoint, 1, 2) - -// Run queue pushback overloads -bool (Nymph::KTProcessorToolbox::*PushBackToRunQueue_string)(const std::string& name) = &Nymph::KTProcessorToolbox::PushBackToRunQueue; -bool (Nymph::KTProcessorToolbox::*PushBackToRunQueue_init_list)(std::initializer_list< std::string >) = &Nymph::KTProcessorToolbox::PushBackToRunQueue; -bool (Nymph::KTProcessorToolbox::*PushBackToRunQueue_vector)(std::vector< std::string >) = &Nymph::KTProcessorToolbox::PushBackToRunQueue; - -// Add Processor overloads -bool (Nymph::KTProcessorToolbox::*AddProcessor_Ref)(const std::string&, Nymph::KTProcessor*) = &Nymph::KTProcessorToolbox::AddProcessor; -bool (Nymph::KTProcessorToolbox::*AddProcessor_TypeStr)(const std::string&, const std::string&) = &Nymph::KTProcessorToolbox::AddProcessor; - -// Get Processor overloads -Nymph::KTProcessor* (Nymph::KTProcessorToolbox::*GetProcessor_wrap)(const std::string&) = &Nymph::KTProcessorToolbox::GetProcessor; - -// Configure Processor overloads -bool (Nymph::KTProcessorToolbox::*ConfigureProcessors_JsonStr)(const std::string&) = &Nymph::KTProcessorToolbox::ConfigureProcessors; - -void export_ProcessorToolbox() -{ - using namespace Nymph; - using namespace boost::python; - class_("KTProcessorToolbox", init()) - - // members related to configuration - .def("ConfigureProcessors", ConfigureProcessors_JsonStr, "Configure processors from a json dictionary. Top-level keys are processor names, values are dictionaries with their configurations") - PROPERTYMEMBER(KTProcessorToolbox, RunSingleThreaded) - - - // Processor access - .def("GetProcessor", GetProcessor_wrap, return_value_policy(), "Get a pointer to a processor in the toolbox") - .def("AddProcessor", AddProcessor_Ref, "add a processor to the toolbox, toolbox takes ownership") - .def("AddProcessor", AddProcessor_TypeStr, "add a processor to the toolbox, toolbox takes ownership") - .def("RemoveProcessor", &KTProcessorToolbox::RemoveProcessor, "remove a processor from the toolbox") - /* TODO: Not 100% certain that the reference count for this processor is now correct, given the return_value_policy */ - .def("ReleaseProcessor", &KTProcessorToolbox::ReleaseProcessor, return_value_policy(), "Remove a processor from the toolbox and return it to the user, ownership is passed") - .def("ClearProcessors", &KTProcessorToolbox::ClearProcessors, "Remove all processors and clear run queue") - - // Processor connections - .def("MakeConnection", MakeConnection_2names, MakeConnection_2names_overloads()) - .def("MakeConnection", MakeConnection_4names, MakeConnection_4names_overloads()) - /* TODO use macro for arg counts?*/ - .def("SetBreakpoint", SetBreakpoint_1arg, "add breakpoint to 'procName:slotName'") - .def("SetBreakpoint", SetBreakpoint_2arg, "add breakpoint to 'procName, slotName'") - .def("RemoveBreakpoint", RemoveBreakpoint_1arg, "add breakpoint to 'procName:slotName'") - .def("RemoveBreakpoint", RemoveBreakpoint_2arg, "add breakpoint to 'procName, slotName'") - - // Run Queue - // Push new processor(s) to back of run queue - .def("PushBackToRunQueue", PushBackToRunQueue_string, "Push processor(s) to the back of the run queue") - .def("PushBackToRunQueue", PushBackToRunQueue_init_list) - .def("PushBackToRunQueue", PushBackToRunQueue_vector) - - // Remove items from run queue - .def("PopBackOfRunQueue", &KTProcessorToolbox::PopBackOfRunQueue, "Remove the last item in the run queue, whether it's a single processor or a group of processors") - .def("ClearRunQueue", &KTProcessorToolbox::ClearRunQueue, "Clear the run queue") - - // Run methods - .def("Run", &KTProcessorToolbox::Run, "Call Run() on all processors in the run queue") - .def("AsyncRun", &KTProcessorToolbox::AsyncRun, "Non-blocking call to Run()") - .def("WaitForContinue", &KTProcessorToolbox::WaitForContinue) - .def("WaitForBreak", &KTProcessorToolbox::WaitForBreak, "blocking call that waits until a breakpoint is reached, you must manually Continue()") - .def("WaitForEndOfRun", &KTProcessorToolbox::WaitForEndOfRun, "blocking call to Continue() execution until end of run is reached, you must manually Continue()") - .def("Continue", &KTProcessorToolbox::Continue, "non-blocking call to resume execution") - .def("CancelThreads", &KTProcessorToolbox::CancelThreads, "kill any running thread at the next breakpoint check") - .def("JoinRunThread", &KTProcessorToolbox::JoinRunThread) - - .def("GetData", &KTProcessorToolbox::GetData) - ; -} - -#endif /* KTPROCESSORTOOLBOXPY_HH_ */ diff --git a/Library/CMakeLists.txt b/Library/CMakeLists.txt index 11ee82f..ba43a3d 100644 --- a/Library/CMakeLists.txt +++ b/Library/CMakeLists.txt @@ -86,12 +86,6 @@ set( NYMPH_SOURCEFILES ${APPL_DIR}/KTThroughputProfiler.cc ) -set( NYMPH_PY_HEADERFILES - ${DATA_DIR}/KTDataPy.hh - ${PROC_DIR}/KTProcessorPy.hh - ${APPL_DIR}/KTProcessorToolboxPy.hh -) - # Python binding headers set( NYMPH_PYBINDING_HEADERFILES #${UTIL_DIR}/KTConfigurablePybind.hh @@ -111,11 +105,7 @@ set( NYMPH_PYBINDING_SOURCEFILES pbuilder_library( Nymph NYMPH_SOURCEFILES "" ) pbuilder_install_headers( ${NYMPH_HEADERFILES} ) -if (Nymph_ENABLE_PYTHON) - python_package_add_module(NymphPy.cc) -endif (Nymph_ENABLE_PYTHON) - -if( Nymph_ENABLE_PYBIND11 ) +if( Nymph_ENABLE_PYTHON ) set( LIB_DEPENDENCIES Nymph ) configure_file( AddLibPythonPath.sh.in AddLibPythonPath.sh @ONLY) @@ -125,5 +115,4 @@ if( Nymph_ENABLE_PYBIND11 ) target_link_libraries( py_nymph PRIVATE ${LIB_DEPENDENCIES} ${EXTERNAL_LIBRARIES} ) pbuilder_install_libraries( py_nymph ) pbuilder_install_headers( ${NYMPH_PYBINDING_HEADERFILES} ) - -endif( Nymph_ENABLE_PYBIND11 ) +endif( Nymph_ENABLE_PYTHON ) diff --git a/Library/Data/KTDataPy.hh b/Library/Data/KTDataPy.hh deleted file mode 100644 index 2b853eb..0000000 --- a/Library/Data/KTDataPy.hh +++ /dev/null @@ -1,23 +0,0 @@ -/* - * KTDataPy.hh - * - * Created on: April 10, 2017 - * Author: laroque - */ - - #ifndef KTDATAPY_HH_ - #define KTDATAPY_HH_ - -#include "KTCoreData.hh" - -void export_DataPy() -{ - using namespace Nymph; - using namespace boost::python; - class_("KTCoreData", init<>()) - .add_property("Counter", &KTCoreData::GetCounter, &KTCoreData::SetCounter) - .add_property("LastData", &KTCoreData::GetLastData, &KTCoreData::SetLastData) - ; -} - -#endif /* KTDATAPY_HH_ */ diff --git a/Library/NymphPy.cc b/Library/NymphPy.cc deleted file mode 100644 index 9fa346d..0000000 --- a/Library/NymphPy.cc +++ /dev/null @@ -1,14 +0,0 @@ -#include - -/* include components here*/ -#include "KTDataPy.hh" -#include "KTProcessorPy.hh" -#include "KTProcessorToolboxPy.hh" - -BOOST_PYTHON_MODULE(NymphPy) -{ - using namespace boost::python; - export_DataPy(); - export_Processor(); - export_ProcessorToolbox(); -} diff --git a/Library/Processor/KTProcessorPy.hh b/Library/Processor/KTProcessorPy.hh deleted file mode 100644 index f258310..0000000 --- a/Library/Processor/KTProcessorPy.hh +++ /dev/null @@ -1,47 +0,0 @@ -/** - @file KTProcessorPy.hh - @brief Contains KTProcessor python wrapping - @details KTProcessor is the processor base class - @author: B. H. LaRoque - @date: April 20, 2017 - */ - -#ifndef KTPROCESSORPY_HH_ -#define KTPROCESSORPY_HH_ - -#include "KTProcessor.hh" - -bool (Nymph::KTConfigurable::*Configure_JsonStr)(const std::string& config) = &Nymph::KTConfigurable::Configure; - -void export_Processor() -{ - using namespace Nymph; - using namespace boost::python; - - // KTProcessor base class - class_("KTProcessor", no_init) - //.def("RegisterProcessor", pure_virtual(&KTProcessor::RegisterProcessor), return_value_policy(), "register a processor") - - // PassThreadRefUpdate... needs KTThreadReference - //.def("PassThreadRefUpdate", &KTProcessor::PassThreadRefUpdate) - .def("ConnectASlot", &KTProcessor::ConnectASlot) - .def("ConnectASignal", &KTProcessor::ConnectASignal) - - // these next four need wrappers for return types (KT[Signal,Slot]Wrapper) - //.def("RegisterSignal", &KTProcessor::RegisterSignal) - //.def("RegisterSlot", &KTProcessor::RegisterSlot) - //.def("GetSignal", &KTProcessor::GetSignal) - //.def("GetSlot", &KTProcessor::GetSlot) - - /* now protected */ - //.def("ConnectSignalToSlot", &KTProcessor::ConnectSignalToSlot) - - .def("GetDoBreakpoint", &KTProcessor::GetDoBreakpoint) - .def("SetDoBreakpoint", &KTProcessor::SetDoBreakpoint) - - /* Inherited methods from unwrapped bases */ - .def("Configure", Configure_JsonStr, "Configure from json encoded configuration") - ; -} - -#endif /* KTPROCESSORPY_HH_ */ From 2e4e59dd19f89ed8f71c854aa4bbc99d3bad21dc Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Fri, 22 Feb 2019 22:55:33 -0800 Subject: [PATCH 126/521] Adaptations to updated scarab --- Executables/Validation/TestApplication.cc | 2 +- Library/Application/KTApplication.cc | 8 ++- Library/Application/KTCommandLineHandler.cc | 2 +- Library/Application/KTConfigurator.hh | 8 +-- Library/Application/KTProcessorToolbox.cc | 48 +++++++++--------- Library/Application/KTRunNymph.cc | 4 +- Library/Data/KTCutFilter.cc | 4 +- Library/Utility/KTConfigurable.cc | 4 +- Library/Utility/KTMemberVariable.hh | 56 +++++++++++---------- 9 files changed, 68 insertions(+), 68 deletions(-) diff --git a/Executables/Validation/TestApplication.cc b/Executables/Validation/TestApplication.cc index 37d4539..059848c 100644 --- a/Executables/Validation/TestApplication.cc +++ b/Executables/Validation/TestApplication.cc @@ -84,7 +84,7 @@ int main(int argc, char** argv) const scarab::param_node& topNode = app->GetConfigurator()->Config(); - if (testObj->Configure(topNode.node_at(testObj->GetConfigName()))) + if (testObj->Configure(topNode[testObj->GetConfigName()].as_node())) { KTINFO(testapplog, "Configuration complete:\n" << "\tInt data: " << testObj->GetIntData() << '\n' diff --git a/Library/Application/KTApplication.cc b/Library/Application/KTApplication.cc index 2ff51e2..4349856 100644 --- a/Library/Application/KTApplication.cc +++ b/Library/Application/KTApplication.cc @@ -67,7 +67,7 @@ namespace Nymph { scarab::path configFilePath = scarab::expand_path( fConfigFilename ); scarab::param_translator translator; - scarab::param* configFromFile = translator.read_file( configFilePath.native() ); + scarab::param_ptr_t configFromFile = translator.read_file( configFilePath.native() ); if( configFromFile == NULL ) { BOOST_THROW_EXCEPTION( KTException() << "[KTApplication] error parsing config file" << eom ); @@ -77,20 +77,18 @@ namespace Nymph BOOST_THROW_EXCEPTION( KTException() << "[KTApplication] configuration file must consist of an object/node" << eom ); } fConfigurator->Merge( configFromFile->as_node() ); - delete configFromFile; } // Command-line JSON configuration if (! clJSON.empty()) { scarab::param_input_json inputJSON; - scarab::param* configFromJSON = inputJSON.read_string( clJSON ); + scarab::param_ptr_t configFromJSON = inputJSON.read_string( clJSON ); if( ! configFromJSON->is_node() ) { BOOST_THROW_EXCEPTION( KTException() << "[KTApplication] command line json must be an object" << eom ); } fConfigurator->Merge( configFromJSON->as_node() ); - delete configFromJSON; } // Command-line overrides @@ -141,7 +139,7 @@ namespace Nymph unsigned arraySize = paramArray.size(); for (unsigned iParam = 0; iParam < arraySize; ++iParam) { - AddConfigOptionsToCLHandler(paramArray.at(iParam), nextRootName + std::to_string(iParam)); + AddConfigOptionsToCLHandler(paramArray[iParam], nextRootName + std::to_string(iParam)); } } else if (param.is_node()) diff --git a/Library/Application/KTCommandLineHandler.cc b/Library/Application/KTCommandLineHandler.cc index 3e72779..e50164f 100644 --- a/Library/Application/KTCommandLineHandler.cc +++ b/Library/Application/KTCommandLineHandler.cc @@ -275,7 +275,7 @@ namespace Nymph string nodeName(t_full_name.substr(t_node_start_pos, t_node_sep_pos)); if (parentNode.has(nodeName)) { - parentNode = parentNode.node_at(nodeName); + parentNode = parentNode[nodeName]().as_node(); } else { diff --git a/Library/Application/KTConfigurator.hh b/Library/Application/KTConfigurator.hh index bbdcc49..a25fcdc 100644 --- a/Library/Application/KTConfigurator.hh +++ b/Library/Application/KTConfigurator.hh @@ -52,10 +52,10 @@ namespace Nymph { try { - fParamBuffer = &const_cast< scarab::param& >( fMasterConfig->at( aName ) ); + fParamBuffer = &const_cast< scarab::param& >( (*fMasterConfig)[aName] ); if( fParamBuffer->is_value() ) { - return fParamBuffer->as_value().get< XReturnType >(); + return (*fParamBuffer)().as< XReturnType >(); } } catch( std::exception& e ) @@ -68,10 +68,10 @@ namespace Nymph { try { - fParamBuffer = &const_cast< scarab::param& >( fMasterConfig->at( aName ) ); + fParamBuffer = &const_cast< scarab::param& >( (*fMasterConfig)[aName] ); if( fParamBuffer->is_value() ) { - return fParamBuffer->as_value().get< XReturnType >(); + return (*fParamBuffer)().as< XReturnType >(); } } catch( std::exception& e ) diff --git a/Library/Application/KTProcessorToolbox.cc b/Library/Application/KTProcessorToolbox.cc index f1589a3..d483f1d 100644 --- a/Library/Application/KTProcessorToolbox.cc +++ b/Library/Application/KTProcessorToolbox.cc @@ -64,7 +64,7 @@ namespace Nymph } else { - const scarab::param_array& procArray = node.array_at( "processors" ); + const scarab::param_array& procArray = node["processors"].as_array(); for( scarab::param_array::const_iterator procIt = procArray.begin(); procIt != procArray.end(); ++procIt ) { if( ! procIt->is_node() ) @@ -72,24 +72,24 @@ namespace Nymph KTERROR( proclog, "Invalid processor entry: not a node" ); return false; } - const scarab::param_node* procNode = &( procIt->as_node() ); + const scarab::param_node& procNode = procIt->as_node(); - if (! procNode->has("type")) + if (! procNode.has("type")) { KTERROR(proclog, "Unable to create processor: no processor type given"); return false; } - string procType = procNode->get_value("type"); + string procType = procNode["type"]().as_string(); string procName; - if (! procNode->has("name")) + if (! procNode.has("name")) { KTINFO(proclog, "No name given for processor of type <" << procType << ">; using type as name."); procName = procType; } else { - procName = procNode->get_value("name"); + procName = procNode["name"]().as_string(); } std::shared_ptr< KTProcessor > newProc ( fProcFactory->create(procType, procType)); if (newProc == NULL) @@ -115,7 +115,7 @@ namespace Nymph } else { - const scarab::param_array& connArray = node.array_at( "connections" ); + const scarab::param_array& connArray = node["connections"].as_array(); for( scarab::param_array::const_iterator connIt = connArray.begin(); connIt != connArray.end(); ++connIt ) { if( ! connIt->is_node() ) @@ -123,23 +123,23 @@ namespace Nymph KTERROR( proclog, "Invalid connection entry: not a node" ); return false; } - const scarab::param_node* connNode = &( connIt->as_node() ); + const scarab::param_node& connNode = connIt->as_node(); - if ( ! connNode->has("signal") || ! connNode->has("slot") ) + if ( ! connNode.has("signal") || ! connNode.has("slot") ) { KTERROR(proclog, "Signal/Slot connection information is incomplete!"); - if (connNode->has("signal")) + if (connNode.has("signal")) { - KTWARN(proclog, "signal = " << connNode->get_value("signal")); + KTWARN(proclog, "signal = " << connNode["signal"]()); } else { KTERROR(proclog, "signal = MISSING"); } - if (connNode->has("slot")) + if (connNode.has("slot")) { - KTWARN(proclog, "slot = " << connNode->get_value("slot")); + KTWARN(proclog, "slot = " << connNode["slot"]()); } else { @@ -149,30 +149,30 @@ namespace Nymph } bool connReturn = false; - if (connNode->has("order")) + if (connNode.has("order")) { - connReturn = MakeConnection(connNode->get_value("signal"), connNode->get_value("slot"), connNode->get_value< int >("order")); + connReturn = MakeConnection(connNode["signal"]().as_string(), connNode["slot"]().as_string(), connNode["order"]().as_int()); } else { - connReturn = MakeConnection(connNode->get_value("signal"), connNode->get_value("slot")); + connReturn = MakeConnection(connNode["signal"]().as_string(), connNode["slot"]().as_string()); } if (! connReturn) { - KTERROR(proclog, "Unable to make connection <" << connNode->get_value("signal") << "> --> <" << connNode->get_value("slot") << ">"); + KTERROR(proclog, "Unable to make connection <" << connNode["signal"]() << "> --> <" << connNode["slot"]() << ">"); return false; } - if (connNode->has("breakpoint")) + if (connNode.has("breakpoint")) { - if (! SetBreakpoint(connNode->get_value("slot"))) + if (! SetBreakpoint(connNode["slot"]().as_string())) { - KTERROR(proclog, "Unable to set breakpoint on <" << connNode->get_value("slot")); + KTERROR(proclog, "Unable to set breakpoint on <" << connNode["slot"]()); return false; } } - KTINFO(proclog, "Signal <" << connNode->get_value("signal") << "> connected to slot <" << connNode->get_value("slot") << ">"); + KTINFO(proclog, "Signal <" << connNode["signal"]() << "> connected to slot <" << connNode["slot"]() << ">"); } } @@ -187,7 +187,7 @@ namespace Nymph } else { - const scarab::param_array& rqArray = node.array_at( "run-queue" ); + const scarab::param_array& rqArray = node["run-queue"].as_array(); for (scarab::param_array::const_iterator rqIt = rqArray.begin(); rqIt != rqArray.end(); ++rqIt) { if (rqIt->is_value()) @@ -247,7 +247,7 @@ namespace Nymph continue; } } - const scarab::param_node& subNode = node.node_at(nameUsed); + const scarab::param_node& subNode = node[nameUsed].as_node(); if (! iter->second.fProc->Configure(subNode)) { KTERROR(proclog, "An error occurred while configuring processor <" << procName << "> with parameter node <" << nameUsed << ">"); @@ -262,7 +262,7 @@ namespace Nymph scarab::param_translator translator; scarab::param_node optNode; optNode.add( "encoding", new scarab::param_value( "json" ) ); - return ConfigureProcessors( translator.read_string( config, &optNode )->as_node() ); + return ConfigureProcessors( translator.read_string( config, optNode )->as_node() ); } std::shared_ptr< KTProcessor > KTProcessorToolbox::GetProcessor(const std::string& procName) diff --git a/Library/Application/KTRunNymph.cc b/Library/Application/KTRunNymph.cc index 26594c4..fd33f28 100644 --- a/Library/Application/KTRunNymph.cc +++ b/Library/Application/KTRunNymph.cc @@ -23,7 +23,7 @@ namespace Nymph { const scarab::param_node& parentConfigNode = app->GetConfigurator()->Config(); - if( ! app->Configure(parentConfigNode.node_at(app->GetConfigName() ) ) ) + if( ! app->Configure( parentConfigNode[app->GetConfigName()].as_node() ) ) { KTERROR( nlog, "Unable to configure the application. Aborting."); return -2; @@ -33,7 +33,7 @@ namespace Nymph // This will create all of the requested processors, connect their signals and slots, and fill the run queue. KTProcessorToolbox procTB; - if ( ! procTB.Configure( parentConfigNode.node_at( procTB.GetConfigName() ) ) ) + if ( ! procTB.Configure( parentConfigNode[procTB.GetConfigName()].as_node() ) ) { KTERROR( nlog, "Unable to configure processor toolbox. Aborting." ); return -3; diff --git a/Library/Data/KTCutFilter.cc b/Library/Data/KTCutFilter.cc index 7be973e..05d1906 100644 --- a/Library/Data/KTCutFilter.cc +++ b/Library/Data/KTCutFilter.cc @@ -40,11 +40,11 @@ namespace Nymph // Config-file settings if (node.has("cut-mask-int")) { - SetCutMask(node.get_value< unsigned long long >("cut-mask-int")); + SetCutMask(node["cut-mask-int"]().as_uint()); } if (node.has("cut-mask")) { - SetCutMask(KTCutStatus::bitset_type(node.get_value("cut-mask"))); + SetCutMask(KTCutStatus::bitset_type(node["cut-mask"]().as_string())); } if (node.get_value("cut-mask-all", false)) { diff --git a/Library/Utility/KTConfigurable.cc b/Library/Utility/KTConfigurable.cc index b79d9fd..d5f2cdb 100644 --- a/Library/Utility/KTConfigurable.cc +++ b/Library/Utility/KTConfigurable.cc @@ -38,8 +38,8 @@ namespace Nymph { scarab::param_translator translator; scarab::param_node optNode; - optNode.add( "encoding", new scarab::param_value( "json" ) ); - return Configure( translator.read_string( config, &optNode )->as_node() );; + optNode.add( "encoding", "json" ); + return Configure( translator.read_string( config, optNode )->as_node() );; } diff --git a/Library/Utility/KTMemberVariable.hh b/Library/Utility/KTMemberVariable.hh index d867381..f9bdec1 100644 --- a/Library/Utility/KTMemberVariable.hh +++ b/Library/Utility/KTMemberVariable.hh @@ -60,37 +60,39 @@ #define var_prefix f #define static_prefix s -#include "_member_variables.hh" +#include "_camel_case_member_variables.hh" -#define MEMBERVARIABLE mv_accessible -#define MEMBERVARIABLE_NOSET mv_accessible_noset -#define MEMBERVARIABLE_STATIC mv_accessible_static -#define MEMBERVARIABLE_STATIC_NOSET mv_accessible_static_noset -#define MEMBERVARIABLE_MUTABLE mv_accessible_mutable -#define MEMBERVARIABLE_MUTABLE_NOSET mv_accessible_mutable_noset +#define MEMBERVARIABLE camel_case_mv_accessible +#define MEMBERVARIABLE_NOSET camel_case_mv_accessible_noset +#define MEMBERVARIABLE_STATIC camel_case_mv_accessible_static +#define MEMBERVARIABLE_STATIC_NOSET camel_case_mv_accessible_static_noset +#define MEMBERVARIABLE_MUTABLE camel_case_mv_accessible_mutable +#define MEMBERVARIABLE_MUTABLE_NOSET camel_case_mv_accessible_mutable_noset -#define MEMBERVARIABLE_REF mv_referrable -#define MEMBERVARIABLE_REF_CONST mv_referrable_const -#define MEMBERVARIABLE_REF_STATIC mv_referrable_static -#define MEMBERVARIABLE_REF_MUTABLE mv_referrable_mutable +#define MEMBERVARIABLE_REF camel_case_mv_referrable +#define MEMBERVARIABLE_REF_CONST camel_case_mv_referrable_const +#define MEMBERVARIABLE_REF_STATIC camel_case_mv_referrable_static +#define MEMBERVARIABLE_REF_MUTABLE camel_case_mv_referrable_mutable +#define MEMBERVARIABLE_REF_MUTABLE_CONST camel_case_mv_referrable_mutable -#define MEMBERVARIABLE_PTR mv_assignable -#define MEMBERVARIABLE_PTR_NOSET mv_assignable_noset -#define MEMBERVARIABLE_PTR_STATIC mv_assignable_static -#define MEMBERVARIABLE_PTR_STATIC_NOSET mv_assignable_static_noset -#define MEMBERVARIABLE_PTR_MUTABLE mv_assignable_mutable -#define MEMBERVARIABLE_PTR_MUTABLE_NOSET mv_assignable_mutable_noset +#define MEMBERVARIABLE_PTR camel_case_mv_assignable +#define MEMBERVARIABLE_PTR_NOSET camel_case_mv_assignable_noset +#define MEMBERVARIABLE_PTR_STATIC camel_case_mv_assignable_static +#define MEMBERVARIABLE_PTR_STATIC_NOSET camel_case_mv_assignable_static_noset +#define MEMBERVARIABLE_PTR_MUTABLE camel_case_mv_assignable_mutable +#define MEMBERVARIABLE_PTR_MUTABLE_NOSET camel_case_mv_assignable_mutable_noset -#define MEMBERVARIABLE_SHARED_PTR mv_shared_ptr -#define MEMBERVARIABLE_SHARED_PTR_CONST mv_shared_ptr_const -#define MEMBERVARIABLE_SHARED_PTR_STATIC mv_shared_ptr_static -#define MEMBERVARIABLE_SHARED_PTR_MUTABLE mv_shared_ptr_mutable +#define MEMBERVARIABLE_SHARED_PTR camel_case_mv_shared_ptr +#define MEMBERVARIABLE_SHARED_PTR_CONST camel_case_mv_shared_ptr_const +#define MEMBERVARIABLE_SHARED_PTR_STATIC camel_case_mv_shared_ptr_static +#define MEMBERVARIABLE_SHARED_PTR_MUTABLE camel_case_mv_shared_ptr_mutable +#define MEMBERVARIABLE_SHARED_PTR_MUTABLE_CONST camel_case_mv_shared_ptr_mutable -#define MEMBERVARIABLE_ATOMIC mv_atomic -#define MEMBERVARIABLE_ATOMIC_NOSET mv_atomic_noset -#define MEMBERVARIABLE_ATOMIC_STATIC mv_atomic_static -#define MEMBERVARIABLE_ATOMIC_STATIC_NOSET mv_atomic_static_noset -#define MEMBERVARIABLE_ATOMIC_MUTABLE mv_atomic_mutable -#define MEMBERVARIABLE_ATOMIC_MUTABLE_NOSET mv_atomic_mutable_noset +#define MEMBERVARIABLE_ATOMIC camel_case_mv_atomic +#define MEMBERVARIABLE_ATOMIC_NOSET camel_case_mv_atomic_noset +#define MEMBERVARIABLE_ATOMIC_STATIC camel_case_mv_atomic_static +#define MEMBERVARIABLE_ATOMIC_STATIC_NOSET camel_case_mv_atomic_static_noset +#define MEMBERVARIABLE_ATOMIC_MUTABLE camel_case_mv_atomic_mutable +#define MEMBERVARIABLE_ATOMIC_MUTABLE_NOSET camel_case_mv_atomic_mutable_noset #endif /* KTMEMBERVARIABLE_HH_ */ From d7691238f84fed21cb8a775a8f765f11c45a23af Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Sat, 23 Feb 2019 23:16:40 -0800 Subject: [PATCH 127/521] Adapted KTParamPybind.hh to changes in param* --- Library/Utility/KTParamPybind.hh | 32 +++++++------------------------- 1 file changed, 7 insertions(+), 25 deletions(-) diff --git a/Library/Utility/KTParamPybind.hh b/Library/Utility/KTParamPybind.hh index e55db88..dbbf917 100644 --- a/Library/Utility/KTParamPybind.hh +++ b/Library/Utility/KTParamPybind.hh @@ -39,10 +39,10 @@ namespace Nymph .def( "as_string", (const std::string& (scarab::param_value::*)() const) &scarab::param_value::as_string, "Get parameter value as a string" ) .def( "set", (void (scarab::param_value::*)(bool)) &scarab::param_value::set, "Set a bool value" ) - .def( "set", (void (scarab::param_value::*)(unsigned)) &scarab::param_value::set, "Set an unsigned integer value" ) - .def( "set", (void (scarab::param_value::*)(int)) &scarab::param_value::set, "Set a signed integer value" ) + .def( "set", (void (scarab::param_value::*)(unsigned)) &scarab::param_value::set, "Set an unsigned integer value" ) + .def( "set", (void (scarab::param_value::*)(int)) &scarab::param_value::set, "Set a signed integer value" ) .def( "set", (void (scarab::param_value::*)(double)) &scarab::param_value::set, "Set an float value" ) - .def( "set", (void (scarab::param_value::*)(const std::string&)) &scarab::param_value::set, "Set an string value" ) + .def( "set", (void (scarab::param_value::*)(std::string)) &scarab::param_value::set, "Set an string value" ) ; // param_node @@ -52,17 +52,8 @@ namespace Nymph .def( "add",(bool (scarab::param_node::*)(const std::string&, const scarab::param&)) &scarab::param_node::add, "Add a param object to a node" ) - // Get value of the parameter, when no default is set - .def( "get_value_bool", (bool (scarab::param_node::*)(const std::string&) const) &scarab::param_node::get_value, - "Get parameter node value as a bool" ) - .def( "get_value_uint", (unsigned (scarab::param_node::*)(const std::string&) const) &scarab::param_node::get_value, - "Get parameter node value as an unsigned integer" ) - .def( "get_value_int", (int (scarab::param_node::*)(const std::string&) const) &scarab::param_node::get_value, - "Get parameter node value as a signed integer" ) - .def( "get_value_double", (double (scarab::param_node::*)(const std::string&) const) &scarab::param_node::get_value, - "Get parameter node value as a float" ) - .def( "get_value_string", (std::string (scarab::param_node::*)(const std::string&) const) &scarab::param_node::get_value, - "Get parameter node value as a string" ) + .def( "at", (scarab::param& (scarab::param_node::*)(const std::string&)) &scarab::param_node::operator[], + "Get the param object for a given key" ) // Get value of the parameter, bringing along the default value .def( "get_value", (bool (scarab::param_node::*)(const std::string&, bool) const) &scarab::param_node::get_value, @@ -90,17 +81,8 @@ namespace Nymph .def( "assign", (void (scarab::param_array::*)(unsigned, const scarab::param&)) &scarab::param_array::assign, "Add a param object to the specified index in a array" ) - // Get value of the parameter, when no default is set - .def( "get_value_bool", (bool (scarab::param_array::*)(unsigned) const) &scarab::param_array::get_value, - "Get parameter array value as a bool" ) - .def( "get_value_uint", (unsigned (scarab::param_array::*)(unsigned) const) &scarab::param_array::get_value, - "Get parameter array value as an unsigned integer" ) - .def( "get_value_int", (int (scarab::param_array::*)(unsigned) const) &scarab::param_array::get_value, - "Get parameter array value as a signed integer" ) - .def( "get_value_double", (double (scarab::param_array::*)(unsigned) const) &scarab::param_array::get_value, - "Get parameter array value as a float" ) - .def( "get_value_string", (std::string (scarab::param_array::*)(unsigned) const) &scarab::param_array::get_value, - "Get parameter array value as a string" ) + .def( "at", (scarab::param& (scarab::param_array::*)(unsigned)) &scarab::param_array::operator[], + "Get the param object for a given index" ) // Get value of the parameter, bringing along the default value .def( "get_value", (bool (scarab::param_array::*)(unsigned, bool) const) &scarab::param_array::get_value, From eae5b0a06f9ed5d10f0e9b7d0712b383d6c371c2 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Mon, 25 Feb 2019 13:04:05 -0800 Subject: [PATCH 128/521] Interim commit --- Library/Processor/KTNymphSignals.hh | 46 +++ Library/Processor/KTNymphSlot.hh | 381 +++++++++++++++++++++ Library/Processor/KTSignal.hh | 144 ++++++-- Library/Processor/KTSignalSlotBase.hh | 52 +++ Library/Processor/KTSlot.hh | 457 ++++++-------------------- 5 files changed, 702 insertions(+), 378 deletions(-) create mode 100644 Library/Processor/KTNymphSignals.hh create mode 100644 Library/Processor/KTNymphSlot.hh create mode 100644 Library/Processor/KTSignalSlotBase.hh diff --git a/Library/Processor/KTNymphSignals.hh b/Library/Processor/KTNymphSignals.hh new file mode 100644 index 0000000..aa52aba --- /dev/null +++ b/Library/Processor/KTNymphSignals.hh @@ -0,0 +1,46 @@ +/* + * KTNymphSignals.hh + * + * Created on: Feb 25, 2019 + * Author: N.S. Oblath + */ + +#ifndef NYMPH_KTNYMPHSIGNALS_HH_ +#define NYMPH_KTNYMPHSIGNALS_HH_ + +#include "KTSignal.hh" + +#include "KTCoreData.hh" + +namespace Nymph +{ + /// Convenience typedef for done signals + typedef KTSignal<> KTSignalDone; + + // Convenience typedef for backwards compatibility + template< typename XDataType > + using KTSignalOneArg = KTSignal< XDataType >; + + /*! + @class KTSignalData + @author N. S. Oblath + + @brief Creates a signal that takes a KTDataHandle object as its argument. + + @details + The purpose of the signal is for passing KTCoreData pointers between Processors. + The signal is emitted by calling operator(). + If a KTDataSlot is being used, and the Slot has been given a pointer to this signal, the Slot will emit the Signal. + + Usage: + In your Processor's header add a member variable of type KTSignalData. + + Initialize the signal with the processor's 'this' pointer and the name of the signal. + + That's it! + */ + typedef KTSignal< KTDataHandle > KTSignalData; + +} /* namespace Nymph */ + +#endif /* NYMPH_KTNYMPHSIGNALS_HH_ */ diff --git a/Library/Processor/KTNymphSlot.hh b/Library/Processor/KTNymphSlot.hh new file mode 100644 index 0000000..5e65969 --- /dev/null +++ b/Library/Processor/KTNymphSlot.hh @@ -0,0 +1,381 @@ +/* + * KTNymphSlot.hh + * + * Created on: Feb 25, 2019 + * Author: N.S. Oblath + */ + +#ifndef NYMPH_KTNYMPHSLOT_HH_ +#define NYMPH_KTNYMPHSLOT_HH_ + +#include "KTSlot.hh" + + + +namespace Nymph +{ + // Typedefs for backwards compatibility + + typedef KTSlot<> KTSlotNoArg; + + template < typename Arg1 > + using KTSlotOneArg = KTSlot< Arg1 >; + + template< typename Arg1, typename Arg2 > + using KTSlotTwoArg = KTSlot< Arg1, Arg2 >; + + + /*! + @class KTSlotData + @author N. S. Oblath + + @brief Creates a slot that takes a KTDataHandle object as the argument; the function that gets called should take 0 or more DataType&'s as its argument. + + @details + Usage: + This slot type adds the slot function (signature void (KTDataHandle). + Your processor (or, optionally, a different object) must have a member function with the signature bool (DataType1&, . . .). + The slot function checks that the provided KTCoreData object contains data of type DataType, and then calls the member function. + + In your Processor's header add a member variable of type KTSlotOneArg< DataType >. + The variable may be private. + + Initialize the slot with the name of the slot, the address of the owner of the slot function, and the function pointer. + Optionally, if the Processor is separate from the owner of the slot function, the Processor address is specified as the second argument to the constructor. + + Also optionally, a signal to be emitted after the return of the member function can be specified as the last argument. + */ + template< class XReturnType, class... XDataArgs > + class KTSlotData : public KTSlot< KTDataHandle > + { + public: + /// Constructor for the case where the processor has the function that will be called by the slot + template< class XFuncOwnerType, class... XFuncDataTypes > + KTSlotData( const std::string& name, XFuncOwnerType* owner, void (XFuncOwnerType::*func)( const XFuncDataTypes&..., XReturnType& ), KTSignalData* signalPtr ); + + /// Constructor for the case where the processor has the function that will be called by the slot + template< class XFuncOwnerType, class... XFuncDataTypes > + KTSlotData( const std::string& name, XFuncOwnerType* owner, void (XFuncOwnerType::*func)( const XFuncDataTypes&..., XReturnType& ) ); + + /// Constructor for the case where the processor and the object with the function that will be called are different + template< class XFuncOwnerType, class... XFuncDataTypes > + KTSlotData( const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, void (XFuncOwnerType::*func)( const XFuncDataTypes&..., XReturnType& ), KTSignalData* signalPtr ); + + /// Constructor for the case where the processor and the object with the function that will be called are different + template< class XFuncOwnerType, class... XFuncDataTypes > + KTSlotData( const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, void (XFuncOwnerType::*func)( const XFuncDataTypes&..., XReturnType& ) ); + + virtual ~KTSlotData(); + + void operator()( KTDataHandle data ); + + protected: + template< typename... DataTypes > + bool DataPresent( KTDataHandle data ); + + //function_signature fFunc; + std::function< XReturnType (const XDataArgs&..., XReturnType&) > fFunc; + + KTSignalData* fSignalPtr; + }; + + // partial specialization for no new data type + template< class... XDataArgs > + class KTSlotData< void, XDataArgs... > : public KTSlot< KTDataHandle > + { + public: + /// Constructor for the case where the processor has the function that will be called by the slot + template< class XFuncOwnerType, class... XFuncDataTypes > + KTSlotData( const std::string& name, XFuncOwnerType* owner, void (XFuncOwnerType::*func)( const XFuncDataTypes&... ), KTSignalData* signalPtr ); + + /// Constructor for the case where the processor has the function that will be called by the slot + template< class XFuncOwnerType, class... XFuncDataTypes > + KTSlotData( const std::string& name, XFuncOwnerType* owner, void (XFuncOwnerType::*func)( const XFuncDataTypes&... ) ); + + /// Constructor for the case where the processor and the object with the function that will be called are different + template< class XFuncOwnerType, class... XFuncDataTypes > + KTSlotData( const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, void (XFuncOwnerType::*func)( const XFuncDataTypes&... ), KTSignalData* signalPtr ); + + /// Constructor for the case where the processor and the object with the function that will be called are different + template< class XFuncOwnerType, class... XFuncDataTypes > + KTSlotData( const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, void (XFuncOwnerType::*func)( const XFuncDataTypes&... ) ); + + virtual ~KTSlotData(); + + void operator()( KTDataHandle data ); + + protected: + template< typename... DataTypes > + bool DataPresent( KTDataHandle data ); + + //function_signature fFunc; + std::function< void (const XDataArgs&...) > fFunc; + + KTSignalData* fSignalPtr; + }; + + + /*! + @class KTSlotDone + @author N. S. Oblath + + @brief Creates a slot to receive indication that upstream processing is complete and will emit a similar signal. + + @details + Usage: + This slot type adds the slot function (signature void ()). + Your processor (or, optionally, a different object) must have a member function with the signature void (). + The slot calls the member function. + + In your Processor's header add a member variable of type KTDoneSlot. + The variable may be private. + + Initialize the slot with the name of the slot, the address of the owner of the slot function, and the function pointer. + Optionally, if the Processor is separate from the owner of the slot function, the Processor address is specified as the second argument to the constructor. + + Also optionally, a signal to be emitted after the return of the member function can be specified as the last argument. + */ + class KTSlotDone : public KTSlot<> + { + public: + /// Constructor for the case where the processor has the function that will be called by the slot + template< class XFuncOwnerType > + KTSlotDone( const std::string& name, XFuncOwnerType* owner, void (XFuncOwnerType::*func)(), KTSignalDone* signalPtr=nullptr ); + /// Constructor for the case where the processor and the object with the function that will be called are different + template< class XFuncOwnerType > + KTSlotDone( const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, void (XFuncOwnerType::*func)(), KTSignalDone* signalPtr=nullptr ); + virtual ~KTSlotDone(); + + void operator()(); + + protected: + std::function< void () > fFunc; + + KTSignalDone* fSignalPtr; + }; + + + //******************* + // Implementations + //******************* + + // KTSlotData + + template< class XReturnType, class... XDataTypes > + template< class XFuncOwnerType, class... XFuncDataTypes > + KTSlotData< XReturnType, XDataTypes... >::KTSlotData(const std::string& name, XFuncOwnerType* owner, void (XFuncOwnerType::*func)( const XFuncDataTypes&..., XReturnType& ), KTSignalData* signalPtr) : + KTSlot( name, owner, this, &KTSlotData::operator(), {signalPtr->GetName()} ), + fFunc( [func, owner]( const XDataTypes&... args ){ return (owner->*func)(args...);} ), + fSignalPtr( signalPtr ) + { + } + + template< class XReturnType, class... XDataTypes > + template< class XFuncOwnerType, class... XFuncDataTypes > + KTSlotData< XReturnType, XDataTypes... >::KTSlotData(const std::string& name, XFuncOwnerType* owner, void (XFuncOwnerType::*func)( const XFuncDataTypes&..., XReturnType& )) : + KTSlot( name, owner, this, &KTSlotData::operator() ), + fFunc( [func, owner]( const XDataTypes&... args ){ return (owner->*func)(args...);} ), + fSignalPtr( nullptr ) + { + } + + template< class XReturnType, class... XDataTypes > + template< class XFuncOwnerType, class... XFuncDataTypes > + KTSlotData< XReturnType, XDataTypes... >::KTSlotData(const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, void (XFuncOwnerType::*func)( const XFuncDataTypes&..., XReturnType& ), KTSignalData* signalPtr) : + KTSlot( name, proc, this, &KTSlotData::operator(), { signalPtr->GetName()} ), + fFunc( [func, owner]( const XDataTypes&... args ){return (owner->*func) (args... );} ), + fSignalPtr( signalPtr ) + { + } + + template< class XReturnType, class... XDataTypes > + template< class XFuncOwnerType, class... XFuncDataTypes > + KTSlotData< XReturnType, XDataTypes... >::KTSlotData(const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, void (XFuncOwnerType::*func)( const XFuncDataTypes&..., XReturnType& )) : + KTSlot( name, proc, this, &KTSlotData::operator() ), + fFunc( [func, owner]( const XDataTypes&... args ){return (owner->*func) (args... );} ), + fSignalPtr( nullptr ) + { + } + + template< class XReturnType, class... XDataTypes > + KTSlotData< XReturnType, XDataTypes... >::~KTSlotData() + { + } + + template< class XReturnType, class... XDataTypes > + void KTSlotData< XReturnType, XDataTypes... >::operator()( KTDataHandle dataHandle ) + { + // Standard data slot pattern: + + std::shared_ptr< KTThreadReference > ref = fSlotWrapper->GetThreadRef(); + + // Check to ensure that the required data type is present + if( ! DataPresent< XDataTypes... >( dataHandle ) ) + { + KTERROR( slotlog, "Failed to find all of the necessary data types in slot <" << fName << ">. Aborting." ); + THROW_THREADREF_EXCEPTION( ref, KTException() << "Failed to find all of the necessary data types in slot <" << fName << ">. Aborting." ); + return; + } + + // Call the function + try + { + fFunc( dataHandle->Of< XDataTypes >()... , dataHandle->Of< XReturnType >() ); + } + catch( boost::exception& e ) + { + e << KTErrorMsgInfo< struct slotData_RunFunc >( "Something went wrong in slot <" + fName + ">. Aborting." ); + ref->SetReturnException( boost::current_exception() ); + } + + // Perform breakpoint here if necessary (either if initiated here or if stopping here due to a breakpoint elsewhere) + // Sets the dataHandle into the return + ref->Break( dataHandle, fSlotWrapper->GetDoBreakpoint() ); + + // If there's a signal pointer, emit the signal + if( fSignalPtr != nullptr ) + { + (*fSignalPtr)( dataHandle ); + } + return; + } + + template< class XReturnType, class... XDataTypes > + template< typename... DataTypes > + bool KTSlotData< XReturnType, XDataTypes... >::DataPresent( KTDataHandle data ) + { + return DataPresentHelper< DataTypes... >::DataPresent( data ); + } + + + // KTSlotData with no return type + + template< class... XDataTypes > + template< class XFuncOwnerType, class... XFuncDataTypes > + KTSlotData< void, XDataTypes... >::KTSlotData(const std::string& name, XFuncOwnerType* owner, void (XFuncOwnerType::*func)( const XFuncDataTypes&... ), KTSignalData* signalPtr) : + KTSlot( name, owner, this, &KTSlotData::operator(), {signalPtr->GetName()} ), + fFunc( [func, owner]( const XDataTypes&... args ){ return (owner->*func)(args...);} ), + fSignalPtr( signalPtr ) + { + } + + template< class... XDataTypes > + template< class XFuncOwnerType, class... XFuncDataTypes > + KTSlotData< void, XDataTypes... >::KTSlotData(const std::string& name, XFuncOwnerType* owner, void (XFuncOwnerType::*func)( const XFuncDataTypes&... )) : + KTSlot( name, owner, this, &KTSlotData::operator() ), + fFunc( [func, owner]( const XDataTypes&... args ){ return (owner->*func)(args...);} ), + fSignalPtr( nullptr ) + { + } + + template< class... XDataTypes > + template< class XFuncOwnerType, class... XFuncDataTypes > + KTSlotData< void, XDataTypes... >::KTSlotData(const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, void (XFuncOwnerType::*func)( const XFuncDataTypes&... ), KTSignalData* signalPtr) : + KTSlot( name, proc, this, &KTSlotData::operator(), { signalPtr->GetName()} ), + fFunc( [func, owner]( const XDataTypes&... args ){return (owner->*func) (args... );} ), + fSignalPtr( signalPtr ) + { + } + + template< class... XDataTypes > + template< class XFuncOwnerType, class... XFuncDataTypes > + KTSlotData< void, XDataTypes... >::KTSlotData(const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, void (XFuncOwnerType::*func)( const XFuncDataTypes&... )) : + KTSlot( name, proc, this, &KTSlotData::operator() ), + fFunc( [func, owner]( const XDataTypes&... args ){return (owner->*func) (args... );} ), + fSignalPtr( nullptr ) + { + } + + template< class... XDataTypes > + KTSlotData< void, XDataTypes... >::~KTSlotData() + { + } + + template< class... XDataTypes > + void KTSlotData< void, XDataTypes... >::operator()( KTDataHandle dataHandle ) + { + // Standard data slot pattern: + + std::shared_ptr< KTThreadReference > ref = fSlotWrapper->GetThreadRef(); + + // Check to ensure that the required data type is present + if( ! DataPresent< XDataTypes... >( dataHandle ) ) + { + KTERROR( slotlog, "Failed to find all of the necessary data types in slot <" << fName << ">. Aborting." ); + THROW_THREADREF_EXCEPTION( ref, KTException() << "Failed to find all of the necessary data types in slot <" << fName << ">. Aborting." ); + return; + } + + // Call the function + try + { + fFunc( dataHandle->Of< XDataTypes >()... ); + } + catch( boost::exception& e ) + { + e << KTErrorMsgInfo< struct slotData_RunFunc >( "Something went wrong in slot <" + fName + ">. Aborting." ); + ref->SetReturnException( boost::current_exception() ); + } + + // Perform breakpoint here if necessary (either if initiated here or if stopping here due to a breakpoint elsewhere) + // Sets the dataHandle into the return + ref->Break( dataHandle, fSlotWrapper->GetDoBreakpoint() ); + + // If there's a signal pointer, emit the signal + if( fSignalPtr != nullptr ) + { + (*fSignalPtr)( dataHandle ); + } + return; + } + + template< class... XDataTypes > + template< typename... DataTypes > + bool KTSlotData< void, XDataTypes... >::DataPresent( KTDataHandle data ) + { + return DataPresentHelper< DataTypes... >::DataPresent( data ); + } + + + // KTSlotDone + + template< class XFuncOwnerType > + KTSlotDone::KTSlotDone(const std::string& name, XFuncOwnerType* owner, void (XFuncOwnerType::*func)(), KTSignalDone* signalPtr) : + KTSlot( name, owner, this, &KTSlotDone::operator(), {signalPtr->GetName()} ), + fFunc( [func, owner](){ return (owner->*func)(); } ), + fSignalPtr( signalPtr ) + { + } + + template< class XFuncOwnerType > + KTSlotDone::KTSlotDone(const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, void (XFuncOwnerType::*func)(), KTSignalDone* signalPtr) : + KTSlot( name, proc, this, &KTSlotDone::operator(), {signalPtr->GetName()} ), + fFunc( [func, owner](){ return (owner->*func)(); } ), + fSignalPtr( signalPtr ) + { + } + + inline KTSlotDone::~KTSlotDone() + { + } + + inline void KTSlotDone::operator()() + { + // Call the function + fFunc(); + + // Perform breakpoint here if necessary (either if initiated here or if stopping here due to a breakpoint elsewhere) + // Sets the dataHandle into the return + fSlotWrapper->GetThreadRef()->Break( KTDataHandle(), fSlotWrapper->GetDoBreakpoint() ); + + // If there's a signal pointer, emit the signal + if( fSignalPtr != nullptr ) + { + (*fSignalPtr)(); + } + return; + } + +} /* namespace Nymph */ + +#endif /* NYMPH_KTNYMPHSLOT_HH_ */ diff --git a/Library/Processor/KTSignal.hh b/Library/Processor/KTSignal.hh index f4dc7e8..8f0d23c 100644 --- a/Library/Processor/KTSignal.hh +++ b/Library/Processor/KTSignal.hh @@ -8,16 +8,54 @@ #ifndef KTSIGNAL_HH_ #define KTSIGNAL_HH_ -#include "KTProcessor.hh" +#include "KTSignalSlotBase.hh" -#include "KTCoreData.hh" +#include "KTConnection.hh" -#include - -#include +#include namespace Nymph { + /// A m_signal object may call multiple slots with the + /// same signature. You can connect functions to the m_signal + /// which will be called when the emit() method on the + /// m_signal object is invoked. Any argument passed to emit() + /// will be passed to the given functions. + /// The name "m_signal" was chosen to avoid conflicting with std::signal. + template< typename... XArgs > + class KTSignal : public KTSignalBase + { + public: + using signature = void( XArgs... ); + using boost_signal = boost::signals2::signal< signature >; + + public: + template< typename XOwner > + KTSignal( const std::string& name, XOwner* owner ); + KTSignal( const KTSignal& ) = delete; + KTSignal( KTSignal&& ) = delete; + virtual ~KTSignal(); + + virtual void Connect( KTSlotBase* slot ); + + // disconnects a previously connected function + void Disconnect( KTSlotBase* slot ) const; + + // disconnects all previously connected functions + void DisconnectAll() const; + + // calls all connected functions + void Emit( XArgs... args ); + void operator()( XArgs... args ); + + private: + typedef std::map< KTSlotBase*, KTConnection > slot_map; // to get around the problem of having a comma inside a macro function argument + MEMBERVARIABLE_REF_MUTABLE_CONST( slot_map, Slots ); + + boost_signal fSignal; + }; + + /*! @class KTSignal @author N. S. Oblath @@ -34,7 +72,7 @@ namespace Nymph Initialize the signal with the processor's 'this' pointer and the name of the signal. To use the signal, call it as: fSignalObject(arg); - */ + *//* template< class... XSignalArguments > class KTSignal { @@ -63,39 +101,87 @@ namespace Nymph std::string fName; }; +*/ - /// Convenience typedef for done signals - typedef KTSignal<> KTSignalDone; - // Convenience typedef for backwards compatibility - template< typename XDataType > - using KTSignalOneArg = KTSignal< XDataType >; + //******************* + // Implementations + //******************* - /*! - @class KTSignalData - @author N. S. Oblath + template< typename... XArgs > + template< typename XOwner > + KTSignal< XArgs... >::KTSignal< XOwner >( const std::string& name, XOwner* owner ) : + fSlots() + { + owner->RegisterSignal( name, this ); + } - @brief Creates a signal that takes a KTDataHandle object as its argument. + template< typename... XArgs > + KTSignal< XArgs... >::~KTSignal() + { + DisconnectAll(); + } - @details - The purpose of the signal is for passing KTCoreData pointers between Processors. - The signal is emitted by calling operator(). - If a KTDataSlot is being used, and the Slot has been given a pointer to this signal, the Slot will emit the Signal. + template< typename... XArgs > + void KTSignal< XArgs... >::Connect( KTSlotBase* slot ) + { + // ensure that the slot is of the correct type + m_slot< x_args... >* derived_slot = dynamic_cast< m_slot< x_args... >* >( p_slot ); + if( p_slot == nullptr ) + { + throw error() << "signal/slot signature mismatch: signal=" << f_name << "; slot=" << p_slot->name(); + } - Usage: - In your Processor's header add a member variable of type KTSignalData. + // make the connection + int connection_id = connect_function( derived_slot->function() ); - Initialize the signal with the processor's 'this' pointer and the name of the signal. + // inform the slot of the signal connection so that it can disconnect + derived_slot->connections().insert( std::pair< int, m_signal< x_args... >* >( connection_id, this ) ); - That's it! - */ - typedef KTSignal< KTDataHandle > KTSignalData; + return connection_id; + } - //******************* - // Implementations - //******************* + // disconnects a previously connected function + template< typename... XArgs > + void KTSignal< XArgs... >::Disconnect( KTSlotBase* slot ) const + { + auto connectionIt = fSlots.find( slot ); + if( connectionIt != fSlots.end() ) + { + connectionIt->second.disconnect(); + connectionIt->first->RemoveConnection( this ); + } + return; + } + // disconnects all previously connected functions + template< typename... XArgs > + void KTSignal< XArgs... >::DisconnectAll() const + { + for( auto connection : fSlots ) + { + connection.second.disconnect(); + connection.first->RemoveConnection( this ); + } + return; + } + + // calls all connected functions + template< typename... XArgs > + void KTSignal< XArgs... >::Emit( XArgs... args ) + { + (*this)( args ); + return; + } + + template< typename... XArgs > + void KTSignal< XArgs... >::operator()( XArgs... args ) + { + fSignal( args ); + } + +/* template< class... XSignalArguments > KTSignal< XSignalArguments... >::KTSignal( const std::string& name, KTProcessor* proc ) : fSignal(), @@ -138,6 +224,6 @@ namespace Nymph { return fName; } - +*/ } /* namespace Nymph */ #endif /* KTSIGNAL_HH_ */ diff --git a/Library/Processor/KTSignalSlotBase.hh b/Library/Processor/KTSignalSlotBase.hh new file mode 100644 index 0000000..1e06d3d --- /dev/null +++ b/Library/Processor/KTSignalSlotBase.hh @@ -0,0 +1,52 @@ +/* + * KTSignalSlotBase.hh + * + * Created on: Feb 25, 2019 + * Author: N.S. Oblath + */ + +#ifndef NYMPH_KTSIGNALSLOTBASE_HH_ +#define NYMPH_KTSIGNALSLOTBASE_HH_ + +#include "KTMemberVariable.hh" + +#include + +namespace Nymph +{ + class KTSignalBase; + + class KTSlotBase + { + public: + KTSlotBase( const std::string& name ); + template< typename XOwner > + KTSlotBase( const std::string& name, XOwner* owner ); + virtual ~KTSlotBase(); + + void AddConnection( KTSignalBase* ) const = 0; + + void RemoveConnection( KTSignalBase* ) const = 0; + + MEMBERVARIABLE_REF( std::string, name ); + }; + + + class KTSignalBase + { + public: + KTSignalBase( const std::string& name ); + template< typename x_owner > + KTSignalBase( const std::string& name, x_owner* owner ); + virtual ~KTSignalBase(); + + virtual void Connect( KTSlotBase* slot ) = 0; + + virtual void Disconnect( KTSlotBase* slot ) = 0; + + MEMBERVARIABLE_REF( std::string, name ); + }; + +} /* namespace Nymph */ + +#endif /* NYMPH_KTSIGNALSLOTBASE_HH_ */ diff --git a/Library/Processor/KTSlot.hh b/Library/Processor/KTSlot.hh index 7f374a9..6a68d08 100644 --- a/Library/Processor/KTSlot.hh +++ b/Library/Processor/KTSlot.hh @@ -8,17 +8,56 @@ #ifndef KTSLOT_HH_ #define KTSLOT_HH_ -#include "KTException.hh" +#include "KTSignalSlotBase.hh" + +//#include "KTException.hh" #include "KTLogger.hh" -#include "KTSignal.hh" -#include -#include +#include +#include namespace Nymph { KTLOGGER(slotlog, "KTSlot"); + + // Type XOwner is the class that owns the KTSlot object + template< typename... XArgs > + class KTSlot : public KTSlotBase + { + public: + using signature = void( XArgs... ); + using signal_list = std::initializer_list< std::string >; + + public: + template< typename XOwner > + KTSlot( const std::string& name, XOwner* owner, void (XOwner::*func)( XArgs... ), signal_list signals = {} ); + template< typename XOwner > + KTSlot( const std::string& name, XOwner* owner, void (XOwner::*func)( XArgs... ) const, signal_list signals = {} ); + template< typename XOwner > + KTSlot( const std::string& name, XOwner* owner, const boost::function< signature >& func, signal_list signals = {} ); + template< typename XOwner, typename XFuncClass > + KTSlot( const std::string& name, XOwner* owner, XFuncClass *inst, void (XFuncClass::*func)( XArgs... ), signal_list signals = {} ); + template< typename XOwner, typename XFuncClass > + KTSlot( const std::string& name, XOwner* owner, XFuncClass *inst, void (XFuncClass::*func)( XArgs... ) const, signal_list signals = {} ); + KTSlot( const KTSlot& ) = delete; + KTSlot( KTSlot&& ) = delete; + virtual ~KTSlot(); + + void DisconnectAll() const; + + void AddConnection( KTSignalBase* ) const; + + void RemoveConnection( KTSignalBase* ) const; + + MEMBERVARIABLE_REF( boost::function< signature >, Function ); + + typedef std::set< KTSignalBase* > signal_connections; // to get around the problem of having a comma inside a macro function argument + MEMBERVARIABLE_REF_MUTABLE( signal_connections, Connections ); + + }; + + /*! @class KTSlot @author N. S. Oblath @@ -35,7 +74,7 @@ namespace Nymph Initialize the slot with the name of the slot, the address of the owner of the slot function, and the function pointer. Optionally, if the Processor is separate from the owner of the slot function, the Processor address is specified as the second argument to the constructor. - */ + *//* template< typename... Args > class KTSlot { @@ -58,146 +97,7 @@ namespace Nymph std::string fName; KTSlotWrapper* fSlotWrapper; }; - - // Typedefs for backwards compatibility - - typedef KTSlot<> KTSlotNoArg; - - template < typename Arg1 > - using KTSlotOneArg = KTSlot< Arg1 >; - - template< typename Arg1, typename Arg2 > - using KTSlotTwoArg = KTSlot< Arg1, Arg2 >; - - - /*! - @class KTSlotData - @author N. S. Oblath - - @brief Creates a slot that takes a KTDataHandle object as the argument; the function that gets called should take 0 or more DataType&'s as its argument. - - @details - Usage: - This slot type adds the slot function (signature void (KTDataHandle). - Your processor (or, optionally, a different object) must have a member function with the signature bool (DataType1&, . . .). - The slot function checks that the provided KTCoreData object contains data of type DataType, and then calls the member function. - - In your Processor's header add a member variable of type KTSlotOneArg< DataType >. - The variable may be private. - - Initialize the slot with the name of the slot, the address of the owner of the slot function, and the function pointer. - Optionally, if the Processor is separate from the owner of the slot function, the Processor address is specified as the second argument to the constructor. - - Also optionally, a signal to be emitted after the return of the member function can be specified as the last argument. - */ - template< class XReturnType, class... XDataArgs > - class KTSlotData : public KTSlot< KTDataHandle > - { - public: - /// Constructor for the case where the processor has the function that will be called by the slot - template< class XFuncOwnerType, class... XFuncDataTypes > - KTSlotData( const std::string& name, XFuncOwnerType* owner, void (XFuncOwnerType::*func)( const XFuncDataTypes&..., XReturnType& ), KTSignalData* signalPtr ); - - /// Constructor for the case where the processor has the function that will be called by the slot - template< class XFuncOwnerType, class... XFuncDataTypes > - KTSlotData( const std::string& name, XFuncOwnerType* owner, void (XFuncOwnerType::*func)( const XFuncDataTypes&..., XReturnType& ) ); - - /// Constructor for the case where the processor and the object with the function that will be called are different - template< class XFuncOwnerType, class... XFuncDataTypes > - KTSlotData( const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, void (XFuncOwnerType::*func)( const XFuncDataTypes&..., XReturnType& ), KTSignalData* signalPtr ); - - /// Constructor for the case where the processor and the object with the function that will be called are different - template< class XFuncOwnerType, class... XFuncDataTypes > - KTSlotData( const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, void (XFuncOwnerType::*func)( const XFuncDataTypes&..., XReturnType& ) ); - - virtual ~KTSlotData(); - - void operator()( KTDataHandle data ); - - protected: - template< typename... DataTypes > - bool DataPresent( KTDataHandle data ); - - //function_signature fFunc; - std::function< XReturnType (const XDataArgs&..., XReturnType&) > fFunc; - - KTSignalData* fSignalPtr; - }; - - // partial specialization for no new data type - template< class... XDataArgs > - class KTSlotData< void, XDataArgs... > : public KTSlot< KTDataHandle > - { - public: - /// Constructor for the case where the processor has the function that will be called by the slot - template< class XFuncOwnerType, class... XFuncDataTypes > - KTSlotData( const std::string& name, XFuncOwnerType* owner, void (XFuncOwnerType::*func)( const XFuncDataTypes&... ), KTSignalData* signalPtr ); - - /// Constructor for the case where the processor has the function that will be called by the slot - template< class XFuncOwnerType, class... XFuncDataTypes > - KTSlotData( const std::string& name, XFuncOwnerType* owner, void (XFuncOwnerType::*func)( const XFuncDataTypes&... ) ); - - /// Constructor for the case where the processor and the object with the function that will be called are different - template< class XFuncOwnerType, class... XFuncDataTypes > - KTSlotData( const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, void (XFuncOwnerType::*func)( const XFuncDataTypes&... ), KTSignalData* signalPtr ); - - /// Constructor for the case where the processor and the object with the function that will be called are different - template< class XFuncOwnerType, class... XFuncDataTypes > - KTSlotData( const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, void (XFuncOwnerType::*func)( const XFuncDataTypes&... ) ); - - virtual ~KTSlotData(); - - void operator()( KTDataHandle data ); - - protected: - template< typename... DataTypes > - bool DataPresent( KTDataHandle data ); - - //function_signature fFunc; - std::function< void (const XDataArgs&...) > fFunc; - - KTSignalData* fSignalPtr; - }; - - - /*! - @class KTSlotDone - @author N. S. Oblath - - @brief Creates a slot to receive indication that upstream processing is complete and will emit a similar signal. - - @details - Usage: - This slot type adds the slot function (signature void ()). - Your processor (or, optionally, a different object) must have a member function with the signature void (). - The slot calls the member function. - - In your Processor's header add a member variable of type KTDoneSlot. - The variable may be private. - - Initialize the slot with the name of the slot, the address of the owner of the slot function, and the function pointer. - Optionally, if the Processor is separate from the owner of the slot function, the Processor address is specified as the second argument to the constructor. - - Also optionally, a signal to be emitted after the return of the member function can be specified as the last argument. - */ - class KTSlotDone : public KTSlot<> - { - public: - /// Constructor for the case where the processor has the function that will be called by the slot - template< class XFuncOwnerType > - KTSlotDone( const std::string& name, XFuncOwnerType* owner, void (XFuncOwnerType::*func)(), KTSignalDone* signalPtr=nullptr ); - /// Constructor for the case where the processor and the object with the function that will be called are different - template< class XFuncOwnerType > - KTSlotDone( const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, void (XFuncOwnerType::*func)(), KTSignalDone* signalPtr=nullptr ); - virtual ~KTSlotDone(); - - void operator()(); - - protected: - std::function< void () > fFunc; - - KTSignalDone* fSignalPtr; - }; +*/ //******************* @@ -206,255 +106,114 @@ namespace Nymph // KTSlot - template< typename... Args > - template< class XFuncOwnerType > - KTSlot< Args... >::KTSlot( const std::string& name, XFuncOwnerType* owner, void (XFuncOwnerType::*func)( Args... ), std::initializer_list< std::string > signals ): - fName( name ) - { - fSlotWrapper = owner->RegisterSlot( name, owner, func, signals ); - } - - template< typename... Args > - template< class XFuncOwnerType > - KTSlot< Args... >::KTSlot( const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, void (XFuncOwnerType::*func)( Args... ), std::initializer_list< std::string > signals ) : - fName( name ) - { - fSlotWrapper = proc->RegisterSlot( name, owner, func, signals ); - } - - template< typename... Args > - KTSlot< Args... >::~KTSlot() - { - } - - template< typename... Args > - inline const std::string& KTSlot< Args... >::GetName() const - { - return fName; - } - - template< typename... Args > - inline KTSlotWrapper* KTSlot< Args... >::GetSlotWrapper() + template< typename... XArgs > + template< typename XOwner > + KTSlot< XArgs... >::KTSlot< XOwner >( const std::string& name, XOwner* owner, void (XOwner::*func)( XArgs... ), signal_list signals ) : + fFunction( [func, owner]( XArgs... args ){ return (owner->*func)(args...);} ), + fConnections() { - return fSlotWrapper; + owner->RegisterSlot( name, this, signals ); } - // KTSlotData - - template< class XReturnType, class... XDataTypes > - template< class XFuncOwnerType, class... XFuncDataTypes > - KTSlotData< XReturnType, XDataTypes... >::KTSlotData(const std::string& name, XFuncOwnerType* owner, void (XFuncOwnerType::*func)( const XFuncDataTypes&..., XReturnType& ), KTSignalData* signalPtr) : - KTSlot( name, owner, this, &KTSlotData::operator(), {signalPtr->GetName()} ), - fFunc( [func, owner]( const XDataTypes&... args ){ return (owner->*func)(args...);} ), - fSignalPtr( signalPtr ) + template< typename... XArgs > + template< typename XOwner > + KTSlot< XArgs... >::KTSlot< XOwner >( const std::string& name, XOwner* owner, void (XOwner::*func)( XArgs... ) const, signal_list signals ) : + fFunction( [func, owner]( XArgs... args ){ return (owner->*func)(args...);} ), + fConnections() { + owner->RegisterSlot( name, this, signals ); } - template< class XReturnType, class... XDataTypes > - template< class XFuncOwnerType, class... XFuncDataTypes > - KTSlotData< XReturnType, XDataTypes... >::KTSlotData(const std::string& name, XFuncOwnerType* owner, void (XFuncOwnerType::*func)( const XFuncDataTypes&..., XReturnType& )) : - KTSlot( name, owner, this, &KTSlotData::operator() ), - fFunc( [func, owner]( const XDataTypes&... args ){ return (owner->*func)(args...);} ), - fSignalPtr( nullptr ) + template< typename... XArgs > + template< typename XOwner > + KTSlot< XArgs... >::KTSlot< XOwner >( const std::string& name, XOwner* owner, const boost::function< signature >& func, signal_list signals ) : + fFunction( func ), + fConnections() { + owner->RegisterSlot( name, this, signals ); } - template< class XReturnType, class... XDataTypes > - template< class XFuncOwnerType, class... XFuncDataTypes > - KTSlotData< XReturnType, XDataTypes... >::KTSlotData(const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, void (XFuncOwnerType::*func)( const XFuncDataTypes&..., XReturnType& ), KTSignalData* signalPtr) : - KTSlot( name, proc, this, &KTSlotData::operator(), { signalPtr->GetName()} ), - fFunc( [func, owner]( const XDataTypes&... args ){return (owner->*func) (args... );} ), - fSignalPtr( signalPtr ) + template< typename... XArgs > + template< typename XOwner, typename XFuncClass > + KTSlot< XArgs... >::KTSlot< XOwner, XFuncClass >( const std::string& name, XOwner* owner, XFuncClass *inst, void (XFuncClass::*func)( XArgs... ), signal_list signals ) : + fFunction( [func, inst]( XArgs... args ){ return (inst->*func)(args...);} ), + fConnections() { + owner->RegisterSlot( name, this, signals ); } - template< class XReturnType, class... XDataTypes > - template< class XFuncOwnerType, class... XFuncDataTypes > - KTSlotData< XReturnType, XDataTypes... >::KTSlotData(const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, void (XFuncOwnerType::*func)( const XFuncDataTypes&..., XReturnType& )) : - KTSlot( name, proc, this, &KTSlotData::operator() ), - fFunc( [func, owner]( const XDataTypes&... args ){return (owner->*func) (args... );} ), - fSignalPtr( nullptr ) + template< typename... XArgs > + template< typename XOwner, typename XFuncClass > + KTSlot< XArgs... >::KTSlot< XOwner, XFuncClass >( const std::string& name, XOwner* owner, XFuncClass *inst, void (XFuncClass::*func)( XArgs... ) const, signal_list signals ) : + fFunction( [func, inst]( XArgs... args ){ return (inst->*func)(args...);} ), + fConnections() { + owner->RegisterSlot( name, this, signals ); } - template< class XReturnType, class... XDataTypes > - KTSlotData< XReturnType, XDataTypes... >::~KTSlotData() + template< typename... XArgs > + KTSlot< XArgs... >::~KTSlot() { + DisconnectAll(); } - template< class XReturnType, class... XDataTypes > - void KTSlotData< XReturnType, XDataTypes... >::operator()( KTDataHandle dataHandle ) + template< typename... XArgs > + void KTSlot< XArgs... >::DisconnectAll() const { - // Standard data slot pattern: - - std::shared_ptr< KTThreadReference > ref = fSlotWrapper->GetThreadRef(); - - // Check to ensure that the required data type is present - if( ! DataPresent< XDataTypes... >( dataHandle ) ) - { - KTERROR( slotlog, "Failed to find all of the necessary data types in slot <" << fName << ">. Aborting." ); - THROW_THREADREF_EXCEPTION( ref, KTException() << "Failed to find all of the necessary data types in slot <" << fName << ">. Aborting." ); - return; - } - - // Call the function - try - { - fFunc( dataHandle->Of< XDataTypes >()... , dataHandle->Of< XReturnType >() ); - } - catch( boost::exception& e ) - { - e << KTErrorMsgInfo< struct slotData_RunFunc >( "Something went wrong in slot <" + fName + ">. Aborting." ); - ref->SetReturnException( boost::current_exception() ); - } - - // Perform breakpoint here if necessary (either if initiated here or if stopping here due to a breakpoint elsewhere) - // Sets the dataHandle into the return - ref->Break( dataHandle, fSlotWrapper->GetDoBreakpoint() ); - - // If there's a signal pointer, emit the signal - if( fSignalPtr != nullptr ) + for( auto connection : fConnections ) { - (*fSignalPtr)( dataHandle ); + connection->Disconnect( this ); } return; } - template< class XReturnType, class... XDataTypes > - template< typename... DataTypes > - bool KTSlotData< XReturnType, XDataTypes... >::DataPresent( KTDataHandle data ) - { - return DataPresentHelper< DataTypes... >::DataPresent( data ); - } - - - // KTSlotData with no return type - - template< class... XDataTypes > - template< class XFuncOwnerType, class... XFuncDataTypes > - KTSlotData< void, XDataTypes... >::KTSlotData(const std::string& name, XFuncOwnerType* owner, void (XFuncOwnerType::*func)( const XFuncDataTypes&... ), KTSignalData* signalPtr) : - KTSlot( name, owner, this, &KTSlotData::operator(), {signalPtr->GetName()} ), - fFunc( [func, owner]( const XDataTypes&... args ){ return (owner->*func)(args...);} ), - fSignalPtr( signalPtr ) - { - } - - template< class... XDataTypes > - template< class XFuncOwnerType, class... XFuncDataTypes > - KTSlotData< void, XDataTypes... >::KTSlotData(const std::string& name, XFuncOwnerType* owner, void (XFuncOwnerType::*func)( const XFuncDataTypes&... )) : - KTSlot( name, owner, this, &KTSlotData::operator() ), - fFunc( [func, owner]( const XDataTypes&... args ){ return (owner->*func)(args...);} ), - fSignalPtr( nullptr ) - { - } - - template< class... XDataTypes > - template< class XFuncOwnerType, class... XFuncDataTypes > - KTSlotData< void, XDataTypes... >::KTSlotData(const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, void (XFuncOwnerType::*func)( const XFuncDataTypes&... ), KTSignalData* signalPtr) : - KTSlot( name, proc, this, &KTSlotData::operator(), { signalPtr->GetName()} ), - fFunc( [func, owner]( const XDataTypes&... args ){return (owner->*func) (args... );} ), - fSignalPtr( signalPtr ) - { - } - - template< class... XDataTypes > - template< class XFuncOwnerType, class... XFuncDataTypes > - KTSlotData< void, XDataTypes... >::KTSlotData(const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, void (XFuncOwnerType::*func)( const XFuncDataTypes&... )) : - KTSlot( name, proc, this, &KTSlotData::operator() ), - fFunc( [func, owner]( const XDataTypes&... args ){return (owner->*func) (args... );} ), - fSignalPtr( nullptr ) - { - } - - template< class... XDataTypes > - KTSlotData< void, XDataTypes... >::~KTSlotData() + template< typename... XArgs > + void KTSlot< XArgs... >::AddConnection( KTSignalBase* signal ) const { + fConnections.insert( signal ); + return; } - template< class... XDataTypes > - void KTSlotData< void, XDataTypes... >::operator()( KTDataHandle dataHandle ) + template< typename... XArgs > + void KTSlot< XArgs... >::RemoveConnection( KTSignalBase* signal ) const { - // Standard data slot pattern: - - std::shared_ptr< KTThreadReference > ref = fSlotWrapper->GetThreadRef(); - - // Check to ensure that the required data type is present - if( ! DataPresent< XDataTypes... >( dataHandle ) ) - { - KTERROR( slotlog, "Failed to find all of the necessary data types in slot <" << fName << ">. Aborting." ); - THROW_THREADREF_EXCEPTION( ref, KTException() << "Failed to find all of the necessary data types in slot <" << fName << ">. Aborting." ); - return; - } - - // Call the function - try - { - fFunc( dataHandle->Of< XDataTypes >()... ); - } - catch( boost::exception& e ) - { - e << KTErrorMsgInfo< struct slotData_RunFunc >( "Something went wrong in slot <" + fName + ">. Aborting." ); - ref->SetReturnException( boost::current_exception() ); - } - - // Perform breakpoint here if necessary (either if initiated here or if stopping here due to a breakpoint elsewhere) - // Sets the dataHandle into the return - ref->Break( dataHandle, fSlotWrapper->GetDoBreakpoint() ); - - // If there's a signal pointer, emit the signal - if( fSignalPtr != nullptr ) - { - (*fSignalPtr)( dataHandle ); - } + fConnections.erase( signal ); return; } - template< class... XDataTypes > - template< typename... DataTypes > - bool KTSlotData< void, XDataTypes... >::DataPresent( KTDataHandle data ) +/* + template< typename... Args > + template< class XFuncOwnerType > + KTSlot< Args... >::KTSlot( const std::string& name, XFuncOwnerType* owner, void (XFuncOwnerType::*func)( Args... ), std::initializer_list< std::string > signals ): + fName( name ) { - return DataPresentHelper< DataTypes... >::DataPresent( data ); + fSlotWrapper = owner->RegisterSlot( name, owner, func, signals ); } - - // KTSlotDone - + template< typename... Args > template< class XFuncOwnerType > - KTSlotDone::KTSlotDone(const std::string& name, XFuncOwnerType* owner, void (XFuncOwnerType::*func)(), KTSignalDone* signalPtr) : - KTSlot( name, owner, this, &KTSlotDone::operator(), {signalPtr->GetName()} ), - fFunc( [func, owner](){ return (owner->*func)(); } ), - fSignalPtr( signalPtr ) + KTSlot< Args... >::KTSlot( const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, void (XFuncOwnerType::*func)( Args... ), std::initializer_list< std::string > signals ) : + fName( name ) { + fSlotWrapper = proc->RegisterSlot( name, owner, func, signals ); } - template< class XFuncOwnerType > - KTSlotDone::KTSlotDone(const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, void (XFuncOwnerType::*func)(), KTSignalDone* signalPtr) : - KTSlot( name, proc, this, &KTSlotDone::operator(), {signalPtr->GetName()} ), - fFunc( [func, owner](){ return (owner->*func)(); } ), - fSignalPtr( signalPtr ) + template< typename... Args > + KTSlot< Args... >::~KTSlot() { } - inline KTSlotDone::~KTSlotDone() + template< typename... Args > + inline const std::string& KTSlot< Args... >::GetName() const { + return fName; } - inline void KTSlotDone::operator()() + template< typename... Args > + inline KTSlotWrapper* KTSlot< Args... >::GetSlotWrapper() { - // Call the function - fFunc(); - - // Perform breakpoint here if necessary (either if initiated here or if stopping here due to a breakpoint elsewhere) - // Sets the dataHandle into the return - fSlotWrapper->GetThreadRef()->Break( KTDataHandle(), fSlotWrapper->GetDoBreakpoint() ); - - // If there's a signal pointer, emit the signal - if( fSignalPtr != nullptr ) - { - (*fSignalPtr)(); - } - return; + return fSlotWrapper; } - +*/ } /* namespace Nymph */ #endif /* KTSLOT_HH_ */ From a43a2e6e29ee43b7cedf8e638fdbdad7c3534581 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Mon, 25 Feb 2019 13:39:20 -0800 Subject: [PATCH 129/521] Basic components of the new signal/slot setup are in place, but untested. --- Library/Processor/KTSignal.hh | 47 +++++++++++++++++++-------- Library/Processor/KTSignalSlotBase.hh | 4 +-- 2 files changed, 36 insertions(+), 15 deletions(-) diff --git a/Library/Processor/KTSignal.hh b/Library/Processor/KTSignal.hh index 8f0d23c..c3a8f8b 100644 --- a/Library/Processor/KTSignal.hh +++ b/Library/Processor/KTSignal.hh @@ -11,11 +11,18 @@ #include "KTSignalSlotBase.hh" #include "KTConnection.hh" +#include "KTException.hh" +#include "KTLogger.hh" #include namespace Nymph { + KTLOGGER( signallog, "KTSignal" ); + + struct KTConnectionException : public KTException + {}; + /// A m_signal object may call multiple slots with the /// same signature. You can connect functions to the m_signal /// which will be called when the emit() method on the @@ -36,7 +43,7 @@ namespace Nymph KTSignal( KTSignal&& ) = delete; virtual ~KTSignal(); - virtual void Connect( KTSlotBase* slot ); + virtual void Connect( KTSlotBase* slot, int group ); // disconnects a previously connected function void Disconnect( KTSlotBase* slot ) const; @@ -52,7 +59,7 @@ namespace Nymph typedef std::map< KTSlotBase*, KTConnection > slot_map; // to get around the problem of having a comma inside a macro function argument MEMBERVARIABLE_REF_MUTABLE_CONST( slot_map, Slots ); - boost_signal fSignal; + boost_signal fInternalSignal; }; @@ -111,7 +118,8 @@ namespace Nymph template< typename... XArgs > template< typename XOwner > KTSignal< XArgs... >::KTSignal< XOwner >( const std::string& name, XOwner* owner ) : - fSlots() + fSlots(), + fInternalSignal() { owner->RegisterSignal( name, this ); } @@ -123,23 +131,36 @@ namespace Nymph } template< typename... XArgs > - void KTSignal< XArgs... >::Connect( KTSlotBase* slot ) + void KTSignal< XArgs... >::Connect( KTSlotBase* slot, int group ) { - // ensure that the slot is of the correct type - m_slot< x_args... >* derived_slot = dynamic_cast< m_slot< x_args... >* >( p_slot ); - if( p_slot == nullptr ) + if( fSlots.count( slot ) != 0 ) { - throw error() << "signal/slot signature mismatch: signal=" << f_name << "; slot=" << p_slot->name(); + KTWARN( signallog, "Signal <" << fName << "> is already connected to slot <" << slot->Name() << ">" ); + return; } - // make the connection - int connection_id = connect_function( derived_slot->function() ); + // ensure that the slot is of the correct type + KTSlot< XArgs... >* derivedSlot = dynamic_cast< KTSlot< XArgs... >* >( slot ); + if( slot == nullptr ) + { + BOOST_THROW_EXCEPTION( KTConnectionException() << "Trying to connect signal <" << fName << "> to slot <" << slot->Name() << ">, but cannot make the connection:\n" << + "\tUnable to cast from KTSlotBase to this signal's derived type." << eom ); + } - // inform the slot of the signal connection so that it can disconnect - derived_slot->connections().insert( std::pair< int, m_signal< x_args... >* >( connection_id, this ) ); + KTConnection connection; + if( group >= 0 ) + { + connection = fInternalSignal.connect( group, derivedSlot->Function() ); + } + else + { + connection = fInternalSignal.connect( derivedSlot->Function() ); + } - return connection_id; + fSlots.insert( std::make_pair< KTSlotBase*, KTConnection >( slot, connection ) ); + slot->AddConnection( this ); + return; } // disconnects a previously connected function diff --git a/Library/Processor/KTSignalSlotBase.hh b/Library/Processor/KTSignalSlotBase.hh index 1e06d3d..6031fd7 100644 --- a/Library/Processor/KTSignalSlotBase.hh +++ b/Library/Processor/KTSignalSlotBase.hh @@ -28,7 +28,7 @@ namespace Nymph void RemoveConnection( KTSignalBase* ) const = 0; - MEMBERVARIABLE_REF( std::string, name ); + MEMBERVARIABLE_REF( std::string, Name ); }; @@ -44,7 +44,7 @@ namespace Nymph virtual void Disconnect( KTSlotBase* slot ) = 0; - MEMBERVARIABLE_REF( std::string, name ); + MEMBERVARIABLE_REF( std::string, Name ); }; } /* namespace Nymph */ From efc6bfd05b8697c580b95bdfd318455c9d9c0b88 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Sat, 13 Jul 2019 22:17:57 -0700 Subject: [PATCH 130/521] More progress --- Library/Processor/KTNymphSlot.hh | 41 ++++++++++++----- Library/Processor/KTProcessor.cc | 19 ++++---- Library/Processor/KTProcessor.hh | 41 ++++++----------- Library/Processor/KTSignalSlotBase.hh | 4 +- Library/Processor/KTSlot.hh | 35 ++++++++++---- Library/Processor/KTThreadReference.hh | 63 ++++++++++++++++++-------- 6 files changed, 124 insertions(+), 79 deletions(-) diff --git a/Library/Processor/KTNymphSlot.hh b/Library/Processor/KTNymphSlot.hh index 5e65969..a584b3c 100644 --- a/Library/Processor/KTNymphSlot.hh +++ b/Library/Processor/KTNymphSlot.hh @@ -10,7 +10,9 @@ #include "KTSlot.hh" - +#include "KTException.hh" +#include "KTNymphSignals.hh" +#include "KTProcessor.hh" namespace Nymph { @@ -25,6 +27,21 @@ namespace Nymph using KTSlotTwoArg = KTSlot< Arg1, Arg2 >; + template + struct foo {}; + + template < typename... Types1, template class T + , typename... Types2, template class V + , typename U > + void + bar(const T&, const V&, const U& u) + { + std::cout << sizeof...(Types1) << std::endl; + std::cout << sizeof...(Types2) << std::endl; + std::cout << u << std::endl; + } + + /*! @class KTSlotData @author N. S. Oblath @@ -164,7 +181,7 @@ namespace Nymph template< class XReturnType, class... XDataTypes > template< class XFuncOwnerType, class... XFuncDataTypes > KTSlotData< XReturnType, XDataTypes... >::KTSlotData(const std::string& name, XFuncOwnerType* owner, void (XFuncOwnerType::*func)( const XFuncDataTypes&..., XReturnType& ), KTSignalData* signalPtr) : - KTSlot( name, owner, this, &KTSlotData::operator(), {signalPtr->GetName()} ), + KTSlot( name, owner, this, &KTSlotData::operator(), {signalPtr->Name()} ), fFunc( [func, owner]( const XDataTypes&... args ){ return (owner->*func)(args...);} ), fSignalPtr( signalPtr ) { @@ -182,7 +199,7 @@ namespace Nymph template< class XReturnType, class... XDataTypes > template< class XFuncOwnerType, class... XFuncDataTypes > KTSlotData< XReturnType, XDataTypes... >::KTSlotData(const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, void (XFuncOwnerType::*func)( const XFuncDataTypes&..., XReturnType& ), KTSignalData* signalPtr) : - KTSlot( name, proc, this, &KTSlotData::operator(), { signalPtr->GetName()} ), + KTSlot( name, proc, this, &KTSlotData::operator(), { signalPtr->Name()} ), fFunc( [func, owner]( const XDataTypes&... args ){return (owner->*func) (args... );} ), fSignalPtr( signalPtr ) { @@ -207,7 +224,7 @@ namespace Nymph { // Standard data slot pattern: - std::shared_ptr< KTThreadReference > ref = fSlotWrapper->GetThreadRef(); + std::shared_ptr< KTThreadReference > ref = fThreadRef; // Check to ensure that the required data type is present if( ! DataPresent< XDataTypes... >( dataHandle ) ) @@ -230,7 +247,7 @@ namespace Nymph // Perform breakpoint here if necessary (either if initiated here or if stopping here due to a breakpoint elsewhere) // Sets the dataHandle into the return - ref->Break( dataHandle, fSlotWrapper->GetDoBreakpoint() ); + ref->Break( dataHandle, fDoBreakpoint ); // If there's a signal pointer, emit the signal if( fSignalPtr != nullptr ) @@ -253,7 +270,7 @@ namespace Nymph template< class... XDataTypes > template< class XFuncOwnerType, class... XFuncDataTypes > KTSlotData< void, XDataTypes... >::KTSlotData(const std::string& name, XFuncOwnerType* owner, void (XFuncOwnerType::*func)( const XFuncDataTypes&... ), KTSignalData* signalPtr) : - KTSlot( name, owner, this, &KTSlotData::operator(), {signalPtr->GetName()} ), + KTSlot( name, owner, this, &KTSlotData::operator(), {signalPtr->Name()} ), fFunc( [func, owner]( const XDataTypes&... args ){ return (owner->*func)(args...);} ), fSignalPtr( signalPtr ) { @@ -271,7 +288,7 @@ namespace Nymph template< class... XDataTypes > template< class XFuncOwnerType, class... XFuncDataTypes > KTSlotData< void, XDataTypes... >::KTSlotData(const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, void (XFuncOwnerType::*func)( const XFuncDataTypes&... ), KTSignalData* signalPtr) : - KTSlot( name, proc, this, &KTSlotData::operator(), { signalPtr->GetName()} ), + KTSlot( name, proc, this, &KTSlotData::operator(), { signalPtr->Name()} ), fFunc( [func, owner]( const XDataTypes&... args ){return (owner->*func) (args... );} ), fSignalPtr( signalPtr ) { @@ -296,7 +313,7 @@ namespace Nymph { // Standard data slot pattern: - std::shared_ptr< KTThreadReference > ref = fSlotWrapper->GetThreadRef(); + std::shared_ptr< KTThreadReference > ref = fThreadRef; // Check to ensure that the required data type is present if( ! DataPresent< XDataTypes... >( dataHandle ) ) @@ -319,7 +336,7 @@ namespace Nymph // Perform breakpoint here if necessary (either if initiated here or if stopping here due to a breakpoint elsewhere) // Sets the dataHandle into the return - ref->Break( dataHandle, fSlotWrapper->GetDoBreakpoint() ); + ref->Break( dataHandle, fDoBreakpoint ); // If there's a signal pointer, emit the signal if( fSignalPtr != nullptr ) @@ -341,7 +358,7 @@ namespace Nymph template< class XFuncOwnerType > KTSlotDone::KTSlotDone(const std::string& name, XFuncOwnerType* owner, void (XFuncOwnerType::*func)(), KTSignalDone* signalPtr) : - KTSlot( name, owner, this, &KTSlotDone::operator(), {signalPtr->GetName()} ), + KTSlot( name, owner, this, &KTSlotDone::operator(), {signalPtr->Name()} ), fFunc( [func, owner](){ return (owner->*func)(); } ), fSignalPtr( signalPtr ) { @@ -349,7 +366,7 @@ namespace Nymph template< class XFuncOwnerType > KTSlotDone::KTSlotDone(const std::string& name, KTProcessor* proc, XFuncOwnerType* owner, void (XFuncOwnerType::*func)(), KTSignalDone* signalPtr) : - KTSlot( name, proc, this, &KTSlotDone::operator(), {signalPtr->GetName()} ), + KTSlot( name, proc, this, &KTSlotDone::operator(), {signalPtr->Name()} ), fFunc( [func, owner](){ return (owner->*func)(); } ), fSignalPtr( signalPtr ) { @@ -366,7 +383,7 @@ namespace Nymph // Perform breakpoint here if necessary (either if initiated here or if stopping here due to a breakpoint elsewhere) // Sets the dataHandle into the return - fSlotWrapper->GetThreadRef()->Break( KTDataHandle(), fSlotWrapper->GetDoBreakpoint() ); + fThreadRef->Break( KTDataHandle(), fDoBreakpoint ); // If there's a signal pointer, emit the signal if( fSignalPtr != nullptr ) diff --git a/Library/Processor/KTProcessor.cc b/Library/Processor/KTProcessor.cc index 0ba0806..c28cfa9 100644 --- a/Library/Processor/KTProcessor.cc +++ b/Library/Processor/KTProcessor.cc @@ -31,7 +31,6 @@ namespace Nymph { for (SlotMapIt iter = fSlotMap.begin(); iter != fSlotMap.end(); iter++) { - iter->second->Disconnect(); delete iter->second; } for (SigMapIt iter = fSignalMap.begin(); iter != fSignalMap.end(); iter++) @@ -42,7 +41,7 @@ namespace Nymph void KTProcessor::PassThreadRefUpdate(const std::string& slotName, std::shared_ptr< KTThreadReference > threadRef) { - std::function< void(std::shared_ptr< KTThreadReference >) > funcObj = [this, &slotName](std::shared_ptr< KTThreadReference > ref){ GetSlot(slotName)->SetThreadRef(ref); }; + std::function< void(std::shared_ptr< KTThreadReference >) > funcObj = [this, &slotName](std::shared_ptr< KTThreadReference > ref){ GetSlot(slotName)->ThreadRef() = ref; }; PassToConnProcs(slotName, funcObj, threadRef); return; } @@ -50,8 +49,8 @@ namespace Nymph void KTProcessor::ConnectASlot(const std::string& signalName, KTProcessor* processor, const std::string& slotName, int groupNum) { // get the signal and slot wrapper pointers - KTSignalWrapper* signal = GetSignal(signalName); - KTSlotWrapper* slot = processor->GetSlot(slotName); + KTSignalBase* signal = GetSignal(signalName); + KTSlotBase* slot = processor->GetSlot(slotName); try { @@ -90,7 +89,7 @@ namespace Nymph return; } - void KTProcessor::ConnectSignalToSlot(KTSignalWrapper* signal, KTSlotWrapper* slot, int groupNum) + void KTProcessor::ConnectSignalToSlot(KTSignalBase* signal, KTSlotBase* slot, int groupNum) { if (signal == nullptr) { @@ -101,12 +100,12 @@ namespace Nymph BOOST_THROW_EXCEPTION( KTSlotException() << "Slot pointer was NULL" << eom ); } - slot->SetConnection(signal, groupNum); + signal->Connect(slot, groupNum); return; } - KTSignalWrapper* KTProcessor::GetSignal(const std::string& name) + KTSignalBase* KTProcessor::GetSignal(const std::string& name) { SigMapIt iter = fSignalMap.find(name); if (iter == fSignalMap.end()) @@ -116,7 +115,7 @@ namespace Nymph return iter->second; } - KTSlotWrapper* KTProcessor::GetSlot(const std::string& name) + KTSlotBase* KTProcessor::GetSlot(const std::string& name) { SlotMapIt iter = fSlotMap.find(name); if (iter == fSlotMap.end()) @@ -128,7 +127,7 @@ namespace Nymph bool KTProcessor::GetDoBreakpoint(const std::string& slotName) { - KTSlotWrapper* slot = GetSlot(slotName); + KTSlotBase* slot = GetSlot(slotName); if (slot != nullptr) { return slot->GetDoBreakpoint(); @@ -139,7 +138,7 @@ namespace Nymph void KTProcessor::SetDoBreakpoint(const std::string& slotName, bool flag) { - KTSlotWrapper* slot = GetSlot(slotName); + KTSlotBase* slot = GetSlot(slotName); if (slot != nullptr) { return slot->SetDoBreakpoint(flag); diff --git a/Library/Processor/KTProcessor.hh b/Library/Processor/KTProcessor.hh index c2e143a..2575131 100644 --- a/Library/Processor/KTProcessor.hh +++ b/Library/Processor/KTProcessor.hh @@ -11,20 +11,15 @@ #include "KTConfigurable.hh" -#include "KTConnection.hh" #include "KTLogger.hh" -#include "KTSignalWrapper.hh" -#include "KTSlotWrapper.hh" +#include "KTNymphSlot.hh" #include "factory.hh" -#include - #include #include #include #include -#include #include namespace Nymph @@ -42,11 +37,11 @@ namespace Nymph class KTProcessor : public KTConfigurable { protected: - typedef std::map< std::string, KTSignalWrapper* > SignalMap; + typedef std::map< std::string, KTSignalBase* > SignalMap; typedef SignalMap::iterator SigMapIt; typedef SignalMap::value_type SigMapVal; - typedef std::map< std::string, KTSlotWrapper* > SlotMap; + typedef std::map< std::string, KTSlotBase* > SlotMap; typedef SlotMap::iterator SlotMapIt; typedef SlotMap::value_type SlotMapVal; @@ -71,20 +66,18 @@ namespace Nymph /// For a slot that is called, update the slot's ThreadRef, and pass the update to any slots that get called by signals emitted by this slot void PassThreadRefUpdate(const std::string& slotName, std::shared_ptr< KTThreadReference > threadRef); - static void ConnectSignalToSlot(KTSignalWrapper* signal, KTSlotWrapper* slot, int groupNum=-1); + static void ConnectSignalToSlot(KTSignalBase* signal, KTSlotBase* slot, int groupNum=-1); void ConnectASlot(const std::string& signalName, KTProcessor* processor, const std::string& slotName, int groupNum=-1); void ConnectASignal(KTProcessor* processor, const std::string& signalName, const std::string& slotName, int groupNum=-1); - template< class XProcessor > - KTSignalWrapper* RegisterSignal(std::string name, XProcessor* signalPtr); + void RegisterSignal(std::string name, KTSignalBase* signal); - template< class XTarget, typename XReturn, typename... XArgs > - KTSlotWrapper* RegisterSlot(std::string name, XTarget* target, XReturn (XTarget::* funcPtr)(XArgs...), std::initializer_list< std::string > signals = {}); + void RegisterSlot(std::string name, KTSlotBase* slot, std::initializer_list< std::string > signals = {}); - KTSignalWrapper* GetSignal(const std::string& name); + KTSignalBase* GetSignal(const std::string& name); - KTSlotWrapper* GetSlot(const std::string& name); + KTSlotBase* GetSlot(const std::string& name); bool GetDoBreakpoint(const std::string& slotName); void SetDoBreakpoint(const std::string& slotName, bool flag); @@ -105,31 +98,25 @@ namespace Nymph }; - template< typename XSignalSig > - KTSignalWrapper* KTProcessor::RegisterSignal(std::string name, XSignalSig* signalPtr) + void KTProcessor::RegisterSignal(std::string name, KTSignalBase* signal) { KTDEBUG(processorlog, "Registering signal <" << name << "> in processor <" << fConfigName << ">"); - KTSignalWrapper* sig = new KTSignalWrapper(signalPtr); - fSignalMap.insert(SigMapVal(name, sig)); - return sig; + fSignalMap.insert(SigMapVal(name, signal)); + return; } - template< class XTarget, typename XReturn, typename... XArgs > - KTSlotWrapper* KTProcessor::RegisterSlot(std::string name, XTarget* target, XReturn (XTarget::* funcPtr)(XArgs...), std::initializer_list< std::string > signals) + void KTProcessor::RegisterSlot(std::string name, KTSlotBase* slot, std::initializer_list< std::string > signals) { KTDEBUG(processorlog, "Registering slot <" << name << "> in processor <" << fConfigName << ">"); - KTSignalConcept< XReturn (XArgs...) > signalConcept; - - KTSlotWrapper* slot = new KTSlotWrapper([funcPtr, target](XArgs... args){return (target->*funcPtr)(args...);}, &signalConcept); fSlotMap.insert(SlotMapVal(name, slot)); - for (std::initializer_list< std::string >::const_iterator sigIt = signals.begin(); sigIt != signals.end(); ++sigIt) + for (auto sigIt = signals.begin(); sigIt != signals.end(); ++sigIt) { fSlotToSigMap.insert(SlotToSigMapVal(name, *sigIt)); KTDEBUG(processorlog, "Slot-to-signal connection <" << name << "> --> <" << *sigIt << ">"); } - return slot; + return; } inline void KTProcessor::ConnectASignal(KTProcessor* processor, const std::string& signalName, const std::string& slotName, int groupNum) diff --git a/Library/Processor/KTSignalSlotBase.hh b/Library/Processor/KTSignalSlotBase.hh index 6031fd7..f775c93 100644 --- a/Library/Processor/KTSignalSlotBase.hh +++ b/Library/Processor/KTSignalSlotBase.hh @@ -40,9 +40,9 @@ namespace Nymph KTSignalBase( const std::string& name, x_owner* owner ); virtual ~KTSignalBase(); - virtual void Connect( KTSlotBase* slot ) = 0; + virtual void Connect( KTSlotBase* slot, int group ) = 0; - virtual void Disconnect( KTSlotBase* slot ) = 0; + virtual void Disconnect( KTSlotBase* slot ) const = 0; MEMBERVARIABLE_REF( std::string, Name ); }; diff --git a/Library/Processor/KTSlot.hh b/Library/Processor/KTSlot.hh index 6a68d08..0729eb0 100644 --- a/Library/Processor/KTSlot.hh +++ b/Library/Processor/KTSlot.hh @@ -12,6 +12,7 @@ //#include "KTException.hh" #include "KTLogger.hh" +#include "KTThreadReference.hh" #include #include @@ -55,6 +56,12 @@ namespace Nymph typedef std::set< KTSignalBase* > signal_connections; // to get around the problem of having a comma inside a macro function argument MEMBERVARIABLE_REF_MUTABLE( signal_connections, Connections ); + // TODO: move fDoBreakpoint to KTSlot + // TODO: KTThreadReference should be a templated object, KTThreadReference< XArgs... > + // TODO: KTThreadReference< XArgs... > inherits from KTThreadReferenceBase + MEMBERVARIABLE( bool, DoBreakpoint ); + MEMBERVARIABLE_SHARED_PTR_CONST( KTThreadReference, ThreadRef ); + }; @@ -110,7 +117,9 @@ namespace Nymph template< typename XOwner > KTSlot< XArgs... >::KTSlot< XOwner >( const std::string& name, XOwner* owner, void (XOwner::*func)( XArgs... ), signal_list signals ) : fFunction( [func, owner]( XArgs... args ){ return (owner->*func)(args...);} ), - fConnections() + fConnections(), + fThreadRef( std::make_shared< KTThreadReference >() ), + fDoBreakpoint(false) { owner->RegisterSlot( name, this, signals ); } @@ -118,8 +127,10 @@ namespace Nymph template< typename... XArgs > template< typename XOwner > KTSlot< XArgs... >::KTSlot< XOwner >( const std::string& name, XOwner* owner, void (XOwner::*func)( XArgs... ) const, signal_list signals ) : - fFunction( [func, owner]( XArgs... args ){ return (owner->*func)(args...);} ), - fConnections() + fFunction( [func, owner]( XArgs... args ){ return (owner->*func)(args...);} ), + fConnections(), + fThreadRef( std::make_shared< KTThreadReference >() ), + fDoBreakpoint(false) { owner->RegisterSlot( name, this, signals ); } @@ -127,8 +138,10 @@ namespace Nymph template< typename... XArgs > template< typename XOwner > KTSlot< XArgs... >::KTSlot< XOwner >( const std::string& name, XOwner* owner, const boost::function< signature >& func, signal_list signals ) : - fFunction( func ), - fConnections() + fFunction( func ), + fConnections(), + fThreadRef( std::make_shared< KTThreadReference >() ), + fDoBreakpoint(false) { owner->RegisterSlot( name, this, signals ); } @@ -136,8 +149,10 @@ namespace Nymph template< typename... XArgs > template< typename XOwner, typename XFuncClass > KTSlot< XArgs... >::KTSlot< XOwner, XFuncClass >( const std::string& name, XOwner* owner, XFuncClass *inst, void (XFuncClass::*func)( XArgs... ), signal_list signals ) : - fFunction( [func, inst]( XArgs... args ){ return (inst->*func)(args...);} ), - fConnections() + fFunction( [func, inst]( XArgs... args ){ return (inst->*func)(args...);} ), + fConnections(), + fThreadRef( std::make_shared< KTThreadReference >() ), + fDoBreakpoint(false) { owner->RegisterSlot( name, this, signals ); } @@ -145,8 +160,10 @@ namespace Nymph template< typename... XArgs > template< typename XOwner, typename XFuncClass > KTSlot< XArgs... >::KTSlot< XOwner, XFuncClass >( const std::string& name, XOwner* owner, XFuncClass *inst, void (XFuncClass::*func)( XArgs... ) const, signal_list signals ) : - fFunction( [func, inst]( XArgs... args ){ return (inst->*func)(args...);} ), - fConnections() + fFunction( [func, inst]( XArgs... args ){ return (inst->*func)(args...);} ), + fConnections(), + fThreadRef( std::make_shared< KTThreadReference >() ), + fDoBreakpoint(false) { owner->RegisterSlot( name, this, signals ); } diff --git a/Library/Processor/KTThreadReference.hh b/Library/Processor/KTThreadReference.hh index 05f6cca..e6d88fe 100644 --- a/Library/Processor/KTThreadReference.hh +++ b/Library/Processor/KTThreadReference.hh @@ -18,11 +18,51 @@ namespace Nymph { typedef boost::promise< KTDataHandle > KTDataPtrReturn; - class KTThreadReference + class KTThreadReferenceBase { - private: + protected: typedef boost::unique_lock< boost::mutex > boost_unique_lock; + public: + KTThreadReferenceBase(); + KTThreadReferenceBase( const KTThreadReferenceBase& ) = delete; + KTThreadReferenceBase( KTThreadReferenceBase&& orig ); + + KTThreadReferenceBase& operator=( const KTThreadReferenceBase& ) = delete; + KTThreadReferenceBase& operator=( KTThreadReferenceBase&& ); + + public: + //************************** + // for use within the thread + //************************** + + void SetReturnException( boost::exception_ptr excPtr ); + + public: + //****************************** + // for use outside of the thread + //****************************** + + void SetInitiateBreakFunc( const std::function< void() >& initBreakFunc ); + void SetWaitForContinueFunc( const std::function< void( boost_unique_lock& ) >& waitForContFunc ); + + public: + MEMBERVARIABLE_REF( std::string, Name ); + MEMBERVARIABLE( bool, BreakFlag ); + MEMBERVARIABLE( bool, Canceled ); + MEMBERVARIABLE_REF( boost::mutex, Mutex ); + + private: + std::function< void() > fInitiateBreakFunc; + std::function< void( boost_unique_lock& ) > fWaitForContinueFunc; + }; + + template< typename... XArgs > + class KTThreadReference : public KTThreadReferenceBase + { + private: + typedef KTThreadReferenceBase::boost_unique_lock boost_unique_lock; + public: KTThreadReference(); KTThreadReference( const KTThreadReference& ) = delete; @@ -36,10 +76,9 @@ namespace Nymph // for use within the thread //************************** - void Break( const KTDataHandle& dataHandle, bool doBreakpoint ); + void Break( bool doBreakpoint, const XArgs&... dataHandle ); - void SetReturnException( boost::exception_ptr excPtr ); - void SetReturnValue( KTDataHandle dataHandle ); + void SetReturnValue( XArgs... dataHandle ); public: //****************************** @@ -52,23 +91,9 @@ namespace Nymph void RefreshDataPtrRet(); - void SetInitiateBreakFunc( const std::function< void() >& initBreakFunc ); - void SetWaitForContinueFunc( const std::function< void( boost_unique_lock& ) >& waitForContFunc ); - - boost::mutex& Mutex(); - const boost::mutex& Mutex() const; - - public: - MEMBERVARIABLE_REF( std::string, Name ); - MEMBERVARIABLE( bool, BreakFlag ); - MEMBERVARIABLE( bool, Canceled ); - private: KTDataPtrReturn fDataPtrRet; boost::unique_future< KTDataHandle > fDataPtrRetFuture; - std::function< void() > fInitiateBreakFunc; - std::function< void( boost_unique_lock& ) > fWaitForContinueFunc; - boost::mutex fMutex; }; inline void KTThreadReference::SetReturnException( boost::exception_ptr excPtr ) From d28a01ac9ec3c5e0eafc6dfe053af22df1840153 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Mon, 26 Aug 2019 09:47:54 -0700 Subject: [PATCH 131/521] Initial use of catch2 --- CMakeLists.txt | 14 + Testing/CMakeLists.txt | 38 + Testing/Catch/catch.hpp | 13359 ++++++++++++++++++++++++++++++++++++++ Testing/README.md | 36 + Testing/TestExt.cc | 88 + Testing/UseCatch.cc | 10 + 6 files changed, 13545 insertions(+) create mode 100644 Testing/CMakeLists.txt create mode 100644 Testing/Catch/catch.hpp create mode 100644 Testing/README.md create mode 100644 Testing/TestExt.cc create mode 100644 Testing/UseCatch.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index 4010fd4..03dee56 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -124,4 +124,18 @@ if (Nymph_ENABLE_EXECUTABLES) add_subdirectory( Executables/Validation ) endif (Nymph_ENABLE_EXECUTABLES) + +######### +# Tests # +######### + +if( Nymph_ENABLE_TESTING ) + add_subdirectory( Testing ) +endif() + + +#################################### +# Variables for the parent project # +#################################### + pbuilder_variables_for_parent() diff --git a/Testing/CMakeLists.txt b/Testing/CMakeLists.txt new file mode 100644 index 0000000..1daaf14 --- /dev/null +++ b/Testing/CMakeLists.txt @@ -0,0 +1,38 @@ +# CMakeLists.txt for Nymph/Testing +# Author: N.S. Oblath +# Created: Aug 23, 2019 + +########## + +set( testing_HEADERS +) + +set( testing_SOURCES + TestExt.cc + UseCatch.cc +) + +set( lib_dependencies + Nymph + Catch +) + +# Interface library was recommended for Catch: +# https://stackoverflow.com/questions/34896891/catch-lib-unit-testing-and-ctest-cmake-integration/34900012#34900012 +add_library( Catch INTERFACE ) +target_include_directories( Catch INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/Catch ) + +add_executable( RunTests ${testing_SOURCES} ) +target_link_libraries( RunTests ${lib_dependencies} ) + +# So far it seems sufficient to use Catch2's ability to run tests, and not CTest. +# Here are two ways it could potentially be integrated with CTest, if we change our minds. + +# Normal CMake Integration +#enable_testing() +#add_test(NAME test_test COMMAND run_tests ) + +# Automated CMake Integration +#include(CTest) +#include(Catch) +#catch_discover_tests(foo) diff --git a/Testing/Catch/catch.hpp b/Testing/Catch/catch.hpp new file mode 100644 index 0000000..bdc2f74 --- /dev/null +++ b/Testing/Catch/catch.hpp @@ -0,0 +1,13359 @@ +/* + * Catch v2.3.0 + * Generated: 2018-07-23 10:09:14.936841 + * ---------------------------------------------------------- + * This file has been merged from multiple headers. Please don't edit it directly + * Copyright (c) 2018 Two Blue Cubes Ltd. All rights reserved. + * + * Distributed under the Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + */ +#ifndef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED +#define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED +// start catch.hpp + + +#define CATCH_VERSION_MAJOR 2 +#define CATCH_VERSION_MINOR 3 +#define CATCH_VERSION_PATCH 0 + +#ifdef __clang__ +# pragma clang system_header +#elif defined __GNUC__ +# pragma GCC system_header +#endif + +// start catch_suppress_warnings.h + +#ifdef __clang__ +# ifdef __ICC // icpc defines the __clang__ macro +# pragma warning(push) +# pragma warning(disable: 161 1682) +# else // __ICC +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wpadded" +# pragma clang diagnostic ignored "-Wswitch-enum" +# pragma clang diagnostic ignored "-Wcovered-switch-default" +# endif +#elif defined __GNUC__ + // GCC likes to warn on REQUIREs, and we cannot suppress them + // locally because g++'s support for _Pragma is lacking in older, + // still supported, versions +# pragma GCC diagnostic ignored "-Wparentheses" +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wunused-variable" +# pragma GCC diagnostic ignored "-Wpadded" +#endif +// end catch_suppress_warnings.h +#if defined(CATCH_CONFIG_MAIN) || defined(CATCH_CONFIG_RUNNER) +# define CATCH_IMPL +# define CATCH_CONFIG_ALL_PARTS +#endif + +// In the impl file, we want to have access to all parts of the headers +// Can also be used to sanely support PCHs +#if defined(CATCH_CONFIG_ALL_PARTS) +# define CATCH_CONFIG_EXTERNAL_INTERFACES +# if defined(CATCH_CONFIG_DISABLE_MATCHERS) +# undef CATCH_CONFIG_DISABLE_MATCHERS +# endif +# if !defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER) +# define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER +# endif +#endif + +#if !defined(CATCH_CONFIG_IMPL_ONLY) +// start catch_platform.h + +#ifdef __APPLE__ +# include +# if TARGET_OS_OSX == 1 +# define CATCH_PLATFORM_MAC +# elif TARGET_OS_IPHONE == 1 +# define CATCH_PLATFORM_IPHONE +# endif + +#elif defined(linux) || defined(__linux) || defined(__linux__) +# define CATCH_PLATFORM_LINUX + +#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) || defined(__MINGW32__) +# define CATCH_PLATFORM_WINDOWS +#endif + +// end catch_platform.h + +#ifdef CATCH_IMPL +# ifndef CLARA_CONFIG_MAIN +# define CLARA_CONFIG_MAIN_NOT_DEFINED +# define CLARA_CONFIG_MAIN +# endif +#endif + +// start catch_user_interfaces.h + +namespace Catch { + unsigned int rngSeed(); +} + +// end catch_user_interfaces.h +// start catch_tag_alias_autoregistrar.h + +// start catch_common.h + +// start catch_compiler_capabilities.h + +// Detect a number of compiler features - by compiler +// The following features are defined: +// +// CATCH_CONFIG_COUNTER : is the __COUNTER__ macro supported? +// CATCH_CONFIG_WINDOWS_SEH : is Windows SEH supported? +// CATCH_CONFIG_POSIX_SIGNALS : are POSIX signals supported? +// **************** +// Note to maintainers: if new toggles are added please document them +// in configuration.md, too +// **************** + +// In general each macro has a _NO_ form +// (e.g. CATCH_CONFIG_NO_POSIX_SIGNALS) which disables the feature. +// Many features, at point of detection, define an _INTERNAL_ macro, so they +// can be combined, en-mass, with the _NO_ forms later. + +#ifdef __cplusplus + +# if __cplusplus >= 201402L +# define CATCH_CPP14_OR_GREATER +# endif + +# if __cplusplus >= 201703L +# define CATCH_CPP17_OR_GREATER +# endif + +#endif + +#if defined(CATCH_CPP17_OR_GREATER) +# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS +#endif + +#ifdef __clang__ + +# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + _Pragma( "clang diagnostic push" ) \ + _Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" ) \ + _Pragma( "clang diagnostic ignored \"-Wglobal-constructors\"") +# define CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \ + _Pragma( "clang diagnostic pop" ) + +# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ + _Pragma( "clang diagnostic push" ) \ + _Pragma( "clang diagnostic ignored \"-Wparentheses\"" ) +# define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \ + _Pragma( "clang diagnostic pop" ) + +# define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \ + _Pragma( "clang diagnostic push" ) \ + _Pragma( "clang diagnostic ignored \"-Wunused-variable\"" ) +# define CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS \ + _Pragma( "clang diagnostic pop" ) + +#endif // __clang__ + +//////////////////////////////////////////////////////////////////////////////// +// Assume that non-Windows platforms support posix signals by default +#if !defined(CATCH_PLATFORM_WINDOWS) + #define CATCH_INTERNAL_CONFIG_POSIX_SIGNALS +#endif + +//////////////////////////////////////////////////////////////////////////////// +// We know some environments not to support full POSIX signals +#if defined(__CYGWIN__) || defined(__QNX__) || defined(__EMSCRIPTEN__) || defined(__DJGPP__) + #define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS +#endif + +#ifdef __OS400__ +# define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS +# define CATCH_CONFIG_COLOUR_NONE +#endif + +//////////////////////////////////////////////////////////////////////////////// +// Android somehow still does not support std::to_string +#if defined(__ANDROID__) +# define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING +#endif + +//////////////////////////////////////////////////////////////////////////////// +// Not all Windows environments support SEH properly +#if defined(__MINGW32__) +# define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH +#endif + +//////////////////////////////////////////////////////////////////////////////// +// PS4 +#if defined(__ORBIS__) +# define CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE +#endif + +//////////////////////////////////////////////////////////////////////////////// +// Cygwin +#ifdef __CYGWIN__ + +// Required for some versions of Cygwin to declare gettimeofday +// see: http://stackoverflow.com/questions/36901803/gettimeofday-not-declared-in-this-scope-cygwin +# define _BSD_SOURCE + +#endif // __CYGWIN__ + +//////////////////////////////////////////////////////////////////////////////// +// Visual C++ +#ifdef _MSC_VER + +# if _MSC_VER >= 1900 // Visual Studio 2015 or newer +# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS +# endif + +// Universal Windows platform does not support SEH +// Or console colours (or console at all...) +# if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) +# define CATCH_CONFIG_COLOUR_NONE +# else +# define CATCH_INTERNAL_CONFIG_WINDOWS_SEH +# endif + +#endif // _MSC_VER + +//////////////////////////////////////////////////////////////////////////////// + +// DJGPP +#ifdef __DJGPP__ +# define CATCH_INTERNAL_CONFIG_NO_WCHAR +#endif // __DJGPP__ + +//////////////////////////////////////////////////////////////////////////////// + +// Use of __COUNTER__ is suppressed during code analysis in +// CLion/AppCode 2017.2.x and former, because __COUNTER__ is not properly +// handled by it. +// Otherwise all supported compilers support COUNTER macro, +// but user still might want to turn it off +#if ( !defined(__JETBRAINS_IDE__) || __JETBRAINS_IDE__ >= 20170300L ) + #define CATCH_INTERNAL_CONFIG_COUNTER +#endif + +#if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER) +# define CATCH_CONFIG_COUNTER +#endif +#if defined(CATCH_INTERNAL_CONFIG_WINDOWS_SEH) && !defined(CATCH_CONFIG_NO_WINDOWS_SEH) && !defined(CATCH_CONFIG_WINDOWS_SEH) && !defined(CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH) +# define CATCH_CONFIG_WINDOWS_SEH +#endif +// This is set by default, because we assume that unix compilers are posix-signal-compatible by default. +#if defined(CATCH_INTERNAL_CONFIG_POSIX_SIGNALS) && !defined(CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_POSIX_SIGNALS) +# define CATCH_CONFIG_POSIX_SIGNALS +#endif +// This is set by default, because we assume that compilers with no wchar_t support are just rare exceptions. +#if !defined(CATCH_INTERNAL_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_WCHAR) +# define CATCH_CONFIG_WCHAR +#endif + +#if !defined(CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_CPP11_TO_STRING) +# define CATCH_CONFIG_CPP11_TO_STRING +#endif + +#if defined(CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_NO_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) +# define CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS +#endif + +#if defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT) +# define CATCH_INTERNAL_CONFIG_NEW_CAPTURE +#endif + +#if defined(CATCH_INTERNAL_CONFIG_NEW_CAPTURE) && !defined(CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE) && !defined(CATCH_CONFIG_NO_NEW_CAPTURE) && !defined(CATCH_CONFIG_NEW_CAPTURE) +# define CATCH_CONFIG_NEW_CAPTURE +#endif + +#if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS +# define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS +#endif +#if !defined(CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS +# define CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS +#endif +#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS +# define CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS +#endif + +// end catch_compiler_capabilities.h +#define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line +#define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) +#ifdef CATCH_CONFIG_COUNTER +# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __COUNTER__ ) +#else +# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ ) +#endif + +#include +#include +#include + +namespace Catch { + + struct CaseSensitive { enum Choice { + Yes, + No + }; }; + + class NonCopyable { + NonCopyable( NonCopyable const& ) = delete; + NonCopyable( NonCopyable && ) = delete; + NonCopyable& operator = ( NonCopyable const& ) = delete; + NonCopyable& operator = ( NonCopyable && ) = delete; + + protected: + NonCopyable(); + virtual ~NonCopyable(); + }; + + struct SourceLineInfo { + + SourceLineInfo() = delete; + SourceLineInfo( char const* _file, std::size_t _line ) noexcept + : file( _file ), + line( _line ) + {} + + SourceLineInfo( SourceLineInfo const& other ) = default; + SourceLineInfo( SourceLineInfo && ) = default; + SourceLineInfo& operator = ( SourceLineInfo const& ) = default; + SourceLineInfo& operator = ( SourceLineInfo && ) = default; + + bool empty() const noexcept; + bool operator == ( SourceLineInfo const& other ) const noexcept; + bool operator < ( SourceLineInfo const& other ) const noexcept; + + char const* file; + std::size_t line; + }; + + std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ); + + // Use this in variadic streaming macros to allow + // >> +StreamEndStop + // as well as + // >> stuff +StreamEndStop + struct StreamEndStop { + std::string operator+() const; + }; + template + T const& operator + ( T const& value, StreamEndStop ) { + return value; + } +} + +#define CATCH_INTERNAL_LINEINFO \ + ::Catch::SourceLineInfo( __FILE__, static_cast( __LINE__ ) ) + +// end catch_common.h +namespace Catch { + + struct RegistrarForTagAliases { + RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); + }; + +} // end namespace Catch + +#define CATCH_REGISTER_TAG_ALIAS( alias, spec ) \ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } \ + CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS + +// end catch_tag_alias_autoregistrar.h +// start catch_test_registry.h + +// start catch_interfaces_testcase.h + +#include +#include + +namespace Catch { + + class TestSpec; + + struct ITestInvoker { + virtual void invoke () const = 0; + virtual ~ITestInvoker(); + }; + + using ITestCasePtr = std::shared_ptr; + + class TestCase; + struct IConfig; + + struct ITestCaseRegistry { + virtual ~ITestCaseRegistry(); + virtual std::vector const& getAllTests() const = 0; + virtual std::vector const& getAllTestsSorted( IConfig const& config ) const = 0; + }; + + bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ); + std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ); + std::vector const& getAllTestCasesSorted( IConfig const& config ); + +} + +// end catch_interfaces_testcase.h +// start catch_stringref.h + +#include +#include +#include + +namespace Catch { + + class StringData; + + /// A non-owning string class (similar to the forthcoming std::string_view) + /// Note that, because a StringRef may be a substring of another string, + /// it may not be null terminated. c_str() must return a null terminated + /// string, however, and so the StringRef will internally take ownership + /// (taking a copy), if necessary. In theory this ownership is not externally + /// visible - but it does mean (substring) StringRefs should not be shared between + /// threads. + class StringRef { + public: + using size_type = std::size_t; + + private: + friend struct StringRefTestAccess; + + char const* m_start; + size_type m_size; + + char* m_data = nullptr; + + void takeOwnership(); + + static constexpr char const* const s_empty = ""; + + public: // construction/ assignment + StringRef() noexcept + : StringRef( s_empty, 0 ) + {} + + StringRef( StringRef const& other ) noexcept + : m_start( other.m_start ), + m_size( other.m_size ) + {} + + StringRef( StringRef&& other ) noexcept + : m_start( other.m_start ), + m_size( other.m_size ), + m_data( other.m_data ) + { + other.m_data = nullptr; + } + + StringRef( char const* rawChars ) noexcept; + + StringRef( char const* rawChars, size_type size ) noexcept + : m_start( rawChars ), + m_size( size ) + {} + + StringRef( std::string const& stdString ) noexcept + : m_start( stdString.c_str() ), + m_size( stdString.size() ) + {} + + ~StringRef() noexcept { + delete[] m_data; + } + + auto operator = ( StringRef const &other ) noexcept -> StringRef& { + delete[] m_data; + m_data = nullptr; + m_start = other.m_start; + m_size = other.m_size; + return *this; + } + + operator std::string() const; + + void swap( StringRef& other ) noexcept; + + public: // operators + auto operator == ( StringRef const& other ) const noexcept -> bool; + auto operator != ( StringRef const& other ) const noexcept -> bool; + + auto operator[] ( size_type index ) const noexcept -> char; + + public: // named queries + auto empty() const noexcept -> bool { + return m_size == 0; + } + auto size() const noexcept -> size_type { + return m_size; + } + + auto numberOfCharacters() const noexcept -> size_type; + auto c_str() const -> char const*; + + public: // substrings and searches + auto substr( size_type start, size_type size ) const noexcept -> StringRef; + + // Returns the current start pointer. + // Note that the pointer can change when if the StringRef is a substring + auto currentData() const noexcept -> char const*; + + private: // ownership queries - may not be consistent between calls + auto isOwned() const noexcept -> bool; + auto isSubstring() const noexcept -> bool; + }; + + auto operator + ( StringRef const& lhs, StringRef const& rhs ) -> std::string; + auto operator + ( StringRef const& lhs, char const* rhs ) -> std::string; + auto operator + ( char const* lhs, StringRef const& rhs ) -> std::string; + + auto operator += ( std::string& lhs, StringRef const& sr ) -> std::string&; + auto operator << ( std::ostream& os, StringRef const& sr ) -> std::ostream&; + + inline auto operator "" _sr( char const* rawChars, std::size_t size ) noexcept -> StringRef { + return StringRef( rawChars, size ); + } + +} // namespace Catch + +// end catch_stringref.h +namespace Catch { + +template +class TestInvokerAsMethod : public ITestInvoker { + void (C::*m_testAsMethod)(); +public: + TestInvokerAsMethod( void (C::*testAsMethod)() ) noexcept : m_testAsMethod( testAsMethod ) {} + + void invoke() const override { + C obj; + (obj.*m_testAsMethod)(); + } +}; + +auto makeTestInvoker( void(*testAsFunction)() ) noexcept -> ITestInvoker*; + +template +auto makeTestInvoker( void (C::*testAsMethod)() ) noexcept -> ITestInvoker* { + return new(std::nothrow) TestInvokerAsMethod( testAsMethod ); +} + +struct NameAndTags { + NameAndTags( StringRef const& name_ = StringRef(), StringRef const& tags_ = StringRef() ) noexcept; + StringRef name; + StringRef tags; +}; + +struct AutoReg : NonCopyable { + AutoReg( ITestInvoker* invoker, SourceLineInfo const& lineInfo, StringRef const& classOrMethod, NameAndTags const& nameAndTags ) noexcept; + ~AutoReg(); +}; + +} // end namespace Catch + +#define INTERNAL_CATCH_EXPAND1(param) INTERNAL_CATCH_EXPAND2(param) +#define INTERNAL_CATCH_EXPAND2(...) INTERNAL_CATCH_NO## __VA_ARGS__ +#define INTERNAL_CATCH_DEF(...) INTERNAL_CATCH_DEF __VA_ARGS__ +#define INTERNAL_CATCH_NOINTERNAL_CATCH_DEF + +#if defined(CATCH_CONFIG_DISABLE) + #define INTERNAL_CATCH_TESTCASE_NO_REGISTRATION( TestName, ... ) \ + static void TestName() + #define INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION( TestName, ClassName, ... ) \ + namespace{ \ + struct TestName : INTERNAL_CATCH_EXPAND1(INTERNAL_CATCH_DEF ClassName) { \ + void test(); \ + }; \ + } \ + void TestName::test() + +#endif + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_TESTCASE2( TestName, ... ) \ + static void TestName(); \ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &TestName ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ __VA_ARGS__ } ); } /* NOLINT */ \ + CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \ + static void TestName() + #define INTERNAL_CATCH_TESTCASE( ... ) \ + INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), __VA_ARGS__ ) + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &QualifiedMethod ), CATCH_INTERNAL_LINEINFO, "&" #QualifiedMethod, Catch::NameAndTags{ __VA_ARGS__ } ); } /* NOLINT */ \ + CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_TEST_CASE_METHOD2( TestName, ClassName, ... )\ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + namespace{ \ + struct TestName : INTERNAL_CATCH_EXPAND1(INTERNAL_CATCH_DEF ClassName) { \ + void test(); \ + }; \ + Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( Catch::makeTestInvoker( &TestName::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \ + } \ + CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \ + void TestName::test() + #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... ) \ + INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), ClassName, __VA_ARGS__ ) + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( Function ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \ + CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS + +// end catch_test_registry.h +// start catch_capture.hpp + +// start catch_assertionhandler.h + +// start catch_assertioninfo.h + +// start catch_result_type.h + +namespace Catch { + + // ResultWas::OfType enum + struct ResultWas { enum OfType { + Unknown = -1, + Ok = 0, + Info = 1, + Warning = 2, + + FailureBit = 0x10, + + ExpressionFailed = FailureBit | 1, + ExplicitFailure = FailureBit | 2, + + Exception = 0x100 | FailureBit, + + ThrewException = Exception | 1, + DidntThrowException = Exception | 2, + + FatalErrorCondition = 0x200 | FailureBit + + }; }; + + bool isOk( ResultWas::OfType resultType ); + bool isJustInfo( int flags ); + + // ResultDisposition::Flags enum + struct ResultDisposition { enum Flags { + Normal = 0x01, + + ContinueOnFailure = 0x02, // Failures fail test, but execution continues + FalseTest = 0x04, // Prefix expression with ! + SuppressFail = 0x08 // Failures are reported but do not fail the test + }; }; + + ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ); + + bool shouldContinueOnFailure( int flags ); + inline bool isFalseTest( int flags ) { return ( flags & ResultDisposition::FalseTest ) != 0; } + bool shouldSuppressFailure( int flags ); + +} // end namespace Catch + +// end catch_result_type.h +namespace Catch { + + struct AssertionInfo + { + StringRef macroName; + SourceLineInfo lineInfo; + StringRef capturedExpression; + ResultDisposition::Flags resultDisposition; + + // We want to delete this constructor but a compiler bug in 4.8 means + // the struct is then treated as non-aggregate + //AssertionInfo() = delete; + }; + +} // end namespace Catch + +// end catch_assertioninfo.h +// start catch_decomposer.h + +// start catch_tostring.h + +#include +#include +#include +#include +// start catch_stream.h + +#include +#include +#include + +namespace Catch { + + std::ostream& cout(); + std::ostream& cerr(); + std::ostream& clog(); + + class StringRef; + + struct IStream { + virtual ~IStream(); + virtual std::ostream& stream() const = 0; + }; + + auto makeStream( StringRef const &filename ) -> IStream const*; + + class ReusableStringStream { + std::size_t m_index; + std::ostream* m_oss; + public: + ReusableStringStream(); + ~ReusableStringStream(); + + auto str() const -> std::string; + + template + auto operator << ( T const& value ) -> ReusableStringStream& { + *m_oss << value; + return *this; + } + auto get() -> std::ostream& { return *m_oss; } + + static void cleanup(); + }; +} + +// end catch_stream.h + +#ifdef __OBJC__ +// start catch_objc_arc.hpp + +#import + +#ifdef __has_feature +#define CATCH_ARC_ENABLED __has_feature(objc_arc) +#else +#define CATCH_ARC_ENABLED 0 +#endif + +void arcSafeRelease( NSObject* obj ); +id performOptionalSelector( id obj, SEL sel ); + +#if !CATCH_ARC_ENABLED +inline void arcSafeRelease( NSObject* obj ) { + [obj release]; +} +inline id performOptionalSelector( id obj, SEL sel ) { + if( [obj respondsToSelector: sel] ) + return [obj performSelector: sel]; + return nil; +} +#define CATCH_UNSAFE_UNRETAINED +#define CATCH_ARC_STRONG +#else +inline void arcSafeRelease( NSObject* ){} +inline id performOptionalSelector( id obj, SEL sel ) { +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Warc-performSelector-leaks" +#endif + if( [obj respondsToSelector: sel] ) + return [obj performSelector: sel]; +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + return nil; +} +#define CATCH_UNSAFE_UNRETAINED __unsafe_unretained +#define CATCH_ARC_STRONG __strong +#endif + +// end catch_objc_arc.hpp +#endif + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4180) // We attempt to stream a function (address) by const&, which MSVC complains about but is harmless +#endif + +// We need a dummy global operator<< so we can bring it into Catch namespace later +struct Catch_global_namespace_dummy {}; +std::ostream& operator<<(std::ostream&, Catch_global_namespace_dummy); + +namespace Catch { + // Bring in operator<< from global namespace into Catch namespace + using ::operator<<; + + namespace Detail { + + extern const std::string unprintableString; + + std::string rawMemoryToString( const void *object, std::size_t size ); + + template + std::string rawMemoryToString( const T& object ) { + return rawMemoryToString( &object, sizeof(object) ); + } + + template + class IsStreamInsertable { + template + static auto test(int) + -> decltype(std::declval() << std::declval(), std::true_type()); + + template + static auto test(...)->std::false_type; + + public: + static const bool value = decltype(test(0))::value; + }; + + template + std::string convertUnknownEnumToString( E e ); + + template + typename std::enable_if< + !std::is_enum::value && !std::is_base_of::value, + std::string>::type convertUnstreamable( T const& ) { + return Detail::unprintableString; + } + template + typename std::enable_if< + !std::is_enum::value && std::is_base_of::value, + std::string>::type convertUnstreamable(T const& ex) { + return ex.what(); + } + + template + typename std::enable_if< + std::is_enum::value + , std::string>::type convertUnstreamable( T const& value ) { + return convertUnknownEnumToString( value ); + } + +#if defined(_MANAGED) + //! Convert a CLR string to a utf8 std::string + template + std::string clrReferenceToString( T^ ref ) { + if (ref == nullptr) + return std::string("null"); + auto bytes = System::Text::Encoding::UTF8->GetBytes(ref->ToString()); + cli::pin_ptr p = &bytes[0]; + return std::string(reinterpret_cast(p), bytes->Length); + } +#endif + + } // namespace Detail + + // If we decide for C++14, change these to enable_if_ts + template + struct StringMaker { + template + static + typename std::enable_if<::Catch::Detail::IsStreamInsertable::value, std::string>::type + convert(const Fake& value) { + ReusableStringStream rss; + // NB: call using the function-like syntax to avoid ambiguity with + // user-defined templated operator<< under clang. + rss.operator<<(value); + return rss.str(); + } + + template + static + typename std::enable_if::value, std::string>::type + convert( const Fake& value ) { +#if !defined(CATCH_CONFIG_FALLBACK_STRINGIFIER) + return Detail::convertUnstreamable(value); +#else + return CATCH_CONFIG_FALLBACK_STRINGIFIER(value); +#endif + } + }; + + namespace Detail { + + // This function dispatches all stringification requests inside of Catch. + // Should be preferably called fully qualified, like ::Catch::Detail::stringify + template + std::string stringify(const T& e) { + return ::Catch::StringMaker::type>::type>::convert(e); + } + + template + std::string convertUnknownEnumToString( E e ) { + return ::Catch::Detail::stringify(static_cast::type>(e)); + } + +#if defined(_MANAGED) + template + std::string stringify( T^ e ) { + return ::Catch::StringMaker::convert(e); + } +#endif + + } // namespace Detail + + // Some predefined specializations + + template<> + struct StringMaker { + static std::string convert(const std::string& str); + }; +#ifdef CATCH_CONFIG_WCHAR + template<> + struct StringMaker { + static std::string convert(const std::wstring& wstr); + }; +#endif + + template<> + struct StringMaker { + static std::string convert(char const * str); + }; + template<> + struct StringMaker { + static std::string convert(char * str); + }; + +#ifdef CATCH_CONFIG_WCHAR + template<> + struct StringMaker { + static std::string convert(wchar_t const * str); + }; + template<> + struct StringMaker { + static std::string convert(wchar_t * str); + }; +#endif + + // TBD: Should we use `strnlen` to ensure that we don't go out of the buffer, + // while keeping string semantics? + template + struct StringMaker { + static std::string convert(char const* str) { + return ::Catch::Detail::stringify(std::string{ str }); + } + }; + template + struct StringMaker { + static std::string convert(signed char const* str) { + return ::Catch::Detail::stringify(std::string{ reinterpret_cast(str) }); + } + }; + template + struct StringMaker { + static std::string convert(unsigned char const* str) { + return ::Catch::Detail::stringify(std::string{ reinterpret_cast(str) }); + } + }; + + template<> + struct StringMaker { + static std::string convert(int value); + }; + template<> + struct StringMaker { + static std::string convert(long value); + }; + template<> + struct StringMaker { + static std::string convert(long long value); + }; + template<> + struct StringMaker { + static std::string convert(unsigned int value); + }; + template<> + struct StringMaker { + static std::string convert(unsigned long value); + }; + template<> + struct StringMaker { + static std::string convert(unsigned long long value); + }; + + template<> + struct StringMaker { + static std::string convert(bool b); + }; + + template<> + struct StringMaker { + static std::string convert(char c); + }; + template<> + struct StringMaker { + static std::string convert(signed char c); + }; + template<> + struct StringMaker { + static std::string convert(unsigned char c); + }; + + template<> + struct StringMaker { + static std::string convert(std::nullptr_t); + }; + + template<> + struct StringMaker { + static std::string convert(float value); + }; + template<> + struct StringMaker { + static std::string convert(double value); + }; + + template + struct StringMaker { + template + static std::string convert(U* p) { + if (p) { + return ::Catch::Detail::rawMemoryToString(p); + } else { + return "nullptr"; + } + } + }; + + template + struct StringMaker { + static std::string convert(R C::* p) { + if (p) { + return ::Catch::Detail::rawMemoryToString(p); + } else { + return "nullptr"; + } + } + }; + +#if defined(_MANAGED) + template + struct StringMaker { + static std::string convert( T^ ref ) { + return ::Catch::Detail::clrReferenceToString(ref); + } + }; +#endif + + namespace Detail { + template + std::string rangeToString(InputIterator first, InputIterator last) { + ReusableStringStream rss; + rss << "{ "; + if (first != last) { + rss << ::Catch::Detail::stringify(*first); + for (++first; first != last; ++first) + rss << ", " << ::Catch::Detail::stringify(*first); + } + rss << " }"; + return rss.str(); + } + } + +#ifdef __OBJC__ + template<> + struct StringMaker { + static std::string convert(NSString * nsstring) { + if (!nsstring) + return "nil"; + return std::string("@") + [nsstring UTF8String]; + } + }; + template<> + struct StringMaker { + static std::string convert(NSObject* nsObject) { + return ::Catch::Detail::stringify([nsObject description]); + } + + }; + namespace Detail { + inline std::string stringify( NSString* nsstring ) { + return StringMaker::convert( nsstring ); + } + + } // namespace Detail +#endif // __OBJC__ + +} // namespace Catch + +////////////////////////////////////////////////////// +// Separate std-lib types stringification, so it can be selectively enabled +// This means that we do not bring in + +#if defined(CATCH_CONFIG_ENABLE_ALL_STRINGMAKERS) +# define CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER +# define CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER +# define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER +#endif + +// Separate std::pair specialization +#if defined(CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER) +#include +namespace Catch { + template + struct StringMaker > { + static std::string convert(const std::pair& pair) { + ReusableStringStream rss; + rss << "{ " + << ::Catch::Detail::stringify(pair.first) + << ", " + << ::Catch::Detail::stringify(pair.second) + << " }"; + return rss.str(); + } + }; +} +#endif // CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER + +// Separate std::tuple specialization +#if defined(CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER) +#include +namespace Catch { + namespace Detail { + template< + typename Tuple, + std::size_t N = 0, + bool = (N < std::tuple_size::value) + > + struct TupleElementPrinter { + static void print(const Tuple& tuple, std::ostream& os) { + os << (N ? ", " : " ") + << ::Catch::Detail::stringify(std::get(tuple)); + TupleElementPrinter::print(tuple, os); + } + }; + + template< + typename Tuple, + std::size_t N + > + struct TupleElementPrinter { + static void print(const Tuple&, std::ostream&) {} + }; + + } + + template + struct StringMaker> { + static std::string convert(const std::tuple& tuple) { + ReusableStringStream rss; + rss << '{'; + Detail::TupleElementPrinter>::print(tuple, rss.get()); + rss << " }"; + return rss.str(); + } + }; +} +#endif // CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER + +namespace Catch { + struct not_this_one {}; // Tag type for detecting which begin/ end are being selected + + // Import begin/ end from std here so they are considered alongside the fallback (...) overloads in this namespace + using std::begin; + using std::end; + + not_this_one begin( ... ); + not_this_one end( ... ); + + template + struct is_range { + static const bool value = + !std::is_same())), not_this_one>::value && + !std::is_same())), not_this_one>::value; + }; + +#if defined(_MANAGED) // Managed types are never ranges + template + struct is_range { + static const bool value = false; + }; +#endif + + template + std::string rangeToString( Range const& range ) { + return ::Catch::Detail::rangeToString( begin( range ), end( range ) ); + } + + // Handle vector specially + template + std::string rangeToString( std::vector const& v ) { + ReusableStringStream rss; + rss << "{ "; + bool first = true; + for( bool b : v ) { + if( first ) + first = false; + else + rss << ", "; + rss << ::Catch::Detail::stringify( b ); + } + rss << " }"; + return rss.str(); + } + + template + struct StringMaker::value && !::Catch::Detail::IsStreamInsertable::value>::type> { + static std::string convert( R const& range ) { + return rangeToString( range ); + } + }; + + template + struct StringMaker { + static std::string convert(T const(&arr)[SZ]) { + return rangeToString(arr); + } + }; + +} // namespace Catch + +// Separate std::chrono::duration specialization +#if defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER) +#include +#include +#include + +namespace Catch { + +template +struct ratio_string { + static std::string symbol(); +}; + +template +std::string ratio_string::symbol() { + Catch::ReusableStringStream rss; + rss << '[' << Ratio::num << '/' + << Ratio::den << ']'; + return rss.str(); +} +template <> +struct ratio_string { + static std::string symbol(); +}; +template <> +struct ratio_string { + static std::string symbol(); +}; +template <> +struct ratio_string { + static std::string symbol(); +}; +template <> +struct ratio_string { + static std::string symbol(); +}; +template <> +struct ratio_string { + static std::string symbol(); +}; +template <> +struct ratio_string { + static std::string symbol(); +}; + + //////////// + // std::chrono::duration specializations + template + struct StringMaker> { + static std::string convert(std::chrono::duration const& duration) { + ReusableStringStream rss; + rss << duration.count() << ' ' << ratio_string::symbol() << 's'; + return rss.str(); + } + }; + template + struct StringMaker>> { + static std::string convert(std::chrono::duration> const& duration) { + ReusableStringStream rss; + rss << duration.count() << " s"; + return rss.str(); + } + }; + template + struct StringMaker>> { + static std::string convert(std::chrono::duration> const& duration) { + ReusableStringStream rss; + rss << duration.count() << " m"; + return rss.str(); + } + }; + template + struct StringMaker>> { + static std::string convert(std::chrono::duration> const& duration) { + ReusableStringStream rss; + rss << duration.count() << " h"; + return rss.str(); + } + }; + + //////////// + // std::chrono::time_point specialization + // Generic time_point cannot be specialized, only std::chrono::time_point + template + struct StringMaker> { + static std::string convert(std::chrono::time_point const& time_point) { + return ::Catch::Detail::stringify(time_point.time_since_epoch()) + " since epoch"; + } + }; + // std::chrono::time_point specialization + template + struct StringMaker> { + static std::string convert(std::chrono::time_point const& time_point) { + auto converted = std::chrono::system_clock::to_time_t(time_point); + +#ifdef _MSC_VER + std::tm timeInfo = {}; + gmtime_s(&timeInfo, &converted); +#else + std::tm* timeInfo = std::gmtime(&converted); +#endif + + auto const timeStampSize = sizeof("2017-01-16T17:06:45Z"); + char timeStamp[timeStampSize]; + const char * const fmt = "%Y-%m-%dT%H:%M:%SZ"; + +#ifdef _MSC_VER + std::strftime(timeStamp, timeStampSize, fmt, &timeInfo); +#else + std::strftime(timeStamp, timeStampSize, fmt, timeInfo); +#endif + return std::string(timeStamp); + } + }; +} +#endif // CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +// end catch_tostring.h +#include + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4389) // '==' : signed/unsigned mismatch +#pragma warning(disable:4018) // more "signed/unsigned mismatch" +#pragma warning(disable:4312) // Converting int to T* using reinterpret_cast (issue on x64 platform) +#pragma warning(disable:4180) // qualifier applied to function type has no meaning +#endif + +namespace Catch { + + struct ITransientExpression { + auto isBinaryExpression() const -> bool { return m_isBinaryExpression; } + auto getResult() const -> bool { return m_result; } + virtual void streamReconstructedExpression( std::ostream &os ) const = 0; + + ITransientExpression( bool isBinaryExpression, bool result ) + : m_isBinaryExpression( isBinaryExpression ), + m_result( result ) + {} + + // We don't actually need a virtual destructor, but many static analysers + // complain if it's not here :-( + virtual ~ITransientExpression(); + + bool m_isBinaryExpression; + bool m_result; + + }; + + void formatReconstructedExpression( std::ostream &os, std::string const& lhs, StringRef op, std::string const& rhs ); + + template + class BinaryExpr : public ITransientExpression { + LhsT m_lhs; + StringRef m_op; + RhsT m_rhs; + + void streamReconstructedExpression( std::ostream &os ) const override { + formatReconstructedExpression + ( os, Catch::Detail::stringify( m_lhs ), m_op, Catch::Detail::stringify( m_rhs ) ); + } + + public: + BinaryExpr( bool comparisonResult, LhsT lhs, StringRef op, RhsT rhs ) + : ITransientExpression{ true, comparisonResult }, + m_lhs( lhs ), + m_op( op ), + m_rhs( rhs ) + {} + }; + + template + class UnaryExpr : public ITransientExpression { + LhsT m_lhs; + + void streamReconstructedExpression( std::ostream &os ) const override { + os << Catch::Detail::stringify( m_lhs ); + } + + public: + explicit UnaryExpr( LhsT lhs ) + : ITransientExpression{ false, lhs ? true : false }, + m_lhs( lhs ) + {} + }; + + // Specialised comparison functions to handle equality comparisons between ints and pointers (NULL deduces as an int) + template + auto compareEqual( LhsT const& lhs, RhsT const& rhs ) -> bool { return static_cast(lhs == rhs); } + template + auto compareEqual( T* const& lhs, int rhs ) -> bool { return lhs == reinterpret_cast( rhs ); } + template + auto compareEqual( T* const& lhs, long rhs ) -> bool { return lhs == reinterpret_cast( rhs ); } + template + auto compareEqual( int lhs, T* const& rhs ) -> bool { return reinterpret_cast( lhs ) == rhs; } + template + auto compareEqual( long lhs, T* const& rhs ) -> bool { return reinterpret_cast( lhs ) == rhs; } + + template + auto compareNotEqual( LhsT const& lhs, RhsT&& rhs ) -> bool { return static_cast(lhs != rhs); } + template + auto compareNotEqual( T* const& lhs, int rhs ) -> bool { return lhs != reinterpret_cast( rhs ); } + template + auto compareNotEqual( T* const& lhs, long rhs ) -> bool { return lhs != reinterpret_cast( rhs ); } + template + auto compareNotEqual( int lhs, T* const& rhs ) -> bool { return reinterpret_cast( lhs ) != rhs; } + template + auto compareNotEqual( long lhs, T* const& rhs ) -> bool { return reinterpret_cast( lhs ) != rhs; } + + template + class ExprLhs { + LhsT m_lhs; + public: + explicit ExprLhs( LhsT lhs ) : m_lhs( lhs ) {} + + template + auto operator == ( RhsT const& rhs ) -> BinaryExpr const { + return { compareEqual( m_lhs, rhs ), m_lhs, "==", rhs }; + } + auto operator == ( bool rhs ) -> BinaryExpr const { + return { m_lhs == rhs, m_lhs, "==", rhs }; + } + + template + auto operator != ( RhsT const& rhs ) -> BinaryExpr const { + return { compareNotEqual( m_lhs, rhs ), m_lhs, "!=", rhs }; + } + auto operator != ( bool rhs ) -> BinaryExpr const { + return { m_lhs != rhs, m_lhs, "!=", rhs }; + } + + template + auto operator > ( RhsT const& rhs ) -> BinaryExpr const { + return { static_cast(m_lhs > rhs), m_lhs, ">", rhs }; + } + template + auto operator < ( RhsT const& rhs ) -> BinaryExpr const { + return { static_cast(m_lhs < rhs), m_lhs, "<", rhs }; + } + template + auto operator >= ( RhsT const& rhs ) -> BinaryExpr const { + return { static_cast(m_lhs >= rhs), m_lhs, ">=", rhs }; + } + template + auto operator <= ( RhsT const& rhs ) -> BinaryExpr const { + return { static_cast(m_lhs <= rhs), m_lhs, "<=", rhs }; + } + + auto makeUnaryExpr() const -> UnaryExpr { + return UnaryExpr{ m_lhs }; + } + }; + + void handleExpression( ITransientExpression const& expr ); + + template + void handleExpression( ExprLhs const& expr ) { + handleExpression( expr.makeUnaryExpr() ); + } + + struct Decomposer { + template + auto operator <= ( T const& lhs ) -> ExprLhs { + return ExprLhs{ lhs }; + } + + auto operator <=( bool value ) -> ExprLhs { + return ExprLhs{ value }; + } + }; + +} // end namespace Catch + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +// end catch_decomposer.h +// start catch_interfaces_capture.h + +#include + +namespace Catch { + + class AssertionResult; + struct AssertionInfo; + struct SectionInfo; + struct SectionEndInfo; + struct MessageInfo; + struct Counts; + struct BenchmarkInfo; + struct BenchmarkStats; + struct AssertionReaction; + + struct ITransientExpression; + + struct IResultCapture { + + virtual ~IResultCapture(); + + virtual bool sectionStarted( SectionInfo const& sectionInfo, + Counts& assertions ) = 0; + virtual void sectionEnded( SectionEndInfo const& endInfo ) = 0; + virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) = 0; + + virtual void benchmarkStarting( BenchmarkInfo const& info ) = 0; + virtual void benchmarkEnded( BenchmarkStats const& stats ) = 0; + + virtual void pushScopedMessage( MessageInfo const& message ) = 0; + virtual void popScopedMessage( MessageInfo const& message ) = 0; + + virtual void handleFatalErrorCondition( StringRef message ) = 0; + + virtual void handleExpr + ( AssertionInfo const& info, + ITransientExpression const& expr, + AssertionReaction& reaction ) = 0; + virtual void handleMessage + ( AssertionInfo const& info, + ResultWas::OfType resultType, + StringRef const& message, + AssertionReaction& reaction ) = 0; + virtual void handleUnexpectedExceptionNotThrown + ( AssertionInfo const& info, + AssertionReaction& reaction ) = 0; + virtual void handleUnexpectedInflightException + ( AssertionInfo const& info, + std::string const& message, + AssertionReaction& reaction ) = 0; + virtual void handleIncomplete + ( AssertionInfo const& info ) = 0; + virtual void handleNonExpr + ( AssertionInfo const &info, + ResultWas::OfType resultType, + AssertionReaction &reaction ) = 0; + + virtual bool lastAssertionPassed() = 0; + virtual void assertionPassed() = 0; + + // Deprecated, do not use: + virtual std::string getCurrentTestName() const = 0; + virtual const AssertionResult* getLastResult() const = 0; + virtual void exceptionEarlyReported() = 0; + }; + + IResultCapture& getResultCapture(); +} + +// end catch_interfaces_capture.h +namespace Catch { + + struct TestFailureException{}; + struct AssertionResultData; + struct IResultCapture; + class RunContext; + + class LazyExpression { + friend class AssertionHandler; + friend struct AssertionStats; + friend class RunContext; + + ITransientExpression const* m_transientExpression = nullptr; + bool m_isNegated; + public: + LazyExpression( bool isNegated ); + LazyExpression( LazyExpression const& other ); + LazyExpression& operator = ( LazyExpression const& ) = delete; + + explicit operator bool() const; + + friend auto operator << ( std::ostream& os, LazyExpression const& lazyExpr ) -> std::ostream&; + }; + + struct AssertionReaction { + bool shouldDebugBreak = false; + bool shouldThrow = false; + }; + + class AssertionHandler { + AssertionInfo m_assertionInfo; + AssertionReaction m_reaction; + bool m_completed = false; + IResultCapture& m_resultCapture; + + public: + AssertionHandler + ( StringRef macroName, + SourceLineInfo const& lineInfo, + StringRef capturedExpression, + ResultDisposition::Flags resultDisposition ); + ~AssertionHandler() { + if ( !m_completed ) { + m_resultCapture.handleIncomplete( m_assertionInfo ); + } + } + + template + void handleExpr( ExprLhs const& expr ) { + handleExpr( expr.makeUnaryExpr() ); + } + void handleExpr( ITransientExpression const& expr ); + + void handleMessage(ResultWas::OfType resultType, StringRef const& message); + + void handleExceptionThrownAsExpected(); + void handleUnexpectedExceptionNotThrown(); + void handleExceptionNotThrownAsExpected(); + void handleThrowingCallSkipped(); + void handleUnexpectedInflightException(); + + void complete(); + void setCompleted(); + + // query + auto allowThrows() const -> bool; + }; + + void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef matcherString ); + +} // namespace Catch + +// end catch_assertionhandler.h +// start catch_message.h + +#include + +namespace Catch { + + struct MessageInfo { + MessageInfo( std::string const& _macroName, + SourceLineInfo const& _lineInfo, + ResultWas::OfType _type ); + + std::string macroName; + std::string message; + SourceLineInfo lineInfo; + ResultWas::OfType type; + unsigned int sequence; + + bool operator == ( MessageInfo const& other ) const; + bool operator < ( MessageInfo const& other ) const; + private: + static unsigned int globalCount; + }; + + struct MessageStream { + + template + MessageStream& operator << ( T const& value ) { + m_stream << value; + return *this; + } + + ReusableStringStream m_stream; + }; + + struct MessageBuilder : MessageStream { + MessageBuilder( std::string const& macroName, + SourceLineInfo const& lineInfo, + ResultWas::OfType type ); + + template + MessageBuilder& operator << ( T const& value ) { + m_stream << value; + return *this; + } + + MessageInfo m_info; + }; + + class ScopedMessage { + public: + explicit ScopedMessage( MessageBuilder const& builder ); + ~ScopedMessage(); + + MessageInfo m_info; + }; + +} // end namespace Catch + +// end catch_message.h +#if !defined(CATCH_CONFIG_DISABLE) + +#if !defined(CATCH_CONFIG_DISABLE_STRINGIFICATION) + #define CATCH_INTERNAL_STRINGIFY(...) #__VA_ARGS__ +#else + #define CATCH_INTERNAL_STRINGIFY(...) "Disabled by CATCH_CONFIG_DISABLE_STRINGIFICATION" +#endif + +#if defined(CATCH_CONFIG_FAST_COMPILE) + +/////////////////////////////////////////////////////////////////////////////// +// Another way to speed-up compilation is to omit local try-catch for REQUIRE* +// macros. +#define INTERNAL_CATCH_TRY +#define INTERNAL_CATCH_CATCH( capturer ) + +#else // CATCH_CONFIG_FAST_COMPILE + +#define INTERNAL_CATCH_TRY try +#define INTERNAL_CATCH_CATCH( handler ) catch(...) { handler.handleUnexpectedInflightException(); } + +#endif + +#define INTERNAL_CATCH_REACT( handler ) handler.complete(); + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_TEST( macroName, resultDisposition, ... ) \ + do { \ + Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \ + INTERNAL_CATCH_TRY { \ + CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ + catchAssertionHandler.handleExpr( Catch::Decomposer() <= __VA_ARGS__ ); \ + CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \ + } INTERNAL_CATCH_CATCH( catchAssertionHandler ) \ + INTERNAL_CATCH_REACT( catchAssertionHandler ) \ + } while( (void)0, false && static_cast( !!(__VA_ARGS__) ) ) // the expression here is never evaluated at runtime but it forces the compiler to give it a look + // The double negation silences MSVC's C4800 warning, the static_cast forces short-circuit evaluation if the type has overloaded &&. + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_IF( macroName, resultDisposition, ... ) \ + INTERNAL_CATCH_TEST( macroName, resultDisposition, __VA_ARGS__ ); \ + if( Catch::getResultCapture().lastAssertionPassed() ) + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_ELSE( macroName, resultDisposition, ... ) \ + INTERNAL_CATCH_TEST( macroName, resultDisposition, __VA_ARGS__ ); \ + if( !Catch::getResultCapture().lastAssertionPassed() ) + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_NO_THROW( macroName, resultDisposition, ... ) \ + do { \ + Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \ + try { \ + static_cast(__VA_ARGS__); \ + catchAssertionHandler.handleExceptionNotThrownAsExpected(); \ + } \ + catch( ... ) { \ + catchAssertionHandler.handleUnexpectedInflightException(); \ + } \ + INTERNAL_CATCH_REACT( catchAssertionHandler ) \ + } while( false ) + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_THROWS( macroName, resultDisposition, ... ) \ + do { \ + Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition); \ + if( catchAssertionHandler.allowThrows() ) \ + try { \ + static_cast(__VA_ARGS__); \ + catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \ + } \ + catch( ... ) { \ + catchAssertionHandler.handleExceptionThrownAsExpected(); \ + } \ + else \ + catchAssertionHandler.handleThrowingCallSkipped(); \ + INTERNAL_CATCH_REACT( catchAssertionHandler ) \ + } while( false ) + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_THROWS_AS( macroName, exceptionType, resultDisposition, expr ) \ + do { \ + Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr) ", " CATCH_INTERNAL_STRINGIFY(exceptionType), resultDisposition ); \ + if( catchAssertionHandler.allowThrows() ) \ + try { \ + static_cast(expr); \ + catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \ + } \ + catch( exceptionType const& ) { \ + catchAssertionHandler.handleExceptionThrownAsExpected(); \ + } \ + catch( ... ) { \ + catchAssertionHandler.handleUnexpectedInflightException(); \ + } \ + else \ + catchAssertionHandler.handleThrowingCallSkipped(); \ + INTERNAL_CATCH_REACT( catchAssertionHandler ) \ + } while( false ) + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_MSG( macroName, messageType, resultDisposition, ... ) \ + do { \ + Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, Catch::StringRef(), resultDisposition ); \ + catchAssertionHandler.handleMessage( messageType, ( Catch::MessageStream() << __VA_ARGS__ + ::Catch::StreamEndStop() ).m_stream.str() ); \ + INTERNAL_CATCH_REACT( catchAssertionHandler ) \ + } while( false ) + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_INFO( macroName, log ) \ + Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage )( Catch::MessageBuilder( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log ); + +/////////////////////////////////////////////////////////////////////////////// +// Although this is matcher-based, it can be used with just a string +#define INTERNAL_CATCH_THROWS_STR_MATCHES( macroName, resultDisposition, matcher, ... ) \ + do { \ + Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \ + if( catchAssertionHandler.allowThrows() ) \ + try { \ + static_cast(__VA_ARGS__); \ + catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \ + } \ + catch( ... ) { \ + Catch::handleExceptionMatchExpr( catchAssertionHandler, matcher, #matcher ); \ + } \ + else \ + catchAssertionHandler.handleThrowingCallSkipped(); \ + INTERNAL_CATCH_REACT( catchAssertionHandler ) \ + } while( false ) + +#endif // CATCH_CONFIG_DISABLE + +// end catch_capture.hpp +// start catch_section.h + +// start catch_section_info.h + +// start catch_totals.h + +#include + +namespace Catch { + + struct Counts { + Counts operator - ( Counts const& other ) const; + Counts& operator += ( Counts const& other ); + + std::size_t total() const; + bool allPassed() const; + bool allOk() const; + + std::size_t passed = 0; + std::size_t failed = 0; + std::size_t failedButOk = 0; + }; + + struct Totals { + + Totals operator - ( Totals const& other ) const; + Totals& operator += ( Totals const& other ); + + Totals delta( Totals const& prevTotals ) const; + + int error = 0; + Counts assertions; + Counts testCases; + }; +} + +// end catch_totals.h +#include + +namespace Catch { + + struct SectionInfo { + SectionInfo + ( SourceLineInfo const& _lineInfo, + std::string const& _name ); + + // Deprecated + SectionInfo + ( SourceLineInfo const& _lineInfo, + std::string const& _name, + std::string const& ) : SectionInfo( _lineInfo, _name ) {} + + std::string name; + std::string description; // !Deprecated: this will always be empty + SourceLineInfo lineInfo; + }; + + struct SectionEndInfo { + SectionInfo sectionInfo; + Counts prevAssertions; + double durationInSeconds; + }; + +} // end namespace Catch + +// end catch_section_info.h +// start catch_timer.h + +#include + +namespace Catch { + + auto getCurrentNanosecondsSinceEpoch() -> uint64_t; + auto getEstimatedClockResolution() -> uint64_t; + + class Timer { + uint64_t m_nanoseconds = 0; + public: + void start(); + auto getElapsedNanoseconds() const -> uint64_t; + auto getElapsedMicroseconds() const -> uint64_t; + auto getElapsedMilliseconds() const -> unsigned int; + auto getElapsedSeconds() const -> double; + }; + +} // namespace Catch + +// end catch_timer.h +#include + +namespace Catch { + + class Section : NonCopyable { + public: + Section( SectionInfo const& info ); + ~Section(); + + // This indicates whether the section should be executed or not + explicit operator bool() const; + + private: + SectionInfo m_info; + + std::string m_name; + Counts m_assertions; + bool m_sectionIncluded; + Timer m_timer; + }; + +} // end namespace Catch + +#define INTERNAL_CATCH_SECTION( ... ) \ + CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \ + if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) ) \ + CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS + +#define INTERNAL_CATCH_DYNAMIC_SECTION( ... ) \ + CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \ + if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, (Catch::ReusableStringStream() << __VA_ARGS__).str() ) ) \ + CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS + +// end catch_section.h +// start catch_benchmark.h + +#include +#include + +namespace Catch { + + class BenchmarkLooper { + + std::string m_name; + std::size_t m_count = 0; + std::size_t m_iterationsToRun = 1; + uint64_t m_resolution; + Timer m_timer; + + static auto getResolution() -> uint64_t; + public: + // Keep most of this inline as it's on the code path that is being timed + BenchmarkLooper( StringRef name ) + : m_name( name ), + m_resolution( getResolution() ) + { + reportStart(); + m_timer.start(); + } + + explicit operator bool() { + if( m_count < m_iterationsToRun ) + return true; + return needsMoreIterations(); + } + + void increment() { + ++m_count; + } + + void reportStart(); + auto needsMoreIterations() -> bool; + }; + +} // end namespace Catch + +#define BENCHMARK( name ) \ + for( Catch::BenchmarkLooper looper( name ); looper; looper.increment() ) + +// end catch_benchmark.h +// start catch_interfaces_exception.h + +// start catch_interfaces_registry_hub.h + +#include +#include + +namespace Catch { + + class TestCase; + struct ITestCaseRegistry; + struct IExceptionTranslatorRegistry; + struct IExceptionTranslator; + struct IReporterRegistry; + struct IReporterFactory; + struct ITagAliasRegistry; + class StartupExceptionRegistry; + + using IReporterFactoryPtr = std::shared_ptr; + + struct IRegistryHub { + virtual ~IRegistryHub(); + + virtual IReporterRegistry const& getReporterRegistry() const = 0; + virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0; + virtual ITagAliasRegistry const& getTagAliasRegistry() const = 0; + + virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() = 0; + + virtual StartupExceptionRegistry const& getStartupExceptionRegistry() const = 0; + }; + + struct IMutableRegistryHub { + virtual ~IMutableRegistryHub(); + virtual void registerReporter( std::string const& name, IReporterFactoryPtr const& factory ) = 0; + virtual void registerListener( IReporterFactoryPtr const& factory ) = 0; + virtual void registerTest( TestCase const& testInfo ) = 0; + virtual void registerTranslator( const IExceptionTranslator* translator ) = 0; + virtual void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) = 0; + virtual void registerStartupException() noexcept = 0; + }; + + IRegistryHub& getRegistryHub(); + IMutableRegistryHub& getMutableRegistryHub(); + void cleanUp(); + std::string translateActiveException(); + +} + +// end catch_interfaces_registry_hub.h +#if defined(CATCH_CONFIG_DISABLE) + #define INTERNAL_CATCH_TRANSLATE_EXCEPTION_NO_REG( translatorName, signature) \ + static std::string translatorName( signature ) +#endif + +#include +#include +#include + +namespace Catch { + using exceptionTranslateFunction = std::string(*)(); + + struct IExceptionTranslator; + using ExceptionTranslators = std::vector>; + + struct IExceptionTranslator { + virtual ~IExceptionTranslator(); + virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const = 0; + }; + + struct IExceptionTranslatorRegistry { + virtual ~IExceptionTranslatorRegistry(); + + virtual std::string translateActiveException() const = 0; + }; + + class ExceptionTranslatorRegistrar { + template + class ExceptionTranslator : public IExceptionTranslator { + public: + + ExceptionTranslator( std::string(*translateFunction)( T& ) ) + : m_translateFunction( translateFunction ) + {} + + std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const override { + try { + if( it == itEnd ) + std::rethrow_exception(std::current_exception()); + else + return (*it)->translate( it+1, itEnd ); + } + catch( T& ex ) { + return m_translateFunction( ex ); + } + } + + protected: + std::string(*m_translateFunction)( T& ); + }; + + public: + template + ExceptionTranslatorRegistrar( std::string(*translateFunction)( T& ) ) { + getMutableRegistryHub().registerTranslator + ( new ExceptionTranslator( translateFunction ) ); + } + }; +} + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_TRANSLATE_EXCEPTION2( translatorName, signature ) \ + static std::string translatorName( signature ); \ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &translatorName ); } \ + CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \ + static std::string translatorName( signature ) + +#define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION2( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature ) + +// end catch_interfaces_exception.h +// start catch_approx.h + +#include +#include + +namespace Catch { +namespace Detail { + + class Approx { + private: + bool equalityComparisonImpl(double other) const; + + public: + explicit Approx ( double value ); + + static Approx custom(); + + Approx operator-() const; + + template ::value>::type> + Approx operator()( T const& value ) { + Approx approx( static_cast(value) ); + approx.epsilon( m_epsilon ); + approx.margin( m_margin ); + approx.scale( m_scale ); + return approx; + } + + template ::value>::type> + explicit Approx( T const& value ): Approx(static_cast(value)) + {} + + template ::value>::type> + friend bool operator == ( const T& lhs, Approx const& rhs ) { + auto lhs_v = static_cast(lhs); + return rhs.equalityComparisonImpl(lhs_v); + } + + template ::value>::type> + friend bool operator == ( Approx const& lhs, const T& rhs ) { + return operator==( rhs, lhs ); + } + + template ::value>::type> + friend bool operator != ( T const& lhs, Approx const& rhs ) { + return !operator==( lhs, rhs ); + } + + template ::value>::type> + friend bool operator != ( Approx const& lhs, T const& rhs ) { + return !operator==( rhs, lhs ); + } + + template ::value>::type> + friend bool operator <= ( T const& lhs, Approx const& rhs ) { + return static_cast(lhs) < rhs.m_value || lhs == rhs; + } + + template ::value>::type> + friend bool operator <= ( Approx const& lhs, T const& rhs ) { + return lhs.m_value < static_cast(rhs) || lhs == rhs; + } + + template ::value>::type> + friend bool operator >= ( T const& lhs, Approx const& rhs ) { + return static_cast(lhs) > rhs.m_value || lhs == rhs; + } + + template ::value>::type> + friend bool operator >= ( Approx const& lhs, T const& rhs ) { + return lhs.m_value > static_cast(rhs) || lhs == rhs; + } + + template ::value>::type> + Approx& epsilon( T const& newEpsilon ) { + double epsilonAsDouble = static_cast(newEpsilon); + if( epsilonAsDouble < 0 || epsilonAsDouble > 1.0 ) { + throw std::domain_error + ( "Invalid Approx::epsilon: " + + Catch::Detail::stringify( epsilonAsDouble ) + + ", Approx::epsilon has to be between 0 and 1" ); + } + m_epsilon = epsilonAsDouble; + return *this; + } + + template ::value>::type> + Approx& margin( T const& newMargin ) { + double marginAsDouble = static_cast(newMargin); + if( marginAsDouble < 0 ) { + throw std::domain_error + ( "Invalid Approx::margin: " + + Catch::Detail::stringify( marginAsDouble ) + + ", Approx::Margin has to be non-negative." ); + + } + m_margin = marginAsDouble; + return *this; + } + + template ::value>::type> + Approx& scale( T const& newScale ) { + m_scale = static_cast(newScale); + return *this; + } + + std::string toString() const; + + private: + double m_epsilon; + double m_margin; + double m_scale; + double m_value; + }; +} // end namespace Detail + +namespace literals { + Detail::Approx operator "" _a(long double val); + Detail::Approx operator "" _a(unsigned long long val); +} // end namespace literals + +template<> +struct StringMaker { + static std::string convert(Catch::Detail::Approx const& value); +}; + +} // end namespace Catch + +// end catch_approx.h +// start catch_string_manip.h + +#include +#include + +namespace Catch { + + bool startsWith( std::string const& s, std::string const& prefix ); + bool startsWith( std::string const& s, char prefix ); + bool endsWith( std::string const& s, std::string const& suffix ); + bool endsWith( std::string const& s, char suffix ); + bool contains( std::string const& s, std::string const& infix ); + void toLowerInPlace( std::string& s ); + std::string toLower( std::string const& s ); + std::string trim( std::string const& str ); + bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ); + + struct pluralise { + pluralise( std::size_t count, std::string const& label ); + + friend std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ); + + std::size_t m_count; + std::string m_label; + }; +} + +// end catch_string_manip.h +#ifndef CATCH_CONFIG_DISABLE_MATCHERS +// start catch_capture_matchers.h + +// start catch_matchers.h + +#include +#include + +namespace Catch { +namespace Matchers { + namespace Impl { + + template struct MatchAllOf; + template struct MatchAnyOf; + template struct MatchNotOf; + + class MatcherUntypedBase { + public: + MatcherUntypedBase() = default; + MatcherUntypedBase ( MatcherUntypedBase const& ) = default; + MatcherUntypedBase& operator = ( MatcherUntypedBase const& ) = delete; + std::string toString() const; + + protected: + virtual ~MatcherUntypedBase(); + virtual std::string describe() const = 0; + mutable std::string m_cachedToString; + }; + + template + struct MatcherMethod { + virtual bool match( ObjectT const& arg ) const = 0; + }; + template + struct MatcherMethod { + virtual bool match( PtrT* arg ) const = 0; + }; + + template + struct MatcherBase : MatcherUntypedBase, MatcherMethod { + + MatchAllOf operator && ( MatcherBase const& other ) const; + MatchAnyOf operator || ( MatcherBase const& other ) const; + MatchNotOf operator ! () const; + }; + + template + struct MatchAllOf : MatcherBase { + bool match( ArgT const& arg ) const override { + for( auto matcher : m_matchers ) { + if (!matcher->match(arg)) + return false; + } + return true; + } + std::string describe() const override { + std::string description; + description.reserve( 4 + m_matchers.size()*32 ); + description += "( "; + bool first = true; + for( auto matcher : m_matchers ) { + if( first ) + first = false; + else + description += " and "; + description += matcher->toString(); + } + description += " )"; + return description; + } + + MatchAllOf& operator && ( MatcherBase const& other ) { + m_matchers.push_back( &other ); + return *this; + } + + std::vector const*> m_matchers; + }; + template + struct MatchAnyOf : MatcherBase { + + bool match( ArgT const& arg ) const override { + for( auto matcher : m_matchers ) { + if (matcher->match(arg)) + return true; + } + return false; + } + std::string describe() const override { + std::string description; + description.reserve( 4 + m_matchers.size()*32 ); + description += "( "; + bool first = true; + for( auto matcher : m_matchers ) { + if( first ) + first = false; + else + description += " or "; + description += matcher->toString(); + } + description += " )"; + return description; + } + + MatchAnyOf& operator || ( MatcherBase const& other ) { + m_matchers.push_back( &other ); + return *this; + } + + std::vector const*> m_matchers; + }; + + template + struct MatchNotOf : MatcherBase { + + MatchNotOf( MatcherBase const& underlyingMatcher ) : m_underlyingMatcher( underlyingMatcher ) {} + + bool match( ArgT const& arg ) const override { + return !m_underlyingMatcher.match( arg ); + } + + std::string describe() const override { + return "not " + m_underlyingMatcher.toString(); + } + MatcherBase const& m_underlyingMatcher; + }; + + template + MatchAllOf MatcherBase::operator && ( MatcherBase const& other ) const { + return MatchAllOf() && *this && other; + } + template + MatchAnyOf MatcherBase::operator || ( MatcherBase const& other ) const { + return MatchAnyOf() || *this || other; + } + template + MatchNotOf MatcherBase::operator ! () const { + return MatchNotOf( *this ); + } + + } // namespace Impl + +} // namespace Matchers + +using namespace Matchers; +using Matchers::Impl::MatcherBase; + +} // namespace Catch + +// end catch_matchers.h +// start catch_matchers_floating.h + +#include +#include + +namespace Catch { +namespace Matchers { + + namespace Floating { + + enum class FloatingPointKind : uint8_t; + + struct WithinAbsMatcher : MatcherBase { + WithinAbsMatcher(double target, double margin); + bool match(double const& matchee) const override; + std::string describe() const override; + private: + double m_target; + double m_margin; + }; + + struct WithinUlpsMatcher : MatcherBase { + WithinUlpsMatcher(double target, int ulps, FloatingPointKind baseType); + bool match(double const& matchee) const override; + std::string describe() const override; + private: + double m_target; + int m_ulps; + FloatingPointKind m_type; + }; + + } // namespace Floating + + // The following functions create the actual matcher objects. + // This allows the types to be inferred + Floating::WithinUlpsMatcher WithinULP(double target, int maxUlpDiff); + Floating::WithinUlpsMatcher WithinULP(float target, int maxUlpDiff); + Floating::WithinAbsMatcher WithinAbs(double target, double margin); + +} // namespace Matchers +} // namespace Catch + +// end catch_matchers_floating.h +// start catch_matchers_generic.hpp + +#include +#include + +namespace Catch { +namespace Matchers { +namespace Generic { + +namespace Detail { + std::string finalizeDescription(const std::string& desc); +} + +template +class PredicateMatcher : public MatcherBase { + std::function m_predicate; + std::string m_description; +public: + + PredicateMatcher(std::function const& elem, std::string const& descr) + :m_predicate(std::move(elem)), + m_description(Detail::finalizeDescription(descr)) + {} + + bool match( T const& item ) const override { + return m_predicate(item); + } + + std::string describe() const override { + return m_description; + } +}; + +} // namespace Generic + + // The following functions create the actual matcher objects. + // The user has to explicitly specify type to the function, because + // infering std::function is hard (but possible) and + // requires a lot of TMP. + template + Generic::PredicateMatcher Predicate(std::function const& predicate, std::string const& description = "") { + return Generic::PredicateMatcher(predicate, description); + } + +} // namespace Matchers +} // namespace Catch + +// end catch_matchers_generic.hpp +// start catch_matchers_string.h + +#include + +namespace Catch { +namespace Matchers { + + namespace StdString { + + struct CasedString + { + CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity ); + std::string adjustString( std::string const& str ) const; + std::string caseSensitivitySuffix() const; + + CaseSensitive::Choice m_caseSensitivity; + std::string m_str; + }; + + struct StringMatcherBase : MatcherBase { + StringMatcherBase( std::string const& operation, CasedString const& comparator ); + std::string describe() const override; + + CasedString m_comparator; + std::string m_operation; + }; + + struct EqualsMatcher : StringMatcherBase { + EqualsMatcher( CasedString const& comparator ); + bool match( std::string const& source ) const override; + }; + struct ContainsMatcher : StringMatcherBase { + ContainsMatcher( CasedString const& comparator ); + bool match( std::string const& source ) const override; + }; + struct StartsWithMatcher : StringMatcherBase { + StartsWithMatcher( CasedString const& comparator ); + bool match( std::string const& source ) const override; + }; + struct EndsWithMatcher : StringMatcherBase { + EndsWithMatcher( CasedString const& comparator ); + bool match( std::string const& source ) const override; + }; + + struct RegexMatcher : MatcherBase { + RegexMatcher( std::string regex, CaseSensitive::Choice caseSensitivity ); + bool match( std::string const& matchee ) const override; + std::string describe() const override; + + private: + std::string m_regex; + CaseSensitive::Choice m_caseSensitivity; + }; + + } // namespace StdString + + // The following functions create the actual matcher objects. + // This allows the types to be inferred + + StdString::EqualsMatcher Equals( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); + StdString::ContainsMatcher Contains( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); + StdString::EndsWithMatcher EndsWith( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); + StdString::StartsWithMatcher StartsWith( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); + StdString::RegexMatcher Matches( std::string const& regex, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); + +} // namespace Matchers +} // namespace Catch + +// end catch_matchers_string.h +// start catch_matchers_vector.h + +#include + +namespace Catch { +namespace Matchers { + + namespace Vector { + namespace Detail { + template + size_t count(InputIterator first, InputIterator last, T const& item) { + size_t cnt = 0; + for (; first != last; ++first) { + if (*first == item) { + ++cnt; + } + } + return cnt; + } + template + bool contains(InputIterator first, InputIterator last, T const& item) { + for (; first != last; ++first) { + if (*first == item) { + return true; + } + } + return false; + } + } + + template + struct ContainsElementMatcher : MatcherBase> { + + ContainsElementMatcher(T const &comparator) : m_comparator( comparator) {} + + bool match(std::vector const &v) const override { + for (auto const& el : v) { + if (el == m_comparator) { + return true; + } + } + return false; + } + + std::string describe() const override { + return "Contains: " + ::Catch::Detail::stringify( m_comparator ); + } + + T const& m_comparator; + }; + + template + struct ContainsMatcher : MatcherBase> { + + ContainsMatcher(std::vector const &comparator) : m_comparator( comparator ) {} + + bool match(std::vector const &v) const override { + // !TBD: see note in EqualsMatcher + if (m_comparator.size() > v.size()) + return false; + for (auto const& comparator : m_comparator) { + auto present = false; + for (const auto& el : v) { + if (el == comparator) { + present = true; + break; + } + } + if (!present) { + return false; + } + } + return true; + } + std::string describe() const override { + return "Contains: " + ::Catch::Detail::stringify( m_comparator ); + } + + std::vector const& m_comparator; + }; + + template + struct EqualsMatcher : MatcherBase> { + + EqualsMatcher(std::vector const &comparator) : m_comparator( comparator ) {} + + bool match(std::vector const &v) const override { + // !TBD: This currently works if all elements can be compared using != + // - a more general approach would be via a compare template that defaults + // to using !=. but could be specialised for, e.g. std::vector etc + // - then just call that directly + if (m_comparator.size() != v.size()) + return false; + for (std::size_t i = 0; i < v.size(); ++i) + if (m_comparator[i] != v[i]) + return false; + return true; + } + std::string describe() const override { + return "Equals: " + ::Catch::Detail::stringify( m_comparator ); + } + std::vector const& m_comparator; + }; + + template + struct UnorderedEqualsMatcher : MatcherBase> { + UnorderedEqualsMatcher(std::vector const& target) : m_target(target) {} + bool match(std::vector const& vec) const override { + // Note: This is a reimplementation of std::is_permutation, + // because I don't want to include inside the common path + if (m_target.size() != vec.size()) { + return false; + } + auto lfirst = m_target.begin(), llast = m_target.end(); + auto rfirst = vec.begin(), rlast = vec.end(); + // Cut common prefix to optimize checking of permuted parts + while (lfirst != llast && *lfirst != *rfirst) { + ++lfirst; ++rfirst; + } + if (lfirst == llast) { + return true; + } + + for (auto mid = lfirst; mid != llast; ++mid) { + // Skip already counted items + if (Detail::contains(lfirst, mid, *mid)) { + continue; + } + size_t num_vec = Detail::count(rfirst, rlast, *mid); + if (num_vec == 0 || Detail::count(lfirst, llast, *mid) != num_vec) { + return false; + } + } + + return true; + } + + std::string describe() const override { + return "UnorderedEquals: " + ::Catch::Detail::stringify(m_target); + } + private: + std::vector const& m_target; + }; + + } // namespace Vector + + // The following functions create the actual matcher objects. + // This allows the types to be inferred + + template + Vector::ContainsMatcher Contains( std::vector const& comparator ) { + return Vector::ContainsMatcher( comparator ); + } + + template + Vector::ContainsElementMatcher VectorContains( T const& comparator ) { + return Vector::ContainsElementMatcher( comparator ); + } + + template + Vector::EqualsMatcher Equals( std::vector const& comparator ) { + return Vector::EqualsMatcher( comparator ); + } + + template + Vector::UnorderedEqualsMatcher UnorderedEquals(std::vector const& target) { + return Vector::UnorderedEqualsMatcher(target); + } + +} // namespace Matchers +} // namespace Catch + +// end catch_matchers_vector.h +namespace Catch { + + template + class MatchExpr : public ITransientExpression { + ArgT const& m_arg; + MatcherT m_matcher; + StringRef m_matcherString; + public: + MatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef matcherString ) + : ITransientExpression{ true, matcher.match( arg ) }, + m_arg( arg ), + m_matcher( matcher ), + m_matcherString( matcherString ) + {} + + void streamReconstructedExpression( std::ostream &os ) const override { + auto matcherAsString = m_matcher.toString(); + os << Catch::Detail::stringify( m_arg ) << ' '; + if( matcherAsString == Detail::unprintableString ) + os << m_matcherString; + else + os << matcherAsString; + } + }; + + using StringMatcher = Matchers::Impl::MatcherBase; + + void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef matcherString ); + + template + auto makeMatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef matcherString ) -> MatchExpr { + return MatchExpr( arg, matcher, matcherString ); + } + +} // namespace Catch + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CHECK_THAT( macroName, matcher, resultDisposition, arg ) \ + do { \ + Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(arg) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \ + INTERNAL_CATCH_TRY { \ + catchAssertionHandler.handleExpr( Catch::makeMatchExpr( arg, matcher, #matcher ) ); \ + } INTERNAL_CATCH_CATCH( catchAssertionHandler ) \ + INTERNAL_CATCH_REACT( catchAssertionHandler ) \ + } while( false ) + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_THROWS_MATCHES( macroName, exceptionType, resultDisposition, matcher, ... ) \ + do { \ + Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__) ", " CATCH_INTERNAL_STRINGIFY(exceptionType) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \ + if( catchAssertionHandler.allowThrows() ) \ + try { \ + static_cast(__VA_ARGS__ ); \ + catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \ + } \ + catch( exceptionType const& ex ) { \ + catchAssertionHandler.handleExpr( Catch::makeMatchExpr( ex, matcher, #matcher ) ); \ + } \ + catch( ... ) { \ + catchAssertionHandler.handleUnexpectedInflightException(); \ + } \ + else \ + catchAssertionHandler.handleThrowingCallSkipped(); \ + INTERNAL_CATCH_REACT( catchAssertionHandler ) \ + } while( false ) + +// end catch_capture_matchers.h +#endif + +// These files are included here so the single_include script doesn't put them +// in the conditionally compiled sections +// start catch_test_case_info.h + +#include +#include +#include + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpadded" +#endif + +namespace Catch { + + struct ITestInvoker; + + struct TestCaseInfo { + enum SpecialProperties{ + None = 0, + IsHidden = 1 << 1, + ShouldFail = 1 << 2, + MayFail = 1 << 3, + Throws = 1 << 4, + NonPortable = 1 << 5, + Benchmark = 1 << 6 + }; + + TestCaseInfo( std::string const& _name, + std::string const& _className, + std::string const& _description, + std::vector const& _tags, + SourceLineInfo const& _lineInfo ); + + friend void setTags( TestCaseInfo& testCaseInfo, std::vector tags ); + + bool isHidden() const; + bool throws() const; + bool okToFail() const; + bool expectedToFail() const; + + std::string tagsAsString() const; + + std::string name; + std::string className; + std::string description; + std::vector tags; + std::vector lcaseTags; + SourceLineInfo lineInfo; + SpecialProperties properties; + }; + + class TestCase : public TestCaseInfo { + public: + + TestCase( ITestInvoker* testCase, TestCaseInfo&& info ); + + TestCase withName( std::string const& _newName ) const; + + void invoke() const; + + TestCaseInfo const& getTestCaseInfo() const; + + bool operator == ( TestCase const& other ) const; + bool operator < ( TestCase const& other ) const; + + private: + std::shared_ptr test; + }; + + TestCase makeTestCase( ITestInvoker* testCase, + std::string const& className, + NameAndTags const& nameAndTags, + SourceLineInfo const& lineInfo ); +} + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +// end catch_test_case_info.h +// start catch_interfaces_runner.h + +namespace Catch { + + struct IRunner { + virtual ~IRunner(); + virtual bool aborting() const = 0; + }; +} + +// end catch_interfaces_runner.h + +#ifdef __OBJC__ +// start catch_objc.hpp + +#import + +#include + +// NB. Any general catch headers included here must be included +// in catch.hpp first to make sure they are included by the single +// header for non obj-usage + +/////////////////////////////////////////////////////////////////////////////// +// This protocol is really only here for (self) documenting purposes, since +// all its methods are optional. +@protocol OcFixture + +@optional + +-(void) setUp; +-(void) tearDown; + +@end + +namespace Catch { + + class OcMethod : public ITestInvoker { + + public: + OcMethod( Class cls, SEL sel ) : m_cls( cls ), m_sel( sel ) {} + + virtual void invoke() const { + id obj = [[m_cls alloc] init]; + + performOptionalSelector( obj, @selector(setUp) ); + performOptionalSelector( obj, m_sel ); + performOptionalSelector( obj, @selector(tearDown) ); + + arcSafeRelease( obj ); + } + private: + virtual ~OcMethod() {} + + Class m_cls; + SEL m_sel; + }; + + namespace Detail{ + + inline std::string getAnnotation( Class cls, + std::string const& annotationName, + std::string const& testCaseName ) { + NSString* selStr = [[NSString alloc] initWithFormat:@"Catch_%s_%s", annotationName.c_str(), testCaseName.c_str()]; + SEL sel = NSSelectorFromString( selStr ); + arcSafeRelease( selStr ); + id value = performOptionalSelector( cls, sel ); + if( value ) + return [(NSString*)value UTF8String]; + return ""; + } + } + + inline std::size_t registerTestMethods() { + std::size_t noTestMethods = 0; + int noClasses = objc_getClassList( nullptr, 0 ); + + Class* classes = (CATCH_UNSAFE_UNRETAINED Class *)malloc( sizeof(Class) * noClasses); + objc_getClassList( classes, noClasses ); + + for( int c = 0; c < noClasses; c++ ) { + Class cls = classes[c]; + { + u_int count; + Method* methods = class_copyMethodList( cls, &count ); + for( u_int m = 0; m < count ; m++ ) { + SEL selector = method_getName(methods[m]); + std::string methodName = sel_getName(selector); + if( startsWith( methodName, "Catch_TestCase_" ) ) { + std::string testCaseName = methodName.substr( 15 ); + std::string name = Detail::getAnnotation( cls, "Name", testCaseName ); + std::string desc = Detail::getAnnotation( cls, "Description", testCaseName ); + const char* className = class_getName( cls ); + + getMutableRegistryHub().registerTest( makeTestCase( new OcMethod( cls, selector ), className, NameAndTags( name.c_str(), desc.c_str() ), SourceLineInfo("",0) ) ); + noTestMethods++; + } + } + free(methods); + } + } + return noTestMethods; + } + +#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) + + namespace Matchers { + namespace Impl { + namespace NSStringMatchers { + + struct StringHolder : MatcherBase{ + StringHolder( NSString* substr ) : m_substr( [substr copy] ){} + StringHolder( StringHolder const& other ) : m_substr( [other.m_substr copy] ){} + StringHolder() { + arcSafeRelease( m_substr ); + } + + bool match( NSString* arg ) const override { + return false; + } + + NSString* CATCH_ARC_STRONG m_substr; + }; + + struct Equals : StringHolder { + Equals( NSString* substr ) : StringHolder( substr ){} + + bool match( NSString* str ) const override { + return (str != nil || m_substr == nil ) && + [str isEqualToString:m_substr]; + } + + std::string describe() const override { + return "equals string: " + Catch::Detail::stringify( m_substr ); + } + }; + + struct Contains : StringHolder { + Contains( NSString* substr ) : StringHolder( substr ){} + + bool match( NSString* str ) const { + return (str != nil || m_substr == nil ) && + [str rangeOfString:m_substr].location != NSNotFound; + } + + std::string describe() const override { + return "contains string: " + Catch::Detail::stringify( m_substr ); + } + }; + + struct StartsWith : StringHolder { + StartsWith( NSString* substr ) : StringHolder( substr ){} + + bool match( NSString* str ) const override { + return (str != nil || m_substr == nil ) && + [str rangeOfString:m_substr].location == 0; + } + + std::string describe() const override { + return "starts with: " + Catch::Detail::stringify( m_substr ); + } + }; + struct EndsWith : StringHolder { + EndsWith( NSString* substr ) : StringHolder( substr ){} + + bool match( NSString* str ) const override { + return (str != nil || m_substr == nil ) && + [str rangeOfString:m_substr].location == [str length] - [m_substr length]; + } + + std::string describe() const override { + return "ends with: " + Catch::Detail::stringify( m_substr ); + } + }; + + } // namespace NSStringMatchers + } // namespace Impl + + inline Impl::NSStringMatchers::Equals + Equals( NSString* substr ){ return Impl::NSStringMatchers::Equals( substr ); } + + inline Impl::NSStringMatchers::Contains + Contains( NSString* substr ){ return Impl::NSStringMatchers::Contains( substr ); } + + inline Impl::NSStringMatchers::StartsWith + StartsWith( NSString* substr ){ return Impl::NSStringMatchers::StartsWith( substr ); } + + inline Impl::NSStringMatchers::EndsWith + EndsWith( NSString* substr ){ return Impl::NSStringMatchers::EndsWith( substr ); } + + } // namespace Matchers + + using namespace Matchers; + +#endif // CATCH_CONFIG_DISABLE_MATCHERS + +} // namespace Catch + +/////////////////////////////////////////////////////////////////////////////// +#define OC_MAKE_UNIQUE_NAME( root, uniqueSuffix ) root##uniqueSuffix +#define OC_TEST_CASE2( name, desc, uniqueSuffix ) \ ++(NSString*) OC_MAKE_UNIQUE_NAME( Catch_Name_test_, uniqueSuffix ) \ +{ \ +return @ name; \ +} \ ++(NSString*) OC_MAKE_UNIQUE_NAME( Catch_Description_test_, uniqueSuffix ) \ +{ \ +return @ desc; \ +} \ +-(void) OC_MAKE_UNIQUE_NAME( Catch_TestCase_test_, uniqueSuffix ) + +#define OC_TEST_CASE( name, desc ) OC_TEST_CASE2( name, desc, __LINE__ ) + +// end catch_objc.hpp +#endif + +#ifdef CATCH_CONFIG_EXTERNAL_INTERFACES +// start catch_external_interfaces.h + +// start catch_reporter_bases.hpp + +// start catch_interfaces_reporter.h + +// start catch_config.hpp + +// start catch_test_spec_parser.h + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpadded" +#endif + +// start catch_test_spec.h + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpadded" +#endif + +// start catch_wildcard_pattern.h + +namespace Catch +{ + class WildcardPattern { + enum WildcardPosition { + NoWildcard = 0, + WildcardAtStart = 1, + WildcardAtEnd = 2, + WildcardAtBothEnds = WildcardAtStart | WildcardAtEnd + }; + + public: + + WildcardPattern( std::string const& pattern, CaseSensitive::Choice caseSensitivity ); + virtual ~WildcardPattern() = default; + virtual bool matches( std::string const& str ) const; + + private: + std::string adjustCase( std::string const& str ) const; + CaseSensitive::Choice m_caseSensitivity; + WildcardPosition m_wildcard = NoWildcard; + std::string m_pattern; + }; +} + +// end catch_wildcard_pattern.h +#include +#include +#include + +namespace Catch { + + class TestSpec { + struct Pattern { + virtual ~Pattern(); + virtual bool matches( TestCaseInfo const& testCase ) const = 0; + }; + using PatternPtr = std::shared_ptr; + + class NamePattern : public Pattern { + public: + NamePattern( std::string const& name ); + virtual ~NamePattern(); + virtual bool matches( TestCaseInfo const& testCase ) const override; + private: + WildcardPattern m_wildcardPattern; + }; + + class TagPattern : public Pattern { + public: + TagPattern( std::string const& tag ); + virtual ~TagPattern(); + virtual bool matches( TestCaseInfo const& testCase ) const override; + private: + std::string m_tag; + }; + + class ExcludedPattern : public Pattern { + public: + ExcludedPattern( PatternPtr const& underlyingPattern ); + virtual ~ExcludedPattern(); + virtual bool matches( TestCaseInfo const& testCase ) const override; + private: + PatternPtr m_underlyingPattern; + }; + + struct Filter { + std::vector m_patterns; + + bool matches( TestCaseInfo const& testCase ) const; + }; + + public: + bool hasFilters() const; + bool matches( TestCaseInfo const& testCase ) const; + + private: + std::vector m_filters; + + friend class TestSpecParser; + }; +} + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +// end catch_test_spec.h +// start catch_interfaces_tag_alias_registry.h + +#include + +namespace Catch { + + struct TagAlias; + + struct ITagAliasRegistry { + virtual ~ITagAliasRegistry(); + // Nullptr if not present + virtual TagAlias const* find( std::string const& alias ) const = 0; + virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const = 0; + + static ITagAliasRegistry const& get(); + }; + +} // end namespace Catch + +// end catch_interfaces_tag_alias_registry.h +namespace Catch { + + class TestSpecParser { + enum Mode{ None, Name, QuotedName, Tag, EscapedName }; + Mode m_mode = None; + bool m_exclusion = false; + std::size_t m_start = std::string::npos, m_pos = 0; + std::string m_arg; + std::vector m_escapeChars; + TestSpec::Filter m_currentFilter; + TestSpec m_testSpec; + ITagAliasRegistry const* m_tagAliases = nullptr; + + public: + TestSpecParser( ITagAliasRegistry const& tagAliases ); + + TestSpecParser& parse( std::string const& arg ); + TestSpec testSpec(); + + private: + void visitChar( char c ); + void startNewMode( Mode mode, std::size_t start ); + void escape(); + std::string subString() const; + + template + void addPattern() { + std::string token = subString(); + for( std::size_t i = 0; i < m_escapeChars.size(); ++i ) + token = token.substr( 0, m_escapeChars[i]-m_start-i ) + token.substr( m_escapeChars[i]-m_start-i+1 ); + m_escapeChars.clear(); + if( startsWith( token, "exclude:" ) ) { + m_exclusion = true; + token = token.substr( 8 ); + } + if( !token.empty() ) { + TestSpec::PatternPtr pattern = std::make_shared( token ); + if( m_exclusion ) + pattern = std::make_shared( pattern ); + m_currentFilter.m_patterns.push_back( pattern ); + } + m_exclusion = false; + m_mode = None; + } + + void addFilter(); + }; + TestSpec parseTestSpec( std::string const& arg ); + +} // namespace Catch + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +// end catch_test_spec_parser.h +// start catch_interfaces_config.h + +#include +#include +#include +#include + +namespace Catch { + + enum class Verbosity { + Quiet = 0, + Normal, + High + }; + + struct WarnAbout { enum What { + Nothing = 0x00, + NoAssertions = 0x01, + NoTests = 0x02 + }; }; + + struct ShowDurations { enum OrNot { + DefaultForReporter, + Always, + Never + }; }; + struct RunTests { enum InWhatOrder { + InDeclarationOrder, + InLexicographicalOrder, + InRandomOrder + }; }; + struct UseColour { enum YesOrNo { + Auto, + Yes, + No + }; }; + struct WaitForKeypress { enum When { + Never, + BeforeStart = 1, + BeforeExit = 2, + BeforeStartAndExit = BeforeStart | BeforeExit + }; }; + + class TestSpec; + + struct IConfig : NonCopyable { + + virtual ~IConfig(); + + virtual bool allowThrows() const = 0; + virtual std::ostream& stream() const = 0; + virtual std::string name() const = 0; + virtual bool includeSuccessfulResults() const = 0; + virtual bool shouldDebugBreak() const = 0; + virtual bool warnAboutMissingAssertions() const = 0; + virtual bool warnAboutNoTests() const = 0; + virtual int abortAfter() const = 0; + virtual bool showInvisibles() const = 0; + virtual ShowDurations::OrNot showDurations() const = 0; + virtual TestSpec const& testSpec() const = 0; + virtual bool hasTestFilters() const = 0; + virtual RunTests::InWhatOrder runOrder() const = 0; + virtual unsigned int rngSeed() const = 0; + virtual int benchmarkResolutionMultiple() const = 0; + virtual UseColour::YesOrNo useColour() const = 0; + virtual std::vector const& getSectionsToRun() const = 0; + virtual Verbosity verbosity() const = 0; + }; + + using IConfigPtr = std::shared_ptr; +} + +// end catch_interfaces_config.h +// Libstdc++ doesn't like incomplete classes for unique_ptr + +#include +#include +#include + +#ifndef CATCH_CONFIG_CONSOLE_WIDTH +#define CATCH_CONFIG_CONSOLE_WIDTH 80 +#endif + +namespace Catch { + + struct IStream; + + struct ConfigData { + bool listTests = false; + bool listTags = false; + bool listReporters = false; + bool listTestNamesOnly = false; + + bool showSuccessfulTests = false; + bool shouldDebugBreak = false; + bool noThrow = false; + bool showHelp = false; + bool showInvisibles = false; + bool filenamesAsTags = false; + bool libIdentify = false; + + int abortAfter = -1; + unsigned int rngSeed = 0; + int benchmarkResolutionMultiple = 100; + + Verbosity verbosity = Verbosity::Normal; + WarnAbout::What warnings = WarnAbout::Nothing; + ShowDurations::OrNot showDurations = ShowDurations::DefaultForReporter; + RunTests::InWhatOrder runOrder = RunTests::InDeclarationOrder; + UseColour::YesOrNo useColour = UseColour::Auto; + WaitForKeypress::When waitForKeypress = WaitForKeypress::Never; + + std::string outputFilename; + std::string name; + std::string processName; +#ifndef CATCH_CONFIG_DEFAULT_REPORTER +#define CATCH_CONFIG_DEFAULT_REPORTER "console" +#endif + std::string reporterName = CATCH_CONFIG_DEFAULT_REPORTER; +#undef CATCH_CONFIG_DEFAULT_REPORTER + + std::vector testsOrTags; + std::vector sectionsToRun; + }; + + class Config : public IConfig { + public: + + Config() = default; + Config( ConfigData const& data ); + virtual ~Config() = default; + + std::string const& getFilename() const; + + bool listTests() const; + bool listTestNamesOnly() const; + bool listTags() const; + bool listReporters() const; + + std::string getProcessName() const; + std::string const& getReporterName() const; + + std::vector const& getTestsOrTags() const; + std::vector const& getSectionsToRun() const override; + + virtual TestSpec const& testSpec() const override; + bool hasTestFilters() const override; + + bool showHelp() const; + + // IConfig interface + bool allowThrows() const override; + std::ostream& stream() const override; + std::string name() const override; + bool includeSuccessfulResults() const override; + bool warnAboutMissingAssertions() const override; + bool warnAboutNoTests() const override; + ShowDurations::OrNot showDurations() const override; + RunTests::InWhatOrder runOrder() const override; + unsigned int rngSeed() const override; + int benchmarkResolutionMultiple() const override; + UseColour::YesOrNo useColour() const override; + bool shouldDebugBreak() const override; + int abortAfter() const override; + bool showInvisibles() const override; + Verbosity verbosity() const override; + + private: + + IStream const* openStream(); + ConfigData m_data; + + std::unique_ptr m_stream; + TestSpec m_testSpec; + bool m_hasTestFilters = false; + }; + +} // end namespace Catch + +// end catch_config.hpp +// start catch_assertionresult.h + +#include + +namespace Catch { + + struct AssertionResultData + { + AssertionResultData() = delete; + + AssertionResultData( ResultWas::OfType _resultType, LazyExpression const& _lazyExpression ); + + std::string message; + mutable std::string reconstructedExpression; + LazyExpression lazyExpression; + ResultWas::OfType resultType; + + std::string reconstructExpression() const; + }; + + class AssertionResult { + public: + AssertionResult() = delete; + AssertionResult( AssertionInfo const& info, AssertionResultData const& data ); + + bool isOk() const; + bool succeeded() const; + ResultWas::OfType getResultType() const; + bool hasExpression() const; + bool hasMessage() const; + std::string getExpression() const; + std::string getExpressionInMacro() const; + bool hasExpandedExpression() const; + std::string getExpandedExpression() const; + std::string getMessage() const; + SourceLineInfo getSourceInfo() const; + StringRef getTestMacroName() const; + + //protected: + AssertionInfo m_info; + AssertionResultData m_resultData; + }; + +} // end namespace Catch + +// end catch_assertionresult.h +// start catch_option.hpp + +namespace Catch { + + // An optional type + template + class Option { + public: + Option() : nullableValue( nullptr ) {} + Option( T const& _value ) + : nullableValue( new( storage ) T( _value ) ) + {} + Option( Option const& _other ) + : nullableValue( _other ? new( storage ) T( *_other ) : nullptr ) + {} + + ~Option() { + reset(); + } + + Option& operator= ( Option const& _other ) { + if( &_other != this ) { + reset(); + if( _other ) + nullableValue = new( storage ) T( *_other ); + } + return *this; + } + Option& operator = ( T const& _value ) { + reset(); + nullableValue = new( storage ) T( _value ); + return *this; + } + + void reset() { + if( nullableValue ) + nullableValue->~T(); + nullableValue = nullptr; + } + + T& operator*() { return *nullableValue; } + T const& operator*() const { return *nullableValue; } + T* operator->() { return nullableValue; } + const T* operator->() const { return nullableValue; } + + T valueOr( T const& defaultValue ) const { + return nullableValue ? *nullableValue : defaultValue; + } + + bool some() const { return nullableValue != nullptr; } + bool none() const { return nullableValue == nullptr; } + + bool operator !() const { return nullableValue == nullptr; } + explicit operator bool() const { + return some(); + } + + private: + T *nullableValue; + alignas(alignof(T)) char storage[sizeof(T)]; + }; + +} // end namespace Catch + +// end catch_option.hpp +#include +#include +#include +#include +#include + +namespace Catch { + + struct ReporterConfig { + explicit ReporterConfig( IConfigPtr const& _fullConfig ); + + ReporterConfig( IConfigPtr const& _fullConfig, std::ostream& _stream ); + + std::ostream& stream() const; + IConfigPtr fullConfig() const; + + private: + std::ostream* m_stream; + IConfigPtr m_fullConfig; + }; + + struct ReporterPreferences { + bool shouldRedirectStdOut = false; + bool shouldReportAllAssertions = false; + }; + + template + struct LazyStat : Option { + LazyStat& operator=( T const& _value ) { + Option::operator=( _value ); + used = false; + return *this; + } + void reset() { + Option::reset(); + used = false; + } + bool used = false; + }; + + struct TestRunInfo { + TestRunInfo( std::string const& _name ); + std::string name; + }; + struct GroupInfo { + GroupInfo( std::string const& _name, + std::size_t _groupIndex, + std::size_t _groupsCount ); + + std::string name; + std::size_t groupIndex; + std::size_t groupsCounts; + }; + + struct AssertionStats { + AssertionStats( AssertionResult const& _assertionResult, + std::vector const& _infoMessages, + Totals const& _totals ); + + AssertionStats( AssertionStats const& ) = default; + AssertionStats( AssertionStats && ) = default; + AssertionStats& operator = ( AssertionStats const& ) = default; + AssertionStats& operator = ( AssertionStats && ) = default; + virtual ~AssertionStats(); + + AssertionResult assertionResult; + std::vector infoMessages; + Totals totals; + }; + + struct SectionStats { + SectionStats( SectionInfo const& _sectionInfo, + Counts const& _assertions, + double _durationInSeconds, + bool _missingAssertions ); + SectionStats( SectionStats const& ) = default; + SectionStats( SectionStats && ) = default; + SectionStats& operator = ( SectionStats const& ) = default; + SectionStats& operator = ( SectionStats && ) = default; + virtual ~SectionStats(); + + SectionInfo sectionInfo; + Counts assertions; + double durationInSeconds; + bool missingAssertions; + }; + + struct TestCaseStats { + TestCaseStats( TestCaseInfo const& _testInfo, + Totals const& _totals, + std::string const& _stdOut, + std::string const& _stdErr, + bool _aborting ); + + TestCaseStats( TestCaseStats const& ) = default; + TestCaseStats( TestCaseStats && ) = default; + TestCaseStats& operator = ( TestCaseStats const& ) = default; + TestCaseStats& operator = ( TestCaseStats && ) = default; + virtual ~TestCaseStats(); + + TestCaseInfo testInfo; + Totals totals; + std::string stdOut; + std::string stdErr; + bool aborting; + }; + + struct TestGroupStats { + TestGroupStats( GroupInfo const& _groupInfo, + Totals const& _totals, + bool _aborting ); + TestGroupStats( GroupInfo const& _groupInfo ); + + TestGroupStats( TestGroupStats const& ) = default; + TestGroupStats( TestGroupStats && ) = default; + TestGroupStats& operator = ( TestGroupStats const& ) = default; + TestGroupStats& operator = ( TestGroupStats && ) = default; + virtual ~TestGroupStats(); + + GroupInfo groupInfo; + Totals totals; + bool aborting; + }; + + struct TestRunStats { + TestRunStats( TestRunInfo const& _runInfo, + Totals const& _totals, + bool _aborting ); + + TestRunStats( TestRunStats const& ) = default; + TestRunStats( TestRunStats && ) = default; + TestRunStats& operator = ( TestRunStats const& ) = default; + TestRunStats& operator = ( TestRunStats && ) = default; + virtual ~TestRunStats(); + + TestRunInfo runInfo; + Totals totals; + bool aborting; + }; + + struct BenchmarkInfo { + std::string name; + }; + struct BenchmarkStats { + BenchmarkInfo info; + std::size_t iterations; + uint64_t elapsedTimeInNanoseconds; + }; + + struct IStreamingReporter { + virtual ~IStreamingReporter() = default; + + // Implementing class must also provide the following static methods: + // static std::string getDescription(); + // static std::set getSupportedVerbosities() + + virtual ReporterPreferences getPreferences() const = 0; + + virtual void noMatchingTestCases( std::string const& spec ) = 0; + + virtual void testRunStarting( TestRunInfo const& testRunInfo ) = 0; + virtual void testGroupStarting( GroupInfo const& groupInfo ) = 0; + + virtual void testCaseStarting( TestCaseInfo const& testInfo ) = 0; + virtual void sectionStarting( SectionInfo const& sectionInfo ) = 0; + + // *** experimental *** + virtual void benchmarkStarting( BenchmarkInfo const& ) {} + + virtual void assertionStarting( AssertionInfo const& assertionInfo ) = 0; + + // The return value indicates if the messages buffer should be cleared: + virtual bool assertionEnded( AssertionStats const& assertionStats ) = 0; + + // *** experimental *** + virtual void benchmarkEnded( BenchmarkStats const& ) {} + + virtual void sectionEnded( SectionStats const& sectionStats ) = 0; + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0; + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) = 0; + virtual void testRunEnded( TestRunStats const& testRunStats ) = 0; + + virtual void skipTest( TestCaseInfo const& testInfo ) = 0; + + // Default empty implementation provided + virtual void fatalErrorEncountered( StringRef name ); + + virtual bool isMulti() const; + }; + using IStreamingReporterPtr = std::unique_ptr; + + struct IReporterFactory { + virtual ~IReporterFactory(); + virtual IStreamingReporterPtr create( ReporterConfig const& config ) const = 0; + virtual std::string getDescription() const = 0; + }; + using IReporterFactoryPtr = std::shared_ptr; + + struct IReporterRegistry { + using FactoryMap = std::map; + using Listeners = std::vector; + + virtual ~IReporterRegistry(); + virtual IStreamingReporterPtr create( std::string const& name, IConfigPtr const& config ) const = 0; + virtual FactoryMap const& getFactories() const = 0; + virtual Listeners const& getListeners() const = 0; + }; + +} // end namespace Catch + +// end catch_interfaces_reporter.h +#include +#include +#include +#include +#include +#include +#include + +namespace Catch { + void prepareExpandedExpression(AssertionResult& result); + + // Returns double formatted as %.3f (format expected on output) + std::string getFormattedDuration( double duration ); + + template + struct StreamingReporterBase : IStreamingReporter { + + StreamingReporterBase( ReporterConfig const& _config ) + : m_config( _config.fullConfig() ), + stream( _config.stream() ) + { + m_reporterPrefs.shouldRedirectStdOut = false; + if( !DerivedT::getSupportedVerbosities().count( m_config->verbosity() ) ) + throw std::domain_error( "Verbosity level not supported by this reporter" ); + } + + ReporterPreferences getPreferences() const override { + return m_reporterPrefs; + } + + static std::set getSupportedVerbosities() { + return { Verbosity::Normal }; + } + + ~StreamingReporterBase() override = default; + + void noMatchingTestCases(std::string const&) override {} + + void testRunStarting(TestRunInfo const& _testRunInfo) override { + currentTestRunInfo = _testRunInfo; + } + void testGroupStarting(GroupInfo const& _groupInfo) override { + currentGroupInfo = _groupInfo; + } + + void testCaseStarting(TestCaseInfo const& _testInfo) override { + currentTestCaseInfo = _testInfo; + } + void sectionStarting(SectionInfo const& _sectionInfo) override { + m_sectionStack.push_back(_sectionInfo); + } + + void sectionEnded(SectionStats const& /* _sectionStats */) override { + m_sectionStack.pop_back(); + } + void testCaseEnded(TestCaseStats const& /* _testCaseStats */) override { + currentTestCaseInfo.reset(); + } + void testGroupEnded(TestGroupStats const& /* _testGroupStats */) override { + currentGroupInfo.reset(); + } + void testRunEnded(TestRunStats const& /* _testRunStats */) override { + currentTestCaseInfo.reset(); + currentGroupInfo.reset(); + currentTestRunInfo.reset(); + } + + void skipTest(TestCaseInfo const&) override { + // Don't do anything with this by default. + // It can optionally be overridden in the derived class. + } + + IConfigPtr m_config; + std::ostream& stream; + + LazyStat currentTestRunInfo; + LazyStat currentGroupInfo; + LazyStat currentTestCaseInfo; + + std::vector m_sectionStack; + ReporterPreferences m_reporterPrefs; + }; + + template + struct CumulativeReporterBase : IStreamingReporter { + template + struct Node { + explicit Node( T const& _value ) : value( _value ) {} + virtual ~Node() {} + + using ChildNodes = std::vector>; + T value; + ChildNodes children; + }; + struct SectionNode { + explicit SectionNode(SectionStats const& _stats) : stats(_stats) {} + virtual ~SectionNode() = default; + + bool operator == (SectionNode const& other) const { + return stats.sectionInfo.lineInfo == other.stats.sectionInfo.lineInfo; + } + bool operator == (std::shared_ptr const& other) const { + return operator==(*other); + } + + SectionStats stats; + using ChildSections = std::vector>; + using Assertions = std::vector; + ChildSections childSections; + Assertions assertions; + std::string stdOut; + std::string stdErr; + }; + + struct BySectionInfo { + BySectionInfo( SectionInfo const& other ) : m_other( other ) {} + BySectionInfo( BySectionInfo const& other ) : m_other( other.m_other ) {} + bool operator() (std::shared_ptr const& node) const { + return ((node->stats.sectionInfo.name == m_other.name) && + (node->stats.sectionInfo.lineInfo == m_other.lineInfo)); + } + void operator=(BySectionInfo const&) = delete; + + private: + SectionInfo const& m_other; + }; + + using TestCaseNode = Node; + using TestGroupNode = Node; + using TestRunNode = Node; + + CumulativeReporterBase( ReporterConfig const& _config ) + : m_config( _config.fullConfig() ), + stream( _config.stream() ) + { + m_reporterPrefs.shouldRedirectStdOut = false; + if( !DerivedT::getSupportedVerbosities().count( m_config->verbosity() ) ) + throw std::domain_error( "Verbosity level not supported by this reporter" ); + } + ~CumulativeReporterBase() override = default; + + ReporterPreferences getPreferences() const override { + return m_reporterPrefs; + } + + static std::set getSupportedVerbosities() { + return { Verbosity::Normal }; + } + + void testRunStarting( TestRunInfo const& ) override {} + void testGroupStarting( GroupInfo const& ) override {} + + void testCaseStarting( TestCaseInfo const& ) override {} + + void sectionStarting( SectionInfo const& sectionInfo ) override { + SectionStats incompleteStats( sectionInfo, Counts(), 0, false ); + std::shared_ptr node; + if( m_sectionStack.empty() ) { + if( !m_rootSection ) + m_rootSection = std::make_shared( incompleteStats ); + node = m_rootSection; + } + else { + SectionNode& parentNode = *m_sectionStack.back(); + auto it = + std::find_if( parentNode.childSections.begin(), + parentNode.childSections.end(), + BySectionInfo( sectionInfo ) ); + if( it == parentNode.childSections.end() ) { + node = std::make_shared( incompleteStats ); + parentNode.childSections.push_back( node ); + } + else + node = *it; + } + m_sectionStack.push_back( node ); + m_deepestSection = std::move(node); + } + + void assertionStarting(AssertionInfo const&) override {} + + bool assertionEnded(AssertionStats const& assertionStats) override { + assert(!m_sectionStack.empty()); + // AssertionResult holds a pointer to a temporary DecomposedExpression, + // which getExpandedExpression() calls to build the expression string. + // Our section stack copy of the assertionResult will likely outlive the + // temporary, so it must be expanded or discarded now to avoid calling + // a destroyed object later. + prepareExpandedExpression(const_cast( assertionStats.assertionResult ) ); + SectionNode& sectionNode = *m_sectionStack.back(); + sectionNode.assertions.push_back(assertionStats); + return true; + } + void sectionEnded(SectionStats const& sectionStats) override { + assert(!m_sectionStack.empty()); + SectionNode& node = *m_sectionStack.back(); + node.stats = sectionStats; + m_sectionStack.pop_back(); + } + void testCaseEnded(TestCaseStats const& testCaseStats) override { + auto node = std::make_shared(testCaseStats); + assert(m_sectionStack.size() == 0); + node->children.push_back(m_rootSection); + m_testCases.push_back(node); + m_rootSection.reset(); + + assert(m_deepestSection); + m_deepestSection->stdOut = testCaseStats.stdOut; + m_deepestSection->stdErr = testCaseStats.stdErr; + } + void testGroupEnded(TestGroupStats const& testGroupStats) override { + auto node = std::make_shared(testGroupStats); + node->children.swap(m_testCases); + m_testGroups.push_back(node); + } + void testRunEnded(TestRunStats const& testRunStats) override { + auto node = std::make_shared(testRunStats); + node->children.swap(m_testGroups); + m_testRuns.push_back(node); + testRunEndedCumulative(); + } + virtual void testRunEndedCumulative() = 0; + + void skipTest(TestCaseInfo const&) override {} + + IConfigPtr m_config; + std::ostream& stream; + std::vector m_assertions; + std::vector>> m_sections; + std::vector> m_testCases; + std::vector> m_testGroups; + + std::vector> m_testRuns; + + std::shared_ptr m_rootSection; + std::shared_ptr m_deepestSection; + std::vector> m_sectionStack; + ReporterPreferences m_reporterPrefs; + }; + + template + char const* getLineOfChars() { + static char line[CATCH_CONFIG_CONSOLE_WIDTH] = {0}; + if( !*line ) { + std::memset( line, C, CATCH_CONFIG_CONSOLE_WIDTH-1 ); + line[CATCH_CONFIG_CONSOLE_WIDTH-1] = 0; + } + return line; + } + + struct TestEventListenerBase : StreamingReporterBase { + TestEventListenerBase( ReporterConfig const& _config ); + + void assertionStarting(AssertionInfo const&) override; + bool assertionEnded(AssertionStats const&) override; + }; + +} // end namespace Catch + +// end catch_reporter_bases.hpp +// start catch_console_colour.h + +namespace Catch { + + struct Colour { + enum Code { + None = 0, + + White, + Red, + Green, + Blue, + Cyan, + Yellow, + Grey, + + Bright = 0x10, + + BrightRed = Bright | Red, + BrightGreen = Bright | Green, + LightGrey = Bright | Grey, + BrightWhite = Bright | White, + BrightYellow = Bright | Yellow, + + // By intention + FileName = LightGrey, + Warning = BrightYellow, + ResultError = BrightRed, + ResultSuccess = BrightGreen, + ResultExpectedFailure = Warning, + + Error = BrightRed, + Success = Green, + + OriginalExpression = Cyan, + ReconstructedExpression = BrightYellow, + + SecondaryText = LightGrey, + Headers = White + }; + + // Use constructed object for RAII guard + Colour( Code _colourCode ); + Colour( Colour&& other ) noexcept; + Colour& operator=( Colour&& other ) noexcept; + ~Colour(); + + // Use static method for one-shot changes + static void use( Code _colourCode ); + + private: + bool m_moved = false; + }; + + std::ostream& operator << ( std::ostream& os, Colour const& ); + +} // end namespace Catch + +// end catch_console_colour.h +// start catch_reporter_registrars.hpp + + +namespace Catch { + + template + class ReporterRegistrar { + + class ReporterFactory : public IReporterFactory { + + virtual IStreamingReporterPtr create( ReporterConfig const& config ) const override { + return std::unique_ptr( new T( config ) ); + } + + virtual std::string getDescription() const override { + return T::getDescription(); + } + }; + + public: + + explicit ReporterRegistrar( std::string const& name ) { + getMutableRegistryHub().registerReporter( name, std::make_shared() ); + } + }; + + template + class ListenerRegistrar { + + class ListenerFactory : public IReporterFactory { + + virtual IStreamingReporterPtr create( ReporterConfig const& config ) const override { + return std::unique_ptr( new T( config ) ); + } + virtual std::string getDescription() const override { + return std::string(); + } + }; + + public: + + ListenerRegistrar() { + getMutableRegistryHub().registerListener( std::make_shared() ); + } + }; +} + +#if !defined(CATCH_CONFIG_DISABLE) + +#define CATCH_REGISTER_REPORTER( name, reporterType ) \ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + namespace{ Catch::ReporterRegistrar catch_internal_RegistrarFor##reporterType( name ); } \ + CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS + +#define CATCH_REGISTER_LISTENER( listenerType ) \ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + namespace{ Catch::ListenerRegistrar catch_internal_RegistrarFor##listenerType; } \ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS +#else // CATCH_CONFIG_DISABLE + +#define CATCH_REGISTER_REPORTER(name, reporterType) +#define CATCH_REGISTER_LISTENER(listenerType) + +#endif // CATCH_CONFIG_DISABLE + +// end catch_reporter_registrars.hpp +// Allow users to base their work off existing reporters +// start catch_reporter_compact.h + +namespace Catch { + + struct CompactReporter : StreamingReporterBase { + + using StreamingReporterBase::StreamingReporterBase; + + ~CompactReporter() override; + + static std::string getDescription(); + + ReporterPreferences getPreferences() const override; + + void noMatchingTestCases(std::string const& spec) override; + + void assertionStarting(AssertionInfo const&) override; + + bool assertionEnded(AssertionStats const& _assertionStats) override; + + void sectionEnded(SectionStats const& _sectionStats) override; + + void testRunEnded(TestRunStats const& _testRunStats) override; + + }; + +} // end namespace Catch + +// end catch_reporter_compact.h +// start catch_reporter_console.h + +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable:4061) // Not all labels are EXPLICITLY handled in switch + // Note that 4062 (not all labels are handled + // and default is missing) is enabled +#endif + +namespace Catch { + // Fwd decls + struct SummaryColumn; + class TablePrinter; + + struct ConsoleReporter : StreamingReporterBase { + std::unique_ptr m_tablePrinter; + + ConsoleReporter(ReporterConfig const& config); + ~ConsoleReporter() override; + static std::string getDescription(); + + void noMatchingTestCases(std::string const& spec) override; + + void assertionStarting(AssertionInfo const&) override; + + bool assertionEnded(AssertionStats const& _assertionStats) override; + + void sectionStarting(SectionInfo const& _sectionInfo) override; + void sectionEnded(SectionStats const& _sectionStats) override; + + void benchmarkStarting(BenchmarkInfo const& info) override; + void benchmarkEnded(BenchmarkStats const& stats) override; + + void testCaseEnded(TestCaseStats const& _testCaseStats) override; + void testGroupEnded(TestGroupStats const& _testGroupStats) override; + void testRunEnded(TestRunStats const& _testRunStats) override; + + private: + + void lazyPrint(); + + void lazyPrintWithoutClosingBenchmarkTable(); + void lazyPrintRunInfo(); + void lazyPrintGroupInfo(); + void printTestCaseAndSectionHeader(); + + void printClosedHeader(std::string const& _name); + void printOpenHeader(std::string const& _name); + + // if string has a : in first line will set indent to follow it on + // subsequent lines + void printHeaderString(std::string const& _string, std::size_t indent = 0); + + void printTotals(Totals const& totals); + void printSummaryRow(std::string const& label, std::vector const& cols, std::size_t row); + + void printTotalsDivider(Totals const& totals); + void printSummaryDivider(); + + private: + bool m_headerPrinted = false; + }; + +} // end namespace Catch + +#if defined(_MSC_VER) +#pragma warning(pop) +#endif + +// end catch_reporter_console.h +// start catch_reporter_junit.h + +// start catch_xmlwriter.h + +#include + +namespace Catch { + + class XmlEncode { + public: + enum ForWhat { ForTextNodes, ForAttributes }; + + XmlEncode( std::string const& str, ForWhat forWhat = ForTextNodes ); + + void encodeTo( std::ostream& os ) const; + + friend std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ); + + private: + std::string m_str; + ForWhat m_forWhat; + }; + + class XmlWriter { + public: + + class ScopedElement { + public: + ScopedElement( XmlWriter* writer ); + + ScopedElement( ScopedElement&& other ) noexcept; + ScopedElement& operator=( ScopedElement&& other ) noexcept; + + ~ScopedElement(); + + ScopedElement& writeText( std::string const& text, bool indent = true ); + + template + ScopedElement& writeAttribute( std::string const& name, T const& attribute ) { + m_writer->writeAttribute( name, attribute ); + return *this; + } + + private: + mutable XmlWriter* m_writer = nullptr; + }; + + XmlWriter( std::ostream& os = Catch::cout() ); + ~XmlWriter(); + + XmlWriter( XmlWriter const& ) = delete; + XmlWriter& operator=( XmlWriter const& ) = delete; + + XmlWriter& startElement( std::string const& name ); + + ScopedElement scopedElement( std::string const& name ); + + XmlWriter& endElement(); + + XmlWriter& writeAttribute( std::string const& name, std::string const& attribute ); + + XmlWriter& writeAttribute( std::string const& name, bool attribute ); + + template + XmlWriter& writeAttribute( std::string const& name, T const& attribute ) { + ReusableStringStream rss; + rss << attribute; + return writeAttribute( name, rss.str() ); + } + + XmlWriter& writeText( std::string const& text, bool indent = true ); + + XmlWriter& writeComment( std::string const& text ); + + void writeStylesheetRef( std::string const& url ); + + XmlWriter& writeBlankLine(); + + void ensureTagClosed(); + + private: + + void writeDeclaration(); + + void newlineIfNecessary(); + + bool m_tagIsOpen = false; + bool m_needsNewline = false; + std::vector m_tags; + std::string m_indent; + std::ostream& m_os; + }; + +} + +// end catch_xmlwriter.h +namespace Catch { + + class JunitReporter : public CumulativeReporterBase { + public: + JunitReporter(ReporterConfig const& _config); + + ~JunitReporter() override; + + static std::string getDescription(); + + void noMatchingTestCases(std::string const& /*spec*/) override; + + void testRunStarting(TestRunInfo const& runInfo) override; + + void testGroupStarting(GroupInfo const& groupInfo) override; + + void testCaseStarting(TestCaseInfo const& testCaseInfo) override; + bool assertionEnded(AssertionStats const& assertionStats) override; + + void testCaseEnded(TestCaseStats const& testCaseStats) override; + + void testGroupEnded(TestGroupStats const& testGroupStats) override; + + void testRunEndedCumulative() override; + + void writeGroup(TestGroupNode const& groupNode, double suiteTime); + + void writeTestCase(TestCaseNode const& testCaseNode); + + void writeSection(std::string const& className, + std::string const& rootName, + SectionNode const& sectionNode); + + void writeAssertions(SectionNode const& sectionNode); + void writeAssertion(AssertionStats const& stats); + + XmlWriter xml; + Timer suiteTimer; + std::string stdOutForSuite; + std::string stdErrForSuite; + unsigned int unexpectedExceptions = 0; + bool m_okToFail = false; + }; + +} // end namespace Catch + +// end catch_reporter_junit.h +// start catch_reporter_xml.h + +namespace Catch { + class XmlReporter : public StreamingReporterBase { + public: + XmlReporter(ReporterConfig const& _config); + + ~XmlReporter() override; + + static std::string getDescription(); + + virtual std::string getStylesheetRef() const; + + void writeSourceInfo(SourceLineInfo const& sourceInfo); + + public: // StreamingReporterBase + + void noMatchingTestCases(std::string const& s) override; + + void testRunStarting(TestRunInfo const& testInfo) override; + + void testGroupStarting(GroupInfo const& groupInfo) override; + + void testCaseStarting(TestCaseInfo const& testInfo) override; + + void sectionStarting(SectionInfo const& sectionInfo) override; + + void assertionStarting(AssertionInfo const&) override; + + bool assertionEnded(AssertionStats const& assertionStats) override; + + void sectionEnded(SectionStats const& sectionStats) override; + + void testCaseEnded(TestCaseStats const& testCaseStats) override; + + void testGroupEnded(TestGroupStats const& testGroupStats) override; + + void testRunEnded(TestRunStats const& testRunStats) override; + + private: + Timer m_testCaseTimer; + XmlWriter m_xml; + int m_sectionDepth = 0; + }; + +} // end namespace Catch + +// end catch_reporter_xml.h + +// end catch_external_interfaces.h +#endif + +#endif // ! CATCH_CONFIG_IMPL_ONLY + +#ifdef CATCH_IMPL +// start catch_impl.hpp + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wweak-vtables" +#endif + +// Keep these here for external reporters +// start catch_test_case_tracker.h + +#include +#include +#include + +namespace Catch { +namespace TestCaseTracking { + + struct NameAndLocation { + std::string name; + SourceLineInfo location; + + NameAndLocation( std::string const& _name, SourceLineInfo const& _location ); + }; + + struct ITracker; + + using ITrackerPtr = std::shared_ptr; + + struct ITracker { + virtual ~ITracker(); + + // static queries + virtual NameAndLocation const& nameAndLocation() const = 0; + + // dynamic queries + virtual bool isComplete() const = 0; // Successfully completed or failed + virtual bool isSuccessfullyCompleted() const = 0; + virtual bool isOpen() const = 0; // Started but not complete + virtual bool hasChildren() const = 0; + + virtual ITracker& parent() = 0; + + // actions + virtual void close() = 0; // Successfully complete + virtual void fail() = 0; + virtual void markAsNeedingAnotherRun() = 0; + + virtual void addChild( ITrackerPtr const& child ) = 0; + virtual ITrackerPtr findChild( NameAndLocation const& nameAndLocation ) = 0; + virtual void openChild() = 0; + + // Debug/ checking + virtual bool isSectionTracker() const = 0; + virtual bool isIndexTracker() const = 0; + }; + + class TrackerContext { + + enum RunState { + NotStarted, + Executing, + CompletedCycle + }; + + ITrackerPtr m_rootTracker; + ITracker* m_currentTracker = nullptr; + RunState m_runState = NotStarted; + + public: + + static TrackerContext& instance(); + + ITracker& startRun(); + void endRun(); + + void startCycle(); + void completeCycle(); + + bool completedCycle() const; + ITracker& currentTracker(); + void setCurrentTracker( ITracker* tracker ); + }; + + class TrackerBase : public ITracker { + protected: + enum CycleState { + NotStarted, + Executing, + ExecutingChildren, + NeedsAnotherRun, + CompletedSuccessfully, + Failed + }; + + class TrackerHasName { + NameAndLocation m_nameAndLocation; + public: + TrackerHasName( NameAndLocation const& nameAndLocation ); + bool operator ()( ITrackerPtr const& tracker ) const; + }; + + using Children = std::vector; + NameAndLocation m_nameAndLocation; + TrackerContext& m_ctx; + ITracker* m_parent; + Children m_children; + CycleState m_runState = NotStarted; + + public: + TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ); + + NameAndLocation const& nameAndLocation() const override; + bool isComplete() const override; + bool isSuccessfullyCompleted() const override; + bool isOpen() const override; + bool hasChildren() const override; + + void addChild( ITrackerPtr const& child ) override; + + ITrackerPtr findChild( NameAndLocation const& nameAndLocation ) override; + ITracker& parent() override; + + void openChild() override; + + bool isSectionTracker() const override; + bool isIndexTracker() const override; + + void open(); + + void close() override; + void fail() override; + void markAsNeedingAnotherRun() override; + + private: + void moveToParent(); + void moveToThis(); + }; + + class SectionTracker : public TrackerBase { + std::vector m_filters; + public: + SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ); + + bool isSectionTracker() const override; + + static SectionTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation ); + + void tryOpen(); + + void addInitialFilters( std::vector const& filters ); + void addNextFilters( std::vector const& filters ); + }; + + class IndexTracker : public TrackerBase { + int m_size; + int m_index = -1; + public: + IndexTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent, int size ); + + bool isIndexTracker() const override; + void close() override; + + static IndexTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation, int size ); + + int index() const; + + void moveNext(); + }; + +} // namespace TestCaseTracking + +using TestCaseTracking::ITracker; +using TestCaseTracking::TrackerContext; +using TestCaseTracking::SectionTracker; +using TestCaseTracking::IndexTracker; + +} // namespace Catch + +// end catch_test_case_tracker.h + +// start catch_leak_detector.h + +namespace Catch { + + struct LeakDetector { + LeakDetector(); + }; + +} +// end catch_leak_detector.h +// Cpp files will be included in the single-header file here +// start catch_approx.cpp + +#include +#include + +namespace { + +// Performs equivalent check of std::fabs(lhs - rhs) <= margin +// But without the subtraction to allow for INFINITY in comparison +bool marginComparison(double lhs, double rhs, double margin) { + return (lhs + margin >= rhs) && (rhs + margin >= lhs); +} + +} + +namespace Catch { +namespace Detail { + + Approx::Approx ( double value ) + : m_epsilon( std::numeric_limits::epsilon()*100 ), + m_margin( 0.0 ), + m_scale( 0.0 ), + m_value( value ) + {} + + Approx Approx::custom() { + return Approx( 0 ); + } + + Approx Approx::operator-() const { + auto temp(*this); + temp.m_value = -temp.m_value; + return temp; + } + + std::string Approx::toString() const { + ReusableStringStream rss; + rss << "Approx( " << ::Catch::Detail::stringify( m_value ) << " )"; + return rss.str(); + } + + bool Approx::equalityComparisonImpl(const double other) const { + // First try with fixed margin, then compute margin based on epsilon, scale and Approx's value + // Thanks to Richard Harris for his help refining the scaled margin value + return marginComparison(m_value, other, m_margin) || marginComparison(m_value, other, m_epsilon * (m_scale + std::fabs(m_value))); + } + +} // end namespace Detail + +namespace literals { + Detail::Approx operator "" _a(long double val) { + return Detail::Approx(val); + } + Detail::Approx operator "" _a(unsigned long long val) { + return Detail::Approx(val); + } +} // end namespace literals + +std::string StringMaker::convert(Catch::Detail::Approx const& value) { + return value.toString(); +} + +} // end namespace Catch +// end catch_approx.cpp +// start catch_assertionhandler.cpp + +// start catch_context.h + +#include + +namespace Catch { + + struct IResultCapture; + struct IRunner; + struct IConfig; + struct IMutableContext; + + using IConfigPtr = std::shared_ptr; + + struct IContext + { + virtual ~IContext(); + + virtual IResultCapture* getResultCapture() = 0; + virtual IRunner* getRunner() = 0; + virtual IConfigPtr const& getConfig() const = 0; + }; + + struct IMutableContext : IContext + { + virtual ~IMutableContext(); + virtual void setResultCapture( IResultCapture* resultCapture ) = 0; + virtual void setRunner( IRunner* runner ) = 0; + virtual void setConfig( IConfigPtr const& config ) = 0; + + private: + static IMutableContext *currentContext; + friend IMutableContext& getCurrentMutableContext(); + friend void cleanUpContext(); + static void createContext(); + }; + + inline IMutableContext& getCurrentMutableContext() + { + if( !IMutableContext::currentContext ) + IMutableContext::createContext(); + return *IMutableContext::currentContext; + } + + inline IContext& getCurrentContext() + { + return getCurrentMutableContext(); + } + + void cleanUpContext(); +} + +// end catch_context.h +// start catch_debugger.h + +namespace Catch { + bool isDebuggerActive(); +} + +#ifdef CATCH_PLATFORM_MAC + + #define CATCH_TRAP() __asm__("int $3\n" : : ) /* NOLINT */ + +#elif defined(CATCH_PLATFORM_LINUX) + // If we can use inline assembler, do it because this allows us to break + // directly at the location of the failing check instead of breaking inside + // raise() called from it, i.e. one stack frame below. + #if defined(__GNUC__) && (defined(__i386) || defined(__x86_64)) + #define CATCH_TRAP() asm volatile ("int $3") /* NOLINT */ + #else // Fall back to the generic way. + #include + + #define CATCH_TRAP() raise(SIGTRAP) + #endif +#elif defined(_MSC_VER) + #define CATCH_TRAP() __debugbreak() +#elif defined(__MINGW32__) + extern "C" __declspec(dllimport) void __stdcall DebugBreak(); + #define CATCH_TRAP() DebugBreak() +#endif + +#ifdef CATCH_TRAP + #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { CATCH_TRAP(); } +#else + namespace Catch { + inline void doNothing() {} + } + #define CATCH_BREAK_INTO_DEBUGGER() Catch::doNothing() +#endif + +// end catch_debugger.h +// start catch_run_context.h + +// start catch_fatal_condition.h + +// start catch_windows_h_proxy.h + + +#if defined(CATCH_PLATFORM_WINDOWS) + +#if !defined(NOMINMAX) && !defined(CATCH_CONFIG_NO_NOMINMAX) +# define CATCH_DEFINED_NOMINMAX +# define NOMINMAX +#endif +#if !defined(WIN32_LEAN_AND_MEAN) && !defined(CATCH_CONFIG_NO_WIN32_LEAN_AND_MEAN) +# define CATCH_DEFINED_WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +#endif + +#ifdef __AFXDLL +#include +#else +#include +#endif + +#ifdef CATCH_DEFINED_NOMINMAX +# undef NOMINMAX +#endif +#ifdef CATCH_DEFINED_WIN32_LEAN_AND_MEAN +# undef WIN32_LEAN_AND_MEAN +#endif + +#endif // defined(CATCH_PLATFORM_WINDOWS) + +// end catch_windows_h_proxy.h +#if defined( CATCH_CONFIG_WINDOWS_SEH ) + +namespace Catch { + + struct FatalConditionHandler { + + static LONG CALLBACK handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo); + FatalConditionHandler(); + static void reset(); + ~FatalConditionHandler(); + + private: + static bool isSet; + static ULONG guaranteeSize; + static PVOID exceptionHandlerHandle; + }; + +} // namespace Catch + +#elif defined ( CATCH_CONFIG_POSIX_SIGNALS ) + +#include + +namespace Catch { + + struct FatalConditionHandler { + + static bool isSet; + static struct sigaction oldSigActions[]; + static stack_t oldSigStack; + static char altStackMem[]; + + static void handleSignal( int sig ); + + FatalConditionHandler(); + ~FatalConditionHandler(); + static void reset(); + }; + +} // namespace Catch + +#else + +namespace Catch { + struct FatalConditionHandler { + void reset(); + }; +} + +#endif + +// end catch_fatal_condition.h +#include + +namespace Catch { + + struct IMutableContext; + + /////////////////////////////////////////////////////////////////////////// + + class RunContext : public IResultCapture, public IRunner { + + public: + RunContext( RunContext const& ) = delete; + RunContext& operator =( RunContext const& ) = delete; + + explicit RunContext( IConfigPtr const& _config, IStreamingReporterPtr&& reporter ); + + ~RunContext() override; + + void testGroupStarting( std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount ); + void testGroupEnded( std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount ); + + Totals runTest(TestCase const& testCase); + + IConfigPtr config() const; + IStreamingReporter& reporter() const; + + public: // IResultCapture + + // Assertion handlers + void handleExpr + ( AssertionInfo const& info, + ITransientExpression const& expr, + AssertionReaction& reaction ) override; + void handleMessage + ( AssertionInfo const& info, + ResultWas::OfType resultType, + StringRef const& message, + AssertionReaction& reaction ) override; + void handleUnexpectedExceptionNotThrown + ( AssertionInfo const& info, + AssertionReaction& reaction ) override; + void handleUnexpectedInflightException + ( AssertionInfo const& info, + std::string const& message, + AssertionReaction& reaction ) override; + void handleIncomplete + ( AssertionInfo const& info ) override; + void handleNonExpr + ( AssertionInfo const &info, + ResultWas::OfType resultType, + AssertionReaction &reaction ) override; + + bool sectionStarted( SectionInfo const& sectionInfo, Counts& assertions ) override; + + void sectionEnded( SectionEndInfo const& endInfo ) override; + void sectionEndedEarly( SectionEndInfo const& endInfo ) override; + + void benchmarkStarting( BenchmarkInfo const& info ) override; + void benchmarkEnded( BenchmarkStats const& stats ) override; + + void pushScopedMessage( MessageInfo const& message ) override; + void popScopedMessage( MessageInfo const& message ) override; + + std::string getCurrentTestName() const override; + + const AssertionResult* getLastResult() const override; + + void exceptionEarlyReported() override; + + void handleFatalErrorCondition( StringRef message ) override; + + bool lastAssertionPassed() override; + + void assertionPassed() override; + + public: + // !TBD We need to do this another way! + bool aborting() const final; + + private: + + void runCurrentTest( std::string& redirectedCout, std::string& redirectedCerr ); + void invokeActiveTestCase(); + + void resetAssertionInfo(); + bool testForMissingAssertions( Counts& assertions ); + + void assertionEnded( AssertionResult const& result ); + void reportExpr + ( AssertionInfo const &info, + ResultWas::OfType resultType, + ITransientExpression const *expr, + bool negated ); + + void populateReaction( AssertionReaction& reaction ); + + private: + + void handleUnfinishedSections(); + + TestRunInfo m_runInfo; + IMutableContext& m_context; + TestCase const* m_activeTestCase = nullptr; + ITracker* m_testCaseTracker; + Option m_lastResult; + + IConfigPtr m_config; + Totals m_totals; + IStreamingReporterPtr m_reporter; + std::vector m_messages; + AssertionInfo m_lastAssertionInfo; + std::vector m_unfinishedSections; + std::vector m_activeSections; + TrackerContext m_trackerContext; + bool m_lastAssertionPassed = false; + bool m_shouldReportUnexpected = true; + bool m_includeSuccessfulResults; + }; + +} // end namespace Catch + +// end catch_run_context.h +namespace Catch { + + namespace { + auto operator <<( std::ostream& os, ITransientExpression const& expr ) -> std::ostream& { + expr.streamReconstructedExpression( os ); + return os; + } + } + + LazyExpression::LazyExpression( bool isNegated ) + : m_isNegated( isNegated ) + {} + + LazyExpression::LazyExpression( LazyExpression const& other ) : m_isNegated( other.m_isNegated ) {} + + LazyExpression::operator bool() const { + return m_transientExpression != nullptr; + } + + auto operator << ( std::ostream& os, LazyExpression const& lazyExpr ) -> std::ostream& { + if( lazyExpr.m_isNegated ) + os << "!"; + + if( lazyExpr ) { + if( lazyExpr.m_isNegated && lazyExpr.m_transientExpression->isBinaryExpression() ) + os << "(" << *lazyExpr.m_transientExpression << ")"; + else + os << *lazyExpr.m_transientExpression; + } + else { + os << "{** error - unchecked empty expression requested **}"; + } + return os; + } + + AssertionHandler::AssertionHandler + ( StringRef macroName, + SourceLineInfo const& lineInfo, + StringRef capturedExpression, + ResultDisposition::Flags resultDisposition ) + : m_assertionInfo{ macroName, lineInfo, capturedExpression, resultDisposition }, + m_resultCapture( getResultCapture() ) + {} + + void AssertionHandler::handleExpr( ITransientExpression const& expr ) { + m_resultCapture.handleExpr( m_assertionInfo, expr, m_reaction ); + } + void AssertionHandler::handleMessage(ResultWas::OfType resultType, StringRef const& message) { + m_resultCapture.handleMessage( m_assertionInfo, resultType, message, m_reaction ); + } + + auto AssertionHandler::allowThrows() const -> bool { + return getCurrentContext().getConfig()->allowThrows(); + } + + void AssertionHandler::complete() { + setCompleted(); + if( m_reaction.shouldDebugBreak ) { + + // If you find your debugger stopping you here then go one level up on the + // call-stack for the code that caused it (typically a failed assertion) + + // (To go back to the test and change execution, jump over the throw, next) + CATCH_BREAK_INTO_DEBUGGER(); + } + if( m_reaction.shouldThrow ) + throw Catch::TestFailureException(); + } + void AssertionHandler::setCompleted() { + m_completed = true; + } + + void AssertionHandler::handleUnexpectedInflightException() { + m_resultCapture.handleUnexpectedInflightException( m_assertionInfo, Catch::translateActiveException(), m_reaction ); + } + + void AssertionHandler::handleExceptionThrownAsExpected() { + m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction); + } + void AssertionHandler::handleExceptionNotThrownAsExpected() { + m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction); + } + + void AssertionHandler::handleUnexpectedExceptionNotThrown() { + m_resultCapture.handleUnexpectedExceptionNotThrown( m_assertionInfo, m_reaction ); + } + + void AssertionHandler::handleThrowingCallSkipped() { + m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction); + } + + // This is the overload that takes a string and infers the Equals matcher from it + // The more general overload, that takes any string matcher, is in catch_capture_matchers.cpp + void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef matcherString ) { + handleExceptionMatchExpr( handler, Matchers::Equals( str ), matcherString ); + } + +} // namespace Catch +// end catch_assertionhandler.cpp +// start catch_assertionresult.cpp + +namespace Catch { + AssertionResultData::AssertionResultData(ResultWas::OfType _resultType, LazyExpression const & _lazyExpression): + lazyExpression(_lazyExpression), + resultType(_resultType) {} + + std::string AssertionResultData::reconstructExpression() const { + + if( reconstructedExpression.empty() ) { + if( lazyExpression ) { + ReusableStringStream rss; + rss << lazyExpression; + reconstructedExpression = rss.str(); + } + } + return reconstructedExpression; + } + + AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData const& data ) + : m_info( info ), + m_resultData( data ) + {} + + // Result was a success + bool AssertionResult::succeeded() const { + return Catch::isOk( m_resultData.resultType ); + } + + // Result was a success, or failure is suppressed + bool AssertionResult::isOk() const { + return Catch::isOk( m_resultData.resultType ) || shouldSuppressFailure( m_info.resultDisposition ); + } + + ResultWas::OfType AssertionResult::getResultType() const { + return m_resultData.resultType; + } + + bool AssertionResult::hasExpression() const { + return m_info.capturedExpression[0] != 0; + } + + bool AssertionResult::hasMessage() const { + return !m_resultData.message.empty(); + } + + std::string AssertionResult::getExpression() const { + if( isFalseTest( m_info.resultDisposition ) ) + return "!(" + m_info.capturedExpression + ")"; + else + return m_info.capturedExpression; + } + + std::string AssertionResult::getExpressionInMacro() const { + std::string expr; + if( m_info.macroName[0] == 0 ) + expr = m_info.capturedExpression; + else { + expr.reserve( m_info.macroName.size() + m_info.capturedExpression.size() + 4 ); + expr += m_info.macroName; + expr += "( "; + expr += m_info.capturedExpression; + expr += " )"; + } + return expr; + } + + bool AssertionResult::hasExpandedExpression() const { + return hasExpression() && getExpandedExpression() != getExpression(); + } + + std::string AssertionResult::getExpandedExpression() const { + std::string expr = m_resultData.reconstructExpression(); + return expr.empty() + ? getExpression() + : expr; + } + + std::string AssertionResult::getMessage() const { + return m_resultData.message; + } + SourceLineInfo AssertionResult::getSourceInfo() const { + return m_info.lineInfo; + } + + StringRef AssertionResult::getTestMacroName() const { + return m_info.macroName; + } + +} // end namespace Catch +// end catch_assertionresult.cpp +// start catch_benchmark.cpp + +namespace Catch { + + auto BenchmarkLooper::getResolution() -> uint64_t { + return getEstimatedClockResolution() * getCurrentContext().getConfig()->benchmarkResolutionMultiple(); + } + + void BenchmarkLooper::reportStart() { + getResultCapture().benchmarkStarting( { m_name } ); + } + auto BenchmarkLooper::needsMoreIterations() -> bool { + auto elapsed = m_timer.getElapsedNanoseconds(); + + // Exponentially increasing iterations until we're confident in our timer resolution + if( elapsed < m_resolution ) { + m_iterationsToRun *= 10; + return true; + } + + getResultCapture().benchmarkEnded( { { m_name }, m_count, elapsed } ); + return false; + } + +} // end namespace Catch +// end catch_benchmark.cpp +// start catch_capture_matchers.cpp + +namespace Catch { + + using StringMatcher = Matchers::Impl::MatcherBase; + + // This is the general overload that takes a any string matcher + // There is another overload, in catch_assertionhandler.h/.cpp, that only takes a string and infers + // the Equals matcher (so the header does not mention matchers) + void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef matcherString ) { + std::string exceptionMessage = Catch::translateActiveException(); + MatchExpr expr( exceptionMessage, matcher, matcherString ); + handler.handleExpr( expr ); + } + +} // namespace Catch +// end catch_capture_matchers.cpp +// start catch_commandline.cpp + +// start catch_commandline.h + +// start catch_clara.h + +// Use Catch's value for console width (store Clara's off to the side, if present) +#ifdef CLARA_CONFIG_CONSOLE_WIDTH +#define CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH +#undef CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH +#endif +#define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH-1 + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wweak-vtables" +#pragma clang diagnostic ignored "-Wexit-time-destructors" +#pragma clang diagnostic ignored "-Wshadow" +#endif + +// start clara.hpp +// Copyright 2017 Two Blue Cubes Ltd. All rights reserved. +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See https://github.com/philsquared/Clara for more details + +// Clara v1.1.4 + + +#ifndef CATCH_CLARA_CONFIG_CONSOLE_WIDTH +#define CATCH_CLARA_CONFIG_CONSOLE_WIDTH 80 +#endif + +#ifndef CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH +#define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CATCH_CLARA_CONFIG_CONSOLE_WIDTH +#endif + +#ifndef CLARA_CONFIG_OPTIONAL_TYPE +#ifdef __has_include +#if __has_include() && __cplusplus >= 201703L +#include +#define CLARA_CONFIG_OPTIONAL_TYPE std::optional +#endif +#endif +#endif + +// ----------- #included from clara_textflow.hpp ----------- + +// TextFlowCpp +// +// A single-header library for wrapping and laying out basic text, by Phil Nash +// +// This work is licensed under the BSD 2-Clause license. +// See the accompanying LICENSE file, or the one at https://opensource.org/licenses/BSD-2-Clause +// +// This project is hosted at https://github.com/philsquared/textflowcpp + + +#include +#include +#include +#include + +#ifndef CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH +#define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH 80 +#endif + +namespace Catch { namespace clara { namespace TextFlow { + + inline auto isWhitespace( char c ) -> bool { + static std::string chars = " \t\n\r"; + return chars.find( c ) != std::string::npos; + } + inline auto isBreakableBefore( char c ) -> bool { + static std::string chars = "[({<|"; + return chars.find( c ) != std::string::npos; + } + inline auto isBreakableAfter( char c ) -> bool { + static std::string chars = "])}>.,:;*+-=&/\\"; + return chars.find( c ) != std::string::npos; + } + + class Columns; + + class Column { + std::vector m_strings; + size_t m_width = CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH; + size_t m_indent = 0; + size_t m_initialIndent = std::string::npos; + + public: + class iterator { + friend Column; + + Column const& m_column; + size_t m_stringIndex = 0; + size_t m_pos = 0; + + size_t m_len = 0; + size_t m_end = 0; + bool m_suffix = false; + + iterator( Column const& column, size_t stringIndex ) + : m_column( column ), + m_stringIndex( stringIndex ) + {} + + auto line() const -> std::string const& { return m_column.m_strings[m_stringIndex]; } + + auto isBoundary( size_t at ) const -> bool { + assert( at > 0 ); + assert( at <= line().size() ); + + return at == line().size() || + ( isWhitespace( line()[at] ) && !isWhitespace( line()[at-1] ) ) || + isBreakableBefore( line()[at] ) || + isBreakableAfter( line()[at-1] ); + } + + void calcLength() { + assert( m_stringIndex < m_column.m_strings.size() ); + + m_suffix = false; + auto width = m_column.m_width-indent(); + m_end = m_pos; + while( m_end < line().size() && line()[m_end] != '\n' ) + ++m_end; + + if( m_end < m_pos + width ) { + m_len = m_end - m_pos; + } + else { + size_t len = width; + while (len > 0 && !isBoundary(m_pos + len)) + --len; + while (len > 0 && isWhitespace( line()[m_pos + len - 1] )) + --len; + + if (len > 0) { + m_len = len; + } else { + m_suffix = true; + m_len = width - 1; + } + } + } + + auto indent() const -> size_t { + auto initial = m_pos == 0 && m_stringIndex == 0 ? m_column.m_initialIndent : std::string::npos; + return initial == std::string::npos ? m_column.m_indent : initial; + } + + auto addIndentAndSuffix(std::string const &plain) const -> std::string { + return std::string( indent(), ' ' ) + (m_suffix ? plain + "-" : plain); + } + + public: + explicit iterator( Column const& column ) : m_column( column ) { + assert( m_column.m_width > m_column.m_indent ); + assert( m_column.m_initialIndent == std::string::npos || m_column.m_width > m_column.m_initialIndent ); + calcLength(); + if( m_len == 0 ) + m_stringIndex++; // Empty string + } + + auto operator *() const -> std::string { + assert( m_stringIndex < m_column.m_strings.size() ); + assert( m_pos <= m_end ); + if( m_pos + m_column.m_width < m_end ) + return addIndentAndSuffix(line().substr(m_pos, m_len)); + else + return addIndentAndSuffix(line().substr(m_pos, m_end - m_pos)); + } + + auto operator ++() -> iterator& { + m_pos += m_len; + if( m_pos < line().size() && line()[m_pos] == '\n' ) + m_pos += 1; + else + while( m_pos < line().size() && isWhitespace( line()[m_pos] ) ) + ++m_pos; + + if( m_pos == line().size() ) { + m_pos = 0; + ++m_stringIndex; + } + if( m_stringIndex < m_column.m_strings.size() ) + calcLength(); + return *this; + } + auto operator ++(int) -> iterator { + iterator prev( *this ); + operator++(); + return prev; + } + + auto operator ==( iterator const& other ) const -> bool { + return + m_pos == other.m_pos && + m_stringIndex == other.m_stringIndex && + &m_column == &other.m_column; + } + auto operator !=( iterator const& other ) const -> bool { + return !operator==( other ); + } + }; + using const_iterator = iterator; + + explicit Column( std::string const& text ) { m_strings.push_back( text ); } + + auto width( size_t newWidth ) -> Column& { + assert( newWidth > 0 ); + m_width = newWidth; + return *this; + } + auto indent( size_t newIndent ) -> Column& { + m_indent = newIndent; + return *this; + } + auto initialIndent( size_t newIndent ) -> Column& { + m_initialIndent = newIndent; + return *this; + } + + auto width() const -> size_t { return m_width; } + auto begin() const -> iterator { return iterator( *this ); } + auto end() const -> iterator { return { *this, m_strings.size() }; } + + inline friend std::ostream& operator << ( std::ostream& os, Column const& col ) { + bool first = true; + for( auto line : col ) { + if( first ) + first = false; + else + os << "\n"; + os << line; + } + return os; + } + + auto operator + ( Column const& other ) -> Columns; + + auto toString() const -> std::string { + std::ostringstream oss; + oss << *this; + return oss.str(); + } + }; + + class Spacer : public Column { + + public: + explicit Spacer( size_t spaceWidth ) : Column( "" ) { + width( spaceWidth ); + } + }; + + class Columns { + std::vector m_columns; + + public: + + class iterator { + friend Columns; + struct EndTag {}; + + std::vector const& m_columns; + std::vector m_iterators; + size_t m_activeIterators; + + iterator( Columns const& columns, EndTag ) + : m_columns( columns.m_columns ), + m_activeIterators( 0 ) + { + m_iterators.reserve( m_columns.size() ); + + for( auto const& col : m_columns ) + m_iterators.push_back( col.end() ); + } + + public: + explicit iterator( Columns const& columns ) + : m_columns( columns.m_columns ), + m_activeIterators( m_columns.size() ) + { + m_iterators.reserve( m_columns.size() ); + + for( auto const& col : m_columns ) + m_iterators.push_back( col.begin() ); + } + + auto operator ==( iterator const& other ) const -> bool { + return m_iterators == other.m_iterators; + } + auto operator !=( iterator const& other ) const -> bool { + return m_iterators != other.m_iterators; + } + auto operator *() const -> std::string { + std::string row, padding; + + for( size_t i = 0; i < m_columns.size(); ++i ) { + auto width = m_columns[i].width(); + if( m_iterators[i] != m_columns[i].end() ) { + std::string col = *m_iterators[i]; + row += padding + col; + if( col.size() < width ) + padding = std::string( width - col.size(), ' ' ); + else + padding = ""; + } + else { + padding += std::string( width, ' ' ); + } + } + return row; + } + auto operator ++() -> iterator& { + for( size_t i = 0; i < m_columns.size(); ++i ) { + if (m_iterators[i] != m_columns[i].end()) + ++m_iterators[i]; + } + return *this; + } + auto operator ++(int) -> iterator { + iterator prev( *this ); + operator++(); + return prev; + } + }; + using const_iterator = iterator; + + auto begin() const -> iterator { return iterator( *this ); } + auto end() const -> iterator { return { *this, iterator::EndTag() }; } + + auto operator += ( Column const& col ) -> Columns& { + m_columns.push_back( col ); + return *this; + } + auto operator + ( Column const& col ) -> Columns { + Columns combined = *this; + combined += col; + return combined; + } + + inline friend std::ostream& operator << ( std::ostream& os, Columns const& cols ) { + + bool first = true; + for( auto line : cols ) { + if( first ) + first = false; + else + os << "\n"; + os << line; + } + return os; + } + + auto toString() const -> std::string { + std::ostringstream oss; + oss << *this; + return oss.str(); + } + }; + + inline auto Column::operator + ( Column const& other ) -> Columns { + Columns cols; + cols += *this; + cols += other; + return cols; + } +}}} // namespace Catch::clara::TextFlow + +// ----------- end of #include from clara_textflow.hpp ----------- +// ........... back in clara.hpp + +#include +#include +#include + +#if !defined(CATCH_PLATFORM_WINDOWS) && ( defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) ) +#define CATCH_PLATFORM_WINDOWS +#endif + +namespace Catch { namespace clara { +namespace detail { + + // Traits for extracting arg and return type of lambdas (for single argument lambdas) + template + struct UnaryLambdaTraits : UnaryLambdaTraits {}; + + template + struct UnaryLambdaTraits { + static const bool isValid = false; + }; + + template + struct UnaryLambdaTraits { + static const bool isValid = true; + using ArgType = typename std::remove_const::type>::type; + using ReturnType = ReturnT; + }; + + class TokenStream; + + // Transport for raw args (copied from main args, or supplied via init list for testing) + class Args { + friend TokenStream; + std::string m_exeName; + std::vector m_args; + + public: + Args( int argc, char const* const* argv ) + : m_exeName(argv[0]), + m_args(argv + 1, argv + argc) {} + + Args( std::initializer_list args ) + : m_exeName( *args.begin() ), + m_args( args.begin()+1, args.end() ) + {} + + auto exeName() const -> std::string { + return m_exeName; + } + }; + + // Wraps a token coming from a token stream. These may not directly correspond to strings as a single string + // may encode an option + its argument if the : or = form is used + enum class TokenType { + Option, Argument + }; + struct Token { + TokenType type; + std::string token; + }; + + inline auto isOptPrefix( char c ) -> bool { + return c == '-' +#ifdef CATCH_PLATFORM_WINDOWS + || c == '/' +#endif + ; + } + + // Abstracts iterators into args as a stream of tokens, with option arguments uniformly handled + class TokenStream { + using Iterator = std::vector::const_iterator; + Iterator it; + Iterator itEnd; + std::vector m_tokenBuffer; + + void loadBuffer() { + m_tokenBuffer.resize( 0 ); + + // Skip any empty strings + while( it != itEnd && it->empty() ) + ++it; + + if( it != itEnd ) { + auto const &next = *it; + if( isOptPrefix( next[0] ) ) { + auto delimiterPos = next.find_first_of( " :=" ); + if( delimiterPos != std::string::npos ) { + m_tokenBuffer.push_back( { TokenType::Option, next.substr( 0, delimiterPos ) } ); + m_tokenBuffer.push_back( { TokenType::Argument, next.substr( delimiterPos + 1 ) } ); + } else { + if( next[1] != '-' && next.size() > 2 ) { + std::string opt = "- "; + for( size_t i = 1; i < next.size(); ++i ) { + opt[1] = next[i]; + m_tokenBuffer.push_back( { TokenType::Option, opt } ); + } + } else { + m_tokenBuffer.push_back( { TokenType::Option, next } ); + } + } + } else { + m_tokenBuffer.push_back( { TokenType::Argument, next } ); + } + } + } + + public: + explicit TokenStream( Args const &args ) : TokenStream( args.m_args.begin(), args.m_args.end() ) {} + + TokenStream( Iterator it, Iterator itEnd ) : it( it ), itEnd( itEnd ) { + loadBuffer(); + } + + explicit operator bool() const { + return !m_tokenBuffer.empty() || it != itEnd; + } + + auto count() const -> size_t { return m_tokenBuffer.size() + (itEnd - it); } + + auto operator*() const -> Token { + assert( !m_tokenBuffer.empty() ); + return m_tokenBuffer.front(); + } + + auto operator->() const -> Token const * { + assert( !m_tokenBuffer.empty() ); + return &m_tokenBuffer.front(); + } + + auto operator++() -> TokenStream & { + if( m_tokenBuffer.size() >= 2 ) { + m_tokenBuffer.erase( m_tokenBuffer.begin() ); + } else { + if( it != itEnd ) + ++it; + loadBuffer(); + } + return *this; + } + }; + + class ResultBase { + public: + enum Type { + Ok, LogicError, RuntimeError + }; + + protected: + ResultBase( Type type ) : m_type( type ) {} + virtual ~ResultBase() = default; + + virtual void enforceOk() const = 0; + + Type m_type; + }; + + template + class ResultValueBase : public ResultBase { + public: + auto value() const -> T const & { + enforceOk(); + return m_value; + } + + protected: + ResultValueBase( Type type ) : ResultBase( type ) {} + + ResultValueBase( ResultValueBase const &other ) : ResultBase( other ) { + if( m_type == ResultBase::Ok ) + new( &m_value ) T( other.m_value ); + } + + ResultValueBase( Type, T const &value ) : ResultBase( Ok ) { + new( &m_value ) T( value ); + } + + auto operator=( ResultValueBase const &other ) -> ResultValueBase & { + if( m_type == ResultBase::Ok ) + m_value.~T(); + ResultBase::operator=(other); + if( m_type == ResultBase::Ok ) + new( &m_value ) T( other.m_value ); + return *this; + } + + ~ResultValueBase() override { + if( m_type == Ok ) + m_value.~T(); + } + + union { + T m_value; + }; + }; + + template<> + class ResultValueBase : public ResultBase { + protected: + using ResultBase::ResultBase; + }; + + template + class BasicResult : public ResultValueBase { + public: + template + explicit BasicResult( BasicResult const &other ) + : ResultValueBase( other.type() ), + m_errorMessage( other.errorMessage() ) + { + assert( type() != ResultBase::Ok ); + } + + template + static auto ok( U const &value ) -> BasicResult { return { ResultBase::Ok, value }; } + static auto ok() -> BasicResult { return { ResultBase::Ok }; } + static auto logicError( std::string const &message ) -> BasicResult { return { ResultBase::LogicError, message }; } + static auto runtimeError( std::string const &message ) -> BasicResult { return { ResultBase::RuntimeError, message }; } + + explicit operator bool() const { return m_type == ResultBase::Ok; } + auto type() const -> ResultBase::Type { return m_type; } + auto errorMessage() const -> std::string { return m_errorMessage; } + + protected: + void enforceOk() const override { + + // Errors shouldn't reach this point, but if they do + // the actual error message will be in m_errorMessage + assert( m_type != ResultBase::LogicError ); + assert( m_type != ResultBase::RuntimeError ); + if( m_type != ResultBase::Ok ) + std::abort(); + } + + std::string m_errorMessage; // Only populated if resultType is an error + + BasicResult( ResultBase::Type type, std::string const &message ) + : ResultValueBase(type), + m_errorMessage(message) + { + assert( m_type != ResultBase::Ok ); + } + + using ResultValueBase::ResultValueBase; + using ResultBase::m_type; + }; + + enum class ParseResultType { + Matched, NoMatch, ShortCircuitAll, ShortCircuitSame + }; + + class ParseState { + public: + + ParseState( ParseResultType type, TokenStream const &remainingTokens ) + : m_type(type), + m_remainingTokens( remainingTokens ) + {} + + auto type() const -> ParseResultType { return m_type; } + auto remainingTokens() const -> TokenStream { return m_remainingTokens; } + + private: + ParseResultType m_type; + TokenStream m_remainingTokens; + }; + + using Result = BasicResult; + using ParserResult = BasicResult; + using InternalParseResult = BasicResult; + + struct HelpColumns { + std::string left; + std::string right; + }; + + template + inline auto convertInto( std::string const &source, T& target ) -> ParserResult { + std::stringstream ss; + ss << source; + ss >> target; + if( ss.fail() ) + return ParserResult::runtimeError( "Unable to convert '" + source + "' to destination type" ); + else + return ParserResult::ok( ParseResultType::Matched ); + } + inline auto convertInto( std::string const &source, std::string& target ) -> ParserResult { + target = source; + return ParserResult::ok( ParseResultType::Matched ); + } + inline auto convertInto( std::string const &source, bool &target ) -> ParserResult { + std::string srcLC = source; + std::transform( srcLC.begin(), srcLC.end(), srcLC.begin(), []( char c ) { return static_cast( ::tolower(c) ); } ); + if (srcLC == "y" || srcLC == "1" || srcLC == "true" || srcLC == "yes" || srcLC == "on") + target = true; + else if (srcLC == "n" || srcLC == "0" || srcLC == "false" || srcLC == "no" || srcLC == "off") + target = false; + else + return ParserResult::runtimeError( "Expected a boolean value but did not recognise: '" + source + "'" ); + return ParserResult::ok( ParseResultType::Matched ); + } +#ifdef CLARA_CONFIG_OPTIONAL_TYPE + template + inline auto convertInto( std::string const &source, CLARA_CONFIG_OPTIONAL_TYPE& target ) -> ParserResult { + T temp; + auto result = convertInto( source, temp ); + if( result ) + target = std::move(temp); + return result; + } +#endif // CLARA_CONFIG_OPTIONAL_TYPE + + struct NonCopyable { + NonCopyable() = default; + NonCopyable( NonCopyable const & ) = delete; + NonCopyable( NonCopyable && ) = delete; + NonCopyable &operator=( NonCopyable const & ) = delete; + NonCopyable &operator=( NonCopyable && ) = delete; + }; + + struct BoundRef : NonCopyable { + virtual ~BoundRef() = default; + virtual auto isContainer() const -> bool { return false; } + virtual auto isFlag() const -> bool { return false; } + }; + struct BoundValueRefBase : BoundRef { + virtual auto setValue( std::string const &arg ) -> ParserResult = 0; + }; + struct BoundFlagRefBase : BoundRef { + virtual auto setFlag( bool flag ) -> ParserResult = 0; + virtual auto isFlag() const -> bool { return true; } + }; + + template + struct BoundValueRef : BoundValueRefBase { + T &m_ref; + + explicit BoundValueRef( T &ref ) : m_ref( ref ) {} + + auto setValue( std::string const &arg ) -> ParserResult override { + return convertInto( arg, m_ref ); + } + }; + + template + struct BoundValueRef> : BoundValueRefBase { + std::vector &m_ref; + + explicit BoundValueRef( std::vector &ref ) : m_ref( ref ) {} + + auto isContainer() const -> bool override { return true; } + + auto setValue( std::string const &arg ) -> ParserResult override { + T temp; + auto result = convertInto( arg, temp ); + if( result ) + m_ref.push_back( temp ); + return result; + } + }; + + struct BoundFlagRef : BoundFlagRefBase { + bool &m_ref; + + explicit BoundFlagRef( bool &ref ) : m_ref( ref ) {} + + auto setFlag( bool flag ) -> ParserResult override { + m_ref = flag; + return ParserResult::ok( ParseResultType::Matched ); + } + }; + + template + struct LambdaInvoker { + static_assert( std::is_same::value, "Lambda must return void or clara::ParserResult" ); + + template + static auto invoke( L const &lambda, ArgType const &arg ) -> ParserResult { + return lambda( arg ); + } + }; + + template<> + struct LambdaInvoker { + template + static auto invoke( L const &lambda, ArgType const &arg ) -> ParserResult { + lambda( arg ); + return ParserResult::ok( ParseResultType::Matched ); + } + }; + + template + inline auto invokeLambda( L const &lambda, std::string const &arg ) -> ParserResult { + ArgType temp{}; + auto result = convertInto( arg, temp ); + return !result + ? result + : LambdaInvoker::ReturnType>::invoke( lambda, temp ); + } + + template + struct BoundLambda : BoundValueRefBase { + L m_lambda; + + static_assert( UnaryLambdaTraits::isValid, "Supplied lambda must take exactly one argument" ); + explicit BoundLambda( L const &lambda ) : m_lambda( lambda ) {} + + auto setValue( std::string const &arg ) -> ParserResult override { + return invokeLambda::ArgType>( m_lambda, arg ); + } + }; + + template + struct BoundFlagLambda : BoundFlagRefBase { + L m_lambda; + + static_assert( UnaryLambdaTraits::isValid, "Supplied lambda must take exactly one argument" ); + static_assert( std::is_same::ArgType, bool>::value, "flags must be boolean" ); + + explicit BoundFlagLambda( L const &lambda ) : m_lambda( lambda ) {} + + auto setFlag( bool flag ) -> ParserResult override { + return LambdaInvoker::ReturnType>::invoke( m_lambda, flag ); + } + }; + + enum class Optionality { Optional, Required }; + + struct Parser; + + class ParserBase { + public: + virtual ~ParserBase() = default; + virtual auto validate() const -> Result { return Result::ok(); } + virtual auto parse( std::string const& exeName, TokenStream const &tokens) const -> InternalParseResult = 0; + virtual auto cardinality() const -> size_t { return 1; } + + auto parse( Args const &args ) const -> InternalParseResult { + return parse( args.exeName(), TokenStream( args ) ); + } + }; + + template + class ComposableParserImpl : public ParserBase { + public: + template + auto operator|( T const &other ) const -> Parser; + + template + auto operator+( T const &other ) const -> Parser; + }; + + // Common code and state for Args and Opts + template + class ParserRefImpl : public ComposableParserImpl { + protected: + Optionality m_optionality = Optionality::Optional; + std::shared_ptr m_ref; + std::string m_hint; + std::string m_description; + + explicit ParserRefImpl( std::shared_ptr const &ref ) : m_ref( ref ) {} + + public: + template + ParserRefImpl( T &ref, std::string const &hint ) + : m_ref( std::make_shared>( ref ) ), + m_hint( hint ) + {} + + template + ParserRefImpl( LambdaT const &ref, std::string const &hint ) + : m_ref( std::make_shared>( ref ) ), + m_hint(hint) + {} + + auto operator()( std::string const &description ) -> DerivedT & { + m_description = description; + return static_cast( *this ); + } + + auto optional() -> DerivedT & { + m_optionality = Optionality::Optional; + return static_cast( *this ); + }; + + auto required() -> DerivedT & { + m_optionality = Optionality::Required; + return static_cast( *this ); + }; + + auto isOptional() const -> bool { + return m_optionality == Optionality::Optional; + } + + auto cardinality() const -> size_t override { + if( m_ref->isContainer() ) + return 0; + else + return 1; + } + + auto hint() const -> std::string { return m_hint; } + }; + + class ExeName : public ComposableParserImpl { + std::shared_ptr m_name; + std::shared_ptr m_ref; + + template + static auto makeRef(LambdaT const &lambda) -> std::shared_ptr { + return std::make_shared>( lambda) ; + } + + public: + ExeName() : m_name( std::make_shared( "" ) ) {} + + explicit ExeName( std::string &ref ) : ExeName() { + m_ref = std::make_shared>( ref ); + } + + template + explicit ExeName( LambdaT const& lambda ) : ExeName() { + m_ref = std::make_shared>( lambda ); + } + + // The exe name is not parsed out of the normal tokens, but is handled specially + auto parse( std::string const&, TokenStream const &tokens ) const -> InternalParseResult override { + return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, tokens ) ); + } + + auto name() const -> std::string { return *m_name; } + auto set( std::string const& newName ) -> ParserResult { + + auto lastSlash = newName.find_last_of( "\\/" ); + auto filename = ( lastSlash == std::string::npos ) + ? newName + : newName.substr( lastSlash+1 ); + + *m_name = filename; + if( m_ref ) + return m_ref->setValue( filename ); + else + return ParserResult::ok( ParseResultType::Matched ); + } + }; + + class Arg : public ParserRefImpl { + public: + using ParserRefImpl::ParserRefImpl; + + auto parse( std::string const &, TokenStream const &tokens ) const -> InternalParseResult override { + auto validationResult = validate(); + if( !validationResult ) + return InternalParseResult( validationResult ); + + auto remainingTokens = tokens; + auto const &token = *remainingTokens; + if( token.type != TokenType::Argument ) + return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, remainingTokens ) ); + + assert( !m_ref->isFlag() ); + auto valueRef = static_cast( m_ref.get() ); + + auto result = valueRef->setValue( remainingTokens->token ); + if( !result ) + return InternalParseResult( result ); + else + return InternalParseResult::ok( ParseState( ParseResultType::Matched, ++remainingTokens ) ); + } + }; + + inline auto normaliseOpt( std::string const &optName ) -> std::string { +#ifdef CATCH_PLATFORM_WINDOWS + if( optName[0] == '/' ) + return "-" + optName.substr( 1 ); + else +#endif + return optName; + } + + class Opt : public ParserRefImpl { + protected: + std::vector m_optNames; + + public: + template + explicit Opt( LambdaT const &ref ) : ParserRefImpl( std::make_shared>( ref ) ) {} + + explicit Opt( bool &ref ) : ParserRefImpl( std::make_shared( ref ) ) {} + + template + Opt( LambdaT const &ref, std::string const &hint ) : ParserRefImpl( ref, hint ) {} + + template + Opt( T &ref, std::string const &hint ) : ParserRefImpl( ref, hint ) {} + + auto operator[]( std::string const &optName ) -> Opt & { + m_optNames.push_back( optName ); + return *this; + } + + auto getHelpColumns() const -> std::vector { + std::ostringstream oss; + bool first = true; + for( auto const &opt : m_optNames ) { + if (first) + first = false; + else + oss << ", "; + oss << opt; + } + if( !m_hint.empty() ) + oss << " <" << m_hint << ">"; + return { { oss.str(), m_description } }; + } + + auto isMatch( std::string const &optToken ) const -> bool { + auto normalisedToken = normaliseOpt( optToken ); + for( auto const &name : m_optNames ) { + if( normaliseOpt( name ) == normalisedToken ) + return true; + } + return false; + } + + using ParserBase::parse; + + auto parse( std::string const&, TokenStream const &tokens ) const -> InternalParseResult override { + auto validationResult = validate(); + if( !validationResult ) + return InternalParseResult( validationResult ); + + auto remainingTokens = tokens; + if( remainingTokens && remainingTokens->type == TokenType::Option ) { + auto const &token = *remainingTokens; + if( isMatch(token.token ) ) { + if( m_ref->isFlag() ) { + auto flagRef = static_cast( m_ref.get() ); + auto result = flagRef->setFlag( true ); + if( !result ) + return InternalParseResult( result ); + if( result.value() == ParseResultType::ShortCircuitAll ) + return InternalParseResult::ok( ParseState( result.value(), remainingTokens ) ); + } else { + auto valueRef = static_cast( m_ref.get() ); + ++remainingTokens; + if( !remainingTokens ) + return InternalParseResult::runtimeError( "Expected argument following " + token.token ); + auto const &argToken = *remainingTokens; + if( argToken.type != TokenType::Argument ) + return InternalParseResult::runtimeError( "Expected argument following " + token.token ); + auto result = valueRef->setValue( argToken.token ); + if( !result ) + return InternalParseResult( result ); + if( result.value() == ParseResultType::ShortCircuitAll ) + return InternalParseResult::ok( ParseState( result.value(), remainingTokens ) ); + } + return InternalParseResult::ok( ParseState( ParseResultType::Matched, ++remainingTokens ) ); + } + } + return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, remainingTokens ) ); + } + + auto validate() const -> Result override { + if( m_optNames.empty() ) + return Result::logicError( "No options supplied to Opt" ); + for( auto const &name : m_optNames ) { + if( name.empty() ) + return Result::logicError( "Option name cannot be empty" ); +#ifdef CATCH_PLATFORM_WINDOWS + if( name[0] != '-' && name[0] != '/' ) + return Result::logicError( "Option name must begin with '-' or '/'" ); +#else + if( name[0] != '-' ) + return Result::logicError( "Option name must begin with '-'" ); +#endif + } + return ParserRefImpl::validate(); + } + }; + + struct Help : Opt { + Help( bool &showHelpFlag ) + : Opt([&]( bool flag ) { + showHelpFlag = flag; + return ParserResult::ok( ParseResultType::ShortCircuitAll ); + }) + { + static_cast( *this ) + ("display usage information") + ["-?"]["-h"]["--help"] + .optional(); + } + }; + + struct Parser : ParserBase { + + mutable ExeName m_exeName; + std::vector m_options; + std::vector m_args; + + auto operator|=( ExeName const &exeName ) -> Parser & { + m_exeName = exeName; + return *this; + } + + auto operator|=( Arg const &arg ) -> Parser & { + m_args.push_back(arg); + return *this; + } + + auto operator|=( Opt const &opt ) -> Parser & { + m_options.push_back(opt); + return *this; + } + + auto operator|=( Parser const &other ) -> Parser & { + m_options.insert(m_options.end(), other.m_options.begin(), other.m_options.end()); + m_args.insert(m_args.end(), other.m_args.begin(), other.m_args.end()); + return *this; + } + + template + auto operator|( T const &other ) const -> Parser { + return Parser( *this ) |= other; + } + + // Forward deprecated interface with '+' instead of '|' + template + auto operator+=( T const &other ) -> Parser & { return operator|=( other ); } + template + auto operator+( T const &other ) const -> Parser { return operator|( other ); } + + auto getHelpColumns() const -> std::vector { + std::vector cols; + for (auto const &o : m_options) { + auto childCols = o.getHelpColumns(); + cols.insert( cols.end(), childCols.begin(), childCols.end() ); + } + return cols; + } + + void writeToStream( std::ostream &os ) const { + if (!m_exeName.name().empty()) { + os << "usage:\n" << " " << m_exeName.name() << " "; + bool required = true, first = true; + for( auto const &arg : m_args ) { + if (first) + first = false; + else + os << " "; + if( arg.isOptional() && required ) { + os << "["; + required = false; + } + os << "<" << arg.hint() << ">"; + if( arg.cardinality() == 0 ) + os << " ... "; + } + if( !required ) + os << "]"; + if( !m_options.empty() ) + os << " options"; + os << "\n\nwhere options are:" << std::endl; + } + + auto rows = getHelpColumns(); + size_t consoleWidth = CATCH_CLARA_CONFIG_CONSOLE_WIDTH; + size_t optWidth = 0; + for( auto const &cols : rows ) + optWidth = (std::max)(optWidth, cols.left.size() + 2); + + optWidth = (std::min)(optWidth, consoleWidth/2); + + for( auto const &cols : rows ) { + auto row = + TextFlow::Column( cols.left ).width( optWidth ).indent( 2 ) + + TextFlow::Spacer(4) + + TextFlow::Column( cols.right ).width( consoleWidth - 7 - optWidth ); + os << row << std::endl; + } + } + + friend auto operator<<( std::ostream &os, Parser const &parser ) -> std::ostream& { + parser.writeToStream( os ); + return os; + } + + auto validate() const -> Result override { + for( auto const &opt : m_options ) { + auto result = opt.validate(); + if( !result ) + return result; + } + for( auto const &arg : m_args ) { + auto result = arg.validate(); + if( !result ) + return result; + } + return Result::ok(); + } + + using ParserBase::parse; + + auto parse( std::string const& exeName, TokenStream const &tokens ) const -> InternalParseResult override { + + struct ParserInfo { + ParserBase const* parser = nullptr; + size_t count = 0; + }; + const size_t totalParsers = m_options.size() + m_args.size(); + assert( totalParsers < 512 ); + // ParserInfo parseInfos[totalParsers]; // <-- this is what we really want to do + ParserInfo parseInfos[512]; + + { + size_t i = 0; + for (auto const &opt : m_options) parseInfos[i++].parser = &opt; + for (auto const &arg : m_args) parseInfos[i++].parser = &arg; + } + + m_exeName.set( exeName ); + + auto result = InternalParseResult::ok( ParseState( ParseResultType::NoMatch, tokens ) ); + while( result.value().remainingTokens() ) { + bool tokenParsed = false; + + for( size_t i = 0; i < totalParsers; ++i ) { + auto& parseInfo = parseInfos[i]; + if( parseInfo.parser->cardinality() == 0 || parseInfo.count < parseInfo.parser->cardinality() ) { + result = parseInfo.parser->parse(exeName, result.value().remainingTokens()); + if (!result) + return result; + if (result.value().type() != ParseResultType::NoMatch) { + tokenParsed = true; + ++parseInfo.count; + break; + } + } + } + + if( result.value().type() == ParseResultType::ShortCircuitAll ) + return result; + if( !tokenParsed ) + return InternalParseResult::runtimeError( "Unrecognised token: " + result.value().remainingTokens()->token ); + } + // !TBD Check missing required options + return result; + } + }; + + template + template + auto ComposableParserImpl::operator|( T const &other ) const -> Parser { + return Parser() | static_cast( *this ) | other; + } +} // namespace detail + +// A Combined parser +using detail::Parser; + +// A parser for options +using detail::Opt; + +// A parser for arguments +using detail::Arg; + +// Wrapper for argc, argv from main() +using detail::Args; + +// Specifies the name of the executable +using detail::ExeName; + +// Convenience wrapper for option parser that specifies the help option +using detail::Help; + +// enum of result types from a parse +using detail::ParseResultType; + +// Result type for parser operation +using detail::ParserResult; + +}} // namespace Catch::clara + +// end clara.hpp +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +// Restore Clara's value for console width, if present +#ifdef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH +#define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH +#undef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH +#endif + +// end catch_clara.h +namespace Catch { + + clara::Parser makeCommandLineParser( ConfigData& config ); + +} // end namespace Catch + +// end catch_commandline.h +#include +#include + +namespace Catch { + + clara::Parser makeCommandLineParser( ConfigData& config ) { + + using namespace clara; + + auto const setWarning = [&]( std::string const& warning ) { + auto warningSet = [&]() { + if( warning == "NoAssertions" ) + return WarnAbout::NoAssertions; + + if ( warning == "NoTests" ) + return WarnAbout::NoTests; + + return WarnAbout::Nothing; + }(); + + if (warningSet == WarnAbout::Nothing) + return ParserResult::runtimeError( "Unrecognised warning: '" + warning + "'" ); + config.warnings = static_cast( config.warnings | warningSet ); + return ParserResult::ok( ParseResultType::Matched ); + }; + auto const loadTestNamesFromFile = [&]( std::string const& filename ) { + std::ifstream f( filename.c_str() ); + if( !f.is_open() ) + return ParserResult::runtimeError( "Unable to load input file: '" + filename + "'" ); + + std::string line; + while( std::getline( f, line ) ) { + line = trim(line); + if( !line.empty() && !startsWith( line, '#' ) ) { + if( !startsWith( line, '"' ) ) + line = '"' + line + '"'; + config.testsOrTags.push_back( line + ',' ); + } + } + return ParserResult::ok( ParseResultType::Matched ); + }; + auto const setTestOrder = [&]( std::string const& order ) { + if( startsWith( "declared", order ) ) + config.runOrder = RunTests::InDeclarationOrder; + else if( startsWith( "lexical", order ) ) + config.runOrder = RunTests::InLexicographicalOrder; + else if( startsWith( "random", order ) ) + config.runOrder = RunTests::InRandomOrder; + else + return clara::ParserResult::runtimeError( "Unrecognised ordering: '" + order + "'" ); + return ParserResult::ok( ParseResultType::Matched ); + }; + auto const setRngSeed = [&]( std::string const& seed ) { + if( seed != "time" ) + return clara::detail::convertInto( seed, config.rngSeed ); + config.rngSeed = static_cast( std::time(nullptr) ); + return ParserResult::ok( ParseResultType::Matched ); + }; + auto const setColourUsage = [&]( std::string const& useColour ) { + auto mode = toLower( useColour ); + + if( mode == "yes" ) + config.useColour = UseColour::Yes; + else if( mode == "no" ) + config.useColour = UseColour::No; + else if( mode == "auto" ) + config.useColour = UseColour::Auto; + else + return ParserResult::runtimeError( "colour mode must be one of: auto, yes or no. '" + useColour + "' not recognised" ); + return ParserResult::ok( ParseResultType::Matched ); + }; + auto const setWaitForKeypress = [&]( std::string const& keypress ) { + auto keypressLc = toLower( keypress ); + if( keypressLc == "start" ) + config.waitForKeypress = WaitForKeypress::BeforeStart; + else if( keypressLc == "exit" ) + config.waitForKeypress = WaitForKeypress::BeforeExit; + else if( keypressLc == "both" ) + config.waitForKeypress = WaitForKeypress::BeforeStartAndExit; + else + return ParserResult::runtimeError( "keypress argument must be one of: start, exit or both. '" + keypress + "' not recognised" ); + return ParserResult::ok( ParseResultType::Matched ); + }; + auto const setVerbosity = [&]( std::string const& verbosity ) { + auto lcVerbosity = toLower( verbosity ); + if( lcVerbosity == "quiet" ) + config.verbosity = Verbosity::Quiet; + else if( lcVerbosity == "normal" ) + config.verbosity = Verbosity::Normal; + else if( lcVerbosity == "high" ) + config.verbosity = Verbosity::High; + else + return ParserResult::runtimeError( "Unrecognised verbosity, '" + verbosity + "'" ); + return ParserResult::ok( ParseResultType::Matched ); + }; + + auto cli + = ExeName( config.processName ) + | Help( config.showHelp ) + | Opt( config.listTests ) + ["-l"]["--list-tests"] + ( "list all/matching test cases" ) + | Opt( config.listTags ) + ["-t"]["--list-tags"] + ( "list all/matching tags" ) + | Opt( config.showSuccessfulTests ) + ["-s"]["--success"] + ( "include successful tests in output" ) + | Opt( config.shouldDebugBreak ) + ["-b"]["--break"] + ( "break into debugger on failure" ) + | Opt( config.noThrow ) + ["-e"]["--nothrow"] + ( "skip exception tests" ) + | Opt( config.showInvisibles ) + ["-i"]["--invisibles"] + ( "show invisibles (tabs, newlines)" ) + | Opt( config.outputFilename, "filename" ) + ["-o"]["--out"] + ( "output filename" ) + | Opt( config.reporterName, "name" ) + ["-r"]["--reporter"] + ( "reporter to use (defaults to console)" ) + | Opt( config.name, "name" ) + ["-n"]["--name"] + ( "suite name" ) + | Opt( [&]( bool ){ config.abortAfter = 1; } ) + ["-a"]["--abort"] + ( "abort at first failure" ) + | Opt( [&]( int x ){ config.abortAfter = x; }, "no. failures" ) + ["-x"]["--abortx"] + ( "abort after x failures" ) + | Opt( setWarning, "warning name" ) + ["-w"]["--warn"] + ( "enable warnings" ) + | Opt( [&]( bool flag ) { config.showDurations = flag ? ShowDurations::Always : ShowDurations::Never; }, "yes|no" ) + ["-d"]["--durations"] + ( "show test durations" ) + | Opt( loadTestNamesFromFile, "filename" ) + ["-f"]["--input-file"] + ( "load test names to run from a file" ) + | Opt( config.filenamesAsTags ) + ["-#"]["--filenames-as-tags"] + ( "adds a tag for the filename" ) + | Opt( config.sectionsToRun, "section name" ) + ["-c"]["--section"] + ( "specify section to run" ) + | Opt( setVerbosity, "quiet|normal|high" ) + ["-v"]["--verbosity"] + ( "set output verbosity" ) + | Opt( config.listTestNamesOnly ) + ["--list-test-names-only"] + ( "list all/matching test cases names only" ) + | Opt( config.listReporters ) + ["--list-reporters"] + ( "list all reporters" ) + | Opt( setTestOrder, "decl|lex|rand" ) + ["--order"] + ( "test case order (defaults to decl)" ) + | Opt( setRngSeed, "'time'|number" ) + ["--rng-seed"] + ( "set a specific seed for random numbers" ) + | Opt( setColourUsage, "yes|no" ) + ["--use-colour"] + ( "should output be colourised" ) + | Opt( config.libIdentify ) + ["--libidentify"] + ( "report name and version according to libidentify standard" ) + | Opt( setWaitForKeypress, "start|exit|both" ) + ["--wait-for-keypress"] + ( "waits for a keypress before exiting" ) + | Opt( config.benchmarkResolutionMultiple, "multiplier" ) + ["--benchmark-resolution-multiple"] + ( "multiple of clock resolution to run benchmarks" ) + + | Arg( config.testsOrTags, "test name|pattern|tags" ) + ( "which test or tests to use" ); + + return cli; + } + +} // end namespace Catch +// end catch_commandline.cpp +// start catch_common.cpp + +#include +#include + +namespace Catch { + + bool SourceLineInfo::empty() const noexcept { + return file[0] == '\0'; + } + bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const noexcept { + return line == other.line && (file == other.file || std::strcmp(file, other.file) == 0); + } + bool SourceLineInfo::operator < ( SourceLineInfo const& other ) const noexcept { + return line < other.line || ( line == other.line && (std::strcmp(file, other.file) < 0)); + } + + std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) { +#ifndef __GNUG__ + os << info.file << '(' << info.line << ')'; +#else + os << info.file << ':' << info.line; +#endif + return os; + } + + std::string StreamEndStop::operator+() const { + return std::string(); + } + + NonCopyable::NonCopyable() = default; + NonCopyable::~NonCopyable() = default; + +} +// end catch_common.cpp +// start catch_config.cpp + +// start catch_enforce.h + +#include + +#define CATCH_PREPARE_EXCEPTION( type, msg ) \ + type( ( Catch::ReusableStringStream() << msg ).str() ) +#define CATCH_INTERNAL_ERROR( msg ) \ + throw CATCH_PREPARE_EXCEPTION( std::logic_error, CATCH_INTERNAL_LINEINFO << ": Internal Catch error: " << msg); +#define CATCH_ERROR( msg ) \ + throw CATCH_PREPARE_EXCEPTION( std::domain_error, msg ) +#define CATCH_ENFORCE( condition, msg ) \ + do{ if( !(condition) ) CATCH_ERROR( msg ); } while(false) + +// end catch_enforce.h +namespace Catch { + + Config::Config( ConfigData const& data ) + : m_data( data ), + m_stream( openStream() ) + { + TestSpecParser parser(ITagAliasRegistry::get()); + if (data.testsOrTags.empty()) { + parser.parse("~[.]"); // All not hidden tests + } + else { + m_hasTestFilters = true; + for( auto const& testOrTags : data.testsOrTags ) + parser.parse( testOrTags ); + } + m_testSpec = parser.testSpec(); + } + + std::string const& Config::getFilename() const { + return m_data.outputFilename ; + } + + bool Config::listTests() const { return m_data.listTests; } + bool Config::listTestNamesOnly() const { return m_data.listTestNamesOnly; } + bool Config::listTags() const { return m_data.listTags; } + bool Config::listReporters() const { return m_data.listReporters; } + + std::string Config::getProcessName() const { return m_data.processName; } + std::string const& Config::getReporterName() const { return m_data.reporterName; } + + std::vector const& Config::getTestsOrTags() const { return m_data.testsOrTags; } + std::vector const& Config::getSectionsToRun() const { return m_data.sectionsToRun; } + + TestSpec const& Config::testSpec() const { return m_testSpec; } + bool Config::hasTestFilters() const { return m_hasTestFilters; } + + bool Config::showHelp() const { return m_data.showHelp; } + + // IConfig interface + bool Config::allowThrows() const { return !m_data.noThrow; } + std::ostream& Config::stream() const { return m_stream->stream(); } + std::string Config::name() const { return m_data.name.empty() ? m_data.processName : m_data.name; } + bool Config::includeSuccessfulResults() const { return m_data.showSuccessfulTests; } + bool Config::warnAboutMissingAssertions() const { return !!(m_data.warnings & WarnAbout::NoAssertions); } + bool Config::warnAboutNoTests() const { return !!(m_data.warnings & WarnAbout::NoTests); } + ShowDurations::OrNot Config::showDurations() const { return m_data.showDurations; } + RunTests::InWhatOrder Config::runOrder() const { return m_data.runOrder; } + unsigned int Config::rngSeed() const { return m_data.rngSeed; } + int Config::benchmarkResolutionMultiple() const { return m_data.benchmarkResolutionMultiple; } + UseColour::YesOrNo Config::useColour() const { return m_data.useColour; } + bool Config::shouldDebugBreak() const { return m_data.shouldDebugBreak; } + int Config::abortAfter() const { return m_data.abortAfter; } + bool Config::showInvisibles() const { return m_data.showInvisibles; } + Verbosity Config::verbosity() const { return m_data.verbosity; } + + IStream const* Config::openStream() { + return Catch::makeStream(m_data.outputFilename); + } + +} // end namespace Catch +// end catch_config.cpp +// start catch_console_colour.cpp + +#if defined(__clang__) +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wexit-time-destructors" +#endif + +// start catch_errno_guard.h + +namespace Catch { + + class ErrnoGuard { + public: + ErrnoGuard(); + ~ErrnoGuard(); + private: + int m_oldErrno; + }; + +} + +// end catch_errno_guard.h +#include + +namespace Catch { + namespace { + + struct IColourImpl { + virtual ~IColourImpl() = default; + virtual void use( Colour::Code _colourCode ) = 0; + }; + + struct NoColourImpl : IColourImpl { + void use( Colour::Code ) {} + + static IColourImpl* instance() { + static NoColourImpl s_instance; + return &s_instance; + } + }; + + } // anon namespace +} // namespace Catch + +#if !defined( CATCH_CONFIG_COLOUR_NONE ) && !defined( CATCH_CONFIG_COLOUR_WINDOWS ) && !defined( CATCH_CONFIG_COLOUR_ANSI ) +# ifdef CATCH_PLATFORM_WINDOWS +# define CATCH_CONFIG_COLOUR_WINDOWS +# else +# define CATCH_CONFIG_COLOUR_ANSI +# endif +#endif + +#if defined ( CATCH_CONFIG_COLOUR_WINDOWS ) ///////////////////////////////////////// + +namespace Catch { +namespace { + + class Win32ColourImpl : public IColourImpl { + public: + Win32ColourImpl() : stdoutHandle( GetStdHandle(STD_OUTPUT_HANDLE) ) + { + CONSOLE_SCREEN_BUFFER_INFO csbiInfo; + GetConsoleScreenBufferInfo( stdoutHandle, &csbiInfo ); + originalForegroundAttributes = csbiInfo.wAttributes & ~( BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_INTENSITY ); + originalBackgroundAttributes = csbiInfo.wAttributes & ~( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY ); + } + + virtual void use( Colour::Code _colourCode ) override { + switch( _colourCode ) { + case Colour::None: return setTextAttribute( originalForegroundAttributes ); + case Colour::White: return setTextAttribute( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); + case Colour::Red: return setTextAttribute( FOREGROUND_RED ); + case Colour::Green: return setTextAttribute( FOREGROUND_GREEN ); + case Colour::Blue: return setTextAttribute( FOREGROUND_BLUE ); + case Colour::Cyan: return setTextAttribute( FOREGROUND_BLUE | FOREGROUND_GREEN ); + case Colour::Yellow: return setTextAttribute( FOREGROUND_RED | FOREGROUND_GREEN ); + case Colour::Grey: return setTextAttribute( 0 ); + + case Colour::LightGrey: return setTextAttribute( FOREGROUND_INTENSITY ); + case Colour::BrightRed: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED ); + case Colour::BrightGreen: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN ); + case Colour::BrightWhite: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); + case Colour::BrightYellow: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN ); + + case Colour::Bright: CATCH_INTERNAL_ERROR( "not a colour" ); + + default: + CATCH_ERROR( "Unknown colour requested" ); + } + } + + private: + void setTextAttribute( WORD _textAttribute ) { + SetConsoleTextAttribute( stdoutHandle, _textAttribute | originalBackgroundAttributes ); + } + HANDLE stdoutHandle; + WORD originalForegroundAttributes; + WORD originalBackgroundAttributes; + }; + + IColourImpl* platformColourInstance() { + static Win32ColourImpl s_instance; + + IConfigPtr config = getCurrentContext().getConfig(); + UseColour::YesOrNo colourMode = config + ? config->useColour() + : UseColour::Auto; + if( colourMode == UseColour::Auto ) + colourMode = UseColour::Yes; + return colourMode == UseColour::Yes + ? &s_instance + : NoColourImpl::instance(); + } + +} // end anon namespace +} // end namespace Catch + +#elif defined( CATCH_CONFIG_COLOUR_ANSI ) ////////////////////////////////////// + +#include + +namespace Catch { +namespace { + + // use POSIX/ ANSI console terminal codes + // Thanks to Adam Strzelecki for original contribution + // (http://github.com/nanoant) + // https://github.com/philsquared/Catch/pull/131 + class PosixColourImpl : public IColourImpl { + public: + virtual void use( Colour::Code _colourCode ) override { + switch( _colourCode ) { + case Colour::None: + case Colour::White: return setColour( "[0m" ); + case Colour::Red: return setColour( "[0;31m" ); + case Colour::Green: return setColour( "[0;32m" ); + case Colour::Blue: return setColour( "[0;34m" ); + case Colour::Cyan: return setColour( "[0;36m" ); + case Colour::Yellow: return setColour( "[0;33m" ); + case Colour::Grey: return setColour( "[1;30m" ); + + case Colour::LightGrey: return setColour( "[0;37m" ); + case Colour::BrightRed: return setColour( "[1;31m" ); + case Colour::BrightGreen: return setColour( "[1;32m" ); + case Colour::BrightWhite: return setColour( "[1;37m" ); + case Colour::BrightYellow: return setColour( "[1;33m" ); + + case Colour::Bright: CATCH_INTERNAL_ERROR( "not a colour" ); + default: CATCH_INTERNAL_ERROR( "Unknown colour requested" ); + } + } + static IColourImpl* instance() { + static PosixColourImpl s_instance; + return &s_instance; + } + + private: + void setColour( const char* _escapeCode ) { + Catch::cout() << '\033' << _escapeCode; + } + }; + + bool useColourOnPlatform() { + return +#ifdef CATCH_PLATFORM_MAC + !isDebuggerActive() && +#endif +#if !(defined(__DJGPP__) && defined(__STRICT_ANSI__)) + isatty(STDOUT_FILENO) +#else + false +#endif + ; + } + IColourImpl* platformColourInstance() { + ErrnoGuard guard; + IConfigPtr config = getCurrentContext().getConfig(); + UseColour::YesOrNo colourMode = config + ? config->useColour() + : UseColour::Auto; + if( colourMode == UseColour::Auto ) + colourMode = useColourOnPlatform() + ? UseColour::Yes + : UseColour::No; + return colourMode == UseColour::Yes + ? PosixColourImpl::instance() + : NoColourImpl::instance(); + } + +} // end anon namespace +} // end namespace Catch + +#else // not Windows or ANSI /////////////////////////////////////////////// + +namespace Catch { + + static IColourImpl* platformColourInstance() { return NoColourImpl::instance(); } + +} // end namespace Catch + +#endif // Windows/ ANSI/ None + +namespace Catch { + + Colour::Colour( Code _colourCode ) { use( _colourCode ); } + Colour::Colour( Colour&& rhs ) noexcept { + m_moved = rhs.m_moved; + rhs.m_moved = true; + } + Colour& Colour::operator=( Colour&& rhs ) noexcept { + m_moved = rhs.m_moved; + rhs.m_moved = true; + return *this; + } + + Colour::~Colour(){ if( !m_moved ) use( None ); } + + void Colour::use( Code _colourCode ) { + static IColourImpl* impl = platformColourInstance(); + impl->use( _colourCode ); + } + + std::ostream& operator << ( std::ostream& os, Colour const& ) { + return os; + } + +} // end namespace Catch + +#if defined(__clang__) +# pragma clang diagnostic pop +#endif + +// end catch_console_colour.cpp +// start catch_context.cpp + +namespace Catch { + + class Context : public IMutableContext, NonCopyable { + + public: // IContext + virtual IResultCapture* getResultCapture() override { + return m_resultCapture; + } + virtual IRunner* getRunner() override { + return m_runner; + } + + virtual IConfigPtr const& getConfig() const override { + return m_config; + } + + virtual ~Context() override; + + public: // IMutableContext + virtual void setResultCapture( IResultCapture* resultCapture ) override { + m_resultCapture = resultCapture; + } + virtual void setRunner( IRunner* runner ) override { + m_runner = runner; + } + virtual void setConfig( IConfigPtr const& config ) override { + m_config = config; + } + + friend IMutableContext& getCurrentMutableContext(); + + private: + IConfigPtr m_config; + IRunner* m_runner = nullptr; + IResultCapture* m_resultCapture = nullptr; + }; + + IMutableContext *IMutableContext::currentContext = nullptr; + + void IMutableContext::createContext() + { + currentContext = new Context(); + } + + void cleanUpContext() { + delete IMutableContext::currentContext; + IMutableContext::currentContext = nullptr; + } + IContext::~IContext() = default; + IMutableContext::~IMutableContext() = default; + Context::~Context() = default; +} +// end catch_context.cpp +// start catch_debug_console.cpp + +// start catch_debug_console.h + +#include + +namespace Catch { + void writeToDebugConsole( std::string const& text ); +} + +// end catch_debug_console.h +#ifdef CATCH_PLATFORM_WINDOWS + + namespace Catch { + void writeToDebugConsole( std::string const& text ) { + ::OutputDebugStringA( text.c_str() ); + } + } + +#else + + namespace Catch { + void writeToDebugConsole( std::string const& text ) { + // !TBD: Need a version for Mac/ XCode and other IDEs + Catch::cout() << text; + } + } + +#endif // Platform +// end catch_debug_console.cpp +// start catch_debugger.cpp + +#ifdef CATCH_PLATFORM_MAC + +# include +# include +# include +# include +# include +# include +# include + +namespace Catch { + + // The following function is taken directly from the following technical note: + // http://developer.apple.com/library/mac/#qa/qa2004/qa1361.html + + // Returns true if the current process is being debugged (either + // running under the debugger or has a debugger attached post facto). + bool isDebuggerActive(){ + + int mib[4]; + struct kinfo_proc info; + std::size_t size; + + // Initialize the flags so that, if sysctl fails for some bizarre + // reason, we get a predictable result. + + info.kp_proc.p_flag = 0; + + // Initialize mib, which tells sysctl the info we want, in this case + // we're looking for information about a specific process ID. + + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PID; + mib[3] = getpid(); + + // Call sysctl. + + size = sizeof(info); + if( sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, nullptr, 0) != 0 ) { + Catch::cerr() << "\n** Call to sysctl failed - unable to determine if debugger is active **\n" << std::endl; + return false; + } + + // We're being debugged if the P_TRACED flag is set. + + return ( (info.kp_proc.p_flag & P_TRACED) != 0 ); + } + } // namespace Catch + +#elif defined(CATCH_PLATFORM_LINUX) + #include + #include + + namespace Catch{ + // The standard POSIX way of detecting a debugger is to attempt to + // ptrace() the process, but this needs to be done from a child and not + // this process itself to still allow attaching to this process later + // if wanted, so is rather heavy. Under Linux we have the PID of the + // "debugger" (which doesn't need to be gdb, of course, it could also + // be strace, for example) in /proc/$PID/status, so just get it from + // there instead. + bool isDebuggerActive(){ + // Libstdc++ has a bug, where std::ifstream sets errno to 0 + // This way our users can properly assert over errno values + ErrnoGuard guard; + std::ifstream in("/proc/self/status"); + for( std::string line; std::getline(in, line); ) { + static const int PREFIX_LEN = 11; + if( line.compare(0, PREFIX_LEN, "TracerPid:\t") == 0 ) { + // We're traced if the PID is not 0 and no other PID starts + // with 0 digit, so it's enough to check for just a single + // character. + return line.length() > PREFIX_LEN && line[PREFIX_LEN] != '0'; + } + } + + return false; + } + } // namespace Catch +#elif defined(_MSC_VER) + extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); + namespace Catch { + bool isDebuggerActive() { + return IsDebuggerPresent() != 0; + } + } +#elif defined(__MINGW32__) + extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); + namespace Catch { + bool isDebuggerActive() { + return IsDebuggerPresent() != 0; + } + } +#else + namespace Catch { + bool isDebuggerActive() { return false; } + } +#endif // Platform +// end catch_debugger.cpp +// start catch_decomposer.cpp + +namespace Catch { + + ITransientExpression::~ITransientExpression() = default; + + void formatReconstructedExpression( std::ostream &os, std::string const& lhs, StringRef op, std::string const& rhs ) { + if( lhs.size() + rhs.size() < 40 && + lhs.find('\n') == std::string::npos && + rhs.find('\n') == std::string::npos ) + os << lhs << " " << op << " " << rhs; + else + os << lhs << "\n" << op << "\n" << rhs; + } +} +// end catch_decomposer.cpp +// start catch_errno_guard.cpp + +#include + +namespace Catch { + ErrnoGuard::ErrnoGuard():m_oldErrno(errno){} + ErrnoGuard::~ErrnoGuard() { errno = m_oldErrno; } +} +// end catch_errno_guard.cpp +// start catch_exception_translator_registry.cpp + +// start catch_exception_translator_registry.h + +#include +#include +#include + +namespace Catch { + + class ExceptionTranslatorRegistry : public IExceptionTranslatorRegistry { + public: + ~ExceptionTranslatorRegistry(); + virtual void registerTranslator( const IExceptionTranslator* translator ); + virtual std::string translateActiveException() const override; + std::string tryTranslators() const; + + private: + std::vector> m_translators; + }; +} + +// end catch_exception_translator_registry.h +#ifdef __OBJC__ +#import "Foundation/Foundation.h" +#endif + +namespace Catch { + + ExceptionTranslatorRegistry::~ExceptionTranslatorRegistry() { + } + + void ExceptionTranslatorRegistry::registerTranslator( const IExceptionTranslator* translator ) { + m_translators.push_back( std::unique_ptr( translator ) ); + } + + std::string ExceptionTranslatorRegistry::translateActiveException() const { + try { +#ifdef __OBJC__ + // In Objective-C try objective-c exceptions first + @try { + return tryTranslators(); + } + @catch (NSException *exception) { + return Catch::Detail::stringify( [exception description] ); + } +#else + // Compiling a mixed mode project with MSVC means that CLR + // exceptions will be caught in (...) as well. However, these + // do not fill-in std::current_exception and thus lead to crash + // when attempting rethrow. + // /EHa switch also causes structured exceptions to be caught + // here, but they fill-in current_exception properly, so + // at worst the output should be a little weird, instead of + // causing a crash. + if (std::current_exception() == nullptr) { + return "Non C++ exception. Possibly a CLR exception."; + } + return tryTranslators(); +#endif + } + catch( TestFailureException& ) { + std::rethrow_exception(std::current_exception()); + } + catch( std::exception& ex ) { + return ex.what(); + } + catch( std::string& msg ) { + return msg; + } + catch( const char* msg ) { + return msg; + } + catch(...) { + return "Unknown exception"; + } + } + + std::string ExceptionTranslatorRegistry::tryTranslators() const { + if( m_translators.empty() ) + std::rethrow_exception(std::current_exception()); + else + return m_translators[0]->translate( m_translators.begin()+1, m_translators.end() ); + } +} +// end catch_exception_translator_registry.cpp +// start catch_fatal_condition.cpp + +#if defined(__GNUC__) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wmissing-field-initializers" +#endif + +#if defined( CATCH_CONFIG_WINDOWS_SEH ) || defined( CATCH_CONFIG_POSIX_SIGNALS ) + +namespace { + // Report the error condition + void reportFatal( char const * const message ) { + Catch::getCurrentContext().getResultCapture()->handleFatalErrorCondition( message ); + } +} + +#endif // signals/SEH handling + +#if defined( CATCH_CONFIG_WINDOWS_SEH ) + +namespace Catch { + struct SignalDefs { DWORD id; const char* name; }; + + // There is no 1-1 mapping between signals and windows exceptions. + // Windows can easily distinguish between SO and SigSegV, + // but SigInt, SigTerm, etc are handled differently. + static SignalDefs signalDefs[] = { + { EXCEPTION_ILLEGAL_INSTRUCTION, "SIGILL - Illegal instruction signal" }, + { EXCEPTION_STACK_OVERFLOW, "SIGSEGV - Stack overflow" }, + { EXCEPTION_ACCESS_VIOLATION, "SIGSEGV - Segmentation violation signal" }, + { EXCEPTION_INT_DIVIDE_BY_ZERO, "Divide by zero error" }, + }; + + LONG CALLBACK FatalConditionHandler::handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo) { + for (auto const& def : signalDefs) { + if (ExceptionInfo->ExceptionRecord->ExceptionCode == def.id) { + reportFatal(def.name); + } + } + // If its not an exception we care about, pass it along. + // This stops us from eating debugger breaks etc. + return EXCEPTION_CONTINUE_SEARCH; + } + + FatalConditionHandler::FatalConditionHandler() { + isSet = true; + // 32k seems enough for Catch to handle stack overflow, + // but the value was found experimentally, so there is no strong guarantee + guaranteeSize = 32 * 1024; + exceptionHandlerHandle = nullptr; + // Register as first handler in current chain + exceptionHandlerHandle = AddVectoredExceptionHandler(1, handleVectoredException); + // Pass in guarantee size to be filled + SetThreadStackGuarantee(&guaranteeSize); + } + + void FatalConditionHandler::reset() { + if (isSet) { + RemoveVectoredExceptionHandler(exceptionHandlerHandle); + SetThreadStackGuarantee(&guaranteeSize); + exceptionHandlerHandle = nullptr; + isSet = false; + } + } + + FatalConditionHandler::~FatalConditionHandler() { + reset(); + } + +bool FatalConditionHandler::isSet = false; +ULONG FatalConditionHandler::guaranteeSize = 0; +PVOID FatalConditionHandler::exceptionHandlerHandle = nullptr; + +} // namespace Catch + +#elif defined( CATCH_CONFIG_POSIX_SIGNALS ) + +namespace Catch { + + struct SignalDefs { + int id; + const char* name; + }; + + // 32kb for the alternate stack seems to be sufficient. However, this value + // is experimentally determined, so that's not guaranteed. + constexpr static std::size_t sigStackSize = 32768 >= MINSIGSTKSZ ? 32768 : MINSIGSTKSZ; + + static SignalDefs signalDefs[] = { + { SIGINT, "SIGINT - Terminal interrupt signal" }, + { SIGILL, "SIGILL - Illegal instruction signal" }, + { SIGFPE, "SIGFPE - Floating point error signal" }, + { SIGSEGV, "SIGSEGV - Segmentation violation signal" }, + { SIGTERM, "SIGTERM - Termination request signal" }, + { SIGABRT, "SIGABRT - Abort (abnormal termination) signal" } + }; + + void FatalConditionHandler::handleSignal( int sig ) { + char const * name = ""; + for (auto const& def : signalDefs) { + if (sig == def.id) { + name = def.name; + break; + } + } + reset(); + reportFatal(name); + raise( sig ); + } + + FatalConditionHandler::FatalConditionHandler() { + isSet = true; + stack_t sigStack; + sigStack.ss_sp = altStackMem; + sigStack.ss_size = sigStackSize; + sigStack.ss_flags = 0; + sigaltstack(&sigStack, &oldSigStack); + struct sigaction sa = { }; + + sa.sa_handler = handleSignal; + sa.sa_flags = SA_ONSTACK; + for (std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i) { + sigaction(signalDefs[i].id, &sa, &oldSigActions[i]); + } + } + + FatalConditionHandler::~FatalConditionHandler() { + reset(); + } + + void FatalConditionHandler::reset() { + if( isSet ) { + // Set signals back to previous values -- hopefully nobody overwrote them in the meantime + for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) { + sigaction(signalDefs[i].id, &oldSigActions[i], nullptr); + } + // Return the old stack + sigaltstack(&oldSigStack, nullptr); + isSet = false; + } + } + + bool FatalConditionHandler::isSet = false; + struct sigaction FatalConditionHandler::oldSigActions[sizeof(signalDefs)/sizeof(SignalDefs)] = {}; + stack_t FatalConditionHandler::oldSigStack = {}; + char FatalConditionHandler::altStackMem[sigStackSize] = {}; + +} // namespace Catch + +#else + +namespace Catch { + void FatalConditionHandler::reset() {} +} + +#endif // signals/SEH handling + +#if defined(__GNUC__) +# pragma GCC diagnostic pop +#endif +// end catch_fatal_condition.cpp +// start catch_interfaces_capture.cpp + +namespace Catch { + IResultCapture::~IResultCapture() = default; +} +// end catch_interfaces_capture.cpp +// start catch_interfaces_config.cpp + +namespace Catch { + IConfig::~IConfig() = default; +} +// end catch_interfaces_config.cpp +// start catch_interfaces_exception.cpp + +namespace Catch { + IExceptionTranslator::~IExceptionTranslator() = default; + IExceptionTranslatorRegistry::~IExceptionTranslatorRegistry() = default; +} +// end catch_interfaces_exception.cpp +// start catch_interfaces_registry_hub.cpp + +namespace Catch { + IRegistryHub::~IRegistryHub() = default; + IMutableRegistryHub::~IMutableRegistryHub() = default; +} +// end catch_interfaces_registry_hub.cpp +// start catch_interfaces_reporter.cpp + +// start catch_reporter_listening.h + +namespace Catch { + + class ListeningReporter : public IStreamingReporter { + using Reporters = std::vector; + Reporters m_listeners; + IStreamingReporterPtr m_reporter = nullptr; + ReporterPreferences m_preferences; + + public: + ListeningReporter(); + + void addListener( IStreamingReporterPtr&& listener ); + void addReporter( IStreamingReporterPtr&& reporter ); + + public: // IStreamingReporter + + ReporterPreferences getPreferences() const override; + + void noMatchingTestCases( std::string const& spec ) override; + + static std::set getSupportedVerbosities(); + + void benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) override; + void benchmarkEnded( BenchmarkStats const& benchmarkStats ) override; + + void testRunStarting( TestRunInfo const& testRunInfo ) override; + void testGroupStarting( GroupInfo const& groupInfo ) override; + void testCaseStarting( TestCaseInfo const& testInfo ) override; + void sectionStarting( SectionInfo const& sectionInfo ) override; + void assertionStarting( AssertionInfo const& assertionInfo ) override; + + // The return value indicates if the messages buffer should be cleared: + bool assertionEnded( AssertionStats const& assertionStats ) override; + void sectionEnded( SectionStats const& sectionStats ) override; + void testCaseEnded( TestCaseStats const& testCaseStats ) override; + void testGroupEnded( TestGroupStats const& testGroupStats ) override; + void testRunEnded( TestRunStats const& testRunStats ) override; + + void skipTest( TestCaseInfo const& testInfo ) override; + bool isMulti() const override; + + }; + +} // end namespace Catch + +// end catch_reporter_listening.h +namespace Catch { + + ReporterConfig::ReporterConfig( IConfigPtr const& _fullConfig ) + : m_stream( &_fullConfig->stream() ), m_fullConfig( _fullConfig ) {} + + ReporterConfig::ReporterConfig( IConfigPtr const& _fullConfig, std::ostream& _stream ) + : m_stream( &_stream ), m_fullConfig( _fullConfig ) {} + + std::ostream& ReporterConfig::stream() const { return *m_stream; } + IConfigPtr ReporterConfig::fullConfig() const { return m_fullConfig; } + + TestRunInfo::TestRunInfo( std::string const& _name ) : name( _name ) {} + + GroupInfo::GroupInfo( std::string const& _name, + std::size_t _groupIndex, + std::size_t _groupsCount ) + : name( _name ), + groupIndex( _groupIndex ), + groupsCounts( _groupsCount ) + {} + + AssertionStats::AssertionStats( AssertionResult const& _assertionResult, + std::vector const& _infoMessages, + Totals const& _totals ) + : assertionResult( _assertionResult ), + infoMessages( _infoMessages ), + totals( _totals ) + { + assertionResult.m_resultData.lazyExpression.m_transientExpression = _assertionResult.m_resultData.lazyExpression.m_transientExpression; + + if( assertionResult.hasMessage() ) { + // Copy message into messages list. + // !TBD This should have been done earlier, somewhere + MessageBuilder builder( assertionResult.getTestMacroName(), assertionResult.getSourceInfo(), assertionResult.getResultType() ); + builder << assertionResult.getMessage(); + builder.m_info.message = builder.m_stream.str(); + + infoMessages.push_back( builder.m_info ); + } + } + + AssertionStats::~AssertionStats() = default; + + SectionStats::SectionStats( SectionInfo const& _sectionInfo, + Counts const& _assertions, + double _durationInSeconds, + bool _missingAssertions ) + : sectionInfo( _sectionInfo ), + assertions( _assertions ), + durationInSeconds( _durationInSeconds ), + missingAssertions( _missingAssertions ) + {} + + SectionStats::~SectionStats() = default; + + TestCaseStats::TestCaseStats( TestCaseInfo const& _testInfo, + Totals const& _totals, + std::string const& _stdOut, + std::string const& _stdErr, + bool _aborting ) + : testInfo( _testInfo ), + totals( _totals ), + stdOut( _stdOut ), + stdErr( _stdErr ), + aborting( _aborting ) + {} + + TestCaseStats::~TestCaseStats() = default; + + TestGroupStats::TestGroupStats( GroupInfo const& _groupInfo, + Totals const& _totals, + bool _aborting ) + : groupInfo( _groupInfo ), + totals( _totals ), + aborting( _aborting ) + {} + + TestGroupStats::TestGroupStats( GroupInfo const& _groupInfo ) + : groupInfo( _groupInfo ), + aborting( false ) + {} + + TestGroupStats::~TestGroupStats() = default; + + TestRunStats::TestRunStats( TestRunInfo const& _runInfo, + Totals const& _totals, + bool _aborting ) + : runInfo( _runInfo ), + totals( _totals ), + aborting( _aborting ) + {} + + TestRunStats::~TestRunStats() = default; + + void IStreamingReporter::fatalErrorEncountered( StringRef ) {} + bool IStreamingReporter::isMulti() const { return false; } + + IReporterFactory::~IReporterFactory() = default; + IReporterRegistry::~IReporterRegistry() = default; + +} // end namespace Catch +// end catch_interfaces_reporter.cpp +// start catch_interfaces_runner.cpp + +namespace Catch { + IRunner::~IRunner() = default; +} +// end catch_interfaces_runner.cpp +// start catch_interfaces_testcase.cpp + +namespace Catch { + ITestInvoker::~ITestInvoker() = default; + ITestCaseRegistry::~ITestCaseRegistry() = default; +} +// end catch_interfaces_testcase.cpp +// start catch_leak_detector.cpp + +#ifdef CATCH_CONFIG_WINDOWS_CRTDBG +#include + +namespace Catch { + + LeakDetector::LeakDetector() { + int flag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG); + flag |= _CRTDBG_LEAK_CHECK_DF; + flag |= _CRTDBG_ALLOC_MEM_DF; + _CrtSetDbgFlag(flag); + _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG); + _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR); + // Change this to leaking allocation's number to break there + _CrtSetBreakAlloc(-1); + } +} + +#else + + Catch::LeakDetector::LeakDetector() {} + +#endif +// end catch_leak_detector.cpp +// start catch_list.cpp + +// start catch_list.h + +#include + +namespace Catch { + + std::size_t listTests( Config const& config ); + + std::size_t listTestsNamesOnly( Config const& config ); + + struct TagInfo { + void add( std::string const& spelling ); + std::string all() const; + + std::set spellings; + std::size_t count = 0; + }; + + std::size_t listTags( Config const& config ); + + std::size_t listReporters( Config const& /*config*/ ); + + Option list( Config const& config ); + +} // end namespace Catch + +// end catch_list.h +// start catch_text.h + +namespace Catch { + using namespace clara::TextFlow; +} + +// end catch_text.h +#include +#include +#include + +namespace Catch { + + std::size_t listTests( Config const& config ) { + TestSpec testSpec = config.testSpec(); + if( config.hasTestFilters() ) + Catch::cout() << "Matching test cases:\n"; + else { + Catch::cout() << "All available test cases:\n"; + } + + auto matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); + for( auto const& testCaseInfo : matchedTestCases ) { + Colour::Code colour = testCaseInfo.isHidden() + ? Colour::SecondaryText + : Colour::None; + Colour colourGuard( colour ); + + Catch::cout() << Column( testCaseInfo.name ).initialIndent( 2 ).indent( 4 ) << "\n"; + if( config.verbosity() >= Verbosity::High ) { + Catch::cout() << Column( Catch::Detail::stringify( testCaseInfo.lineInfo ) ).indent(4) << std::endl; + std::string description = testCaseInfo.description; + if( description.empty() ) + description = "(NO DESCRIPTION)"; + Catch::cout() << Column( description ).indent(4) << std::endl; + } + if( !testCaseInfo.tags.empty() ) + Catch::cout() << Column( testCaseInfo.tagsAsString() ).indent( 6 ) << "\n"; + } + + if( !config.hasTestFilters() ) + Catch::cout() << pluralise( matchedTestCases.size(), "test case" ) << '\n' << std::endl; + else + Catch::cout() << pluralise( matchedTestCases.size(), "matching test case" ) << '\n' << std::endl; + return matchedTestCases.size(); + } + + std::size_t listTestsNamesOnly( Config const& config ) { + TestSpec testSpec = config.testSpec(); + std::size_t matchedTests = 0; + std::vector matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); + for( auto const& testCaseInfo : matchedTestCases ) { + matchedTests++; + if( startsWith( testCaseInfo.name, '#' ) ) + Catch::cout() << '"' << testCaseInfo.name << '"'; + else + Catch::cout() << testCaseInfo.name; + if ( config.verbosity() >= Verbosity::High ) + Catch::cout() << "\t@" << testCaseInfo.lineInfo; + Catch::cout() << std::endl; + } + return matchedTests; + } + + void TagInfo::add( std::string const& spelling ) { + ++count; + spellings.insert( spelling ); + } + + std::string TagInfo::all() const { + std::string out; + for( auto const& spelling : spellings ) + out += "[" + spelling + "]"; + return out; + } + + std::size_t listTags( Config const& config ) { + TestSpec testSpec = config.testSpec(); + if( config.hasTestFilters() ) + Catch::cout() << "Tags for matching test cases:\n"; + else { + Catch::cout() << "All available tags:\n"; + } + + std::map tagCounts; + + std::vector matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); + for( auto const& testCase : matchedTestCases ) { + for( auto const& tagName : testCase.getTestCaseInfo().tags ) { + std::string lcaseTagName = toLower( tagName ); + auto countIt = tagCounts.find( lcaseTagName ); + if( countIt == tagCounts.end() ) + countIt = tagCounts.insert( std::make_pair( lcaseTagName, TagInfo() ) ).first; + countIt->second.add( tagName ); + } + } + + for( auto const& tagCount : tagCounts ) { + ReusableStringStream rss; + rss << " " << std::setw(2) << tagCount.second.count << " "; + auto str = rss.str(); + auto wrapper = Column( tagCount.second.all() ) + .initialIndent( 0 ) + .indent( str.size() ) + .width( CATCH_CONFIG_CONSOLE_WIDTH-10 ); + Catch::cout() << str << wrapper << '\n'; + } + Catch::cout() << pluralise( tagCounts.size(), "tag" ) << '\n' << std::endl; + return tagCounts.size(); + } + + std::size_t listReporters( Config const& /*config*/ ) { + Catch::cout() << "Available reporters:\n"; + IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories(); + std::size_t maxNameLen = 0; + for( auto const& factoryKvp : factories ) + maxNameLen = (std::max)( maxNameLen, factoryKvp.first.size() ); + + for( auto const& factoryKvp : factories ) { + Catch::cout() + << Column( factoryKvp.first + ":" ) + .indent(2) + .width( 5+maxNameLen ) + + Column( factoryKvp.second->getDescription() ) + .initialIndent(0) + .indent(2) + .width( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen-8 ) + << "\n"; + } + Catch::cout() << std::endl; + return factories.size(); + } + + Option list( Config const& config ) { + Option listedCount; + if( config.listTests() ) + listedCount = listedCount.valueOr(0) + listTests( config ); + if( config.listTestNamesOnly() ) + listedCount = listedCount.valueOr(0) + listTestsNamesOnly( config ); + if( config.listTags() ) + listedCount = listedCount.valueOr(0) + listTags( config ); + if( config.listReporters() ) + listedCount = listedCount.valueOr(0) + listReporters( config ); + return listedCount; + } + +} // end namespace Catch +// end catch_list.cpp +// start catch_matchers.cpp + +namespace Catch { +namespace Matchers { + namespace Impl { + + std::string MatcherUntypedBase::toString() const { + if( m_cachedToString.empty() ) + m_cachedToString = describe(); + return m_cachedToString; + } + + MatcherUntypedBase::~MatcherUntypedBase() = default; + + } // namespace Impl +} // namespace Matchers + +using namespace Matchers; +using Matchers::Impl::MatcherBase; + +} // namespace Catch +// end catch_matchers.cpp +// start catch_matchers_floating.cpp + +// start catch_to_string.hpp + +#include + +namespace Catch { + template + std::string to_string(T const& t) { +#if defined(CATCH_CONFIG_CPP11_TO_STRING) + return std::to_string(t); +#else + ReusableStringStream rss; + rss << t; + return rss.str(); +#endif + } +} // end namespace Catch + +// end catch_to_string.hpp +#include +#include +#include +#include + +namespace Catch { +namespace Matchers { +namespace Floating { +enum class FloatingPointKind : uint8_t { + Float, + Double +}; +} +} +} + +namespace { + +template +struct Converter; + +template <> +struct Converter { + static_assert(sizeof(float) == sizeof(int32_t), "Important ULP matcher assumption violated"); + Converter(float f) { + std::memcpy(&i, &f, sizeof(f)); + } + int32_t i; +}; + +template <> +struct Converter { + static_assert(sizeof(double) == sizeof(int64_t), "Important ULP matcher assumption violated"); + Converter(double d) { + std::memcpy(&i, &d, sizeof(d)); + } + int64_t i; +}; + +template +auto convert(T t) -> Converter { + return Converter(t); +} + +template +bool almostEqualUlps(FP lhs, FP rhs, int maxUlpDiff) { + // Comparison with NaN should always be false. + // This way we can rule it out before getting into the ugly details + if (std::isnan(lhs) || std::isnan(rhs)) { + return false; + } + + auto lc = convert(lhs); + auto rc = convert(rhs); + + if ((lc.i < 0) != (rc.i < 0)) { + // Potentially we can have +0 and -0 + return lhs == rhs; + } + + auto ulpDiff = std::abs(lc.i - rc.i); + return ulpDiff <= maxUlpDiff; +} + +} + +namespace Catch { +namespace Matchers { +namespace Floating { + WithinAbsMatcher::WithinAbsMatcher(double target, double margin) + :m_target{ target }, m_margin{ margin } { + if (m_margin < 0) { + throw std::domain_error("Allowed margin difference has to be >= 0"); + } + } + + // Performs equivalent check of std::fabs(lhs - rhs) <= margin + // But without the subtraction to allow for INFINITY in comparison + bool WithinAbsMatcher::match(double const& matchee) const { + return (matchee + m_margin >= m_target) && (m_target + m_margin >= matchee); + } + + std::string WithinAbsMatcher::describe() const { + return "is within " + ::Catch::Detail::stringify(m_margin) + " of " + ::Catch::Detail::stringify(m_target); + } + + WithinUlpsMatcher::WithinUlpsMatcher(double target, int ulps, FloatingPointKind baseType) + :m_target{ target }, m_ulps{ ulps }, m_type{ baseType } { + if (m_ulps < 0) { + throw std::domain_error("Allowed ulp difference has to be >= 0"); + } + } + + bool WithinUlpsMatcher::match(double const& matchee) const { + switch (m_type) { + case FloatingPointKind::Float: + return almostEqualUlps(static_cast(matchee), static_cast(m_target), m_ulps); + case FloatingPointKind::Double: + return almostEqualUlps(matchee, m_target, m_ulps); + default: + throw std::domain_error("Unknown FloatingPointKind value"); + } + } + + std::string WithinUlpsMatcher::describe() const { + return "is within " + Catch::to_string(m_ulps) + " ULPs of " + ::Catch::Detail::stringify(m_target) + ((m_type == FloatingPointKind::Float)? "f" : ""); + } + +}// namespace Floating + +Floating::WithinUlpsMatcher WithinULP(double target, int maxUlpDiff) { + return Floating::WithinUlpsMatcher(target, maxUlpDiff, Floating::FloatingPointKind::Double); +} + +Floating::WithinUlpsMatcher WithinULP(float target, int maxUlpDiff) { + return Floating::WithinUlpsMatcher(target, maxUlpDiff, Floating::FloatingPointKind::Float); +} + +Floating::WithinAbsMatcher WithinAbs(double target, double margin) { + return Floating::WithinAbsMatcher(target, margin); +} + +} // namespace Matchers +} // namespace Catch + +// end catch_matchers_floating.cpp +// start catch_matchers_generic.cpp + +std::string Catch::Matchers::Generic::Detail::finalizeDescription(const std::string& desc) { + if (desc.empty()) { + return "matches undescribed predicate"; + } else { + return "matches predicate: \"" + desc + '"'; + } +} +// end catch_matchers_generic.cpp +// start catch_matchers_string.cpp + +#include + +namespace Catch { +namespace Matchers { + + namespace StdString { + + CasedString::CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity ) + : m_caseSensitivity( caseSensitivity ), + m_str( adjustString( str ) ) + {} + std::string CasedString::adjustString( std::string const& str ) const { + return m_caseSensitivity == CaseSensitive::No + ? toLower( str ) + : str; + } + std::string CasedString::caseSensitivitySuffix() const { + return m_caseSensitivity == CaseSensitive::No + ? " (case insensitive)" + : std::string(); + } + + StringMatcherBase::StringMatcherBase( std::string const& operation, CasedString const& comparator ) + : m_comparator( comparator ), + m_operation( operation ) { + } + + std::string StringMatcherBase::describe() const { + std::string description; + description.reserve(5 + m_operation.size() + m_comparator.m_str.size() + + m_comparator.caseSensitivitySuffix().size()); + description += m_operation; + description += ": \""; + description += m_comparator.m_str; + description += "\""; + description += m_comparator.caseSensitivitySuffix(); + return description; + } + + EqualsMatcher::EqualsMatcher( CasedString const& comparator ) : StringMatcherBase( "equals", comparator ) {} + + bool EqualsMatcher::match( std::string const& source ) const { + return m_comparator.adjustString( source ) == m_comparator.m_str; + } + + ContainsMatcher::ContainsMatcher( CasedString const& comparator ) : StringMatcherBase( "contains", comparator ) {} + + bool ContainsMatcher::match( std::string const& source ) const { + return contains( m_comparator.adjustString( source ), m_comparator.m_str ); + } + + StartsWithMatcher::StartsWithMatcher( CasedString const& comparator ) : StringMatcherBase( "starts with", comparator ) {} + + bool StartsWithMatcher::match( std::string const& source ) const { + return startsWith( m_comparator.adjustString( source ), m_comparator.m_str ); + } + + EndsWithMatcher::EndsWithMatcher( CasedString const& comparator ) : StringMatcherBase( "ends with", comparator ) {} + + bool EndsWithMatcher::match( std::string const& source ) const { + return endsWith( m_comparator.adjustString( source ), m_comparator.m_str ); + } + + RegexMatcher::RegexMatcher(std::string regex, CaseSensitive::Choice caseSensitivity): m_regex(std::move(regex)), m_caseSensitivity(caseSensitivity) {} + + bool RegexMatcher::match(std::string const& matchee) const { + auto flags = std::regex::ECMAScript; // ECMAScript is the default syntax option anyway + if (m_caseSensitivity == CaseSensitive::Choice::No) { + flags |= std::regex::icase; + } + auto reg = std::regex(m_regex, flags); + return std::regex_match(matchee, reg); + } + + std::string RegexMatcher::describe() const { + return "matches " + ::Catch::Detail::stringify(m_regex) + ((m_caseSensitivity == CaseSensitive::Choice::Yes)? " case sensitively" : " case insensitively"); + } + + } // namespace StdString + + StdString::EqualsMatcher Equals( std::string const& str, CaseSensitive::Choice caseSensitivity ) { + return StdString::EqualsMatcher( StdString::CasedString( str, caseSensitivity) ); + } + StdString::ContainsMatcher Contains( std::string const& str, CaseSensitive::Choice caseSensitivity ) { + return StdString::ContainsMatcher( StdString::CasedString( str, caseSensitivity) ); + } + StdString::EndsWithMatcher EndsWith( std::string const& str, CaseSensitive::Choice caseSensitivity ) { + return StdString::EndsWithMatcher( StdString::CasedString( str, caseSensitivity) ); + } + StdString::StartsWithMatcher StartsWith( std::string const& str, CaseSensitive::Choice caseSensitivity ) { + return StdString::StartsWithMatcher( StdString::CasedString( str, caseSensitivity) ); + } + + StdString::RegexMatcher Matches(std::string const& regex, CaseSensitive::Choice caseSensitivity) { + return StdString::RegexMatcher(regex, caseSensitivity); + } + +} // namespace Matchers +} // namespace Catch +// end catch_matchers_string.cpp +// start catch_message.cpp + +// start catch_uncaught_exceptions.h + +namespace Catch { + bool uncaught_exceptions(); +} // end namespace Catch + +// end catch_uncaught_exceptions.h +namespace Catch { + + MessageInfo::MessageInfo( std::string const& _macroName, + SourceLineInfo const& _lineInfo, + ResultWas::OfType _type ) + : macroName( _macroName ), + lineInfo( _lineInfo ), + type( _type ), + sequence( ++globalCount ) + {} + + bool MessageInfo::operator==( MessageInfo const& other ) const { + return sequence == other.sequence; + } + + bool MessageInfo::operator<( MessageInfo const& other ) const { + return sequence < other.sequence; + } + + // This may need protecting if threading support is added + unsigned int MessageInfo::globalCount = 0; + + //////////////////////////////////////////////////////////////////////////// + + Catch::MessageBuilder::MessageBuilder( std::string const& macroName, + SourceLineInfo const& lineInfo, + ResultWas::OfType type ) + :m_info(macroName, lineInfo, type) {} + + //////////////////////////////////////////////////////////////////////////// + + ScopedMessage::ScopedMessage( MessageBuilder const& builder ) + : m_info( builder.m_info ) + { + m_info.message = builder.m_stream.str(); + getResultCapture().pushScopedMessage( m_info ); + } + + ScopedMessage::~ScopedMessage() { + if ( !uncaught_exceptions() ){ + getResultCapture().popScopedMessage(m_info); + } + } +} // end namespace Catch +// end catch_message.cpp +// start catch_output_redirect.cpp + +// start catch_output_redirect.h +#ifndef TWOBLUECUBES_CATCH_OUTPUT_REDIRECT_H +#define TWOBLUECUBES_CATCH_OUTPUT_REDIRECT_H + +#include +#include +#include + +namespace Catch { + + class RedirectedStream { + std::ostream& m_originalStream; + std::ostream& m_redirectionStream; + std::streambuf* m_prevBuf; + + public: + RedirectedStream( std::ostream& originalStream, std::ostream& redirectionStream ); + ~RedirectedStream(); + }; + + class RedirectedStdOut { + ReusableStringStream m_rss; + RedirectedStream m_cout; + public: + RedirectedStdOut(); + auto str() const -> std::string; + }; + + // StdErr has two constituent streams in C++, std::cerr and std::clog + // This means that we need to redirect 2 streams into 1 to keep proper + // order of writes + class RedirectedStdErr { + ReusableStringStream m_rss; + RedirectedStream m_cerr; + RedirectedStream m_clog; + public: + RedirectedStdErr(); + auto str() const -> std::string; + }; + +#if defined(CATCH_CONFIG_NEW_CAPTURE) + + // Windows's implementation of std::tmpfile is terrible (it tries + // to create a file inside system folder, thus requiring elevated + // privileges for the binary), so we have to use tmpnam(_s) and + // create the file ourselves there. + class TempFile { + public: + TempFile(TempFile const&) = delete; + TempFile& operator=(TempFile const&) = delete; + TempFile(TempFile&&) = delete; + TempFile& operator=(TempFile&&) = delete; + + TempFile(); + ~TempFile(); + + std::FILE* getFile(); + std::string getContents(); + + private: + std::FILE* m_file = nullptr; + #if defined(_MSC_VER) + char m_buffer[L_tmpnam] = { 0 }; + #endif + }; + + class OutputRedirect { + public: + OutputRedirect(OutputRedirect const&) = delete; + OutputRedirect& operator=(OutputRedirect const&) = delete; + OutputRedirect(OutputRedirect&&) = delete; + OutputRedirect& operator=(OutputRedirect&&) = delete; + + OutputRedirect(std::string& stdout_dest, std::string& stderr_dest); + ~OutputRedirect(); + + private: + int m_originalStdout = -1; + int m_originalStderr = -1; + TempFile m_stdoutFile; + TempFile m_stderrFile; + std::string& m_stdoutDest; + std::string& m_stderrDest; + }; + +#endif + +} // end namespace Catch + +#endif // TWOBLUECUBES_CATCH_OUTPUT_REDIRECT_H +// end catch_output_redirect.h +#include +#include +#include +#include +#include + +#if defined(CATCH_CONFIG_NEW_CAPTURE) + #if defined(_MSC_VER) + #include //_dup and _dup2 + #define dup _dup + #define dup2 _dup2 + #define fileno _fileno + #else + #include // dup and dup2 + #endif +#endif + +namespace Catch { + + RedirectedStream::RedirectedStream( std::ostream& originalStream, std::ostream& redirectionStream ) + : m_originalStream( originalStream ), + m_redirectionStream( redirectionStream ), + m_prevBuf( m_originalStream.rdbuf() ) + { + m_originalStream.rdbuf( m_redirectionStream.rdbuf() ); + } + + RedirectedStream::~RedirectedStream() { + m_originalStream.rdbuf( m_prevBuf ); + } + + RedirectedStdOut::RedirectedStdOut() : m_cout( Catch::cout(), m_rss.get() ) {} + auto RedirectedStdOut::str() const -> std::string { return m_rss.str(); } + + RedirectedStdErr::RedirectedStdErr() + : m_cerr( Catch::cerr(), m_rss.get() ), + m_clog( Catch::clog(), m_rss.get() ) + {} + auto RedirectedStdErr::str() const -> std::string { return m_rss.str(); } + +#if defined(CATCH_CONFIG_NEW_CAPTURE) + +#if defined(_MSC_VER) + TempFile::TempFile() { + if (tmpnam_s(m_buffer)) { + throw std::runtime_error("Could not get a temp filename"); + } + if (fopen_s(&m_file, m_buffer, "w")) { + char buffer[100]; + if (strerror_s(buffer, errno)) { + throw std::runtime_error("Could not translate errno to string"); + } + throw std::runtime_error("Could not open the temp file: " + std::string(m_buffer) + buffer); + } + } +#else + TempFile::TempFile() { + m_file = std::tmpfile(); + if (!m_file) { + throw std::runtime_error("Could not create a temp file."); + } + } + +#endif + + TempFile::~TempFile() { + // TBD: What to do about errors here? + std::fclose(m_file); + // We manually create the file on Windows only, on Linux + // it will be autodeleted +#if defined(_MSC_VER) + std::remove(m_buffer); +#endif + } + + FILE* TempFile::getFile() { + return m_file; + } + + std::string TempFile::getContents() { + std::stringstream sstr; + char buffer[100] = {}; + std::rewind(m_file); + while (std::fgets(buffer, sizeof(buffer), m_file)) { + sstr << buffer; + } + return sstr.str(); + } + + OutputRedirect::OutputRedirect(std::string& stdout_dest, std::string& stderr_dest) : + m_originalStdout(dup(1)), + m_originalStderr(dup(2)), + m_stdoutDest(stdout_dest), + m_stderrDest(stderr_dest) { + dup2(fileno(m_stdoutFile.getFile()), 1); + dup2(fileno(m_stderrFile.getFile()), 2); + } + + OutputRedirect::~OutputRedirect() { + Catch::cout() << std::flush; + fflush(stdout); + // Since we support overriding these streams, we flush cerr + // even though std::cerr is unbuffered + Catch::cerr() << std::flush; + Catch::clog() << std::flush; + fflush(stderr); + + dup2(m_originalStdout, 1); + dup2(m_originalStderr, 2); + + m_stdoutDest += m_stdoutFile.getContents(); + m_stderrDest += m_stderrFile.getContents(); + } + +#endif // CATCH_CONFIG_NEW_CAPTURE + +} // namespace Catch + +#if defined(CATCH_CONFIG_NEW_CAPTURE) + #if defined(_MSC_VER) + #undef dup + #undef dup2 + #undef fileno + #endif +#endif +// end catch_output_redirect.cpp +// start catch_random_number_generator.cpp + +// start catch_random_number_generator.h + +#include +#include + +namespace Catch { + + struct IConfig; + + std::mt19937& rng(); + void seedRng( IConfig const& config ); + unsigned int rngSeed(); + +} + +// end catch_random_number_generator.h +namespace Catch { + + std::mt19937& rng() { + static std::mt19937 s_rng; + return s_rng; + } + + void seedRng( IConfig const& config ) { + if( config.rngSeed() != 0 ) { + std::srand( config.rngSeed() ); + rng().seed( config.rngSeed() ); + } + } + + unsigned int rngSeed() { + return getCurrentContext().getConfig()->rngSeed(); + } +} +// end catch_random_number_generator.cpp +// start catch_registry_hub.cpp + +// start catch_test_case_registry_impl.h + +#include +#include +#include +#include + +namespace Catch { + + class TestCase; + struct IConfig; + + std::vector sortTests( IConfig const& config, std::vector const& unsortedTestCases ); + bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ); + + void enforceNoDuplicateTestCases( std::vector const& functions ); + + std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ); + std::vector const& getAllTestCasesSorted( IConfig const& config ); + + class TestRegistry : public ITestCaseRegistry { + public: + virtual ~TestRegistry() = default; + + virtual void registerTest( TestCase const& testCase ); + + std::vector const& getAllTests() const override; + std::vector const& getAllTestsSorted( IConfig const& config ) const override; + + private: + std::vector m_functions; + mutable RunTests::InWhatOrder m_currentSortOrder = RunTests::InDeclarationOrder; + mutable std::vector m_sortedFunctions; + std::size_t m_unnamedCount = 0; + std::ios_base::Init m_ostreamInit; // Forces cout/ cerr to be initialised + }; + + /////////////////////////////////////////////////////////////////////////// + + class TestInvokerAsFunction : public ITestInvoker { + void(*m_testAsFunction)(); + public: + TestInvokerAsFunction( void(*testAsFunction)() ) noexcept; + + void invoke() const override; + }; + + std::string extractClassName( StringRef const& classOrQualifiedMethodName ); + + /////////////////////////////////////////////////////////////////////////// + +} // end namespace Catch + +// end catch_test_case_registry_impl.h +// start catch_reporter_registry.h + +#include + +namespace Catch { + + class ReporterRegistry : public IReporterRegistry { + + public: + + ~ReporterRegistry() override; + + IStreamingReporterPtr create( std::string const& name, IConfigPtr const& config ) const override; + + void registerReporter( std::string const& name, IReporterFactoryPtr const& factory ); + void registerListener( IReporterFactoryPtr const& factory ); + + FactoryMap const& getFactories() const override; + Listeners const& getListeners() const override; + + private: + FactoryMap m_factories; + Listeners m_listeners; + }; +} + +// end catch_reporter_registry.h +// start catch_tag_alias_registry.h + +// start catch_tag_alias.h + +#include + +namespace Catch { + + struct TagAlias { + TagAlias(std::string const& _tag, SourceLineInfo _lineInfo); + + std::string tag; + SourceLineInfo lineInfo; + }; + +} // end namespace Catch + +// end catch_tag_alias.h +#include + +namespace Catch { + + class TagAliasRegistry : public ITagAliasRegistry { + public: + ~TagAliasRegistry() override; + TagAlias const* find( std::string const& alias ) const override; + std::string expandAliases( std::string const& unexpandedTestSpec ) const override; + void add( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ); + + private: + std::map m_registry; + }; + +} // end namespace Catch + +// end catch_tag_alias_registry.h +// start catch_startup_exception_registry.h + +#include +#include + +namespace Catch { + + class StartupExceptionRegistry { + public: + void add(std::exception_ptr const& exception) noexcept; + std::vector const& getExceptions() const noexcept; + private: + std::vector m_exceptions; + }; + +} // end namespace Catch + +// end catch_startup_exception_registry.h +namespace Catch { + + namespace { + + class RegistryHub : public IRegistryHub, public IMutableRegistryHub, + private NonCopyable { + + public: // IRegistryHub + RegistryHub() = default; + IReporterRegistry const& getReporterRegistry() const override { + return m_reporterRegistry; + } + ITestCaseRegistry const& getTestCaseRegistry() const override { + return m_testCaseRegistry; + } + IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() override { + return m_exceptionTranslatorRegistry; + } + ITagAliasRegistry const& getTagAliasRegistry() const override { + return m_tagAliasRegistry; + } + StartupExceptionRegistry const& getStartupExceptionRegistry() const override { + return m_exceptionRegistry; + } + + public: // IMutableRegistryHub + void registerReporter( std::string const& name, IReporterFactoryPtr const& factory ) override { + m_reporterRegistry.registerReporter( name, factory ); + } + void registerListener( IReporterFactoryPtr const& factory ) override { + m_reporterRegistry.registerListener( factory ); + } + void registerTest( TestCase const& testInfo ) override { + m_testCaseRegistry.registerTest( testInfo ); + } + void registerTranslator( const IExceptionTranslator* translator ) override { + m_exceptionTranslatorRegistry.registerTranslator( translator ); + } + void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) override { + m_tagAliasRegistry.add( alias, tag, lineInfo ); + } + void registerStartupException() noexcept override { + m_exceptionRegistry.add(std::current_exception()); + } + + private: + TestRegistry m_testCaseRegistry; + ReporterRegistry m_reporterRegistry; + ExceptionTranslatorRegistry m_exceptionTranslatorRegistry; + TagAliasRegistry m_tagAliasRegistry; + StartupExceptionRegistry m_exceptionRegistry; + }; + + // Single, global, instance + RegistryHub*& getTheRegistryHub() { + static RegistryHub* theRegistryHub = nullptr; + if( !theRegistryHub ) + theRegistryHub = new RegistryHub(); + return theRegistryHub; + } + } + + IRegistryHub& getRegistryHub() { + return *getTheRegistryHub(); + } + IMutableRegistryHub& getMutableRegistryHub() { + return *getTheRegistryHub(); + } + void cleanUp() { + delete getTheRegistryHub(); + getTheRegistryHub() = nullptr; + cleanUpContext(); + ReusableStringStream::cleanup(); + } + std::string translateActiveException() { + return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException(); + } + +} // end namespace Catch +// end catch_registry_hub.cpp +// start catch_reporter_registry.cpp + +namespace Catch { + + ReporterRegistry::~ReporterRegistry() = default; + + IStreamingReporterPtr ReporterRegistry::create( std::string const& name, IConfigPtr const& config ) const { + auto it = m_factories.find( name ); + if( it == m_factories.end() ) + return nullptr; + return it->second->create( ReporterConfig( config ) ); + } + + void ReporterRegistry::registerReporter( std::string const& name, IReporterFactoryPtr const& factory ) { + m_factories.emplace(name, factory); + } + void ReporterRegistry::registerListener( IReporterFactoryPtr const& factory ) { + m_listeners.push_back( factory ); + } + + IReporterRegistry::FactoryMap const& ReporterRegistry::getFactories() const { + return m_factories; + } + IReporterRegistry::Listeners const& ReporterRegistry::getListeners() const { + return m_listeners; + } + +} +// end catch_reporter_registry.cpp +// start catch_result_type.cpp + +namespace Catch { + + bool isOk( ResultWas::OfType resultType ) { + return ( resultType & ResultWas::FailureBit ) == 0; + } + bool isJustInfo( int flags ) { + return flags == ResultWas::Info; + } + + ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ) { + return static_cast( static_cast( lhs ) | static_cast( rhs ) ); + } + + bool shouldContinueOnFailure( int flags ) { return ( flags & ResultDisposition::ContinueOnFailure ) != 0; } + bool shouldSuppressFailure( int flags ) { return ( flags & ResultDisposition::SuppressFail ) != 0; } + +} // end namespace Catch +// end catch_result_type.cpp +// start catch_run_context.cpp + +#include +#include +#include + +namespace Catch { + + RunContext::RunContext(IConfigPtr const& _config, IStreamingReporterPtr&& reporter) + : m_runInfo(_config->name()), + m_context(getCurrentMutableContext()), + m_config(_config), + m_reporter(std::move(reporter)), + m_lastAssertionInfo{ StringRef(), SourceLineInfo("",0), StringRef(), ResultDisposition::Normal }, + m_includeSuccessfulResults( m_config->includeSuccessfulResults() || m_reporter->getPreferences().shouldReportAllAssertions ) + { + m_context.setRunner(this); + m_context.setConfig(m_config); + m_context.setResultCapture(this); + m_reporter->testRunStarting(m_runInfo); + } + + RunContext::~RunContext() { + m_reporter->testRunEnded(TestRunStats(m_runInfo, m_totals, aborting())); + } + + void RunContext::testGroupStarting(std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount) { + m_reporter->testGroupStarting(GroupInfo(testSpec, groupIndex, groupsCount)); + } + + void RunContext::testGroupEnded(std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount) { + m_reporter->testGroupEnded(TestGroupStats(GroupInfo(testSpec, groupIndex, groupsCount), totals, aborting())); + } + + Totals RunContext::runTest(TestCase const& testCase) { + Totals prevTotals = m_totals; + + std::string redirectedCout; + std::string redirectedCerr; + + auto const& testInfo = testCase.getTestCaseInfo(); + + m_reporter->testCaseStarting(testInfo); + + m_activeTestCase = &testCase; + + ITracker& rootTracker = m_trackerContext.startRun(); + assert(rootTracker.isSectionTracker()); + static_cast(rootTracker).addInitialFilters(m_config->getSectionsToRun()); + do { + m_trackerContext.startCycle(); + m_testCaseTracker = &SectionTracker::acquire(m_trackerContext, TestCaseTracking::NameAndLocation(testInfo.name, testInfo.lineInfo)); + runCurrentTest(redirectedCout, redirectedCerr); + } while (!m_testCaseTracker->isSuccessfullyCompleted() && !aborting()); + + Totals deltaTotals = m_totals.delta(prevTotals); + if (testInfo.expectedToFail() && deltaTotals.testCases.passed > 0) { + deltaTotals.assertions.failed++; + deltaTotals.testCases.passed--; + deltaTotals.testCases.failed++; + } + m_totals.testCases += deltaTotals.testCases; + m_reporter->testCaseEnded(TestCaseStats(testInfo, + deltaTotals, + redirectedCout, + redirectedCerr, + aborting())); + + m_activeTestCase = nullptr; + m_testCaseTracker = nullptr; + + return deltaTotals; + } + + IConfigPtr RunContext::config() const { + return m_config; + } + + IStreamingReporter& RunContext::reporter() const { + return *m_reporter; + } + + void RunContext::assertionEnded(AssertionResult const & result) { + if (result.getResultType() == ResultWas::Ok) { + m_totals.assertions.passed++; + m_lastAssertionPassed = true; + } else if (!result.isOk()) { + m_lastAssertionPassed = false; + if( m_activeTestCase->getTestCaseInfo().okToFail() ) + m_totals.assertions.failedButOk++; + else + m_totals.assertions.failed++; + } + else { + m_lastAssertionPassed = true; + } + + // We have no use for the return value (whether messages should be cleared), because messages were made scoped + // and should be let to clear themselves out. + static_cast(m_reporter->assertionEnded(AssertionStats(result, m_messages, m_totals))); + + // Reset working state + resetAssertionInfo(); + m_lastResult = result; + } + void RunContext::resetAssertionInfo() { + m_lastAssertionInfo.macroName = StringRef(); + m_lastAssertionInfo.capturedExpression = "{Unknown expression after the reported line}"_sr; + } + + bool RunContext::sectionStarted(SectionInfo const & sectionInfo, Counts & assertions) { + ITracker& sectionTracker = SectionTracker::acquire(m_trackerContext, TestCaseTracking::NameAndLocation(sectionInfo.name, sectionInfo.lineInfo)); + if (!sectionTracker.isOpen()) + return false; + m_activeSections.push_back(§ionTracker); + + m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo; + + m_reporter->sectionStarting(sectionInfo); + + assertions = m_totals.assertions; + + return true; + } + + bool RunContext::testForMissingAssertions(Counts& assertions) { + if (assertions.total() != 0) + return false; + if (!m_config->warnAboutMissingAssertions()) + return false; + if (m_trackerContext.currentTracker().hasChildren()) + return false; + m_totals.assertions.failed++; + assertions.failed++; + return true; + } + + void RunContext::sectionEnded(SectionEndInfo const & endInfo) { + Counts assertions = m_totals.assertions - endInfo.prevAssertions; + bool missingAssertions = testForMissingAssertions(assertions); + + if (!m_activeSections.empty()) { + m_activeSections.back()->close(); + m_activeSections.pop_back(); + } + + m_reporter->sectionEnded(SectionStats(endInfo.sectionInfo, assertions, endInfo.durationInSeconds, missingAssertions)); + m_messages.clear(); + } + + void RunContext::sectionEndedEarly(SectionEndInfo const & endInfo) { + if (m_unfinishedSections.empty()) + m_activeSections.back()->fail(); + else + m_activeSections.back()->close(); + m_activeSections.pop_back(); + + m_unfinishedSections.push_back(endInfo); + } + void RunContext::benchmarkStarting( BenchmarkInfo const& info ) { + m_reporter->benchmarkStarting( info ); + } + void RunContext::benchmarkEnded( BenchmarkStats const& stats ) { + m_reporter->benchmarkEnded( stats ); + } + + void RunContext::pushScopedMessage(MessageInfo const & message) { + m_messages.push_back(message); + } + + void RunContext::popScopedMessage(MessageInfo const & message) { + m_messages.erase(std::remove(m_messages.begin(), m_messages.end(), message), m_messages.end()); + } + + std::string RunContext::getCurrentTestName() const { + return m_activeTestCase + ? m_activeTestCase->getTestCaseInfo().name + : std::string(); + } + + const AssertionResult * RunContext::getLastResult() const { + return &(*m_lastResult); + } + + void RunContext::exceptionEarlyReported() { + m_shouldReportUnexpected = false; + } + + void RunContext::handleFatalErrorCondition( StringRef message ) { + // First notify reporter that bad things happened + m_reporter->fatalErrorEncountered(message); + + // Don't rebuild the result -- the stringification itself can cause more fatal errors + // Instead, fake a result data. + AssertionResultData tempResult( ResultWas::FatalErrorCondition, { false } ); + tempResult.message = message; + AssertionResult result(m_lastAssertionInfo, tempResult); + + assertionEnded(result); + + handleUnfinishedSections(); + + // Recreate section for test case (as we will lose the one that was in scope) + auto const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); + SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name); + + Counts assertions; + assertions.failed = 1; + SectionStats testCaseSectionStats(testCaseSection, assertions, 0, false); + m_reporter->sectionEnded(testCaseSectionStats); + + auto const& testInfo = m_activeTestCase->getTestCaseInfo(); + + Totals deltaTotals; + deltaTotals.testCases.failed = 1; + deltaTotals.assertions.failed = 1; + m_reporter->testCaseEnded(TestCaseStats(testInfo, + deltaTotals, + std::string(), + std::string(), + false)); + m_totals.testCases.failed++; + testGroupEnded(std::string(), m_totals, 1, 1); + m_reporter->testRunEnded(TestRunStats(m_runInfo, m_totals, false)); + } + + bool RunContext::lastAssertionPassed() { + return m_lastAssertionPassed; + } + + void RunContext::assertionPassed() { + m_lastAssertionPassed = true; + ++m_totals.assertions.passed; + resetAssertionInfo(); + } + + bool RunContext::aborting() const { + return m_totals.assertions.failed == static_cast(m_config->abortAfter()); + } + + void RunContext::runCurrentTest(std::string & redirectedCout, std::string & redirectedCerr) { + auto const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); + SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name); + m_reporter->sectionStarting(testCaseSection); + Counts prevAssertions = m_totals.assertions; + double duration = 0; + m_shouldReportUnexpected = true; + m_lastAssertionInfo = { "TEST_CASE"_sr, testCaseInfo.lineInfo, StringRef(), ResultDisposition::Normal }; + + seedRng(*m_config); + + Timer timer; + try { + if (m_reporter->getPreferences().shouldRedirectStdOut) { +#if !defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT) + RedirectedStdOut redirectedStdOut; + RedirectedStdErr redirectedStdErr; + + timer.start(); + invokeActiveTestCase(); + redirectedCout += redirectedStdOut.str(); + redirectedCerr += redirectedStdErr.str(); +#else + OutputRedirect r(redirectedCout, redirectedCerr); + timer.start(); + invokeActiveTestCase(); +#endif + } else { + timer.start(); + invokeActiveTestCase(); + } + duration = timer.getElapsedSeconds(); + } catch (TestFailureException&) { + // This just means the test was aborted due to failure + } catch (...) { + // Under CATCH_CONFIG_FAST_COMPILE, unexpected exceptions under REQUIRE assertions + // are reported without translation at the point of origin. + if( m_shouldReportUnexpected ) { + AssertionReaction dummyReaction; + handleUnexpectedInflightException( m_lastAssertionInfo, translateActiveException(), dummyReaction ); + } + } + Counts assertions = m_totals.assertions - prevAssertions; + bool missingAssertions = testForMissingAssertions(assertions); + + m_testCaseTracker->close(); + handleUnfinishedSections(); + m_messages.clear(); + + SectionStats testCaseSectionStats(testCaseSection, assertions, duration, missingAssertions); + m_reporter->sectionEnded(testCaseSectionStats); + } + + void RunContext::invokeActiveTestCase() { + FatalConditionHandler fatalConditionHandler; // Handle signals + m_activeTestCase->invoke(); + fatalConditionHandler.reset(); + } + + void RunContext::handleUnfinishedSections() { + // If sections ended prematurely due to an exception we stored their + // infos here so we can tear them down outside the unwind process. + for (auto it = m_unfinishedSections.rbegin(), + itEnd = m_unfinishedSections.rend(); + it != itEnd; + ++it) + sectionEnded(*it); + m_unfinishedSections.clear(); + } + + void RunContext::handleExpr( + AssertionInfo const& info, + ITransientExpression const& expr, + AssertionReaction& reaction + ) { + m_reporter->assertionStarting( info ); + + bool negated = isFalseTest( info.resultDisposition ); + bool result = expr.getResult() != negated; + + if( result ) { + if (!m_includeSuccessfulResults) { + assertionPassed(); + } + else { + reportExpr(info, ResultWas::Ok, &expr, negated); + } + } + else { + reportExpr(info, ResultWas::ExpressionFailed, &expr, negated ); + populateReaction( reaction ); + } + } + void RunContext::reportExpr( + AssertionInfo const &info, + ResultWas::OfType resultType, + ITransientExpression const *expr, + bool negated ) { + + m_lastAssertionInfo = info; + AssertionResultData data( resultType, LazyExpression( negated ) ); + + AssertionResult assertionResult{ info, data }; + assertionResult.m_resultData.lazyExpression.m_transientExpression = expr; + + assertionEnded( assertionResult ); + } + + void RunContext::handleMessage( + AssertionInfo const& info, + ResultWas::OfType resultType, + StringRef const& message, + AssertionReaction& reaction + ) { + m_reporter->assertionStarting( info ); + + m_lastAssertionInfo = info; + + AssertionResultData data( resultType, LazyExpression( false ) ); + data.message = message; + AssertionResult assertionResult{ m_lastAssertionInfo, data }; + assertionEnded( assertionResult ); + if( !assertionResult.isOk() ) + populateReaction( reaction ); + } + void RunContext::handleUnexpectedExceptionNotThrown( + AssertionInfo const& info, + AssertionReaction& reaction + ) { + handleNonExpr(info, Catch::ResultWas::DidntThrowException, reaction); + } + + void RunContext::handleUnexpectedInflightException( + AssertionInfo const& info, + std::string const& message, + AssertionReaction& reaction + ) { + m_lastAssertionInfo = info; + + AssertionResultData data( ResultWas::ThrewException, LazyExpression( false ) ); + data.message = message; + AssertionResult assertionResult{ info, data }; + assertionEnded( assertionResult ); + populateReaction( reaction ); + } + + void RunContext::populateReaction( AssertionReaction& reaction ) { + reaction.shouldDebugBreak = m_config->shouldDebugBreak(); + reaction.shouldThrow = aborting() || (m_lastAssertionInfo.resultDisposition & ResultDisposition::Normal); + } + + void RunContext::handleIncomplete( + AssertionInfo const& info + ) { + m_lastAssertionInfo = info; + + AssertionResultData data( ResultWas::ThrewException, LazyExpression( false ) ); + data.message = "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE"; + AssertionResult assertionResult{ info, data }; + assertionEnded( assertionResult ); + } + void RunContext::handleNonExpr( + AssertionInfo const &info, + ResultWas::OfType resultType, + AssertionReaction &reaction + ) { + m_lastAssertionInfo = info; + + AssertionResultData data( resultType, LazyExpression( false ) ); + AssertionResult assertionResult{ info, data }; + assertionEnded( assertionResult ); + + if( !assertionResult.isOk() ) + populateReaction( reaction ); + } + + IResultCapture& getResultCapture() { + if (auto* capture = getCurrentContext().getResultCapture()) + return *capture; + else + CATCH_INTERNAL_ERROR("No result capture instance"); + } +} +// end catch_run_context.cpp +// start catch_section.cpp + +namespace Catch { + + Section::Section( SectionInfo const& info ) + : m_info( info ), + m_sectionIncluded( getResultCapture().sectionStarted( m_info, m_assertions ) ) + { + m_timer.start(); + } + + Section::~Section() { + if( m_sectionIncluded ) { + SectionEndInfo endInfo{ m_info, m_assertions, m_timer.getElapsedSeconds() }; + if( uncaught_exceptions() ) + getResultCapture().sectionEndedEarly( endInfo ); + else + getResultCapture().sectionEnded( endInfo ); + } + } + + // This indicates whether the section should be executed or not + Section::operator bool() const { + return m_sectionIncluded; + } + +} // end namespace Catch +// end catch_section.cpp +// start catch_section_info.cpp + +namespace Catch { + + SectionInfo::SectionInfo + ( SourceLineInfo const& _lineInfo, + std::string const& _name ) + : name( _name ), + lineInfo( _lineInfo ) + {} + +} // end namespace Catch +// end catch_section_info.cpp +// start catch_session.cpp + +// start catch_session.h + +#include + +namespace Catch { + + class Session : NonCopyable { + public: + + Session(); + ~Session() override; + + void showHelp() const; + void libIdentify(); + + int applyCommandLine( int argc, char const * const * argv ); + + void useConfigData( ConfigData const& configData ); + + int run( int argc, char* argv[] ); + #if defined(CATCH_CONFIG_WCHAR) && defined(WIN32) && defined(UNICODE) + int run( int argc, wchar_t* const argv[] ); + #endif + int run(); + + clara::Parser const& cli() const; + void cli( clara::Parser const& newParser ); + ConfigData& configData(); + Config& config(); + private: + int runInternal(); + + clara::Parser m_cli; + ConfigData m_configData; + std::shared_ptr m_config; + bool m_startupExceptions = false; + }; + +} // end namespace Catch + +// end catch_session.h +// start catch_version.h + +#include + +namespace Catch { + + // Versioning information + struct Version { + Version( Version const& ) = delete; + Version& operator=( Version const& ) = delete; + Version( unsigned int _majorVersion, + unsigned int _minorVersion, + unsigned int _patchNumber, + char const * const _branchName, + unsigned int _buildNumber ); + + unsigned int const majorVersion; + unsigned int const minorVersion; + unsigned int const patchNumber; + + // buildNumber is only used if branchName is not null + char const * const branchName; + unsigned int const buildNumber; + + friend std::ostream& operator << ( std::ostream& os, Version const& version ); + }; + + Version const& libraryVersion(); +} + +// end catch_version.h +#include +#include + +namespace Catch { + + namespace { + const int MaxExitCode = 255; + + IStreamingReporterPtr createReporter(std::string const& reporterName, IConfigPtr const& config) { + auto reporter = Catch::getRegistryHub().getReporterRegistry().create(reporterName, config); + CATCH_ENFORCE(reporter, "No reporter registered with name: '" << reporterName << "'"); + + return reporter; + } + + IStreamingReporterPtr makeReporter(std::shared_ptr const& config) { + if (Catch::getRegistryHub().getReporterRegistry().getListeners().empty()) { + return createReporter(config->getReporterName(), config); + } + + auto multi = std::unique_ptr(new ListeningReporter); + + auto const& listeners = Catch::getRegistryHub().getReporterRegistry().getListeners(); + for (auto const& listener : listeners) { + multi->addListener(listener->create(Catch::ReporterConfig(config))); + } + multi->addReporter(createReporter(config->getReporterName(), config)); + return std::move(multi); + } + + Catch::Totals runTests(std::shared_ptr const& config) { + // FixMe: Add listeners in order first, then add reporters. + + auto reporter = makeReporter(config); + + RunContext context(config, std::move(reporter)); + + Totals totals; + + context.testGroupStarting(config->name(), 1, 1); + + TestSpec testSpec = config->testSpec(); + + auto const& allTestCases = getAllTestCasesSorted(*config); + for (auto const& testCase : allTestCases) { + if (!context.aborting() && matchTest(testCase, testSpec, *config)) + totals += context.runTest(testCase); + else + context.reporter().skipTest(testCase); + } + + if (config->warnAboutNoTests() && totals.testCases.total() == 0) { + ReusableStringStream testConfig; + + bool first = true; + for (const auto& input : config->getTestsOrTags()) { + if (!first) { testConfig << ' '; } + first = false; + testConfig << input; + } + + context.reporter().noMatchingTestCases(testConfig.str()); + totals.error = -1; + } + + context.testGroupEnded(config->name(), totals, 1, 1); + return totals; + } + + void applyFilenamesAsTags(Catch::IConfig const& config) { + auto& tests = const_cast&>(getAllTestCasesSorted(config)); + for (auto& testCase : tests) { + auto tags = testCase.tags; + + std::string filename = testCase.lineInfo.file; + auto lastSlash = filename.find_last_of("\\/"); + if (lastSlash != std::string::npos) { + filename.erase(0, lastSlash); + filename[0] = '#'; + } + + auto lastDot = filename.find_last_of('.'); + if (lastDot != std::string::npos) { + filename.erase(lastDot); + } + + tags.push_back(std::move(filename)); + setTags(testCase, tags); + } + } + + } // anon namespace + + Session::Session() { + static bool alreadyInstantiated = false; + if( alreadyInstantiated ) { + try { CATCH_INTERNAL_ERROR( "Only one instance of Catch::Session can ever be used" ); } + catch(...) { getMutableRegistryHub().registerStartupException(); } + } + + const auto& exceptions = getRegistryHub().getStartupExceptionRegistry().getExceptions(); + if ( !exceptions.empty() ) { + m_startupExceptions = true; + Colour colourGuard( Colour::Red ); + Catch::cerr() << "Errors occurred during startup!" << '\n'; + // iterate over all exceptions and notify user + for ( const auto& ex_ptr : exceptions ) { + try { + std::rethrow_exception(ex_ptr); + } catch ( std::exception const& ex ) { + Catch::cerr() << Column( ex.what() ).indent(2) << '\n'; + } + } + } + + alreadyInstantiated = true; + m_cli = makeCommandLineParser( m_configData ); + } + Session::~Session() { + Catch::cleanUp(); + } + + void Session::showHelp() const { + Catch::cout() + << "\nCatch v" << libraryVersion() << "\n" + << m_cli << std::endl + << "For more detailed usage please see the project docs\n" << std::endl; + } + void Session::libIdentify() { + Catch::cout() + << std::left << std::setw(16) << "description: " << "A Catch test executable\n" + << std::left << std::setw(16) << "category: " << "testframework\n" + << std::left << std::setw(16) << "framework: " << "Catch Test\n" + << std::left << std::setw(16) << "version: " << libraryVersion() << std::endl; + } + + int Session::applyCommandLine( int argc, char const * const * argv ) { + if( m_startupExceptions ) + return 1; + + auto result = m_cli.parse( clara::Args( argc, argv ) ); + if( !result ) { + Catch::cerr() + << Colour( Colour::Red ) + << "\nError(s) in input:\n" + << Column( result.errorMessage() ).indent( 2 ) + << "\n\n"; + Catch::cerr() << "Run with -? for usage\n" << std::endl; + return MaxExitCode; + } + + if( m_configData.showHelp ) + showHelp(); + if( m_configData.libIdentify ) + libIdentify(); + m_config.reset(); + return 0; + } + + void Session::useConfigData( ConfigData const& configData ) { + m_configData = configData; + m_config.reset(); + } + + int Session::run( int argc, char* argv[] ) { + if( m_startupExceptions ) + return 1; + int returnCode = applyCommandLine( argc, argv ); + if( returnCode == 0 ) + returnCode = run(); + return returnCode; + } + +#if defined(CATCH_CONFIG_WCHAR) && defined(WIN32) && defined(UNICODE) + int Session::run( int argc, wchar_t* const argv[] ) { + + char **utf8Argv = new char *[ argc ]; + + for ( int i = 0; i < argc; ++i ) { + int bufSize = WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, NULL, 0, NULL, NULL ); + + utf8Argv[ i ] = new char[ bufSize ]; + + WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, utf8Argv[i], bufSize, NULL, NULL ); + } + + int returnCode = run( argc, utf8Argv ); + + for ( int i = 0; i < argc; ++i ) + delete [] utf8Argv[ i ]; + + delete [] utf8Argv; + + return returnCode; + } +#endif + int Session::run() { + if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeStart ) != 0 ) { + Catch::cout() << "...waiting for enter/ return before starting" << std::endl; + static_cast(std::getchar()); + } + int exitCode = runInternal(); + if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeExit ) != 0 ) { + Catch::cout() << "...waiting for enter/ return before exiting, with code: " << exitCode << std::endl; + static_cast(std::getchar()); + } + return exitCode; + } + + clara::Parser const& Session::cli() const { + return m_cli; + } + void Session::cli( clara::Parser const& newParser ) { + m_cli = newParser; + } + ConfigData& Session::configData() { + return m_configData; + } + Config& Session::config() { + if( !m_config ) + m_config = std::make_shared( m_configData ); + return *m_config; + } + + int Session::runInternal() { + if( m_startupExceptions ) + return 1; + + if( m_configData.showHelp || m_configData.libIdentify ) + return 0; + + try + { + config(); // Force config to be constructed + + seedRng( *m_config ); + + if( m_configData.filenamesAsTags ) + applyFilenamesAsTags( *m_config ); + + // Handle list request + if( Option listed = list( config() ) ) + return static_cast( *listed ); + + auto totals = runTests( m_config ); + // Note that on unices only the lower 8 bits are usually used, clamping + // the return value to 255 prevents false negative when some multiple + // of 256 tests has failed + return (std::min) (MaxExitCode, (std::max) (totals.error, static_cast(totals.assertions.failed))); + } + catch( std::exception& ex ) { + Catch::cerr() << ex.what() << std::endl; + return MaxExitCode; + } + } + +} // end namespace Catch +// end catch_session.cpp +// start catch_startup_exception_registry.cpp + +namespace Catch { + void StartupExceptionRegistry::add( std::exception_ptr const& exception ) noexcept { + try { + m_exceptions.push_back(exception); + } + catch(...) { + // If we run out of memory during start-up there's really not a lot more we can do about it + std::terminate(); + } + } + + std::vector const& StartupExceptionRegistry::getExceptions() const noexcept { + return m_exceptions; + } + +} // end namespace Catch +// end catch_startup_exception_registry.cpp +// start catch_stream.cpp + +#include +#include +#include +#include +#include +#include + +#if defined(__clang__) +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wexit-time-destructors" +#endif + +namespace Catch { + + Catch::IStream::~IStream() = default; + + namespace detail { namespace { + template + class StreamBufImpl : public std::streambuf { + char data[bufferSize]; + WriterF m_writer; + + public: + StreamBufImpl() { + setp( data, data + sizeof(data) ); + } + + ~StreamBufImpl() noexcept { + StreamBufImpl::sync(); + } + + private: + int overflow( int c ) override { + sync(); + + if( c != EOF ) { + if( pbase() == epptr() ) + m_writer( std::string( 1, static_cast( c ) ) ); + else + sputc( static_cast( c ) ); + } + return 0; + } + + int sync() override { + if( pbase() != pptr() ) { + m_writer( std::string( pbase(), static_cast( pptr() - pbase() ) ) ); + setp( pbase(), epptr() ); + } + return 0; + } + }; + + /////////////////////////////////////////////////////////////////////////// + + struct OutputDebugWriter { + + void operator()( std::string const&str ) { + writeToDebugConsole( str ); + } + }; + + /////////////////////////////////////////////////////////////////////////// + + class FileStream : public IStream { + mutable std::ofstream m_ofs; + public: + FileStream( StringRef filename ) { + m_ofs.open( filename.c_str() ); + CATCH_ENFORCE( !m_ofs.fail(), "Unable to open file: '" << filename << "'" ); + } + ~FileStream() override = default; + public: // IStream + std::ostream& stream() const override { + return m_ofs; + } + }; + + /////////////////////////////////////////////////////////////////////////// + + class CoutStream : public IStream { + mutable std::ostream m_os; + public: + // Store the streambuf from cout up-front because + // cout may get redirected when running tests + CoutStream() : m_os( Catch::cout().rdbuf() ) {} + ~CoutStream() override = default; + + public: // IStream + std::ostream& stream() const override { return m_os; } + }; + + /////////////////////////////////////////////////////////////////////////// + + class DebugOutStream : public IStream { + std::unique_ptr> m_streamBuf; + mutable std::ostream m_os; + public: + DebugOutStream() + : m_streamBuf( new StreamBufImpl() ), + m_os( m_streamBuf.get() ) + {} + + ~DebugOutStream() override = default; + + public: // IStream + std::ostream& stream() const override { return m_os; } + }; + + }} // namespace anon::detail + + /////////////////////////////////////////////////////////////////////////// + + auto makeStream( StringRef const &filename ) -> IStream const* { + if( filename.empty() ) + return new detail::CoutStream(); + else if( filename[0] == '%' ) { + if( filename == "%debug" ) + return new detail::DebugOutStream(); + else + CATCH_ERROR( "Unrecognised stream: '" << filename << "'" ); + } + else + return new detail::FileStream( filename ); + } + + // This class encapsulates the idea of a pool of ostringstreams that can be reused. + struct StringStreams { + std::vector> m_streams; + std::vector m_unused; + std::ostringstream m_referenceStream; // Used for copy state/ flags from + static StringStreams* s_instance; + + auto add() -> std::size_t { + if( m_unused.empty() ) { + m_streams.push_back( std::unique_ptr( new std::ostringstream ) ); + return m_streams.size()-1; + } + else { + auto index = m_unused.back(); + m_unused.pop_back(); + return index; + } + } + + void release( std::size_t index ) { + m_streams[index]->copyfmt( m_referenceStream ); // Restore initial flags and other state + m_unused.push_back(index); + } + + // !TBD: put in TLS + static auto instance() -> StringStreams& { + if( !s_instance ) + s_instance = new StringStreams(); + return *s_instance; + } + static void cleanup() { + delete s_instance; + s_instance = nullptr; + } + }; + + StringStreams* StringStreams::s_instance = nullptr; + + void ReusableStringStream::cleanup() { + StringStreams::cleanup(); + } + + ReusableStringStream::ReusableStringStream() + : m_index( StringStreams::instance().add() ), + m_oss( StringStreams::instance().m_streams[m_index].get() ) + {} + + ReusableStringStream::~ReusableStringStream() { + static_cast( m_oss )->str(""); + m_oss->clear(); + StringStreams::instance().release( m_index ); + } + + auto ReusableStringStream::str() const -> std::string { + return static_cast( m_oss )->str(); + } + + /////////////////////////////////////////////////////////////////////////// + +#ifndef CATCH_CONFIG_NOSTDOUT // If you #define this you must implement these functions + std::ostream& cout() { return std::cout; } + std::ostream& cerr() { return std::cerr; } + std::ostream& clog() { return std::clog; } +#endif +} + +#if defined(__clang__) +# pragma clang diagnostic pop +#endif +// end catch_stream.cpp +// start catch_string_manip.cpp + +#include +#include +#include +#include + +namespace Catch { + + namespace { + char toLowerCh(char c) { + return static_cast( std::tolower( c ) ); + } + } + + bool startsWith( std::string const& s, std::string const& prefix ) { + return s.size() >= prefix.size() && std::equal(prefix.begin(), prefix.end(), s.begin()); + } + bool startsWith( std::string const& s, char prefix ) { + return !s.empty() && s[0] == prefix; + } + bool endsWith( std::string const& s, std::string const& suffix ) { + return s.size() >= suffix.size() && std::equal(suffix.rbegin(), suffix.rend(), s.rbegin()); + } + bool endsWith( std::string const& s, char suffix ) { + return !s.empty() && s[s.size()-1] == suffix; + } + bool contains( std::string const& s, std::string const& infix ) { + return s.find( infix ) != std::string::npos; + } + void toLowerInPlace( std::string& s ) { + std::transform( s.begin(), s.end(), s.begin(), toLowerCh ); + } + std::string toLower( std::string const& s ) { + std::string lc = s; + toLowerInPlace( lc ); + return lc; + } + std::string trim( std::string const& str ) { + static char const* whitespaceChars = "\n\r\t "; + std::string::size_type start = str.find_first_not_of( whitespaceChars ); + std::string::size_type end = str.find_last_not_of( whitespaceChars ); + + return start != std::string::npos ? str.substr( start, 1+end-start ) : std::string(); + } + + bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ) { + bool replaced = false; + std::size_t i = str.find( replaceThis ); + while( i != std::string::npos ) { + replaced = true; + str = str.substr( 0, i ) + withThis + str.substr( i+replaceThis.size() ); + if( i < str.size()-withThis.size() ) + i = str.find( replaceThis, i+withThis.size() ); + else + i = std::string::npos; + } + return replaced; + } + + pluralise::pluralise( std::size_t count, std::string const& label ) + : m_count( count ), + m_label( label ) + {} + + std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ) { + os << pluraliser.m_count << ' ' << pluraliser.m_label; + if( pluraliser.m_count != 1 ) + os << 's'; + return os; + } + +} +// end catch_string_manip.cpp +// start catch_stringref.cpp + +#if defined(__clang__) +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wexit-time-destructors" +#endif + +#include +#include +#include + +namespace { + const uint32_t byte_2_lead = 0xC0; + const uint32_t byte_3_lead = 0xE0; + const uint32_t byte_4_lead = 0xF0; +} + +namespace Catch { + StringRef::StringRef( char const* rawChars ) noexcept + : StringRef( rawChars, static_cast(std::strlen(rawChars) ) ) + {} + + StringRef::operator std::string() const { + return std::string( m_start, m_size ); + } + + void StringRef::swap( StringRef& other ) noexcept { + std::swap( m_start, other.m_start ); + std::swap( m_size, other.m_size ); + std::swap( m_data, other.m_data ); + } + + auto StringRef::c_str() const -> char const* { + if( isSubstring() ) + const_cast( this )->takeOwnership(); + return m_start; + } + auto StringRef::currentData() const noexcept -> char const* { + return m_start; + } + + auto StringRef::isOwned() const noexcept -> bool { + return m_data != nullptr; + } + auto StringRef::isSubstring() const noexcept -> bool { + return m_start[m_size] != '\0'; + } + + void StringRef::takeOwnership() { + if( !isOwned() ) { + m_data = new char[m_size+1]; + memcpy( m_data, m_start, m_size ); + m_data[m_size] = '\0'; + m_start = m_data; + } + } + auto StringRef::substr( size_type start, size_type size ) const noexcept -> StringRef { + if( start < m_size ) + return StringRef( m_start+start, size ); + else + return StringRef(); + } + auto StringRef::operator == ( StringRef const& other ) const noexcept -> bool { + return + size() == other.size() && + (std::strncmp( m_start, other.m_start, size() ) == 0); + } + auto StringRef::operator != ( StringRef const& other ) const noexcept -> bool { + return !operator==( other ); + } + + auto StringRef::operator[](size_type index) const noexcept -> char { + return m_start[index]; + } + + auto StringRef::numberOfCharacters() const noexcept -> size_type { + size_type noChars = m_size; + // Make adjustments for uft encodings + for( size_type i=0; i < m_size; ++i ) { + char c = m_start[i]; + if( ( c & byte_2_lead ) == byte_2_lead ) { + noChars--; + if (( c & byte_3_lead ) == byte_3_lead ) + noChars--; + if( ( c & byte_4_lead ) == byte_4_lead ) + noChars--; + } + } + return noChars; + } + + auto operator + ( StringRef const& lhs, StringRef const& rhs ) -> std::string { + std::string str; + str.reserve( lhs.size() + rhs.size() ); + str += lhs; + str += rhs; + return str; + } + auto operator + ( StringRef const& lhs, const char* rhs ) -> std::string { + return std::string( lhs ) + std::string( rhs ); + } + auto operator + ( char const* lhs, StringRef const& rhs ) -> std::string { + return std::string( lhs ) + std::string( rhs ); + } + + auto operator << ( std::ostream& os, StringRef const& str ) -> std::ostream& { + return os.write(str.currentData(), str.size()); + } + + auto operator+=( std::string& lhs, StringRef const& rhs ) -> std::string& { + lhs.append(rhs.currentData(), rhs.size()); + return lhs; + } + +} // namespace Catch + +#if defined(__clang__) +# pragma clang diagnostic pop +#endif +// end catch_stringref.cpp +// start catch_tag_alias.cpp + +namespace Catch { + TagAlias::TagAlias(std::string const & _tag, SourceLineInfo _lineInfo): tag(_tag), lineInfo(_lineInfo) {} +} +// end catch_tag_alias.cpp +// start catch_tag_alias_autoregistrar.cpp + +namespace Catch { + + RegistrarForTagAliases::RegistrarForTagAliases(char const* alias, char const* tag, SourceLineInfo const& lineInfo) { + try { + getMutableRegistryHub().registerTagAlias(alias, tag, lineInfo); + } catch (...) { + // Do not throw when constructing global objects, instead register the exception to be processed later + getMutableRegistryHub().registerStartupException(); + } + } + +} +// end catch_tag_alias_autoregistrar.cpp +// start catch_tag_alias_registry.cpp + +#include + +namespace Catch { + + TagAliasRegistry::~TagAliasRegistry() {} + + TagAlias const* TagAliasRegistry::find( std::string const& alias ) const { + auto it = m_registry.find( alias ); + if( it != m_registry.end() ) + return &(it->second); + else + return nullptr; + } + + std::string TagAliasRegistry::expandAliases( std::string const& unexpandedTestSpec ) const { + std::string expandedTestSpec = unexpandedTestSpec; + for( auto const& registryKvp : m_registry ) { + std::size_t pos = expandedTestSpec.find( registryKvp.first ); + if( pos != std::string::npos ) { + expandedTestSpec = expandedTestSpec.substr( 0, pos ) + + registryKvp.second.tag + + expandedTestSpec.substr( pos + registryKvp.first.size() ); + } + } + return expandedTestSpec; + } + + void TagAliasRegistry::add( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) { + CATCH_ENFORCE( startsWith(alias, "[@") && endsWith(alias, ']'), + "error: tag alias, '" << alias << "' is not of the form [@alias name].\n" << lineInfo ); + + CATCH_ENFORCE( m_registry.insert(std::make_pair(alias, TagAlias(tag, lineInfo))).second, + "error: tag alias, '" << alias << "' already registered.\n" + << "\tFirst seen at: " << find(alias)->lineInfo << "\n" + << "\tRedefined at: " << lineInfo ); + } + + ITagAliasRegistry::~ITagAliasRegistry() {} + + ITagAliasRegistry const& ITagAliasRegistry::get() { + return getRegistryHub().getTagAliasRegistry(); + } + +} // end namespace Catch +// end catch_tag_alias_registry.cpp +// start catch_test_case_info.cpp + +#include +#include +#include +#include + +namespace Catch { + + namespace { + TestCaseInfo::SpecialProperties parseSpecialTag( std::string const& tag ) { + if( startsWith( tag, '.' ) || + tag == "!hide" ) + return TestCaseInfo::IsHidden; + else if( tag == "!throws" ) + return TestCaseInfo::Throws; + else if( tag == "!shouldfail" ) + return TestCaseInfo::ShouldFail; + else if( tag == "!mayfail" ) + return TestCaseInfo::MayFail; + else if( tag == "!nonportable" ) + return TestCaseInfo::NonPortable; + else if( tag == "!benchmark" ) + return static_cast( TestCaseInfo::Benchmark | TestCaseInfo::IsHidden ); + else + return TestCaseInfo::None; + } + bool isReservedTag( std::string const& tag ) { + return parseSpecialTag( tag ) == TestCaseInfo::None && tag.size() > 0 && !std::isalnum( static_cast(tag[0]) ); + } + void enforceNotReservedTag( std::string const& tag, SourceLineInfo const& _lineInfo ) { + CATCH_ENFORCE( !isReservedTag(tag), + "Tag name: [" << tag << "] is not allowed.\n" + << "Tag names starting with non alpha-numeric characters are reserved\n" + << _lineInfo ); + } + } + + TestCase makeTestCase( ITestInvoker* _testCase, + std::string const& _className, + NameAndTags const& nameAndTags, + SourceLineInfo const& _lineInfo ) + { + bool isHidden = false; + + // Parse out tags + std::vector tags; + std::string desc, tag; + bool inTag = false; + std::string _descOrTags = nameAndTags.tags; + for (char c : _descOrTags) { + if( !inTag ) { + if( c == '[' ) + inTag = true; + else + desc += c; + } + else { + if( c == ']' ) { + TestCaseInfo::SpecialProperties prop = parseSpecialTag( tag ); + if( ( prop & TestCaseInfo::IsHidden ) != 0 ) + isHidden = true; + else if( prop == TestCaseInfo::None ) + enforceNotReservedTag( tag, _lineInfo ); + + tags.push_back( tag ); + tag.clear(); + inTag = false; + } + else + tag += c; + } + } + if( isHidden ) { + tags.push_back( "." ); + } + + TestCaseInfo info( nameAndTags.name, _className, desc, tags, _lineInfo ); + return TestCase( _testCase, std::move(info) ); + } + + void setTags( TestCaseInfo& testCaseInfo, std::vector tags ) { + std::sort(begin(tags), end(tags)); + tags.erase(std::unique(begin(tags), end(tags)), end(tags)); + testCaseInfo.lcaseTags.clear(); + + for( auto const& tag : tags ) { + std::string lcaseTag = toLower( tag ); + testCaseInfo.properties = static_cast( testCaseInfo.properties | parseSpecialTag( lcaseTag ) ); + testCaseInfo.lcaseTags.push_back( lcaseTag ); + } + testCaseInfo.tags = std::move(tags); + } + + TestCaseInfo::TestCaseInfo( std::string const& _name, + std::string const& _className, + std::string const& _description, + std::vector const& _tags, + SourceLineInfo const& _lineInfo ) + : name( _name ), + className( _className ), + description( _description ), + lineInfo( _lineInfo ), + properties( None ) + { + setTags( *this, _tags ); + } + + bool TestCaseInfo::isHidden() const { + return ( properties & IsHidden ) != 0; + } + bool TestCaseInfo::throws() const { + return ( properties & Throws ) != 0; + } + bool TestCaseInfo::okToFail() const { + return ( properties & (ShouldFail | MayFail ) ) != 0; + } + bool TestCaseInfo::expectedToFail() const { + return ( properties & (ShouldFail ) ) != 0; + } + + std::string TestCaseInfo::tagsAsString() const { + std::string ret; + // '[' and ']' per tag + std::size_t full_size = 2 * tags.size(); + for (const auto& tag : tags) { + full_size += tag.size(); + } + ret.reserve(full_size); + for (const auto& tag : tags) { + ret.push_back('['); + ret.append(tag); + ret.push_back(']'); + } + + return ret; + } + + TestCase::TestCase( ITestInvoker* testCase, TestCaseInfo&& info ) : TestCaseInfo( std::move(info) ), test( testCase ) {} + + TestCase TestCase::withName( std::string const& _newName ) const { + TestCase other( *this ); + other.name = _newName; + return other; + } + + void TestCase::invoke() const { + test->invoke(); + } + + bool TestCase::operator == ( TestCase const& other ) const { + return test.get() == other.test.get() && + name == other.name && + className == other.className; + } + + bool TestCase::operator < ( TestCase const& other ) const { + return name < other.name; + } + + TestCaseInfo const& TestCase::getTestCaseInfo() const + { + return *this; + } + +} // end namespace Catch +// end catch_test_case_info.cpp +// start catch_test_case_registry_impl.cpp + +#include + +namespace Catch { + + std::vector sortTests( IConfig const& config, std::vector const& unsortedTestCases ) { + + std::vector sorted = unsortedTestCases; + + switch( config.runOrder() ) { + case RunTests::InLexicographicalOrder: + std::sort( sorted.begin(), sorted.end() ); + break; + case RunTests::InRandomOrder: + seedRng( config ); + std::shuffle( sorted.begin(), sorted.end(), rng() ); + break; + case RunTests::InDeclarationOrder: + // already in declaration order + break; + } + return sorted; + } + bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ) { + return testSpec.matches( testCase ) && ( config.allowThrows() || !testCase.throws() ); + } + + void enforceNoDuplicateTestCases( std::vector const& functions ) { + std::set seenFunctions; + for( auto const& function : functions ) { + auto prev = seenFunctions.insert( function ); + CATCH_ENFORCE( prev.second, + "error: TEST_CASE( \"" << function.name << "\" ) already defined.\n" + << "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << "\n" + << "\tRedefined at " << function.getTestCaseInfo().lineInfo ); + } + } + + std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ) { + std::vector filtered; + filtered.reserve( testCases.size() ); + for( auto const& testCase : testCases ) + if( matchTest( testCase, testSpec, config ) ) + filtered.push_back( testCase ); + return filtered; + } + std::vector const& getAllTestCasesSorted( IConfig const& config ) { + return getRegistryHub().getTestCaseRegistry().getAllTestsSorted( config ); + } + + void TestRegistry::registerTest( TestCase const& testCase ) { + std::string name = testCase.getTestCaseInfo().name; + if( name.empty() ) { + ReusableStringStream rss; + rss << "Anonymous test case " << ++m_unnamedCount; + return registerTest( testCase.withName( rss.str() ) ); + } + m_functions.push_back( testCase ); + } + + std::vector const& TestRegistry::getAllTests() const { + return m_functions; + } + std::vector const& TestRegistry::getAllTestsSorted( IConfig const& config ) const { + if( m_sortedFunctions.empty() ) + enforceNoDuplicateTestCases( m_functions ); + + if( m_currentSortOrder != config.runOrder() || m_sortedFunctions.empty() ) { + m_sortedFunctions = sortTests( config, m_functions ); + m_currentSortOrder = config.runOrder(); + } + return m_sortedFunctions; + } + + /////////////////////////////////////////////////////////////////////////// + TestInvokerAsFunction::TestInvokerAsFunction( void(*testAsFunction)() ) noexcept : m_testAsFunction( testAsFunction ) {} + + void TestInvokerAsFunction::invoke() const { + m_testAsFunction(); + } + + std::string extractClassName( StringRef const& classOrQualifiedMethodName ) { + std::string className = classOrQualifiedMethodName; + if( startsWith( className, '&' ) ) + { + std::size_t lastColons = className.rfind( "::" ); + std::size_t penultimateColons = className.rfind( "::", lastColons-1 ); + if( penultimateColons == std::string::npos ) + penultimateColons = 1; + className = className.substr( penultimateColons, lastColons-penultimateColons ); + } + return className; + } + +} // end namespace Catch +// end catch_test_case_registry_impl.cpp +// start catch_test_case_tracker.cpp + +#include +#include +#include +#include +#include + +#if defined(__clang__) +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wexit-time-destructors" +#endif + +namespace Catch { +namespace TestCaseTracking { + + NameAndLocation::NameAndLocation( std::string const& _name, SourceLineInfo const& _location ) + : name( _name ), + location( _location ) + {} + + ITracker::~ITracker() = default; + + TrackerContext& TrackerContext::instance() { + static TrackerContext s_instance; + return s_instance; + } + + ITracker& TrackerContext::startRun() { + m_rootTracker = std::make_shared( NameAndLocation( "{root}", CATCH_INTERNAL_LINEINFO ), *this, nullptr ); + m_currentTracker = nullptr; + m_runState = Executing; + return *m_rootTracker; + } + + void TrackerContext::endRun() { + m_rootTracker.reset(); + m_currentTracker = nullptr; + m_runState = NotStarted; + } + + void TrackerContext::startCycle() { + m_currentTracker = m_rootTracker.get(); + m_runState = Executing; + } + void TrackerContext::completeCycle() { + m_runState = CompletedCycle; + } + + bool TrackerContext::completedCycle() const { + return m_runState == CompletedCycle; + } + ITracker& TrackerContext::currentTracker() { + return *m_currentTracker; + } + void TrackerContext::setCurrentTracker( ITracker* tracker ) { + m_currentTracker = tracker; + } + + TrackerBase::TrackerHasName::TrackerHasName( NameAndLocation const& nameAndLocation ) : m_nameAndLocation( nameAndLocation ) {} + bool TrackerBase::TrackerHasName::operator ()( ITrackerPtr const& tracker ) const { + return + tracker->nameAndLocation().location == m_nameAndLocation.location && + tracker->nameAndLocation().name == m_nameAndLocation.name; + } + + TrackerBase::TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ) + : m_nameAndLocation( nameAndLocation ), + m_ctx( ctx ), + m_parent( parent ) + {} + + NameAndLocation const& TrackerBase::nameAndLocation() const { + return m_nameAndLocation; + } + bool TrackerBase::isComplete() const { + return m_runState == CompletedSuccessfully || m_runState == Failed; + } + bool TrackerBase::isSuccessfullyCompleted() const { + return m_runState == CompletedSuccessfully; + } + bool TrackerBase::isOpen() const { + return m_runState != NotStarted && !isComplete(); + } + bool TrackerBase::hasChildren() const { + return !m_children.empty(); + } + + void TrackerBase::addChild( ITrackerPtr const& child ) { + m_children.push_back( child ); + } + + ITrackerPtr TrackerBase::findChild( NameAndLocation const& nameAndLocation ) { + auto it = std::find_if( m_children.begin(), m_children.end(), TrackerHasName( nameAndLocation ) ); + return( it != m_children.end() ) + ? *it + : nullptr; + } + ITracker& TrackerBase::parent() { + assert( m_parent ); // Should always be non-null except for root + return *m_parent; + } + + void TrackerBase::openChild() { + if( m_runState != ExecutingChildren ) { + m_runState = ExecutingChildren; + if( m_parent ) + m_parent->openChild(); + } + } + + bool TrackerBase::isSectionTracker() const { return false; } + bool TrackerBase::isIndexTracker() const { return false; } + + void TrackerBase::open() { + m_runState = Executing; + moveToThis(); + if( m_parent ) + m_parent->openChild(); + } + + void TrackerBase::close() { + + // Close any still open children (e.g. generators) + while( &m_ctx.currentTracker() != this ) + m_ctx.currentTracker().close(); + + switch( m_runState ) { + case NeedsAnotherRun: + break; + + case Executing: + m_runState = CompletedSuccessfully; + break; + case ExecutingChildren: + if( m_children.empty() || m_children.back()->isComplete() ) + m_runState = CompletedSuccessfully; + break; + + case NotStarted: + case CompletedSuccessfully: + case Failed: + CATCH_INTERNAL_ERROR( "Illogical state: " << m_runState ); + + default: + CATCH_INTERNAL_ERROR( "Unknown state: " << m_runState ); + } + moveToParent(); + m_ctx.completeCycle(); + } + void TrackerBase::fail() { + m_runState = Failed; + if( m_parent ) + m_parent->markAsNeedingAnotherRun(); + moveToParent(); + m_ctx.completeCycle(); + } + void TrackerBase::markAsNeedingAnotherRun() { + m_runState = NeedsAnotherRun; + } + + void TrackerBase::moveToParent() { + assert( m_parent ); + m_ctx.setCurrentTracker( m_parent ); + } + void TrackerBase::moveToThis() { + m_ctx.setCurrentTracker( this ); + } + + SectionTracker::SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ) + : TrackerBase( nameAndLocation, ctx, parent ) + { + if( parent ) { + while( !parent->isSectionTracker() ) + parent = &parent->parent(); + + SectionTracker& parentSection = static_cast( *parent ); + addNextFilters( parentSection.m_filters ); + } + } + + bool SectionTracker::isSectionTracker() const { return true; } + + SectionTracker& SectionTracker::acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation ) { + std::shared_ptr section; + + ITracker& currentTracker = ctx.currentTracker(); + if( ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) { + assert( childTracker ); + assert( childTracker->isSectionTracker() ); + section = std::static_pointer_cast( childTracker ); + } + else { + section = std::make_shared( nameAndLocation, ctx, ¤tTracker ); + currentTracker.addChild( section ); + } + if( !ctx.completedCycle() ) + section->tryOpen(); + return *section; + } + + void SectionTracker::tryOpen() { + if( !isComplete() && (m_filters.empty() || m_filters[0].empty() || m_filters[0] == m_nameAndLocation.name ) ) + open(); + } + + void SectionTracker::addInitialFilters( std::vector const& filters ) { + if( !filters.empty() ) { + m_filters.push_back(""); // Root - should never be consulted + m_filters.push_back(""); // Test Case - not a section filter + m_filters.insert( m_filters.end(), filters.begin(), filters.end() ); + } + } + void SectionTracker::addNextFilters( std::vector const& filters ) { + if( filters.size() > 1 ) + m_filters.insert( m_filters.end(), ++filters.begin(), filters.end() ); + } + + IndexTracker::IndexTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent, int size ) + : TrackerBase( nameAndLocation, ctx, parent ), + m_size( size ) + {} + + bool IndexTracker::isIndexTracker() const { return true; } + + IndexTracker& IndexTracker::acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation, int size ) { + std::shared_ptr tracker; + + ITracker& currentTracker = ctx.currentTracker(); + if( ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) { + assert( childTracker ); + assert( childTracker->isIndexTracker() ); + tracker = std::static_pointer_cast( childTracker ); + } + else { + tracker = std::make_shared( nameAndLocation, ctx, ¤tTracker, size ); + currentTracker.addChild( tracker ); + } + + if( !ctx.completedCycle() && !tracker->isComplete() ) { + if( tracker->m_runState != ExecutingChildren && tracker->m_runState != NeedsAnotherRun ) + tracker->moveNext(); + tracker->open(); + } + + return *tracker; + } + + int IndexTracker::index() const { return m_index; } + + void IndexTracker::moveNext() { + m_index++; + m_children.clear(); + } + + void IndexTracker::close() { + TrackerBase::close(); + if( m_runState == CompletedSuccessfully && m_index < m_size-1 ) + m_runState = Executing; + } + +} // namespace TestCaseTracking + +using TestCaseTracking::ITracker; +using TestCaseTracking::TrackerContext; +using TestCaseTracking::SectionTracker; +using TestCaseTracking::IndexTracker; + +} // namespace Catch + +#if defined(__clang__) +# pragma clang diagnostic pop +#endif +// end catch_test_case_tracker.cpp +// start catch_test_registry.cpp + +namespace Catch { + + auto makeTestInvoker( void(*testAsFunction)() ) noexcept -> ITestInvoker* { + return new(std::nothrow) TestInvokerAsFunction( testAsFunction ); + } + + NameAndTags::NameAndTags( StringRef const& name_ , StringRef const& tags_ ) noexcept : name( name_ ), tags( tags_ ) {} + + AutoReg::AutoReg( ITestInvoker* invoker, SourceLineInfo const& lineInfo, StringRef const& classOrMethod, NameAndTags const& nameAndTags ) noexcept { + try { + getMutableRegistryHub() + .registerTest( + makeTestCase( + invoker, + extractClassName( classOrMethod ), + nameAndTags, + lineInfo)); + } catch (...) { + // Do not throw when constructing global objects, instead register the exception to be processed later + getMutableRegistryHub().registerStartupException(); + } + } + + AutoReg::~AutoReg() = default; +} +// end catch_test_registry.cpp +// start catch_test_spec.cpp + +#include +#include +#include +#include + +namespace Catch { + + TestSpec::Pattern::~Pattern() = default; + TestSpec::NamePattern::~NamePattern() = default; + TestSpec::TagPattern::~TagPattern() = default; + TestSpec::ExcludedPattern::~ExcludedPattern() = default; + + TestSpec::NamePattern::NamePattern( std::string const& name ) + : m_wildcardPattern( toLower( name ), CaseSensitive::No ) + {} + bool TestSpec::NamePattern::matches( TestCaseInfo const& testCase ) const { + return m_wildcardPattern.matches( toLower( testCase.name ) ); + } + + TestSpec::TagPattern::TagPattern( std::string const& tag ) : m_tag( toLower( tag ) ) {} + bool TestSpec::TagPattern::matches( TestCaseInfo const& testCase ) const { + return std::find(begin(testCase.lcaseTags), + end(testCase.lcaseTags), + m_tag) != end(testCase.lcaseTags); + } + + TestSpec::ExcludedPattern::ExcludedPattern( PatternPtr const& underlyingPattern ) : m_underlyingPattern( underlyingPattern ) {} + bool TestSpec::ExcludedPattern::matches( TestCaseInfo const& testCase ) const { return !m_underlyingPattern->matches( testCase ); } + + bool TestSpec::Filter::matches( TestCaseInfo const& testCase ) const { + // All patterns in a filter must match for the filter to be a match + for( auto const& pattern : m_patterns ) { + if( !pattern->matches( testCase ) ) + return false; + } + return true; + } + + bool TestSpec::hasFilters() const { + return !m_filters.empty(); + } + bool TestSpec::matches( TestCaseInfo const& testCase ) const { + // A TestSpec matches if any filter matches + for( auto const& filter : m_filters ) + if( filter.matches( testCase ) ) + return true; + return false; + } +} +// end catch_test_spec.cpp +// start catch_test_spec_parser.cpp + +namespace Catch { + + TestSpecParser::TestSpecParser( ITagAliasRegistry const& tagAliases ) : m_tagAliases( &tagAliases ) {} + + TestSpecParser& TestSpecParser::parse( std::string const& arg ) { + m_mode = None; + m_exclusion = false; + m_start = std::string::npos; + m_arg = m_tagAliases->expandAliases( arg ); + m_escapeChars.clear(); + for( m_pos = 0; m_pos < m_arg.size(); ++m_pos ) + visitChar( m_arg[m_pos] ); + if( m_mode == Name ) + addPattern(); + return *this; + } + TestSpec TestSpecParser::testSpec() { + addFilter(); + return m_testSpec; + } + + void TestSpecParser::visitChar( char c ) { + if( m_mode == None ) { + switch( c ) { + case ' ': return; + case '~': m_exclusion = true; return; + case '[': return startNewMode( Tag, ++m_pos ); + case '"': return startNewMode( QuotedName, ++m_pos ); + case '\\': return escape(); + default: startNewMode( Name, m_pos ); break; + } + } + if( m_mode == Name ) { + if( c == ',' ) { + addPattern(); + addFilter(); + } + else if( c == '[' ) { + if( subString() == "exclude:" ) + m_exclusion = true; + else + addPattern(); + startNewMode( Tag, ++m_pos ); + } + else if( c == '\\' ) + escape(); + } + else if( m_mode == EscapedName ) + m_mode = Name; + else if( m_mode == QuotedName && c == '"' ) + addPattern(); + else if( m_mode == Tag && c == ']' ) + addPattern(); + } + void TestSpecParser::startNewMode( Mode mode, std::size_t start ) { + m_mode = mode; + m_start = start; + } + void TestSpecParser::escape() { + if( m_mode == None ) + m_start = m_pos; + m_mode = EscapedName; + m_escapeChars.push_back( m_pos ); + } + std::string TestSpecParser::subString() const { return m_arg.substr( m_start, m_pos - m_start ); } + + void TestSpecParser::addFilter() { + if( !m_currentFilter.m_patterns.empty() ) { + m_testSpec.m_filters.push_back( m_currentFilter ); + m_currentFilter = TestSpec::Filter(); + } + } + + TestSpec parseTestSpec( std::string const& arg ) { + return TestSpecParser( ITagAliasRegistry::get() ).parse( arg ).testSpec(); + } + +} // namespace Catch +// end catch_test_spec_parser.cpp +// start catch_timer.cpp + +#include + +static const uint64_t nanosecondsInSecond = 1000000000; + +namespace Catch { + + auto getCurrentNanosecondsSinceEpoch() -> uint64_t { + return std::chrono::duration_cast( std::chrono::high_resolution_clock::now().time_since_epoch() ).count(); + } + + namespace { + auto estimateClockResolution() -> uint64_t { + uint64_t sum = 0; + static const uint64_t iterations = 1000000; + + auto startTime = getCurrentNanosecondsSinceEpoch(); + + for( std::size_t i = 0; i < iterations; ++i ) { + + uint64_t ticks; + uint64_t baseTicks = getCurrentNanosecondsSinceEpoch(); + do { + ticks = getCurrentNanosecondsSinceEpoch(); + } while( ticks == baseTicks ); + + auto delta = ticks - baseTicks; + sum += delta; + + // If we have been calibrating for over 3 seconds -- the clock + // is terrible and we should move on. + // TBD: How to signal that the measured resolution is probably wrong? + if (ticks > startTime + 3 * nanosecondsInSecond) { + return sum / i; + } + } + + // We're just taking the mean, here. To do better we could take the std. dev and exclude outliers + // - and potentially do more iterations if there's a high variance. + return sum/iterations; + } + } + auto getEstimatedClockResolution() -> uint64_t { + static auto s_resolution = estimateClockResolution(); + return s_resolution; + } + + void Timer::start() { + m_nanoseconds = getCurrentNanosecondsSinceEpoch(); + } + auto Timer::getElapsedNanoseconds() const -> uint64_t { + return getCurrentNanosecondsSinceEpoch() - m_nanoseconds; + } + auto Timer::getElapsedMicroseconds() const -> uint64_t { + return getElapsedNanoseconds()/1000; + } + auto Timer::getElapsedMilliseconds() const -> unsigned int { + return static_cast(getElapsedMicroseconds()/1000); + } + auto Timer::getElapsedSeconds() const -> double { + return getElapsedMicroseconds()/1000000.0; + } + +} // namespace Catch +// end catch_timer.cpp +// start catch_tostring.cpp + +#if defined(__clang__) +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wexit-time-destructors" +# pragma clang diagnostic ignored "-Wglobal-constructors" +#endif + +// Enable specific decls locally +#if !defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER) +#define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER +#endif + +#include +#include + +namespace Catch { + +namespace Detail { + + const std::string unprintableString = "{?}"; + + namespace { + const int hexThreshold = 255; + + struct Endianness { + enum Arch { Big, Little }; + + static Arch which() { + union _{ + int asInt; + char asChar[sizeof (int)]; + } u; + + u.asInt = 1; + return ( u.asChar[sizeof(int)-1] == 1 ) ? Big : Little; + } + }; + } + + std::string rawMemoryToString( const void *object, std::size_t size ) { + // Reverse order for little endian architectures + int i = 0, end = static_cast( size ), inc = 1; + if( Endianness::which() == Endianness::Little ) { + i = end-1; + end = inc = -1; + } + + unsigned char const *bytes = static_cast(object); + ReusableStringStream rss; + rss << "0x" << std::setfill('0') << std::hex; + for( ; i != end; i += inc ) + rss << std::setw(2) << static_cast(bytes[i]); + return rss.str(); + } +} + +template +std::string fpToString( T value, int precision ) { + if (std::isnan(value)) { + return "nan"; + } + + ReusableStringStream rss; + rss << std::setprecision( precision ) + << std::fixed + << value; + std::string d = rss.str(); + std::size_t i = d.find_last_not_of( '0' ); + if( i != std::string::npos && i != d.size()-1 ) { + if( d[i] == '.' ) + i++; + d = d.substr( 0, i+1 ); + } + return d; +} + +//// ======================================================= //// +// +// Out-of-line defs for full specialization of StringMaker +// +//// ======================================================= //// + +std::string StringMaker::convert(const std::string& str) { + if (!getCurrentContext().getConfig()->showInvisibles()) { + return '"' + str + '"'; + } + + std::string s("\""); + for (char c : str) { + switch (c) { + case '\n': + s.append("\\n"); + break; + case '\t': + s.append("\\t"); + break; + default: + s.push_back(c); + break; + } + } + s.append("\""); + return s; +} + +#ifdef CATCH_CONFIG_WCHAR +std::string StringMaker::convert(const std::wstring& wstr) { + std::string s; + s.reserve(wstr.size()); + for (auto c : wstr) { + s += (c <= 0xff) ? static_cast(c) : '?'; + } + return ::Catch::Detail::stringify(s); +} +#endif + +std::string StringMaker::convert(char const* str) { + if (str) { + return ::Catch::Detail::stringify(std::string{ str }); + } else { + return{ "{null string}" }; + } +} +std::string StringMaker::convert(char* str) { + if (str) { + return ::Catch::Detail::stringify(std::string{ str }); + } else { + return{ "{null string}" }; + } +} +#ifdef CATCH_CONFIG_WCHAR +std::string StringMaker::convert(wchar_t const * str) { + if (str) { + return ::Catch::Detail::stringify(std::wstring{ str }); + } else { + return{ "{null string}" }; + } +} +std::string StringMaker::convert(wchar_t * str) { + if (str) { + return ::Catch::Detail::stringify(std::wstring{ str }); + } else { + return{ "{null string}" }; + } +} +#endif + +std::string StringMaker::convert(int value) { + return ::Catch::Detail::stringify(static_cast(value)); +} +std::string StringMaker::convert(long value) { + return ::Catch::Detail::stringify(static_cast(value)); +} +std::string StringMaker::convert(long long value) { + ReusableStringStream rss; + rss << value; + if (value > Detail::hexThreshold) { + rss << " (0x" << std::hex << value << ')'; + } + return rss.str(); +} + +std::string StringMaker::convert(unsigned int value) { + return ::Catch::Detail::stringify(static_cast(value)); +} +std::string StringMaker::convert(unsigned long value) { + return ::Catch::Detail::stringify(static_cast(value)); +} +std::string StringMaker::convert(unsigned long long value) { + ReusableStringStream rss; + rss << value; + if (value > Detail::hexThreshold) { + rss << " (0x" << std::hex << value << ')'; + } + return rss.str(); +} + +std::string StringMaker::convert(bool b) { + return b ? "true" : "false"; +} + +std::string StringMaker::convert(char value) { + if (value == '\r') { + return "'\\r'"; + } else if (value == '\f') { + return "'\\f'"; + } else if (value == '\n') { + return "'\\n'"; + } else if (value == '\t') { + return "'\\t'"; + } else if ('\0' <= value && value < ' ') { + return ::Catch::Detail::stringify(static_cast(value)); + } else { + char chstr[] = "' '"; + chstr[1] = value; + return chstr; + } +} +std::string StringMaker::convert(signed char c) { + return ::Catch::Detail::stringify(static_cast(c)); +} +std::string StringMaker::convert(unsigned char c) { + return ::Catch::Detail::stringify(static_cast(c)); +} + +std::string StringMaker::convert(std::nullptr_t) { + return "nullptr"; +} + +std::string StringMaker::convert(float value) { + return fpToString(value, 5) + 'f'; +} +std::string StringMaker::convert(double value) { + return fpToString(value, 10); +} + +std::string ratio_string::symbol() { return "a"; } +std::string ratio_string::symbol() { return "f"; } +std::string ratio_string::symbol() { return "p"; } +std::string ratio_string::symbol() { return "n"; } +std::string ratio_string::symbol() { return "u"; } +std::string ratio_string::symbol() { return "m"; } + +} // end namespace Catch + +#if defined(__clang__) +# pragma clang diagnostic pop +#endif + +// end catch_tostring.cpp +// start catch_totals.cpp + +namespace Catch { + + Counts Counts::operator - ( Counts const& other ) const { + Counts diff; + diff.passed = passed - other.passed; + diff.failed = failed - other.failed; + diff.failedButOk = failedButOk - other.failedButOk; + return diff; + } + + Counts& Counts::operator += ( Counts const& other ) { + passed += other.passed; + failed += other.failed; + failedButOk += other.failedButOk; + return *this; + } + + std::size_t Counts::total() const { + return passed + failed + failedButOk; + } + bool Counts::allPassed() const { + return failed == 0 && failedButOk == 0; + } + bool Counts::allOk() const { + return failed == 0; + } + + Totals Totals::operator - ( Totals const& other ) const { + Totals diff; + diff.assertions = assertions - other.assertions; + diff.testCases = testCases - other.testCases; + return diff; + } + + Totals& Totals::operator += ( Totals const& other ) { + assertions += other.assertions; + testCases += other.testCases; + return *this; + } + + Totals Totals::delta( Totals const& prevTotals ) const { + Totals diff = *this - prevTotals; + if( diff.assertions.failed > 0 ) + ++diff.testCases.failed; + else if( diff.assertions.failedButOk > 0 ) + ++diff.testCases.failedButOk; + else + ++diff.testCases.passed; + return diff; + } + +} +// end catch_totals.cpp +// start catch_uncaught_exceptions.cpp + +#include + +namespace Catch { + bool uncaught_exceptions() { +#if defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) + return std::uncaught_exceptions() > 0; +#else + return std::uncaught_exception(); +#endif + } +} // end namespace Catch +// end catch_uncaught_exceptions.cpp +// start catch_version.cpp + +#include + +namespace Catch { + + Version::Version + ( unsigned int _majorVersion, + unsigned int _minorVersion, + unsigned int _patchNumber, + char const * const _branchName, + unsigned int _buildNumber ) + : majorVersion( _majorVersion ), + minorVersion( _minorVersion ), + patchNumber( _patchNumber ), + branchName( _branchName ), + buildNumber( _buildNumber ) + {} + + std::ostream& operator << ( std::ostream& os, Version const& version ) { + os << version.majorVersion << '.' + << version.minorVersion << '.' + << version.patchNumber; + // branchName is never null -> 0th char is \0 if it is empty + if (version.branchName[0]) { + os << '-' << version.branchName + << '.' << version.buildNumber; + } + return os; + } + + Version const& libraryVersion() { + static Version version( 2, 3, 0, "", 0 ); + return version; + } + +} +// end catch_version.cpp +// start catch_wildcard_pattern.cpp + +#include + +namespace Catch { + + WildcardPattern::WildcardPattern( std::string const& pattern, + CaseSensitive::Choice caseSensitivity ) + : m_caseSensitivity( caseSensitivity ), + m_pattern( adjustCase( pattern ) ) + { + if( startsWith( m_pattern, '*' ) ) { + m_pattern = m_pattern.substr( 1 ); + m_wildcard = WildcardAtStart; + } + if( endsWith( m_pattern, '*' ) ) { + m_pattern = m_pattern.substr( 0, m_pattern.size()-1 ); + m_wildcard = static_cast( m_wildcard | WildcardAtEnd ); + } + } + + bool WildcardPattern::matches( std::string const& str ) const { + switch( m_wildcard ) { + case NoWildcard: + return m_pattern == adjustCase( str ); + case WildcardAtStart: + return endsWith( adjustCase( str ), m_pattern ); + case WildcardAtEnd: + return startsWith( adjustCase( str ), m_pattern ); + case WildcardAtBothEnds: + return contains( adjustCase( str ), m_pattern ); + default: + CATCH_INTERNAL_ERROR( "Unknown enum" ); + } + } + + std::string WildcardPattern::adjustCase( std::string const& str ) const { + return m_caseSensitivity == CaseSensitive::No ? toLower( str ) : str; + } +} +// end catch_wildcard_pattern.cpp +// start catch_xmlwriter.cpp + +#include + +using uchar = unsigned char; + +namespace Catch { + +namespace { + + size_t trailingBytes(unsigned char c) { + if ((c & 0xE0) == 0xC0) { + return 2; + } + if ((c & 0xF0) == 0xE0) { + return 3; + } + if ((c & 0xF8) == 0xF0) { + return 4; + } + CATCH_INTERNAL_ERROR("Invalid multibyte utf-8 start byte encountered"); + } + + uint32_t headerValue(unsigned char c) { + if ((c & 0xE0) == 0xC0) { + return c & 0x1F; + } + if ((c & 0xF0) == 0xE0) { + return c & 0x0F; + } + if ((c & 0xF8) == 0xF0) { + return c & 0x07; + } + CATCH_INTERNAL_ERROR("Invalid multibyte utf-8 start byte encountered"); + } + + void hexEscapeChar(std::ostream& os, unsigned char c) { + os << "\\x" + << std::uppercase << std::hex << std::setfill('0') << std::setw(2) + << static_cast(c); + } + +} // anonymous namespace + + XmlEncode::XmlEncode( std::string const& str, ForWhat forWhat ) + : m_str( str ), + m_forWhat( forWhat ) + {} + + void XmlEncode::encodeTo( std::ostream& os ) const { + // Apostrophe escaping not necessary if we always use " to write attributes + // (see: http://www.w3.org/TR/xml/#syntax) + + for( std::size_t idx = 0; idx < m_str.size(); ++ idx ) { + uchar c = m_str[idx]; + switch (c) { + case '<': os << "<"; break; + case '&': os << "&"; break; + + case '>': + // See: http://www.w3.org/TR/xml/#syntax + if (idx > 2 && m_str[idx - 1] == ']' && m_str[idx - 2] == ']') + os << ">"; + else + os << c; + break; + + case '\"': + if (m_forWhat == ForAttributes) + os << """; + else + os << c; + break; + + default: + // Check for control characters and invalid utf-8 + + // Escape control characters in standard ascii + // see http://stackoverflow.com/questions/404107/why-are-control-characters-illegal-in-xml-1-0 + if (c < 0x09 || (c > 0x0D && c < 0x20) || c == 0x7F) { + hexEscapeChar(os, c); + break; + } + + // Plain ASCII: Write it to stream + if (c < 0x7F) { + os << c; + break; + } + + // UTF-8 territory + // Check if the encoding is valid and if it is not, hex escape bytes. + // Important: We do not check the exact decoded values for validity, only the encoding format + // First check that this bytes is a valid lead byte: + // This means that it is not encoded as 1111 1XXX + // Or as 10XX XXXX + if (c < 0xC0 || + c >= 0xF8) { + hexEscapeChar(os, c); + break; + } + + auto encBytes = trailingBytes(c); + // Are there enough bytes left to avoid accessing out-of-bounds memory? + if (idx + encBytes - 1 >= m_str.size()) { + hexEscapeChar(os, c); + break; + } + // The header is valid, check data + // The next encBytes bytes must together be a valid utf-8 + // This means: bitpattern 10XX XXXX and the extracted value is sane (ish) + bool valid = true; + uint32_t value = headerValue(c); + for (std::size_t n = 1; n < encBytes; ++n) { + uchar nc = m_str[idx + n]; + valid &= ((nc & 0xC0) == 0x80); + value = (value << 6) | (nc & 0x3F); + } + + if ( + // Wrong bit pattern of following bytes + (!valid) || + // Overlong encodings + (value < 0x80) || + (0x80 <= value && value < 0x800 && encBytes > 2) || + (0x800 < value && value < 0x10000 && encBytes > 3) || + // Encoded value out of range + (value >= 0x110000) + ) { + hexEscapeChar(os, c); + break; + } + + // If we got here, this is in fact a valid(ish) utf-8 sequence + for (std::size_t n = 0; n < encBytes; ++n) { + os << m_str[idx + n]; + } + idx += encBytes - 1; + break; + } + } + } + + std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ) { + xmlEncode.encodeTo( os ); + return os; + } + + XmlWriter::ScopedElement::ScopedElement( XmlWriter* writer ) + : m_writer( writer ) + {} + + XmlWriter::ScopedElement::ScopedElement( ScopedElement&& other ) noexcept + : m_writer( other.m_writer ){ + other.m_writer = nullptr; + } + XmlWriter::ScopedElement& XmlWriter::ScopedElement::operator=( ScopedElement&& other ) noexcept { + if ( m_writer ) { + m_writer->endElement(); + } + m_writer = other.m_writer; + other.m_writer = nullptr; + return *this; + } + + XmlWriter::ScopedElement::~ScopedElement() { + if( m_writer ) + m_writer->endElement(); + } + + XmlWriter::ScopedElement& XmlWriter::ScopedElement::writeText( std::string const& text, bool indent ) { + m_writer->writeText( text, indent ); + return *this; + } + + XmlWriter::XmlWriter( std::ostream& os ) : m_os( os ) + { + writeDeclaration(); + } + + XmlWriter::~XmlWriter() { + while( !m_tags.empty() ) + endElement(); + } + + XmlWriter& XmlWriter::startElement( std::string const& name ) { + ensureTagClosed(); + newlineIfNecessary(); + m_os << m_indent << '<' << name; + m_tags.push_back( name ); + m_indent += " "; + m_tagIsOpen = true; + return *this; + } + + XmlWriter::ScopedElement XmlWriter::scopedElement( std::string const& name ) { + ScopedElement scoped( this ); + startElement( name ); + return scoped; + } + + XmlWriter& XmlWriter::endElement() { + newlineIfNecessary(); + m_indent = m_indent.substr( 0, m_indent.size()-2 ); + if( m_tagIsOpen ) { + m_os << "/>"; + m_tagIsOpen = false; + } + else { + m_os << m_indent << ""; + } + m_os << std::endl; + m_tags.pop_back(); + return *this; + } + + XmlWriter& XmlWriter::writeAttribute( std::string const& name, std::string const& attribute ) { + if( !name.empty() && !attribute.empty() ) + m_os << ' ' << name << "=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << '"'; + return *this; + } + + XmlWriter& XmlWriter::writeAttribute( std::string const& name, bool attribute ) { + m_os << ' ' << name << "=\"" << ( attribute ? "true" : "false" ) << '"'; + return *this; + } + + XmlWriter& XmlWriter::writeText( std::string const& text, bool indent ) { + if( !text.empty() ){ + bool tagWasOpen = m_tagIsOpen; + ensureTagClosed(); + if( tagWasOpen && indent ) + m_os << m_indent; + m_os << XmlEncode( text ); + m_needsNewline = true; + } + return *this; + } + + XmlWriter& XmlWriter::writeComment( std::string const& text ) { + ensureTagClosed(); + m_os << m_indent << ""; + m_needsNewline = true; + return *this; + } + + void XmlWriter::writeStylesheetRef( std::string const& url ) { + m_os << "\n"; + } + + XmlWriter& XmlWriter::writeBlankLine() { + ensureTagClosed(); + m_os << '\n'; + return *this; + } + + void XmlWriter::ensureTagClosed() { + if( m_tagIsOpen ) { + m_os << ">" << std::endl; + m_tagIsOpen = false; + } + } + + void XmlWriter::writeDeclaration() { + m_os << "\n"; + } + + void XmlWriter::newlineIfNecessary() { + if( m_needsNewline ) { + m_os << std::endl; + m_needsNewline = false; + } + } +} +// end catch_xmlwriter.cpp +// start catch_reporter_bases.cpp + +#include +#include +#include +#include +#include + +namespace Catch { + void prepareExpandedExpression(AssertionResult& result) { + result.getExpandedExpression(); + } + + // Because formatting using c++ streams is stateful, drop down to C is required + // Alternatively we could use stringstream, but its performance is... not good. + std::string getFormattedDuration( double duration ) { + // Max exponent + 1 is required to represent the whole part + // + 1 for decimal point + // + 3 for the 3 decimal places + // + 1 for null terminator + const std::size_t maxDoubleSize = DBL_MAX_10_EXP + 1 + 1 + 3 + 1; + char buffer[maxDoubleSize]; + + // Save previous errno, to prevent sprintf from overwriting it + ErrnoGuard guard; +#ifdef _MSC_VER + sprintf_s(buffer, "%.3f", duration); +#else + sprintf(buffer, "%.3f", duration); +#endif + return std::string(buffer); + } + + TestEventListenerBase::TestEventListenerBase(ReporterConfig const & _config) + :StreamingReporterBase(_config) {} + + void TestEventListenerBase::assertionStarting(AssertionInfo const &) {} + + bool TestEventListenerBase::assertionEnded(AssertionStats const &) { + return false; + } + +} // end namespace Catch +// end catch_reporter_bases.cpp +// start catch_reporter_compact.cpp + +namespace { + +#ifdef CATCH_PLATFORM_MAC + const char* failedString() { return "FAILED"; } + const char* passedString() { return "PASSED"; } +#else + const char* failedString() { return "failed"; } + const char* passedString() { return "passed"; } +#endif + + // Colour::LightGrey + Catch::Colour::Code dimColour() { return Catch::Colour::FileName; } + + std::string bothOrAll( std::size_t count ) { + return count == 1 ? std::string() : + count == 2 ? "both " : "all " ; + } + +} // anon namespace + +namespace Catch { +namespace { +// Colour, message variants: +// - white: No tests ran. +// - red: Failed [both/all] N test cases, failed [both/all] M assertions. +// - white: Passed [both/all] N test cases (no assertions). +// - red: Failed N tests cases, failed M assertions. +// - green: Passed [both/all] N tests cases with M assertions. +void printTotals(std::ostream& out, const Totals& totals) { + if (totals.testCases.total() == 0) { + out << "No tests ran."; + } else if (totals.testCases.failed == totals.testCases.total()) { + Colour colour(Colour::ResultError); + const std::string qualify_assertions_failed = + totals.assertions.failed == totals.assertions.total() ? + bothOrAll(totals.assertions.failed) : std::string(); + out << + "Failed " << bothOrAll(totals.testCases.failed) + << pluralise(totals.testCases.failed, "test case") << ", " + "failed " << qualify_assertions_failed << + pluralise(totals.assertions.failed, "assertion") << '.'; + } else if (totals.assertions.total() == 0) { + out << + "Passed " << bothOrAll(totals.testCases.total()) + << pluralise(totals.testCases.total(), "test case") + << " (no assertions)."; + } else if (totals.assertions.failed) { + Colour colour(Colour::ResultError); + out << + "Failed " << pluralise(totals.testCases.failed, "test case") << ", " + "failed " << pluralise(totals.assertions.failed, "assertion") << '.'; + } else { + Colour colour(Colour::ResultSuccess); + out << + "Passed " << bothOrAll(totals.testCases.passed) + << pluralise(totals.testCases.passed, "test case") << + " with " << pluralise(totals.assertions.passed, "assertion") << '.'; + } +} + +// Implementation of CompactReporter formatting +class AssertionPrinter { +public: + AssertionPrinter& operator= (AssertionPrinter const&) = delete; + AssertionPrinter(AssertionPrinter const&) = delete; + AssertionPrinter(std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages) + : stream(_stream) + , result(_stats.assertionResult) + , messages(_stats.infoMessages) + , itMessage(_stats.infoMessages.begin()) + , printInfoMessages(_printInfoMessages) {} + + void print() { + printSourceInfo(); + + itMessage = messages.begin(); + + switch (result.getResultType()) { + case ResultWas::Ok: + printResultType(Colour::ResultSuccess, passedString()); + printOriginalExpression(); + printReconstructedExpression(); + if (!result.hasExpression()) + printRemainingMessages(Colour::None); + else + printRemainingMessages(); + break; + case ResultWas::ExpressionFailed: + if (result.isOk()) + printResultType(Colour::ResultSuccess, failedString() + std::string(" - but was ok")); + else + printResultType(Colour::Error, failedString()); + printOriginalExpression(); + printReconstructedExpression(); + printRemainingMessages(); + break; + case ResultWas::ThrewException: + printResultType(Colour::Error, failedString()); + printIssue("unexpected exception with message:"); + printMessage(); + printExpressionWas(); + printRemainingMessages(); + break; + case ResultWas::FatalErrorCondition: + printResultType(Colour::Error, failedString()); + printIssue("fatal error condition with message:"); + printMessage(); + printExpressionWas(); + printRemainingMessages(); + break; + case ResultWas::DidntThrowException: + printResultType(Colour::Error, failedString()); + printIssue("expected exception, got none"); + printExpressionWas(); + printRemainingMessages(); + break; + case ResultWas::Info: + printResultType(Colour::None, "info"); + printMessage(); + printRemainingMessages(); + break; + case ResultWas::Warning: + printResultType(Colour::None, "warning"); + printMessage(); + printRemainingMessages(); + break; + case ResultWas::ExplicitFailure: + printResultType(Colour::Error, failedString()); + printIssue("explicitly"); + printRemainingMessages(Colour::None); + break; + // These cases are here to prevent compiler warnings + case ResultWas::Unknown: + case ResultWas::FailureBit: + case ResultWas::Exception: + printResultType(Colour::Error, "** internal error **"); + break; + } + } + +private: + void printSourceInfo() const { + Colour colourGuard(Colour::FileName); + stream << result.getSourceInfo() << ':'; + } + + void printResultType(Colour::Code colour, std::string const& passOrFail) const { + if (!passOrFail.empty()) { + { + Colour colourGuard(colour); + stream << ' ' << passOrFail; + } + stream << ':'; + } + } + + void printIssue(std::string const& issue) const { + stream << ' ' << issue; + } + + void printExpressionWas() { + if (result.hasExpression()) { + stream << ';'; + { + Colour colour(dimColour()); + stream << " expression was:"; + } + printOriginalExpression(); + } + } + + void printOriginalExpression() const { + if (result.hasExpression()) { + stream << ' ' << result.getExpression(); + } + } + + void printReconstructedExpression() const { + if (result.hasExpandedExpression()) { + { + Colour colour(dimColour()); + stream << " for: "; + } + stream << result.getExpandedExpression(); + } + } + + void printMessage() { + if (itMessage != messages.end()) { + stream << " '" << itMessage->message << '\''; + ++itMessage; + } + } + + void printRemainingMessages(Colour::Code colour = dimColour()) { + if (itMessage == messages.end()) + return; + + // using messages.end() directly yields (or auto) compilation error: + std::vector::const_iterator itEnd = messages.end(); + const std::size_t N = static_cast(std::distance(itMessage, itEnd)); + + { + Colour colourGuard(colour); + stream << " with " << pluralise(N, "message") << ':'; + } + + for (; itMessage != itEnd; ) { + // If this assertion is a warning ignore any INFO messages + if (printInfoMessages || itMessage->type != ResultWas::Info) { + stream << " '" << itMessage->message << '\''; + if (++itMessage != itEnd) { + Colour colourGuard(dimColour()); + stream << " and"; + } + } + } + } + +private: + std::ostream& stream; + AssertionResult const& result; + std::vector messages; + std::vector::const_iterator itMessage; + bool printInfoMessages; +}; + +} // anon namespace + + std::string CompactReporter::getDescription() { + return "Reports test results on a single line, suitable for IDEs"; + } + + ReporterPreferences CompactReporter::getPreferences() const { + return m_reporterPrefs; + } + + void CompactReporter::noMatchingTestCases( std::string const& spec ) { + stream << "No test cases matched '" << spec << '\'' << std::endl; + } + + void CompactReporter::assertionStarting( AssertionInfo const& ) {} + + bool CompactReporter::assertionEnded( AssertionStats const& _assertionStats ) { + AssertionResult const& result = _assertionStats.assertionResult; + + bool printInfoMessages = true; + + // Drop out if result was successful and we're not printing those + if( !m_config->includeSuccessfulResults() && result.isOk() ) { + if( result.getResultType() != ResultWas::Warning ) + return false; + printInfoMessages = false; + } + + AssertionPrinter printer( stream, _assertionStats, printInfoMessages ); + printer.print(); + + stream << std::endl; + return true; + } + + void CompactReporter::sectionEnded(SectionStats const& _sectionStats) { + if (m_config->showDurations() == ShowDurations::Always) { + stream << getFormattedDuration(_sectionStats.durationInSeconds) << " s: " << _sectionStats.sectionInfo.name << std::endl; + } + } + + void CompactReporter::testRunEnded( TestRunStats const& _testRunStats ) { + printTotals( stream, _testRunStats.totals ); + stream << '\n' << std::endl; + StreamingReporterBase::testRunEnded( _testRunStats ); + } + + CompactReporter::~CompactReporter() {} + + CATCH_REGISTER_REPORTER( "compact", CompactReporter ) + +} // end namespace Catch +// end catch_reporter_compact.cpp +// start catch_reporter_console.cpp + +#include +#include + +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable:4061) // Not all labels are EXPLICITLY handled in switch + // Note that 4062 (not all labels are handled + // and default is missing) is enabled +#endif + +namespace Catch { + +namespace { + +// Formatter impl for ConsoleReporter +class ConsoleAssertionPrinter { +public: + ConsoleAssertionPrinter& operator= (ConsoleAssertionPrinter const&) = delete; + ConsoleAssertionPrinter(ConsoleAssertionPrinter const&) = delete; + ConsoleAssertionPrinter(std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages) + : stream(_stream), + stats(_stats), + result(_stats.assertionResult), + colour(Colour::None), + message(result.getMessage()), + messages(_stats.infoMessages), + printInfoMessages(_printInfoMessages) { + switch (result.getResultType()) { + case ResultWas::Ok: + colour = Colour::Success; + passOrFail = "PASSED"; + //if( result.hasMessage() ) + if (_stats.infoMessages.size() == 1) + messageLabel = "with message"; + if (_stats.infoMessages.size() > 1) + messageLabel = "with messages"; + break; + case ResultWas::ExpressionFailed: + if (result.isOk()) { + colour = Colour::Success; + passOrFail = "FAILED - but was ok"; + } else { + colour = Colour::Error; + passOrFail = "FAILED"; + } + if (_stats.infoMessages.size() == 1) + messageLabel = "with message"; + if (_stats.infoMessages.size() > 1) + messageLabel = "with messages"; + break; + case ResultWas::ThrewException: + colour = Colour::Error; + passOrFail = "FAILED"; + messageLabel = "due to unexpected exception with "; + if (_stats.infoMessages.size() == 1) + messageLabel += "message"; + if (_stats.infoMessages.size() > 1) + messageLabel += "messages"; + break; + case ResultWas::FatalErrorCondition: + colour = Colour::Error; + passOrFail = "FAILED"; + messageLabel = "due to a fatal error condition"; + break; + case ResultWas::DidntThrowException: + colour = Colour::Error; + passOrFail = "FAILED"; + messageLabel = "because no exception was thrown where one was expected"; + break; + case ResultWas::Info: + messageLabel = "info"; + break; + case ResultWas::Warning: + messageLabel = "warning"; + break; + case ResultWas::ExplicitFailure: + passOrFail = "FAILED"; + colour = Colour::Error; + if (_stats.infoMessages.size() == 1) + messageLabel = "explicitly with message"; + if (_stats.infoMessages.size() > 1) + messageLabel = "explicitly with messages"; + break; + // These cases are here to prevent compiler warnings + case ResultWas::Unknown: + case ResultWas::FailureBit: + case ResultWas::Exception: + passOrFail = "** internal error **"; + colour = Colour::Error; + break; + } + } + + void print() const { + printSourceInfo(); + if (stats.totals.assertions.total() > 0) { + if (result.isOk()) + stream << '\n'; + printResultType(); + printOriginalExpression(); + printReconstructedExpression(); + } else { + stream << '\n'; + } + printMessage(); + } + +private: + void printResultType() const { + if (!passOrFail.empty()) { + Colour colourGuard(colour); + stream << passOrFail << ":\n"; + } + } + void printOriginalExpression() const { + if (result.hasExpression()) { + Colour colourGuard(Colour::OriginalExpression); + stream << " "; + stream << result.getExpressionInMacro(); + stream << '\n'; + } + } + void printReconstructedExpression() const { + if (result.hasExpandedExpression()) { + stream << "with expansion:\n"; + Colour colourGuard(Colour::ReconstructedExpression); + stream << Column(result.getExpandedExpression()).indent(2) << '\n'; + } + } + void printMessage() const { + if (!messageLabel.empty()) + stream << messageLabel << ':' << '\n'; + for (auto const& msg : messages) { + // If this assertion is a warning ignore any INFO messages + if (printInfoMessages || msg.type != ResultWas::Info) + stream << Column(msg.message).indent(2) << '\n'; + } + } + void printSourceInfo() const { + Colour colourGuard(Colour::FileName); + stream << result.getSourceInfo() << ": "; + } + + std::ostream& stream; + AssertionStats const& stats; + AssertionResult const& result; + Colour::Code colour; + std::string passOrFail; + std::string messageLabel; + std::string message; + std::vector messages; + bool printInfoMessages; +}; + +std::size_t makeRatio(std::size_t number, std::size_t total) { + std::size_t ratio = total > 0 ? CATCH_CONFIG_CONSOLE_WIDTH * number / total : 0; + return (ratio == 0 && number > 0) ? 1 : ratio; +} + +std::size_t& findMax(std::size_t& i, std::size_t& j, std::size_t& k) { + if (i > j && i > k) + return i; + else if (j > k) + return j; + else + return k; +} + +struct ColumnInfo { + enum Justification { Left, Right }; + std::string name; + int width; + Justification justification; +}; +struct ColumnBreak {}; +struct RowBreak {}; + +class Duration { + enum class Unit { + Auto, + Nanoseconds, + Microseconds, + Milliseconds, + Seconds, + Minutes + }; + static const uint64_t s_nanosecondsInAMicrosecond = 1000; + static const uint64_t s_nanosecondsInAMillisecond = 1000 * s_nanosecondsInAMicrosecond; + static const uint64_t s_nanosecondsInASecond = 1000 * s_nanosecondsInAMillisecond; + static const uint64_t s_nanosecondsInAMinute = 60 * s_nanosecondsInASecond; + + uint64_t m_inNanoseconds; + Unit m_units; + +public: + explicit Duration(uint64_t inNanoseconds, Unit units = Unit::Auto) + : m_inNanoseconds(inNanoseconds), + m_units(units) { + if (m_units == Unit::Auto) { + if (m_inNanoseconds < s_nanosecondsInAMicrosecond) + m_units = Unit::Nanoseconds; + else if (m_inNanoseconds < s_nanosecondsInAMillisecond) + m_units = Unit::Microseconds; + else if (m_inNanoseconds < s_nanosecondsInASecond) + m_units = Unit::Milliseconds; + else if (m_inNanoseconds < s_nanosecondsInAMinute) + m_units = Unit::Seconds; + else + m_units = Unit::Minutes; + } + + } + + auto value() const -> double { + switch (m_units) { + case Unit::Microseconds: + return m_inNanoseconds / static_cast(s_nanosecondsInAMicrosecond); + case Unit::Milliseconds: + return m_inNanoseconds / static_cast(s_nanosecondsInAMillisecond); + case Unit::Seconds: + return m_inNanoseconds / static_cast(s_nanosecondsInASecond); + case Unit::Minutes: + return m_inNanoseconds / static_cast(s_nanosecondsInAMinute); + default: + return static_cast(m_inNanoseconds); + } + } + auto unitsAsString() const -> std::string { + switch (m_units) { + case Unit::Nanoseconds: + return "ns"; + case Unit::Microseconds: + return "µs"; + case Unit::Milliseconds: + return "ms"; + case Unit::Seconds: + return "s"; + case Unit::Minutes: + return "m"; + default: + return "** internal error **"; + } + + } + friend auto operator << (std::ostream& os, Duration const& duration) -> std::ostream& { + return os << duration.value() << " " << duration.unitsAsString(); + } +}; +} // end anon namespace + +class TablePrinter { + std::ostream& m_os; + std::vector m_columnInfos; + std::ostringstream m_oss; + int m_currentColumn = -1; + bool m_isOpen = false; + +public: + TablePrinter( std::ostream& os, std::vector columnInfos ) + : m_os( os ), + m_columnInfos( std::move( columnInfos ) ) {} + + auto columnInfos() const -> std::vector const& { + return m_columnInfos; + } + + void open() { + if (!m_isOpen) { + m_isOpen = true; + *this << RowBreak(); + for (auto const& info : m_columnInfos) + *this << info.name << ColumnBreak(); + *this << RowBreak(); + m_os << Catch::getLineOfChars<'-'>() << "\n"; + } + } + void close() { + if (m_isOpen) { + *this << RowBreak(); + m_os << std::endl; + m_isOpen = false; + } + } + + template + friend TablePrinter& operator << (TablePrinter& tp, T const& value) { + tp.m_oss << value; + return tp; + } + + friend TablePrinter& operator << (TablePrinter& tp, ColumnBreak) { + auto colStr = tp.m_oss.str(); + // This takes account of utf8 encodings + auto strSize = Catch::StringRef(colStr).numberOfCharacters(); + tp.m_oss.str(""); + tp.open(); + if (tp.m_currentColumn == static_cast(tp.m_columnInfos.size() - 1)) { + tp.m_currentColumn = -1; + tp.m_os << "\n"; + } + tp.m_currentColumn++; + + auto colInfo = tp.m_columnInfos[tp.m_currentColumn]; + auto padding = (strSize + 2 < static_cast(colInfo.width)) + ? std::string(colInfo.width - (strSize + 2), ' ') + : std::string(); + if (colInfo.justification == ColumnInfo::Left) + tp.m_os << colStr << padding << " "; + else + tp.m_os << padding << colStr << " "; + return tp; + } + + friend TablePrinter& operator << (TablePrinter& tp, RowBreak) { + if (tp.m_currentColumn > 0) { + tp.m_os << "\n"; + tp.m_currentColumn = -1; + } + return tp; + } +}; + +ConsoleReporter::ConsoleReporter(ReporterConfig const& config) + : StreamingReporterBase(config), + m_tablePrinter(new TablePrinter(config.stream(), + { + { "benchmark name", CATCH_CONFIG_CONSOLE_WIDTH - 32, ColumnInfo::Left }, + { "iters", 8, ColumnInfo::Right }, + { "elapsed ns", 14, ColumnInfo::Right }, + { "average", 14, ColumnInfo::Right } + })) {} +ConsoleReporter::~ConsoleReporter() = default; + +std::string ConsoleReporter::getDescription() { + return "Reports test results as plain lines of text"; +} + +void ConsoleReporter::noMatchingTestCases(std::string const& spec) { + stream << "No test cases matched '" << spec << '\'' << std::endl; +} + +void ConsoleReporter::assertionStarting(AssertionInfo const&) {} + +bool ConsoleReporter::assertionEnded(AssertionStats const& _assertionStats) { + AssertionResult const& result = _assertionStats.assertionResult; + + bool includeResults = m_config->includeSuccessfulResults() || !result.isOk(); + + // Drop out if result was successful but we're not printing them. + if (!includeResults && result.getResultType() != ResultWas::Warning) + return false; + + lazyPrint(); + + ConsoleAssertionPrinter printer(stream, _assertionStats, includeResults); + printer.print(); + stream << std::endl; + return true; +} + +void ConsoleReporter::sectionStarting(SectionInfo const& _sectionInfo) { + m_headerPrinted = false; + StreamingReporterBase::sectionStarting(_sectionInfo); +} +void ConsoleReporter::sectionEnded(SectionStats const& _sectionStats) { + m_tablePrinter->close(); + if (_sectionStats.missingAssertions) { + lazyPrint(); + Colour colour(Colour::ResultError); + if (m_sectionStack.size() > 1) + stream << "\nNo assertions in section"; + else + stream << "\nNo assertions in test case"; + stream << " '" << _sectionStats.sectionInfo.name << "'\n" << std::endl; + } + if (m_config->showDurations() == ShowDurations::Always) { + stream << getFormattedDuration(_sectionStats.durationInSeconds) << " s: " << _sectionStats.sectionInfo.name << std::endl; + } + if (m_headerPrinted) { + m_headerPrinted = false; + } + StreamingReporterBase::sectionEnded(_sectionStats); +} + +void ConsoleReporter::benchmarkStarting(BenchmarkInfo const& info) { + lazyPrintWithoutClosingBenchmarkTable(); + + auto nameCol = Column( info.name ).width( static_cast( m_tablePrinter->columnInfos()[0].width - 2 ) ); + + bool firstLine = true; + for (auto line : nameCol) { + if (!firstLine) + (*m_tablePrinter) << ColumnBreak() << ColumnBreak() << ColumnBreak(); + else + firstLine = false; + + (*m_tablePrinter) << line << ColumnBreak(); + } +} +void ConsoleReporter::benchmarkEnded(BenchmarkStats const& stats) { + Duration average(stats.elapsedTimeInNanoseconds / stats.iterations); + (*m_tablePrinter) + << stats.iterations << ColumnBreak() + << stats.elapsedTimeInNanoseconds << ColumnBreak() + << average << ColumnBreak(); +} + +void ConsoleReporter::testCaseEnded(TestCaseStats const& _testCaseStats) { + m_tablePrinter->close(); + StreamingReporterBase::testCaseEnded(_testCaseStats); + m_headerPrinted = false; +} +void ConsoleReporter::testGroupEnded(TestGroupStats const& _testGroupStats) { + if (currentGroupInfo.used) { + printSummaryDivider(); + stream << "Summary for group '" << _testGroupStats.groupInfo.name << "':\n"; + printTotals(_testGroupStats.totals); + stream << '\n' << std::endl; + } + StreamingReporterBase::testGroupEnded(_testGroupStats); +} +void ConsoleReporter::testRunEnded(TestRunStats const& _testRunStats) { + printTotalsDivider(_testRunStats.totals); + printTotals(_testRunStats.totals); + stream << std::endl; + StreamingReporterBase::testRunEnded(_testRunStats); +} + +void ConsoleReporter::lazyPrint() { + + m_tablePrinter->close(); + lazyPrintWithoutClosingBenchmarkTable(); +} + +void ConsoleReporter::lazyPrintWithoutClosingBenchmarkTable() { + + if (!currentTestRunInfo.used) + lazyPrintRunInfo(); + if (!currentGroupInfo.used) + lazyPrintGroupInfo(); + + if (!m_headerPrinted) { + printTestCaseAndSectionHeader(); + m_headerPrinted = true; + } +} +void ConsoleReporter::lazyPrintRunInfo() { + stream << '\n' << getLineOfChars<'~'>() << '\n'; + Colour colour(Colour::SecondaryText); + stream << currentTestRunInfo->name + << " is a Catch v" << libraryVersion() << " host application.\n" + << "Run with -? for options\n\n"; + + if (m_config->rngSeed() != 0) + stream << "Randomness seeded to: " << m_config->rngSeed() << "\n\n"; + + currentTestRunInfo.used = true; +} +void ConsoleReporter::lazyPrintGroupInfo() { + if (!currentGroupInfo->name.empty() && currentGroupInfo->groupsCounts > 1) { + printClosedHeader("Group: " + currentGroupInfo->name); + currentGroupInfo.used = true; + } +} +void ConsoleReporter::printTestCaseAndSectionHeader() { + assert(!m_sectionStack.empty()); + printOpenHeader(currentTestCaseInfo->name); + + if (m_sectionStack.size() > 1) { + Colour colourGuard(Colour::Headers); + + auto + it = m_sectionStack.begin() + 1, // Skip first section (test case) + itEnd = m_sectionStack.end(); + for (; it != itEnd; ++it) + printHeaderString(it->name, 2); + } + + SourceLineInfo lineInfo = m_sectionStack.back().lineInfo; + + if (!lineInfo.empty()) { + stream << getLineOfChars<'-'>() << '\n'; + Colour colourGuard(Colour::FileName); + stream << lineInfo << '\n'; + } + stream << getLineOfChars<'.'>() << '\n' << std::endl; +} + +void ConsoleReporter::printClosedHeader(std::string const& _name) { + printOpenHeader(_name); + stream << getLineOfChars<'.'>() << '\n'; +} +void ConsoleReporter::printOpenHeader(std::string const& _name) { + stream << getLineOfChars<'-'>() << '\n'; + { + Colour colourGuard(Colour::Headers); + printHeaderString(_name); + } +} + +// if string has a : in first line will set indent to follow it on +// subsequent lines +void ConsoleReporter::printHeaderString(std::string const& _string, std::size_t indent) { + std::size_t i = _string.find(": "); + if (i != std::string::npos) + i += 2; + else + i = 0; + stream << Column(_string).indent(indent + i).initialIndent(indent) << '\n'; +} + +struct SummaryColumn { + + SummaryColumn( std::string _label, Colour::Code _colour ) + : label( std::move( _label ) ), + colour( _colour ) {} + SummaryColumn addRow( std::size_t count ) { + ReusableStringStream rss; + rss << count; + std::string row = rss.str(); + for (auto& oldRow : rows) { + while (oldRow.size() < row.size()) + oldRow = ' ' + oldRow; + while (oldRow.size() > row.size()) + row = ' ' + row; + } + rows.push_back(row); + return *this; + } + + std::string label; + Colour::Code colour; + std::vector rows; + +}; + +void ConsoleReporter::printTotals( Totals const& totals ) { + if (totals.testCases.total() == 0) { + stream << Colour(Colour::Warning) << "No tests ran\n"; + } else if (totals.assertions.total() > 0 && totals.testCases.allPassed()) { + stream << Colour(Colour::ResultSuccess) << "All tests passed"; + stream << " (" + << pluralise(totals.assertions.passed, "assertion") << " in " + << pluralise(totals.testCases.passed, "test case") << ')' + << '\n'; + } else { + + std::vector columns; + columns.push_back(SummaryColumn("", Colour::None) + .addRow(totals.testCases.total()) + .addRow(totals.assertions.total())); + columns.push_back(SummaryColumn("passed", Colour::Success) + .addRow(totals.testCases.passed) + .addRow(totals.assertions.passed)); + columns.push_back(SummaryColumn("failed", Colour::ResultError) + .addRow(totals.testCases.failed) + .addRow(totals.assertions.failed)); + columns.push_back(SummaryColumn("failed as expected", Colour::ResultExpectedFailure) + .addRow(totals.testCases.failedButOk) + .addRow(totals.assertions.failedButOk)); + + printSummaryRow("test cases", columns, 0); + printSummaryRow("assertions", columns, 1); + } +} +void ConsoleReporter::printSummaryRow(std::string const& label, std::vector const& cols, std::size_t row) { + for (auto col : cols) { + std::string value = col.rows[row]; + if (col.label.empty()) { + stream << label << ": "; + if (value != "0") + stream << value; + else + stream << Colour(Colour::Warning) << "- none -"; + } else if (value != "0") { + stream << Colour(Colour::LightGrey) << " | "; + stream << Colour(col.colour) + << value << ' ' << col.label; + } + } + stream << '\n'; +} + +void ConsoleReporter::printTotalsDivider(Totals const& totals) { + if (totals.testCases.total() > 0) { + std::size_t failedRatio = makeRatio(totals.testCases.failed, totals.testCases.total()); + std::size_t failedButOkRatio = makeRatio(totals.testCases.failedButOk, totals.testCases.total()); + std::size_t passedRatio = makeRatio(totals.testCases.passed, totals.testCases.total()); + while (failedRatio + failedButOkRatio + passedRatio < CATCH_CONFIG_CONSOLE_WIDTH - 1) + findMax(failedRatio, failedButOkRatio, passedRatio)++; + while (failedRatio + failedButOkRatio + passedRatio > CATCH_CONFIG_CONSOLE_WIDTH - 1) + findMax(failedRatio, failedButOkRatio, passedRatio)--; + + stream << Colour(Colour::Error) << std::string(failedRatio, '='); + stream << Colour(Colour::ResultExpectedFailure) << std::string(failedButOkRatio, '='); + if (totals.testCases.allPassed()) + stream << Colour(Colour::ResultSuccess) << std::string(passedRatio, '='); + else + stream << Colour(Colour::Success) << std::string(passedRatio, '='); + } else { + stream << Colour(Colour::Warning) << std::string(CATCH_CONFIG_CONSOLE_WIDTH - 1, '='); + } + stream << '\n'; +} +void ConsoleReporter::printSummaryDivider() { + stream << getLineOfChars<'-'>() << '\n'; +} + +CATCH_REGISTER_REPORTER("console", ConsoleReporter) + +} // end namespace Catch + +#if defined(_MSC_VER) +#pragma warning(pop) +#endif +// end catch_reporter_console.cpp +// start catch_reporter_junit.cpp + +#include +#include +#include +#include + +namespace Catch { + + namespace { + std::string getCurrentTimestamp() { + // Beware, this is not reentrant because of backward compatibility issues + // Also, UTC only, again because of backward compatibility (%z is C++11) + time_t rawtime; + std::time(&rawtime); + auto const timeStampSize = sizeof("2017-01-16T17:06:45Z"); + +#ifdef _MSC_VER + std::tm timeInfo = {}; + gmtime_s(&timeInfo, &rawtime); +#else + std::tm* timeInfo; + timeInfo = std::gmtime(&rawtime); +#endif + + char timeStamp[timeStampSize]; + const char * const fmt = "%Y-%m-%dT%H:%M:%SZ"; + +#ifdef _MSC_VER + std::strftime(timeStamp, timeStampSize, fmt, &timeInfo); +#else + std::strftime(timeStamp, timeStampSize, fmt, timeInfo); +#endif + return std::string(timeStamp); + } + + std::string fileNameTag(const std::vector &tags) { + auto it = std::find_if(begin(tags), + end(tags), + [] (std::string const& tag) {return tag.front() == '#'; }); + if (it != tags.end()) + return it->substr(1); + return std::string(); + } + } // anonymous namespace + + JunitReporter::JunitReporter( ReporterConfig const& _config ) + : CumulativeReporterBase( _config ), + xml( _config.stream() ) + { + m_reporterPrefs.shouldRedirectStdOut = true; + m_reporterPrefs.shouldReportAllAssertions = true; + } + + JunitReporter::~JunitReporter() {} + + std::string JunitReporter::getDescription() { + return "Reports test results in an XML format that looks like Ant's junitreport target"; + } + + void JunitReporter::noMatchingTestCases( std::string const& /*spec*/ ) {} + + void JunitReporter::testRunStarting( TestRunInfo const& runInfo ) { + CumulativeReporterBase::testRunStarting( runInfo ); + xml.startElement( "testsuites" ); + } + + void JunitReporter::testGroupStarting( GroupInfo const& groupInfo ) { + suiteTimer.start(); + stdOutForSuite.clear(); + stdErrForSuite.clear(); + unexpectedExceptions = 0; + CumulativeReporterBase::testGroupStarting( groupInfo ); + } + + void JunitReporter::testCaseStarting( TestCaseInfo const& testCaseInfo ) { + m_okToFail = testCaseInfo.okToFail(); + } + + bool JunitReporter::assertionEnded( AssertionStats const& assertionStats ) { + if( assertionStats.assertionResult.getResultType() == ResultWas::ThrewException && !m_okToFail ) + unexpectedExceptions++; + return CumulativeReporterBase::assertionEnded( assertionStats ); + } + + void JunitReporter::testCaseEnded( TestCaseStats const& testCaseStats ) { + stdOutForSuite += testCaseStats.stdOut; + stdErrForSuite += testCaseStats.stdErr; + CumulativeReporterBase::testCaseEnded( testCaseStats ); + } + + void JunitReporter::testGroupEnded( TestGroupStats const& testGroupStats ) { + double suiteTime = suiteTimer.getElapsedSeconds(); + CumulativeReporterBase::testGroupEnded( testGroupStats ); + writeGroup( *m_testGroups.back(), suiteTime ); + } + + void JunitReporter::testRunEndedCumulative() { + xml.endElement(); + } + + void JunitReporter::writeGroup( TestGroupNode const& groupNode, double suiteTime ) { + XmlWriter::ScopedElement e = xml.scopedElement( "testsuite" ); + TestGroupStats const& stats = groupNode.value; + xml.writeAttribute( "name", stats.groupInfo.name ); + xml.writeAttribute( "errors", unexpectedExceptions ); + xml.writeAttribute( "failures", stats.totals.assertions.failed-unexpectedExceptions ); + xml.writeAttribute( "tests", stats.totals.assertions.total() ); + xml.writeAttribute( "hostname", "tbd" ); // !TBD + if( m_config->showDurations() == ShowDurations::Never ) + xml.writeAttribute( "time", "" ); + else + xml.writeAttribute( "time", suiteTime ); + xml.writeAttribute( "timestamp", getCurrentTimestamp() ); + + // Write test cases + for( auto const& child : groupNode.children ) + writeTestCase( *child ); + + xml.scopedElement( "system-out" ).writeText( trim( stdOutForSuite ), false ); + xml.scopedElement( "system-err" ).writeText( trim( stdErrForSuite ), false ); + } + + void JunitReporter::writeTestCase( TestCaseNode const& testCaseNode ) { + TestCaseStats const& stats = testCaseNode.value; + + // All test cases have exactly one section - which represents the + // test case itself. That section may have 0-n nested sections + assert( testCaseNode.children.size() == 1 ); + SectionNode const& rootSection = *testCaseNode.children.front(); + + std::string className = stats.testInfo.className; + + if( className.empty() ) { + className = fileNameTag(stats.testInfo.tags); + if ( className.empty() ) + className = "global"; + } + + if ( !m_config->name().empty() ) + className = m_config->name() + "." + className; + + writeSection( className, "", rootSection ); + } + + void JunitReporter::writeSection( std::string const& className, + std::string const& rootName, + SectionNode const& sectionNode ) { + std::string name = trim( sectionNode.stats.sectionInfo.name ); + if( !rootName.empty() ) + name = rootName + '/' + name; + + if( !sectionNode.assertions.empty() || + !sectionNode.stdOut.empty() || + !sectionNode.stdErr.empty() ) { + XmlWriter::ScopedElement e = xml.scopedElement( "testcase" ); + if( className.empty() ) { + xml.writeAttribute( "classname", name ); + xml.writeAttribute( "name", "root" ); + } + else { + xml.writeAttribute( "classname", className ); + xml.writeAttribute( "name", name ); + } + xml.writeAttribute( "time", ::Catch::Detail::stringify( sectionNode.stats.durationInSeconds ) ); + + writeAssertions( sectionNode ); + + if( !sectionNode.stdOut.empty() ) + xml.scopedElement( "system-out" ).writeText( trim( sectionNode.stdOut ), false ); + if( !sectionNode.stdErr.empty() ) + xml.scopedElement( "system-err" ).writeText( trim( sectionNode.stdErr ), false ); + } + for( auto const& childNode : sectionNode.childSections ) + if( className.empty() ) + writeSection( name, "", *childNode ); + else + writeSection( className, name, *childNode ); + } + + void JunitReporter::writeAssertions( SectionNode const& sectionNode ) { + for( auto const& assertion : sectionNode.assertions ) + writeAssertion( assertion ); + } + + void JunitReporter::writeAssertion( AssertionStats const& stats ) { + AssertionResult const& result = stats.assertionResult; + if( !result.isOk() ) { + std::string elementName; + switch( result.getResultType() ) { + case ResultWas::ThrewException: + case ResultWas::FatalErrorCondition: + elementName = "error"; + break; + case ResultWas::ExplicitFailure: + elementName = "failure"; + break; + case ResultWas::ExpressionFailed: + elementName = "failure"; + break; + case ResultWas::DidntThrowException: + elementName = "failure"; + break; + + // We should never see these here: + case ResultWas::Info: + case ResultWas::Warning: + case ResultWas::Ok: + case ResultWas::Unknown: + case ResultWas::FailureBit: + case ResultWas::Exception: + elementName = "internalError"; + break; + } + + XmlWriter::ScopedElement e = xml.scopedElement( elementName ); + + xml.writeAttribute( "message", result.getExpandedExpression() ); + xml.writeAttribute( "type", result.getTestMacroName() ); + + ReusableStringStream rss; + if( !result.getMessage().empty() ) + rss << result.getMessage() << '\n'; + for( auto const& msg : stats.infoMessages ) + if( msg.type == ResultWas::Info ) + rss << msg.message << '\n'; + + rss << "at " << result.getSourceInfo(); + xml.writeText( rss.str(), false ); + } + } + + CATCH_REGISTER_REPORTER( "junit", JunitReporter ) + +} // end namespace Catch +// end catch_reporter_junit.cpp +// start catch_reporter_listening.cpp + +#include + +namespace Catch { + + ListeningReporter::ListeningReporter() { + // We will assume that listeners will always want all assertions + m_preferences.shouldReportAllAssertions = true; + } + + void ListeningReporter::addListener( IStreamingReporterPtr&& listener ) { + m_listeners.push_back( std::move( listener ) ); + } + + void ListeningReporter::addReporter(IStreamingReporterPtr&& reporter) { + assert(!m_reporter && "Listening reporter can wrap only 1 real reporter"); + m_reporter = std::move( reporter ); + m_preferences.shouldRedirectStdOut = m_reporter->getPreferences().shouldRedirectStdOut; + } + + ReporterPreferences ListeningReporter::getPreferences() const { + return m_preferences; + } + + std::set ListeningReporter::getSupportedVerbosities() { + return std::set{ }; + } + + void ListeningReporter::noMatchingTestCases( std::string const& spec ) { + for ( auto const& listener : m_listeners ) { + listener->noMatchingTestCases( spec ); + } + m_reporter->noMatchingTestCases( spec ); + } + + void ListeningReporter::benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) { + for ( auto const& listener : m_listeners ) { + listener->benchmarkStarting( benchmarkInfo ); + } + m_reporter->benchmarkStarting( benchmarkInfo ); + } + void ListeningReporter::benchmarkEnded( BenchmarkStats const& benchmarkStats ) { + for ( auto const& listener : m_listeners ) { + listener->benchmarkEnded( benchmarkStats ); + } + m_reporter->benchmarkEnded( benchmarkStats ); + } + + void ListeningReporter::testRunStarting( TestRunInfo const& testRunInfo ) { + for ( auto const& listener : m_listeners ) { + listener->testRunStarting( testRunInfo ); + } + m_reporter->testRunStarting( testRunInfo ); + } + + void ListeningReporter::testGroupStarting( GroupInfo const& groupInfo ) { + for ( auto const& listener : m_listeners ) { + listener->testGroupStarting( groupInfo ); + } + m_reporter->testGroupStarting( groupInfo ); + } + + void ListeningReporter::testCaseStarting( TestCaseInfo const& testInfo ) { + for ( auto const& listener : m_listeners ) { + listener->testCaseStarting( testInfo ); + } + m_reporter->testCaseStarting( testInfo ); + } + + void ListeningReporter::sectionStarting( SectionInfo const& sectionInfo ) { + for ( auto const& listener : m_listeners ) { + listener->sectionStarting( sectionInfo ); + } + m_reporter->sectionStarting( sectionInfo ); + } + + void ListeningReporter::assertionStarting( AssertionInfo const& assertionInfo ) { + for ( auto const& listener : m_listeners ) { + listener->assertionStarting( assertionInfo ); + } + m_reporter->assertionStarting( assertionInfo ); + } + + // The return value indicates if the messages buffer should be cleared: + bool ListeningReporter::assertionEnded( AssertionStats const& assertionStats ) { + for( auto const& listener : m_listeners ) { + static_cast( listener->assertionEnded( assertionStats ) ); + } + return m_reporter->assertionEnded( assertionStats ); + } + + void ListeningReporter::sectionEnded( SectionStats const& sectionStats ) { + for ( auto const& listener : m_listeners ) { + listener->sectionEnded( sectionStats ); + } + m_reporter->sectionEnded( sectionStats ); + } + + void ListeningReporter::testCaseEnded( TestCaseStats const& testCaseStats ) { + for ( auto const& listener : m_listeners ) { + listener->testCaseEnded( testCaseStats ); + } + m_reporter->testCaseEnded( testCaseStats ); + } + + void ListeningReporter::testGroupEnded( TestGroupStats const& testGroupStats ) { + for ( auto const& listener : m_listeners ) { + listener->testGroupEnded( testGroupStats ); + } + m_reporter->testGroupEnded( testGroupStats ); + } + + void ListeningReporter::testRunEnded( TestRunStats const& testRunStats ) { + for ( auto const& listener : m_listeners ) { + listener->testRunEnded( testRunStats ); + } + m_reporter->testRunEnded( testRunStats ); + } + + void ListeningReporter::skipTest( TestCaseInfo const& testInfo ) { + for ( auto const& listener : m_listeners ) { + listener->skipTest( testInfo ); + } + m_reporter->skipTest( testInfo ); + } + + bool ListeningReporter::isMulti() const { + return true; + } + +} // end namespace Catch +// end catch_reporter_listening.cpp +// start catch_reporter_xml.cpp + +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable:4061) // Not all labels are EXPLICITLY handled in switch + // Note that 4062 (not all labels are handled + // and default is missing) is enabled +#endif + +namespace Catch { + XmlReporter::XmlReporter( ReporterConfig const& _config ) + : StreamingReporterBase( _config ), + m_xml(_config.stream()) + { + m_reporterPrefs.shouldRedirectStdOut = true; + m_reporterPrefs.shouldReportAllAssertions = true; + } + + XmlReporter::~XmlReporter() = default; + + std::string XmlReporter::getDescription() { + return "Reports test results as an XML document"; + } + + std::string XmlReporter::getStylesheetRef() const { + return std::string(); + } + + void XmlReporter::writeSourceInfo( SourceLineInfo const& sourceInfo ) { + m_xml + .writeAttribute( "filename", sourceInfo.file ) + .writeAttribute( "line", sourceInfo.line ); + } + + void XmlReporter::noMatchingTestCases( std::string const& s ) { + StreamingReporterBase::noMatchingTestCases( s ); + } + + void XmlReporter::testRunStarting( TestRunInfo const& testInfo ) { + StreamingReporterBase::testRunStarting( testInfo ); + std::string stylesheetRef = getStylesheetRef(); + if( !stylesheetRef.empty() ) + m_xml.writeStylesheetRef( stylesheetRef ); + m_xml.startElement( "Catch" ); + if( !m_config->name().empty() ) + m_xml.writeAttribute( "name", m_config->name() ); + } + + void XmlReporter::testGroupStarting( GroupInfo const& groupInfo ) { + StreamingReporterBase::testGroupStarting( groupInfo ); + m_xml.startElement( "Group" ) + .writeAttribute( "name", groupInfo.name ); + } + + void XmlReporter::testCaseStarting( TestCaseInfo const& testInfo ) { + StreamingReporterBase::testCaseStarting(testInfo); + m_xml.startElement( "TestCase" ) + .writeAttribute( "name", trim( testInfo.name ) ) + .writeAttribute( "description", testInfo.description ) + .writeAttribute( "tags", testInfo.tagsAsString() ); + + writeSourceInfo( testInfo.lineInfo ); + + if ( m_config->showDurations() == ShowDurations::Always ) + m_testCaseTimer.start(); + m_xml.ensureTagClosed(); + } + + void XmlReporter::sectionStarting( SectionInfo const& sectionInfo ) { + StreamingReporterBase::sectionStarting( sectionInfo ); + if( m_sectionDepth++ > 0 ) { + m_xml.startElement( "Section" ) + .writeAttribute( "name", trim( sectionInfo.name ) ); + writeSourceInfo( sectionInfo.lineInfo ); + m_xml.ensureTagClosed(); + } + } + + void XmlReporter::assertionStarting( AssertionInfo const& ) { } + + bool XmlReporter::assertionEnded( AssertionStats const& assertionStats ) { + + AssertionResult const& result = assertionStats.assertionResult; + + bool includeResults = m_config->includeSuccessfulResults() || !result.isOk(); + + if( includeResults || result.getResultType() == ResultWas::Warning ) { + // Print any info messages in tags. + for( auto const& msg : assertionStats.infoMessages ) { + if( msg.type == ResultWas::Info && includeResults ) { + m_xml.scopedElement( "Info" ) + .writeText( msg.message ); + } else if ( msg.type == ResultWas::Warning ) { + m_xml.scopedElement( "Warning" ) + .writeText( msg.message ); + } + } + } + + // Drop out if result was successful but we're not printing them. + if( !includeResults && result.getResultType() != ResultWas::Warning ) + return true; + + // Print the expression if there is one. + if( result.hasExpression() ) { + m_xml.startElement( "Expression" ) + .writeAttribute( "success", result.succeeded() ) + .writeAttribute( "type", result.getTestMacroName() ); + + writeSourceInfo( result.getSourceInfo() ); + + m_xml.scopedElement( "Original" ) + .writeText( result.getExpression() ); + m_xml.scopedElement( "Expanded" ) + .writeText( result.getExpandedExpression() ); + } + + // And... Print a result applicable to each result type. + switch( result.getResultType() ) { + case ResultWas::ThrewException: + m_xml.startElement( "Exception" ); + writeSourceInfo( result.getSourceInfo() ); + m_xml.writeText( result.getMessage() ); + m_xml.endElement(); + break; + case ResultWas::FatalErrorCondition: + m_xml.startElement( "FatalErrorCondition" ); + writeSourceInfo( result.getSourceInfo() ); + m_xml.writeText( result.getMessage() ); + m_xml.endElement(); + break; + case ResultWas::Info: + m_xml.scopedElement( "Info" ) + .writeText( result.getMessage() ); + break; + case ResultWas::Warning: + // Warning will already have been written + break; + case ResultWas::ExplicitFailure: + m_xml.startElement( "Failure" ); + writeSourceInfo( result.getSourceInfo() ); + m_xml.writeText( result.getMessage() ); + m_xml.endElement(); + break; + default: + break; + } + + if( result.hasExpression() ) + m_xml.endElement(); + + return true; + } + + void XmlReporter::sectionEnded( SectionStats const& sectionStats ) { + StreamingReporterBase::sectionEnded( sectionStats ); + if( --m_sectionDepth > 0 ) { + XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResults" ); + e.writeAttribute( "successes", sectionStats.assertions.passed ); + e.writeAttribute( "failures", sectionStats.assertions.failed ); + e.writeAttribute( "expectedFailures", sectionStats.assertions.failedButOk ); + + if ( m_config->showDurations() == ShowDurations::Always ) + e.writeAttribute( "durationInSeconds", sectionStats.durationInSeconds ); + + m_xml.endElement(); + } + } + + void XmlReporter::testCaseEnded( TestCaseStats const& testCaseStats ) { + StreamingReporterBase::testCaseEnded( testCaseStats ); + XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResult" ); + e.writeAttribute( "success", testCaseStats.totals.assertions.allOk() ); + + if ( m_config->showDurations() == ShowDurations::Always ) + e.writeAttribute( "durationInSeconds", m_testCaseTimer.getElapsedSeconds() ); + + if( !testCaseStats.stdOut.empty() ) + m_xml.scopedElement( "StdOut" ).writeText( trim( testCaseStats.stdOut ), false ); + if( !testCaseStats.stdErr.empty() ) + m_xml.scopedElement( "StdErr" ).writeText( trim( testCaseStats.stdErr ), false ); + + m_xml.endElement(); + } + + void XmlReporter::testGroupEnded( TestGroupStats const& testGroupStats ) { + StreamingReporterBase::testGroupEnded( testGroupStats ); + // TODO: Check testGroupStats.aborting and act accordingly. + m_xml.scopedElement( "OverallResults" ) + .writeAttribute( "successes", testGroupStats.totals.assertions.passed ) + .writeAttribute( "failures", testGroupStats.totals.assertions.failed ) + .writeAttribute( "expectedFailures", testGroupStats.totals.assertions.failedButOk ); + m_xml.endElement(); + } + + void XmlReporter::testRunEnded( TestRunStats const& testRunStats ) { + StreamingReporterBase::testRunEnded( testRunStats ); + m_xml.scopedElement( "OverallResults" ) + .writeAttribute( "successes", testRunStats.totals.assertions.passed ) + .writeAttribute( "failures", testRunStats.totals.assertions.failed ) + .writeAttribute( "expectedFailures", testRunStats.totals.assertions.failedButOk ); + m_xml.endElement(); + } + + CATCH_REGISTER_REPORTER( "xml", XmlReporter ) + +} // end namespace Catch + +#if defined(_MSC_VER) +#pragma warning(pop) +#endif +// end catch_reporter_xml.cpp + +namespace Catch { + LeakDetector leakDetector; +} + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +// end catch_impl.hpp +#endif + +#ifdef CATCH_CONFIG_MAIN +// start catch_default_main.hpp + +#ifndef __OBJC__ + +#if defined(CATCH_CONFIG_WCHAR) && defined(WIN32) && defined(_UNICODE) && !defined(DO_NOT_USE_WMAIN) +// Standard C/C++ Win32 Unicode wmain entry point +extern "C" int wmain (int argc, wchar_t * argv[], wchar_t * []) { +#else +// Standard C/C++ main entry point +int main (int argc, char * argv[]) { +#endif + + return Catch::Session().run( argc, argv ); +} + +#else // __OBJC__ + +// Objective-C entry point +int main (int argc, char * const argv[]) { +#if !CATCH_ARC_ENABLED + NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; +#endif + + Catch::registerTestMethods(); + int result = Catch::Session().run( argc, (char**)argv ); + +#if !CATCH_ARC_ENABLED + [pool drain]; +#endif + + return result; +} + +#endif // __OBJC__ + +// end catch_default_main.hpp +#endif + +#if !defined(CATCH_CONFIG_IMPL_ONLY) + +#ifdef CLARA_CONFIG_MAIN_NOT_DEFINED +# undef CLARA_CONFIG_MAIN +#endif + +#if !defined(CATCH_CONFIG_DISABLE) +////// +// If this config identifier is defined then all CATCH macros are prefixed with CATCH_ +#ifdef CATCH_CONFIG_PREFIX_ALL + +#define CATCH_REQUIRE( ... ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE", Catch::ResultDisposition::Normal, __VA_ARGS__ ) +#define CATCH_REQUIRE_FALSE( ... ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, __VA_ARGS__ ) + +#define CATCH_REQUIRE_THROWS( ... ) INTERNAL_CATCH_THROWS( "CATCH_REQUIRE_THROWS", Catch::ResultDisposition::Normal, "", __VA_ARGS__ ) +#define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_REQUIRE_THROWS_AS", exceptionType, Catch::ResultDisposition::Normal, expr ) +#define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CATCH_REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr ) +#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) +#define CATCH_REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "CATCH_REQUIRE_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::Normal, matcher, expr ) +#endif// CATCH_CONFIG_DISABLE_MATCHERS +#define CATCH_REQUIRE_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CATCH_REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, __VA_ARGS__ ) + +#define CATCH_CHECK( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) +#define CATCH_CHECK_FALSE( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK_FALSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, __VA_ARGS__ ) +#define CATCH_CHECKED_IF( ... ) INTERNAL_CATCH_IF( "CATCH_CHECKED_IF", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) +#define CATCH_CHECKED_ELSE( ... ) INTERNAL_CATCH_ELSE( "CATCH_CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) +#define CATCH_CHECK_NOFAIL( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ ) + +#define CATCH_CHECK_THROWS( ... ) INTERNAL_CATCH_THROWS( "CATCH_CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, "", __VA_ARGS__ ) +#define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_CHECK_THROWS_AS", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr ) +#define CATCH_CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CATCH_CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr ) +#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) +#define CATCH_CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "CATCH_CHECK_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::ContinueOnFailure, matcher, expr ) +#endif // CATCH_CONFIG_DISABLE_MATCHERS +#define CATCH_CHECK_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CATCH_CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) + +#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) +#define CATCH_CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CATCH_CHECK_THAT", matcher, Catch::ResultDisposition::ContinueOnFailure, arg ) + +#define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CATCH_REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg ) +#endif // CATCH_CONFIG_DISABLE_MATCHERS + +#define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( "CATCH_INFO", msg ) +#define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( "CATCH_WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg ) +#define CATCH_CAPTURE( msg ) INTERNAL_CATCH_INFO( "CATCH_CAPTURE", #msg " := " << ::Catch::Detail::stringify(msg) ) + +#define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) +#define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) +#define CATCH_METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) +#define CATCH_REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ ) +#define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) +#define CATCH_DYNAMIC_SECTION( ... ) INTERNAL_CATCH_DYNAMIC_SECTION( __VA_ARGS__ ) +#define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ ) +#define CATCH_FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) +#define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( "CATCH_SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) + +#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE() + +// "BDD-style" convenience wrappers +#define CATCH_SCENARIO( ... ) CATCH_TEST_CASE( "Scenario: " __VA_ARGS__ ) +#define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ ) +#define CATCH_GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Given: " << desc ) +#define CATCH_WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " When: " << desc ) +#define CATCH_AND_WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( "And when: " << desc ) +#define CATCH_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Then: " << desc ) +#define CATCH_AND_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And: " << desc ) + +// If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required +#else + +#define REQUIRE( ... ) INTERNAL_CATCH_TEST( "REQUIRE", Catch::ResultDisposition::Normal, __VA_ARGS__ ) +#define REQUIRE_FALSE( ... ) INTERNAL_CATCH_TEST( "REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, __VA_ARGS__ ) + +#define REQUIRE_THROWS( ... ) INTERNAL_CATCH_THROWS( "REQUIRE_THROWS", Catch::ResultDisposition::Normal, __VA_ARGS__ ) +#define REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "REQUIRE_THROWS_AS", exceptionType, Catch::ResultDisposition::Normal, expr ) +#define REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr ) +#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) +#define REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "REQUIRE_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::Normal, matcher, expr ) +#endif // CATCH_CONFIG_DISABLE_MATCHERS +#define REQUIRE_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, __VA_ARGS__ ) + +#define CHECK( ... ) INTERNAL_CATCH_TEST( "CHECK", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) +#define CHECK_FALSE( ... ) INTERNAL_CATCH_TEST( "CHECK_FALSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, __VA_ARGS__ ) +#define CHECKED_IF( ... ) INTERNAL_CATCH_IF( "CHECKED_IF", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) +#define CHECKED_ELSE( ... ) INTERNAL_CATCH_ELSE( "CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) +#define CHECK_NOFAIL( ... ) INTERNAL_CATCH_TEST( "CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ ) + +#define CHECK_THROWS( ... ) INTERNAL_CATCH_THROWS( "CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) +#define CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CHECK_THROWS_AS", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr ) +#define CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr ) +#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) +#define CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "CHECK_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::ContinueOnFailure, matcher, expr ) +#endif // CATCH_CONFIG_DISABLE_MATCHERS +#define CHECK_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) + +#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) +#define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CHECK_THAT", matcher, Catch::ResultDisposition::ContinueOnFailure, arg ) + +#define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg ) +#endif // CATCH_CONFIG_DISABLE_MATCHERS + +#define INFO( msg ) INTERNAL_CATCH_INFO( "INFO", msg ) +#define WARN( msg ) INTERNAL_CATCH_MSG( "WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg ) +#define CAPTURE( msg ) INTERNAL_CATCH_INFO( "CAPTURE", #msg " := " << ::Catch::Detail::stringify(msg) ) + +#define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) +#define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) +#define METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) +#define REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ ) +#define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) +#define DYNAMIC_SECTION( ... ) INTERNAL_CATCH_DYNAMIC_SECTION( __VA_ARGS__ ) +#define FAIL( ... ) INTERNAL_CATCH_MSG( "FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ ) +#define FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) +#define SUCCEED( ... ) INTERNAL_CATCH_MSG( "SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) +#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE() + +#endif + +#define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) + +// "BDD-style" convenience wrappers +#define SCENARIO( ... ) TEST_CASE( "Scenario: " __VA_ARGS__ ) +#define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ ) + +#define GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Given: " << desc ) +#define WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " When: " << desc ) +#define AND_WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( "And when: " << desc ) +#define THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Then: " << desc ) +#define AND_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And: " << desc ) + +using Catch::Detail::Approx; + +#else // CATCH_CONFIG_DISABLE + +////// +// If this config identifier is defined then all CATCH macros are prefixed with CATCH_ +#ifdef CATCH_CONFIG_PREFIX_ALL + +#define CATCH_REQUIRE( ... ) (void)(0) +#define CATCH_REQUIRE_FALSE( ... ) (void)(0) + +#define CATCH_REQUIRE_THROWS( ... ) (void)(0) +#define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) (void)(0) +#define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) (void)(0) +#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) +#define CATCH_REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0) +#endif// CATCH_CONFIG_DISABLE_MATCHERS +#define CATCH_REQUIRE_NOTHROW( ... ) (void)(0) + +#define CATCH_CHECK( ... ) (void)(0) +#define CATCH_CHECK_FALSE( ... ) (void)(0) +#define CATCH_CHECKED_IF( ... ) if (__VA_ARGS__) +#define CATCH_CHECKED_ELSE( ... ) if (!(__VA_ARGS__)) +#define CATCH_CHECK_NOFAIL( ... ) (void)(0) + +#define CATCH_CHECK_THROWS( ... ) (void)(0) +#define CATCH_CHECK_THROWS_AS( expr, exceptionType ) (void)(0) +#define CATCH_CHECK_THROWS_WITH( expr, matcher ) (void)(0) +#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) +#define CATCH_CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0) +#endif // CATCH_CONFIG_DISABLE_MATCHERS +#define CATCH_CHECK_NOTHROW( ... ) (void)(0) + +#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) +#define CATCH_CHECK_THAT( arg, matcher ) (void)(0) + +#define CATCH_REQUIRE_THAT( arg, matcher ) (void)(0) +#endif // CATCH_CONFIG_DISABLE_MATCHERS + +#define CATCH_INFO( msg ) (void)(0) +#define CATCH_WARN( msg ) (void)(0) +#define CATCH_CAPTURE( msg ) (void)(0) + +#define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) +#define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) +#define CATCH_METHOD_AS_TEST_CASE( method, ... ) +#define CATCH_REGISTER_TEST_CASE( Function, ... ) (void)(0) +#define CATCH_SECTION( ... ) +#define CATCH_DYNAMIC_SECTION( ... ) +#define CATCH_FAIL( ... ) (void)(0) +#define CATCH_FAIL_CHECK( ... ) (void)(0) +#define CATCH_SUCCEED( ... ) (void)(0) + +#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) + +// "BDD-style" convenience wrappers +#define CATCH_SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) +#define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), className ) +#define CATCH_GIVEN( desc ) +#define CATCH_WHEN( desc ) +#define CATCH_AND_WHEN( desc ) +#define CATCH_THEN( desc ) +#define CATCH_AND_THEN( desc ) + +// If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required +#else + +#define REQUIRE( ... ) (void)(0) +#define REQUIRE_FALSE( ... ) (void)(0) + +#define REQUIRE_THROWS( ... ) (void)(0) +#define REQUIRE_THROWS_AS( expr, exceptionType ) (void)(0) +#define REQUIRE_THROWS_WITH( expr, matcher ) (void)(0) +#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) +#define REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0) +#endif // CATCH_CONFIG_DISABLE_MATCHERS +#define REQUIRE_NOTHROW( ... ) (void)(0) + +#define CHECK( ... ) (void)(0) +#define CHECK_FALSE( ... ) (void)(0) +#define CHECKED_IF( ... ) if (__VA_ARGS__) +#define CHECKED_ELSE( ... ) if (!(__VA_ARGS__)) +#define CHECK_NOFAIL( ... ) (void)(0) + +#define CHECK_THROWS( ... ) (void)(0) +#define CHECK_THROWS_AS( expr, exceptionType ) (void)(0) +#define CHECK_THROWS_WITH( expr, matcher ) (void)(0) +#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) +#define CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0) +#endif // CATCH_CONFIG_DISABLE_MATCHERS +#define CHECK_NOTHROW( ... ) (void)(0) + +#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) +#define CHECK_THAT( arg, matcher ) (void)(0) + +#define REQUIRE_THAT( arg, matcher ) (void)(0) +#endif // CATCH_CONFIG_DISABLE_MATCHERS + +#define INFO( msg ) (void)(0) +#define WARN( msg ) (void)(0) +#define CAPTURE( msg ) (void)(0) + +#define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) +#define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) +#define METHOD_AS_TEST_CASE( method, ... ) +#define REGISTER_TEST_CASE( Function, ... ) (void)(0) +#define SECTION( ... ) +#define DYNAMIC_SECTION( ... ) +#define FAIL( ... ) (void)(0) +#define FAIL_CHECK( ... ) (void)(0) +#define SUCCEED( ... ) (void)(0) +#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) + +#endif + +#define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION_NO_REG( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature ) + +// "BDD-style" convenience wrappers +#define SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ) ) +#define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), className ) + +#define GIVEN( desc ) +#define WHEN( desc ) +#define AND_WHEN( desc ) +#define THEN( desc ) +#define AND_THEN( desc ) + +using Catch::Detail::Approx; + +#endif + +#endif // ! CATCH_CONFIG_IMPL_ONLY + +// start catch_reenable_warnings.h + + +#ifdef __clang__ +# ifdef __ICC // icpc defines the __clang__ macro +# pragma warning(pop) +# else +# pragma clang diagnostic pop +# endif +#elif defined __GNUC__ +# pragma GCC diagnostic pop +#endif + +// end catch_reenable_warnings.h +// end catch.hpp +#endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED + diff --git a/Testing/README.md b/Testing/README.md new file mode 100644 index 0000000..bafcc78 --- /dev/null +++ b/Testing/README.md @@ -0,0 +1,36 @@ +# README for Nymph/Testing + +## Catch2 + +Nymph uses the Catch2 testing framework for unit tests. See these links for more information: + +* [Main GitHub page](https://github.com/catchorg/Catch2) +* [Tutorial](https://github.com/catchorg/Catch2/blob/master/docs/tutorial.md) + +## Building tests + +In CMake, enable the option `Nymph_ENABLE_TESTING`, and build. + +The testing executable, `RunTests`, will be installed in `install_prefix/testing`. + +## Running tests + +To see the available options for running tests, you can do: + +``` +> testing/RunTests -h +``` + +To simply run all of the tests, you can do: + +``` +> testing/RunTests +``` + +Or if you want to run a specific test, you can do: + +``` +> testing/RunTests [name] +``` + +For further documentation on using Catch2, see the [tutorial](https://github.com/catchorg/Catch2/blob/master/docs/tutorial.md). diff --git a/Testing/TestExt.cc b/Testing/TestExt.cc new file mode 100644 index 0000000..9521af1 --- /dev/null +++ b/Testing/TestExt.cc @@ -0,0 +1,88 @@ +/* + * TestExt.cc + * + * Created on: Aug 23, 2019 + * Author: N.S. Oblath + */ + +#include "KTExtensible.hh" + +#include "catch.hpp" + +namespace Nymph +{ + class MyBaseClass + { + public: + MyBaseClass() {} + virtual ~MyBaseClass() {} + }; + + class MyClass1 : public KTExtensible< MyClass1, MyBaseClass > + { + public: + MyClass1() : KTExtensible< MyClass1, MyBaseClass >(), fValue() {} + MyClass1( const MyClass1& orig ) : KTExtensible< MyClass1, MyBaseClass >( orig ), fValue( orig.fValue ) {} + virtual ~MyClass1() {}; + public: + int fValue; + }; + + class MyClass2 : public KTExtensible< MyClass2, MyBaseClass > + { + public: + MyClass2() : KTExtensible< MyClass2, MyBaseClass >(), fValue() {} + MyClass2( const MyClass2& orig ) : KTExtensible< MyClass2, MyBaseClass >( orig ), fValue( orig.fValue ) {} + virtual ~MyClass2() {}; + public: + int fValue; + }; + +} + +TEST_CASE( "extensible", "[utility]" ) +{ + using namespace Nymph; + + std::shared_ptr< MyClass1 > data1 = std::make_shared< MyClass1 >(); + data1->fValue = 5; + + MyClass2& data2 = data1->Of< MyClass2 >(); + data2.fValue = 3; + + std::shared_ptr< MyClass2 > data2Shared = data1->Share< MyClass2 >(); + + SECTION( "Basic extensibility and values" ) + { + REQUIRE( data1->Has< MyClass1 >() ); + REQUIRE( data1->Has< MyClass2 >() ); + REQUIRE_FALSE( data2.Has< MyClass1 >() ); + REQUIRE( data2.Has< MyClass2 >() ); + + REQUIRE( data1->fValue == 5 ); + REQUIRE( data2.fValue == 3 ); + + REQUIRE( data2Shared->fValue == 3 ); + + REQUIRE( data1->size() == 2 ); + REQUIRE( data2.size() == 1 ); + } + + std::shared_ptr< MyClass1 > copyOfData1 = std::make_shared< MyClass1 >( *data1 ); + MyClass2& copyOfData2 = copyOfData1->Of< MyClass2 >(); + + SECTION( "Copying data" ) + { + REQUIRE( copyOfData1->fValue == data1->fValue ); + REQUIRE_FALSE( copyOfData1 == data1 ); + REQUIRE( copyOfData2.fValue == data2.fValue ); + } + + std::shared_ptr< MyClass2 > detatchedCopyOfData2 = copyOfData1->Detatch< MyClass2 >(); + + SECTION( "Detatching" ) + { + REQUIRE( copyOfData1->size() == 1 ); + REQUIRE( detatchedCopyOfData2->size() == 1 ); + } +} diff --git a/Testing/UseCatch.cc b/Testing/UseCatch.cc new file mode 100644 index 0000000..4cb169c --- /dev/null +++ b/Testing/UseCatch.cc @@ -0,0 +1,10 @@ +/* + * use_catch.cc + * + * Created on: Aug 14, 2018 + * Author: N.S. Oblath + */ + +// Tells Catch to provide a main() +#define CATCH_CONFIG_MAIN +#include "catch.hpp" From 8f1411d33c0c726a9214f5a69f14ef404ee2bf5f Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Mon, 26 Aug 2019 09:48:29 -0700 Subject: [PATCH 132/521] Added a Dockerfile --- .dockerignore | 31 +++++++++++++++++++++++++++++++ Dockerfile | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+) create mode 100644 .dockerignore create mode 100644 Dockerfile diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..a97774f --- /dev/null +++ b/.dockerignore @@ -0,0 +1,31 @@ +#general: +*.swp +*.o +*.so +*.a +*.dylib + +#mac +.DS_Store + +#from Eclipse +.project +.cproject + +#from cmake +CMakeCache.txt +CMakeFiles/ +Makefile +build*/ +cbuild*/ +cmake_install.cmake +*Dict.h +*Dict.cxx +Documentation/ReferenceGuide/Doxyfile +Source/Main/ExtractEvents +Source/Main/SimpleElectronHunt +Source/Applications/Main/SimpleElectronHunt +install_manifest.txt + +# from emacs +*~ diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..b743827 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,50 @@ +FROM project8/p8compute_dependencies:v0.7.0 as nymph_common + +ARG build_type=Release +ENV NYMPH_BUILD_TYPE=$build_type +ARG build_tests_exe=FALSE +ENV NYMPH_BUILD_TESTS_EXE=$build_tests_exe + +ENV NYMPH_TAG=v2.17.0 +ENV NYMPH_BUILD_PREFIX=/usr/local/p8/katydid/$NYMPH_TAG + +RUN mkdir -p $NYMPH_BUILD_PREFIX &&\ + chmod -R 777 $NYMPH_BUILD_PREFIX/.. &&\ + cd $NYMPH_BUILD_PREFIX &&\ + echo "source ${COMMON_BUILD_PREFIX}/setup.sh" > setup.sh &&\ + echo "export NYMPH_TAG=${NYMPH_TAG}" >> setup.sh &&\ + echo "export NYMPH_BUILD_PREFIX=${NYMPH_BUILD_PREFIX}" >> setup.sh &&\ + echo 'ln -sfT $NYMPH_BUILD_PREFIX $NYMPH_BUILD_PREFIX/../current' >> setup.sh &&\ + echo 'export PATH=$NYMPH_BUILD_PREFIX/bin:$PATH' >> setup.sh &&\ + echo 'export LD_LIBRARY_PATH=$NYMPH_BUILD_PREFIX/lib:$LD_LIBRARY_PATH' >> setup.sh &&\ + /bin/true + +######################## +FROM nymph_common as nymph_done + +COPY cmake /tmp_source/cmake +COPY Executables /tmp_source/Executables +COPY External /tmp_source/External +COPY Library /tmp_source/Library +COPY Scarab /tmp_source/Scarab +COPY CMakeLists.txt /tmp_source/CMakeLists.txt +COPY .git /tmp_source/.git + +# repeat the cmake command to get the change of install prefix to set correctly (a package_builder known issue) +RUN source $NYMPH_BUILD_PREFIX/setup.sh &&\ + cd /tmp_source &&\ + mkdir build &&\ + cd build &&\ + cmake -D CMAKE_BUILD_TYPE=$NYMPH_BUILD_TYPE \ + -D CMAKE_INSTALL_PREFIX:PATH=$NYMPH_BUILD_PREFIX \ + -D Nymph_ENABLE_TESTING:BOOL=$NYMPH_BUILD_TESTS_EXE .. &&\ + cmake -D CMAKE_BUILD_TYPE=$NYMPH_BUILD_TYPE \ + -D CMAKE_INSTALL_PREFIX:PATH=$NYMPH_BUILD_PREFIX \ + -D Nymph_ENABLE_TESTING:BOOL=$NYMPH_BUILD_TESTS_EXE .. &&\ + make -j3 install &&\ + /bin/true + +######################## +FROM nymph_common + +COPY --from=nymph_done $NYMPH_BUILD_PREFIX $NYMPH_BUILD_PREFIX From f73aa479a37d2d4803b0b2cf2e2edce3e4144935 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Wed, 28 Aug 2019 00:33:04 -0700 Subject: [PATCH 133/521] Some bug fixing --- Library/Processor/KTSignalSlotBase.hh | 4 +-- Library/Processor/KTThreadReference.hh | 38 ++++++++++++-------------- 2 files changed, 20 insertions(+), 22 deletions(-) diff --git a/Library/Processor/KTSignalSlotBase.hh b/Library/Processor/KTSignalSlotBase.hh index f775c93..35a7db1 100644 --- a/Library/Processor/KTSignalSlotBase.hh +++ b/Library/Processor/KTSignalSlotBase.hh @@ -24,9 +24,9 @@ namespace Nymph KTSlotBase( const std::string& name, XOwner* owner ); virtual ~KTSlotBase(); - void AddConnection( KTSignalBase* ) const = 0; + virtual void AddConnection( KTSignalBase* ) const = 0; - void RemoveConnection( KTSignalBase* ) const = 0; + virtual void RemoveConnection( KTSignalBase* ) const = 0; MEMBERVARIABLE_REF( std::string, Name ); }; diff --git a/Library/Processor/KTThreadReference.hh b/Library/Processor/KTThreadReference.hh index e6d88fe..b792c3f 100644 --- a/Library/Processor/KTThreadReference.hh +++ b/Library/Processor/KTThreadReference.hh @@ -36,7 +36,7 @@ namespace Nymph // for use within the thread //************************** - void SetReturnException( boost::exception_ptr excPtr ); + //void SetReturnException( boost::exception_ptr excPtr ); public: //****************************** @@ -85,6 +85,8 @@ namespace Nymph // for use outside of the thread //****************************** + void SetReturnException( boost::exception_ptr excPtr ); + KTDataHandle GetReturnValue(); boost::unique_future< KTDataHandle >& GetDataPtrRetFuture(); const boost::unique_future< KTDataHandle >& GetDataPtrRetFuture() const; @@ -96,62 +98,58 @@ namespace Nymph boost::unique_future< KTDataHandle > fDataPtrRetFuture; }; - inline void KTThreadReference::SetReturnException( boost::exception_ptr excPtr ) + template< typename... XArgs > + void KTThreadReference< XArgs... >::SetReturnException( boost::exception_ptr excPtr ) { fDataPtrRet.set_exception( excPtr ); return; } - inline void KTThreadReference::SetReturnValue( KTDataHandle dataHandle ) + template< typename... XArgs > + void KTThreadReference< XArgs... >::SetReturnValue( XArgs... dataHandle ) { - fDataPtrRet.set_value( dataHandle ); + fDataPtrRet.set_value( dataHandle... ); return; } - inline KTDataHandle KTThreadReference::GetReturnValue() + template< typename... XArgs > + KTDataHandle KTThreadReference< XArgs... >::GetReturnValue() { return fDataPtrRetFuture.get(); } - inline boost::unique_future< KTDataHandle >& KTThreadReference::GetDataPtrRetFuture() + template< typename... XArgs > + boost::unique_future< KTDataHandle >& KTThreadReference< XArgs... >::GetDataPtrRetFuture() { return fDataPtrRetFuture; } - inline const boost::unique_future< KTDataHandle >& KTThreadReference::GetDataPtrRetFuture() const + template< typename... XArgs > + const boost::unique_future< KTDataHandle >& KTThreadReference< XArgs... >::GetDataPtrRetFuture() const { return fDataPtrRetFuture; } - inline void KTThreadReference::RefreshDataPtrRet() + template< typename... XArgs > + void KTThreadReference< XArgs... >::RefreshDataPtrRet() { fDataPtrRet = KTDataPtrReturn(); fDataPtrRetFuture = fDataPtrRet.get_future(); return; } - inline void KTThreadReference::SetInitiateBreakFunc( const std::function< void() >& initBreakFunc ) + inline void KTThreadReferenceBase::SetInitiateBreakFunc( const std::function< void() >& initBreakFunc ) { fInitiateBreakFunc = initBreakFunc; return; } - inline void KTThreadReference::SetWaitForContinueFunc( const std::function< void( boost_unique_lock& ) >& waitForContFunc ) + inline void KTThreadReferenceBase::SetWaitForContinueFunc( const std::function< void( boost_unique_lock& ) >& waitForContFunc ) { fWaitForContinueFunc = waitForContFunc; return; } - inline boost::mutex& KTThreadReference::Mutex() - { - return fMutex; - } - - inline const boost::mutex& KTThreadReference::Mutex() const - { - return fMutex; - } - #ifndef THROW_THREADREF_EXCEPTION #define THROW_THREADREF_EXCEPTION( ref, exc ) \ From 24541ce35c9b344b9d6d44bac2498b5058959e55 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Wed, 28 Aug 2019 00:57:50 -0700 Subject: [PATCH 134/521] Remove everything from the build --- Executables/Main/CMakeLists.txt | 6 +- Library/CMakeLists.txt | 142 ++++++++++++++++---------------- 2 files changed, 74 insertions(+), 74 deletions(-) diff --git a/Executables/Main/CMakeLists.txt b/Executables/Main/CMakeLists.txt index 8fd619b..e41ac9d 100644 --- a/Executables/Main/CMakeLists.txt +++ b/Executables/Main/CMakeLists.txt @@ -7,15 +7,15 @@ if( Nymph_ENABLE_EXECUTABLES ) message(STATUS "Nymph exectuables library dependencies: ${all_libs}" ) set( programs - ConfigCheck +# ConfigCheck ) if( Nymph_BUILD_NYMPH_EXE ) set( programs - Nymph +# Nymph ) endif( Nymph_BUILD_NYMPH_EXE ) - pbuilder_executables( programs all_libs ) +# pbuilder_executables( programs all_libs ) endif( Nymph_ENABLE_EXECUTABLES ) diff --git a/Library/CMakeLists.txt b/Library/CMakeLists.txt index ba43a3d..93c2421 100644 --- a/Library/CMakeLists.txt +++ b/Library/CMakeLists.txt @@ -10,80 +10,80 @@ set( IO_DIR IO ) set( APPL_DIR Application ) set( NYMPH_HEADERFILES - ${UTIL_DIR}/KTCacheDirectory.hh - ${UTIL_DIR}/KTConcurrentQueue.hh - ${UTIL_DIR}/KTConfigurable.hh - ${UTIL_DIR}/KTDirectory.hh - ${UTIL_DIR}/KTEventLoop.hh - ${UTIL_DIR}/KTException.hh - ${UTIL_DIR}/KTExtensible.hh - ${UTIL_DIR}/KTExtensibleStruct.hh - ${UTIL_DIR}/KTExtensibleStructFactory.hh - ${UTIL_DIR}/KTLogger.hh - ${UTIL_DIR}/KTMemberVariable.hh - ${UTIL_DIR}/KTTIFactory.hh - ${UTIL_DIR}/KTTime.hh - ${DATA_DIR}/KTApplyCut.hh - ${DATA_DIR}/KTCoreData.hh - ${DATA_DIR}/KTCut.hh - ${DATA_DIR}/KTCutFilter.hh - ${DATA_DIR}/KTCutResult.hh - ${DATA_DIR}/KTCutStatus.hh - ${DATA_DIR}/KTData.hh - ${DATA_DIR}/KTRegisterNymphExtData.hh - ${PROC_DIR}/KTConnection.hh - ${PROC_DIR}/KTPrimaryProcessor.hh - ${PROC_DIR}/KTProcessor.hh - ${PROC_DIR}/KTSignal.hh - ${PROC_DIR}/KTSignalWrapper.hh - ${PROC_DIR}/KTSlot.hh - ${PROC_DIR}/KTSlotWrapper.hh - ${PROC_DIR}/KTThreadReference.hh - ${IO_DIR}/KTJSONWriter.hh - ${IO_DIR}/KTReader.hh - ${IO_DIR}/KTWriter.hh - ${APPL_DIR}/KTApplication.hh - ${APPL_DIR}/KTCommandLineHandler.hh - ${APPL_DIR}/KTCommandLineOption.hh - ${APPL_DIR}/KTConfigurator.hh - ${APPL_DIR}/KTDataQueueProcessor.hh - ${APPL_DIR}/KTFilenameParsers.hh - ${APPL_DIR}/KTPrintDataStructure.hh - ${APPL_DIR}/KTProcessorToolbox.hh - ${APPL_DIR}/KTRunNymph.hh - ${APPL_DIR}/KTThroughputProfiler.hh +# ${UTIL_DIR}/KTCacheDirectory.hh +# ${UTIL_DIR}/KTConcurrentQueue.hh +# ${UTIL_DIR}/KTConfigurable.hh +# ${UTIL_DIR}/KTDirectory.hh +# ${UTIL_DIR}/KTEventLoop.hh +# ${UTIL_DIR}/KTException.hh +# ${UTIL_DIR}/KTExtensible.hh +# ${UTIL_DIR}/KTExtensibleStruct.hh +# ${UTIL_DIR}/KTExtensibleStructFactory.hh +# ${UTIL_DIR}/KTLogger.hh +# ${UTIL_DIR}/KTMemberVariable.hh +# ${UTIL_DIR}/KTTIFactory.hh +# ${UTIL_DIR}/KTTime.hh +# ${DATA_DIR}/KTApplyCut.hh +# ${DATA_DIR}/KTCoreData.hh +# ${DATA_DIR}/KTCut.hh +# ${DATA_DIR}/KTCutFilter.hh +# ${DATA_DIR}/KTCutResult.hh +# ${DATA_DIR}/KTCutStatus.hh +# ${DATA_DIR}/KTData.hh +# ${DATA_DIR}/KTRegisterNymphExtData.hh +# ${PROC_DIR}/KTConnection.hh +# ${PROC_DIR}/KTPrimaryProcessor.hh +# ${PROC_DIR}/KTProcessor.hh +# ${PROC_DIR}/KTSignal.hh +# ${PROC_DIR}/KTSignalWrapper.hh +# ${PROC_DIR}/KTSlot.hh +# ${PROC_DIR}/KTSlotWrapper.hh +# ${PROC_DIR}/KTThreadReference.hh +# ${IO_DIR}/KTJSONWriter.hh +# ${IO_DIR}/KTReader.hh +# ${IO_DIR}/KTWriter.hh +# ${APPL_DIR}/KTApplication.hh +# ${APPL_DIR}/KTCommandLineHandler.hh +# ${APPL_DIR}/KTCommandLineOption.hh +# ${APPL_DIR}/KTConfigurator.hh +# ${APPL_DIR}/KTDataQueueProcessor.hh +# ${APPL_DIR}/KTFilenameParsers.hh +# ${APPL_DIR}/KTPrintDataStructure.hh +# ${APPL_DIR}/KTProcessorToolbox.hh +# ${APPL_DIR}/KTRunNymph.hh +# ${APPL_DIR}/KTThroughputProfiler.hh ) set( NYMPH_SOURCEFILES - ${UTIL_DIR}/KTCacheDirectory.cc - ${UTIL_DIR}/KTConfigurable.cc - ${UTIL_DIR}/KTDirectory.cc - ${UTIL_DIR}/KTEventLoop.cc - ${UTIL_DIR}/KTException.cc - ${UTIL_DIR}/KTTime.cc - ${DATA_DIR}/KTApplyCut.cc - ${DATA_DIR}/KTCoreData.cc - ${DATA_DIR}/KTCut.cc - ${DATA_DIR}/KTCutFilter.cc - ${DATA_DIR}/KTCutStatus.cc - ${DATA_DIR}/KTData.cc - ${PROC_DIR}/KTPrimaryProcessor.cc - ${PROC_DIR}/KTProcessor.cc - ${PROC_DIR}/KTSignalWrapper.cc - ${PROC_DIR}/KTSlotWrapper.cc - ${PROC_DIR}/KTThreadReference.cc - ${IO_DIR}/KTJSONWriter.cc - ${IO_DIR}/KTReader.cc - ${IO_DIR}/KTWriter.cc - ${APPL_DIR}/KTApplication.cc - ${APPL_DIR}/KTCommandLineHandler.cc - ${APPL_DIR}/KTConfigurator.cc - ${APPL_DIR}/KTDataQueueProcessor.cc - ${APPL_DIR}/KTFilenameParsers.cc - ${APPL_DIR}/KTPrintDataStructure.cc - ${APPL_DIR}/KTProcessorToolbox.cc - ${APPL_DIR}/KTRunNymph.cc - ${APPL_DIR}/KTThroughputProfiler.cc +# ${UTIL_DIR}/KTCacheDirectory.cc +# ${UTIL_DIR}/KTConfigurable.cc +# ${UTIL_DIR}/KTDirectory.cc +# ${UTIL_DIR}/KTEventLoop.cc +# ${UTIL_DIR}/KTException.cc +# ${UTIL_DIR}/KTTime.cc +# ${DATA_DIR}/KTApplyCut.cc +# ${DATA_DIR}/KTCoreData.cc +# ${DATA_DIR}/KTCut.cc +# ${DATA_DIR}/KTCutFilter.cc +# ${DATA_DIR}/KTCutStatus.cc +# ${DATA_DIR}/KTData.cc +# ${PROC_DIR}/KTPrimaryProcessor.cc +# ${PROC_DIR}/KTProcessor.cc +# ${PROC_DIR}/KTSignalWrapper.cc +# ${PROC_DIR}/KTSlotWrapper.cc +# ${PROC_DIR}/KTThreadReference.cc +# ${IO_DIR}/KTJSONWriter.cc +# ${IO_DIR}/KTReader.cc +# ${IO_DIR}/KTWriter.cc +# ${APPL_DIR}/KTApplication.cc +# ${APPL_DIR}/KTCommandLineHandler.cc +# ${APPL_DIR}/KTConfigurator.cc +# ${APPL_DIR}/KTDataQueueProcessor.cc +# ${APPL_DIR}/KTFilenameParsers.cc +# ${APPL_DIR}/KTPrintDataStructure.cc +# ${APPL_DIR}/KTProcessorToolbox.cc +# ${APPL_DIR}/KTRunNymph.cc +# ${APPL_DIR}/KTThroughputProfiler.cc ) # Python binding headers From f0e1e9d6934fa0a3103fba4cd3eca3a29d495307 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Wed, 28 Aug 2019 01:22:33 -0700 Subject: [PATCH 135/521] Starting rebuild: Exception.cc/hh and MemberVariable.hh --- Library/CMakeLists.txt | 3 + Library/Utility/Exception.cc | 30 +++++++ Library/Utility/Exception.hh | 127 ++++++++++++++++++++++++++++++ Library/Utility/MemberVariable.hh | 93 ++++++++++++++++++++++ 4 files changed, 253 insertions(+) create mode 100644 Library/Utility/Exception.cc create mode 100644 Library/Utility/Exception.hh create mode 100644 Library/Utility/MemberVariable.hh diff --git a/Library/CMakeLists.txt b/Library/CMakeLists.txt index 93c2421..1411560 100644 --- a/Library/CMakeLists.txt +++ b/Library/CMakeLists.txt @@ -52,6 +52,8 @@ set( NYMPH_HEADERFILES # ${APPL_DIR}/KTProcessorToolbox.hh # ${APPL_DIR}/KTRunNymph.hh # ${APPL_DIR}/KTThroughputProfiler.hh + ${UTIL_DIR}/Exception.hh + ${UTIL_DIR}/MemberVariable.hh ) set( NYMPH_SOURCEFILES @@ -84,6 +86,7 @@ set( NYMPH_SOURCEFILES # ${APPL_DIR}/KTProcessorToolbox.cc # ${APPL_DIR}/KTRunNymph.cc # ${APPL_DIR}/KTThroughputProfiler.cc + ${UTIL_DIR}/Exception.cc ) # Python binding headers diff --git a/Library/Utility/Exception.cc b/Library/Utility/Exception.cc new file mode 100644 index 0000000..6770e91 --- /dev/null +++ b/Library/Utility/Exception.cc @@ -0,0 +1,30 @@ +/* + * Exception.cc + * + * Created on: Feb 25, 2014 + * Author: nsoblath + */ + +#include "Exception.hh" + +namespace Nymph +{ + + Exception::Exception() : + boost::exception(), + std::exception(), + fMsgBuffer() + { + } + Exception::Exception( const Exception& an_exception ) : + boost::exception( an_exception ), + std::exception( an_exception ), + fMsgBuffer( an_exception.fMsgBuffer ) + { + } + + Exception::~Exception() throw () + { + } + +} diff --git a/Library/Utility/Exception.hh b/Library/Utility/Exception.hh new file mode 100644 index 0000000..cc7c542 --- /dev/null +++ b/Library/Utility/Exception.hh @@ -0,0 +1,127 @@ +/* + * Exception.hh + * + * Created on: Feb 25, 2014 + * Author: nsoblath + */ + + +#ifndef NYMPH_EXCEPTION_HH_ +#define NYMPH_EXCEPTION_HH_ + +#include "macros.hh" + +#include + +#include +#include +#include + +namespace Nymph +{ + struct MessageEnd {}; + static const MessageEnd eom = MessageEnd(); + + //typedef boost::error_info ErrorMsgInfo; + + template< class XLabel > + using ErrorMsgInfo = boost::error_info< XLabel, std::string>; + + /*! + @class Exception + @author N.S. Oblath + + @brief Exception base class for Nymph and Nymph-based projects + + @details + + How to throw: + + BOOST_THROW_EXCEPTION( Exception() << "[error message here]" << eom ); + + Why do it like this? + - BOOST_THROW_EXCEPTION will record the location that the exception was thrown. This is incredibly useful in diagnosing problems. + - eom ensure that your error message is handled properly; until that's processed the message is stored in a buffer, and the eom takes that buffer and adds it to the boost::exception base class's storage. + - Exception can be replaced with whatever derived exception class you're using. + + How to catch, add information, and re-throw: + + try + { + // code that throws a Exception + } + catch( boost::exception& e ) + { + e << ErrorMsgInfo< struct UniqueLocationTag >( "Here's some information about the context in which the exception was thrown" ); + throw; + } + + + How to do the final catch + + try + { + // code that throws a Exception + } + catch( boost::exception& e ) + { + ERROR( my_log, "An exception was caught: " << diagnostic_information( e ) ): + } + */ + + class Exception : virtual public boost::exception, virtual public std::exception + { + public: + Exception(); + Exception( const Exception& ); + ~Exception() throw (); + + // adds to the message buffer + template< class XStreamable > + Exception& operator<<( XStreamable a_fragment ); + // adds to the message buffer + Exception& operator<<( const std::string& a_fragment ); + // adds to the message buffer + Exception& operator<<( const char* a_fragment ); + + // adds the current contents of the message buffer as a ErrorMsgInfo + Exception& operator<<( const MessageEnd& eom ); + + private: + mutable std::string fMsgBuffer; + }; + + template< class XStreamable > + Exception& Exception::operator<<( XStreamable a_fragment ) + { + std::stringstream stream; + stream << a_fragment; + stream >> fMsgBuffer; + return *this; + } + + inline Exception& Exception::operator<<( const std::string& a_fragment ) + { + fMsgBuffer += a_fragment; + return *this; + } + + inline Exception& Exception::operator<<( const char* a_fragment ) + { + fMsgBuffer += std::string( a_fragment ); + return *this; + } + + inline Exception& Exception::operator<<( const MessageEnd& eom ) + { + if( ! fMsgBuffer.empty() ) + { + boost::operator<<( *this, ErrorMsgInfo< struct ExcpMsg >{ fMsgBuffer } ); + fMsgBuffer.clear(); + } + return *this; + } + +} + +#endif /* NYMPH_EXCEPTION_HH_ */ diff --git a/Library/Utility/MemberVariable.hh b/Library/Utility/MemberVariable.hh new file mode 100644 index 0000000..b48e3ef --- /dev/null +++ b/Library/Utility/MemberVariable.hh @@ -0,0 +1,93 @@ +/* + * MemberVariable.hh + * + * Created on: Aug 5, 2014 + * Author: nsoblath + */ + +#ifndef NYMPH_MEMBERVARIABLE_HH_ +#define NYMPH_MEMBERVARIABLE_HH_ + +/** + * Macros for class member variables + * + * In all cases remember to initialize the variables! + * + * For "normal" variables + * Defines accessors [type GetMyVar() const], [void SetMyVar( type )], and member variable [type fMyVar] + * The Set function is not available if the _NOSET macros are used + * - MEMVAR + * - MEMVAR_NOSET + * - MEMVAR_STATIC + * - MEMVAR_STATIC_NOSET + * + * For variables accessed by reference + * Defines accessors [const type& MyVar() const], [type& MyVar()], and member variable [type fMyVar] + * The non-const function is not available if the _CONST macros are used + * - MEMVAR_REF + * - MEMVAR_REF_CONST + * - MEMVAR_REF_STATIC + * - MEMVAR_REF_STATIC_CONST + * + * For pointer variables + * Defines accessors [type* GetMyVar() const], [void SetMyVar( type* )], and member variable [type* fMyVar] + * The Set function is not available if the _NOSET macros are used + * - MEMVAR_PTR + * - MEMVAR_PTR_NOSET + * - MEMVAR_PTR_STATIC + * - MEMVAR_PTR_STATIC_NOSET + * + * For shared_ptr's + * Defines accessors [const std::shared_ptr< type > MyVar() const], [std::shared_ptr< type > MyVar()], and member variable [std::shared_ptr< type > fMyVar] + * The non-const function is not available if the _CONST macros are used + * - MEMVAR_SHARED_PTR + * - MEMVAR_SHARED_PTR_CONST + * - MEMVAR_SHARED_PTR_STATIC + * - MEMVAR_SHARED_PTR_STATIC_CONST + * + * For atomic variables + * Defines accessors [type GetMyVar() const], [void SetMyVar( type )], and member variable [std::atomic< type > fMyVar] + * The Set function is not available if the _NOSET macros are used + * - MEMVAR_ATOMIC + * - MEMVAR_ATOMIC_NOSET + * - MEMVAR_ATOMIC_STATIC + * - MEMVAR_ATOMIC_STATIC_NOSET + * + */ + +#include "_camel_case_member_variables.hh" + +#define MEMVAR camel_case_mv_accessible +#define MEMVAR_NOSET camel_case_mv_accessible_noset +#define MEMVAR_STATIC camel_case_mv_accessible_static +#define MEMVAR_STATIC_NOSET camel_case_mv_accessible_static_noset +#define MEMVAR_MUTABLE camel_case_mv_accessible_mutable +#define MEMVAR_MUTABLE_NOSET camel_case_mv_accessible_mutable_noset + +#define MEMVAR_REF camel_case_mv_referrable +#define MEMVAR_REF_CONST camel_case_mv_referrable_const +#define MEMVAR_REF_STATIC camel_case_mv_referrable_static +#define MEMVAR_REF_MUTABLE camel_case_mv_referrable_mutable +#define MEMVAR_REF_MUTABLE_CONST camel_case_mv_referrable_mutable + +#define MEMVAR_PTR camel_case_mv_assignable +#define MEMVAR_PTR_NOSET camel_case_mv_assignable_noset +#define MEMVAR_PTR_STATIC camel_case_mv_assignable_static +#define MEMVAR_PTR_STATIC_NOSET camel_case_mv_assignable_static_noset +#define MEMVAR_PTR_MUTABLE camel_case_mv_assignable_mutable +#define MEMVAR_PTR_MUTABLE_NOSET camel_case_mv_assignable_mutable_noset + +#define MEMVAR_SHARED_PTR camel_case_mv_shared_ptr +#define MEMVAR_SHARED_PTR_CONST camel_case_mv_shared_ptr_const +#define MEMVAR_SHARED_PTR_STATIC camel_case_mv_shared_ptr_static +#define MEMVAR_SHARED_PTR_MUTABLE camel_case_mv_shared_ptr_mutable +#define MEMVAR_SHARED_PTR_MUTABLE_CONST camel_case_mv_shared_ptr_mutable + +#define MEMVAR_ATOMIC camel_case_mv_atomic +#define MEMVAR_ATOMIC_NOSET camel_case_mv_atomic_noset +#define MEMVAR_ATOMIC_STATIC camel_case_mv_atomic_static +#define MEMVAR_ATOMIC_STATIC_NOSET camel_case_mv_atomic_static_noset +#define MEMVAR_ATOMIC_MUTABLE camel_case_mv_atomic_mutable +#define MEMVAR_ATOMIC_MUTABLE_NOSET camel_case_mv_atomic_mutable_noset + +#endif /* NYMPH_MEMBERVARIABLE_HH_ */ From e08ad5406da76007b2510e8f10bb6acaf3b47d55 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Mon, 2 Sep 2019 02:44:01 -0700 Subject: [PATCH 136/521] Moved old library to a separate directory. New .gitignore. --- .gitignore | 55 +++++--- Library/CMakeLists.txt | 98 +------------- .../AddLibPythonPath.sh.in | 0 .../Application/KTApplication.cc | 0 .../Application/KTApplication.hh | 0 .../Application/KTCommandLineHandler.cc | 0 .../Application/KTCommandLineHandler.hh | 0 .../Application/KTCommandLineOption.hh | 0 .../Application/KTConfigurator.cc | 0 .../Application/KTConfigurator.hh | 0 .../Application/KTDataQueueProcessor.cc | 0 .../Application/KTDataQueueProcessor.hh | 0 .../Application/KTFilenameParsers.cc | 0 .../Application/KTFilenameParsers.hh | 0 .../Application/KTPrintDataStructure.cc | 0 .../Application/KTPrintDataStructure.hh | 0 .../Application/KTProcessorToolbox.cc | 0 .../Application/KTProcessorToolbox.hh | 0 .../Application/KTProcessorToolboxPybind.hh | 0 .../Application/KTRunNymph.cc | 0 .../Application/KTRunNymph.hh | 0 .../Application/KTThroughputProfiler.cc | 0 .../Application/KTThroughputProfiler.hh | 0 Library_v1/CMakeLists.txt | 121 ++++++++++++++++++ {Library => Library_v1}/Data/KTApplyCut.cc | 0 {Library => Library_v1}/Data/KTApplyCut.hh | 0 {Library => Library_v1}/Data/KTCoreData.cc | 0 {Library => Library_v1}/Data/KTCoreData.hh | 0 {Library => Library_v1}/Data/KTCut.cc | 0 {Library => Library_v1}/Data/KTCut.hh | 0 {Library => Library_v1}/Data/KTCutFilter.cc | 0 {Library => Library_v1}/Data/KTCutFilter.hh | 0 {Library => Library_v1}/Data/KTCutResult.hh | 0 {Library => Library_v1}/Data/KTCutStatus.cc | 0 {Library => Library_v1}/Data/KTCutStatus.hh | 0 {Library => Library_v1}/Data/KTData.cc | 0 {Library => Library_v1}/Data/KTData.hh | 0 .../Data/KTRegisterNymphExtData.hh | 0 Library_v1/Data/KTTester.cc | 24 ++++ Library_v1/Data/KTTester.hh | 41 ++++++ {Library => Library_v1}/IO/KTJSONWriter.cc | 0 {Library => Library_v1}/IO/KTJSONWriter.hh | 0 {Library => Library_v1}/IO/KTReader.cc | 0 {Library => Library_v1}/IO/KTReader.hh | 0 {Library => Library_v1}/IO/KTWriter.cc | 0 {Library => Library_v1}/IO/KTWriter.hh | 0 {Library => Library_v1}/NymphPybind.cc | 0 .../Processor/KTConnection.hh | 0 .../Processor/KTNymphSignals.hh | 0 .../Processor/KTNymphSlot.hh | 0 .../Processor/KTPrimaryProcessor.cc | 0 .../Processor/KTPrimaryProcessor.hh | 0 .../Processor/KTProcessor.cc | 0 .../Processor/KTProcessor.hh | 0 .../Processor/KTProcessorPybind.cc | 0 .../Processor/KTProcessorPybind.hh | 0 .../Processor/KTPyProcessor.hh | 0 {Library => Library_v1}/Processor/KTSignal.hh | 0 .../Processor/KTSignalSlotBase.hh | 0 .../Processor/KTSignalWrapper.cc | 0 .../Processor/KTSignalWrapper.hh | 0 {Library => Library_v1}/Processor/KTSlot.hh | 0 .../Processor/KTSlotWrapper.cc | 0 .../Processor/KTSlotWrapper.hh | 0 .../Processor/KTThreadReference.cc | 0 .../Processor/KTThreadReference.hh | 0 .../Utility/KTCacheDirectory.cc | 0 .../Utility/KTCacheDirectory.hh | 0 .../Utility/KTConcurrentQueue.hh | 0 .../Utility/KTConfigurable.cc | 0 .../Utility/KTConfigurable.hh | 0 .../Utility/KTConfigurablePybind.hh | 0 .../Utility/KTDirectory.cc | 0 .../Utility/KTDirectory.hh | 0 .../Utility/KTEventLoop.cc | 0 .../Utility/KTEventLoop.hh | 0 .../Utility/KTException.cc | 0 .../Utility/KTException.hh | 0 .../Utility/KTExtensible.hh | 0 .../Utility/KTExtensibleStruct.hh | 0 .../Utility/KTExtensibleStructFactory.hh | 0 {Library => Library_v1}/Utility/KTLogger.hh | 0 .../Utility/KTMemberVariable.hh | 0 .../Utility/KTParamPybind.hh | 0 .../Utility/KTPythonMacros.hh | 0 .../Utility/KTTIFactory.hh | 0 {Library => Library_v1}/Utility/KTTime.cc | 0 {Library => Library_v1}/Utility/KTTime.hh | 0 88 files changed, 221 insertions(+), 118 deletions(-) rename {Library => Library_v1}/AddLibPythonPath.sh.in (100%) rename {Library => Library_v1}/Application/KTApplication.cc (100%) rename {Library => Library_v1}/Application/KTApplication.hh (100%) rename {Library => Library_v1}/Application/KTCommandLineHandler.cc (100%) rename {Library => Library_v1}/Application/KTCommandLineHandler.hh (100%) rename {Library => Library_v1}/Application/KTCommandLineOption.hh (100%) rename {Library => Library_v1}/Application/KTConfigurator.cc (100%) rename {Library => Library_v1}/Application/KTConfigurator.hh (100%) rename {Library => Library_v1}/Application/KTDataQueueProcessor.cc (100%) rename {Library => Library_v1}/Application/KTDataQueueProcessor.hh (100%) rename {Library => Library_v1}/Application/KTFilenameParsers.cc (100%) rename {Library => Library_v1}/Application/KTFilenameParsers.hh (100%) rename {Library => Library_v1}/Application/KTPrintDataStructure.cc (100%) rename {Library => Library_v1}/Application/KTPrintDataStructure.hh (100%) rename {Library => Library_v1}/Application/KTProcessorToolbox.cc (100%) rename {Library => Library_v1}/Application/KTProcessorToolbox.hh (100%) rename {Library => Library_v1}/Application/KTProcessorToolboxPybind.hh (100%) rename {Library => Library_v1}/Application/KTRunNymph.cc (100%) rename {Library => Library_v1}/Application/KTRunNymph.hh (100%) rename {Library => Library_v1}/Application/KTThroughputProfiler.cc (100%) rename {Library => Library_v1}/Application/KTThroughputProfiler.hh (100%) create mode 100644 Library_v1/CMakeLists.txt rename {Library => Library_v1}/Data/KTApplyCut.cc (100%) rename {Library => Library_v1}/Data/KTApplyCut.hh (100%) rename {Library => Library_v1}/Data/KTCoreData.cc (100%) rename {Library => Library_v1}/Data/KTCoreData.hh (100%) rename {Library => Library_v1}/Data/KTCut.cc (100%) rename {Library => Library_v1}/Data/KTCut.hh (100%) rename {Library => Library_v1}/Data/KTCutFilter.cc (100%) rename {Library => Library_v1}/Data/KTCutFilter.hh (100%) rename {Library => Library_v1}/Data/KTCutResult.hh (100%) rename {Library => Library_v1}/Data/KTCutStatus.cc (100%) rename {Library => Library_v1}/Data/KTCutStatus.hh (100%) rename {Library => Library_v1}/Data/KTData.cc (100%) rename {Library => Library_v1}/Data/KTData.hh (100%) rename {Library => Library_v1}/Data/KTRegisterNymphExtData.hh (100%) create mode 100644 Library_v1/Data/KTTester.cc create mode 100644 Library_v1/Data/KTTester.hh rename {Library => Library_v1}/IO/KTJSONWriter.cc (100%) rename {Library => Library_v1}/IO/KTJSONWriter.hh (100%) rename {Library => Library_v1}/IO/KTReader.cc (100%) rename {Library => Library_v1}/IO/KTReader.hh (100%) rename {Library => Library_v1}/IO/KTWriter.cc (100%) rename {Library => Library_v1}/IO/KTWriter.hh (100%) rename {Library => Library_v1}/NymphPybind.cc (100%) rename {Library => Library_v1}/Processor/KTConnection.hh (100%) rename {Library => Library_v1}/Processor/KTNymphSignals.hh (100%) rename {Library => Library_v1}/Processor/KTNymphSlot.hh (100%) rename {Library => Library_v1}/Processor/KTPrimaryProcessor.cc (100%) rename {Library => Library_v1}/Processor/KTPrimaryProcessor.hh (100%) rename {Library => Library_v1}/Processor/KTProcessor.cc (100%) rename {Library => Library_v1}/Processor/KTProcessor.hh (100%) rename {Library => Library_v1}/Processor/KTProcessorPybind.cc (100%) rename {Library => Library_v1}/Processor/KTProcessorPybind.hh (100%) rename {Library => Library_v1}/Processor/KTPyProcessor.hh (100%) rename {Library => Library_v1}/Processor/KTSignal.hh (100%) rename {Library => Library_v1}/Processor/KTSignalSlotBase.hh (100%) rename {Library => Library_v1}/Processor/KTSignalWrapper.cc (100%) rename {Library => Library_v1}/Processor/KTSignalWrapper.hh (100%) rename {Library => Library_v1}/Processor/KTSlot.hh (100%) rename {Library => Library_v1}/Processor/KTSlotWrapper.cc (100%) rename {Library => Library_v1}/Processor/KTSlotWrapper.hh (100%) rename {Library => Library_v1}/Processor/KTThreadReference.cc (100%) rename {Library => Library_v1}/Processor/KTThreadReference.hh (100%) rename {Library => Library_v1}/Utility/KTCacheDirectory.cc (100%) rename {Library => Library_v1}/Utility/KTCacheDirectory.hh (100%) rename {Library => Library_v1}/Utility/KTConcurrentQueue.hh (100%) rename {Library => Library_v1}/Utility/KTConfigurable.cc (100%) rename {Library => Library_v1}/Utility/KTConfigurable.hh (100%) rename {Library => Library_v1}/Utility/KTConfigurablePybind.hh (100%) rename {Library => Library_v1}/Utility/KTDirectory.cc (100%) rename {Library => Library_v1}/Utility/KTDirectory.hh (100%) rename {Library => Library_v1}/Utility/KTEventLoop.cc (100%) rename {Library => Library_v1}/Utility/KTEventLoop.hh (100%) rename {Library => Library_v1}/Utility/KTException.cc (100%) rename {Library => Library_v1}/Utility/KTException.hh (100%) rename {Library => Library_v1}/Utility/KTExtensible.hh (100%) rename {Library => Library_v1}/Utility/KTExtensibleStruct.hh (100%) rename {Library => Library_v1}/Utility/KTExtensibleStructFactory.hh (100%) rename {Library => Library_v1}/Utility/KTLogger.hh (100%) rename {Library => Library_v1}/Utility/KTMemberVariable.hh (100%) rename {Library => Library_v1}/Utility/KTParamPybind.hh (100%) rename {Library => Library_v1}/Utility/KTPythonMacros.hh (100%) rename {Library => Library_v1}/Utility/KTTIFactory.hh (100%) rename {Library => Library_v1}/Utility/KTTime.cc (100%) rename {Library => Library_v1}/Utility/KTTime.hh (100%) diff --git a/.gitignore b/.gitignore index a97774f..77bfe6e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,31 +1,44 @@ -#general: -*.swp +# from emacs +*~ + +# Compiled Object files +*.slo +*.lo *.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries *.so -*.a *.dylib +*.dll -#mac -.DS_Store +# Fortran module files +*.mod +*.smod -#from Eclipse +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app + +# Eclipse .project .cproject +.settings/ -#from cmake -CMakeCache.txt -CMakeFiles/ -Makefile +# VSCode +.vscode/ + +# Build directories build*/ -cbuild*/ -cmake_install.cmake -*Dict.h -*Dict.cxx -Documentation/ReferenceGuide/Doxyfile -Source/Main/ExtractEvents -Source/Main/SimpleElectronHunt -Source/Applications/Main/SimpleElectronHunt -install_manifest.txt -# from emacs -*~ diff --git a/Library/CMakeLists.txt b/Library/CMakeLists.txt index 1411560..508f7ac 100644 --- a/Library/CMakeLists.txt +++ b/Library/CMakeLists.txt @@ -1,5 +1,5 @@ # CMakeLists for Nymph/Library -# Author: N. Oblath +# Author: N.S. Oblath include( PythonPackage ) @@ -10,112 +10,16 @@ set( IO_DIR IO ) set( APPL_DIR Application ) set( NYMPH_HEADERFILES -# ${UTIL_DIR}/KTCacheDirectory.hh -# ${UTIL_DIR}/KTConcurrentQueue.hh -# ${UTIL_DIR}/KTConfigurable.hh -# ${UTIL_DIR}/KTDirectory.hh -# ${UTIL_DIR}/KTEventLoop.hh -# ${UTIL_DIR}/KTException.hh -# ${UTIL_DIR}/KTExtensible.hh -# ${UTIL_DIR}/KTExtensibleStruct.hh -# ${UTIL_DIR}/KTExtensibleStructFactory.hh -# ${UTIL_DIR}/KTLogger.hh -# ${UTIL_DIR}/KTMemberVariable.hh -# ${UTIL_DIR}/KTTIFactory.hh -# ${UTIL_DIR}/KTTime.hh -# ${DATA_DIR}/KTApplyCut.hh -# ${DATA_DIR}/KTCoreData.hh -# ${DATA_DIR}/KTCut.hh -# ${DATA_DIR}/KTCutFilter.hh -# ${DATA_DIR}/KTCutResult.hh -# ${DATA_DIR}/KTCutStatus.hh -# ${DATA_DIR}/KTData.hh -# ${DATA_DIR}/KTRegisterNymphExtData.hh -# ${PROC_DIR}/KTConnection.hh -# ${PROC_DIR}/KTPrimaryProcessor.hh -# ${PROC_DIR}/KTProcessor.hh -# ${PROC_DIR}/KTSignal.hh -# ${PROC_DIR}/KTSignalWrapper.hh -# ${PROC_DIR}/KTSlot.hh -# ${PROC_DIR}/KTSlotWrapper.hh -# ${PROC_DIR}/KTThreadReference.hh -# ${IO_DIR}/KTJSONWriter.hh -# ${IO_DIR}/KTReader.hh -# ${IO_DIR}/KTWriter.hh -# ${APPL_DIR}/KTApplication.hh -# ${APPL_DIR}/KTCommandLineHandler.hh -# ${APPL_DIR}/KTCommandLineOption.hh -# ${APPL_DIR}/KTConfigurator.hh -# ${APPL_DIR}/KTDataQueueProcessor.hh -# ${APPL_DIR}/KTFilenameParsers.hh -# ${APPL_DIR}/KTPrintDataStructure.hh -# ${APPL_DIR}/KTProcessorToolbox.hh -# ${APPL_DIR}/KTRunNymph.hh -# ${APPL_DIR}/KTThroughputProfiler.hh ${UTIL_DIR}/Exception.hh ${UTIL_DIR}/MemberVariable.hh ) set( NYMPH_SOURCEFILES -# ${UTIL_DIR}/KTCacheDirectory.cc -# ${UTIL_DIR}/KTConfigurable.cc -# ${UTIL_DIR}/KTDirectory.cc -# ${UTIL_DIR}/KTEventLoop.cc -# ${UTIL_DIR}/KTException.cc -# ${UTIL_DIR}/KTTime.cc -# ${DATA_DIR}/KTApplyCut.cc -# ${DATA_DIR}/KTCoreData.cc -# ${DATA_DIR}/KTCut.cc -# ${DATA_DIR}/KTCutFilter.cc -# ${DATA_DIR}/KTCutStatus.cc -# ${DATA_DIR}/KTData.cc -# ${PROC_DIR}/KTPrimaryProcessor.cc -# ${PROC_DIR}/KTProcessor.cc -# ${PROC_DIR}/KTSignalWrapper.cc -# ${PROC_DIR}/KTSlotWrapper.cc -# ${PROC_DIR}/KTThreadReference.cc -# ${IO_DIR}/KTJSONWriter.cc -# ${IO_DIR}/KTReader.cc -# ${IO_DIR}/KTWriter.cc -# ${APPL_DIR}/KTApplication.cc -# ${APPL_DIR}/KTCommandLineHandler.cc -# ${APPL_DIR}/KTConfigurator.cc -# ${APPL_DIR}/KTDataQueueProcessor.cc -# ${APPL_DIR}/KTFilenameParsers.cc -# ${APPL_DIR}/KTPrintDataStructure.cc -# ${APPL_DIR}/KTProcessorToolbox.cc -# ${APPL_DIR}/KTRunNymph.cc -# ${APPL_DIR}/KTThroughputProfiler.cc ${UTIL_DIR}/Exception.cc ) -# Python binding headers -set( NYMPH_PYBINDING_HEADERFILES - #${UTIL_DIR}/KTConfigurablePybind.hh - ${UTIL_DIR}/KTParamPybind.hh - ${PROC_DIR}/KTProcessorPybind.hh - ${PROC_DIR}/KTPyProcessor.hh -) - -# Python bindings -set( NYMPH_PYBINDING_SOURCEFILES - ${PROC_DIR}/KTProcessorPybind.cc - NymphPybind.cc -) ################################################## pbuilder_library( Nymph NYMPH_SOURCEFILES "" ) pbuilder_install_headers( ${NYMPH_HEADERFILES} ) - -if( Nymph_ENABLE_PYTHON ) - set( LIB_DEPENDENCIES Nymph ) - - configure_file( AddLibPythonPath.sh.in AddLibPythonPath.sh @ONLY) - install( FILES ${CMAKE_CURRENT_BINARY_DIR}/AddLibPythonPath.sh DESTINATION ${BIN_INSTALL_DIR} ) - - pybind11_add_module( py_nymph MODULE ${NYMPH_PYBINDING_SOURCEFILES} ) - target_link_libraries( py_nymph PRIVATE ${LIB_DEPENDENCIES} ${EXTERNAL_LIBRARIES} ) - pbuilder_install_libraries( py_nymph ) - pbuilder_install_headers( ${NYMPH_PYBINDING_HEADERFILES} ) -endif( Nymph_ENABLE_PYTHON ) diff --git a/Library/AddLibPythonPath.sh.in b/Library_v1/AddLibPythonPath.sh.in similarity index 100% rename from Library/AddLibPythonPath.sh.in rename to Library_v1/AddLibPythonPath.sh.in diff --git a/Library/Application/KTApplication.cc b/Library_v1/Application/KTApplication.cc similarity index 100% rename from Library/Application/KTApplication.cc rename to Library_v1/Application/KTApplication.cc diff --git a/Library/Application/KTApplication.hh b/Library_v1/Application/KTApplication.hh similarity index 100% rename from Library/Application/KTApplication.hh rename to Library_v1/Application/KTApplication.hh diff --git a/Library/Application/KTCommandLineHandler.cc b/Library_v1/Application/KTCommandLineHandler.cc similarity index 100% rename from Library/Application/KTCommandLineHandler.cc rename to Library_v1/Application/KTCommandLineHandler.cc diff --git a/Library/Application/KTCommandLineHandler.hh b/Library_v1/Application/KTCommandLineHandler.hh similarity index 100% rename from Library/Application/KTCommandLineHandler.hh rename to Library_v1/Application/KTCommandLineHandler.hh diff --git a/Library/Application/KTCommandLineOption.hh b/Library_v1/Application/KTCommandLineOption.hh similarity index 100% rename from Library/Application/KTCommandLineOption.hh rename to Library_v1/Application/KTCommandLineOption.hh diff --git a/Library/Application/KTConfigurator.cc b/Library_v1/Application/KTConfigurator.cc similarity index 100% rename from Library/Application/KTConfigurator.cc rename to Library_v1/Application/KTConfigurator.cc diff --git a/Library/Application/KTConfigurator.hh b/Library_v1/Application/KTConfigurator.hh similarity index 100% rename from Library/Application/KTConfigurator.hh rename to Library_v1/Application/KTConfigurator.hh diff --git a/Library/Application/KTDataQueueProcessor.cc b/Library_v1/Application/KTDataQueueProcessor.cc similarity index 100% rename from Library/Application/KTDataQueueProcessor.cc rename to Library_v1/Application/KTDataQueueProcessor.cc diff --git a/Library/Application/KTDataQueueProcessor.hh b/Library_v1/Application/KTDataQueueProcessor.hh similarity index 100% rename from Library/Application/KTDataQueueProcessor.hh rename to Library_v1/Application/KTDataQueueProcessor.hh diff --git a/Library/Application/KTFilenameParsers.cc b/Library_v1/Application/KTFilenameParsers.cc similarity index 100% rename from Library/Application/KTFilenameParsers.cc rename to Library_v1/Application/KTFilenameParsers.cc diff --git a/Library/Application/KTFilenameParsers.hh b/Library_v1/Application/KTFilenameParsers.hh similarity index 100% rename from Library/Application/KTFilenameParsers.hh rename to Library_v1/Application/KTFilenameParsers.hh diff --git a/Library/Application/KTPrintDataStructure.cc b/Library_v1/Application/KTPrintDataStructure.cc similarity index 100% rename from Library/Application/KTPrintDataStructure.cc rename to Library_v1/Application/KTPrintDataStructure.cc diff --git a/Library/Application/KTPrintDataStructure.hh b/Library_v1/Application/KTPrintDataStructure.hh similarity index 100% rename from Library/Application/KTPrintDataStructure.hh rename to Library_v1/Application/KTPrintDataStructure.hh diff --git a/Library/Application/KTProcessorToolbox.cc b/Library_v1/Application/KTProcessorToolbox.cc similarity index 100% rename from Library/Application/KTProcessorToolbox.cc rename to Library_v1/Application/KTProcessorToolbox.cc diff --git a/Library/Application/KTProcessorToolbox.hh b/Library_v1/Application/KTProcessorToolbox.hh similarity index 100% rename from Library/Application/KTProcessorToolbox.hh rename to Library_v1/Application/KTProcessorToolbox.hh diff --git a/Library/Application/KTProcessorToolboxPybind.hh b/Library_v1/Application/KTProcessorToolboxPybind.hh similarity index 100% rename from Library/Application/KTProcessorToolboxPybind.hh rename to Library_v1/Application/KTProcessorToolboxPybind.hh diff --git a/Library/Application/KTRunNymph.cc b/Library_v1/Application/KTRunNymph.cc similarity index 100% rename from Library/Application/KTRunNymph.cc rename to Library_v1/Application/KTRunNymph.cc diff --git a/Library/Application/KTRunNymph.hh b/Library_v1/Application/KTRunNymph.hh similarity index 100% rename from Library/Application/KTRunNymph.hh rename to Library_v1/Application/KTRunNymph.hh diff --git a/Library/Application/KTThroughputProfiler.cc b/Library_v1/Application/KTThroughputProfiler.cc similarity index 100% rename from Library/Application/KTThroughputProfiler.cc rename to Library_v1/Application/KTThroughputProfiler.cc diff --git a/Library/Application/KTThroughputProfiler.hh b/Library_v1/Application/KTThroughputProfiler.hh similarity index 100% rename from Library/Application/KTThroughputProfiler.hh rename to Library_v1/Application/KTThroughputProfiler.hh diff --git a/Library_v1/CMakeLists.txt b/Library_v1/CMakeLists.txt new file mode 100644 index 0000000..1411560 --- /dev/null +++ b/Library_v1/CMakeLists.txt @@ -0,0 +1,121 @@ +# CMakeLists for Nymph/Library +# Author: N. Oblath + +include( PythonPackage ) + +set( UTIL_DIR Utility ) +set( DATA_DIR Data ) +set( PROC_DIR Processor ) +set( IO_DIR IO ) +set( APPL_DIR Application ) + +set( NYMPH_HEADERFILES +# ${UTIL_DIR}/KTCacheDirectory.hh +# ${UTIL_DIR}/KTConcurrentQueue.hh +# ${UTIL_DIR}/KTConfigurable.hh +# ${UTIL_DIR}/KTDirectory.hh +# ${UTIL_DIR}/KTEventLoop.hh +# ${UTIL_DIR}/KTException.hh +# ${UTIL_DIR}/KTExtensible.hh +# ${UTIL_DIR}/KTExtensibleStruct.hh +# ${UTIL_DIR}/KTExtensibleStructFactory.hh +# ${UTIL_DIR}/KTLogger.hh +# ${UTIL_DIR}/KTMemberVariable.hh +# ${UTIL_DIR}/KTTIFactory.hh +# ${UTIL_DIR}/KTTime.hh +# ${DATA_DIR}/KTApplyCut.hh +# ${DATA_DIR}/KTCoreData.hh +# ${DATA_DIR}/KTCut.hh +# ${DATA_DIR}/KTCutFilter.hh +# ${DATA_DIR}/KTCutResult.hh +# ${DATA_DIR}/KTCutStatus.hh +# ${DATA_DIR}/KTData.hh +# ${DATA_DIR}/KTRegisterNymphExtData.hh +# ${PROC_DIR}/KTConnection.hh +# ${PROC_DIR}/KTPrimaryProcessor.hh +# ${PROC_DIR}/KTProcessor.hh +# ${PROC_DIR}/KTSignal.hh +# ${PROC_DIR}/KTSignalWrapper.hh +# ${PROC_DIR}/KTSlot.hh +# ${PROC_DIR}/KTSlotWrapper.hh +# ${PROC_DIR}/KTThreadReference.hh +# ${IO_DIR}/KTJSONWriter.hh +# ${IO_DIR}/KTReader.hh +# ${IO_DIR}/KTWriter.hh +# ${APPL_DIR}/KTApplication.hh +# ${APPL_DIR}/KTCommandLineHandler.hh +# ${APPL_DIR}/KTCommandLineOption.hh +# ${APPL_DIR}/KTConfigurator.hh +# ${APPL_DIR}/KTDataQueueProcessor.hh +# ${APPL_DIR}/KTFilenameParsers.hh +# ${APPL_DIR}/KTPrintDataStructure.hh +# ${APPL_DIR}/KTProcessorToolbox.hh +# ${APPL_DIR}/KTRunNymph.hh +# ${APPL_DIR}/KTThroughputProfiler.hh + ${UTIL_DIR}/Exception.hh + ${UTIL_DIR}/MemberVariable.hh +) + +set( NYMPH_SOURCEFILES +# ${UTIL_DIR}/KTCacheDirectory.cc +# ${UTIL_DIR}/KTConfigurable.cc +# ${UTIL_DIR}/KTDirectory.cc +# ${UTIL_DIR}/KTEventLoop.cc +# ${UTIL_DIR}/KTException.cc +# ${UTIL_DIR}/KTTime.cc +# ${DATA_DIR}/KTApplyCut.cc +# ${DATA_DIR}/KTCoreData.cc +# ${DATA_DIR}/KTCut.cc +# ${DATA_DIR}/KTCutFilter.cc +# ${DATA_DIR}/KTCutStatus.cc +# ${DATA_DIR}/KTData.cc +# ${PROC_DIR}/KTPrimaryProcessor.cc +# ${PROC_DIR}/KTProcessor.cc +# ${PROC_DIR}/KTSignalWrapper.cc +# ${PROC_DIR}/KTSlotWrapper.cc +# ${PROC_DIR}/KTThreadReference.cc +# ${IO_DIR}/KTJSONWriter.cc +# ${IO_DIR}/KTReader.cc +# ${IO_DIR}/KTWriter.cc +# ${APPL_DIR}/KTApplication.cc +# ${APPL_DIR}/KTCommandLineHandler.cc +# ${APPL_DIR}/KTConfigurator.cc +# ${APPL_DIR}/KTDataQueueProcessor.cc +# ${APPL_DIR}/KTFilenameParsers.cc +# ${APPL_DIR}/KTPrintDataStructure.cc +# ${APPL_DIR}/KTProcessorToolbox.cc +# ${APPL_DIR}/KTRunNymph.cc +# ${APPL_DIR}/KTThroughputProfiler.cc + ${UTIL_DIR}/Exception.cc +) + +# Python binding headers +set( NYMPH_PYBINDING_HEADERFILES + #${UTIL_DIR}/KTConfigurablePybind.hh + ${UTIL_DIR}/KTParamPybind.hh + ${PROC_DIR}/KTProcessorPybind.hh + ${PROC_DIR}/KTPyProcessor.hh +) + +# Python bindings +set( NYMPH_PYBINDING_SOURCEFILES + ${PROC_DIR}/KTProcessorPybind.cc + NymphPybind.cc +) + +################################################## + +pbuilder_library( Nymph NYMPH_SOURCEFILES "" ) +pbuilder_install_headers( ${NYMPH_HEADERFILES} ) + +if( Nymph_ENABLE_PYTHON ) + set( LIB_DEPENDENCIES Nymph ) + + configure_file( AddLibPythonPath.sh.in AddLibPythonPath.sh @ONLY) + install( FILES ${CMAKE_CURRENT_BINARY_DIR}/AddLibPythonPath.sh DESTINATION ${BIN_INSTALL_DIR} ) + + pybind11_add_module( py_nymph MODULE ${NYMPH_PYBINDING_SOURCEFILES} ) + target_link_libraries( py_nymph PRIVATE ${LIB_DEPENDENCIES} ${EXTERNAL_LIBRARIES} ) + pbuilder_install_libraries( py_nymph ) + pbuilder_install_headers( ${NYMPH_PYBINDING_HEADERFILES} ) +endif( Nymph_ENABLE_PYTHON ) diff --git a/Library/Data/KTApplyCut.cc b/Library_v1/Data/KTApplyCut.cc similarity index 100% rename from Library/Data/KTApplyCut.cc rename to Library_v1/Data/KTApplyCut.cc diff --git a/Library/Data/KTApplyCut.hh b/Library_v1/Data/KTApplyCut.hh similarity index 100% rename from Library/Data/KTApplyCut.hh rename to Library_v1/Data/KTApplyCut.hh diff --git a/Library/Data/KTCoreData.cc b/Library_v1/Data/KTCoreData.cc similarity index 100% rename from Library/Data/KTCoreData.cc rename to Library_v1/Data/KTCoreData.cc diff --git a/Library/Data/KTCoreData.hh b/Library_v1/Data/KTCoreData.hh similarity index 100% rename from Library/Data/KTCoreData.hh rename to Library_v1/Data/KTCoreData.hh diff --git a/Library/Data/KTCut.cc b/Library_v1/Data/KTCut.cc similarity index 100% rename from Library/Data/KTCut.cc rename to Library_v1/Data/KTCut.cc diff --git a/Library/Data/KTCut.hh b/Library_v1/Data/KTCut.hh similarity index 100% rename from Library/Data/KTCut.hh rename to Library_v1/Data/KTCut.hh diff --git a/Library/Data/KTCutFilter.cc b/Library_v1/Data/KTCutFilter.cc similarity index 100% rename from Library/Data/KTCutFilter.cc rename to Library_v1/Data/KTCutFilter.cc diff --git a/Library/Data/KTCutFilter.hh b/Library_v1/Data/KTCutFilter.hh similarity index 100% rename from Library/Data/KTCutFilter.hh rename to Library_v1/Data/KTCutFilter.hh diff --git a/Library/Data/KTCutResult.hh b/Library_v1/Data/KTCutResult.hh similarity index 100% rename from Library/Data/KTCutResult.hh rename to Library_v1/Data/KTCutResult.hh diff --git a/Library/Data/KTCutStatus.cc b/Library_v1/Data/KTCutStatus.cc similarity index 100% rename from Library/Data/KTCutStatus.cc rename to Library_v1/Data/KTCutStatus.cc diff --git a/Library/Data/KTCutStatus.hh b/Library_v1/Data/KTCutStatus.hh similarity index 100% rename from Library/Data/KTCutStatus.hh rename to Library_v1/Data/KTCutStatus.hh diff --git a/Library/Data/KTData.cc b/Library_v1/Data/KTData.cc similarity index 100% rename from Library/Data/KTData.cc rename to Library_v1/Data/KTData.cc diff --git a/Library/Data/KTData.hh b/Library_v1/Data/KTData.hh similarity index 100% rename from Library/Data/KTData.hh rename to Library_v1/Data/KTData.hh diff --git a/Library/Data/KTRegisterNymphExtData.hh b/Library_v1/Data/KTRegisterNymphExtData.hh similarity index 100% rename from Library/Data/KTRegisterNymphExtData.hh rename to Library_v1/Data/KTRegisterNymphExtData.hh diff --git a/Library_v1/Data/KTTester.cc b/Library_v1/Data/KTTester.cc new file mode 100644 index 0000000..e0ce295 --- /dev/null +++ b/Library_v1/Data/KTTester.cc @@ -0,0 +1,24 @@ +/* + * KTTester.cc + * + * Created on: Aug 26, 2019 + * Author: obla999 + */ + +#include "KTTester.hh" + +namespace Nymph +{ + + KTTester::KTTester() + { + // TODO Auto-generated constructor stub + + } + + KTTester::~KTTester() + { + // TODO Auto-generated destructor stub + } + +} /* namespace Nymph */ diff --git a/Library_v1/Data/KTTester.hh b/Library_v1/Data/KTTester.hh new file mode 100644 index 0000000..f0e3f5b --- /dev/null +++ b/Library_v1/Data/KTTester.hh @@ -0,0 +1,41 @@ +/* + * KTTester.hh + * + * Created on: Aug 26, 2019 + * Author: obla999 + */ + +#ifndef LIBRARY_DATA_KTTESTER_HH_ +#define LIBRARY_DATA_KTTESTER_HH_ + +//#include "KTConfigurable.hh" + +#include "KTConnection.hh" +//#include "KTLogger.hh" +#include "KTSignalWrapper.hh" +#include "KTSlotWrapper.hh" + +//#include "factory.hh" + +//#include + +//#include +//#include +//#include +//#include +//#include +//#include + +namespace Nymph +{ + + class KTTester + { + public: + KTTester(); + virtual ~KTTester(); + }; + +} /* namespace Nymph */ + +#endif /* LIBRARY_DATA_KTTESTER_HH_ */ diff --git a/Library/IO/KTJSONWriter.cc b/Library_v1/IO/KTJSONWriter.cc similarity index 100% rename from Library/IO/KTJSONWriter.cc rename to Library_v1/IO/KTJSONWriter.cc diff --git a/Library/IO/KTJSONWriter.hh b/Library_v1/IO/KTJSONWriter.hh similarity index 100% rename from Library/IO/KTJSONWriter.hh rename to Library_v1/IO/KTJSONWriter.hh diff --git a/Library/IO/KTReader.cc b/Library_v1/IO/KTReader.cc similarity index 100% rename from Library/IO/KTReader.cc rename to Library_v1/IO/KTReader.cc diff --git a/Library/IO/KTReader.hh b/Library_v1/IO/KTReader.hh similarity index 100% rename from Library/IO/KTReader.hh rename to Library_v1/IO/KTReader.hh diff --git a/Library/IO/KTWriter.cc b/Library_v1/IO/KTWriter.cc similarity index 100% rename from Library/IO/KTWriter.cc rename to Library_v1/IO/KTWriter.cc diff --git a/Library/IO/KTWriter.hh b/Library_v1/IO/KTWriter.hh similarity index 100% rename from Library/IO/KTWriter.hh rename to Library_v1/IO/KTWriter.hh diff --git a/Library/NymphPybind.cc b/Library_v1/NymphPybind.cc similarity index 100% rename from Library/NymphPybind.cc rename to Library_v1/NymphPybind.cc diff --git a/Library/Processor/KTConnection.hh b/Library_v1/Processor/KTConnection.hh similarity index 100% rename from Library/Processor/KTConnection.hh rename to Library_v1/Processor/KTConnection.hh diff --git a/Library/Processor/KTNymphSignals.hh b/Library_v1/Processor/KTNymphSignals.hh similarity index 100% rename from Library/Processor/KTNymphSignals.hh rename to Library_v1/Processor/KTNymphSignals.hh diff --git a/Library/Processor/KTNymphSlot.hh b/Library_v1/Processor/KTNymphSlot.hh similarity index 100% rename from Library/Processor/KTNymphSlot.hh rename to Library_v1/Processor/KTNymphSlot.hh diff --git a/Library/Processor/KTPrimaryProcessor.cc b/Library_v1/Processor/KTPrimaryProcessor.cc similarity index 100% rename from Library/Processor/KTPrimaryProcessor.cc rename to Library_v1/Processor/KTPrimaryProcessor.cc diff --git a/Library/Processor/KTPrimaryProcessor.hh b/Library_v1/Processor/KTPrimaryProcessor.hh similarity index 100% rename from Library/Processor/KTPrimaryProcessor.hh rename to Library_v1/Processor/KTPrimaryProcessor.hh diff --git a/Library/Processor/KTProcessor.cc b/Library_v1/Processor/KTProcessor.cc similarity index 100% rename from Library/Processor/KTProcessor.cc rename to Library_v1/Processor/KTProcessor.cc diff --git a/Library/Processor/KTProcessor.hh b/Library_v1/Processor/KTProcessor.hh similarity index 100% rename from Library/Processor/KTProcessor.hh rename to Library_v1/Processor/KTProcessor.hh diff --git a/Library/Processor/KTProcessorPybind.cc b/Library_v1/Processor/KTProcessorPybind.cc similarity index 100% rename from Library/Processor/KTProcessorPybind.cc rename to Library_v1/Processor/KTProcessorPybind.cc diff --git a/Library/Processor/KTProcessorPybind.hh b/Library_v1/Processor/KTProcessorPybind.hh similarity index 100% rename from Library/Processor/KTProcessorPybind.hh rename to Library_v1/Processor/KTProcessorPybind.hh diff --git a/Library/Processor/KTPyProcessor.hh b/Library_v1/Processor/KTPyProcessor.hh similarity index 100% rename from Library/Processor/KTPyProcessor.hh rename to Library_v1/Processor/KTPyProcessor.hh diff --git a/Library/Processor/KTSignal.hh b/Library_v1/Processor/KTSignal.hh similarity index 100% rename from Library/Processor/KTSignal.hh rename to Library_v1/Processor/KTSignal.hh diff --git a/Library/Processor/KTSignalSlotBase.hh b/Library_v1/Processor/KTSignalSlotBase.hh similarity index 100% rename from Library/Processor/KTSignalSlotBase.hh rename to Library_v1/Processor/KTSignalSlotBase.hh diff --git a/Library/Processor/KTSignalWrapper.cc b/Library_v1/Processor/KTSignalWrapper.cc similarity index 100% rename from Library/Processor/KTSignalWrapper.cc rename to Library_v1/Processor/KTSignalWrapper.cc diff --git a/Library/Processor/KTSignalWrapper.hh b/Library_v1/Processor/KTSignalWrapper.hh similarity index 100% rename from Library/Processor/KTSignalWrapper.hh rename to Library_v1/Processor/KTSignalWrapper.hh diff --git a/Library/Processor/KTSlot.hh b/Library_v1/Processor/KTSlot.hh similarity index 100% rename from Library/Processor/KTSlot.hh rename to Library_v1/Processor/KTSlot.hh diff --git a/Library/Processor/KTSlotWrapper.cc b/Library_v1/Processor/KTSlotWrapper.cc similarity index 100% rename from Library/Processor/KTSlotWrapper.cc rename to Library_v1/Processor/KTSlotWrapper.cc diff --git a/Library/Processor/KTSlotWrapper.hh b/Library_v1/Processor/KTSlotWrapper.hh similarity index 100% rename from Library/Processor/KTSlotWrapper.hh rename to Library_v1/Processor/KTSlotWrapper.hh diff --git a/Library/Processor/KTThreadReference.cc b/Library_v1/Processor/KTThreadReference.cc similarity index 100% rename from Library/Processor/KTThreadReference.cc rename to Library_v1/Processor/KTThreadReference.cc diff --git a/Library/Processor/KTThreadReference.hh b/Library_v1/Processor/KTThreadReference.hh similarity index 100% rename from Library/Processor/KTThreadReference.hh rename to Library_v1/Processor/KTThreadReference.hh diff --git a/Library/Utility/KTCacheDirectory.cc b/Library_v1/Utility/KTCacheDirectory.cc similarity index 100% rename from Library/Utility/KTCacheDirectory.cc rename to Library_v1/Utility/KTCacheDirectory.cc diff --git a/Library/Utility/KTCacheDirectory.hh b/Library_v1/Utility/KTCacheDirectory.hh similarity index 100% rename from Library/Utility/KTCacheDirectory.hh rename to Library_v1/Utility/KTCacheDirectory.hh diff --git a/Library/Utility/KTConcurrentQueue.hh b/Library_v1/Utility/KTConcurrentQueue.hh similarity index 100% rename from Library/Utility/KTConcurrentQueue.hh rename to Library_v1/Utility/KTConcurrentQueue.hh diff --git a/Library/Utility/KTConfigurable.cc b/Library_v1/Utility/KTConfigurable.cc similarity index 100% rename from Library/Utility/KTConfigurable.cc rename to Library_v1/Utility/KTConfigurable.cc diff --git a/Library/Utility/KTConfigurable.hh b/Library_v1/Utility/KTConfigurable.hh similarity index 100% rename from Library/Utility/KTConfigurable.hh rename to Library_v1/Utility/KTConfigurable.hh diff --git a/Library/Utility/KTConfigurablePybind.hh b/Library_v1/Utility/KTConfigurablePybind.hh similarity index 100% rename from Library/Utility/KTConfigurablePybind.hh rename to Library_v1/Utility/KTConfigurablePybind.hh diff --git a/Library/Utility/KTDirectory.cc b/Library_v1/Utility/KTDirectory.cc similarity index 100% rename from Library/Utility/KTDirectory.cc rename to Library_v1/Utility/KTDirectory.cc diff --git a/Library/Utility/KTDirectory.hh b/Library_v1/Utility/KTDirectory.hh similarity index 100% rename from Library/Utility/KTDirectory.hh rename to Library_v1/Utility/KTDirectory.hh diff --git a/Library/Utility/KTEventLoop.cc b/Library_v1/Utility/KTEventLoop.cc similarity index 100% rename from Library/Utility/KTEventLoop.cc rename to Library_v1/Utility/KTEventLoop.cc diff --git a/Library/Utility/KTEventLoop.hh b/Library_v1/Utility/KTEventLoop.hh similarity index 100% rename from Library/Utility/KTEventLoop.hh rename to Library_v1/Utility/KTEventLoop.hh diff --git a/Library/Utility/KTException.cc b/Library_v1/Utility/KTException.cc similarity index 100% rename from Library/Utility/KTException.cc rename to Library_v1/Utility/KTException.cc diff --git a/Library/Utility/KTException.hh b/Library_v1/Utility/KTException.hh similarity index 100% rename from Library/Utility/KTException.hh rename to Library_v1/Utility/KTException.hh diff --git a/Library/Utility/KTExtensible.hh b/Library_v1/Utility/KTExtensible.hh similarity index 100% rename from Library/Utility/KTExtensible.hh rename to Library_v1/Utility/KTExtensible.hh diff --git a/Library/Utility/KTExtensibleStruct.hh b/Library_v1/Utility/KTExtensibleStruct.hh similarity index 100% rename from Library/Utility/KTExtensibleStruct.hh rename to Library_v1/Utility/KTExtensibleStruct.hh diff --git a/Library/Utility/KTExtensibleStructFactory.hh b/Library_v1/Utility/KTExtensibleStructFactory.hh similarity index 100% rename from Library/Utility/KTExtensibleStructFactory.hh rename to Library_v1/Utility/KTExtensibleStructFactory.hh diff --git a/Library/Utility/KTLogger.hh b/Library_v1/Utility/KTLogger.hh similarity index 100% rename from Library/Utility/KTLogger.hh rename to Library_v1/Utility/KTLogger.hh diff --git a/Library/Utility/KTMemberVariable.hh b/Library_v1/Utility/KTMemberVariable.hh similarity index 100% rename from Library/Utility/KTMemberVariable.hh rename to Library_v1/Utility/KTMemberVariable.hh diff --git a/Library/Utility/KTParamPybind.hh b/Library_v1/Utility/KTParamPybind.hh similarity index 100% rename from Library/Utility/KTParamPybind.hh rename to Library_v1/Utility/KTParamPybind.hh diff --git a/Library/Utility/KTPythonMacros.hh b/Library_v1/Utility/KTPythonMacros.hh similarity index 100% rename from Library/Utility/KTPythonMacros.hh rename to Library_v1/Utility/KTPythonMacros.hh diff --git a/Library/Utility/KTTIFactory.hh b/Library_v1/Utility/KTTIFactory.hh similarity index 100% rename from Library/Utility/KTTIFactory.hh rename to Library_v1/Utility/KTTIFactory.hh diff --git a/Library/Utility/KTTime.cc b/Library_v1/Utility/KTTime.cc similarity index 100% rename from Library/Utility/KTTime.cc rename to Library_v1/Utility/KTTime.cc diff --git a/Library/Utility/KTTime.hh b/Library_v1/Utility/KTTime.hh similarity index 100% rename from Library/Utility/KTTime.hh rename to Library_v1/Utility/KTTime.hh From f189a7637f6606950edb5272ef0365295e4946a3 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Sat, 7 Sep 2019 07:56:53 -0700 Subject: [PATCH 137/521] Updated Scarab (develop branch) --- Scarab | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Scarab b/Scarab index ae05d4c..d8a19bf 160000 --- a/Scarab +++ b/Scarab @@ -1 +1 @@ -Subproject commit ae05d4c5c157c6cc569b1f3855a8b2599abbdd70 +Subproject commit d8a19bfb2d8d41eff57a84f30760d1c4c3291ab0 From 7ede698d6c5e8dea61a15acc4b9b81575f75f3f9 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Sat, 7 Sep 2019 08:03:14 -0700 Subject: [PATCH 138/521] Removed pybind11 submodule --- .gitmodules | 3 --- External/pybind11 | 1 - 2 files changed, 4 deletions(-) delete mode 160000 External/pybind11 diff --git a/.gitmodules b/.gitmodules index 2588cda..4a11728 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,9 +1,6 @@ [submodule "Scarab"] path = Scarab url = https://github.com/project8/scarab -[submodule "External/pybind11"] - path = External/pybind11 - url = https://github.com/pybind/pybind11.git [submodule "External/cereal"] path = External/cereal url = https://github.com/USCiLab/cereal.git diff --git a/External/pybind11 b/External/pybind11 deleted file mode 160000 index add56cc..0000000 --- a/External/pybind11 +++ /dev/null @@ -1 +0,0 @@ -Subproject commit add56ccdcac23a6c522a2c1174a866e293c61dab From df14b7ed68d017c497b19b918d2e4f9e7e6dc7df Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Sat, 7 Sep 2019 16:21:58 -0700 Subject: [PATCH 139/521] Basics of signals, slots, and processors compile --- Library/CMakeLists.txt | 6 + Library/Processor/PrimaryProcessor.cc | 69 +++++++ Library/Processor/PrimaryProcessor.hh | 53 ++++++ Library/Processor/Processor.cc | 114 ++++++++++++ Library/Processor/Processor.hh | 115 ++++++++++++ Library/Processor/Signal.hh | 259 ++++++++++++++++++++++++++ Library/Processor/SignalSlotBase.cc | 26 +++ Library/Processor/SignalSlotBase.hh | 57 ++++++ Library/Processor/Slot.hh | 229 +++++++++++++++++++++++ 9 files changed, 928 insertions(+) create mode 100644 Library/Processor/PrimaryProcessor.cc create mode 100644 Library/Processor/PrimaryProcessor.hh create mode 100644 Library/Processor/Processor.cc create mode 100644 Library/Processor/Processor.hh create mode 100644 Library/Processor/Signal.hh create mode 100644 Library/Processor/SignalSlotBase.cc create mode 100644 Library/Processor/SignalSlotBase.hh create mode 100644 Library/Processor/Slot.hh diff --git a/Library/CMakeLists.txt b/Library/CMakeLists.txt index 508f7ac..7cc4740 100644 --- a/Library/CMakeLists.txt +++ b/Library/CMakeLists.txt @@ -12,10 +12,16 @@ set( APPL_DIR Application ) set( NYMPH_HEADERFILES ${UTIL_DIR}/Exception.hh ${UTIL_DIR}/MemberVariable.hh + #${PROC_DIR}/PrimaryProcessor.hh + ${PROC_DIR}/Processor.hh + ${PROC_DIR}/SignalSlotBase.hh ) set( NYMPH_SOURCEFILES ${UTIL_DIR}/Exception.cc + #${PROC_DIR}/PrimaryProcessor.cc + ${PROC_DIR}/Processor.cc + ${PROC_DIR}/SignalSlotBase.cc ) diff --git a/Library/Processor/PrimaryProcessor.cc b/Library/Processor/PrimaryProcessor.cc new file mode 100644 index 0000000..27b6f1d --- /dev/null +++ b/Library/Processor/PrimaryProcessor.cc @@ -0,0 +1,69 @@ +/* + * KTPrimaryProcessor.cc + * + * Created on: Oct 10, 2012 + * Author: N.S. Oblath + */ + +#include "KTPrimaryProcessor.hh" + +#include "KTException.hh" +#include "KTLogger.hh" + +namespace Nymph +{ + KTLOGGER( proclog, "KTPrimaryProcessor" ); + + KTPrimaryProcessor::KTPrimaryProcessor( std::initializer_list< std::string > signals, const std::string& name ) : + KTProcessor( name ), + fSignalsEmitted( signals ), + fThreadRef(), + fDoBreakpoint(false) + { + + } + + KTPrimaryProcessor::~KTPrimaryProcessor() + { + } + + void KTPrimaryProcessor::operator ()( std::shared_ptr< KTThreadReference > ref, boost::condition_variable& startedCV, bool& startedFlag ) + { + fThreadRef = ref; + + // pass updated thread reference to downstream slots + for( auto sigIt = fSignalsEmitted.begin(); sigIt != fSignalsEmitted.end(); ++sigIt ) + { + // loop over all processor:slots called by this signal + auto sigConnRange = fSigConnMap.equal_range( *sigIt ); + for( SigConnMapCIt sigConnIt = sigConnRange.first; sigConnIt != sigConnRange.second; ++sigConnIt ) + { + // pass the update on to the connected-to processor + sigConnIt->second.first->PassThreadRefUpdate( sigConnIt->second.second, fThreadRef ); + } + } + + startedFlag = true; + startedCV.notify_all(); + + // go! + try + { + if( ! Run() ) + { + KTERROR( proclog, "An error occurred during processor running." ); + THROW_THREADREF_EXCEPTION( fThreadRef, KTException() << "An error occurred during processor running" ); + } + else + { + fThreadRef->SetReturnValue( KTDataHandle() ); + } + } + catch( boost::exception& e ) + { + fThreadRef->SetReturnException( boost::current_exception() ); + } + return; + } + +} /* namespace Nymph */ diff --git a/Library/Processor/PrimaryProcessor.hh b/Library/Processor/PrimaryProcessor.hh new file mode 100644 index 0000000..e72fcf3 --- /dev/null +++ b/Library/Processor/PrimaryProcessor.hh @@ -0,0 +1,53 @@ +/* + * KTPrimaryProcessor.hh + * + * Created on: Oct 10, 2012 + * Author: N.S. Oblath + */ + +#ifndef KTPRIMARYPROCESSOR_HH_ +#define KTPRIMARYPROCESSOR_HH_ + +#include "KTProcessor.hh" + +#include "KTCoreData.hh" +#include "KTThreadReference.hh" + +#include + +#include + +namespace Nymph +{ + + class KTPrimaryProcessor : public KTProcessor + { + public: + KTPrimaryProcessor( std::initializer_list< std::string > signals, const std::string& name = "default-primary-processor-name" ); + virtual ~KTPrimaryProcessor(); + + public: + /// Callable function used by std::thread + void operator()( std::shared_ptr< KTThreadReference > ref, boost::condition_variable& startedCV, bool& startedFlag ); + + /// Starts the main action of the processor + virtual bool Run() = 0; + + std::shared_ptr< KTThreadReference > GetThreadRef(); + + MEMBERVARIABLE( bool, DoBreakpoint ); + + protected: + std::vector< std::string > fSignalsEmitted; + + std::shared_ptr< KTThreadReference > fThreadRef; + + }; + + inline std::shared_ptr< KTThreadReference > KTPrimaryProcessor::GetThreadRef() + { + return fThreadRef; + } + +} /* namespace Nymph */ +#endif /* KTPRIMARYPROCESSOR_HH_ */ diff --git a/Library/Processor/Processor.cc b/Library/Processor/Processor.cc new file mode 100644 index 0000000..0bfca18 --- /dev/null +++ b/Library/Processor/Processor.cc @@ -0,0 +1,114 @@ +/* + * Processor.cc + * + * Created on: Jan 5, 2012 + * Author: N.S. Oblath + */ + +#include "Processor.hh" + + +namespace Nymph +{ + //KTLOGGER(proclog, "Processor"); + + Processor::Processor( const std::string& name ) : + fName( name ), + fSignals(), + fSlots() + { + } + + Processor::~Processor() + {} + + void Processor::ConnectASlot( const std::string& signalName, Processor& processor, const std::string& slotName, int groupNum ) + { + // get the signal and slot pointers + SigMapIt signalIt = fSignals.find(signalName); + if( signalIt == fSignals.end() ) + { + BOOST_THROW_EXCEPTION( SignalException() << "Unable to connect signal <" + signalName + "> to slot <" + slotName + "> due to a problem with the signal.\n" << + "You may have the signal name wrong." << eom ); + } + + SlotMapIt slotIt = processor.fSlots.find(slotName); + if( slotIt == processor.fSlots.end() ) + { + BOOST_THROW_EXCEPTION( SlotException() << "Unable to connect signal <" + signalName + "> to slot <" + slotName + "> due to a problem with the slot." << + "You may have the slot name wrong." << eom ); + } + + try + { + // make the connection + ConnectSignalToSlot( signalIt->second, slotIt->second, groupNum ); + } + catch( SignalException& e ) + { + e << ErrorMsgInfo< struct proc_Sig_0 >( "Unable to connect signal <" + signalName + "> to slot <" + slotName + "> due to a problem with the signal." ); + e << ErrorMsgInfo< struct proc_Sig_1 >( "You may have the signal name wrong." ); + throw; + } + catch( SlotException& e ) + { + e << ErrorMsgInfo< struct proc_Slot_0 >( "Unable to connect signal <" + signalName + "> to slot <" + slotName + "> due to a problem with the slot." ); + e << ErrorMsgInfo< struct proc_Slot_1 >( "You may have the slot name wrong." ); + throw; + } + catch( ConnectionException& e ) + { + e << ErrorMsgInfo< struct proc_Conn_0 >( "Unable to connect signal <" + signalName + "> to slot <" + slotName + "> due to a problem making the connection." ); + e << ErrorMsgInfo< struct proc_Conn_1 >( "Check that the signatures of the signal and slot match exactly." ); + throw; + } + catch( boost::exception& e ) + { + e << ErrorMsgInfo< struct proc_Unkn >( "Unable to connect signal <" + signalName + "> to slot <" + slotName + "> for an unknown reason." ); + throw; + } + + LDEBUG(processorlog, "Connected signal <" << this->Name() << ":" << signalName << "> to slot <" << processor.Name() << ":" << slotName << ">"); + + return; + } + + void Processor::ConnectSignalToSlot( SignalPtr_t signal, SlotPtr_t slot, int groupNum ) + { + if( ! signal ) + { + BOOST_THROW_EXCEPTION( SignalException() << "Signal pointer was NULL" << eom ); + } + if( ! slot ) + { + BOOST_THROW_EXCEPTION( SlotException() << "Slot pointer was NULL" << eom ); + } + + signal->Connect(slot, groupNum); + + return; + } +/* + bool Processor::GetDoBreakpoint( const std::string& slotName ) + { + KTSlotBase* slot = GetSlot(slotName); + if (slot != nullptr) + { + return slot->GetDoBreakpoint(); + } + BOOST_THROW_EXCEPTION( KTException() << "Slot <" << slotName << "> was not found" << eom ); + return false; + } + + void Processor::SetDoBreakpoint( const std::string& slotName, bool flag ) + { + KTSlotBase* slot = GetSlot(slotName); + if (slot != nullptr) + { + return slot->SetDoBreakpoint(flag); + } + BOOST_THROW_EXCEPTION( KTException() << "Slot <" << slotName << "> was not found" << eom ); + return; + } +*/ +} /* namespace Nymph */ diff --git a/Library/Processor/Processor.hh b/Library/Processor/Processor.hh new file mode 100644 index 0000000..ab40742 --- /dev/null +++ b/Library/Processor/Processor.hh @@ -0,0 +1,115 @@ +/** + @file Processor.hh + @brief Base class for processors + @author: N. S. Oblath + @date: Jan 5, 2012 + */ + +#ifndef NYMPH_PROCESSOR_HH_ +#define NYMPH_PROCESSOR_HH_ + +#include "SignalSlotBase.hh" + +#include "Exception.hh" +#include "MemberVariable.hh" + +#include "factory.hh" +#include "logger.hh" +#include "param.hh" + +#include + +namespace Nymph +{ + LOGGER(processorlog, "Processor.hh"); + + struct ProcessorException : virtual public Exception {}; + + struct SignalException : virtual public Exception {}; + struct SlotException : virtual public Exception {}; + + struct ConnectionException : public Exception {}; + + class Processor + { + protected: + typedef std::map< std::string, SignalPtr_t > SignalMap; + typedef SignalMap::iterator SigMapIt; + typedef SignalMap::value_type SigMapVal; + + typedef std::map< std::string, SlotPtr_t > SlotMap; + typedef SlotMap::iterator SlotMapIt; + typedef SlotMap::value_type SlotMapVal; + + public: + Processor( const std::string& name ); + virtual ~Processor(); + + template< class XDerivedProc > + static scarab::registrar< Nymph::Processor, XDerivedProc, const std::string& >* RegisterProcessor( const std::string& name ); + + public: + /// Configure the processor with a param_node + virtual bool Configure( const scarab::param_node& node ) = 0; + + /// Utility function for connecting any signal to any slot + static void ConnectSignalToSlot( SignalPtr_t signal, SlotPtr_t slot, int groupNum=-1 ); + + /// Connect a signal in this processor to a slot in a different processor + void ConnectASlot( const std::string& signalName, Processor& processor, const std::string& slotName, int groupNum=-1 ); + /// Connect a signal in a different processor to a slot in this processor + void ConnectASignal( Processor& processor, const std::string& signalName, const std::string& slotName, int groupNum=-1 ); + + /// Register a signal object with this processor + void RegisterSignal( std::string name, SignalPtr_t signal ); + + /// Register a slot object with this processor + void RegisterSlot( std::string name, SlotPtr_t slot, std::initializer_list< std::string > signals = {} ); + + //bool GetDoBreakpoint( const std::string& slotName ); + //void SetDoBreakpoint( const std::string& slotName, bool flag ); + + MEMVAR_REF( std::string, Name ); + + MEMVAR_REF_CONST( SignalMap, Signals ); + MEMVAR_REF_CONST( SlotMap, Slots ); + + protected: + template< typename XReturn, typename... XArgs > + void PassToConnProcs( const std::string& slotName, std::function< XReturn(XArgs...) > function, XArgs... args ); + + }; + + + inline void Processor::RegisterSignal( std::string name, SignalPtr_t signal ) + { + LDEBUG( processorlog, "Registering signal <" << name << "> in processor <" << fName << ">" ); + fSignals.insert( SigMapVal(name, signal) ); + return; + } + + inline void Processor::RegisterSlot( std::string name, SlotPtr_t slot, std::initializer_list< std::string > signals ) + { + LDEBUG( processorlog, "Registering slot <" << name << "> in processor <" << fName << ">" ); + fSlots.insert( SlotMapVal(name, slot) ); + return; + } + + inline void Processor::ConnectASignal(Processor& processor, const std::string& signalName, const std::string& slotName, int groupNum ) + { + processor.ConnectASlot( signalName, *this, slotName, groupNum ); + return; + } + + template< class XDerivedProc > + scarab::registrar< Processor, XDerivedProc, const std::string& >* Processor::RegisterProcessor( const std::string& name ) + { + return new scarab::registrar< Processor, XDerivedProc, const std::string& >( name ); + } + +#define KT_REGISTER_PROCESSOR(proc_class, proc_name) \ + static ::scarab::registrar< ::Nymph::Processor, proc_class, const std::string& > sProc##proc_class##Registrar( proc_name ); + +} /* namespace Nymph */ + +#endif /* NYMPH_PROCESSOR_HH_ */ diff --git a/Library/Processor/Signal.hh b/Library/Processor/Signal.hh new file mode 100644 index 0000000..b583990 --- /dev/null +++ b/Library/Processor/Signal.hh @@ -0,0 +1,259 @@ +/* + * Signal.hh + * + * Created on: Jan 15, 2013 + * Author: N.S. Oblath + * + * Based on this implementation: https://schneegans.github.io/tutorials/2015/09/20/signal-slot + */ + +#ifndef NYMPH_SIGNAL_HH_ +#define NYMPH_SIGNAL_HH_ + +#include "SignalSlotBase.hh" + +#include "Exception.hh" +#include "Logger.hh" + +#include + +namespace Nymph +{ + LOGGER( signallog, "Signal" ); + + /// A Signal object may call multiple slots with the + /// same signature. You can connect functions to the Signal + /// that will be called when the emit() method on the + /// Signal object is invoked. Any argument passed to emit() + /// will be passed to the given functions. + template< typename... XArgs > + class Signal : public SignalBase + { + public: + using signature = void( XArgs... ); + + public: + Signal( const std::string& name ); + template< typename XOwner > + Signal( const std::string& name, XOwner* owner ); + Signal( const Signal& ) = delete; + Signal( Signal&& ) = delete; + virtual ~Signal(); + + virtual void Connect( SlotPtr_t slot, int group ); + + // disconnects a previously connected function + void Disconnect( SlotPtr_t slot ) const; + + // disconnects all previously connected functions + void DisconnectAll() const; + + // calls all connected functions + void Emit( XArgs... args ); + void operator()( XArgs... args ); + + typedef std::set< SlotPtr_t > slot_connections; // to get around the problem of having a comma inside a macro function argument + MEMVAR_REF_MUTABLE_CONST( slot_connections, Connections ); + + protected: + friend class Slot< XArgs... >; + void _Connect( SlotPtr_t slot, int group ); + }; + + + /*! + @class Signal + @author N. S. Oblath + + @brief Creates a signal that takes 0 or more arguments. + + @details + The signal is emitted by calling operator(). + If a Slot is being used, and the Slot has been given a pointer to this signal, the Slot will emit the Signal. + + Usage: + In your Processor's header add a member variable of type Signal< ArgumentTypes >. + + Initialize the signal with the processor's 'this' pointer and the name of the signal. + + To use the signal, call it as: fSignalObject(arg); + *//* + template< class... XSignalArguments > + class Signal + { + public: + typedef void (signature)( XSignalArguments... ); + typedef boost::signals2::signal< signature > boost_signal; + typedef typename boost::signals2::signal< signature >::slot_type slot_type; + + public: + Signal(); + Signal( const std::string& name, Processor* proc ); + virtual ~Signal(); + + protected: + Signal( const Signal& ); + + public: + void operator()( XSignalArguments... args ); + + boost_signal* Signal(); + + const std::string& GetName() const; + + protected: + boost_signal fSignal; + + std::string fName; + }; +*/ + + + //******************* + // Implementations + //******************* + + template< typename... XArgs > + Signal< XArgs... >::Signal( const std::string& name ) : + SignalBase( name ), + fConnections() + {} + + template< typename... XArgs > + template< typename XOwner > + Signal< XArgs... >::Signal< XOwner >( const std::string& name, XOwner* owner ) : + fSlots() + { + owner->RegisterSignal( name, this ); + } + + template< typename... XArgs > + Signal< XArgs... >::~Signal() + { + DisconnectAll(); + } + + template< typename... XArgs > + void Signal< XArgs... >::Connect( SlotPtr_t slot, int group ) + { + if( fSlots.count( slot ) != 0 ) + { + LWARN( signallog, "Signal <" << fName << "> is already connected to slot <" << slot->Name() << ">" ); + return; + } + + // ensure that the slot is of the correct type + if( ! std::dynamic_pointer_cast< Slot< XArgs... > >( slot ) ) + { + BOOST_THROW_EXCEPTION( ConnectionException() << "Trying to connect signal <" << fName << "> to slot <" << slot->Name() << ">, but cannot make the connection:\n" << + "\tUnable to cast from SlotBase to this signal's derived type.\n" << + "\tArgument types do not match" << eom ); + } +/* + Connection connection; + if( group >= 0 ) + { + connection = fInternalSignal.connect( group, derivedSlot->Function() ); + } + else + { + connection = fInternalSignal.connect( derivedSlot->Function() ); + } +*/ + _Connect( slot, group ); + slot->_AddConnection( this ); + + return; + } + + template< typename... XArgs > + void Signal< XArgs... >::_Connect( SlotPtr_t slot, int group ) + { + fConnections.insert( slot ); + return; + } + + // disconnects a previously connected function + template< typename... XArgs > + void Signal< XArgs... >::Disconnect( SlotPtr_t slot ) const + { + slot->RemoveConnection( this ); + return; + } + + // disconnects all previously connected functions + template< typename... XArgs > + void Signal< XArgs... >::DisconnectAll() const + { + for( auto connection : fSlots ) + { + connection->RemoveConnection( this ); + } + return; + } + + // calls all connected functions + template< typename... XArgs > + inline void Signal< XArgs... >::Emit( XArgs... args ) + { + (*this)( args ); + return; + } + + template< typename... XArgs > + inline void Signal< XArgs... >::operator()( XArgs... args ) + { + for( auto connection : fSlots ) + { + connection->Function( args ); + } + return; + } + +/* + template< class... XSignalArguments > + Signal< XSignalArguments... >::Signal( const std::string& name, Processor* proc ) : + fSignal(), + fName( name ) + { + proc->RegisterSignal(name, &fSignal); + } + + template< class... XSignalArguments > + Signal< XSignalArguments... >::Signal() : + fSignal(), + fName("none") + {} + + template< class... XSignalArguments > + Signal< XSignalArguments... >::Signal( const Signal& signal ) : + fSignal(), + fName( signal.fName ) + {} + + template< class... XSignalArguments > + Signal< XSignalArguments... >::~Signal() + { + } + + template< class... XSignalArguments > + inline void Signal< XSignalArguments... >::operator()( XSignalArguments... args ) + { + fSignal( args... ); + } + + template< class... XSignalArguments > + inline typename Signal< XSignalArguments... >::boost_signal* Signal< XSignalArguments... >::Signal() + { + return &fSignal; + } + + template< class... XSignalArguments > + inline const std::string& Signal< XSignalArguments... >::GetName() const + { + return fName; + } +*/ +} /* namespace Nymph */ + +#endif /* NYMPH_SIGNAL_HH_ */ diff --git a/Library/Processor/SignalSlotBase.cc b/Library/Processor/SignalSlotBase.cc new file mode 100644 index 0000000..bdc9afe --- /dev/null +++ b/Library/Processor/SignalSlotBase.cc @@ -0,0 +1,26 @@ +/* + * SignalSlotBase.cc + * + * Created on: Sept 7, 2019 + * Author: N.S. Oblath + */ + +#include "SignalSlotBase.hh" + +namespace Nymph +{ + SlotBase::SlotBase( const std::string& name ) : + fName( name ) + {} + + SlotBase::~SlotBase() + {} + + SignalBase::SignalBase( const std::string& name ) : + fName( name ) + {} + + SignalBase::~SignalBase() + {} + +} diff --git a/Library/Processor/SignalSlotBase.hh b/Library/Processor/SignalSlotBase.hh new file mode 100644 index 0000000..d8b1e69 --- /dev/null +++ b/Library/Processor/SignalSlotBase.hh @@ -0,0 +1,57 @@ +/* + * SignalSlotBase.hh + * + * Created on: Feb 25, 2019 + * Author: N.S. Oblath + */ + +#ifndef NYMPH_SIGNALSLOTBASE_HH_ +#define NYMPH_SIGNALSLOTBASE_HH_ + +#include "MemberVariable.hh" + +#include +#include + +namespace Nymph +{ + class SignalBase; + class SlotBase; + + typedef std::shared_ptr< SignalBase > SignalPtr_t; + typedef std::shared_ptr< SlotBase > SlotPtr_t; + + class SlotBase + { + public: + SlotBase( const std::string& name ); + //template< typename XOwner > + //SlotBase( const std::string& name, XOwner* owner ); + virtual ~SlotBase(); + + virtual void AddConnection( SignalPtr_t ) const = 0; + + virtual void RemoveConnection( SignalPtr_t ) const = 0; + + MEMVAR_REF( std::string, Name ); + }; + + + class SignalBase + { + public: + SignalBase( const std::string& name ); + //template< typename XOwner > + //SignalBase( const std::string& name, XOwner* owner ); + virtual ~SignalBase(); + + virtual void Connect( SlotPtr_t slot, int group ) = 0; + + virtual void Disconnect( SlotPtr_t slot ) const = 0; + + MEMVAR_REF( std::string, Name ); + }; + +} /* namespace Nymph */ + +#endif /* NYMPH_SIGNALSLOTBASE_HH_ */ diff --git a/Library/Processor/Slot.hh b/Library/Processor/Slot.hh new file mode 100644 index 0000000..9f2c37b --- /dev/null +++ b/Library/Processor/Slot.hh @@ -0,0 +1,229 @@ +/* + * Slot.hh + * + * Created on: Jan 13, 2013 + * Author: N.S. Oblath + * + * Based on this implementation: https://schneegans.github.io/tutorials/2015/09/20/signal-slot + */ + +#ifndef NYMPH_SLOT_HH_ +#define NYMPH_SLOT_HH_ + +#include "SignalSlotBase.hh" + +//#include "Exception.hh" +//#include "ThreadReference.hh" + +#include "Logger.hh" + +#include +#include + +namespace Nymph +{ + LOGGER(slotlog, "Slot"); + + + // Type XOwner is the class that owns the Slot object + template< typename... XArgs > + class Slot : public SlotBase + { + public: + using signature = void( XArgs... ); + using signal_list = std::initializer_list< std::string >; + + public: + template< typename XOwner > + Slot( const std::string& name, XOwner* owner, void (XOwner::*func)( XArgs... ), signal_list signals = {} ); + template< typename XOwner > + Slot( const std::string& name, XOwner* owner, void (XOwner::*func)( XArgs... ) const, signal_list signals = {} ); + template< typename XOwner > + Slot( const std::string& name, XOwner* owner, const boost::function< signature >& func, signal_list signals = {} ); + template< typename XOwner, typename XFuncClass > + Slot( const std::string& name, XOwner* owner, XFuncClass *inst, void (XFuncClass::*func)( XArgs... ), signal_list signals = {} ); + template< typename XOwner, typename XFuncClass > + Slot( const std::string& name, XOwner* owner, XFuncClass *inst, void (XFuncClass::*func)( XArgs... ) const, signal_list signals = {} ); + Slot( const Slot& ) = delete; + Slot( Slot&& ) = delete; + virtual ~Slot(); + + void DisconnectAll() const; + + void AddConnection( SignalPtr_t ) const; + + void RemoveConnection( SignalPtr_t ) const; + + MEMVAR_REF( boost::function< signature >, Function ); + + typedef std::set< SignalBase* > signal_connections; // to get around the problem of having a comma inside a macro function argument + MEMVAR_REF_MUTABLE( signal_connections, Connections ); + + MEMVAR( bool, DoBreakpoint ); + + protected: + friend class Signal< XArgs... >; + void _AddConnection( Signal_ptr_t ) const; + + }; + + + /*! + @class Slot + @author N. S. Oblath + + @brief Creates a slot that calls a member function of the func_owner_type object, taking 0 or more arguments. + + @details + Usage: + To use this slot type the function to be called by the slot must exist in an object of type FuncOwnerType. + The function should have the signature void (Args). + + In your Processor's header add a member variable of type Slot< ProcessorType, ReturnType, Args >. + The variable may be private. + + Initialize the slot with the name of the slot, the address of the owner of the slot function, and the function pointer. + Optionally, if the Processor is separate from the owner of the slot function, the Processor address is specified as the second argument to the constructor. + *//* + template< typename... Args > + class Slot + { + public: + /// Constructor for the case where the processor has the function that will be called by the slot + template< class XFuncOwnerType > + Slot( const std::string& name, XFuncOwnerType* owner, void (XFuncOwnerType::*func)( Args... ), std::initializer_list< std::string > signals = {} ); + + /// Constructor for the case where the processor and the object with the function that will be called are different + template< class XFuncOwnerType > + Slot( const std::string& name, Processor* proc, XFuncOwnerType* owner, void (XFuncOwnerType::*func)( Args... ), std::initializer_list< std::string > signals = {} ); + + virtual ~Slot(); + + const std::string& GetName() const; + + SlotWrapper* GetSlotWrapper(); + + protected: + std::string fName; + SlotWrapper* fSlotWrapper; + }; +*/ + + + //******************* + // Implementations + //******************* + + // Slot + + template< typename... XArgs > + template< typename XOwner > + Slot< XArgs... >::Slot< XOwner >( const std::string& name, XOwner* owner, void (XOwner::*func)( XArgs... ), signal_list signals ) : + fFunction( [func, owner]( XArgs... args ){ return (owner->*func)(args...);} ), + fConnections(), + fThreadRef( std::make_shared< ThreadReference >() ), + fDoBreakpoint(false) + { + owner->RegisterSlot( name, this, signals ); + } + + template< typename... XArgs > + template< typename XOwner > + Slot< XArgs... >::Slot< XOwner >( const std::string& name, XOwner* owner, void (XOwner::*func)( XArgs... ) const, signal_list signals ) : + fFunction( [func, owner]( XArgs... args ){ return (owner->*func)(args...);} ), + fConnections(), + fThreadRef( std::make_shared< ThreadReference >() ), + fDoBreakpoint(false) + { + owner->RegisterSlot( name, this, signals ); + } + + template< typename... XArgs > + template< typename XOwner > + Slot< XArgs... >::Slot< XOwner >( const std::string& name, XOwner* owner, const boost::function< signature >& func, signal_list signals ) : + fFunction( func ), + fConnections(), + fThreadRef( std::make_shared< ThreadReference >() ), + fDoBreakpoint(false) + { + owner->RegisterSlot( name, this, signals ); + } + + template< typename... XArgs > + template< typename XOwner, typename XFuncClass > + Slot< XArgs... >::Slot< XOwner, XFuncClass >( const std::string& name, XOwner* owner, XFuncClass *inst, void (XFuncClass::*func)( XArgs... ), signal_list signals ) : + fFunction( [func, inst]( XArgs... args ){ return (inst->*func)(args...);} ), + fConnections(), + fThreadRef( std::make_shared< ThreadReference >() ), + fDoBreakpoint(false) + { + owner->RegisterSlot( name, this, signals ); + } + + template< typename... XArgs > + template< typename XOwner, typename XFuncClass > + Slot< XArgs... >::Slot< XOwner, XFuncClass >( const std::string& name, XOwner* owner, XFuncClass *inst, void (XFuncClass::*func)( XArgs... ) const, signal_list signals ) : + fFunction( [func, inst]( XArgs... args ){ return (inst->*func)(args...);} ), + fConnections(), + fThreadRef( std::make_shared< ThreadReference >() ), + fDoBreakpoint(false) + { + owner->RegisterSlot( name, this, signals ); + } + + template< typename... XArgs > + Slot< XArgs... >::~Slot() + { + DisconnectAll(); + } + + template< typename... XArgs > + void Slot< XArgs... >::DisconnectAll() const + { + for( auto connection : fConnections ) + { + connection->Disconnect( this ); + } + return; + } + + template< typename... XArgs > + void Slot< XArgs... >::AddConnection( SignalPtr_t signal ) const + { + if( fConnections.count( signal ) != 0 ) + { + LWARN( signallog, "Slot <" << fName << "> is already has connection to signal <" << signal->Name() << ">" ); + return; + } + + // ensure that the slot is of the correct type + if( ! std::dynamic_pointer_cast< Signal< XArgs... > >( signal ) ) + { + BOOST_THROW_EXCEPTION( ConnectionException() << "Trying to connect slot <" << fName << "> to signal <" << signal->Name() << ">, but cannot make the connection:\n" << + "\tUnable to cast from SignalBase to this slot's derived type.\n" << + "\tArgument types do not match" << eom ); + } + + _AddConnection( signal, group ); + signal->_Connect( this, group ); + + return; + } + + template< typename... XArgs > + void Slot< XArgs... >::_AddConnection( SignalPtr_t signal ) const + { + fConnections.insert( signal ); + return; + } + + template< typename... XArgs > + void Slot< XArgs... >::RemoveConnection( SignalPtr_t signal ) const + { + fConnections.erase( signal ); + return; + } + +} /* namespace Nymph */ + +#endif /* NYMPH_SLOT_HH_ */ From f0190bb8fe26f0c76bd89cd7002e4db26bd969fb Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Tue, 10 Sep 2019 08:48:50 -0700 Subject: [PATCH 140/521] Progress --- CMakeLists.txt | 2 +- Library/Processor/Processor.hh | 8 ----- Library/Processor/Signal.hh | 33 +++++++++++------- Library/Processor/SignalSlotBase.hh | 19 +++++++++-- Library/Processor/Slot.hh | 53 +++++++++++++++++++++-------- Testing/CMakeLists.txt | 2 +- Testing/TestSignalSlot.cc | 37 ++++++++++++++++++++ 7 files changed, 113 insertions(+), 41 deletions(-) create mode 100644 Testing/TestSignalSlot.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index 03dee56..8ac8bf3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -121,7 +121,7 @@ include_directories (BEFORE add_subdirectory( Library ) if (Nymph_ENABLE_EXECUTABLES) - add_subdirectory( Executables/Validation ) + #add_subdirectory( Executables/Validation ) endif (Nymph_ENABLE_EXECUTABLES) diff --git a/Library/Processor/Processor.hh b/Library/Processor/Processor.hh index ab40742..6efb137 100644 --- a/Library/Processor/Processor.hh +++ b/Library/Processor/Processor.hh @@ -10,9 +10,6 @@ #include "SignalSlotBase.hh" -#include "Exception.hh" -#include "MemberVariable.hh" - #include "factory.hh" #include "logger.hh" #include "param.hh" @@ -25,11 +22,6 @@ namespace Nymph struct ProcessorException : virtual public Exception {}; - struct SignalException : virtual public Exception {}; - struct SlotException : virtual public Exception {}; - - struct ConnectionException : public Exception {}; - class Processor { protected: diff --git a/Library/Processor/Signal.hh b/Library/Processor/Signal.hh index b583990..d448927 100644 --- a/Library/Processor/Signal.hh +++ b/Library/Processor/Signal.hh @@ -13,14 +13,18 @@ #include "SignalSlotBase.hh" #include "Exception.hh" -#include "Logger.hh" -#include +#include "logger.hh" + +#include namespace Nymph { LOGGER( signallog, "Signal" ); + template< typename... XArgs > + class Slot; + /// A Signal object may call multiple slots with the /// same signature. You can connect functions to the Signal /// that will be called when the emit() method on the @@ -33,14 +37,16 @@ namespace Nymph using signature = void( XArgs... ); public: + /// Unowned signal Signal( const std::string& name ); + /// Owned signal template< typename XOwner > Signal( const std::string& name, XOwner* owner ); Signal( const Signal& ) = delete; Signal( Signal&& ) = delete; virtual ~Signal(); - virtual void Connect( SlotPtr_t slot, int group ); + virtual void Connect( SlotPtr_t slot, int group = -1 ); // disconnects a previously connected function void Disconnect( SlotPtr_t slot ) const; @@ -57,7 +63,7 @@ namespace Nymph protected: friend class Slot< XArgs... >; - void _Connect( SlotPtr_t slot, int group ); + virtual void _Connect( SlotPtr_t slot, int group ); }; @@ -121,8 +127,9 @@ namespace Nymph template< typename... XArgs > template< typename XOwner > - Signal< XArgs... >::Signal< XOwner >( const std::string& name, XOwner* owner ) : - fSlots() + inline Signal< XArgs... >::Signal( const std::string& name, XOwner* owner ) : + SignalBase( name ), + fConnections() { owner->RegisterSignal( name, this ); } @@ -136,7 +143,7 @@ namespace Nymph template< typename... XArgs > void Signal< XArgs... >::Connect( SlotPtr_t slot, int group ) { - if( fSlots.count( slot ) != 0 ) + if( fConnections.count( slot ) != 0 ) { LWARN( signallog, "Signal <" << fName << "> is already connected to slot <" << slot->Name() << ">" ); return; @@ -167,7 +174,7 @@ namespace Nymph } template< typename... XArgs > - void Signal< XArgs... >::_Connect( SlotPtr_t slot, int group ) + inline void Signal< XArgs... >::_Connect( SlotPtr_t slot, int group ) { fConnections.insert( slot ); return; @@ -175,7 +182,7 @@ namespace Nymph // disconnects a previously connected function template< typename... XArgs > - void Signal< XArgs... >::Disconnect( SlotPtr_t slot ) const + inline void Signal< XArgs... >::Disconnect( SlotPtr_t slot ) const { slot->RemoveConnection( this ); return; @@ -185,7 +192,7 @@ namespace Nymph template< typename... XArgs > void Signal< XArgs... >::DisconnectAll() const { - for( auto connection : fSlots ) + for( auto connection : fConnections ) { connection->RemoveConnection( this ); } @@ -196,16 +203,16 @@ namespace Nymph template< typename... XArgs > inline void Signal< XArgs... >::Emit( XArgs... args ) { - (*this)( args ); + (*this)( args... ); return; } template< typename... XArgs > inline void Signal< XArgs... >::operator()( XArgs... args ) { - for( auto connection : fSlots ) + for( auto connection : fConnections ) { - connection->Function( args ); + connection->Function( args... ); } return; } diff --git a/Library/Processor/SignalSlotBase.hh b/Library/Processor/SignalSlotBase.hh index d8b1e69..3766c66 100644 --- a/Library/Processor/SignalSlotBase.hh +++ b/Library/Processor/SignalSlotBase.hh @@ -8,6 +8,7 @@ #ifndef NYMPH_SIGNALSLOTBASE_HH_ #define NYMPH_SIGNALSLOTBASE_HH_ +#include "Exception.hh" #include "MemberVariable.hh" #include @@ -15,6 +16,12 @@ namespace Nymph { + struct SignalException : virtual public Exception {}; + struct SlotException : virtual public Exception {}; + + struct ConnectionException : public Exception {}; + + class SignalBase; class SlotBase; @@ -29,11 +36,14 @@ namespace Nymph //SlotBase( const std::string& name, XOwner* owner ); virtual ~SlotBase(); - virtual void AddConnection( SignalPtr_t ) const = 0; + virtual void AddConnection( SignalPtr_t signal, int group = -1 ) const = 0; - virtual void RemoveConnection( SignalPtr_t ) const = 0; + virtual void RemoveConnection( SignalPtr_t signal) const = 0; MEMVAR_REF( std::string, Name ); + + protected: + virtual void _AddConnection( SignalPtr_t signal, int group ) const = 0; }; @@ -45,11 +55,14 @@ namespace Nymph //SignalBase( const std::string& name, XOwner* owner ); virtual ~SignalBase(); - virtual void Connect( SlotPtr_t slot, int group ) = 0; + virtual void Connect( SlotPtr_t slot, int group = -1 ) = 0; virtual void Disconnect( SlotPtr_t slot ) const = 0; MEMVAR_REF( std::string, Name ); + + protected: + virtual void _Connect( SlotPtr_t slot, int group ) = 0; }; } /* namespace Nymph */ diff --git a/Library/Processor/Slot.hh b/Library/Processor/Slot.hh index 9f2c37b..7d74e0f 100644 --- a/Library/Processor/Slot.hh +++ b/Library/Processor/Slot.hh @@ -15,7 +15,9 @@ //#include "Exception.hh" //#include "ThreadReference.hh" -#include "Logger.hh" +#include "logger.hh" + +#include #include #include @@ -34,14 +36,21 @@ namespace Nymph using signal_list = std::initializer_list< std::string >; public: + /// Unowned slot + Slot( const std::string& name, const boost::function< signature >& func, signal_list signals = {} ); + /// Owned slot, non-const member function template< typename XOwner > Slot( const std::string& name, XOwner* owner, void (XOwner::*func)( XArgs... ), signal_list signals = {} ); + /// Owned slot, const member function template< typename XOwner > Slot( const std::string& name, XOwner* owner, void (XOwner::*func)( XArgs... ) const, signal_list signals = {} ); + /// Owned slot, generic function template< typename XOwner > Slot( const std::string& name, XOwner* owner, const boost::function< signature >& func, signal_list signals = {} ); + /// Owned slot, non-const member fuction of another class template< typename XOwner, typename XFuncClass > Slot( const std::string& name, XOwner* owner, XFuncClass *inst, void (XFuncClass::*func)( XArgs... ), signal_list signals = {} ); + /// Owned slot, const member fuction of another class template< typename XOwner, typename XFuncClass > Slot( const std::string& name, XOwner* owner, XFuncClass *inst, void (XFuncClass::*func)( XArgs... ) const, signal_list signals = {} ); Slot( const Slot& ) = delete; @@ -50,9 +59,9 @@ namespace Nymph void DisconnectAll() const; - void AddConnection( SignalPtr_t ) const; + void AddConnection( SignalPtr_t signal, int group = -1 ) const; - void RemoveConnection( SignalPtr_t ) const; + void RemoveConnection( SignalPtr_t signal ) const; MEMVAR_REF( boost::function< signature >, Function ); @@ -63,7 +72,7 @@ namespace Nymph protected: friend class Signal< XArgs... >; - void _AddConnection( Signal_ptr_t ) const; + virtual void _AddConnection( SignalPtr_t, int group ) const; }; @@ -116,12 +125,22 @@ namespace Nymph // Slot + template< typename... XArgs > + Slot< XArgs... >::Slot( const std::string& name, const boost::function< signature >& func, signal_list signals ) : + SlotBase( name ), + fFunction( func ), + fConnections(), + //fThreadRef( std::make_shared< ThreadReference >() ), + fDoBreakpoint( false ) + {} + template< typename... XArgs > template< typename XOwner > - Slot< XArgs... >::Slot< XOwner >( const std::string& name, XOwner* owner, void (XOwner::*func)( XArgs... ), signal_list signals ) : + Slot< XArgs... >::Slot( const std::string& name, XOwner* owner, void (XOwner::*func)( XArgs... ), signal_list signals ) : + SlotBase( name ), fFunction( [func, owner]( XArgs... args ){ return (owner->*func)(args...);} ), fConnections(), - fThreadRef( std::make_shared< ThreadReference >() ), + //fThreadRef( std::make_shared< ThreadReference >() ), fDoBreakpoint(false) { owner->RegisterSlot( name, this, signals ); @@ -129,10 +148,11 @@ namespace Nymph template< typename... XArgs > template< typename XOwner > - Slot< XArgs... >::Slot< XOwner >( const std::string& name, XOwner* owner, void (XOwner::*func)( XArgs... ) const, signal_list signals ) : + Slot< XArgs... >::Slot( const std::string& name, XOwner* owner, void (XOwner::*func)( XArgs... ) const, signal_list signals ) : + SlotBase( name ), fFunction( [func, owner]( XArgs... args ){ return (owner->*func)(args...);} ), fConnections(), - fThreadRef( std::make_shared< ThreadReference >() ), + //fThreadRef( std::make_shared< ThreadReference >() ), fDoBreakpoint(false) { owner->RegisterSlot( name, this, signals ); @@ -140,10 +160,11 @@ namespace Nymph template< typename... XArgs > template< typename XOwner > - Slot< XArgs... >::Slot< XOwner >( const std::string& name, XOwner* owner, const boost::function< signature >& func, signal_list signals ) : + Slot< XArgs... >::Slot( const std::string& name, XOwner* owner, const boost::function< signature >& func, signal_list signals ) : + SlotBase( name ), fFunction( func ), fConnections(), - fThreadRef( std::make_shared< ThreadReference >() ), + //fThreadRef( std::make_shared< ThreadReference >() ), fDoBreakpoint(false) { owner->RegisterSlot( name, this, signals ); @@ -151,10 +172,11 @@ namespace Nymph template< typename... XArgs > template< typename XOwner, typename XFuncClass > - Slot< XArgs... >::Slot< XOwner, XFuncClass >( const std::string& name, XOwner* owner, XFuncClass *inst, void (XFuncClass::*func)( XArgs... ), signal_list signals ) : + Slot< XArgs... >::Slot( const std::string& name, XOwner* owner, XFuncClass *inst, void (XFuncClass::*func)( XArgs... ), signal_list signals ) : + SlotBase( name ), fFunction( [func, inst]( XArgs... args ){ return (inst->*func)(args...);} ), fConnections(), - fThreadRef( std::make_shared< ThreadReference >() ), + //fThreadRef( std::make_shared< ThreadReference >() ), fDoBreakpoint(false) { owner->RegisterSlot( name, this, signals ); @@ -162,10 +184,11 @@ namespace Nymph template< typename... XArgs > template< typename XOwner, typename XFuncClass > - Slot< XArgs... >::Slot< XOwner, XFuncClass >( const std::string& name, XOwner* owner, XFuncClass *inst, void (XFuncClass::*func)( XArgs... ) const, signal_list signals ) : + Slot< XArgs... >::Slot( const std::string& name, XOwner* owner, XFuncClass *inst, void (XFuncClass::*func)( XArgs... ) const, signal_list signals ) : + SlotBase( name ), fFunction( [func, inst]( XArgs... args ){ return (inst->*func)(args...);} ), fConnections(), - fThreadRef( std::make_shared< ThreadReference >() ), + //fThreadRef( std::make_shared< ThreadReference >() ), fDoBreakpoint(false) { owner->RegisterSlot( name, this, signals ); @@ -188,7 +211,7 @@ namespace Nymph } template< typename... XArgs > - void Slot< XArgs... >::AddConnection( SignalPtr_t signal ) const + void Slot< XArgs... >::AddConnection( SignalPtr_t signal, int group ) const { if( fConnections.count( signal ) != 0 ) { diff --git a/Testing/CMakeLists.txt b/Testing/CMakeLists.txt index 1daaf14..be65fc3 100644 --- a/Testing/CMakeLists.txt +++ b/Testing/CMakeLists.txt @@ -8,7 +8,7 @@ set( testing_HEADERS ) set( testing_SOURCES - TestExt.cc + TestSignalSlot.cc UseCatch.cc ) diff --git a/Testing/TestSignalSlot.cc b/Testing/TestSignalSlot.cc new file mode 100644 index 0000000..8b18fa0 --- /dev/null +++ b/Testing/TestSignalSlot.cc @@ -0,0 +1,37 @@ +/* + * TestSigSlot.cc + * + * Created on: Sept 7, 2019 + * Author: N.S. Oblath + */ + +#include "Signal.hh" +#include "Slot.hh" + +#include "catch.hpp" + + +TEST_CASE( "signal_slot", "[signal],[slot],[processor]" ) +{ + using namespace Nymph; + + int testValue = 0; + + SignalPtr_t signalPtr = std::make_shared< Signal< int > >( "signal" ); + SlotPtr_t slotPtr = std::make_shared< Slot< int > >( "slot", [&](int aValue ){ testValue = aValue; } ); + + REQUIRE( signalPtr ); + REQUIRE( slotPtr ); + + signalPtr->Connect( slotPtr ); + + //REQUIRE( signalPtr->Connections().size() == 1 ); + //REQUIRE( slotPtr->Connections().size() == 1 ); + + std::dynamic_pointer_cast< Signal< int > >(signalPtr)->Emit( 5 ); + REQUIRE( testValue == 5 ); + + std::dynamic_pointer_cast< Signal< int > >(signalPtr)->operator()( 10 ); + REQUIRE( testValue == 10 ); + +} From dd0b85f764f5dc2ad1e6938c767c6ff11b019811 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Tue, 10 Sep 2019 22:54:57 -0700 Subject: [PATCH 141/521] Working version of new signals and slots --- Library/Processor/Signal.hh | 51 +++----------------------- Library/Processor/SignalSlotBase.cc | 29 +++++++++++++-- Library/Processor/SignalSlotBase.hh | 52 +++++++++++++++++++++++---- Library/Processor/Slot.hh | 56 ++++------------------------- 4 files changed, 82 insertions(+), 106 deletions(-) diff --git a/Library/Processor/Signal.hh b/Library/Processor/Signal.hh index d448927..ebfc7a2 100644 --- a/Library/Processor/Signal.hh +++ b/Library/Processor/Signal.hh @@ -16,7 +16,6 @@ #include "logger.hh" -#include namespace Nymph { @@ -48,22 +47,9 @@ namespace Nymph virtual void Connect( SlotPtr_t slot, int group = -1 ); - // disconnects a previously connected function - void Disconnect( SlotPtr_t slot ) const; - - // disconnects all previously connected functions - void DisconnectAll() const; - // calls all connected functions void Emit( XArgs... args ); void operator()( XArgs... args ); - - typedef std::set< SlotPtr_t > slot_connections; // to get around the problem of having a comma inside a macro function argument - MEMVAR_REF_MUTABLE_CONST( slot_connections, Connections ); - - protected: - friend class Slot< XArgs... >; - virtual void _Connect( SlotPtr_t slot, int group ); }; @@ -121,15 +107,13 @@ namespace Nymph template< typename... XArgs > Signal< XArgs... >::Signal( const std::string& name ) : - SignalBase( name ), - fConnections() + SignalBase( name ) {} template< typename... XArgs > template< typename XOwner > inline Signal< XArgs... >::Signal( const std::string& name, XOwner* owner ) : - SignalBase( name ), - fConnections() + SignalBase( name ) { owner->RegisterSignal( name, this ); } @@ -167,35 +151,8 @@ namespace Nymph connection = fInternalSignal.connect( derivedSlot->Function() ); } */ - _Connect( slot, group ); - slot->_AddConnection( this ); - - return; - } + AddConnection( slot, group ); - template< typename... XArgs > - inline void Signal< XArgs... >::_Connect( SlotPtr_t slot, int group ) - { - fConnections.insert( slot ); - return; - } - - // disconnects a previously connected function - template< typename... XArgs > - inline void Signal< XArgs... >::Disconnect( SlotPtr_t slot ) const - { - slot->RemoveConnection( this ); - return; - } - - // disconnects all previously connected functions - template< typename... XArgs > - void Signal< XArgs... >::DisconnectAll() const - { - for( auto connection : fConnections ) - { - connection->RemoveConnection( this ); - } return; } @@ -212,7 +169,7 @@ namespace Nymph { for( auto connection : fConnections ) { - connection->Function( args... ); + std::static_pointer_cast< Slot< XArgs... > >(connection)->Function()( args... ); } return; } diff --git a/Library/Processor/SignalSlotBase.cc b/Library/Processor/SignalSlotBase.cc index bdc9afe..cf6588d 100644 --- a/Library/Processor/SignalSlotBase.cc +++ b/Library/Processor/SignalSlotBase.cc @@ -9,18 +9,41 @@ namespace Nymph { - SlotBase::SlotBase( const std::string& name ) : - fName( name ) + SlotBase::SlotBase( const std::string& name ) : + fName( name ), + fConnections() {} SlotBase::~SlotBase() {} + void SlotBase::DisconnectAll() + { + for( auto connection : fConnections ) + { + connection->Disconnect( shared_from_this() ); + } + return; + } + SignalBase::SignalBase( const std::string& name ) : - fName( name ) + fName( name ), + fConnections() {} SignalBase::~SignalBase() {} + // disconnects all previously connected functions + void SignalBase::DisconnectAll() + { + for( auto connection : fConnections ) + { + Disconnect( connection ); + } + return; + } + + } + diff --git a/Library/Processor/SignalSlotBase.hh b/Library/Processor/SignalSlotBase.hh index 3766c66..cdeaaa5 100644 --- a/Library/Processor/SignalSlotBase.hh +++ b/Library/Processor/SignalSlotBase.hh @@ -12,6 +12,7 @@ #include "MemberVariable.hh" #include +#include #include namespace Nymph @@ -28,7 +29,7 @@ namespace Nymph typedef std::shared_ptr< SignalBase > SignalPtr_t; typedef std::shared_ptr< SlotBase > SlotPtr_t; - class SlotBase + class SlotBase : public std::enable_shared_from_this< SlotBase > { public: SlotBase( const std::string& name ); @@ -36,18 +37,23 @@ namespace Nymph //SlotBase( const std::string& name, XOwner* owner ); virtual ~SlotBase(); - virtual void AddConnection( SignalPtr_t signal, int group = -1 ) const = 0; + virtual void ConnectTo( SignalPtr_t signal, int group = -1 ) = 0; - virtual void RemoveConnection( SignalPtr_t signal) const = 0; + void Disconnect( SignalPtr_t signal); + void DisconnectAll(); MEMVAR_REF( std::string, Name ); + typedef std::set< SignalPtr_t > signal_connections; // to get around the problem of having a comma inside a macro function argument + MEMVAR_REF_MUTABLE( signal_connections, Connections ); + protected: - virtual void _AddConnection( SignalPtr_t signal, int group ) const = 0; + friend class SignalBase; + virtual void AddConnection( SignalPtr_t signal ); }; - class SignalBase + class SignalBase : public std::enable_shared_from_this< SignalBase > { public: SignalBase( const std::string& name ); @@ -57,14 +63,46 @@ namespace Nymph virtual void Connect( SlotPtr_t slot, int group = -1 ) = 0; - virtual void Disconnect( SlotPtr_t slot ) const = 0; + void Disconnect( const SlotPtr_t slot ); + void DisconnectAll(); MEMVAR_REF( std::string, Name ); + typedef std::set< SlotPtr_t > slot_connections; // to get around the problem of having a comma inside a macro function argument + MEMVAR_REF_MUTABLE_CONST( slot_connections, Connections ); + protected: - virtual void _Connect( SlotPtr_t slot, int group ) = 0; + friend class SignalBase; + virtual void AddConnection( SlotPtr_t slot, int group ); }; + inline void SlotBase::AddConnection( SignalPtr_t signal ) + { + fConnections.insert( signal ); + return; + } + + inline void SlotBase::Disconnect( SignalPtr_t signal ) + { + signal->Disconnect( shared_from_this() ); + return; + } + + inline void SignalBase::AddConnection( SlotPtr_t slot, int group ) + { + fConnections.insert( slot ); + slot->AddConnection( shared_from_this() ); + return; + } + + // disconnects a previously connected function + inline void SignalBase::Disconnect( SlotPtr_t slot ) + { + slot->fConnections.erase( shared_from_this() ); + fConnections.erase( slot ); + return; + } + } /* namespace Nymph */ #endif /* NYMPH_SIGNALSLOTBASE_HH_ */ diff --git a/Library/Processor/Slot.hh b/Library/Processor/Slot.hh index 7d74e0f..72d4acb 100644 --- a/Library/Processor/Slot.hh +++ b/Library/Processor/Slot.hh @@ -20,7 +20,6 @@ #include #include -#include namespace Nymph { @@ -57,23 +56,14 @@ namespace Nymph Slot( Slot&& ) = delete; virtual ~Slot(); - void DisconnectAll() const; + void ConnectTo( SignalPtr_t signal, int group = -1 ); - void AddConnection( SignalPtr_t signal, int group = -1 ) const; - - void RemoveConnection( SignalPtr_t signal ) const; + // execute fFunction + void operator()( XArgs... args ); MEMVAR_REF( boost::function< signature >, Function ); - typedef std::set< SignalBase* > signal_connections; // to get around the problem of having a comma inside a macro function argument - MEMVAR_REF_MUTABLE( signal_connections, Connections ); - MEMVAR( bool, DoBreakpoint ); - - protected: - friend class Signal< XArgs... >; - virtual void _AddConnection( SignalPtr_t, int group ) const; - }; @@ -129,7 +119,6 @@ namespace Nymph Slot< XArgs... >::Slot( const std::string& name, const boost::function< signature >& func, signal_list signals ) : SlotBase( name ), fFunction( func ), - fConnections(), //fThreadRef( std::make_shared< ThreadReference >() ), fDoBreakpoint( false ) {} @@ -139,7 +128,6 @@ namespace Nymph Slot< XArgs... >::Slot( const std::string& name, XOwner* owner, void (XOwner::*func)( XArgs... ), signal_list signals ) : SlotBase( name ), fFunction( [func, owner]( XArgs... args ){ return (owner->*func)(args...);} ), - fConnections(), //fThreadRef( std::make_shared< ThreadReference >() ), fDoBreakpoint(false) { @@ -151,7 +139,6 @@ namespace Nymph Slot< XArgs... >::Slot( const std::string& name, XOwner* owner, void (XOwner::*func)( XArgs... ) const, signal_list signals ) : SlotBase( name ), fFunction( [func, owner]( XArgs... args ){ return (owner->*func)(args...);} ), - fConnections(), //fThreadRef( std::make_shared< ThreadReference >() ), fDoBreakpoint(false) { @@ -163,7 +150,6 @@ namespace Nymph Slot< XArgs... >::Slot( const std::string& name, XOwner* owner, const boost::function< signature >& func, signal_list signals ) : SlotBase( name ), fFunction( func ), - fConnections(), //fThreadRef( std::make_shared< ThreadReference >() ), fDoBreakpoint(false) { @@ -175,7 +161,6 @@ namespace Nymph Slot< XArgs... >::Slot( const std::string& name, XOwner* owner, XFuncClass *inst, void (XFuncClass::*func)( XArgs... ), signal_list signals ) : SlotBase( name ), fFunction( [func, inst]( XArgs... args ){ return (inst->*func)(args...);} ), - fConnections(), //fThreadRef( std::make_shared< ThreadReference >() ), fDoBreakpoint(false) { @@ -187,7 +172,6 @@ namespace Nymph Slot< XArgs... >::Slot( const std::string& name, XOwner* owner, XFuncClass *inst, void (XFuncClass::*func)( XArgs... ) const, signal_list signals ) : SlotBase( name ), fFunction( [func, inst]( XArgs... args ){ return (inst->*func)(args...);} ), - fConnections(), //fThreadRef( std::make_shared< ThreadReference >() ), fDoBreakpoint(false) { @@ -201,17 +185,7 @@ namespace Nymph } template< typename... XArgs > - void Slot< XArgs... >::DisconnectAll() const - { - for( auto connection : fConnections ) - { - connection->Disconnect( this ); - } - return; - } - - template< typename... XArgs > - void Slot< XArgs... >::AddConnection( SignalPtr_t signal, int group ) const + void Slot< XArgs... >::ConnectTo( SignalPtr_t signal, int group ) { if( fConnections.count( signal ) != 0 ) { @@ -219,31 +193,15 @@ namespace Nymph return; } - // ensure that the slot is of the correct type - if( ! std::dynamic_pointer_cast< Signal< XArgs... > >( signal ) ) - { - BOOST_THROW_EXCEPTION( ConnectionException() << "Trying to connect slot <" << fName << "> to signal <" << signal->Name() << ">, but cannot make the connection:\n" << - "\tUnable to cast from SignalBase to this slot's derived type.\n" << - "\tArgument types do not match" << eom ); - } - - _AddConnection( signal, group ); - signal->_Connect( this, group ); + signal->Connect( shared_from_this(), group ); return; } template< typename... XArgs > - void Slot< XArgs... >::_AddConnection( SignalPtr_t signal ) const - { - fConnections.insert( signal ); - return; - } - - template< typename... XArgs > - void Slot< XArgs... >::RemoveConnection( SignalPtr_t signal ) const + inline void Slot< XArgs... >::operator()( XArgs... args ) { - fConnections.erase( signal ); + fFunction( args... ); return; } From 66e8562652f9231fe96ab77e6655f9cbae63867c Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Fri, 13 Sep 2019 04:15:45 -0700 Subject: [PATCH 142/521] Some reworking of signals, slots, and their use by processors. Added TestProcessor.cc. Seems to be working now. --- Library/Processor/Processor.cc | 2 +- Library/Processor/Processor.hh | 20 ++-- Library/Processor/Signal.hh | 8 +- Library/Processor/SignalSlotBase.cc | 8 +- Library/Processor/SignalSlotBase.hh | 38 ++++---- Library/Processor/Slot.hh | 6 +- Testing/CMakeLists.txt | 1 + Testing/TestProcessor.cc | 145 ++++++++++++++++++++++++++++ Testing/TestSignalSlot.cc | 55 +++++++++-- 9 files changed, 228 insertions(+), 55 deletions(-) create mode 100644 Testing/TestProcessor.cc diff --git a/Library/Processor/Processor.cc b/Library/Processor/Processor.cc index 0bfca18..aa647a2 100644 --- a/Library/Processor/Processor.cc +++ b/Library/Processor/Processor.cc @@ -73,7 +73,7 @@ namespace Nymph return; } - void Processor::ConnectSignalToSlot( SignalPtr_t signal, SlotPtr_t slot, int groupNum ) + void Processor::ConnectSignalToSlot( SignalBase* signal, SlotBase* slot, int groupNum ) { if( ! signal ) { diff --git a/Library/Processor/Processor.hh b/Library/Processor/Processor.hh index 6efb137..cfcf109 100644 --- a/Library/Processor/Processor.hh +++ b/Library/Processor/Processor.hh @@ -25,11 +25,11 @@ namespace Nymph class Processor { protected: - typedef std::map< std::string, SignalPtr_t > SignalMap; + typedef std::map< std::string, SignalBase* > SignalMap; typedef SignalMap::iterator SigMapIt; typedef SignalMap::value_type SigMapVal; - typedef std::map< std::string, SlotPtr_t > SlotMap; + typedef std::map< std::string, SlotBase* > SlotMap; typedef SlotMap::iterator SlotMapIt; typedef SlotMap::value_type SlotMapVal; @@ -42,10 +42,10 @@ namespace Nymph public: /// Configure the processor with a param_node - virtual bool Configure( const scarab::param_node& node ) = 0; + virtual void Configure( const scarab::param_node& node ) = 0; /// Utility function for connecting any signal to any slot - static void ConnectSignalToSlot( SignalPtr_t signal, SlotPtr_t slot, int groupNum=-1 ); + static void ConnectSignalToSlot( SignalBase* signal, SlotBase* slot, int groupNum=-1 ); /// Connect a signal in this processor to a slot in a different processor void ConnectASlot( const std::string& signalName, Processor& processor, const std::string& slotName, int groupNum=-1 ); @@ -53,10 +53,10 @@ namespace Nymph void ConnectASignal( Processor& processor, const std::string& signalName, const std::string& slotName, int groupNum=-1 ); /// Register a signal object with this processor - void RegisterSignal( std::string name, SignalPtr_t signal ); + void RegisterSignal( std::string name, SignalBase* signal ); /// Register a slot object with this processor - void RegisterSlot( std::string name, SlotPtr_t slot, std::initializer_list< std::string > signals = {} ); + void RegisterSlot( std::string name, SlotBase* slot, std::initializer_list< std::string > signals = {} ); //bool GetDoBreakpoint( const std::string& slotName ); //void SetDoBreakpoint( const std::string& slotName, bool flag ); @@ -66,21 +66,17 @@ namespace Nymph MEMVAR_REF_CONST( SignalMap, Signals ); MEMVAR_REF_CONST( SlotMap, Slots ); - protected: - template< typename XReturn, typename... XArgs > - void PassToConnProcs( const std::string& slotName, std::function< XReturn(XArgs...) > function, XArgs... args ); - }; - inline void Processor::RegisterSignal( std::string name, SignalPtr_t signal ) + inline void Processor::RegisterSignal( std::string name, SignalBase* signal ) { LDEBUG( processorlog, "Registering signal <" << name << "> in processor <" << fName << ">" ); fSignals.insert( SigMapVal(name, signal) ); return; } - inline void Processor::RegisterSlot( std::string name, SlotPtr_t slot, std::initializer_list< std::string > signals ) + inline void Processor::RegisterSlot( std::string name, SlotBase* slot, std::initializer_list< std::string > signals ) { LDEBUG( processorlog, "Registering slot <" << name << "> in processor <" << fName << ">" ); fSlots.insert( SlotMapVal(name, slot) ); diff --git a/Library/Processor/Signal.hh b/Library/Processor/Signal.hh index ebfc7a2..42bc3c5 100644 --- a/Library/Processor/Signal.hh +++ b/Library/Processor/Signal.hh @@ -45,7 +45,7 @@ namespace Nymph Signal( Signal&& ) = delete; virtual ~Signal(); - virtual void Connect( SlotPtr_t slot, int group = -1 ); + virtual void Connect( SlotBase* slot, int group = -1 ); // calls all connected functions void Emit( XArgs... args ); @@ -125,7 +125,7 @@ namespace Nymph } template< typename... XArgs > - void Signal< XArgs... >::Connect( SlotPtr_t slot, int group ) + void Signal< XArgs... >::Connect( SlotBase* slot, int group ) { if( fConnections.count( slot ) != 0 ) { @@ -134,7 +134,7 @@ namespace Nymph } // ensure that the slot is of the correct type - if( ! std::dynamic_pointer_cast< Slot< XArgs... > >( slot ) ) + if( ! dynamic_cast< Slot< XArgs... >* >( slot ) ) { BOOST_THROW_EXCEPTION( ConnectionException() << "Trying to connect signal <" << fName << "> to slot <" << slot->Name() << ">, but cannot make the connection:\n" << "\tUnable to cast from SlotBase to this signal's derived type.\n" << @@ -169,7 +169,7 @@ namespace Nymph { for( auto connection : fConnections ) { - std::static_pointer_cast< Slot< XArgs... > >(connection)->Function()( args... ); + static_cast< Slot< XArgs... >* >(connection)->Function()( args... ); } return; } diff --git a/Library/Processor/SignalSlotBase.cc b/Library/Processor/SignalSlotBase.cc index cf6588d..1e76364 100644 --- a/Library/Processor/SignalSlotBase.cc +++ b/Library/Processor/SignalSlotBase.cc @@ -19,9 +19,9 @@ namespace Nymph void SlotBase::DisconnectAll() { - for( auto connection : fConnections ) + while( ! fConnections.empty() ) { - connection->Disconnect( shared_from_this() ); + Disconnect( *fConnections.begin() ); } return; } @@ -37,9 +37,9 @@ namespace Nymph // disconnects all previously connected functions void SignalBase::DisconnectAll() { - for( auto connection : fConnections ) + while( ! fConnections.empty() ) { - Disconnect( connection ); + Disconnect( *fConnections.begin() ); } return; } diff --git a/Library/Processor/SignalSlotBase.hh b/Library/Processor/SignalSlotBase.hh index cdeaaa5..ae1fd3c 100644 --- a/Library/Processor/SignalSlotBase.hh +++ b/Library/Processor/SignalSlotBase.hh @@ -24,12 +24,8 @@ namespace Nymph class SignalBase; - class SlotBase; - typedef std::shared_ptr< SignalBase > SignalPtr_t; - typedef std::shared_ptr< SlotBase > SlotPtr_t; - - class SlotBase : public std::enable_shared_from_this< SlotBase > + class SlotBase { public: SlotBase( const std::string& name ); @@ -37,23 +33,23 @@ namespace Nymph //SlotBase( const std::string& name, XOwner* owner ); virtual ~SlotBase(); - virtual void ConnectTo( SignalPtr_t signal, int group = -1 ) = 0; + virtual void ConnectTo( SignalBase* signal, int group = -1 ) = 0; - void Disconnect( SignalPtr_t signal); + void Disconnect( SignalBase* signal); void DisconnectAll(); MEMVAR_REF( std::string, Name ); - typedef std::set< SignalPtr_t > signal_connections; // to get around the problem of having a comma inside a macro function argument + typedef std::set< SignalBase* > signal_connections; // to get around the problem of having a comma inside a macro function argument MEMVAR_REF_MUTABLE( signal_connections, Connections ); protected: friend class SignalBase; - virtual void AddConnection( SignalPtr_t signal ); + virtual void AddConnection( SignalBase* signal ); }; - class SignalBase : public std::enable_shared_from_this< SignalBase > + class SignalBase { public: SignalBase( const std::string& name ); @@ -61,44 +57,44 @@ namespace Nymph //SignalBase( const std::string& name, XOwner* owner ); virtual ~SignalBase(); - virtual void Connect( SlotPtr_t slot, int group = -1 ) = 0; + virtual void Connect( SlotBase* slot, int group = -1 ) = 0; - void Disconnect( const SlotPtr_t slot ); + void Disconnect( SlotBase* slot ); void DisconnectAll(); MEMVAR_REF( std::string, Name ); - typedef std::set< SlotPtr_t > slot_connections; // to get around the problem of having a comma inside a macro function argument + typedef std::set< SlotBase* > slot_connections; // to get around the problem of having a comma inside a macro function argument MEMVAR_REF_MUTABLE_CONST( slot_connections, Connections ); protected: friend class SignalBase; - virtual void AddConnection( SlotPtr_t slot, int group ); + virtual void AddConnection( SlotBase* slot, int group ); }; - inline void SlotBase::AddConnection( SignalPtr_t signal ) + inline void SlotBase::AddConnection( SignalBase* signal ) { fConnections.insert( signal ); return; } - inline void SlotBase::Disconnect( SignalPtr_t signal ) + inline void SlotBase::Disconnect( SignalBase* signal ) { - signal->Disconnect( shared_from_this() ); + signal->Disconnect( this ); return; } - inline void SignalBase::AddConnection( SlotPtr_t slot, int group ) + inline void SignalBase::AddConnection( SlotBase* slot, int group ) { fConnections.insert( slot ); - slot->AddConnection( shared_from_this() ); + slot->AddConnection( this ); return; } // disconnects a previously connected function - inline void SignalBase::Disconnect( SlotPtr_t slot ) + inline void SignalBase::Disconnect( SlotBase* slot ) { - slot->fConnections.erase( shared_from_this() ); + slot->fConnections.erase( this ); fConnections.erase( slot ); return; } diff --git a/Library/Processor/Slot.hh b/Library/Processor/Slot.hh index 72d4acb..46202a0 100644 --- a/Library/Processor/Slot.hh +++ b/Library/Processor/Slot.hh @@ -56,7 +56,7 @@ namespace Nymph Slot( Slot&& ) = delete; virtual ~Slot(); - void ConnectTo( SignalPtr_t signal, int group = -1 ); + void ConnectTo( SignalBase* signal, int group = -1 ); // execute fFunction void operator()( XArgs... args ); @@ -185,7 +185,7 @@ namespace Nymph } template< typename... XArgs > - void Slot< XArgs... >::ConnectTo( SignalPtr_t signal, int group ) + void Slot< XArgs... >::ConnectTo( SignalBase* signal, int group ) { if( fConnections.count( signal ) != 0 ) { @@ -193,7 +193,7 @@ namespace Nymph return; } - signal->Connect( shared_from_this(), group ); + signal->Connect( this, group ); return; } diff --git a/Testing/CMakeLists.txt b/Testing/CMakeLists.txt index be65fc3..e95e65f 100644 --- a/Testing/CMakeLists.txt +++ b/Testing/CMakeLists.txt @@ -8,6 +8,7 @@ set( testing_HEADERS ) set( testing_SOURCES + TestProcessor.cc TestSignalSlot.cc UseCatch.cc ) diff --git a/Testing/TestProcessor.cc b/Testing/TestProcessor.cc new file mode 100644 index 0000000..3b1f94e --- /dev/null +++ b/Testing/TestProcessor.cc @@ -0,0 +1,145 @@ +/* + * TestProcessor.cc + * + * Created on: Sept 12, 2019 + * Author: N.S. Oblath + */ + +#include "Processor.hh" +#include "Signal.hh" +#include "Slot.hh" + +#include "catch.hpp" + +namespace Nymph +{ + // concrete processor class that we can test + // implements Configure() and has its own signal and slot + class TestProc : public Processor + { + public: + TestProc() : + Processor( "test" ), + fValue( 0 ), + fValueSig( "value", this ), + fValueSlot( "value", this, &TestProc::SetValue ) + {} + + ~TestProc() + {} + + void Configure( const scarab::param_node& node ) + { + fValue = node.get_value( "value", fValue ); + return; + } + + MEMVAR( int, Value ); + + Signal< int >& ValueSig() + { + return fValueSig; + } + + private: + Signal< int > fValueSig; + Slot< int > fValueSlot; + }; + + // external slot function owner + struct TestSlotOwner + { + int fValue = 0; + void TestSlotFunc( int input ) + { + fValue = input; + return; + } + }; +} + +TEST_CASE( "processor", "[signal],[slot],[processor]" ) +{ + using namespace Nymph; + + TestProc tester; + + SECTION( "Configuration" ) + { + REQUIRE( tester.GetValue() == 0 ); + + // setup the config parameter + scarab::param_node config; + int configValue = 5; + config.add( "value", configValue ); + + // perform configuration + tester.Configure( config ); + + // check that the value was set correctly + REQUIRE( tester.GetValue() == configValue ); + } + + SECTION( "Signals and Slots" ) + { + // check that the processor has one slot and one signal + REQUIRE( tester.Signals().size() == 1 ); + REQUIRE( tester.Slots().size() == 1 ); + + // this is a slot using a lambda function to set a variable + int lambdaValue = 0; + Slot< int > lambdaSlot( "lambdaSlot", [&lambdaValue](int input){ lambdaValue = input; } ); + tester.RegisterSlot( "lambdaSlot", &lambdaSlot ); + + // this slot is a member function of an object other than the processor + TestSlotOwner slotOwner; + Slot< int > slotOwnerSlot( "slotOwnerSlot", &tester, &slotOwner, &TestSlotOwner::TestSlotFunc ); + + // check initial value + REQUIRE( slotOwner.fValue == 0 ); + REQUIRE( lambdaValue == 0 ); + + // we've added a couple more slots + REQUIRE( tester.Slots().size() == 3 ); + + // no connections yet + REQUIRE( tester.Signals().at("value")->Connections().size() == 0 ); + REQUIRE( tester.Slots().at("value")->Connections().size() == 0 ); + + // make a connection + tester.ConnectASlot( "value", tester, "value" ); + + REQUIRE( tester.Signals().at("value")->Connections().size() == 1 ); + REQUIRE( tester.Slots().at("value")->Connections().size() == 1 ); + + // repeat connection should be ignored + tester.ConnectASlot( "value", tester, "value" ); + + REQUIRE( tester.Signals().at("value")->Connections().size() == 1 ); + REQUIRE( tester.Slots().at("value")->Connections().size() == 1 ); + + // connect the lambda slot to the signal + tester.ConnectASignal( tester, "value", "lambdaSlot" ); + + REQUIRE( tester.Signals().at("value")->Connections().size() == 2 ); + REQUIRE( tester.Slots().at("value")->Connections().size() == 1 ); + REQUIRE( tester.Slots().at("lambdaSlot")->Connections().size() == 1 ); + + // connect the exteranlly-owned slot to the signal + Processor::ConnectSignalToSlot( tester.Signals().at("value"), tester.Slots().at("slotOwnerSlot") ); + + REQUIRE( tester.Signals().at("value")->Connections().size() == 3 ); + REQUIRE( tester.Slots().at("value")->Connections().size() == 1 ); + REQUIRE( tester.Slots().at("slotOwnerSlot")->Connections().size() == 1 ); + + // emit the signal + int newValue = 10; + tester.ValueSig().Emit( newValue ); + + // check that all values have been changed + REQUIRE( tester.GetValue() == newValue ); + REQUIRE( slotOwner.fValue == newValue ); + REQUIRE( lambdaValue == newValue ); + } + +} diff --git a/Testing/TestSignalSlot.cc b/Testing/TestSignalSlot.cc index 8b18fa0..dabb39b 100644 --- a/Testing/TestSignalSlot.cc +++ b/Testing/TestSignalSlot.cc @@ -17,21 +17,56 @@ TEST_CASE( "signal_slot", "[signal],[slot],[processor]" ) int testValue = 0; - SignalPtr_t signalPtr = std::make_shared< Signal< int > >( "signal" ); - SlotPtr_t slotPtr = std::make_shared< Slot< int > >( "slot", [&](int aValue ){ testValue = aValue; } ); + Signal< int > signal( "signal" ); + Slot< int > slot( "slot", [&](int aValue ){ testValue = aValue; } ); - REQUIRE( signalPtr ); - REQUIRE( slotPtr ); + signal.Connect( &slot ); - signalPtr->Connect( slotPtr ); + REQUIRE( signal.Connections().size() == 1 ); + REQUIRE( slot.Connections().size() == 1 ); - //REQUIRE( signalPtr->Connections().size() == 1 ); - //REQUIRE( slotPtr->Connections().size() == 1 ); - - std::dynamic_pointer_cast< Signal< int > >(signalPtr)->Emit( 5 ); + signal.Emit( 5 ); REQUIRE( testValue == 5 ); - std::dynamic_pointer_cast< Signal< int > >(signalPtr)->operator()( 10 ); + signal( 10 ); REQUIRE( testValue == 10 ); + signal.Disconnect( &slot ); + + REQUIRE( signal.Connections().size() == 0 ); + REQUIRE( slot.Connections().size() == 0 ); + + // connect and disconnect via slot + slot.ConnectTo( &signal ); + + REQUIRE( signal.Connections().size() == 1 ); + REQUIRE( slot.Connections().size() == 1 ); + + slot.Disconnect( &signal ); + + REQUIRE( signal.Connections().size() == 0 ); + REQUIRE( slot.Connections().size() == 0 ); + + // reconnect for testing SignalBase::DisconnectAll() + signal.Connect( &slot ); + + REQUIRE( signal.Connections().size() == 1 ); + REQUIRE( slot.Connections().size() == 1 ); + + signal.DisconnectAll(); + + REQUIRE( signal.Connections().size() == 0 ); + REQUIRE( slot.Connections().size() == 0 ); + + // reconnect for testing SlotBaseDisconnectAll() + slot.ConnectTo( &signal ); + + REQUIRE( signal.Connections().size() == 1 ); + REQUIRE( slot.Connections().size() == 1 ); + + slot.DisconnectAll(); + + REQUIRE( signal.Connections().size() == 0 ); + REQUIRE( slot.Connections().size() == 0 ); + } From 1ccd07d47f8b3bc3d8d84ba5ab41f30b45fbb678 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Sat, 14 Sep 2019 19:54:00 -0700 Subject: [PATCH 143/521] Added blank ControlAccess class, the slot wrapper function, calling the slot wrapper function from a signal with the control access, and the ability to tell a slot which signals it calls. --- Library/CMakeLists.txt | 1 + Library/Processor/ControlAccess.hh | 20 +++++++++++++++ Library/Processor/Processor.cc | 40 +++++++++++++++++++++++++++++ Library/Processor/Processor.hh | 19 ++++---------- Library/Processor/Signal.hh | 3 ++- Library/Processor/SignalSlotBase.cc | 6 +++-- Library/Processor/SignalSlotBase.hh | 6 +++++ Library/Processor/Slot.hh | 38 +++++++++++++++++++++++---- 8 files changed, 111 insertions(+), 22 deletions(-) create mode 100644 Library/Processor/ControlAccess.hh diff --git a/Library/CMakeLists.txt b/Library/CMakeLists.txt index 7cc4740..164a04a 100644 --- a/Library/CMakeLists.txt +++ b/Library/CMakeLists.txt @@ -12,6 +12,7 @@ set( APPL_DIR Application ) set( NYMPH_HEADERFILES ${UTIL_DIR}/Exception.hh ${UTIL_DIR}/MemberVariable.hh + ${PROC_DIR}/ControlAccess.hh #${PROC_DIR}/PrimaryProcessor.hh ${PROC_DIR}/Processor.hh ${PROC_DIR}/SignalSlotBase.hh diff --git a/Library/Processor/ControlAccess.hh b/Library/Processor/ControlAccess.hh new file mode 100644 index 0000000..12109d3 --- /dev/null +++ b/Library/Processor/ControlAccess.hh @@ -0,0 +1,20 @@ +/* + * ControlAccess.hh + * + * Created on: Sept 14, 2019 + * Author: N.S. Oblath + */ + +#ifndef NYMPH_CONTROLACCESS_HH_ +#define NYMPH_CONTROLACCESS_HH_ + +namespace Nymph +{ + + //TODO fill this in with anything useful + struct ControlAccess + {}; + +} /* namespace Nymph */ + +#endif /* NYMPH_CONTROLACCESS_HH_ */ diff --git a/Library/Processor/Processor.cc b/Library/Processor/Processor.cc index aa647a2..4a56b47 100644 --- a/Library/Processor/Processor.cc +++ b/Library/Processor/Processor.cc @@ -7,6 +7,7 @@ #include "Processor.hh" +#include namespace Nymph { @@ -22,6 +23,45 @@ namespace Nymph Processor::~Processor() {} + void Processor::RegisterSignal( std::string name, SignalBase* signal ) + { + LDEBUG( processorlog, "Registering signal <" << name << "> in processor <" << fName << ">" ); + fSignals.insert( SigMapVal(name, signal) ); + + // give the signal to any slots that are waiting for it + auto range = fSlotsWaitingForSignals.equal_range( name ); + for( auto rangeIt = range.first; rangeIt != range.second; ++rangeIt ) + { + rangeIt->second->SignalsUsed().push_back( signal ); + } + + return; + } + + void Processor::RegisterSlot( std::string name, SlotBase* slot, std::initializer_list< std::string > signals ) + { + LDEBUG( processorlog, "Registering slot <" << name << "> in processor <" << fName << ">" ); + fSlots.insert( SlotMapVal(name, slot) ); + + // take care of giving signal pointers to the slot, or saving them for later assignment + for( auto signalIt = signals.begin(); signalIt != signals.end(); ++signalIt ) + { + auto signalPtrIt = fSignals.find( *signalIt ); + if( signalPtrIt == fSignals.end() ) + { + // don't have that signal yet, so the slot will wait + fSlotsWaitingForSignals.insert( std::make_pair( *signalIt, slot ) ); + } + else + { + // have the signal; give it to the slot + slot->SignalsUsed().push_back( signalPtrIt->second ); + } + } + + return; + } + void Processor::ConnectASlot( const std::string& signalName, Processor& processor, const std::string& slotName, int groupNum ) { // get the signal and slot pointers diff --git a/Library/Processor/Processor.hh b/Library/Processor/Processor.hh index cfcf109..46f7856 100644 --- a/Library/Processor/Processor.hh +++ b/Library/Processor/Processor.hh @@ -66,22 +66,13 @@ namespace Nymph MEMVAR_REF_CONST( SignalMap, Signals ); MEMVAR_REF_CONST( SlotMap, Slots ); - }; - + // this is used only to hold pointers to slots waiting for signals + // the keys are the names of the signals being waited for, and the values are the slot pointers + typedef std::multimap< std::string, SlotBase* > WaitingSlotMap; + MEMVAR_REF_CONST( WaitingSlotMap, SlotsWaitingForSignals ); - inline void Processor::RegisterSignal( std::string name, SignalBase* signal ) - { - LDEBUG( processorlog, "Registering signal <" << name << "> in processor <" << fName << ">" ); - fSignals.insert( SigMapVal(name, signal) ); - return; - } + }; - inline void Processor::RegisterSlot( std::string name, SlotBase* slot, std::initializer_list< std::string > signals ) - { - LDEBUG( processorlog, "Registering slot <" << name << "> in processor <" << fName << ">" ); - fSlots.insert( SlotMapVal(name, slot) ); - return; - } inline void Processor::ConnectASignal(Processor& processor, const std::string& signalName, const std::string& slotName, int groupNum ) { diff --git a/Library/Processor/Signal.hh b/Library/Processor/Signal.hh index 42bc3c5..64025d7 100644 --- a/Library/Processor/Signal.hh +++ b/Library/Processor/Signal.hh @@ -34,6 +34,7 @@ namespace Nymph { public: using signature = void( XArgs... ); + using full_signature = void( ControlAccess*, XArgs... ); public: /// Unowned signal @@ -169,7 +170,7 @@ namespace Nymph { for( auto connection : fConnections ) { - static_cast< Slot< XArgs... >* >(connection)->Function()( args... ); + static_cast< Slot< XArgs... >* >(connection)->operator()( fControl, args... ); } return; } diff --git a/Library/Processor/SignalSlotBase.cc b/Library/Processor/SignalSlotBase.cc index 1e76364..b5529d9 100644 --- a/Library/Processor/SignalSlotBase.cc +++ b/Library/Processor/SignalSlotBase.cc @@ -11,7 +11,8 @@ namespace Nymph { SlotBase::SlotBase( const std::string& name ) : fName( name ), - fConnections() + fConnections(), + fSignalsUsed() {} SlotBase::~SlotBase() @@ -28,7 +29,8 @@ namespace Nymph SignalBase::SignalBase( const std::string& name ) : fName( name ), - fConnections() + fConnections(), + fControl( nullptr ) {} SignalBase::~SignalBase() diff --git a/Library/Processor/SignalSlotBase.hh b/Library/Processor/SignalSlotBase.hh index ae1fd3c..2168dfc 100644 --- a/Library/Processor/SignalSlotBase.hh +++ b/Library/Processor/SignalSlotBase.hh @@ -8,12 +8,14 @@ #ifndef NYMPH_SIGNALSLOTBASE_HH_ #define NYMPH_SIGNALSLOTBASE_HH_ +#include "ControlAccess.hh" #include "Exception.hh" #include "MemberVariable.hh" #include #include #include +#include namespace Nymph { @@ -43,6 +45,8 @@ namespace Nymph typedef std::set< SignalBase* > signal_connections; // to get around the problem of having a comma inside a macro function argument MEMVAR_REF_MUTABLE( signal_connections, Connections ); + MEMVAR_REF( std::vector< SignalBase* >, SignalsUsed ); + protected: friend class SignalBase; virtual void AddConnection( SignalBase* signal ); @@ -67,6 +71,8 @@ namespace Nymph typedef std::set< SlotBase* > slot_connections; // to get around the problem of having a comma inside a macro function argument MEMVAR_REF_MUTABLE_CONST( slot_connections, Connections ); + MEMVAR( ControlAccess*, Control ); // doesn't use MEMVAR_PTR because Signal doesn't own the object pointed to by fControl + protected: friend class SignalBase; virtual void AddConnection( SlotBase* slot, int group ); diff --git a/Library/Processor/Slot.hh b/Library/Processor/Slot.hh index 46202a0..c132f5b 100644 --- a/Library/Processor/Slot.hh +++ b/Library/Processor/Slot.hh @@ -13,7 +13,6 @@ #include "SignalSlotBase.hh" //#include "Exception.hh" -//#include "ThreadReference.hh" #include "logger.hh" @@ -25,18 +24,18 @@ namespace Nymph { LOGGER(slotlog, "Slot"); - // Type XOwner is the class that owns the Slot object template< typename... XArgs > class Slot : public SlotBase { public: using signature = void( XArgs... ); + using full_signature = void( ControlAccess*, XArgs... ); using signal_list = std::initializer_list< std::string >; public: /// Unowned slot - Slot( const std::string& name, const boost::function< signature >& func, signal_list signals = {} ); + Slot( const std::string& name, const boost::function< signature >& func ); /// Owned slot, non-const member function template< typename XOwner > Slot( const std::string& name, XOwner* owner, void (XOwner::*func)( XArgs... ), signal_list signals = {} ); @@ -58,12 +57,18 @@ namespace Nymph void ConnectTo( SignalBase* signal, int group = -1 ); - // execute fFunction + /// execute fFunction without using a ControlAccess object void operator()( XArgs... args ); + /// execute fFunction with a ControlAccess object + void operator()( ControlAccess* access, XArgs... args ); + MEMVAR_REF( boost::function< signature >, Function ); MEMVAR( bool, DoBreakpoint ); + + protected: + void SlotFuncWrapper( ControlAccess* access, XArgs... args ); }; @@ -116,7 +121,7 @@ namespace Nymph // Slot template< typename... XArgs > - Slot< XArgs... >::Slot( const std::string& name, const boost::function< signature >& func, signal_list signals ) : + Slot< XArgs... >::Slot( const std::string& name, const boost::function< signature >& func ) : SlotBase( name ), fFunction( func ), //fThreadRef( std::make_shared< ThreadReference >() ), @@ -205,6 +210,29 @@ namespace Nymph return; } + template< typename... XArgs > + inline void Slot< XArgs... >::operator()( ControlAccess* access, XArgs... args ) + { + SlotFuncWrapper( access, args... ); + return; + } + + template< typename... XArgs > + inline void Slot< XArgs... >::SlotFuncWrapper( ControlAccess* access, XArgs... args ) + { + //TODO could do something with `access` here + for( auto signalIt = fSignalsUsed.begin(); signalIt != fSignalsUsed.end(); ++signalIt ) + { + (*signalIt)->SetControl( access ); + } + + fFunction( args... ); + + //TODO could do more with `access` here + + return; + } + } /* namespace Nymph */ #endif /* NYMPH_SLOT_HH_ */ From 8f394ee61a2070a84707645f0c8515295ae92166 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Sun, 15 Sep 2019 03:31:53 -0700 Subject: [PATCH 144/521] Added testing of slot/signal/slot relationships --- Testing/TestProcessor.cc | 60 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 55 insertions(+), 5 deletions(-) diff --git a/Testing/TestProcessor.cc b/Testing/TestProcessor.cc index 3b1f94e..e110634 100644 --- a/Testing/TestProcessor.cc +++ b/Testing/TestProcessor.cc @@ -9,8 +9,12 @@ #include "Signal.hh" #include "Slot.hh" +#include "logger.hh" + #include "catch.hpp" +LOGGER( testlog, "TestProcessor" ); + namespace Nymph { // concrete processor class that we can test @@ -21,8 +25,12 @@ namespace Nymph TestProc() : Processor( "test" ), fValue( 0 ), + fSecondValue( 0 ), fValueSig( "value", this ), - fValueSlot( "value", this, &TestProc::SetValue ) + fValueSlot( "value", this, &TestProc::SetValue ), + fSecondValueSig( "second-value", this ), + fSecondValueSlot( "second-value", this, &TestProc::SecondValueSlotFunction, {"second-value"} ), + fSecondValueSlot2( "second-value-2", this, &TestProc::SetSecondValue ) {} ~TestProc() @@ -35,15 +43,27 @@ namespace Nymph } MEMVAR( int, Value ); + MEMVAR( int, SecondValue ); Signal< int >& ValueSig() { return fValueSig; } + void SecondValueSlotFunction( int newValue ) + { + fSecondValueSig( newValue ); + } + private: Signal< int > fValueSig; Slot< int > fValueSlot; + + //Signal< int > fSecondValueSig; + MEMVAR_REF( Signal< int >, SecondValueSig ); + private: + Slot< int > fSecondValueSlot; + Slot< int > fSecondValueSlot2; }; // external slot function owner @@ -82,9 +102,13 @@ TEST_CASE( "processor", "[signal],[slot],[processor]" ) SECTION( "Signals and Slots" ) { - // check that the processor has one slot and one signal - REQUIRE( tester.Signals().size() == 1 ); - REQUIRE( tester.Slots().size() == 1 ); + // check that the processor has the right number of signals and slots registered + REQUIRE( tester.Signals().size() == 2 ); + REQUIRE( tester.Slots().size() == 3 ); + + //************************** + // Testing signal->slot + //************************** // this is a slot using a lambda function to set a variable int lambdaValue = 0; @@ -100,7 +124,7 @@ TEST_CASE( "processor", "[signal],[slot],[processor]" ) REQUIRE( lambdaValue == 0 ); // we've added a couple more slots - REQUIRE( tester.Slots().size() == 3 ); + REQUIRE( tester.Slots().size() == 5 ); // no connections yet REQUIRE( tester.Signals().at("value")->Connections().size() == 0 ); @@ -132,6 +156,11 @@ TEST_CASE( "processor", "[signal],[slot],[processor]" ) REQUIRE( tester.Slots().at("value")->Connections().size() == 1 ); REQUIRE( tester.Slots().at("slotOwnerSlot")->Connections().size() == 1 ); + // now have "signal" connected to three slots: + // value --> value + // value --> lambdaSlot + // value --> slotOwnerSlot + // emit the signal int newValue = 10; tester.ValueSig().Emit( newValue ); @@ -140,6 +169,27 @@ TEST_CASE( "processor", "[signal],[slot],[processor]" ) REQUIRE( tester.GetValue() == newValue ); REQUIRE( slotOwner.fValue == newValue ); REQUIRE( lambdaValue == newValue ); + + //********************************* + // testing slot->signal->slot + //********************************* + + // check initial value + REQUIRE( tester.GetSecondValue() == 0 ); + + REQUIRE( tester.Slots().at("second-value")->SignalsUsed().size() == 1 ); + REQUIRE( tester.Slots().at("second-value")->SignalsUsed()[0] == &tester.SecondValueSig() ); + + tester.ConnectASlot( "second-value", tester, "second-value-2" ); + + // now have second-value (slot) emits second-value --> second-value-2 + + REQUIRE( tester.Signals().at("second-value")->Connections().size() == 1 ); + REQUIRE( tester.Slots().at("second-value-2")->Connections().size() == 1 ); + + tester.SecondValueSlotFunction( newValue ); + + REQUIRE( tester.GetSecondValue() == newValue ); } } From 11bc36d90b4215317a5e552bdd25f1df303044a3 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Sun, 15 Sep 2019 06:17:43 -0700 Subject: [PATCH 145/521] Got PrimaryProcessor in shape and a test version of ControlAccess. --- Library/CMakeLists.txt | 7 ++- Library/Processor/ControlAccess.cc | 28 ++++++++++ Library/Processor/ControlAccess.hh | 80 ++++++++++++++++++++++++++- Library/Processor/PrimaryProcessor.cc | 54 +++++++----------- Library/Processor/PrimaryProcessor.hh | 43 +++++++++----- Testing/CMakeLists.txt | 2 + Testing/TestControlAccess.cc | 29 ++++++++++ Testing/TestPrimaryProcessor.cc | 70 +++++++++++++++++++++++ Testing/TestProcessor.cc | 19 ++----- 9 files changed, 265 insertions(+), 67 deletions(-) create mode 100644 Library/Processor/ControlAccess.cc create mode 100644 Testing/TestControlAccess.cc create mode 100644 Testing/TestPrimaryProcessor.cc diff --git a/Library/CMakeLists.txt b/Library/CMakeLists.txt index 164a04a..bd3fee4 100644 --- a/Library/CMakeLists.txt +++ b/Library/CMakeLists.txt @@ -12,15 +12,18 @@ set( APPL_DIR Application ) set( NYMPH_HEADERFILES ${UTIL_DIR}/Exception.hh ${UTIL_DIR}/MemberVariable.hh + ${PROC_DIR}/ControlAccess.hh - #${PROC_DIR}/PrimaryProcessor.hh + ${PROC_DIR}/PrimaryProcessor.hh ${PROC_DIR}/Processor.hh ${PROC_DIR}/SignalSlotBase.hh ) set( NYMPH_SOURCEFILES ${UTIL_DIR}/Exception.cc - #${PROC_DIR}/PrimaryProcessor.cc + + ${PROC_DIR}/ControlAccess.cc + ${PROC_DIR}/PrimaryProcessor.cc ${PROC_DIR}/Processor.cc ${PROC_DIR}/SignalSlotBase.cc ) diff --git a/Library/Processor/ControlAccess.cc b/Library/Processor/ControlAccess.cc new file mode 100644 index 0000000..673a6d6 --- /dev/null +++ b/Library/Processor/ControlAccess.cc @@ -0,0 +1,28 @@ +/* + * ControlAccess.cc + * + * Created on: Sept 15, 2019 + * Author: N.S. Oblath + */ + +#include "ControlAccess.hh" + + +namespace Nymph +{ + ReturnBufferBase::ReturnBufferBase() + {} + + ReturnBufferBase::~ReturnBufferBase() + {} + + + ControlAccess::ControlAccess() : + fReturn( new ReturnBuffer< int >() ) + {} + + ControlAccess::~ControlAccess() + {} + + +} /* namespace Nymph */ diff --git a/Library/Processor/ControlAccess.hh b/Library/Processor/ControlAccess.hh index 12109d3..b64ef60 100644 --- a/Library/Processor/ControlAccess.hh +++ b/Library/Processor/ControlAccess.hh @@ -8,12 +8,88 @@ #ifndef NYMPH_CONTROLACCESS_HH_ #define NYMPH_CONTROLACCESS_HH_ +#include + namespace Nymph { + class ReturnBufferBase + { + public: + ReturnBufferBase(); + virtual ~ReturnBufferBase(); + }; + + template< typename OneArg > + struct ReturnBuffer : ReturnBufferBase + { + public: + ReturnBuffer() : + fReturn( nullptr ) + {} + + ReturnBuffer( OneArg& retval ) : + fReturn( &retval ) + {} + + virtual ~ReturnBuffer() + {} + + OneArg& GetReturn() + { + if( fReturn == nullptr ) throw std::exception(); + return *fReturn; + } + + protected: + OneArg* fReturn; + }; + + template<> + struct ReturnBuffer< void > : ReturnBufferBase + { + ReturnBuffer() : + ReturnBufferBase() + {} + + void GetReturn() + { + return; + } + }; //TODO fill this in with anything useful - struct ControlAccess - {}; + class ControlAccess + { + public: + ControlAccess(); + + virtual ~ControlAccess(); + + template< typename OneArg > + void SetReturn( OneArg& arg ); + + template< typename OneArg > + OneArg& GetReturn(); + + protected: + std::shared_ptr< ReturnBufferBase > fReturn; + }; + + + template< typename OneArg > + void ControlAccess::SetReturn( OneArg& arg ) + { + fReturn = std::make_shared< ReturnBuffer< OneArg > >( arg ); + return; + } + + template< typename OneArg > + OneArg& ControlAccess::GetReturn() + { + std::shared_ptr< ReturnBuffer< OneArg > > buffer( std::dynamic_pointer_cast< ReturnBuffer< OneArg > >(fReturn) ); + if( buffer == nullptr ) throw std::exception(); + return buffer->GetReturn(); + } } /* namespace Nymph */ diff --git a/Library/Processor/PrimaryProcessor.cc b/Library/Processor/PrimaryProcessor.cc index 27b6f1d..7c362a1 100644 --- a/Library/Processor/PrimaryProcessor.cc +++ b/Library/Processor/PrimaryProcessor.cc @@ -1,67 +1,51 @@ /* - * KTPrimaryProcessor.cc + * PrimaryProcessor.cc * * Created on: Oct 10, 2012 * Author: N.S. Oblath */ -#include "KTPrimaryProcessor.hh" +#include "PrimaryProcessor.hh" -#include "KTException.hh" -#include "KTLogger.hh" +#include "Exception.hh" + +#include "logger.hh" namespace Nymph { - KTLOGGER( proclog, "KTPrimaryProcessor" ); + LOGGER( proclog, "PrimaryProcessor" ); - KTPrimaryProcessor::KTPrimaryProcessor( std::initializer_list< std::string > signals, const std::string& name ) : - KTProcessor( name ), - fSignalsEmitted( signals ), - fThreadRef(), - fDoBreakpoint(false) - { + PrimaryProcessor::PrimaryProcessor( const std::string& name ) : + Processor( name ) + {} - } - - KTPrimaryProcessor::~KTPrimaryProcessor() - { - } + PrimaryProcessor::~PrimaryProcessor() + {} - void KTPrimaryProcessor::operator ()( std::shared_ptr< KTThreadReference > ref, boost::condition_variable& startedCV, bool& startedFlag ) + void PrimaryProcessor::operator()( ControlAccess* control ) { - fThreadRef = ref; - - // pass updated thread reference to downstream slots - for( auto sigIt = fSignalsEmitted.begin(); sigIt != fSignalsEmitted.end(); ++sigIt ) + for( auto signalIt = fSignals.begin(); signalIt != fSignals.end(); ++signalIt ) { - // loop over all processor:slots called by this signal - auto sigConnRange = fSigConnMap.equal_range( *sigIt ); - for( SigConnMapCIt sigConnIt = sigConnRange.first; sigConnIt != sigConnRange.second; ++sigConnIt ) - { - // pass the update on to the connected-to processor - sigConnIt->second.first->PassThreadRefUpdate( sigConnIt->second.second, fThreadRef ); - } + signalIt->second->SetControl( control ); } - startedFlag = true; - startedCV.notify_all(); - // go! try { if( ! Run() ) { - KTERROR( proclog, "An error occurred during processor running." ); - THROW_THREADREF_EXCEPTION( fThreadRef, KTException() << "An error occurred during processor running" ); + LERROR( proclog, "An error occurred during processor running." ); + //THROW_THREADREF_EXCEPTION( fThreadRef, KTException() << "An error occurred during processor running" ); } else { - fThreadRef->SetReturnValue( KTDataHandle() ); + LWARN( proclog, "Valid return" ); + //fThreadRef->SetReturnValue( KTDataHandle() ); } } catch( boost::exception& e ) { - fThreadRef->SetReturnException( boost::current_exception() ); + //fThreadRef->SetReturnException( boost::current_exception() ); } return; } diff --git a/Library/Processor/PrimaryProcessor.hh b/Library/Processor/PrimaryProcessor.hh index e72fcf3..9d125b7 100644 --- a/Library/Processor/PrimaryProcessor.hh +++ b/Library/Processor/PrimaryProcessor.hh @@ -1,30 +1,41 @@ /* - * KTPrimaryProcessor.hh + * PrimaryProcessor.hh * * Created on: Oct 10, 2012 * Author: N.S. Oblath */ -#ifndef KTPRIMARYPROCESSOR_HH_ -#define KTPRIMARYPROCESSOR_HH_ +#ifndef NYMPH_PRIMARYPROCESSOR_HH_ +#define NYMPH_PRIMARYPROCESSOR_HH_ -#include "KTProcessor.hh" +#include "Processor.hh" -#include "KTCoreData.hh" -#include "KTThreadReference.hh" - -#include - -#include namespace Nymph { - class KTPrimaryProcessor : public KTProcessor + class PrimaryProcessor : public Processor + { + public: + PrimaryProcessor( const std::string& name ); + virtual ~PrimaryProcessor(); + + public: + /// Callable function used by std::thread + void operator()( ControlAccess* control ); + + /// Starts the main action of the processor + virtual bool Run() = 0; + + }; + + +/* + class PrimaryProcessor : public Processor { public: - KTPrimaryProcessor( std::initializer_list< std::string > signals, const std::string& name = "default-primary-processor-name" ); - virtual ~KTPrimaryProcessor(); + PrimaryProcessor( std::initializer_list< std::string > signals, const std::string& name = "default-primary-processor-name" ); + virtual ~PrimaryProcessor(); public: /// Callable function used by std::thread @@ -44,10 +55,12 @@ namespace Nymph }; - inline std::shared_ptr< KTThreadReference > KTPrimaryProcessor::GetThreadRef() + inline std::shared_ptr< KTThreadReference > PrimaryProcessor::GetThreadRef() { return fThreadRef; } +*/ } /* namespace Nymph */ -#endif /* KTPRIMARYPROCESSOR_HH_ */ + +#endif /* NYMPH_PRIMARYPROCESSOR_HH_ */ diff --git a/Testing/CMakeLists.txt b/Testing/CMakeLists.txt index e95e65f..29726b0 100644 --- a/Testing/CMakeLists.txt +++ b/Testing/CMakeLists.txt @@ -8,6 +8,8 @@ set( testing_HEADERS ) set( testing_SOURCES + TestControlAccess.cc + TestPrimaryProcessor.cc TestProcessor.cc TestSignalSlot.cc UseCatch.cc diff --git a/Testing/TestControlAccess.cc b/Testing/TestControlAccess.cc new file mode 100644 index 0000000..f853c3c --- /dev/null +++ b/Testing/TestControlAccess.cc @@ -0,0 +1,29 @@ +/* + * TestControlAccesss.cc + * + * Created on: Sept 15, 2019 + * Author: N.S. Oblath + */ + + +#include "ControlAccess.hh" + +#include "catch.hpp" + + +TEST_CASE( "control_access", "[control_access]" ) +{ + using namespace Nymph; + + ControlAccess control; + + int intReturn = 5; + + REQUIRE_THROWS( control.GetReturn< int >() ); + + control.SetReturn< int >( intReturn ); + + REQUIRE( control.GetReturn< int >() == intReturn ); + REQUIRE_THROWS( control.GetReturn< unsigned >() == intReturn ); + +} \ No newline at end of file diff --git a/Testing/TestPrimaryProcessor.cc b/Testing/TestPrimaryProcessor.cc new file mode 100644 index 0000000..62afb44 --- /dev/null +++ b/Testing/TestPrimaryProcessor.cc @@ -0,0 +1,70 @@ +/* + * TestPrimaryProcessor.cc + * + * Created on: Sept 15, 2019 + * Author: N.S. Oblath + */ + +#include "PrimaryProcessor.hh" +#include "Signal.hh" +#include "Slot.hh" + +#include "logger.hh" + +#include "catch.hpp" + +LOGGER( testlog, "TestPrimaryProcessor" ); + +namespace Nymph +{ + // concrete processor class that we can test + // implements Configure() and has its own signal and slot + class TestPrimaryProc : public PrimaryProcessor + { + public: + TestPrimaryProc() : + PrimaryProcessor( "test" ), + fNewValue( 10 ), + fValue( 0 ), + fValueSig( "value", this ), + fValueSlot( "value", this, &TestPrimaryProc::SetValue ) + {} + + virtual ~TestPrimaryProc() + {} + + void Configure( const scarab::param_node& ) + { + return; + } + + bool Run() + { + fValueSig( fNewValue ); + return true; + } + + MEMVAR( int, NewValue ); + MEMVAR( int, Value ); + + MEMVAR_REF( Signal< int >, ValueSig ); + MEMVAR_REF( Slot< int >, ValueSlot ); + + }; +} + +TEST_CASE( "primary_processor", "[primary_processor]" ) +{ + using namespace Nymph; + + TestPrimaryProc tester; + + tester.ConnectASlot( "value", tester, "value" ); + + ControlAccess control; + tester( &control ); + + REQUIRE( tester.GetValue() == tester.GetNewValue() ); + + REQUIRE( tester.ValueSig().GetControl() == &control ); +} diff --git a/Testing/TestProcessor.cc b/Testing/TestProcessor.cc index e110634..f075355 100644 --- a/Testing/TestProcessor.cc +++ b/Testing/TestProcessor.cc @@ -33,7 +33,7 @@ namespace Nymph fSecondValueSlot2( "second-value-2", this, &TestProc::SetSecondValue ) {} - ~TestProc() + virtual ~TestProc() {} void Configure( const scarab::param_node& node ) @@ -45,25 +45,18 @@ namespace Nymph MEMVAR( int, Value ); MEMVAR( int, SecondValue ); - Signal< int >& ValueSig() - { - return fValueSig; - } - void SecondValueSlotFunction( int newValue ) { fSecondValueSig( newValue ); } - private: - Signal< int > fValueSig; - Slot< int > fValueSlot; + MEMVAR_REF( Signal< int >, ValueSig ); + MEMVAR_REF( Slot< int >, ValueSlot ); - //Signal< int > fSecondValueSig; MEMVAR_REF( Signal< int >, SecondValueSig ); - private: - Slot< int > fSecondValueSlot; - Slot< int > fSecondValueSlot2; + MEMVAR_REF( Slot< int >, SecondValueSlot ); + MEMVAR_REF( Slot< int >, SecondValueSlot2 ); + }; // external slot function owner From 7d49d5127f81b934d5d436f0babfebb9681e477a Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Sun, 15 Sep 2019 07:04:05 -0700 Subject: [PATCH 146/521] Switch ControlAccess return to use std::tuple to return multiple types --- Library/Processor/ControlAccess.hh | 32 +++++++++++++++--------------- Testing/TestControlAccess.cc | 4 ++-- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/Library/Processor/ControlAccess.hh b/Library/Processor/ControlAccess.hh index b64ef60..13296bc 100644 --- a/Library/Processor/ControlAccess.hh +++ b/Library/Processor/ControlAccess.hh @@ -9,6 +9,7 @@ #define NYMPH_CONTROLACCESS_HH_ #include +#include namespace Nymph { @@ -19,7 +20,7 @@ namespace Nymph virtual ~ReturnBufferBase(); }; - template< typename OneArg > + template< typename... Args > struct ReturnBuffer : ReturnBufferBase { public: @@ -27,21 +28,21 @@ namespace Nymph fReturn( nullptr ) {} - ReturnBuffer( OneArg& retval ) : - fReturn( &retval ) + ReturnBuffer( Args&... retval ) : + fReturn( new std::tuple< Args&... >( retval... ) ) {} virtual ~ReturnBuffer() {} - OneArg& GetReturn() + std::tuple< Args&... >& GetReturn() { if( fReturn == nullptr ) throw std::exception(); return *fReturn; } protected: - OneArg* fReturn; + std::tuple< Args&... >* fReturn; }; template<> @@ -57,7 +58,6 @@ namespace Nymph } }; - //TODO fill this in with anything useful class ControlAccess { public: @@ -65,28 +65,28 @@ namespace Nymph virtual ~ControlAccess(); - template< typename OneArg > - void SetReturn( OneArg& arg ); + template< typename... Args > + void SetReturn( Args&... arg ); - template< typename OneArg > - OneArg& GetReturn(); + template< typename... Args > + std::tuple< Args&... >& GetReturn(); protected: std::shared_ptr< ReturnBufferBase > fReturn; }; - template< typename OneArg > - void ControlAccess::SetReturn( OneArg& arg ) + template< typename... Args > + void ControlAccess::SetReturn( Args&... args ) { - fReturn = std::make_shared< ReturnBuffer< OneArg > >( arg ); + fReturn = std::make_shared< ReturnBuffer< Args... > >( args... ); return; } - template< typename OneArg > - OneArg& ControlAccess::GetReturn() + template< typename... Args > + std::tuple< Args&... >& ControlAccess::GetReturn() { - std::shared_ptr< ReturnBuffer< OneArg > > buffer( std::dynamic_pointer_cast< ReturnBuffer< OneArg > >(fReturn) ); + std::shared_ptr< ReturnBuffer< Args... > > buffer( std::dynamic_pointer_cast< ReturnBuffer< Args... > >(fReturn) ); if( buffer == nullptr ) throw std::exception(); return buffer->GetReturn(); } diff --git a/Testing/TestControlAccess.cc b/Testing/TestControlAccess.cc index f853c3c..c4adf02 100644 --- a/Testing/TestControlAccess.cc +++ b/Testing/TestControlAccess.cc @@ -23,7 +23,7 @@ TEST_CASE( "control_access", "[control_access]" ) control.SetReturn< int >( intReturn ); - REQUIRE( control.GetReturn< int >() == intReturn ); - REQUIRE_THROWS( control.GetReturn< unsigned >() == intReturn ); + REQUIRE( std::get< 0 >(control.GetReturn< int >()) == intReturn ); + REQUIRE_THROWS( control.GetReturn< unsigned >() ); } \ No newline at end of file From ca48401b27b1b9b37a5f571f9d599a381e2ca885 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Sun, 15 Sep 2019 07:09:57 -0700 Subject: [PATCH 147/521] Test two returns --- Testing/TestControlAccess.cc | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/Testing/TestControlAccess.cc b/Testing/TestControlAccess.cc index c4adf02..039e0cd 100644 --- a/Testing/TestControlAccess.cc +++ b/Testing/TestControlAccess.cc @@ -17,13 +17,27 @@ TEST_CASE( "control_access", "[control_access]" ) ControlAccess control; - int intReturn = 5; + SECTION( "One Return" ) + { + int intReturn = 5; - REQUIRE_THROWS( control.GetReturn< int >() ); + REQUIRE_THROWS( control.GetReturn< int >() ); - control.SetReturn< int >( intReturn ); + control.SetReturn< int >( intReturn ); - REQUIRE( std::get< 0 >(control.GetReturn< int >()) == intReturn ); - REQUIRE_THROWS( control.GetReturn< unsigned >() ); + REQUIRE( std::get< 0 >(control.GetReturn< int >()) == intReturn ); + REQUIRE_THROWS( control.GetReturn< unsigned >() ); + } + + SECTION( "Two Returns" ) + { + int return1 = 5; + double return2 = 10.; + + control.SetReturn< int, double >( return1, return2 ); + + REQUIRE( std::get< 0 >(control.GetReturn< int, double >()) == return1 ); + REQUIRE( std::get< 1 >(control.GetReturn< int, double >()) == return2 ); + } } \ No newline at end of file From 192cef12b425831e285b59a6fadd5cc2180bf256 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Fri, 20 Sep 2019 00:48:01 -0700 Subject: [PATCH 148/521] Finished and tested basic breakpoint functionality --- Library/Processor/ControlAccess.cc | 26 +++++++++++++++++++++++++- Library/Processor/ControlAccess.hh | 19 ++++++++++++++++++- Library/Processor/Signal.hh | 14 ++++++++++++-- Testing/TestControlAccess.cc | 20 ++++++++++++++++++++ 4 files changed, 75 insertions(+), 4 deletions(-) diff --git a/Library/Processor/ControlAccess.cc b/Library/Processor/ControlAccess.cc index 673a6d6..8069c4d 100644 --- a/Library/Processor/ControlAccess.cc +++ b/Library/Processor/ControlAccess.cc @@ -7,6 +7,9 @@ #include "ControlAccess.hh" +#include +#include + namespace Nymph { @@ -18,11 +21,32 @@ namespace Nymph ControlAccess::ControlAccess() : - fReturn( new ReturnBuffer< int >() ) + fReturn( new ReturnBuffer< int >() ), + fMutex(), + fCondVar(), + fBreakFlag( false ), + fCycleTimeMS( 500 ) {} ControlAccess::~ControlAccess() {} + void ControlAccess::Resume() + { + boost::unique_lock< boost::mutex > lock( fMutex ); + fBreakFlag.store( false ); + fCondVar.notify_one(); + } + + void ControlAccess::Break() + { + boost::unique_lock< boost::mutex > lock( fMutex ); + fBreakFlag.store( true ); + while( fBreakFlag.load() && ! is_canceled() ) + { + fCondVar.wait_for( lock, boost::chrono::milliseconds(fCycleTimeMS) ); + } + } + } /* namespace Nymph */ diff --git a/Library/Processor/ControlAccess.hh b/Library/Processor/ControlAccess.hh index 13296bc..90a768a 100644 --- a/Library/Processor/ControlAccess.hh +++ b/Library/Processor/ControlAccess.hh @@ -8,6 +8,13 @@ #ifndef NYMPH_CONTROLACCESS_HH_ #define NYMPH_CONTROLACCESS_HH_ +#include "MemberVariable.hh" + +#include "cancelable.hh" + +#include +#include + #include #include @@ -58,7 +65,7 @@ namespace Nymph } }; - class ControlAccess + class ControlAccess : public scarab::cancelable { public: ControlAccess(); @@ -73,6 +80,16 @@ namespace Nymph protected: std::shared_ptr< ReturnBufferBase > fReturn; + + public: + void Break(); // called by this thread + void Resume(); // called by user thread + + MEMVAR_REF( boost::mutex, Mutex ); + MEMVAR_REF( boost::condition_variable, CondVar ); + MEMVAR_ATOMIC_NOSET( bool, BreakFlag ); + MEMVAR( unsigned, CycleTimeMS ); + }; diff --git a/Library/Processor/Signal.hh b/Library/Processor/Signal.hh index 64025d7..27109b7 100644 --- a/Library/Processor/Signal.hh +++ b/Library/Processor/Signal.hh @@ -51,6 +51,8 @@ namespace Nymph // calls all connected functions void Emit( XArgs... args ); void operator()( XArgs... args ); + + MEMVAR( bool, DoBreakpoint ); }; @@ -108,13 +110,15 @@ namespace Nymph template< typename... XArgs > Signal< XArgs... >::Signal( const std::string& name ) : - SignalBase( name ) + SignalBase( name ), + fDoBreakpoint( false ) {} template< typename... XArgs > template< typename XOwner > inline Signal< XArgs... >::Signal( const std::string& name, XOwner* owner ) : - SignalBase( name ) + SignalBase( name ), + fDoBreakpoint( false ) { owner->RegisterSignal( name, this ); } @@ -168,6 +172,12 @@ namespace Nymph template< typename... XArgs > inline void Signal< XArgs... >::operator()( XArgs... args ) { + if( fDoBreakpoint ) + { + fControl->SetReturn< XArgs... >( args... ); + fControl->Break(); // waits for resume or exit + } + for( auto connection : fConnections ) { static_cast< Slot< XArgs... >* >(connection)->operator()( fControl, args... ); diff --git a/Testing/TestControlAccess.cc b/Testing/TestControlAccess.cc index 039e0cd..fbbe650 100644 --- a/Testing/TestControlAccess.cc +++ b/Testing/TestControlAccess.cc @@ -8,6 +8,8 @@ #include "ControlAccess.hh" +#include + #include "catch.hpp" @@ -40,4 +42,22 @@ TEST_CASE( "control_access", "[control_access]" ) REQUIRE( std::get< 1 >(control.GetReturn< int, double >()) == return2 ); } + SECTION( "Break" ) + { + std::thread thread( [&](){ + control.Break(); + } ); + + std::this_thread::sleep_for( std::chrono::milliseconds(100) ); + REQUIRE( control.GetBreakFlag() ); + + control.Resume(); + std::this_thread::sleep_for( std::chrono::milliseconds(100) ); + REQUIRE_FALSE( control.GetBreakFlag() ); + + thread.join(); + + REQUIRE_FALSE( control.GetBreakFlag() ); + } + } \ No newline at end of file From c669fbda23420272560358a6f2a9918c43e81613 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Wed, 25 Sep 2019 01:12:14 -0700 Subject: [PATCH 149/521] Some formatting changes --- Library/Processor/ProcessorToolbox.cc | 985 ++++++++++++++++++++++++++ Library/Processor/ProcessorToolbox.hh | 338 +++++++++ 2 files changed, 1323 insertions(+) create mode 100644 Library/Processor/ProcessorToolbox.cc create mode 100644 Library/Processor/ProcessorToolbox.hh diff --git a/Library/Processor/ProcessorToolbox.cc b/Library/Processor/ProcessorToolbox.cc new file mode 100644 index 0000000..371fbac --- /dev/null +++ b/Library/Processor/ProcessorToolbox.cc @@ -0,0 +1,985 @@ +/* + * ProcessorToolbox.cc + * + * Created on: Sep 27, 2012 + * Author: N.S. Oblath + */ + +#include "ProcessorToolbox.hh" + +#include "Exception.hh" +#include "Logger.hh" +#include "PrimaryProcessor.hh" + +#include "factory.hh" +#include "param_codec.hh" + +#include +#include + +using std::deque; +using std::set; +using std::string; +using std::vector; + +namespace Nymph +{ + LOGGER(proclog, "ProcessorToolbox"); + + ProcessorToolbox::ProcessorToolbox( const std::string& name ) : + fProcFactory( scarab::factory< Processor, const std::string& >::get_instance() ), + fRunSingleThreaded( false ), + fRunQueue(), + fProcMap(), + fThreadReferences(), + fContinueCV(), + fDoContinue( false ), + fBreakContMutex(), + fDoRunThread( nullptr ), + fDoRunPromise(), + fDoRunBreakFlag( false ) + { + } + + ProcessorToolbox::~ProcessorToolbox() + { + CancelThreads(); + + JoinRunThread(); + + ClearProcessors(); + } + + bool ProcessorToolbox::Configure( const scarab::param_node& node ) + { + LPROG(proclog, "Configuring . . ."); + + SetRunSingleThreaded( node.get_value( "single-threaded", fRunSingleThreaded ) ); + + // Deal with "processor" blocks + if( ! node.has("processors") ) + { + LWARN(proclog, "No processors were specified"); + } + else + { + const scarab::param_array& procArray = node["processors"].as_array(); + for( scarab::param_array::const_iterator procIt = procArray.begin(); procIt != procArray.end(); ++procIt ) + { + if( ! procIt->is_node() ) + { + LERROR( proclog, "Invalid processor entry (not a node): " << *procIt ); + return false; + } + const scarab::param_node& procNode = procIt->as_node(); + + if (! procNode.has("type")) + { + LERROR(proclog, "Unable to create processor: no processor type given"); + return false; + } + string procType = procNode["type"]().as_string(); + + string procName; + if (! procNode.has("name")) + { + LINFO(proclog, "No name given for processor of type <" << procType << ">; using type as name."); + procName = procType; + } + else + { + procName = procNode["name"]().as_string(); + } + std::shared_ptr< Processor > newProc ( fProcFactory->create(procType, procType)); + if (newProc == NULL) + { + LERROR(proclog, "Unable to create processor of type <" << procType << ">"); + return false; + } + + if (! AddProcessor(procName, newProc)) + { + LERROR(proclog, "Unable to add processor <" << procName << ">"); + //delete newProc; //not required for smart pointers + return false; + } + } + } + + + // Then deal with connections" + if (! node.has("connections")) + { + LWARN(proclog, "No connections were specified"); + } + else + { + const scarab::param_array& connArray = node["connections"].as_array(); + for( scarab::param_array::const_iterator connIt = connArray.begin(); connIt != connArray.end(); ++connIt ) + { + if( ! connIt->is_node() ) + { + LERROR( proclog, "Invalid connection entry: not a node" ); + return false; + } + const scarab::param_node& connNode = connIt->as_node(); + + if ( ! connNode.has("signal") || ! connNode.has("slot") ) + { + LERROR(proclog, "Signal/Slot connection information is incomplete!"); + if (connNode.has("signal")) + { + LWARN(proclog, "signal = " << connNode["signal"]()); + } + else + { + LERROR(proclog, "signal = MISSING"); + } + + if (connNode.has("slot")) + { + LWARN(proclog, "slot = " << connNode["slot"]()); + } + else + { + LERROR(proclog, "slot = MISSING"); + } + return false; + } + + bool connReturn = false; + if (connNode.has("order")) + { + connReturn = MakeConnection(connNode["signal"]().as_string(), connNode["slot"]().as_string(), connNode["order"]().as_int()); + } + else + { + connReturn = MakeConnection(connNode["signal"]().as_string(), connNode["slot"]().as_string()); + } + if (! connReturn) + { + LERROR(proclog, "Unable to make connection <" << connNode["signal"]() << "> --> <" << connNode["slot"]() << ">"); + return false; + } + + if (connNode.has("breakpoint")) + { + if (! SetBreakpoint(connNode["slot"]().as_string())) + { + LERROR(proclog, "Unable to set breakpoint on <" << connNode["slot"]()); + return false; + } + } + + LINFO(proclog, "Signal <" << connNode["signal"]() << "> connected to slot <" << connNode["slot"]() << ">"); + } + } + + + // Finally, deal with processor-run specifications + // The run queue is an array of processor names, or groups of names, which will be run sequentially. + // If names are grouped (in another array), those in that group will be run in parallel. + // In single threaded mode all threads will be run sequentially in the order they were specified. + if (! node.has("run-queue")) + { + LWARN(proclog, "Run queue was not specified"); + } + else + { + const scarab::param_array& rqArray = node["run-queue"].as_array(); + for (scarab::param_array::const_iterator rqIt = rqArray.begin(); rqIt != rqArray.end(); ++rqIt) + { + if (rqIt->is_value()) + { + if (! PushBackToRunQueue((*rqIt)().as_string())) + { + LERROR(proclog, "Unable to process run-queue entry: could not add processor to the queue"); + return false; + } + } + else if (rqIt->is_array()) + { + const scarab::param_array* rqNode = &( rqIt->as_array() ); + std::vector< std::string > names; + + for (scarab::param_array::const_iterator rqArrayIt = rqNode->begin(); rqArrayIt != rqNode->end(); ++rqArrayIt) + { + if (! rqArrayIt->is_value()) + { + LERROR(proclog, "Invalid run-queue array entry: not a value"); + return false; + } + names.push_back((*rqArrayIt)().as_string()); + } + + if (! PushBackToRunQueue(names)) + { + LERROR(proclog, "Unable to process run-queue entry: could not add list of processors to the queue"); + return false; + } + } + else + { + LERROR(proclog, "Invalid run-queue entry: not a value or array"); + return false; + } + } + } + + return true; + } + + bool ProcessorToolbox::ConfigureProcessors( const scarab::param_node& node ) + { + for( ProcMapIt iter = fProcMap.begin(); iter != fProcMap.end(); ++iter ) + { + LDEBUG( proclog, "Attempting to configure processor <" << iter->first << ">" ); + string procName = iter->first; + string nameUsed(procName); + if( ! node.has(nameUsed) ) + { + nameUsed = iter->second.fProc->GetConfigName(); + if( ! node.has(nameUsed) ) + { + LWARN( proclog, "Did not find a parameter node <" << procName << "> or <" << nameUsed << ">\n" + "\tProcessor <" << procName << "> was not configured." ); + continue; + } + } + const scarab::param_node& subNode = node[nameUsed].as_node(); + if( ! iter->second.fProc->Configure(subNode) ) + { + LERROR( proclog, "An error occurred while configuring processor <" << procName << "> with parameter node <" << nameUsed << ">" ); + return false; + } + } + return true; + } + + bool ProcessorToolbox::ConfigureProcessors( const std::string& config ) + { + scarab::param_translator translator; + scarab::param_node optNode; + optNode.add( "encoding", new scarab::param_value( "json" ) ); + return ConfigureProcessors( translator.read_string( config, optNode )->as_node() ); + } + + std::shared_ptr< Processor > ProcessorToolbox::GetProcessor( const std::string& procName ) + { + ProcMapIt it = fProcMap.find( procName ); + if( it == fProcMap.end() ) + { + LWARN( proclog, "Processor <" << procName << "> was not found." ); + return NULL; + } + return it->second.fProc; + } + + const std::shared_ptr< Processor > ProcessorToolbox::GetProcessor( const std::string& procName ) const + { + ProcMapCIt it = fProcMap.find( procName ); + if (it == fProcMap.end()) + { + LWARN( proclog, "Processor <" << procName << "> was not found." ); + return NULL; + } + return it->second.fProc; + } + + bool ProcessorToolbox::AddProcessor( const std::string& procName, std::shared_ptr< Processor > proc ) + { + ProcMapIt it = fProcMap.find( procName); + if( it == fProcMap.end() ) + { + ProcessorInfo pInfo; + pInfo.fProc = proc; + fProcMap.insert( ProcMapValue(procName, pInfo) ); + LDEBUG( proclog, "Added processor <" << procName << "> (a.k.a. " << proc->GetConfigName() << ")" ); + return true; + } + LWARN( proclog, "Processor <" << procName << "> already exists; new processor was not added." ); + return false; + } + + bool ProcessorToolbox::AddProcessor( const std::string& procType, const std::string& procName ) + { + ProcMapIt it = fProcMap.find( procName ); + if( it == fProcMap.end() ) + { + std::shared_ptr< Processor > newProc ( fProcFactory->create(procType, procType) ); + if( newProc == NULL ) + { + LERROR( proclog, "Unable to create processor of type <" << procType << ">" ); + return false; + } + if( ! AddProcessor(procName, newProc) ) + { + LERROR( proclog, "Unable to add processor <" << procName << ">" ); + //delete newProc; + return false; + } + return true; + } + LWARN( proclog, "Processor <" << procName << "> already exists; new processor was not added." ); + return false; + } + + bool ProcessorToolbox::RemoveProcessor( const std::string& procName ) + { + std::shared_ptr< Processor > procToRemove = ReleaseProcessor( procName ); + if( procToRemove == NULL ) + { + return false; + } + //delete procToRemove; + LDEBUG( proclog, "Processor <" << procName << "> deleted." ); + return true; + } + + std::shared_ptr< Processor > ProcessorToolbox::ReleaseProcessor( const std::string& procName + { + ProcMapIt it = fProcMap.find(p rocName ); + if( it == fProcMap.end() ) + { + LWARN( proclog, "Processor <" << procName << "> was not found." ); + return NULL; + } + std::shared_ptr< Processor > procToRelease = it->second.fProc; + fProcMap.erase( it ); + return procToRelease; + } + + void ProcessorToolbox::ClearProcessors() + { + /*for (ProcMapIt it = fProcMap.begin(); it != fProcMap.end(); it++) + { + delete it->second.fProc; + }*/ //not required for smart pointers + fProcMap.clear(); + fRunQueue.clear(); + return; + } + + + bool ProcessorToolbox::MakeConnection( const std::string& signal, const std::string& slot, int order ) + { + string signalProcName, signalName; + if( ! ParseSignalSlotName( signal, signalProcName, signalName ) ) + { + LERROR( proclog, "Unable to parse signal name: <" << signal << ">" ); + return false; + } + + string slotProcName, slotName; + if( ! ParseSignalSlotName( slot, slotProcName, slotName ) ) + { + LERROR( proclog, "Unable to parse slot name: <" << slot << ">" ); + return false; + } + + return MakeConnection( signalProcName, signalName, slotProcName, slotName, order ); + } + + bool ProcessorToolbox::MakeConnection( const std::string& signalProcName, const std::string& signalName, const std::string& slotProcName, const std::string& slotName, int order ) + { + std::shared_ptr< Processor > signalProc = GetProcessor( signalProcName ); + if( signalProc == nullptr ) + { + LERROR(proclog, "Processor named <" << signalProcName << "> was not found!"); + return false; + } + + std::shared_ptr< Processor > slotProc = GetProcessor( slotProcName ); + if( slotProc == nullptr ) + { + LERROR( proclog, "Processor named <" << slotProcName << "> was not found!" ); + return false; + } + + try + { + if( order != std::numeric_limits< int >::min() ) + { + signalProc->ConnectASlot( signalName, *slotProc.get(), slotName, order ); + } + else + { + signalProc->ConnectASlot(signalName, *slotProc.get(), slotName); + } + } + catch (boost::exception& e) + { + LERROR( proclog, "An error occurred while connecting signals and slots:\n" + << "\tSignal " << signalName << " from processor " << signalProcName << " (a.k.a. " << signalProc->GetConfigName() << ")" << '\n' + << "\tSlot " << slotName << " from processor " << slotProcName << " (a.k.a. " << slotProc->GetConfigName() << ")" << '\n' + << '\t' << diagnostic_information( e ) ); + return false; + } + + return true; + } + + bool ProcessorToolbox::SetBreakpoint( const std::string& slot ) + { + string slotProcName, slotName; + if(! ParseSignalSlotName( slot, slotProcName, slotName ) ) + { + LERROR(proclog, "Unable to parse slot name: <" << slot << ">"); + return false; + } + + return SetBreakpoint( slotProcName, slotName ); + } + + bool ProcessorToolbox::SetBreakpoint( const std::string& slotProcName, const std::string& slotName ) + { + std::shared_ptr< Processor > slotProc = GetProcessor( slotProcName ); + if( slotProc == nullptr ) + { + LERROR( proclog, "Processor named <" << slotProcName << "> was not found!" ); + return false; + } + + try + { + slotProc->SetDoBreakpoint( slotName, true ); + return true; + } + catch( boost::exception& e ) + { + LERROR( proclog, "Unable to set breakpoint: " << diagnostic_information( e ) ); + return false; + } + } + + bool ProcessorToolbox::RemoveBreakpoint( const std::string& slot ) + { + string slotProcName, slotName; + if( ! ParseSignalSlotName( slot, slotProcName, slotName ) ) + { + LERROR( proclog, "Unable to parse slot name: <" << slot << ">" ); + return false; + } + + return RemoveBreakpoint( slotProcName, slotName ); + } + + bool ProcessorToolbox::RemoveBreakpoint( const std::string& slotProcName, const std::string& slotName ) + { + std::shared_ptr< Processor > slotProc = GetProcessor( slotProcName ); + if( slotProc == nullptr ) + { + LERROR(proclog, "Processor named <" << slotProcName << "> was not found!"); + return false; + } + + try + { + slotProc->SetDoBreakpoint( slotName, false ); + return true; + } + catch( boost::exception& e ) + { + LERROR( proclog, "Unable to set breakpoint: " << diagnostic_information( e ) ); + return false; + } + } + + bool ProcessorToolbox::ParseSignalSlotName( const std::string& toParse, std::string& nameOfProc, std::string& nameOfSigSlot ) const + { + size_t sepPos = toParse.find_first_of( fSigSlotNameSep ); + if( sepPos == string::npos ) + { + LERROR( proclog, "Unable to find separator between processor and signal/slot name in <" << toParse << ">" ); + return false; + } + nameOfProc = toParse.substr( 0, sepPos ); + nameOfSigSlot = toParse.substr( sepPos + 1 ); + return true; + } + + + bool ProcessorToolbox::PushBackToRunQueue( const std::string& name ) + { + ThreadGroup threadGroup; + + if( ! AddProcessorToThreadGroup( name, threadGroup ) ) + { + LERROR( proclog, "Unable to add processor <" << name << "> to thread group" ); + return false; + } + + fRunQueue.push_back( threadGroup ); + + LINFO( proclog, "Added processor <" << name << "> to the run queue" ); + return true; + } + + bool ProcessorToolbox::PushBackToRunQueue( std::initializer_list< std::string > names ) + { + return PushBackToRunQueue( std::vector< std::string >(names) ); + } + + bool ProcessorToolbox::PushBackToRunQueue( std::vector< std::string > names ) + { + ThreadGroup threadGroup; + + std::stringstream toPrint; + for( const std::string& name : names ) + { + if(! AddProcessorToThreadGroup( name, threadGroup ) ) + { + LERROR( proclog, "Unable to add processor <" << name << "> to thread group" ); + return false; + } + toPrint << name << ", "; // the extra comma at the end is removed below + } + + fRunQueue.push_back( threadGroup ); + std::string toPrintString = toPrint.str(); + toPrintString.resize( toPrintString.size() - 2 ); + LINFO( proclog, "Added processors <" << toPrintString << "> to the run queue" ); + return true; + } + + bool ProcessorToolbox::AddProcessorToThreadGroup( const std::string& name, ThreadGroup& group ) + { + std::shared_ptr< Processor > procForRunQueue = GetProcessor( name ); + LDEBUG( proclog, "Attempting to add processor <" << name << "> to the run queue" ); + if( procForRunQueue == nullptr ) + { + LERROR( proclog, "Unable to find processor <" << name << "> requested for the run queue" ); + return false; + } + + PrimaryProcessor* primaryProc = dynamic_cast< PrimaryProcessor* >( procForRunQueue.get() ); + if( primaryProc == nullptr ) + { + LERROR( proclog, "Processor <" << name << "> is not a primary processor." ); + return false; + } + //group.insert(primaryProc); + group.insert( Thread(primaryProc, name) ); + return true; + } + + void ProcessorToolbox::AsyncRun() + { + if( fDoRunThread != nullptr ) + { + LERROR( proclog, "It appears that a run has already been started" ); + return; + } + + fDoRunPromise = boost::promise< void >(); + fDoRunFuture = fDoRunPromise.get_future().share(); + + bool willRunSingleThreaded = fRunSingleThreaded; +#ifdef SINGLETHREADED + willRunSingleThreaded = true; +#endif + + if( willRunSingleThreaded ) + { + StartSingleThreadedRun(); + } + else + { + StartMultiThreadedRun(); + } + + return; + } + + void ProcessorToolbox::StartSingleThreadedRun() + { + auto singleThreadRun = [&]() + { + try + { + LPROG( proclog, "Starting single-threaded processing" ); + + for (RunQueue::iterator rqIter = fRunQueue.begin(); rqIter != fRunQueue.end(); ++rqIter) + { + for (ThreadGroup::iterator tgIter = rqIter->begin(); tgIter != rqIter->end(); ++tgIter) + { + boost_unique_lock breakContLock( fBreakContMutex ); + + std::string procName( tgIter->fName ); + LINFO( proclog, "Starting processor <" << procName << ">" ); + + std::shared_ptr< KTThreadReference > thisThreadRef = std::make_shared< KTThreadReference >(); + thisThreadRef->Name() = procName; + + thisThreadRef->SetInitiateBreakFunc( [&](){ this->InitiateBreak(); } ); + thisThreadRef->SetWaitForContinueFunc( [&]( boost_unique_lock& lock ){ this->WaitForContinue( lock ); } ); + + fThreadReferences.push_back( thisThreadRef ); + + boost::condition_variable threadStartedCV; + boost::mutex threadStartedMutex; + bool threadStartedFlag = false; + + boost_unique_lock threadStartedLock( threadStartedMutex ); + boost::thread thread( [&](){ tgIter->fProc->operator()( thisThreadRef, threadStartedCV, threadStartedFlag ); } ); + KTDEBUG( proclog, "Thread ID is <" << thread.get_id() << ">; waiting for thread start" ); + while( ! threadStartedFlag ) + { + threadStartedCV.wait( threadStartedLock ); + } + KTDEBUG( proclog, "Thread has started" ); + + KTDEBUG( proclog, "Thread ID is <" << thread.get_id() << ">" ); + + bool stillRunning = true; // determines behavior that depends on whether a return from the thread was temporary or from the thread completing + do + { + boost::future_status status; + do + { + status = fThreadReferences.back()->GetDataPtrRetFuture().wait_for( boost::chrono::milliseconds(500) ); + } while (status != boost::future_status::ready); + + stillRunning = false; + if( fThreadReferences.back()->GetBreakFlag() ) + { + KTDEBUG( proclog, "Breakpoint reached (seen first in thread <" << procName << ">; may not be where breakpoint is set)" ); + + WaitForContinue( breakContLock ); + + KTDEBUG( proclog, "Breakpoint finished" ); + stillRunning = true; + } + else + { + try + { + fThreadReferences.back()->GetReturnValue(); + LINFO( proclog, "Thread <" << procName << "> has finished" ); + fThreadReferences.pop_back(); + } + catch( boost::exception& e ) + { + e << KTErrorMsgInfo< struct procTB_STRFinishing >( "There was an error while finishing thread <" + procName + "> and retrieving its results" ); + throw; + } + stillRunning = false; + } + } while( stillRunning ); + + LINFO( proclog, "Processor <" << procName << "> has finished" ); + + thread.join(); + fThreadReferences.clear(); + } // end for loop over the thread group + } // end for loop over the run-queue + + LPROG( proclog, "Processing is complete (single-threaded)" ); + } + catch( std::exception& e ) + { + // exceptions thrown in this function or from within processors will end up here + LERROR( proclog, "Caught std::exception thrown in a processor or in the single-threaded run function: " << e.what() ); + LWARN( proclog, "Setting boost::exception of do-run-promise in StartSingleThreadedRun" ); + fDoRunPromise.set_exception( boost::current_exception() ); + return; + } + catch( boost::exception& e ) + { + // exceptions thrown in this function or from within processors will end up here + LERROR( proclog, "Caught boost::exception thrown in a processor or in the single-threaded run function" ); + LWARN( proclog, "Setting boost::exception of do-run-promise in StartSingleThreadedRun" ); + fDoRunPromise.set_exception( boost::current_exception() ); + return; + } + fDoRunPromise.set_value(); + return; + }; // end single-threaded run lambda + + fDoRunThread = new boost::thread( singleThreadRun ); + return; + } + void ProcessorToolbox::StartMultiThreadedRun() + { + auto multiThreadRun = [&]() + { + try + { + LPROG( proclog, "Starting multi-threaded processing" ); + + for (RunQueue::iterator rqIter = fRunQueue.begin(); rqIter != fRunQueue.end(); ++rqIter) + { + boost::thread_group threads; + + { // scope for threadFuturesLock + boost_unique_lock breakContLock( fBreakContMutex ); + //boost_unique_lock threadFuturesLock( fThreadReferencesMutex ); + + for (ThreadGroup::iterator tgIter = rqIter->begin(); tgIter != rqIter->end(); ++tgIter) + { + std::string procName( tgIter->fName ); + LINFO( proclog, "Starting processor <" << procName << ">" ); + + std::shared_ptr< KTThreadReference > thisThreadRef = std::make_shared< KTThreadReference >(); + thisThreadRef->Name() = procName; + + thisThreadRef->SetInitiateBreakFunc( [&](){ this->InitiateBreak(); } ); + thisThreadRef->SetWaitForContinueFunc( [&]( boost_unique_lock& lock ){ this->WaitForContinue( lock ); } ); + fThreadReferences.push_back( thisThreadRef ); + + boost::condition_variable threadStartedCV; + boost::mutex threadStartedMutex; + bool threadStartedFlag = false; + + boost_unique_lock threadStartedLock( threadStartedMutex ); + boost::thread* thisThread = new boost::thread( [&](){ tgIter->fProc->operator()( thisThreadRef, threadStartedCV, threadStartedFlag ); } ); + KTDEBUG( proclog, "Thread ID is <" << thisThread->get_id() << ">; waiting for thread start" ); + while( ! threadStartedFlag ) + { + threadStartedCV.wait( threadStartedLock ); + } + KTDEBUG( proclog, "Thread has started" ); + + threads.add_thread( thisThread ); + + }// end for loop over the thread group + } // end scope for threadFuturesLock + + bool stillRunning = true; // determines behavior that depends on whether a return from the thread was temporary or from the thread completing + do + { + auto finishedFuturePtr = boost::wait_for_any( KTThreadRefFutureIterator(fThreadReferences.begin()), KTThreadRefFutureIterator(fThreadReferences.end()) ); + boost_unique_lock breakContLock( fBreakContMutex ); + + size_t iThread = finishedFuturePtr - KTThreadRefFutureIterator(fThreadReferences.begin()); + auto finishedReferencePtr = fThreadReferences.begin() + iThread; + std::string threadName( (*finishedReferencePtr)->Name() ); + KTDEBUG( proclog, "Thread <" << iThread << " (" << threadName << ") > has stopped for some reason" ); + + stillRunning = false; + if( fDoRunBreakFlag ) + { + // a breakpoint has been reached + KTDEBUG( proclog, "Breakpoint reached (seen first in thread <" << threadName << ">; may not be where breakpoint is set)" ); + + // wait here for the user to continue + WaitForContinue( breakContLock ); + + KTDEBUG( proclog, "Breakpoint finished" ); + stillRunning = true; + //continueSignal = fMasterContSignal; // refresh the local copy of the shared future + } + else + { + // we're finished a thread; get its results + try + { + LINFO( proclog, "Thread <" << threadName << "> has finished" ); + finishedFuturePtr->get(); + fThreadReferences.erase( finishedReferencePtr ); + } + catch( boost::exception& e ) + { + e << KTErrorMsgInfo< struct procTB_MTRFinishing >( "There was an error while finishing thread <" + threadName + "> and retrieving its results" ); + throw; + } + + if( fThreadReferences.empty() ) stillRunning = false; + else stillRunning = true; + } + } while( stillRunning ); + + KTDEBUG( proclog, "Joining threads" ); + threads.join_all(); + boost_unique_lock breakContLock( fBreakContMutex ); + fThreadReferences.clear(); + } // end for loop over the run-queue + + LPROG( proclog, "Processing is complete (multi-threaded)" ); + } + catch( std::exception& e ) + { + // exceptions thrown in this function or from within processors will end up here + LERROR( proclog, "Caught std::exception thrown in a processor or in the multi-threaded run function: " << e.what() ); + LWARN( proclog, "Setting boost::exception of do-run-promise in StartMultiThreadedRun" ); + fDoRunPromise.set_exception( boost::current_exception() ); + return; + } + catch( boost::exception& e ) + { + // exceptions thrown in this function or from within processors will end up here + LERROR( proclog, "Caught boost::exception thrown in a processor or in the multi-threaded run function" ); + LWARN( proclog, "Setting boost::exception of do-run-promise in StartMultiThreadedRun" ); + fDoRunPromise.set_exception( boost::current_exception() ); + return; + } + LWARN( proclog, "Setting value of do-run-promise in StartMultiThreadedRun" ); + fDoRunPromise.set_value(); + return; + }; // end multi-threaded run lambda + + fDoRunThread = new boost::thread( multiThreadRun ); + return; + } + + + bool ProcessorToolbox::WaitForBreak() + { + boost_unique_lock breakContLock( fBreakContMutex ); + + if( fDoRunBreakFlag ) + { + LWARN( proclog, "Can't wait for a break; Already at a breakpoint" ); + return true; + } + + boost::shared_future< void > doRunFuture = fDoRunFuture; + if( ! doRunFuture.valid() ) + { + BOOST_THROW_EXCEPTION( KTException() << "Cannot wait for a break in the current state (the \"DoRun\" future does not have a valid shared state)" << eom ); + } + + breakContLock.unlock(); + + // block here until there's a break + doRunFuture.wait(); + + if( fDoRunBreakFlag ) + { + KTDEBUG( proclog, "Breakpoint reached (the wait is over)" ); + return true; + } + + try + { + doRunFuture.get(); + KTDEBUG( proclog, "End-of-run reached (the wait-for-break is over)" ); + return false; + } + catch( boost::exception& e ) + { + LERROR( proclog, "An error occurred during processing: " << boost::diagnostic_information( e ) ); + return false; + } + } + + void ProcessorToolbox::WaitForEndOfRun() + { + // WaitForBreak() and WaitForContinue() throw boost::exception for problems with the future or promise objects + + KTDEBUG( proclog, "Waiting for end-of-run" ); + while( WaitForBreak() ) + { + KTDEBUG( proclog, "Reached breakpoint; waiting for continue" ); + boost::mutex localMutex; + boost_unique_lock localLock( localMutex ); + WaitForContinue( localLock ); + KTDEBUG( proclog, "Processing resuming; waiting for end-of-run" ); + } + KTDEBUG( proclog, "End-of-run reached" ); + + return; + } + + void ProcessorToolbox::Continue() + { + if( ! fDoRunBreakFlag ) + { + LWARN( proclog, "Not currently at a breakpoint" ); + return; + } + + boost_unique_lock breakContLock( fBreakContMutex ); + + // reset all break flags + fDoRunBreakFlag = false; + std::vector< boost_unique_lock > trLocks; + for( auto trIt = fThreadReferences.begin(); trIt != fThreadReferences.end(); ++trIt ) + { + trLocks.emplace_back( (*trIt)->Mutex() ); + (*trIt)->SetBreakFlag( false ); + (*trIt)->RefreshDataPtrRet(); + } + + // reset the do-run promise and future + fDoRunPromise = boost::promise< void >(); + fDoRunFuture = fDoRunPromise.get_future().share(); + + LINFO( proclog, "Continuing from breakpoint" ); + // signal everything to resume + fDoContinue = true; + fContinueCV.notify_all(); + + return; + } + + KTDataHandle ProcessorToolbox::GetData( const std::string& threadName ) + { + //boost_unique_lock threadFuturesLock( fThreadReferencesMutex ); + boost_unique_lock breakContLock( fBreakContMutex ); + + auto trIt = fThreadReferences.begin(); + for( ; trIt != fThreadReferences.end(); ++trIt ) + { + if( (*trIt)->Name() == threadName ) break; + } + if( trIt == fThreadReferences.end() ) + { + LWARN( proclog, "Did not find thread <" << threadName << ">" ); + BOOST_THROW_EXCEPTION( KTException() << "Did not find thread <" << threadName << ">" << eom ); + } + + boost_unique_lock lock( (*trIt)->Mutex() ); + return (*trIt)->GetReturnValue(); + } + + void ProcessorToolbox::InitiateBreak() + { + boost_unique_lock breakContLock( fBreakContMutex ); + if( fDoRunBreakFlag ) return; + + // set the continue flag to false so that things will wait for the continue + fDoContinue = false; + + // set all break flags + // master break flag + fDoRunBreakFlag = true; + // thread break flags + for( auto trIt = fThreadReferences.begin(); trIt != fThreadReferences.end(); ++trIt ) + { + boost_unique_lock lock( (*trIt)->Mutex() ); + (*trIt)->SetBreakFlag( true ); + } + + // use the do-run promise to signal the break + LWARN( proclog, "Setting value of do-run-promise" ); + fDoRunPromise.set_value(); + + return; + } + + void ProcessorToolbox::CancelThreads() + { + boost_unique_lock breakContLock( fBreakContMutex ); + for( auto trIt = fThreadReferences.begin(); trIt != fThreadReferences.end(); ++trIt ) + { + boost_unique_lock lock( (*trIt)->Mutex() ); + (*trIt)->SetCanceled( true ); + } + return; + } + + bool ProcessorToolbox::Run() + { + // can throw boost::exception + + AsyncRun(); + + WaitForEndOfRun(); + + JoinRunThread(); + + return true; + } + +} /* namespace Nymph */ diff --git a/Library/Processor/ProcessorToolbox.hh b/Library/Processor/ProcessorToolbox.hh new file mode 100644 index 0000000..6ac45a8 --- /dev/null +++ b/Library/Processor/ProcessorToolbox.hh @@ -0,0 +1,338 @@ +/** + @file ProcessorToolbox.hh + @brief Contains ProcessorToolbox + @details Manages processors requested by the user at run time. + @author: N. S. Oblath + @date: Sep 27, 2012 + */ + +#ifndef NYMPH_PROCESSORTOOLBOX_HH_ +#define NYMPH_PROCESSORTOOLBOX_HH_ + +#include "MemberVariable.hh" +//#include "KTThreadReference.hh" + +#include "factory.hh" +#include "param.hh" + +#define BOOST_THREAD_PROVIDES_FUTURE +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + + +namespace Nymph +{ + class PrimaryProcessor; + class Processor; + + /*! + @class ProcessorToolbox + @author N. S. Oblath + + @brief Manages processors requested by the user at run time. + + @details + ProcessorToolbox allows the user to setup an application at runtime. + + The user chooses the processors to be used, how they're linked with signals and slots, and what is used to "run" + the program via a configuration file. + + While this does result in longer configuration files, it drastically simplifies the space of executables that are needed. + + The following order should be used for configuring the processor toolbox: +
        +
      1. Create processors
      2. +
      3. Connect signals and slots
      4. +
      5. Create the run queue
      6. +
      + + Available (nested) configuration values: +
        +
      • run-single-threaded (bool) -- specify whether to run in single-threaded mode (will be ignored if the application has been compiled with the SINGLETHREADED flag set) +
      • processors (array of objects) -- create a processor; each object in the array should consist of: +
          +
        • type -- string specifying the processor type (matches the string given to the Registrar, which should be specified before the class implementation in each processor's .cc file).
        • +
        • name -- string giving the individual processor a name so that multiple processors of the same type can be created.
        • +
        +
      • +
      • connection (array of objects) -- connect a signal to a slot; each object should consist of: +
          +
        • signal -- proc-name:signal-name; name (i.e. the name given in the array of processors above) of the processor, and the signal that will be emitted.
        • +
        • slot -- proc-name:slot-name
        • ; name of the processor with the slot that will receive the signal. +
        • group-order -- (optional) integer specifying the order in which slots should be called. +
        +
      • +
      • run-queue -- (array of strings and arrays of strings) define the queue of processors that will control the running of Nymph. + The elements of this array specify processors that are run sequentially. + If an element is itself an array, those processors listed in the sub-array will be run in parallel. +
          +
        • processor name -- add a processor to the run queue, or
        • +
        • array of processor names -- add a group of processors to the run queue.
        • +
        + In single-threaded mode, all processors will be run sequentially, in the order specified. +
      • +
      + */ + class ProcessorToolbox + { + private: + typedef boost::unique_lock< boost::mutex > boost_unique_lock; + + public: + ProcessorToolbox( const std::string& name = "processor-toolbox" ); + virtual ~ProcessorToolbox(); + + private: + scarab::factory< Processor, const std::string& >* fProcFactory; // singleton; not owned by ProcessorToolbox + + + public: + /// Configure the toolbox: create the processors; connnect signals and slots; and setup the run queue. + bool Configure( const scarab::param_node& node ); + + /// Configure processors (only those specified in the toolbox) + bool ConfigureProcessors( const scarab::param_node& node ); + + MEMVAR( bool, RunSingleThreaded ); + + private: + struct ProcessorInfo + { + std::shared_ptr< Processor > fProc; + }; + typedef std::map< std::string, ProcessorInfo > ProcessorMap; + typedef ProcessorMap::iterator ProcMapIt; + typedef ProcessorMap::const_iterator ProcMapCIt; + typedef ProcessorMap::value_type ProcMapValue; + + public: + /// Get a pointer to a processor in the toolbox + std::shared_ptr< Processor > GetProcessor( const std::string& procName ); + /// Get a pointer to a processor in the toolbox + const std::shared_ptr< Processor > GetProcessor( const std::string& procName ) const; + + /// Add a processor to the toolbox + /// Toolbox takes ownership of the processor + bool AddProcessor( const std::string& procName, std::shared_ptr< Processor > proc ); + bool AddProcessor( const std::string& procType, const std::string& procName ); + + /// Remove a processor from the toolbox + bool RemoveProcessor( const std::string& procName ); + + /// Remove a processor from the toolbox and return it to the user + /// Ownership is passed to the user + std::shared_ptr< Processor > ReleaseProcessor( const std::string& procName ); + + /// Remove all processors from the toolbox + /// Also clears the run queue + void ClearProcessors(); + + private: + ProcessorMap fProcMap; + + + public: + // for the MakeConnection overloading, extra overloading is used instead of default parameters so that the python interface works + + /// Make a connection between the signal from one processor and the slot from another processor + /// Both processors should already have been added to the Toolbox + /// Signal and slot strings should be formatted as: [processor name]:[signal/slot name] + bool MakeConnection(const std::string& signal, const std::string& slot, int order); + bool MakeConnection(const std::string& signal, const std::string& slot); + + /// Make a connection between the signal from one processor and the slot from another processor + /// Both processors should already have been added to the Toolbox + bool MakeConnection(const std::string& signalProcName, const std::string& signalName, const std::string& slotProcName, const std::string& slotName, int order); + bool MakeConnection(const std::string& signalProcName, const std::string& signalName, const std::string& slotProcName, const std::string& slotName); + + /// Set a breakpoint on a slot + /// Slot string should be formatted as: [processor name]:[slot name] + bool SetBreakpoint( const std::string& slot ); + /// Set a breakpoint on a slot + bool SetBreakpoint( const std::string& slotProcName, const std::string& slotName ); + + /// Remove a breakpoint from a slot + /// Slot string should be formatted as: [processor name]:[slot name] + bool RemoveBreakpoint( const std::string& slot ); + /// Remove a breakpoint from a slot + bool RemoveBreakpoint( const std::string& slotProcName, const std::string& slotName ); + + private: + bool ParseSignalSlotName( const std::string& toParse, std::string& nameOfProc, std::string& nameOfSigSlot ) const; + static const char fSigSlotNameSep = ':'; + + + public: + /// Push a single processor to the back of the run queue + bool PushBackToRunQueue( const std::string& name ); + + /// Push a set of processors to be run in parallel to the back of the run queue + bool PushBackToRunQueue( std::initializer_list< std::string > names ); + /// Push a set of processors to be run in parallel to the back of the run queue + bool PushBackToRunQueue( std::vector< std::string > names ); + + /// Remove the last item in the run queue, whether it's a single processor or a group of processors + void PopBackOfRunQueue(); + + /// Clear the run queue + void ClearRunQueue(); + + private: + struct Thread + { + PrimaryProcessor* fProc; + std::string fName; + Thread( PrimaryProcessor* proc, const std::string& name ) : + fProc(proc), fName(name) + {} + }; + struct CompareThread + { + bool operator()( const Thread& lhs, const Thread& rhs ) const + { + return lhs.fProc < rhs.fProc; + } + }; + typedef std::set< Thread, CompareThread > ThreadGroup; + typedef std::deque< ThreadGroup > RunQueue; + bool AddProcessorToThreadGroup( const std::string& name, ThreadGroup& group ); + + RunQueue fRunQueue; + + public: + /// Process the run queue. + /// This will call Run() on all of the processors in the queue. + bool Run(); + + void AsyncRun(); + + void WaitForContinue( boost_unique_lock& lock ); + + /// Returns when processing is completed or a breakpoint is reached + /// Throws a boost::exception if there's an error with the future object in use + /// If the return is true, processing can continue after the break + /// If the return is false, processing has ended (either normally or due to an error) + bool WaitForBreak(); + + void WaitForEndOfRun(); + + void Continue(); + + void CancelThreads(); + + void JoinRunThread(); + + KTDataHandle GetData( const std::string& threadName ); + + private: + friend class KTThreadReference; + + typedef boost::shared_future< KTDataHandle > Future; + + void StartSingleThreadedRun(); + void StartMultiThreadedRun(); + + // called from KTThreadReference::Break + void InitiateBreak(); + + std::vector< std::shared_ptr< KTThreadReference > > fThreadReferences; + + boost::condition_variable fContinueCV; + bool fDoContinue; + boost::mutex fBreakContMutex; + + boost::thread* fDoRunThread; + boost::promise< void > fDoRunPromise; + boost::shared_future< void > fDoRunFuture; + bool fDoRunBreakFlag; + + }; + + + template< class Value, class IIterator > + class KTThreadRefFutureIter : public boost::iterator_adaptor< KTThreadRefFutureIter< Value, IIterator >, IIterator, Value, boost::random_access_traversal_tag > + { + private: + // used for the conversion constructor below + struct enabler {}; + + public: + KTThreadRefFutureIter() : + KTThreadRefFutureIter::iterator_adaptor_() + {} + KTThreadRefFutureIter( const IIterator& other ) : + KTThreadRefFutureIter::iterator_adaptor_( other ) + {} + + // converts from Iterator to ConstIterator, but the enable_if business prevents converting from ConstIterator to Iterator + template< class OtherValue, class OtherIIterator > + KTThreadRefFutureIter( const KTThreadRefFutureIter< OtherValue, OtherIIterator > & other, typename boost::enable_if< boost::is_convertible< OtherValue, Value >, enabler >::type = enabler() ) : + KTThreadRefFutureIter::iterator_adaptor_( other.base ) + {} + + private: + friend class boost::iterator_core_access; + + Value& dereference() const + { + return (*(this->base_reference()))->GetDataPtrRetFuture(); + } + }; + + typedef KTThreadRefFutureIter< boost::unique_future< KTDataHandle >, std::vector< std::shared_ptr< KTThreadReference > >::iterator > KTThreadRefFutureIterator; + typedef KTThreadRefFutureIter< const boost::unique_future< KTDataHandle >, std::vector< std::shared_ptr< KTThreadReference > >::const_iterator > KTThreadRefFutureConstIterator; + + + inline bool ProcessorToolbox::MakeConnection(const std::string& signal, const std::string& slot) + { + return MakeConnection(signal, slot, std::numeric_limits< int >::min()); + } + + inline bool ProcessorToolbox::MakeConnection(const std::string& signalProcName, const std::string& signalName, const std::string& slotProcName, const std::string& slotName) + { + return MakeConnection(signalProcName, signalName, slotProcName, slotName, std::numeric_limits< int >::min()); + } + + inline void ProcessorToolbox::PopBackOfRunQueue() + { + fRunQueue.pop_back(); + return; + } + + inline void ProcessorToolbox::ClearRunQueue() + { + fRunQueue.clear(); + return; + } + + inline void ProcessorToolbox::WaitForContinue( boost_unique_lock& lock ) + { + //fMasterContSignal.wait(); + while( ! fDoContinue ) + { + fContinueCV.wait( lock ); + } + return; + } + + inline void ProcessorToolbox::JoinRunThread() + { + if( fDoRunThread == nullptr ) return; + fDoRunThread->join(); + delete fDoRunThread; + fDoRunThread = nullptr; + } + +} /* namespace Nymph */ +#endif /* NYMPH_PROCESSORTOOLBOX_HH_ */ From 69a33b10185e0d4f7d824344e441fb73536758a4 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Sat, 28 Sep 2019 00:38:11 -0700 Subject: [PATCH 150/521] Progress --- Library/CMakeLists.txt | 2 + Library/Processor/Processor.hh | 4 +- Library/Processor/ProcessorToolbox.cc | 68 ++++++++++++--------------- Library/Processor/ProcessorToolbox.hh | 37 ++++++++------- Library/Processor/Signal.hh | 8 +--- Library/Processor/SignalSlotBase.cc | 3 +- Library/Processor/SignalSlotBase.hh | 2 + 7 files changed, 59 insertions(+), 65 deletions(-) diff --git a/Library/CMakeLists.txt b/Library/CMakeLists.txt index bd3fee4..83c75ff 100644 --- a/Library/CMakeLists.txt +++ b/Library/CMakeLists.txt @@ -16,6 +16,7 @@ set( NYMPH_HEADERFILES ${PROC_DIR}/ControlAccess.hh ${PROC_DIR}/PrimaryProcessor.hh ${PROC_DIR}/Processor.hh + ${PROC_DIR}/ProcessorToolbox.hh ${PROC_DIR}/SignalSlotBase.hh ) @@ -25,6 +26,7 @@ set( NYMPH_SOURCEFILES ${PROC_DIR}/ControlAccess.cc ${PROC_DIR}/PrimaryProcessor.cc ${PROC_DIR}/Processor.cc + ${PROC_DIR}/ProcessorToolbox.cc ${PROC_DIR}/SignalSlotBase.cc ) diff --git a/Library/Processor/Processor.hh b/Library/Processor/Processor.hh index 46f7856..168ff9c 100644 --- a/Library/Processor/Processor.hh +++ b/Library/Processor/Processor.hh @@ -58,8 +58,8 @@ namespace Nymph /// Register a slot object with this processor void RegisterSlot( std::string name, SlotBase* slot, std::initializer_list< std::string > signals = {} ); - //bool GetDoBreakpoint( const std::string& slotName ); - //void SetDoBreakpoint( const std::string& slotName, bool flag ); + bool GetDoBreakpoint( const std::string& slotName ); + void SetDoBreakpoint( const std::string& slotName, bool flag ); MEMVAR_REF( std::string, Name ); diff --git a/Library/Processor/ProcessorToolbox.cc b/Library/Processor/ProcessorToolbox.cc index 371fbac..5e551ff 100644 --- a/Library/Processor/ProcessorToolbox.cc +++ b/Library/Processor/ProcessorToolbox.cc @@ -8,10 +8,10 @@ #include "ProcessorToolbox.hh" #include "Exception.hh" -#include "Logger.hh" #include "PrimaryProcessor.hh" #include "factory.hh" +#include "logger.hh" #include "param_codec.hh" #include @@ -30,22 +30,22 @@ namespace Nymph fProcFactory( scarab::factory< Processor, const std::string& >::get_instance() ), fRunSingleThreaded( false ), fRunQueue(), - fProcMap(), + fProcMap()/*, fThreadReferences(), fContinueCV(), fDoContinue( false ), fBreakContMutex(), fDoRunThread( nullptr ), fDoRunPromise(), - fDoRunBreakFlag( false ) + fDoRunBreakFlag( false )*/ { } ProcessorToolbox::~ProcessorToolbox() { - CancelThreads(); + //CancelThreads(); - JoinRunThread(); + //JoinRunThread(); ClearProcessors(); } @@ -238,7 +238,7 @@ namespace Nymph string nameUsed(procName); if( ! node.has(nameUsed) ) { - nameUsed = iter->second.fProc->GetConfigName(); + nameUsed = iter->second.fProc->Name(); if( ! node.has(nameUsed) ) { LWARN( proclog, "Did not find a parameter node <" << procName << "> or <" << nameUsed << ">\n" @@ -256,14 +256,6 @@ namespace Nymph return true; } - bool ProcessorToolbox::ConfigureProcessors( const std::string& config ) - { - scarab::param_translator translator; - scarab::param_node optNode; - optNode.add( "encoding", new scarab::param_value( "json" ) ); - return ConfigureProcessors( translator.read_string( config, optNode )->as_node() ); - } - std::shared_ptr< Processor > ProcessorToolbox::GetProcessor( const std::string& procName ) { ProcMapIt it = fProcMap.find( procName ); @@ -336,9 +328,9 @@ namespace Nymph return true; } - std::shared_ptr< Processor > ProcessorToolbox::ReleaseProcessor( const std::string& procName + std::shared_ptr< Processor > ProcessorToolbox::ReleaseProcessor( const std::string& procName ) { - ProcMapIt it = fProcMap.find(p rocName ); + ProcMapIt it = fProcMap.find( procName ); if( it == fProcMap.end() ) { LWARN( proclog, "Processor <" << procName << "> was not found." ); @@ -419,30 +411,30 @@ namespace Nymph return true; } - bool ProcessorToolbox::SetBreakpoint( const std::string& slot ) + bool ProcessorToolbox::SetBreakpoint( const std::string& signal ) { - string slotProcName, slotName; - if(! ParseSignalSlotName( slot, slotProcName, slotName ) ) + string signalProcName, signalName; + if(! ParseSignalSlotName( signal, signalProcName, signalName ) ) { - LERROR(proclog, "Unable to parse slot name: <" << slot << ">"); + LERROR(proclog, "Unable to parse signal name: <" << signal << ">"); return false; } - return SetBreakpoint( slotProcName, slotName ); + return SetBreakpoint( signalProcName, signalName ); } - bool ProcessorToolbox::SetBreakpoint( const std::string& slotProcName, const std::string& slotName ) + bool ProcessorToolbox::SetBreakpoint( const std::string& signalProcName, const std::string& signalName ) { - std::shared_ptr< Processor > slotProc = GetProcessor( slotProcName ); - if( slotProc == nullptr ) + std::shared_ptr< Processor > signalProc = GetProcessor( signalProcName ); + if( signalProc == nullptr ) { - LERROR( proclog, "Processor named <" << slotProcName << "> was not found!" ); + LERROR( proclog, "Processor named <" << signalProcName << "> was not found!" ); return false; } try { - slotProc->SetDoBreakpoint( slotName, true ); + signalProc->SetDoBreakpoint( signalName, true ); return true; } catch( boost::exception& e ) @@ -452,30 +444,30 @@ namespace Nymph } } - bool ProcessorToolbox::RemoveBreakpoint( const std::string& slot ) + bool ProcessorToolbox::RemoveBreakpoint( const std::string& signal ) { - string slotProcName, slotName; - if( ! ParseSignalSlotName( slot, slotProcName, slotName ) ) + string signalProcName, signalName; + if( ! ParseSignalSlotName( signal, signalProcName, signalName ) ) { - LERROR( proclog, "Unable to parse slot name: <" << slot << ">" ); + LERROR( proclog, "Unable to parse signal name: <" << signal << ">" ); return false; } - return RemoveBreakpoint( slotProcName, slotName ); + return RemoveBreakpoint( signalProcName, signalName ); } - bool ProcessorToolbox::RemoveBreakpoint( const std::string& slotProcName, const std::string& slotName ) + bool ProcessorToolbox::RemoveBreakpoint( const std::string& signalProcName, const std::string& signalName ) { - std::shared_ptr< Processor > slotProc = GetProcessor( slotProcName ); - if( slotProc == nullptr ) + std::shared_ptr< Processor > signalProc = GetProcessor( signalProcName ); + if( signalProc == nullptr ) { - LERROR(proclog, "Processor named <" << slotProcName << "> was not found!"); + LERROR(proclog, "Processor named <" << signalProcName << "> was not found!"); return false; } try { - slotProc->SetDoBreakpoint( slotName, false ); + signalProc->SetDoBreakpoint( signalName, false ); return true; } catch( boost::exception& e ) @@ -562,7 +554,7 @@ namespace Nymph group.insert( Thread(primaryProc, name) ); return true; } - +/* void ProcessorToolbox::AsyncRun() { if( fDoRunThread != nullptr ) @@ -981,5 +973,5 @@ namespace Nymph return true; } - +*/ } /* namespace Nymph */ diff --git a/Library/Processor/ProcessorToolbox.hh b/Library/Processor/ProcessorToolbox.hh index 6ac45a8..2889a85 100644 --- a/Library/Processor/ProcessorToolbox.hh +++ b/Library/Processor/ProcessorToolbox.hh @@ -156,17 +156,17 @@ namespace Nymph bool MakeConnection(const std::string& signalProcName, const std::string& signalName, const std::string& slotProcName, const std::string& slotName, int order); bool MakeConnection(const std::string& signalProcName, const std::string& signalName, const std::string& slotProcName, const std::string& slotName); - /// Set a breakpoint on a slot - /// Slot string should be formatted as: [processor name]:[slot name] - bool SetBreakpoint( const std::string& slot ); - /// Set a breakpoint on a slot - bool SetBreakpoint( const std::string& slotProcName, const std::string& slotName ); - - /// Remove a breakpoint from a slot - /// Slot string should be formatted as: [processor name]:[slot name] - bool RemoveBreakpoint( const std::string& slot ); - /// Remove a breakpoint from a slot - bool RemoveBreakpoint( const std::string& slotProcName, const std::string& slotName ); + /// Set a breakpoint on a signal + /// Slot string should be formatted as: [processor name]:[signal name] + bool SetBreakpoint( const std::string& signal ); + /// Set a breakpoint on a signal + bool SetBreakpoint( const std::string& signalProcName, const std::string& signalName ); + + /// Remove a breakpoint from a signal + /// Slot string should be formatted as: [processor name]:[signal name] + bool RemoveBreakpoint( const std::string& signal ); + /// Remove a breakpoint from a signal + bool RemoveBreakpoint( const std::string& signalProcName, const std::string& signalName ); private: bool ParseSignalSlotName( const std::string& toParse, std::string& nameOfProc, std::string& nameOfSigSlot ) const; @@ -206,10 +206,11 @@ namespace Nymph }; typedef std::set< Thread, CompareThread > ThreadGroup; typedef std::deque< ThreadGroup > RunQueue; - bool AddProcessorToThreadGroup( const std::string& name, ThreadGroup& group ); - RunQueue fRunQueue; + bool AddProcessorToThreadGroup( const std::string& name, ThreadGroup& group ); +/* + public: /// Process the run queue. /// This will call Run() on all of the processors in the queue. @@ -256,10 +257,10 @@ namespace Nymph boost::promise< void > fDoRunPromise; boost::shared_future< void > fDoRunFuture; bool fDoRunBreakFlag; - +*/ }; - +/* template< class Value, class IIterator > class KTThreadRefFutureIter : public boost::iterator_adaptor< KTThreadRefFutureIter< Value, IIterator >, IIterator, Value, boost::random_access_traversal_tag > { @@ -292,7 +293,7 @@ namespace Nymph typedef KTThreadRefFutureIter< boost::unique_future< KTDataHandle >, std::vector< std::shared_ptr< KTThreadReference > >::iterator > KTThreadRefFutureIterator; typedef KTThreadRefFutureIter< const boost::unique_future< KTDataHandle >, std::vector< std::shared_ptr< KTThreadReference > >::const_iterator > KTThreadRefFutureConstIterator; - +*/ inline bool ProcessorToolbox::MakeConnection(const std::string& signal, const std::string& slot) { @@ -315,7 +316,7 @@ namespace Nymph fRunQueue.clear(); return; } - +/* inline void ProcessorToolbox::WaitForContinue( boost_unique_lock& lock ) { //fMasterContSignal.wait(); @@ -333,6 +334,6 @@ namespace Nymph delete fDoRunThread; fDoRunThread = nullptr; } - +*/ } /* namespace Nymph */ #endif /* NYMPH_PROCESSORTOOLBOX_HH_ */ diff --git a/Library/Processor/Signal.hh b/Library/Processor/Signal.hh index 27109b7..1a2ffd1 100644 --- a/Library/Processor/Signal.hh +++ b/Library/Processor/Signal.hh @@ -51,8 +51,6 @@ namespace Nymph // calls all connected functions void Emit( XArgs... args ); void operator()( XArgs... args ); - - MEMVAR( bool, DoBreakpoint ); }; @@ -110,15 +108,13 @@ namespace Nymph template< typename... XArgs > Signal< XArgs... >::Signal( const std::string& name ) : - SignalBase( name ), - fDoBreakpoint( false ) + SignalBase( name ) {} template< typename... XArgs > template< typename XOwner > inline Signal< XArgs... >::Signal( const std::string& name, XOwner* owner ) : - SignalBase( name ), - fDoBreakpoint( false ) + SignalBase( name ) { owner->RegisterSignal( name, this ); } diff --git a/Library/Processor/SignalSlotBase.cc b/Library/Processor/SignalSlotBase.cc index b5529d9..bcdba67 100644 --- a/Library/Processor/SignalSlotBase.cc +++ b/Library/Processor/SignalSlotBase.cc @@ -30,7 +30,8 @@ namespace Nymph SignalBase::SignalBase( const std::string& name ) : fName( name ), fConnections(), - fControl( nullptr ) + fControl( nullptr ), + fDoBreakpoint( false ) {} SignalBase::~SignalBase() diff --git a/Library/Processor/SignalSlotBase.hh b/Library/Processor/SignalSlotBase.hh index 2168dfc..69a33ea 100644 --- a/Library/Processor/SignalSlotBase.hh +++ b/Library/Processor/SignalSlotBase.hh @@ -73,6 +73,8 @@ namespace Nymph MEMVAR( ControlAccess*, Control ); // doesn't use MEMVAR_PTR because Signal doesn't own the object pointed to by fControl + MEMVAR( bool, DoBreakpoint ); + protected: friend class SignalBase; virtual void AddConnection( SlotBase* slot, int group ); From ad5bbf84cb76b039b32c9230f325fcacec8fe777 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Wed, 16 Oct 2019 00:30:43 -0700 Subject: [PATCH 151/521] Toolbox progress --- Library/Processor/Processor.cc | 14 ++++++++------ Library/Processor/ProcessorToolbox.cc | 10 +++++----- Library/Processor/ProcessorToolbox.hh | 12 ++++++------ 3 files changed, 19 insertions(+), 17 deletions(-) diff --git a/Library/Processor/Processor.cc b/Library/Processor/Processor.cc index 4a56b47..6d5c7b1 100644 --- a/Library/Processor/Processor.cc +++ b/Library/Processor/Processor.cc @@ -128,13 +128,15 @@ namespace Nymph return; } -/* - bool Processor::GetDoBreakpoint( const std::string& slotName ) + + bool Processor::GetDoBreakpoint( const std::string& signalName ) { - KTSlotBase* slot = GetSlot(slotName); - if (slot != nullptr) + if( fSignals.count( signalName ) != 0 ) + { + SignalBase* signal = fSignals.at(signalName); + if (signal != nullptr) { - return slot->GetDoBreakpoint(); + return signal->GetDoBreakpoint(); } BOOST_THROW_EXCEPTION( KTException() << "Slot <" << slotName << "> was not found" << eom ); return false; @@ -150,5 +152,5 @@ namespace Nymph BOOST_THROW_EXCEPTION( KTException() << "Slot <" << slotName << "> was not found" << eom ); return; } -*/ + } /* namespace Nymph */ diff --git a/Library/Processor/ProcessorToolbox.cc b/Library/Processor/ProcessorToolbox.cc index 5e551ff..da630f6 100644 --- a/Library/Processor/ProcessorToolbox.cc +++ b/Library/Processor/ProcessorToolbox.cc @@ -14,8 +14,8 @@ #include "logger.hh" #include "param_codec.hh" -#include -#include +//#include +//#include using std::deque; using std::set; @@ -286,7 +286,7 @@ namespace Nymph ProcessorInfo pInfo; pInfo.fProc = proc; fProcMap.insert( ProcMapValue(procName, pInfo) ); - LDEBUG( proclog, "Added processor <" << procName << "> (a.k.a. " << proc->GetConfigName() << ")" ); + LDEBUG( proclog, "Added processor <" << procName << "> (a.k.a. " << proc->Name() << ")" ); return true; } LWARN( proclog, "Processor <" << procName << "> already exists; new processor was not added." ); @@ -402,8 +402,8 @@ namespace Nymph catch (boost::exception& e) { LERROR( proclog, "An error occurred while connecting signals and slots:\n" - << "\tSignal " << signalName << " from processor " << signalProcName << " (a.k.a. " << signalProc->GetConfigName() << ")" << '\n' - << "\tSlot " << slotName << " from processor " << slotProcName << " (a.k.a. " << slotProc->GetConfigName() << ")" << '\n' + << "\tSignal " << signalName << " from processor " << signalProcName << " (a.k.a. " << signalProc->Name() << ")" << '\n' + << "\tSlot " << slotName << " from processor " << slotProcName << " (a.k.a. " << slotProc->Name() << ")" << '\n' << '\t' << diagnostic_information( e ) ); return false; } diff --git a/Library/Processor/ProcessorToolbox.hh b/Library/Processor/ProcessorToolbox.hh index 2889a85..598b6b1 100644 --- a/Library/Processor/ProcessorToolbox.hh +++ b/Library/Processor/ProcessorToolbox.hh @@ -15,14 +15,14 @@ #include "factory.hh" #include "param.hh" -#define BOOST_THREAD_PROVIDES_FUTURE -#include +//#define BOOST_THREAD_PROVIDES_FUTURE +//#include #include -#include +//#include -#include -#include -#include +//#include +//#include +//#include #include #include From 33d667ae29f07253c1af56a048e491e225c6a0d9 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Wed, 16 Oct 2019 10:18:34 -0700 Subject: [PATCH 152/521] Switch to the standard threading library --- Library/Processor/ControlAccess.cc | 6 +++--- Library/Processor/ControlAccess.hh | 10 ++++++---- Library/Processor/Processor.cc | 18 +++++++++--------- Library/Processor/Processor.hh | 4 ++-- Library/Processor/ProcessorToolbox.cc | 7 ++++++- Library/Processor/ProcessorToolbox.hh | 4 ++-- 6 files changed, 28 insertions(+), 21 deletions(-) diff --git a/Library/Processor/ControlAccess.cc b/Library/Processor/ControlAccess.cc index 8069c4d..f4943fe 100644 --- a/Library/Processor/ControlAccess.cc +++ b/Library/Processor/ControlAccess.cc @@ -33,18 +33,18 @@ namespace Nymph void ControlAccess::Resume() { - boost::unique_lock< boost::mutex > lock( fMutex ); + std::unique_lock< std::mutex > lock( fMutex ); fBreakFlag.store( false ); fCondVar.notify_one(); } void ControlAccess::Break() { - boost::unique_lock< boost::mutex > lock( fMutex ); + std::unique_lock< std::mutex > lock( fMutex ); fBreakFlag.store( true ); while( fBreakFlag.load() && ! is_canceled() ) { - fCondVar.wait_for( lock, boost::chrono::milliseconds(fCycleTimeMS) ); + fCondVar.wait_for( lock, std::chrono::milliseconds(fCycleTimeMS) ); } } diff --git a/Library/Processor/ControlAccess.hh b/Library/Processor/ControlAccess.hh index 90a768a..6dc6a85 100644 --- a/Library/Processor/ControlAccess.hh +++ b/Library/Processor/ControlAccess.hh @@ -12,10 +12,12 @@ #include "cancelable.hh" -#include -#include +//#include +//#include +#include #include +#include #include namespace Nymph @@ -85,8 +87,8 @@ namespace Nymph void Break(); // called by this thread void Resume(); // called by user thread - MEMVAR_REF( boost::mutex, Mutex ); - MEMVAR_REF( boost::condition_variable, CondVar ); + MEMVAR_REF( std::mutex, Mutex ); + MEMVAR_REF( std::condition_variable, CondVar ); MEMVAR_ATOMIC_NOSET( bool, BreakFlag ); MEMVAR( unsigned, CycleTimeMS ); diff --git a/Library/Processor/Processor.cc b/Library/Processor/Processor.cc index 6d5c7b1..21df8a4 100644 --- a/Library/Processor/Processor.cc +++ b/Library/Processor/Processor.cc @@ -7,6 +7,8 @@ #include "Processor.hh" +#include "Exception.hh" + #include namespace Nymph @@ -131,25 +133,23 @@ namespace Nymph bool Processor::GetDoBreakpoint( const std::string& signalName ) { - if( fSignals.count( signalName ) != 0 ) - { - SignalBase* signal = fSignals.at(signalName); + SignalBase* signal = fSignals.at(signalName ); if (signal != nullptr) { return signal->GetDoBreakpoint(); } - BOOST_THROW_EXCEPTION( KTException() << "Slot <" << slotName << "> was not found" << eom ); + BOOST_THROW_EXCEPTION( Exception() << "Signal <" << signalName << "> was not found" << eom ); return false; } - void Processor::SetDoBreakpoint( const std::string& slotName, bool flag ) + void Processor::SetDoBreakpoint( const std::string& signalName, bool flag ) { - KTSlotBase* slot = GetSlot(slotName); - if (slot != nullptr) + SignalBase* signal = fSignals.at(signalName ); + if( signal != nullptr ) { - return slot->SetDoBreakpoint(flag); + return signal->SetDoBreakpoint( flag ); } - BOOST_THROW_EXCEPTION( KTException() << "Slot <" << slotName << "> was not found" << eom ); + BOOST_THROW_EXCEPTION( Exception() << "Signal <" << signalName << "> was not found" << eom ); return; } diff --git a/Library/Processor/Processor.hh b/Library/Processor/Processor.hh index 168ff9c..045c655 100644 --- a/Library/Processor/Processor.hh +++ b/Library/Processor/Processor.hh @@ -58,8 +58,8 @@ namespace Nymph /// Register a slot object with this processor void RegisterSlot( std::string name, SlotBase* slot, std::initializer_list< std::string > signals = {} ); - bool GetDoBreakpoint( const std::string& slotName ); - void SetDoBreakpoint( const std::string& slotName, bool flag ); + bool GetDoBreakpoint( const std::string& signalName ); + void SetDoBreakpoint( const std::string& signalName, bool flag ); MEMVAR_REF( std::string, Name ); diff --git a/Library/Processor/ProcessorToolbox.cc b/Library/Processor/ProcessorToolbox.cc index da630f6..a35c30e 100644 --- a/Library/Processor/ProcessorToolbox.cc +++ b/Library/Processor/ProcessorToolbox.cc @@ -247,9 +247,14 @@ namespace Nymph } } const scarab::param_node& subNode = node[nameUsed].as_node(); - if( ! iter->second.fProc->Configure(subNode) ) + try + { + iter->second.fProc->Configure(subNode); + } + catch( const Exception& e ) { LERROR( proclog, "An error occurred while configuring processor <" << procName << "> with parameter node <" << nameUsed << ">" ); + LERROR( proclog, e.what() ); return false; } } diff --git a/Library/Processor/ProcessorToolbox.hh b/Library/Processor/ProcessorToolbox.hh index 598b6b1..d3d639c 100644 --- a/Library/Processor/ProcessorToolbox.hh +++ b/Library/Processor/ProcessorToolbox.hh @@ -17,7 +17,7 @@ //#define BOOST_THREAD_PROVIDES_FUTURE //#include -#include +//#include //#include //#include @@ -87,7 +87,7 @@ namespace Nymph class ProcessorToolbox { private: - typedef boost::unique_lock< boost::mutex > boost_unique_lock; + typedef std::unique_lock< std::mutex > unique_lock; public: ProcessorToolbox( const std::string& name = "processor-toolbox" ); From 69f4f50a8b532e1fbcff1bf582e58135972b21c1 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Thu, 17 Oct 2019 10:02:19 -0700 Subject: [PATCH 153/521] Interim commit, processor toolbox execution --- Library/Processor/ProcessorToolbox.cc | 47 ++++++++++++++------------- Library/Processor/ProcessorToolbox.hh | 18 +++++----- 2 files changed, 33 insertions(+), 32 deletions(-) diff --git a/Library/Processor/ProcessorToolbox.cc b/Library/Processor/ProcessorToolbox.cc index a35c30e..39f3119 100644 --- a/Library/Processor/ProcessorToolbox.cc +++ b/Library/Processor/ProcessorToolbox.cc @@ -498,7 +498,7 @@ namespace Nymph bool ProcessorToolbox::PushBackToRunQueue( const std::string& name ) { - ThreadGroup threadGroup; + ThreadSourceGroup threadGroup; if( ! AddProcessorToThreadGroup( name, threadGroup ) ) { @@ -519,7 +519,7 @@ namespace Nymph bool ProcessorToolbox::PushBackToRunQueue( std::vector< std::string > names ) { - ThreadGroup threadGroup; + ThreadSourceGroup threadGroup; std::stringstream toPrint; for( const std::string& name : names ) @@ -539,7 +539,7 @@ namespace Nymph return true; } - bool ProcessorToolbox::AddProcessorToThreadGroup( const std::string& name, ThreadGroup& group ) + bool ProcessorToolbox::AddProcessorToThreadGroup( const std::string& name, ThreadSourceGroup& group ) { std::shared_ptr< Processor > procForRunQueue = GetProcessor( name ); LDEBUG( proclog, "Attempting to add processor <" << name << "> to the run queue" ); @@ -556,10 +556,10 @@ namespace Nymph return false; } //group.insert(primaryProc); - group.insert( Thread(primaryProc, name) ); + group.insert( ThreadSource(primaryProc, name) ); return true; } -/* + void ProcessorToolbox::AsyncRun() { if( fDoRunThread != nullptr ) @@ -696,6 +696,7 @@ namespace Nymph fDoRunThread = new boost::thread( singleThreadRun ); return; } + void ProcessorToolbox::StartMultiThreadedRun() { auto multiThreadRun = [&]() @@ -712,30 +713,30 @@ namespace Nymph boost_unique_lock breakContLock( fBreakContMutex ); //boost_unique_lock threadFuturesLock( fThreadReferencesMutex ); - for (ThreadGroup::iterator tgIter = rqIter->begin(); tgIter != rqIter->end(); ++tgIter) + for (ThreadSourceGroup::iterator tgIter = rqIter->begin(); tgIter != rqIter->end(); ++tgIter) { std::string procName( tgIter->fName ); LINFO( proclog, "Starting processor <" << procName << ">" ); - std::shared_ptr< KTThreadReference > thisThreadRef = std::make_shared< KTThreadReference >(); - thisThreadRef->Name() = procName; + //std::shared_ptr< KTThreadReference > thisThreadRef = std::make_shared< KTThreadReference >(); + //thisThreadRef->Name() = procName; - thisThreadRef->SetInitiateBreakFunc( [&](){ this->InitiateBreak(); } ); - thisThreadRef->SetWaitForContinueFunc( [&]( boost_unique_lock& lock ){ this->WaitForContinue( lock ); } ); - fThreadReferences.push_back( thisThreadRef ); + //thisThreadRef->SetInitiateBreakFunc( [&](){ this->InitiateBreak(); } ); + //thisThreadRef->SetWaitForContinueFunc( [&]( boost_unique_lock& lock ){ this->WaitForContinue( lock ); } ); + //fThreadReferences.push_back( thisThreadRef ); - boost::condition_variable threadStartedCV; - boost::mutex threadStartedMutex; - bool threadStartedFlag = false; + //boost::condition_variable threadStartedCV; + //boost::mutex threadStartedMutex; + //bool threadStartedFlag = false; - boost_unique_lock threadStartedLock( threadStartedMutex ); - boost::thread* thisThread = new boost::thread( [&](){ tgIter->fProc->operator()( thisThreadRef, threadStartedCV, threadStartedFlag ); } ); - KTDEBUG( proclog, "Thread ID is <" << thisThread->get_id() << ">; waiting for thread start" ); - while( ! threadStartedFlag ) - { - threadStartedCV.wait( threadStartedLock ); - } - KTDEBUG( proclog, "Thread has started" ); + //boost_unique_lock threadStartedLock( threadStartedMutex ); + //boost::thread* thisThread = new boost::thread( [&](){ tgIter->fProc->operator()( thisThreadRef, threadStartedCV, threadStartedFlag ); } ); + //KTDEBUG( proclog, "Thread ID is <" << thisThread->get_id() << ">; waiting for thread start" ); + //while( ! threadStartedFlag ) + //{ + // threadStartedCV.wait( threadStartedLock ); + //} + //KTDEBUG( proclog, "Thread has started" ); threads.add_thread( thisThread ); @@ -978,5 +979,5 @@ namespace Nymph return true; } -*/ + } /* namespace Nymph */ diff --git a/Library/Processor/ProcessorToolbox.hh b/Library/Processor/ProcessorToolbox.hh index d3d639c..65364ca 100644 --- a/Library/Processor/ProcessorToolbox.hh +++ b/Library/Processor/ProcessorToolbox.hh @@ -189,27 +189,27 @@ namespace Nymph void ClearRunQueue(); private: - struct Thread + struct ThreadSource { PrimaryProcessor* fProc; std::string fName; - Thread( PrimaryProcessor* proc, const std::string& name ) : + ThreadSource( PrimaryProcessor* proc, const std::string& name ) : fProc(proc), fName(name) {} }; - struct CompareThread + struct CompareThreadSource { - bool operator()( const Thread& lhs, const Thread& rhs ) const + bool operator()( const ThreadSource& lhs, const ThreadSource& rhs ) const { return lhs.fProc < rhs.fProc; } }; - typedef std::set< Thread, CompareThread > ThreadGroup; - typedef std::deque< ThreadGroup > RunQueue; + typedef std::set< ThreadSource, CompareThreadSource > ThreadSourceGroup; + typedef std::deque< ThreadSourceGroup > RunQueue; RunQueue fRunQueue; - bool AddProcessorToThreadGroup( const std::string& name, ThreadGroup& group ); -/* + bool AddProcessorToThreadGroup( const std::string& name, ThreadSourceGroup& group ); + public: /// Process the run queue. @@ -257,7 +257,7 @@ namespace Nymph boost::promise< void > fDoRunPromise; boost::shared_future< void > fDoRunFuture; bool fDoRunBreakFlag; -*/ + }; /* From da464c55d3b8bd866f03750f7740cb13d41c461e Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Fri, 18 Oct 2019 11:41:24 -0700 Subject: [PATCH 154/521] Incremental progress on control access, processors, and signals/slots --- Library/Processor/ControlAccess.cc | 72 ++++++++++++++++++++------- Library/Processor/ControlAccess.hh | 38 +++++++++++--- Library/Processor/PrimaryProcessor.cc | 5 +- Library/Processor/PrimaryProcessor.hh | 2 +- Library/Processor/ProcessorToolbox.cc | 5 +- Library/Processor/ProcessorToolbox.hh | 8 +-- Library/Processor/Signal.hh | 8 ++- Library/Processor/Slot.hh | 10 ++-- 8 files changed, 109 insertions(+), 39 deletions(-) diff --git a/Library/Processor/ControlAccess.cc b/Library/Processor/ControlAccess.cc index f4943fe..f85985f 100644 --- a/Library/Processor/ControlAccess.cc +++ b/Library/Processor/ControlAccess.cc @@ -13,40 +13,78 @@ namespace Nymph { - ReturnBufferBase::ReturnBufferBase() - {} - - ReturnBufferBase::~ReturnBufferBase() - {} - - - ControlAccess::ControlAccess() : - fReturn( new ReturnBuffer< int >() ), + SharedControl::SharedControl() : fMutex(), fCondVar(), fBreakFlag( false ), + fCanceledFlag( false ), fCycleTimeMS( 500 ) {} - ControlAccess::~ControlAccess() + SharedContrl::~SharedControl() {} - void ControlAccess::Resume() + void SharedContrl::Break() { std::unique_lock< std::mutex > lock( fMutex ); - fBreakFlag.store( false ); - fCondVar.notify_one(); + fBreakFlag = true; + return; } - void ControlAccess::Break() + void SharedContrl::Cancel() { std::unique_lock< std::mutex > lock( fMutex ); - fBreakFlag.store( true ); - while( fBreakFlag.load() && ! is_canceled() ) + fCanceledFlag = true; + return; + } + + bool SharedContrl::IsAtBreak() const + { + std::unique_lock< std::mutex > lock( fMutex ); + return fBreakFlag; + } + + bool SharedContrl::IsCanceled() const + { + std::unique_lock< std::mutex > lock( fMutex ); + return fCanceledFlag; + } + + bool SharedContrl::WaitToContinue() const + { + std::unique_lock< std::mutex > lock( fMutex ); + if( fBreakFlag ) { - fCondVar.wait_for( lock, std::chrono::milliseconds(fCycleTimeMS) ); + while( fBreakFlag && ! fCanceledFlag ) + { + fCondVar.wait_for( lock, std::chrono::milliseconds(fCycleTimeMS) ); + } } + return ! fCanceled; // returns true if the thread should continue; false if it should end + } + + void SharedContrl::Resume() + { + std::unique_lock< std::mutex > lock( fMutex ); + fBreakFlag = false; + fCondVar.notify_all(); } + + ReturnBufferBase::ReturnBufferBase() + {} + + ReturnBufferBase::~ReturnBufferBase() + {} + + + ControlAccess::ControlAccess() : + fReturn( new ReturnBuffer< int >() ), + fControl() + {} + + ControlAccess::~ControlAccess() + {} + } /* namespace Nymph */ diff --git a/Library/Processor/ControlAccess.hh b/Library/Processor/ControlAccess.hh index 6dc6a85..98252b8 100644 --- a/Library/Processor/ControlAccess.hh +++ b/Library/Processor/ControlAccess.hh @@ -22,6 +22,33 @@ namespace Nymph { + class SharedControl + { + public: + SharedControl(); + virtual ~SharedControl(); + + void Break(); // to be called by a working thread + + void Cancel(); // to be called by a working thread + + bool IsAtBreak() const; // to be called by a working thread + + bool IsCanceled() const; // to be called by a working thread + + // return: true = continue; false = cancel + bool WaitToContinue() const; // to be called by a working thread + + void Resume(); // to be called by the processor toolbox + + MEMVAR_REF( std::mutex, Mutex ); + MEMVAR_REF( std::condition_variable, CondVar ); + MEMVAR_NOSET( bool, BreakFlag ); + MEMVAR_NOSET( bool, CanceledFlag ); + MEMVAR( unsigned, CycleTimeMS ); + + } + class ReturnBufferBase { public: @@ -84,16 +111,11 @@ namespace Nymph std::shared_ptr< ReturnBufferBase > fReturn; public: - void Break(); // called by this thread - void Resume(); // called by user thread - - MEMVAR_REF( std::mutex, Mutex ); - MEMVAR_REF( std::condition_variable, CondVar ); - MEMVAR_ATOMIC_NOSET( bool, BreakFlag ); - MEMVAR( unsigned, CycleTimeMS ); - + MEM_VAR_SHARED_PTR( SharedControl, Control ); }; + typedef std::shared_ptr< ControlAccess > ControlAccessPtr; + template< typename... Args > void ControlAccess::SetReturn( Args&... args ) diff --git a/Library/Processor/PrimaryProcessor.cc b/Library/Processor/PrimaryProcessor.cc index 7c362a1..246cc5f 100644 --- a/Library/Processor/PrimaryProcessor.cc +++ b/Library/Processor/PrimaryProcessor.cc @@ -22,11 +22,12 @@ namespace Nymph PrimaryProcessor::~PrimaryProcessor() {} - void PrimaryProcessor::operator()( ControlAccess* control ) + void PrimaryProcessor::operator()( ControlAccessPtr control ) { + // pass the control access pointer to every signal in the primary processor for( auto signalIt = fSignals.begin(); signalIt != fSignals.end(); ++signalIt ) { - signalIt->second->SetControl( control ); + signalIt->second->SetControlAcc( control ); } // go! diff --git a/Library/Processor/PrimaryProcessor.hh b/Library/Processor/PrimaryProcessor.hh index 9d125b7..45f6530 100644 --- a/Library/Processor/PrimaryProcessor.hh +++ b/Library/Processor/PrimaryProcessor.hh @@ -22,7 +22,7 @@ namespace Nymph public: /// Callable function used by std::thread - void operator()( ControlAccess* control ); + void operator()( ControlAccessPtr control ); /// Starts the main action of the processor virtual bool Run() = 0; diff --git a/Library/Processor/ProcessorToolbox.cc b/Library/Processor/ProcessorToolbox.cc index 39f3119..86da326 100644 --- a/Library/Processor/ProcessorToolbox.cc +++ b/Library/Processor/ProcessorToolbox.cc @@ -30,7 +30,8 @@ namespace Nymph fProcFactory( scarab::factory< Processor, const std::string& >::get_instance() ), fRunSingleThreaded( false ), fRunQueue(), - fProcMap()/*, + fProcMap(), + fControl( new SharedControl() )/*, fThreadReferences(), fContinueCV(), fDoContinue( false ), @@ -718,6 +719,8 @@ namespace Nymph std::string procName( tgIter->fName ); LINFO( proclog, "Starting processor <" << procName << ">" ); + + //std::shared_ptr< KTThreadReference > thisThreadRef = std::make_shared< KTThreadReference >(); //thisThreadRef->Name() = procName; diff --git a/Library/Processor/ProcessorToolbox.hh b/Library/Processor/ProcessorToolbox.hh index 65364ca..577ceee 100644 --- a/Library/Processor/ProcessorToolbox.hh +++ b/Library/Processor/ProcessorToolbox.hh @@ -9,6 +9,7 @@ #ifndef NYMPH_PROCESSORTOOLBOX_HH_ #define NYMPH_PROCESSORTOOLBOX_HH_ +#include "ControlAccess.hh" #include "MemberVariable.hh" //#include "KTThreadReference.hh" @@ -193,8 +194,9 @@ namespace Nymph { PrimaryProcessor* fProc; std::string fName; + ControlAccessPtr fControlAccess; ThreadSource( PrimaryProcessor* proc, const std::string& name ) : - fProc(proc), fName(name) + fProc(proc), fName(name), fControlAccess( new ControlAccess() ) {} }; struct CompareThreadSource @@ -236,9 +238,9 @@ namespace Nymph KTDataHandle GetData( const std::string& threadName ); - private: - friend class KTThreadReference; + MEMVAR_SHARED_PTR_CONST( SharedControl, Control ); + private: typedef boost::shared_future< KTDataHandle > Future; void StartSingleThreadedRun(); diff --git a/Library/Processor/Signal.hh b/Library/Processor/Signal.hh index 1a2ffd1..9f7b08e 100644 --- a/Library/Processor/Signal.hh +++ b/Library/Processor/Signal.hh @@ -34,7 +34,7 @@ namespace Nymph { public: using signature = void( XArgs... ); - using full_signature = void( ControlAccess*, XArgs... ); + using full_signature = void( ControlAccessPtr, XArgs... ); public: /// Unowned signal @@ -51,6 +51,8 @@ namespace Nymph // calls all connected functions void Emit( XArgs... args ); void operator()( XArgs... args ); + + MEMVAR_SHARED_PTR( ControlAccess, ControlAcc ); }; @@ -168,15 +170,17 @@ namespace Nymph template< typename... XArgs > inline void Signal< XArgs... >::operator()( XArgs... args ) { + // TODO: if not canceled and at breakpoint, then set return and break if( fDoBreakpoint ) { fControl->SetReturn< XArgs... >( args... ); fControl->Break(); // waits for resume or exit } + // TODO: if canceled, quit for( auto connection : fConnections ) { - static_cast< Slot< XArgs... >* >(connection)->operator()( fControl, args... ); + static_cast< Slot< XArgs... >* >(connection)->operator()( fControlAcc, args... ); } return; } diff --git a/Library/Processor/Slot.hh b/Library/Processor/Slot.hh index c132f5b..446507b 100644 --- a/Library/Processor/Slot.hh +++ b/Library/Processor/Slot.hh @@ -30,7 +30,7 @@ namespace Nymph { public: using signature = void( XArgs... ); - using full_signature = void( ControlAccess*, XArgs... ); + using full_signature = void( ControlAccessPtr, XArgs... ); using signal_list = std::initializer_list< std::string >; public: @@ -61,14 +61,14 @@ namespace Nymph void operator()( XArgs... args ); /// execute fFunction with a ControlAccess object - void operator()( ControlAccess* access, XArgs... args ); + void operator()( ControlAccessPtr access, XArgs... args ); MEMVAR_REF( boost::function< signature >, Function ); MEMVAR( bool, DoBreakpoint ); protected: - void SlotFuncWrapper( ControlAccess* access, XArgs... args ); + void SlotFuncWrapper( ControlAccessPtr access, XArgs... args ); }; @@ -211,14 +211,14 @@ namespace Nymph } template< typename... XArgs > - inline void Slot< XArgs... >::operator()( ControlAccess* access, XArgs... args ) + inline void Slot< XArgs... >::operator()( ControlAccessPtr access, XArgs... args ) { SlotFuncWrapper( access, args... ); return; } template< typename... XArgs > - inline void Slot< XArgs... >::SlotFuncWrapper( ControlAccess* access, XArgs... args ) + inline void Slot< XArgs... >::SlotFuncWrapper( ControlAccessPtr access, XArgs... args ) { //TODO could do something with `access` here for( auto signalIt = fSignalsUsed.begin(); signalIt != fSignalsUsed.end(); ++signalIt ) From 0378283e7713d9360da14ee5d4e3de89566f9e6a Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Tue, 22 Oct 2019 14:37:50 -0700 Subject: [PATCH 155/521] A lot of preliminary progress in reworking how the processor toolbox and associated classes operate. --- Library/CMakeLists.txt | 3 + Library/Processor/ControlAccess.cc | 53 ++++++++-------- Library/Processor/ControlAccess.hh | 89 ++++++++++++++------------- Library/Processor/PrimaryProcessor.cc | 9 ++- Library/Processor/PrimaryProcessor.hh | 2 +- Library/Processor/Processor.cc | 12 ++-- Library/Processor/Processor.hh | 4 +- Library/Processor/ProcessorToolbox.cc | 56 +++++++++++++---- Library/Processor/QuitThread.hh | 31 ++++++++++ Library/Processor/ReturnBuffer.cc | 19 ++++++ Library/Processor/ReturnBuffer.hh | 63 +++++++++++++++++++ Library/Processor/Signal.hh | 22 +++++-- Library/Processor/SignalSlotBase.cc | 6 +- Library/Processor/SignalSlotBase.hh | 6 +- Library/Processor/Slot.hh | 8 +-- Scarab | 2 +- 16 files changed, 279 insertions(+), 106 deletions(-) create mode 100644 Library/Processor/QuitThread.hh create mode 100644 Library/Processor/ReturnBuffer.cc create mode 100644 Library/Processor/ReturnBuffer.hh diff --git a/Library/CMakeLists.txt b/Library/CMakeLists.txt index 83c75ff..84e6f66 100644 --- a/Library/CMakeLists.txt +++ b/Library/CMakeLists.txt @@ -17,6 +17,8 @@ set( NYMPH_HEADERFILES ${PROC_DIR}/PrimaryProcessor.hh ${PROC_DIR}/Processor.hh ${PROC_DIR}/ProcessorToolbox.hh + ${PROC_DIR}/QuitThread.hh + ${PROC_DIR}/ReturnBuffer.hh ${PROC_DIR}/SignalSlotBase.hh ) @@ -27,6 +29,7 @@ set( NYMPH_SOURCEFILES ${PROC_DIR}/PrimaryProcessor.cc ${PROC_DIR}/Processor.cc ${PROC_DIR}/ProcessorToolbox.cc + ${PROC_DIR}/ReturnBuffer.cc ${PROC_DIR}/SignalSlotBase.cc ) diff --git a/Library/Processor/ControlAccess.cc b/Library/Processor/ControlAccess.cc index f85985f..f473cec 100644 --- a/Library/Processor/ControlAccess.cc +++ b/Library/Processor/ControlAccess.cc @@ -7,81 +7,80 @@ #include "ControlAccess.hh" -#include -#include +//#include +//#include namespace Nymph { SharedControl::SharedControl() : fMutex(), - fCondVar(), + fCondVarContinue(), + fCondVarBreak(), fBreakFlag( false ), fCanceledFlag( false ), fCycleTimeMS( 500 ) {} - SharedContrl::~SharedControl() + SharedControl::~SharedControl() {} - void SharedContrl::Break() - { - std::unique_lock< std::mutex > lock( fMutex ); - fBreakFlag = true; - return; - } - - void SharedContrl::Cancel() + void SharedControl::Cancel() { std::unique_lock< std::mutex > lock( fMutex ); fCanceledFlag = true; + fCondVarBreak.notify_all(); return; } - bool SharedContrl::IsAtBreak() const + bool SharedControl::IsAtBreak() const { std::unique_lock< std::mutex > lock( fMutex ); return fBreakFlag; } - bool SharedContrl::IsCanceled() const + bool SharedControl::IsCanceled() const { std::unique_lock< std::mutex > lock( fMutex ); return fCanceledFlag; } - bool SharedContrl::WaitToContinue() const + bool SharedControl::WaitToContinue() const { std::unique_lock< std::mutex > lock( fMutex ); if( fBreakFlag ) { while( fBreakFlag && ! fCanceledFlag ) { - fCondVar.wait_for( lock, std::chrono::milliseconds(fCycleTimeMS) ); + fCondVarContinue.wait_for( lock, std::chrono::milliseconds(fCycleTimeMS) ); } } - return ! fCanceled; // returns true if the thread should continue; false if it should end + return ! fCanceledFlag; // returns true if the thread should continue; false if it should end } - void SharedContrl::Resume() + bool SharedControl::WaitForBreakOrCanceled() const { std::unique_lock< std::mutex > lock( fMutex ); - fBreakFlag = false; - fCondVar.notify_all(); + while( ! fBreakFlag && ! fCanceledFlag ) + { + fCondVarBreak.wait_for( lock, std::chrono::milliseconds(fCycleTimeMS) ); + } + return fCanceledFlag ? false : fBreakFlag; } + void SharedControl::Resume() + { + std::unique_lock< std::mutex > lock( fMutex ); + fBreakFlag = false; + fCondVarContinue.notify_all(); + } - ReturnBufferBase::ReturnBufferBase() - {} - - ReturnBufferBase::~ReturnBufferBase() - {} ControlAccess::ControlAccess() : - fReturn( new ReturnBuffer< int >() ), - fControl() + fReturn( new ReturnBuffer< int >() )//, + //fControl() {} ControlAccess::~ControlAccess() diff --git a/Library/Processor/ControlAccess.hh b/Library/Processor/ControlAccess.hh index 98252b8..b034ce9 100644 --- a/Library/Processor/ControlAccess.hh +++ b/Library/Processor/ControlAccess.hh @@ -8,9 +8,12 @@ #ifndef NYMPH_CONTROLACCESS_HH_ #define NYMPH_CONTROLACCESS_HH_ +#include "Exception.hh" #include "MemberVariable.hh" +#include "ReturnBuffer.hh" -#include "cancelable.hh" +#include "cancelable.hh" // remove when ControlAccess is removed +#include "singleton.hh" //#include //#include @@ -18,17 +21,24 @@ #include #include #include -#include namespace Nymph { - class SharedControl + + class SharedControl : public scarab::singleton< SharedControl > { - public: + protected: + allow_singleton_access( SharedControl ); + SharedControl(); virtual ~SharedControl(); - void Break(); // to be called by a working thread + public: + template< typename... Args > + std::tuple< Args&... >& GetReturn(); + + template< typename... Args > + void Break( Args&... args ); // to be called by a working thread void Cancel(); // to be called by a working thread @@ -39,60 +49,51 @@ namespace Nymph // return: true = continue; false = cancel bool WaitToContinue() const; // to be called by a working thread + // return: true = was a break; false = cancel + bool WaitForBreakOrCanceled() const; // to be called by the processor toolbox + void Resume(); // to be called by the processor toolbox - MEMVAR_REF( std::mutex, Mutex ); - MEMVAR_REF( std::condition_variable, CondVar ); + MEMVAR_REF_MUTABLE( std::mutex, Mutex ); + MEMVAR_REF_MUTABLE( std::condition_variable, CondVarContinue ); + MEMVAR_REF_MUTABLE( std::condition_variable, CondVarBreak ); MEMVAR_NOSET( bool, BreakFlag ); MEMVAR_NOSET( bool, CanceledFlag ); MEMVAR( unsigned, CycleTimeMS ); + MEMVAR_SHARED_PTR_CONST( ReturnBufferBase, ReturnPtr ); - } - - class ReturnBufferBase - { - public: - ReturnBufferBase(); - virtual ~ReturnBufferBase(); }; template< typename... Args > - struct ReturnBuffer : ReturnBufferBase + void SharedControl::Break( Args&... args ) { - public: - ReturnBuffer() : - fReturn( nullptr ) - {} - - ReturnBuffer( Args&... retval ) : - fReturn( new std::tuple< Args&... >( retval... ) ) - {} - - virtual ~ReturnBuffer() - {} - - std::tuple< Args&... >& GetReturn() + while( IsAtBreak() && ! IsCanceled() ) + { + if( ! WaitToContinue() ) { - if( fReturn == nullptr ) throw std::exception(); - return *fReturn; + BOOST_THROW_EXCEPTION( Exception() << "Canceled while waiting to initiate a breakpoint" << eom ); } + } + + std::unique_lock< std::mutex > lock( fMutex ); + fBreakFlag = true; + fCondVarBreak.notify_all(); + return; + } - protected: - std::tuple< Args&... >* fReturn; - }; - template<> - struct ReturnBuffer< void > : ReturnBufferBase + + template< typename... Args > + std::tuple< Args&... >& SharedControl::GetReturn() { - ReturnBuffer() : - ReturnBufferBase() - {} + if( ! fReturnPtr ) BOOST_THROW_EXCEPTION( Exception() << "No return available" << eom ); + std::unique_lock< std::mutex > lock( fMutex ); + std::shared_ptr< ReturnBuffer< Args... > > buffer( std::dynamic_pointer_cast< ReturnBuffer< Args... > >(fReturnPtr) ); + if( buffer == nullptr ) BOOST_THROW_EXCEPTION( Exception() << "Incorrect types used to get return" << eom ); + return buffer->GetReturn(); + } + - void GetReturn() - { - return; - } - }; class ControlAccess : public scarab::cancelable { @@ -111,7 +112,7 @@ namespace Nymph std::shared_ptr< ReturnBufferBase > fReturn; public: - MEM_VAR_SHARED_PTR( SharedControl, Control ); + //MEM_VAR_SHARED_PTR( SharedControl, Control ); }; typedef std::shared_ptr< ControlAccess > ControlAccessPtr; diff --git a/Library/Processor/PrimaryProcessor.cc b/Library/Processor/PrimaryProcessor.cc index 246cc5f..87ee3cf 100644 --- a/Library/Processor/PrimaryProcessor.cc +++ b/Library/Processor/PrimaryProcessor.cc @@ -7,6 +7,7 @@ #include "PrimaryProcessor.hh" +#include "QuitThread.hh" #include "Exception.hh" #include "logger.hh" @@ -22,13 +23,15 @@ namespace Nymph PrimaryProcessor::~PrimaryProcessor() {} - void PrimaryProcessor::operator()( ControlAccessPtr control ) + void PrimaryProcessor::operator()()// ControlAccessPtr control ) { // pass the control access pointer to every signal in the primary processor + /* for( auto signalIt = fSignals.begin(); signalIt != fSignals.end(); ++signalIt ) { signalIt->second->SetControlAcc( control ); } + */ // go! try @@ -44,6 +47,10 @@ namespace Nymph //fThreadRef->SetReturnValue( KTDataHandle() ); } } + catch( QuitThread& e ) + { + LDEBUG( proclog, "Thread quit from " << e.fFile << ", line " << e.fLine ); + } catch( boost::exception& e ) { //fThreadRef->SetReturnException( boost::current_exception() ); diff --git a/Library/Processor/PrimaryProcessor.hh b/Library/Processor/PrimaryProcessor.hh index 45f6530..785ff57 100644 --- a/Library/Processor/PrimaryProcessor.hh +++ b/Library/Processor/PrimaryProcessor.hh @@ -22,7 +22,7 @@ namespace Nymph public: /// Callable function used by std::thread - void operator()( ControlAccessPtr control ); + void operator()();// ControlAccessPtr control ); /// Starts the main action of the processor virtual bool Run() = 0; diff --git a/Library/Processor/Processor.cc b/Library/Processor/Processor.cc index 21df8a4..d491122 100644 --- a/Library/Processor/Processor.cc +++ b/Library/Processor/Processor.cc @@ -31,11 +31,11 @@ namespace Nymph fSignals.insert( SigMapVal(name, signal) ); // give the signal to any slots that are waiting for it - auto range = fSlotsWaitingForSignals.equal_range( name ); - for( auto rangeIt = range.first; rangeIt != range.second; ++rangeIt ) - { - rangeIt->second->SignalsUsed().push_back( signal ); - } + //auto range = fSlotsWaitingForSignals.equal_range( name ); + //for( auto rangeIt = range.first; rangeIt != range.second; ++rangeIt ) + //{ + // rangeIt->second->SignalsUsed().push_back( signal ); + //} return; } @@ -45,6 +45,7 @@ namespace Nymph LDEBUG( processorlog, "Registering slot <" << name << "> in processor <" << fName << ">" ); fSlots.insert( SlotMapVal(name, slot) ); + /* // take care of giving signal pointers to the slot, or saving them for later assignment for( auto signalIt = signals.begin(); signalIt != signals.end(); ++signalIt ) { @@ -60,6 +61,7 @@ namespace Nymph slot->SignalsUsed().push_back( signalPtrIt->second ); } } + */ return; } diff --git a/Library/Processor/Processor.hh b/Library/Processor/Processor.hh index 045c655..3b5e9ae 100644 --- a/Library/Processor/Processor.hh +++ b/Library/Processor/Processor.hh @@ -68,8 +68,8 @@ namespace Nymph // this is used only to hold pointers to slots waiting for signals // the keys are the names of the signals being waited for, and the values are the slot pointers - typedef std::multimap< std::string, SlotBase* > WaitingSlotMap; - MEMVAR_REF_CONST( WaitingSlotMap, SlotsWaitingForSignals ); + //typedef std::multimap< std::string, SlotBase* > WaitingSlotMap; + //MEMVAR_REF_CONST( WaitingSlotMap, SlotsWaitingForSignals ); }; diff --git a/Library/Processor/ProcessorToolbox.cc b/Library/Processor/ProcessorToolbox.cc index 86da326..1e8359a 100644 --- a/Library/Processor/ProcessorToolbox.cc +++ b/Library/Processor/ProcessorToolbox.cc @@ -14,6 +14,9 @@ #include "logger.hh" #include "param_codec.hh" +#include +#include + //#include //#include @@ -708,10 +711,11 @@ namespace Nymph for (RunQueue::iterator rqIter = fRunQueue.begin(); rqIter != fRunQueue.end(); ++rqIter) { - boost::thread_group threads; + //boost::thread_group threads; + std::map< std::thread > threads; { // scope for threadFuturesLock - boost_unique_lock breakContLock( fBreakContMutex ); + //boost_unique_lock breakContLock( fBreakContMutex ); //boost_unique_lock threadFuturesLock( fThreadReferencesMutex ); for (ThreadSourceGroup::iterator tgIter = rqIter->begin(); tgIter != rqIter->end(); ++tgIter) @@ -719,7 +723,7 @@ namespace Nymph std::string procName( tgIter->fName ); LINFO( proclog, "Starting processor <" << procName << ">" ); - + threads.emplace( procName, &PrimaryProcessor::operator(), tgIter->fProc ); //std::shared_ptr< KTThreadReference > thisThreadRef = std::make_shared< KTThreadReference >(); //thisThreadRef->Name() = procName; @@ -741,11 +745,37 @@ namespace Nymph //} //KTDEBUG( proclog, "Thread has started" ); - threads.add_thread( thisThread ); + //threads.add_thread( thisThread ); }// end for loop over the thread group } // end scope for threadFuturesLock + SharedControl* control = SharedControl::get_instance(); + bool stillRunning = true; + while( stillRunning ) + { + bool breakOrCanceled = control->WaitForBreakOrCanceled(); + if( breakOrCanceled ) + { + // then at a breakpoint + stillRunning = true; + LDEBUG( proclog, "At a breakpoint" ); + // TODO: do we need to do anything while at a breakpoint? + if( ! control->WaitToContinue() ) + { + stillRunning = false; + LDEBUG( proclog, "Detected cancelation while waiting at breakpoint" ); + } + } + else + { + // then canceled + stillRunning = false; + LDEBUG( proclog, "Detected cancelation while waiting during running" ); + } + } + + /* bool stillRunning = true; // determines behavior that depends on whether a return from the thread was temporary or from the thread completing do { @@ -794,6 +824,7 @@ namespace Nymph threads.join_all(); boost_unique_lock breakContLock( fBreakContMutex ); fThreadReferences.clear(); + */ } // end for loop over the run-queue LPROG( proclog, "Processing is complete (multi-threaded)" ); @@ -802,24 +833,27 @@ namespace Nymph { // exceptions thrown in this function or from within processors will end up here LERROR( proclog, "Caught std::exception thrown in a processor or in the multi-threaded run function: " << e.what() ); - LWARN( proclog, "Setting boost::exception of do-run-promise in StartMultiThreadedRun" ); - fDoRunPromise.set_exception( boost::current_exception() ); + SharedControl::get_instance()->Cancel(); + //LWARN( proclog, "Setting boost::exception of do-run-promise in StartMultiThreadedRun" ); + //fDoRunPromise.set_exception( boost::current_exception() ); return; } catch( boost::exception& e ) { // exceptions thrown in this function or from within processors will end up here LERROR( proclog, "Caught boost::exception thrown in a processor or in the multi-threaded run function" ); - LWARN( proclog, "Setting boost::exception of do-run-promise in StartMultiThreadedRun" ); - fDoRunPromise.set_exception( boost::current_exception() ); + LERROR( proclog, "Diagnostic Information:\n" << diagnostic_information( e ) ); + SharedControl::get_instance()->Cancel(); + //LWARN( proclog, "Setting boost::exception of do-run-promise in StartMultiThreadedRun" ); + //fDoRunPromise.set_exception( boost::current_exception() ); return; } - LWARN( proclog, "Setting value of do-run-promise in StartMultiThreadedRun" ); - fDoRunPromise.set_value(); + //LWARN( proclog, "Setting value of do-run-promise in StartMultiThreadedRun" ); + //fDoRunPromise.set_value(); return; }; // end multi-threaded run lambda - fDoRunThread = new boost::thread( multiThreadRun ); + fDoRunThread = new std::thread( multiThreadRun ); return; } diff --git a/Library/Processor/QuitThread.hh b/Library/Processor/QuitThread.hh new file mode 100644 index 0000000..a11983c --- /dev/null +++ b/Library/Processor/QuitThread.hh @@ -0,0 +1,31 @@ +/* + * QuitThread.hh + * + * Created on: Oct 22, 2019 + * Author: N.S. Oblath + */ + +#ifndef NYMPH_QUITTHREAD_HH_ +#define NYMPH_QUITTHREAD_HH_ + +#include + +namespace Nymph +{ + + struct QuitThread + { + std::string fFile; + std::string fLine; + QuitThread( const std::string& file, const std::string& line ) : + fFile( file ), + fLine( line ) + {} + }; + + #define QUIT_THREAD \ + throw ::Nymph::QuitThread( TOSTRING(__FILE__), TOSTRING(__LINE__) ); + +} /* namespace Nymph */ + +#endif /* NYMPH_QUITTHREAD_HH_ */ diff --git a/Library/Processor/ReturnBuffer.cc b/Library/Processor/ReturnBuffer.cc new file mode 100644 index 0000000..7e0bf57 --- /dev/null +++ b/Library/Processor/ReturnBuffer.cc @@ -0,0 +1,19 @@ +/* + * ReturnBuffer.cc + * + * Created on: Oct 22, 2019 + * Author: N.S. Oblath + */ + +#include "ReturnBuffer.hh" + +namespace Nymph +{ + + ReturnBufferBase::ReturnBufferBase() + {} + + ReturnBufferBase::~ReturnBufferBase() + {} + +} diff --git a/Library/Processor/ReturnBuffer.hh b/Library/Processor/ReturnBuffer.hh new file mode 100644 index 0000000..c29a146 --- /dev/null +++ b/Library/Processor/ReturnBuffer.hh @@ -0,0 +1,63 @@ +/* + * ReturnBuffer.hh + * + * Created on: Oct 22, 2019 + * Author: N.S. Oblath + */ + +#ifndef NYMPH_RETURNBUFFER_HH_ +#define NYMPH_RETURNBUFFER_HH_ + +#include + +namespace Nymph +{ + + class ReturnBufferBase + { + public: + ReturnBufferBase(); + virtual ~ReturnBufferBase(); + }; + + template< typename... Args > + struct ReturnBuffer : ReturnBufferBase + { + public: + ReturnBuffer() : + fReturn( nullptr ) + {} + + ReturnBuffer( Args&... retval ) : + fReturn( new std::tuple< Args&... >( retval... ) ) + {} + + virtual ~ReturnBuffer() + {} + + std::tuple< Args&... >& GetReturn() + { + if( fReturn == nullptr ) throw std::exception(); + return *fReturn; + } + + protected: + std::tuple< Args&... >* fReturn; + }; + + template<> + struct ReturnBuffer< void > : ReturnBufferBase + { + ReturnBuffer() : + ReturnBufferBase() + {} + + void GetReturn() + { + return; + } + }; + +} /* namespace Nymph */ + +#endif /* NYMPH_RETURNBUFFER_HH_ */ diff --git a/Library/Processor/Signal.hh b/Library/Processor/Signal.hh index 9f7b08e..2bb2ffe 100644 --- a/Library/Processor/Signal.hh +++ b/Library/Processor/Signal.hh @@ -12,7 +12,9 @@ #include "SignalSlotBase.hh" +#include "ControlAccess.hh" #include "Exception.hh" +#include "QuitThread.hh" #include "logger.hh" @@ -52,6 +54,7 @@ namespace Nymph void Emit( XArgs... args ); void operator()( XArgs... args ); + // TODO: remove this MEMVAR_SHARED_PTR( ControlAccess, ControlAcc ); }; @@ -170,13 +173,24 @@ namespace Nymph template< typename... XArgs > inline void Signal< XArgs... >::operator()( XArgs... args ) { - // TODO: if not canceled and at breakpoint, then set return and break + SharedControl* control = SharedControl::get_instance(); + + // if we're canceled, then quit the thread + // if we're at a break, then wait to continue + // once we continue, if we need to quit, then do so + if( control->IsCanceled() || (control->IsAtBreak() && ! control->WaitToContinue()) ) + { + QUIT_THREAD; + } + if( fDoBreakpoint ) { - fControl->SetReturn< XArgs... >( args... ); - fControl->Break(); // waits for resume or exit + control->Break( args... ); + if( ! control->WaitToContinue() ) + { + QUIT_THREAD; + } } - // TODO: if canceled, quit for( auto connection : fConnections ) { diff --git a/Library/Processor/SignalSlotBase.cc b/Library/Processor/SignalSlotBase.cc index bcdba67..ec234ce 100644 --- a/Library/Processor/SignalSlotBase.cc +++ b/Library/Processor/SignalSlotBase.cc @@ -11,8 +11,8 @@ namespace Nymph { SlotBase::SlotBase( const std::string& name ) : fName( name ), - fConnections(), - fSignalsUsed() + fConnections()//, + //fSignalsUsed() {} SlotBase::~SlotBase() @@ -30,7 +30,7 @@ namespace Nymph SignalBase::SignalBase( const std::string& name ) : fName( name ), fConnections(), - fControl( nullptr ), + //fControl( nullptr ), fDoBreakpoint( false ) {} diff --git a/Library/Processor/SignalSlotBase.hh b/Library/Processor/SignalSlotBase.hh index 69a33ea..dc43d74 100644 --- a/Library/Processor/SignalSlotBase.hh +++ b/Library/Processor/SignalSlotBase.hh @@ -8,7 +8,7 @@ #ifndef NYMPH_SIGNALSLOTBASE_HH_ #define NYMPH_SIGNALSLOTBASE_HH_ -#include "ControlAccess.hh" +//#include "ControlAccess.hh" #include "Exception.hh" #include "MemberVariable.hh" @@ -45,7 +45,7 @@ namespace Nymph typedef std::set< SignalBase* > signal_connections; // to get around the problem of having a comma inside a macro function argument MEMVAR_REF_MUTABLE( signal_connections, Connections ); - MEMVAR_REF( std::vector< SignalBase* >, SignalsUsed ); + //MEMVAR_REF( std::vector< SignalBase* >, SignalsUsed ); protected: friend class SignalBase; @@ -71,7 +71,7 @@ namespace Nymph typedef std::set< SlotBase* > slot_connections; // to get around the problem of having a comma inside a macro function argument MEMVAR_REF_MUTABLE_CONST( slot_connections, Connections ); - MEMVAR( ControlAccess*, Control ); // doesn't use MEMVAR_PTR because Signal doesn't own the object pointed to by fControl + //MEMVAR( ControlAccess*, Control ); // doesn't use MEMVAR_PTR because Signal doesn't own the object pointed to by fControl MEMVAR( bool, DoBreakpoint ); diff --git a/Library/Processor/Slot.hh b/Library/Processor/Slot.hh index 446507b..ad79b8b 100644 --- a/Library/Processor/Slot.hh +++ b/Library/Processor/Slot.hh @@ -221,10 +221,10 @@ namespace Nymph inline void Slot< XArgs... >::SlotFuncWrapper( ControlAccessPtr access, XArgs... args ) { //TODO could do something with `access` here - for( auto signalIt = fSignalsUsed.begin(); signalIt != fSignalsUsed.end(); ++signalIt ) - { - (*signalIt)->SetControl( access ); - } + //for( auto signalIt = fSignalsUsed.begin(); signalIt != fSignalsUsed.end(); ++signalIt ) + //{ + // (*signalIt)->SetControl( access ); + //} fFunction( args... ); diff --git a/Scarab b/Scarab index d8a19bf..25cf398 160000 --- a/Scarab +++ b/Scarab @@ -1 +1 @@ -Subproject commit d8a19bfb2d8d41eff57a84f30760d1c4c3291ab0 +Subproject commit 25cf3988ff1968cfc0750349c9c14e23b1b1697a From 79c667803e55f1f91bdeade33feb3a9964f441d8 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Tue, 22 Oct 2019 17:05:29 -0700 Subject: [PATCH 156/521] A little more progress --- Library/Processor/ProcessorToolbox.cc | 42 +++++++++++++++------------ Library/Processor/ProcessorToolbox.hh | 36 ++++++++++++----------- 2 files changed, 43 insertions(+), 35 deletions(-) diff --git a/Library/Processor/ProcessorToolbox.cc b/Library/Processor/ProcessorToolbox.cc index 1e8359a..7973bd8 100644 --- a/Library/Processor/ProcessorToolbox.cc +++ b/Library/Processor/ProcessorToolbox.cc @@ -572,26 +572,26 @@ namespace Nymph return; } - fDoRunPromise = boost::promise< void >(); - fDoRunFuture = fDoRunPromise.get_future().share(); - - bool willRunSingleThreaded = fRunSingleThreaded; -#ifdef SINGLETHREADED - willRunSingleThreaded = true; -#endif - - if( willRunSingleThreaded ) - { - StartSingleThreadedRun(); - } - else - { - StartMultiThreadedRun(); - } + //fDoRunPromise = boost::promise< void >(); + //fDoRunFuture = fDoRunPromise.get_future().share(); + + //bool willRunSingleThreaded = fRunSingleThreaded; +//#ifdef SINGLETHREADED + //willRunSingleThreaded = true; +//#endif + + //if( willRunSingleThreaded ) + //{ + // StartSingleThreadedRun(); + //} + //else + //{ + StartMultiThreadedRun(); + //} return; } - +/* void ProcessorToolbox::StartSingleThreadedRun() { auto singleThreadRun = [&]() @@ -700,7 +700,7 @@ namespace Nymph fDoRunThread = new boost::thread( singleThreadRun ); return; } - +*/ void ProcessorToolbox::StartMultiThreadedRun() { auto multiThreadRun = [&]() @@ -968,6 +968,7 @@ namespace Nymph return (*trIt)->GetReturnValue(); } +/* void ProcessorToolbox::InitiateBreak() { boost_unique_lock breakContLock( fBreakContMutex ); @@ -992,9 +993,13 @@ namespace Nymph return; } + */ void ProcessorToolbox::CancelThreads() { + SharedControl::get_instance()->Cancel(); + return; + /* boost_unique_lock breakContLock( fBreakContMutex ); for( auto trIt = fThreadReferences.begin(); trIt != fThreadReferences.end(); ++trIt ) { @@ -1002,6 +1007,7 @@ namespace Nymph (*trIt)->SetCanceled( true ); } return; + */ } bool ProcessorToolbox::Run() diff --git a/Library/Processor/ProcessorToolbox.hh b/Library/Processor/ProcessorToolbox.hh index 577ceee..f5cc696 100644 --- a/Library/Processor/ProcessorToolbox.hh +++ b/Library/Processor/ProcessorToolbox.hh @@ -194,9 +194,9 @@ namespace Nymph { PrimaryProcessor* fProc; std::string fName; - ControlAccessPtr fControlAccess; + //ControlAccessPtr fControlAccess; ThreadSource( PrimaryProcessor* proc, const std::string& name ) : - fProc(proc), fName(name), fControlAccess( new ControlAccess() ) + fProc(proc), fName(name)//, fControlAccess( new ControlAccess() ) {} }; struct CompareThreadSource @@ -220,13 +220,13 @@ namespace Nymph void AsyncRun(); - void WaitForContinue( boost_unique_lock& lock ); + void WaitToContinue(); /// Returns when processing is completed or a breakpoint is reached /// Throws a boost::exception if there's an error with the future object in use /// If the return is true, processing can continue after the break /// If the return is false, processing has ended (either normally or due to an error) - bool WaitForBreak(); + bool WaitForBreakOrCanceled(); void WaitForEndOfRun(); @@ -236,29 +236,31 @@ namespace Nymph void JoinRunThread(); - KTDataHandle GetData( const std::string& threadName ); + // TODO: return value access - MEMVAR_SHARED_PTR_CONST( SharedControl, Control ); + //KTDataHandle GetData( const std::string& threadName ); + + //MEMVAR_SHARED_PTR_CONST( SharedControl, Control ); private: - typedef boost::shared_future< KTDataHandle > Future; + //typedef boost::shared_future< KTDataHandle > Future; - void StartSingleThreadedRun(); + //void StartSingleThreadedRun(); void StartMultiThreadedRun(); // called from KTThreadReference::Break - void InitiateBreak(); + //void InitiateBreak(); - std::vector< std::shared_ptr< KTThreadReference > > fThreadReferences; + //std::vector< std::shared_ptr< KTThreadReference > > fThreadReferences; - boost::condition_variable fContinueCV; - bool fDoContinue; - boost::mutex fBreakContMutex; + //boost::condition_variable fContinueCV; + //bool fDoContinue; + //boost::mutex fBreakContMutex; - boost::thread* fDoRunThread; - boost::promise< void > fDoRunPromise; - boost::shared_future< void > fDoRunFuture; - bool fDoRunBreakFlag; + //boost::thread* fDoRunThread; + //boost::promise< void > fDoRunPromise; + //boost::shared_future< void > fDoRunFuture; + //bool fDoRunBreakFlag; }; From 00c44a00723f97fb689f0e6b851cb7914ccb18eb Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Wed, 23 Oct 2019 00:44:06 -0700 Subject: [PATCH 157/521] ProcessorToolbox compiles, but untested and minus return setup. --- Library/Processor/ProcessorToolbox.cc | 62 +++++++++++++++++---------- Library/Processor/ProcessorToolbox.hh | 5 ++- 2 files changed, 42 insertions(+), 25 deletions(-) diff --git a/Library/Processor/ProcessorToolbox.cc b/Library/Processor/ProcessorToolbox.cc index 7973bd8..e6c124a 100644 --- a/Library/Processor/ProcessorToolbox.cc +++ b/Library/Processor/ProcessorToolbox.cc @@ -34,14 +34,14 @@ namespace Nymph fRunSingleThreaded( false ), fRunQueue(), fProcMap(), - fControl( new SharedControl() )/*, - fThreadReferences(), - fContinueCV(), - fDoContinue( false ), - fBreakContMutex(), - fDoRunThread( nullptr ), - fDoRunPromise(), - fDoRunBreakFlag( false )*/ + //fControl( new SharedControl() ), + //fThreadReferences(), + //fContinueCV(), + //fDoContinue( false ), + //fBreakContMutex(), + fDoRunThread()//, + //fDoRunPromise(), + //fDoRunBreakFlag( false ) { } @@ -566,7 +566,7 @@ namespace Nymph void ProcessorToolbox::AsyncRun() { - if( fDoRunThread != nullptr ) + if( ! fDoRunThread.joinable() ) { LERROR( proclog, "It appears that a run has already been started" ); return; @@ -712,7 +712,7 @@ namespace Nymph for (RunQueue::iterator rqIter = fRunQueue.begin(); rqIter != fRunQueue.end(); ++rqIter) { //boost::thread_group threads; - std::map< std::thread > threads; + std::map< std::string, std::thread > threads; { // scope for threadFuturesLock //boost_unique_lock breakContLock( fBreakContMutex ); @@ -723,7 +723,7 @@ namespace Nymph std::string procName( tgIter->fName ); LINFO( proclog, "Starting processor <" << procName << ">" ); - threads.emplace( procName, &PrimaryProcessor::operator(), tgIter->fProc ); + threads.emplace( procName, std::thread(&PrimaryProcessor::operator(), tgIter->fProc) ); //std::shared_ptr< KTThreadReference > thisThreadRef = std::make_shared< KTThreadReference >(); //thisThreadRef->Name() = procName; @@ -853,13 +853,15 @@ namespace Nymph return; }; // end multi-threaded run lambda - fDoRunThread = new std::thread( multiThreadRun ); + fDoRunThread = std::thread( multiThreadRun ); return; } - bool ProcessorToolbox::WaitForBreak() + bool ProcessorToolbox::WaitForBreakOrCanceled() { + return SharedControl::get_instance()->WaitForBreakOrCanceled(); + /* boost_unique_lock breakContLock( fBreakContMutex ); if( fDoRunBreakFlag ) @@ -896,28 +898,35 @@ namespace Nymph LERROR( proclog, "An error occurred during processing: " << boost::diagnostic_information( e ) ); return false; } + */ + } + + bool ProcessorToolbox::WaitToContinue() + { + return SharedControl::get_instance()->WaitToContinue(); } void ProcessorToolbox::WaitForEndOfRun() { // WaitForBreak() and WaitForContinue() throw boost::exception for problems with the future or promise objects - KTDEBUG( proclog, "Waiting for end-of-run" ); - while( WaitForBreak() ) + LDEBUG( proclog, "Waiting for end-of-run" ); + while( WaitForBreakOrCanceled() ) { - KTDEBUG( proclog, "Reached breakpoint; waiting for continue" ); - boost::mutex localMutex; - boost_unique_lock localLock( localMutex ); - WaitForContinue( localLock ); - KTDEBUG( proclog, "Processing resuming; waiting for end-of-run" ); + LDEBUG( proclog, "Reached breakpoint; waiting for continue" ); + WaitToContinue(); + LDEBUG( proclog, "Processing resuming; waiting for end-of-run" ); } - KTDEBUG( proclog, "End-of-run reached" ); + LDEBUG( proclog, "End-of-run reached" ); return; } void ProcessorToolbox::Continue() { + SharedControl::get_instance()->Resume(); + return; + /* if( ! fDoRunBreakFlag ) { LWARN( proclog, "Not currently at a breakpoint" ); @@ -946,8 +955,9 @@ namespace Nymph fContinueCV.notify_all(); return; + */ } - +/* KTDataHandle ProcessorToolbox::GetData( const std::string& threadName ) { //boost_unique_lock threadFuturesLock( fThreadReferencesMutex ); @@ -967,7 +977,7 @@ namespace Nymph boost_unique_lock lock( (*trIt)->Mutex() ); return (*trIt)->GetReturnValue(); } - +*/ /* void ProcessorToolbox::InitiateBreak() { @@ -995,6 +1005,12 @@ namespace Nymph } */ + void ProcessorToolbox::JoinRunThread() + { + fDoRunThread.join(); + return; + } + void ProcessorToolbox::CancelThreads() { SharedControl::get_instance()->Cancel(); diff --git a/Library/Processor/ProcessorToolbox.hh b/Library/Processor/ProcessorToolbox.hh index f5cc696..96a6be9 100644 --- a/Library/Processor/ProcessorToolbox.hh +++ b/Library/Processor/ProcessorToolbox.hh @@ -30,6 +30,7 @@ #include #include #include +#include namespace Nymph @@ -220,7 +221,7 @@ namespace Nymph void AsyncRun(); - void WaitToContinue(); + bool WaitToContinue(); /// Returns when processing is completed or a breakpoint is reached /// Throws a boost::exception if there's an error with the future object in use @@ -257,7 +258,7 @@ namespace Nymph //bool fDoContinue; //boost::mutex fBreakContMutex; - //boost::thread* fDoRunThread; + std::thread fDoRunThread; //boost::promise< void > fDoRunPromise; //boost::shared_future< void > fDoRunFuture; //bool fDoRunBreakFlag; From 3d3d5b35fe835ecc9b2dbff6704267bba2afcdef Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Mon, 11 Nov 2019 00:44:12 -0800 Subject: [PATCH 158/521] Very preliminary work on data --- Library/Data/Data.cc | 18 +++++++++++++++++ Library/Data/Data.hh | 24 +++++++++++++++++++++++ Library/Data/DataFrame.cc | 18 +++++++++++++++++ Library/Data/DataFrame.hh | 24 +++++++++++++++++++++++ Library/Data/DataManager.cc | 18 +++++++++++++++++ Library/Data/DataManager.hh | 39 +++++++++++++++++++++++++++++++++++++ 6 files changed, 141 insertions(+) create mode 100644 Library/Data/Data.cc create mode 100644 Library/Data/Data.hh create mode 100644 Library/Data/DataFrame.cc create mode 100644 Library/Data/DataFrame.hh create mode 100644 Library/Data/DataManager.cc create mode 100644 Library/Data/DataManager.hh diff --git a/Library/Data/Data.cc b/Library/Data/Data.cc new file mode 100644 index 0000000..12be720 --- /dev/null +++ b/Library/Data/Data.cc @@ -0,0 +1,18 @@ +/* + * Data.cc + * + * Created on: Nov 5, 2019 + * Author: N.S. Oblath + */ + +#include "Data.hh" + +namespace Nymph +{ + Data::Data() + {} + + Data::~Data() + {} + +} /* namespace Nymph */ diff --git a/Library/Data/Data.hh b/Library/Data/Data.hh new file mode 100644 index 0000000..590deca --- /dev/null +++ b/Library/Data/Data.hh @@ -0,0 +1,24 @@ +/* + * Data.hh + * + * Created on: Nov 5, 2019 + * Author: N.S. Oblath + */ + + +#ifndef NYMPH_DATA_HH_ +#define NYMPH_DATA_HH_ + +namespace Nymph +{ + + class Data + { + public: + Data(); + virtual ~Data(); + }; + +} /* namespace Nymph */ + +#endif /* NYMPH_DATA_HH_ */ diff --git a/Library/Data/DataFrame.cc b/Library/Data/DataFrame.cc new file mode 100644 index 0000000..833fdce --- /dev/null +++ b/Library/Data/DataFrame.cc @@ -0,0 +1,18 @@ +/* + * DataFrame.cc + * + * Created on: Nov 5, 2019 + * Author: N.S. Oblath + */ + +#include "DataFrame.hh" + +namespace Nymph +{ + DataFrame::DataFrame() + {} + + DataFrame::~DataFrame() + {} + +} /* namespace Nymph */ diff --git a/Library/Data/DataFrame.hh b/Library/Data/DataFrame.hh new file mode 100644 index 0000000..8a8b62d --- /dev/null +++ b/Library/Data/DataFrame.hh @@ -0,0 +1,24 @@ +/* + * DataFrame.hh + * + * Created on: Nov 5, 2019 + * Author: N.S. Oblath + */ + + +#ifndef NYMPH_DATAFRAME_HH_ +#define NYMPH_DATAFRAME_HH_ + +namespace Nymph +{ + + class DataFrame + { + public: + DataFrame(); + virtual ~DataFrame(); + }; + +} /* namespace Nymph */ + +#endif /* NYMPH_DATAFRAME_HH_ */ diff --git a/Library/Data/DataManager.cc b/Library/Data/DataManager.cc new file mode 100644 index 0000000..3fda7bc --- /dev/null +++ b/Library/Data/DataManager.cc @@ -0,0 +1,18 @@ +/* + * DataManager.cc + * + * Created on: Nov 5, 2019 + * Author: N.S. Oblath + */ + +#include "DataManager.hh" + +namespace Nymph +{ + DataManager::DataManager() + {} + + DataManager::~DataManager() + {} + +} /* namespace Nymph */ diff --git a/Library/Data/DataManager.hh b/Library/Data/DataManager.hh new file mode 100644 index 0000000..3552738 --- /dev/null +++ b/Library/Data/DataManager.hh @@ -0,0 +1,39 @@ +/* + * DataManager.hh + * + * Created on: Nov 5, 2019 + * Author: N.S. Oblath + */ + + +#ifndef NYMPH_DATAMANAGER_HH_ +#define NYMPH_DATAMANAGER_HH_ + +#include "MemberVariable.hh" + +#include +#include + +namespace Nymph +{ + struct Holder + {} + + template< typename XType > + struct TypedHolder + { + + } + + class DataManager + { + public: + DataManager(); + virtual ~DataManager(); + + MEMVAR_REF( std::map< std::type_index, std::list< Holder > >, DataStore ); + }; + +} /* namespace Nymph */ + +#endif /* NYMPH_DATAMANAGER_HH_ */ From 7f835caa9d5a986176018656175f3f1f165400fc Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Wed, 8 Dec 2021 15:20:07 -0800 Subject: [PATCH 159/521] Remove another KT prefix --- Library/Processor/Processor.hh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Library/Processor/Processor.hh b/Library/Processor/Processor.hh index 3b5e9ae..294319b 100644 --- a/Library/Processor/Processor.hh +++ b/Library/Processor/Processor.hh @@ -86,7 +86,7 @@ namespace Nymph return new scarab::registrar< Processor, XDerivedProc, const std::string& >( name ); } -#define KT_REGISTER_PROCESSOR(proc_class, proc_name) \ +#define REGISTER_PROCESSOR(proc_class, proc_name) \ static ::scarab::registrar< ::Nymph::Processor, proc_class, const std::string& > sProc##proc_class##Registrar( proc_name ); } /* namespace Nymph */ From 9448e523666f35cb59f12aabb35bd6cbd5843f27 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Wed, 8 Dec 2021 15:20:33 -0800 Subject: [PATCH 160/521] Move the test processor to its own header file --- Testing/CMakeLists.txt | 6 ++++ Testing/TestProc.hh | 67 ++++++++++++++++++++++++++++++++++++++++ Testing/TestProcessor.cc | 61 ++---------------------------------- 3 files changed, 76 insertions(+), 58 deletions(-) create mode 100644 Testing/TestProc.hh diff --git a/Testing/CMakeLists.txt b/Testing/CMakeLists.txt index 29726b0..26945fe 100644 --- a/Testing/CMakeLists.txt +++ b/Testing/CMakeLists.txt @@ -4,13 +4,19 @@ ########## +include_directories( BEFORE + ${CMAKE_CURRENT_SOURCE_DIR} +) + set( testing_HEADERS + TestProc.hh ) set( testing_SOURCES TestControlAccess.cc TestPrimaryProcessor.cc TestProcessor.cc + TestProcessorToolbox.cc TestSignalSlot.cc UseCatch.cc ) diff --git a/Testing/TestProc.hh b/Testing/TestProc.hh new file mode 100644 index 0000000..19cb143 --- /dev/null +++ b/Testing/TestProc.hh @@ -0,0 +1,67 @@ +/* + * TestProc.hh + * + * Created on: Nov 25, 2021 + * Author: N.S. Oblath + */ + +#include "Processor.hh" +#include "Signal.hh" +#include "Slot.hh" + + +namespace Nymph +{ + // concrete processor class that we can test + // implements Configure() and has its own signal and slot + class TestProc : public Processor + { + public: + TestProc() : + Processor( "test" ), + fValue( 0 ), + fSecondValue( 0 ), + fValueSig( "value", this ), + fValueSlot( "value", this, &TestProc::SetValue ), + fSecondValueSig( "second-value", this ), + fSecondValueSlot( "second-value", this, &TestProc::SecondValueSlotFunction, {"second-value"} ), + fSecondValueSlot2( "second-value-2", this, &TestProc::SetSecondValue ) + {} + + virtual ~TestProc() + {} + + void Configure( const scarab::param_node& node ) + { + fValue = node.get_value( "value", fValue ); + return; + } + + MEMVAR( int, Value ); + MEMVAR( int, SecondValue ); + + void SecondValueSlotFunction( int newValue ) + { + fSecondValueSig( newValue ); + } + + MEMVAR_REF( Signal< int >, ValueSig ); + MEMVAR_REF( Slot< int >, ValueSlot ); + + MEMVAR_REF( Signal< int >, SecondValueSig ); + MEMVAR_REF( Slot< int >, SecondValueSlot ); + MEMVAR_REF( Slot< int >, SecondValueSlot2 ); + + }; + + // external slot function owner + struct TestSlotOwner + { + int fValue = 0; + void TestSlotFunc( int input ) + { + fValue = input; + return; + } + }; +} diff --git a/Testing/TestProcessor.cc b/Testing/TestProcessor.cc index f075355..42e7465 100644 --- a/Testing/TestProcessor.cc +++ b/Testing/TestProcessor.cc @@ -5,9 +5,7 @@ * Author: N.S. Oblath */ -#include "Processor.hh" -#include "Signal.hh" -#include "Slot.hh" +#include "TestProc.hh" #include "logger.hh" @@ -15,61 +13,8 @@ LOGGER( testlog, "TestProcessor" ); -namespace Nymph -{ - // concrete processor class that we can test - // implements Configure() and has its own signal and slot - class TestProc : public Processor - { - public: - TestProc() : - Processor( "test" ), - fValue( 0 ), - fSecondValue( 0 ), - fValueSig( "value", this ), - fValueSlot( "value", this, &TestProc::SetValue ), - fSecondValueSig( "second-value", this ), - fSecondValueSlot( "second-value", this, &TestProc::SecondValueSlotFunction, {"second-value"} ), - fSecondValueSlot2( "second-value-2", this, &TestProc::SetSecondValue ) - {} - - virtual ~TestProc() - {} - - void Configure( const scarab::param_node& node ) - { - fValue = node.get_value( "value", fValue ); - return; - } - - MEMVAR( int, Value ); - MEMVAR( int, SecondValue ); - - void SecondValueSlotFunction( int newValue ) - { - fSecondValueSig( newValue ); - } - - MEMVAR_REF( Signal< int >, ValueSig ); - MEMVAR_REF( Slot< int >, ValueSlot ); - - MEMVAR_REF( Signal< int >, SecondValueSig ); - MEMVAR_REF( Slot< int >, SecondValueSlot ); - MEMVAR_REF( Slot< int >, SecondValueSlot2 ); - - }; - - // external slot function owner - struct TestSlotOwner - { - int fValue = 0; - void TestSlotFunc( int input ) - { - fValue = input; - return; - } - }; -} +REGISTER_PROCESSOR(Nymph::TestProc, "test-proc"); + TEST_CASE( "processor", "[signal],[slot],[processor]" ) { From 0a7f7adfadb6ea6e5b3965818f210f00dd110738 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Wed, 8 Dec 2021 15:21:00 -0800 Subject: [PATCH 161/521] The Break section of the control access test uses SharedControl --- Testing/TestControlAccess.cc | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/Testing/TestControlAccess.cc b/Testing/TestControlAccess.cc index fbbe650..215981b 100644 --- a/Testing/TestControlAccess.cc +++ b/Testing/TestControlAccess.cc @@ -44,20 +44,22 @@ TEST_CASE( "control_access", "[control_access]" ) SECTION( "Break" ) { + SharedControl* shared = SharedControl::create_instance(); + std::thread thread( [&](){ - control.Break(); - } ); + shared->Break(); + } ); std::this_thread::sleep_for( std::chrono::milliseconds(100) ); - REQUIRE( control.GetBreakFlag() ); + REQUIRE( shared->GetBreakFlag() ); - control.Resume(); + shared->Resume(); std::this_thread::sleep_for( std::chrono::milliseconds(100) ); - REQUIRE_FALSE( control.GetBreakFlag() ); + REQUIRE_FALSE( shared->GetBreakFlag() ); thread.join(); - REQUIRE_FALSE( control.GetBreakFlag() ); + REQUIRE_FALSE( shared->GetBreakFlag() ); } } \ No newline at end of file From 72484b2a765a7faf00abe4e93537626b94c32d7f Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Wed, 8 Dec 2021 15:21:19 -0800 Subject: [PATCH 162/521] Added TestProcessorToolbox.cc --- Testing/TestProcessorToolbox.cc | 46 +++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 Testing/TestProcessorToolbox.cc diff --git a/Testing/TestProcessorToolbox.cc b/Testing/TestProcessorToolbox.cc new file mode 100644 index 0000000..9f2e52d --- /dev/null +++ b/Testing/TestProcessorToolbox.cc @@ -0,0 +1,46 @@ +/* + * TestProcessorToolbox.cc + * + * Created on: Nov 25, 2021 + * Author: N.S. Oblath + */ + +#include "TestProc.hh" + +#include "ProcessorToolbox.hh" + +#include "logger.hh" + +#include "catch.hpp" + +LOGGER( testlog, "TestProcessorToolbox" ); + + +TEST_CASE( "processor_toolbox" ) +{ + using namespace Nymph; + + ProcessorToolbox toolbox; + + SECTION( "Configuration" ) + { + REQUIRE_FALSE( toolbox.GetProcessor( "testproc-1" ) ); + + std::string config_str( + "processors:\n" + + " - type: test-proc\n" + + " name: testproc-1" + ) + + scarab::param_translator translator; + auto config = translator.read_string( config_str ); + + toolbox.Configure( config ); + + REQUIRE( toolbox.GetProcessor( "testproc-1" ) ); + + + } + + +} From aab1d18cdc4224204d40eb1080359a319713ea44 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Thu, 9 Dec 2021 11:28:13 -0800 Subject: [PATCH 163/521] Cleaning up modifications to use of signals and slots --- Library/Processor/PrimaryProcessor.cc | 2 +- Library/Processor/PrimaryProcessor.hh | 2 +- Library/Processor/Processor.hh | 12 +++++++++++- Library/Processor/Signal.hh | 9 +++++---- Library/Processor/SignalSlotBase.hh | 10 +++++----- Library/Processor/Slot.hh | 17 ++++++++++------- Testing/TestPrimaryProcessor.cc | 5 ++--- Testing/TestProc.hh | 4 ++-- Testing/TestProcessor.cc | 6 +++--- Testing/TestProcessorToolbox.cc | 11 ++++++----- 10 files changed, 46 insertions(+), 32 deletions(-) diff --git a/Library/Processor/PrimaryProcessor.cc b/Library/Processor/PrimaryProcessor.cc index 87ee3cf..90be231 100644 --- a/Library/Processor/PrimaryProcessor.cc +++ b/Library/Processor/PrimaryProcessor.cc @@ -23,7 +23,7 @@ namespace Nymph PrimaryProcessor::~PrimaryProcessor() {} - void PrimaryProcessor::operator()()// ControlAccessPtr control ) + void PrimaryProcessor::operator()()// ControlAccessPtr control ) // SharedControl is now accessed in Signal::operator(), so we don't have to pass it from signal to slot to signal, etc { // pass the control access pointer to every signal in the primary processor /* diff --git a/Library/Processor/PrimaryProcessor.hh b/Library/Processor/PrimaryProcessor.hh index 785ff57..5850396 100644 --- a/Library/Processor/PrimaryProcessor.hh +++ b/Library/Processor/PrimaryProcessor.hh @@ -22,7 +22,7 @@ namespace Nymph public: /// Callable function used by std::thread - void operator()();// ControlAccessPtr control ); + void operator()();// ControlAccessPtr control ); // SharedControl is now accessed in Signal::operator(), so we don't have to pass it from signal to slot to signal, etc /// Starts the main action of the processor virtual bool Run() = 0; diff --git a/Library/Processor/Processor.hh b/Library/Processor/Processor.hh index 294319b..b815f30 100644 --- a/Library/Processor/Processor.hh +++ b/Library/Processor/Processor.hh @@ -86,9 +86,19 @@ namespace Nymph return new scarab::registrar< Processor, XDerivedProc, const std::string& >( name ); } -#define REGISTER_PROCESSOR(proc_class, proc_name) \ +#define REGISTER_PROCESSOR_NONAMEPSACE(proc_class, proc_name) \ static ::scarab::registrar< ::Nymph::Processor, proc_class, const std::string& > sProc##proc_class##Registrar( proc_name ); +#define REGISTER_PROCESSOR_NAMESPACE(proc_namespace, proc_class, proc_name) \ + static ::scarab::registrar< ::Nymph::Processor, ::proc_namespace::proc_class, const std::string& > sProc##proc_class##Registrar( proc_name ); + +// Macro overloading trick from here: https://stackoverflow.com/a/11763277 +#define GET_MACRO(_1, _2, _3, NAME, ...) NAME +/// Processors defined in a namespace need to specify the namespace first: +/// [no namespace]: REGISTER_PROCESSOR( [class], [name in quotes] ) +/// [with namespace]: REGISTER_PROCESSOR( [namespace], [class], [name in quotes] ) +#define REGISTER_PROCESSOR(...) GET_MACRO(__VA_ARGS__, REGISTER_PROCESSOR_NAMESPACE, REGISTER_PROCESSOR_NONAMESPACE, )(__VA_ARGS__) + } /* namespace Nymph */ #endif /* NYMPH_PROCESSOR_HH_ */ diff --git a/Library/Processor/Signal.hh b/Library/Processor/Signal.hh index 2bb2ffe..8f04cf3 100644 --- a/Library/Processor/Signal.hh +++ b/Library/Processor/Signal.hh @@ -36,7 +36,7 @@ namespace Nymph { public: using signature = void( XArgs... ); - using full_signature = void( ControlAccessPtr, XArgs... ); +// using full_signature = void( ControlAccessPtr, XArgs... ); public: /// Unowned signal @@ -54,8 +54,8 @@ namespace Nymph void Emit( XArgs... args ); void operator()( XArgs... args ); - // TODO: remove this - MEMVAR_SHARED_PTR( ControlAccess, ControlAcc ); + // TODO: remove this // 12/8/21, NSO: why remove this? // NSO: oh, because we no longer need to pass ControlAccess between signals and slots before they're used + //MEMVAR_SHARED_PTR( ControlAccess, ControlAcc ); }; @@ -194,7 +194,8 @@ namespace Nymph for( auto connection : fConnections ) { - static_cast< Slot< XArgs... >* >(connection)->operator()( fControlAcc, args... ); +// static_cast< Slot< XArgs... >* >(connection)->operator()( fControlAcc, args... ); + static_cast< Slot< XArgs... >* >(connection)->operator()( args... ); } return; } diff --git a/Library/Processor/SignalSlotBase.hh b/Library/Processor/SignalSlotBase.hh index dc43d74..04bc1ef 100644 --- a/Library/Processor/SignalSlotBase.hh +++ b/Library/Processor/SignalSlotBase.hh @@ -42,8 +42,8 @@ namespace Nymph MEMVAR_REF( std::string, Name ); - typedef std::set< SignalBase* > signal_connections; // to get around the problem of having a comma inside a macro function argument - MEMVAR_REF_MUTABLE( signal_connections, Connections ); + typedef std::set< SignalBase* > SignalConnections; // to get around the problem of having a comma inside a macro function argument + MEMVAR_REF_MUTABLE( SignalConnections, Connections ); //MEMVAR_REF( std::vector< SignalBase* >, SignalsUsed ); @@ -68,15 +68,15 @@ namespace Nymph MEMVAR_REF( std::string, Name ); - typedef std::set< SlotBase* > slot_connections; // to get around the problem of having a comma inside a macro function argument - MEMVAR_REF_MUTABLE_CONST( slot_connections, Connections ); + typedef std::set< SlotBase* > SlotConnections; // to get around the problem of having a comma inside a macro function argument + MEMVAR_REF_MUTABLE_CONST( SlotConnections, Connections ); //MEMVAR( ControlAccess*, Control ); // doesn't use MEMVAR_PTR because Signal doesn't own the object pointed to by fControl MEMVAR( bool, DoBreakpoint ); protected: - friend class SignalBase; + friend class SlotBase; virtual void AddConnection( SlotBase* slot, int group ); }; diff --git a/Library/Processor/Slot.hh b/Library/Processor/Slot.hh index ad79b8b..1eb33a8 100644 --- a/Library/Processor/Slot.hh +++ b/Library/Processor/Slot.hh @@ -30,7 +30,7 @@ namespace Nymph { public: using signature = void( XArgs... ); - using full_signature = void( ControlAccessPtr, XArgs... ); +// using full_signature = void( ControlAccessPtr, XArgs... ); using signal_list = std::initializer_list< std::string >; public: @@ -61,14 +61,15 @@ namespace Nymph void operator()( XArgs... args ); /// execute fFunction with a ControlAccess object - void operator()( ControlAccessPtr access, XArgs... args ); +// void operator()( ControlAccessPtr access, XArgs... args ); MEMVAR_REF( boost::function< signature >, Function ); MEMVAR( bool, DoBreakpoint ); protected: - void SlotFuncWrapper( ControlAccessPtr access, XArgs... args ); +// void SlotFuncWrapper( ControlAccessPtr access, XArgs... args ); + void SlotFuncWrapper( XArgs... args ); }; @@ -206,21 +207,23 @@ namespace Nymph template< typename... XArgs > inline void Slot< XArgs... >::operator()( XArgs... args ) { - fFunction( args... ); +// fFunction( args... ); + SlotFuncWrapper( args... ); return; } - +/* template< typename... XArgs > inline void Slot< XArgs... >::operator()( ControlAccessPtr access, XArgs... args ) { SlotFuncWrapper( access, args... ); return; } - +*/ template< typename... XArgs > - inline void Slot< XArgs... >::SlotFuncWrapper( ControlAccessPtr access, XArgs... args ) + inline void Slot< XArgs... >::SlotFuncWrapper( /*ControlAccessPtr access,*/ XArgs... args ) { //TODO could do something with `access` here + //NOTE (12/9/21): instead of using `access`, get SharedControl and use that //for( auto signalIt = fSignalsUsed.begin(); signalIt != fSignalsUsed.end(); ++signalIt ) //{ // (*signalIt)->SetControl( access ); diff --git a/Testing/TestPrimaryProcessor.cc b/Testing/TestPrimaryProcessor.cc index 62afb44..0bb9940 100644 --- a/Testing/TestPrimaryProcessor.cc +++ b/Testing/TestPrimaryProcessor.cc @@ -61,10 +61,9 @@ TEST_CASE( "primary_processor", "[primary_processor]" ) tester.ConnectASlot( "value", tester, "value" ); - ControlAccess control; - tester( &control ); + tester(); REQUIRE( tester.GetValue() == tester.GetNewValue() ); - REQUIRE( tester.ValueSig().GetControl() == &control ); + //REQUIRE( tester.ValueSig().GetControl() == &control ); } diff --git a/Testing/TestProc.hh b/Testing/TestProc.hh index 19cb143..e733127 100644 --- a/Testing/TestProc.hh +++ b/Testing/TestProc.hh @@ -17,8 +17,8 @@ namespace Nymph class TestProc : public Processor { public: - TestProc() : - Processor( "test" ), + TestProc( const std::string& name = "test" ) : + Processor( name ), fValue( 0 ), fSecondValue( 0 ), fValueSig( "value", this ), diff --git a/Testing/TestProcessor.cc b/Testing/TestProcessor.cc index 42e7465..be824ad 100644 --- a/Testing/TestProcessor.cc +++ b/Testing/TestProcessor.cc @@ -13,7 +13,7 @@ LOGGER( testlog, "TestProcessor" ); -REGISTER_PROCESSOR(Nymph::TestProc, "test-proc"); +REGISTER_PROCESSOR(Nymph, TestProc, "test-proc"); TEST_CASE( "processor", "[signal],[slot],[processor]" ) @@ -115,8 +115,8 @@ TEST_CASE( "processor", "[signal],[slot],[processor]" ) // check initial value REQUIRE( tester.GetSecondValue() == 0 ); - REQUIRE( tester.Slots().at("second-value")->SignalsUsed().size() == 1 ); - REQUIRE( tester.Slots().at("second-value")->SignalsUsed()[0] == &tester.SecondValueSig() ); + //REQUIRE( tester.Slots().at("second-value")->SignalsUsed().size() == 1 ); + //REQUIRE( tester.Slots().at("second-value")->SignalsUsed()[0] == &tester.SecondValueSig() ); tester.ConnectASlot( "second-value", tester, "second-value-2" ); diff --git a/Testing/TestProcessorToolbox.cc b/Testing/TestProcessorToolbox.cc index 9f2e52d..6298598 100644 --- a/Testing/TestProcessorToolbox.cc +++ b/Testing/TestProcessorToolbox.cc @@ -10,6 +10,7 @@ #include "ProcessorToolbox.hh" #include "logger.hh" +#include "param_codec.hh" #include "catch.hpp" @@ -27,15 +28,15 @@ TEST_CASE( "processor_toolbox" ) REQUIRE_FALSE( toolbox.GetProcessor( "testproc-1" ) ); std::string config_str( - "processors:\n" + - " - type: test-proc\n" + - " name: testproc-1" - ) + "processors:" + "- type: test-proc" + " name: testproc-1" + ); scarab::param_translator translator; auto config = translator.read_string( config_str ); - toolbox.Configure( config ); + toolbox.Configure( config->as_node() ); REQUIRE( toolbox.GetProcessor( "testproc-1" ) ); From b7e667473fcd5117d7367cbe486bb404c223ba22 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Thu, 9 Dec 2021 13:11:17 -0800 Subject: [PATCH 164/521] Updated Scarab to v3.9.1 --- Scarab | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Scarab b/Scarab index 25cf398..62f3004 160000 --- a/Scarab +++ b/Scarab @@ -1 +1 @@ -Subproject commit 25cf3988ff1968cfc0750349c9c14e23b1b1697a +Subproject commit 62f3004eda6eab02d03bdedfb81e385d915f82a5 From 9d341c71eede79a20a90a5f3adcc27462887bda8 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Thu, 9 Dec 2021 13:47:34 -0800 Subject: [PATCH 165/521] A few more changes from upgrading Scarab --- CMakeLists.txt | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ccd1cef..4f34b38 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -89,9 +89,9 @@ endif( Nymph_ENABLE_PYTHON ) # Cereal ######## -set( JUST_INSTALL_CEREAL ON CACHE BOOL "Cereal option: only install library" FORCE) -add_subdirectory( External/cereal ) -include_directories( External/cereal/include ) +#set( JUST_INSTALL_CEREAL ON CACHE BOOL "Cereal option: only install library" FORCE) +#add_subdirectory( External/cereal ) +#include_directories( External/cereal/include ) ##################### @@ -115,7 +115,7 @@ pbuilder_add_submodule( Scarab Scarab ) pbuilder_use_sm_library( Scarab Scarab ) # this is needed for anything that wants to read or write JSON files -get_directory_property( RAPIDJSON_FILE_BUFFER_SIZE DIRECTORY Scarab/library DEFINITION RAPIDJSON_FILE_BUFFER_SIZE ) +get_directory_property( RAPIDJSON_FILE_BUFFER_SIZE DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/Scarab DEFINITION RAPIDJSON_FILE_BUFFER_SIZE ) set( RAPIDJSON_FILE_BUFFER_SIZE ${RAPIDJSON_FILE_BUFFER_SIZE} PARENT_SCOPE ) @@ -125,13 +125,9 @@ set( RAPIDJSON_FILE_BUFFER_SIZE ${RAPIDJSON_FILE_BUFFER_SIZE} PARENT_SCOPE ) add_subdirectory( Library ) -if (Nymph_ENABLE_TESTING) - add_subdirectory( Executables/Validation ) -endif (Nymph_ENABLE_TESTING) - -if (Nymph_ENABLE_EXECUTABLES) - add_subdirectory( Executables/Main ) -endif (Nymph_ENABLE_EXECUTABLES ) +#if (Nymph_ENABLE_EXECUTABLES) +# add_subdirectory( Executables/Main ) +#endif (Nymph_ENABLE_EXECUTABLES ) ######### From 067f4a021f515e879d88a54bb88ef074c7352bf1 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Thu, 9 Dec 2021 13:48:16 -0800 Subject: [PATCH 166/521] Finished the AddRemoveProcessors section of TestProcessorToolbox; one bug fix in the toolbox --- Library/Processor/ProcessorToolbox.cc | 2 +- Testing/TestProcessorToolbox.cc | 33 ++++++++++++++++++++++----- 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/Library/Processor/ProcessorToolbox.cc b/Library/Processor/ProcessorToolbox.cc index e6c124a..5cd2423 100644 --- a/Library/Processor/ProcessorToolbox.cc +++ b/Library/Processor/ProcessorToolbox.cc @@ -94,7 +94,7 @@ namespace Nymph { procName = procNode["name"]().as_string(); } - std::shared_ptr< Processor > newProc ( fProcFactory->create(procType, procType)); + std::shared_ptr< Processor > newProc ( fProcFactory->create(procType, procName)); if (newProc == NULL) { LERROR(proclog, "Unable to create processor of type <" << procType << ">"); diff --git a/Testing/TestProcessorToolbox.cc b/Testing/TestProcessorToolbox.cc index 6298598..fb5beb4 100644 --- a/Testing/TestProcessorToolbox.cc +++ b/Testing/TestProcessorToolbox.cc @@ -23,24 +23,45 @@ TEST_CASE( "processor_toolbox" ) ProcessorToolbox toolbox; - SECTION( "Configuration" ) + SECTION( "AddRemoveProcessors" ) { - REQUIRE_FALSE( toolbox.GetProcessor( "testproc-1" ) ); + LINFO( testlog, "Add/Remove Processor tests" ); + + std::string procName1( "testproc-1" ); + std::string procName2( "testproc-2" ); + + REQUIRE_FALSE( toolbox.GetProcessor( procName1 ) ); + REQUIRE_FALSE( toolbox.GetProcessor( procName2 ) ); std::string config_str( - "processors:" - "- type: test-proc" + "processors:\n" + "- type: test-proc\n" " name: testproc-1" ); scarab::param_translator translator; - auto config = translator.read_string( config_str ); + auto config = translator.read_string( config_str, "yaml" ); toolbox.Configure( config->as_node() ); - REQUIRE( toolbox.GetProcessor( "testproc-1" ) ); + REQUIRE( toolbox.GetProcessor( procName1 ) ); + REQUIRE( toolbox.GetProcessor( procName1 )->Name() == procName1 ); + + std::shared_ptr< Processor > tp1 = toolbox.ReleaseProcessor( procName1 ); + REQUIRE_FALSE( toolbox.GetProcessor( procName1 ) ); + + REQUIRE( toolbox.AddProcessor( procName1, tp1 ) ); + REQUIRE( toolbox.GetProcessor( procName1 ) ); + + REQUIRE( toolbox.AddProcessor( "test-proc", procName2 ) ); + REQUIRE( toolbox.GetProcessor( procName2 ) ); + REQUIRE( toolbox.RemoveProcessor( procName1 ) ); + REQUIRE_FALSE( toolbox.GetProcessor( procName1 ) ); + REQUIRE( toolbox.GetProcessor( procName2 ) ); + toolbox.ClearProcessors(); + REQUIRE_FALSE( toolbox.GetProcessor( procName2 ) ); } From fb07274ec86321c925af33835e3c675c82232af5 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Thu, 9 Dec 2021 13:11:17 -0800 Subject: [PATCH 167/521] Upgrade Scarab to v3.9.1 --- Scarab | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Scarab b/Scarab index d8a19bf..62f3004 160000 --- a/Scarab +++ b/Scarab @@ -1 +1 @@ -Subproject commit d8a19bfb2d8d41eff57a84f30760d1c4c3291ab0 +Subproject commit 62f3004eda6eab02d03bdedfb81e385d915f82a5 From a2b4c8a30019998b095ead38bd3bd90da00c6031 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Thu, 9 Dec 2021 13:47:34 -0800 Subject: [PATCH 168/521] A few more changes from upgrading Scarab --- CMakeLists.txt | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ccd1cef..4f34b38 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -89,9 +89,9 @@ endif( Nymph_ENABLE_PYTHON ) # Cereal ######## -set( JUST_INSTALL_CEREAL ON CACHE BOOL "Cereal option: only install library" FORCE) -add_subdirectory( External/cereal ) -include_directories( External/cereal/include ) +#set( JUST_INSTALL_CEREAL ON CACHE BOOL "Cereal option: only install library" FORCE) +#add_subdirectory( External/cereal ) +#include_directories( External/cereal/include ) ##################### @@ -115,7 +115,7 @@ pbuilder_add_submodule( Scarab Scarab ) pbuilder_use_sm_library( Scarab Scarab ) # this is needed for anything that wants to read or write JSON files -get_directory_property( RAPIDJSON_FILE_BUFFER_SIZE DIRECTORY Scarab/library DEFINITION RAPIDJSON_FILE_BUFFER_SIZE ) +get_directory_property( RAPIDJSON_FILE_BUFFER_SIZE DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/Scarab DEFINITION RAPIDJSON_FILE_BUFFER_SIZE ) set( RAPIDJSON_FILE_BUFFER_SIZE ${RAPIDJSON_FILE_BUFFER_SIZE} PARENT_SCOPE ) @@ -125,13 +125,9 @@ set( RAPIDJSON_FILE_BUFFER_SIZE ${RAPIDJSON_FILE_BUFFER_SIZE} PARENT_SCOPE ) add_subdirectory( Library ) -if (Nymph_ENABLE_TESTING) - add_subdirectory( Executables/Validation ) -endif (Nymph_ENABLE_TESTING) - -if (Nymph_ENABLE_EXECUTABLES) - add_subdirectory( Executables/Main ) -endif (Nymph_ENABLE_EXECUTABLES ) +#if (Nymph_ENABLE_EXECUTABLES) +# add_subdirectory( Executables/Main ) +#endif (Nymph_ENABLE_EXECUTABLES ) ######### From 61cbec08b438dcd30f651d37503511e6cef22d1d Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Thu, 9 Dec 2021 14:21:03 -0800 Subject: [PATCH 169/521] Added Connections tests for ProcessorToolbox --- Testing/TestProcessorToolbox.cc | 50 +++++++++++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 2 deletions(-) diff --git a/Testing/TestProcessorToolbox.cc b/Testing/TestProcessorToolbox.cc index fb5beb4..5060a21 100644 --- a/Testing/TestProcessorToolbox.cc +++ b/Testing/TestProcessorToolbox.cc @@ -26,7 +26,7 @@ TEST_CASE( "processor_toolbox" ) SECTION( "AddRemoveProcessors" ) { LINFO( testlog, "Add/Remove Processor tests" ); - + std::string procName1( "testproc-1" ); std::string procName2( "testproc-2" ); @@ -42,7 +42,7 @@ TEST_CASE( "processor_toolbox" ) scarab::param_translator translator; auto config = translator.read_string( config_str, "yaml" ); - toolbox.Configure( config->as_node() ); + REQUIRE( toolbox.Configure( config->as_node() ) ); REQUIRE( toolbox.GetProcessor( procName1 ) ); REQUIRE( toolbox.GetProcessor( procName1 )->Name() == procName1 ); @@ -64,5 +64,51 @@ TEST_CASE( "processor_toolbox" ) REQUIRE_FALSE( toolbox.GetProcessor( procName2 ) ); } + SECTION( "Connections" ) + { + LINFO( testlog, "Connections Tests") + + std::string procName1( "testproc-1" ); + std::string procName2( "testproc-2" ); + + std::string config_str( + "processors:\n" + "- type: test-proc\n" + " name: testproc-1\n" + "connections:\n" + "- signal: \"testproc-1:value\"\n" + " slot: \"testproc-1:second-value\"" + ); + + scarab::param_translator translator; + auto config = translator.read_string( config_str, "yaml" ); + + REQUIRE( toolbox.Configure( config->as_node() ) ); + + std::shared_ptr< Processor > tp1 = toolbox.GetProcessor( procName1 ); + + REQUIRE( tp1->Signals().at("value")->Connections().size() == 1 ); + REQUIRE( tp1->Slots().at("value")->Connections().size() == 0 ); + REQUIRE( tp1->Signals().at("second-value")->Connections().size() == 0 ); + REQUIRE( tp1->Slots().at("second-value")->Connections().size() == 1 ); + + tp1->Signals().at("value")->DisconnectAll(); + REQUIRE( tp1->Signals().at("value")->Connections().empty() ); + + toolbox.MakeConnection( "testproc-1:value", "testproc-1:second-value" ); + REQUIRE( tp1->Signals().at("value")->Connections().size() == 1 ); + REQUIRE( tp1->Slots().at("value")->Connections().size() == 0 ); + REQUIRE( tp1->Signals().at("second-value")->Connections().size() == 0 ); + REQUIRE( tp1->Slots().at("second-value")->Connections().size() == 1 ); + + tp1->Signals().at("value")->DisconnectAll(); + REQUIRE( tp1->Signals().at("value")->Connections().empty() ); + + toolbox.MakeConnection( "testproc-1", "value", "testproc-1", "second-value" ); + REQUIRE( tp1->Signals().at("value")->Connections().size() == 1 ); + REQUIRE( tp1->Slots().at("value")->Connections().size() == 0 ); + REQUIRE( tp1->Signals().at("second-value")->Connections().size() == 0 ); + REQUIRE( tp1->Slots().at("second-value")->Connections().size() == 1 ); + } } From 61b0b942551ec1776a6be5bd4c42225bfc408ea1 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Wed, 22 Dec 2021 11:15:59 -0800 Subject: [PATCH 170/521] Initial build-and-test workflow --- .github/workflows/build.yaml | 75 ++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 .github/workflows/build.yaml diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml new file mode 100644 index 0000000..b2f9a42 --- /dev/null +++ b/.github/workflows/build.yaml @@ -0,0 +1,75 @@ +name: Build and Test Nymph + +on: + pull_request: + push: + branches: [main, develop] + tags: ['*'] + +env: + Nymph_BUILD_NYMPH_EXE: ON + Nymph_ENABLE_EXECUTABLES: ON + Nymph_ENABLE_PYTHON: OFF + Nymph_ENABLE_TESTING: ON + Nymph_SINGLETHREADED: OFF + +jobs: + + build: + name: Build and Test + + runs-on: ${{ matrix.os }} + + strategy: + fail-fast: false + matrix: + os: [ubuntu-20.04, macOS-10.15] + python-version: [3.9] + + steps: + + - name: Checkout reposistory + uses: actions/checkout@master + with: + submodules: recursive + + - name: Set up Python + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + + - name: Mac Dependencies + if: startsWith(matrix.os, 'macos') # Mac only + run: | + brew update \ + brew install \ + boost + + - name: Linux Dependencies + if: startsWith(matrix.os, 'ubuntu') # Linux only + run: | + sudo apt-get update + sudo apt-get install -yq \ + boost + + - name: Configure + run: | + mkdir -p build + cd build + cmake -DNymph_BUILD_NYMPH_EXE=${Nymph_BUILD_NYMPH_EXE} -DNymph_ENABLE_EXECUTABLES=${Nymph_ENABLE_EXECUTABLES} -DNymph_ENABLE_PYTHON=${Nymph_ENABLE_PYTHON} -DNymph_ENABLE_TESTING=${Nymph_ENABLE_TESTING} -DNymph_SINGLETHREADED=${Nymph_SINGLETHREADED} .. + + - name: Build + run: | + cd build + make -j install + + - name: Run tests + run: | + cd build + Testing/RunTests + +# For debugging +# - name: Setup tmate session +# if: ${{ ! success() }} +# uses: mxschmitt/action-tmate@v3 + From dc2afddb4889308572ac3ef0ca136bca00f76a4c Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Wed, 22 Dec 2021 11:22:16 -0800 Subject: [PATCH 171/521] Fixing and updating dependencies --- .github/workflows/build.yaml | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index b2f9a42..56d1af5 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -41,16 +41,20 @@ jobs: - name: Mac Dependencies if: startsWith(matrix.os, 'macos') # Mac only run: | - brew update \ + brew update brew install \ - boost + boost \ + rapidjson \ + yaml-cpp - name: Linux Dependencies if: startsWith(matrix.os, 'ubuntu') # Linux only run: | sudo apt-get update sudo apt-get install -yq \ - boost + libboost-dev \ + libyaml-cpp-dev \ + rapidjson-dev - name: Configure run: | From 6853fcdbf8f1532186d5d1d92974076e95c1ab0b Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Wed, 22 Dec 2021 11:28:44 -0800 Subject: [PATCH 172/521] Remove use of brew update because it takes so long --- .github/workflows/build.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 56d1af5..67cab88 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -41,7 +41,6 @@ jobs: - name: Mac Dependencies if: startsWith(matrix.os, 'macos') # Mac only run: | - brew update brew install \ boost \ rapidjson \ From e115c095448bedac3acf1cfcda1e54e8ee5c5cb0 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Wed, 22 Dec 2021 11:28:54 -0800 Subject: [PATCH 173/521] Test without rt library --- cmake/Nymph.cmake | 1 - 1 file changed, 1 deletion(-) diff --git a/cmake/Nymph.cmake b/cmake/Nymph.cmake index 003dab9..1d4d1ef 100644 --- a/cmake/Nymph.cmake +++ b/cmake/Nymph.cmake @@ -49,7 +49,6 @@ macro (nymph_process_options) set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${FLAG_WARNINGS}") if( UNIX AND NOT APPLE ) - pbuilder_add_ext_libraries (rt) set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--no-as-needed") endif( UNIX AND NOT APPLE ) From c21b79d167e24545123f6c0e028f92fee73b854f Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Wed, 22 Dec 2021 11:37:07 -0800 Subject: [PATCH 174/521] Required the boost.chrono library --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4f34b38..4c3845f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -66,9 +66,9 @@ set( PRIVATE_EXT_LIBS ) ####### # Boost (1.46 required for filesystem version 3) -list( APPEND BOOST_COMPONENTS date_time filesystem program_options system thread ) +list( APPEND BOOST_COMPONENTS chrono date_time filesystem program_options system thread ) find_package( Boost 1.46.0 REQUIRED COMPONENTS ${BOOST_COMPONENTS} ) -list( APPEND PUBLIC_EXT_LIBS Boost::boost Boost::date_time Boost::program_options Boost::thread Boost::filesystem ) +list( APPEND PUBLIC_EXT_LIBS Boost::boost Boost::chrono Boost::date_time Boost::program_options Boost::thread Boost::filesystem ) # make sure dynamic linking is assumed for all boost libraries set( Boost_USE_STATIC_LIBS OFF ) set( Boost_USE_STATIC_RUNTIME OFF ) From a28eb557e2889c0a7de44493c4d56b65662c941d Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Wed, 22 Dec 2021 11:39:41 -0800 Subject: [PATCH 175/521] Enable tmate session for debugging --- .github/workflows/build.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 67cab88..5cb939b 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -72,7 +72,7 @@ jobs: Testing/RunTests # For debugging -# - name: Setup tmate session -# if: ${{ ! success() }} -# uses: mxschmitt/action-tmate@v3 + - name: Setup tmate session + if: ${{ ! success() }} + uses: mxschmitt/action-tmate@v3 From 4380c64b10acf1ec0e27469db808fab74cbae9c1 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Wed, 22 Dec 2021 13:44:39 -0800 Subject: [PATCH 176/521] Add a docker build based on p8compute_dependencies --- .github/workflows/build.yaml | 27 +++++++++++++++++++++++++++ Dockerfile | 10 ++++++---- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 5cb939b..3664632 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -12,9 +12,36 @@ env: Nymph_ENABLE_PYTHON: OFF Nymph_ENABLE_TESTING: ON Nymph_SINGLETHREADED: OFF + Nymph_TAG: test jobs: + docker_build: + name: Build and Test in Docker + + runs-on: ubuntu-20.04 + + steps: + + - name: Checkout the repo + uses: actions/checkout@v2 + with: + submodules: recursive + + - name: Build and run + run: | + docker build \ + --build-arg img_repo=${BASE_IMAGE_REPO} \ + --build-arg img_tag=${BASE_IMAGE_TAG} \ + --build-arg build_type=Debug \ + --build-arg build_tests_exe=${Nymph_ENABLE_TESTING} \ + --build-arg nymph_tag=${Nymph_TAG} \ + --tag project8/nymph:${Nymph_TAG} \ + . + +# docker run project8/nymph:${Nymph_TAG} /usr/local/p8/nymph/${Nymph_TAG} + + build: name: Build and Test diff --git a/Dockerfile b/Dockerfile index b743827..84e03cb 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,12 +1,13 @@ -FROM project8/p8compute_dependencies:v0.7.0 as nymph_common +FROM project8/p8compute_dependencies:v1.2.0 as nymph_common ARG build_type=Release ENV NYMPH_BUILD_TYPE=$build_type ARG build_tests_exe=FALSE ENV NYMPH_BUILD_TESTS_EXE=$build_tests_exe -ENV NYMPH_TAG=v2.17.0 -ENV NYMPH_BUILD_PREFIX=/usr/local/p8/katydid/$NYMPH_TAG +ARG nymph_tag=dev +ENV NYMPH_TAG=$nymph_tag +ENV NYMPH_BUILD_PREFIX=/usr/local/p8/nymph/$NYMPH_TAG RUN mkdir -p $NYMPH_BUILD_PREFIX &&\ chmod -R 777 $NYMPH_BUILD_PREFIX/.. &&\ @@ -24,9 +25,10 @@ FROM nymph_common as nymph_done COPY cmake /tmp_source/cmake COPY Executables /tmp_source/Executables -COPY External /tmp_source/External +#COPY External /tmp_source/External COPY Library /tmp_source/Library COPY Scarab /tmp_source/Scarab +COPY Testing /tmp_source/Testing COPY CMakeLists.txt /tmp_source/CMakeLists.txt COPY .git /tmp_source/.git From 2cf60d32a203720a069f6fbb101aaa8fe54e0eb7 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Wed, 22 Dec 2021 13:44:47 -0800 Subject: [PATCH 177/521] Fix boost package --- .github/workflows/build.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 3664632..e86c7d4 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -78,7 +78,7 @@ jobs: run: | sudo apt-get update sudo apt-get install -yq \ - libboost-dev \ + libboost-all-dev \ libyaml-cpp-dev \ rapidjson-dev From 3d778c8bd7b036d8ef9ed1279e28a86d6d089b4b Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Wed, 22 Dec 2021 14:13:52 -0800 Subject: [PATCH 178/521] Missing file in the docker build --- Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Dockerfile b/Dockerfile index 84e03cb..715365a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -30,6 +30,7 @@ COPY Library /tmp_source/Library COPY Scarab /tmp_source/Scarab COPY Testing /tmp_source/Testing COPY CMakeLists.txt /tmp_source/CMakeLists.txt +COPY NymphConfig.cmake.in /tmp_source/NymphConfig.cmake.in COPY .git /tmp_source/.git # repeat the cmake command to get the change of install prefix to set correctly (a package_builder known issue) From 8d089e01be416e0334fef6902128707cf1a85f2f Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Wed, 22 Dec 2021 14:45:09 -0800 Subject: [PATCH 179/521] Add test running to the docker build --- .github/workflows/build.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index e86c7d4..9ada860 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -28,9 +28,10 @@ jobs: with: submodules: recursive - - name: Build and run + - name: Build and test run: | docker build \ + --target nymph_common \ --build-arg img_repo=${BASE_IMAGE_REPO} \ --build-arg img_tag=${BASE_IMAGE_TAG} \ --build-arg build_type=Debug \ @@ -38,8 +39,7 @@ jobs: --build-arg nymph_tag=${Nymph_TAG} \ --tag project8/nymph:${Nymph_TAG} \ . - -# docker run project8/nymph:${Nymph_TAG} /usr/local/p8/nymph/${Nymph_TAG} + docker run project8/nymph:${Nymph_TAG} /tmp_source/Testing/RunTests build: From 8d059a3e440d1998bb7772c34771bbc39b01cfcf Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Wed, 22 Dec 2021 14:53:27 -0800 Subject: [PATCH 180/521] Fixing two more mistakes in the docker build --- .github/workflows/build.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 9ada860..d5611e5 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -31,7 +31,7 @@ jobs: - name: Build and test run: | docker build \ - --target nymph_common \ + --target nymph_done \ --build-arg img_repo=${BASE_IMAGE_REPO} \ --build-arg img_tag=${BASE_IMAGE_TAG} \ --build-arg build_type=Debug \ @@ -39,7 +39,7 @@ jobs: --build-arg nymph_tag=${Nymph_TAG} \ --tag project8/nymph:${Nymph_TAG} \ . - docker run project8/nymph:${Nymph_TAG} /tmp_source/Testing/RunTests + docker run project8/nymph:${Nymph_TAG} /tmp_source/build/Testing/RunTests build: From e1807f4f14f3583c803e4eccaeb2a5b841426ce2 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Wed, 22 Dec 2021 16:24:03 -0800 Subject: [PATCH 181/521] Add class revealing protected (previously private) methods in ProcessorToolbox for testing --- Library/Processor/ProcessorToolbox.hh | 14 +++++----- Testing/TestProcessorToolbox.cc | 37 ++++++++++++++++++++++++++- 2 files changed, 43 insertions(+), 8 deletions(-) diff --git a/Library/Processor/ProcessorToolbox.hh b/Library/Processor/ProcessorToolbox.hh index 96a6be9..b8574b3 100644 --- a/Library/Processor/ProcessorToolbox.hh +++ b/Library/Processor/ProcessorToolbox.hh @@ -88,14 +88,14 @@ namespace Nymph */ class ProcessorToolbox { - private: + protected: typedef std::unique_lock< std::mutex > unique_lock; public: ProcessorToolbox( const std::string& name = "processor-toolbox" ); virtual ~ProcessorToolbox(); - private: + protected: scarab::factory< Processor, const std::string& >* fProcFactory; // singleton; not owned by ProcessorToolbox @@ -108,7 +108,7 @@ namespace Nymph MEMVAR( bool, RunSingleThreaded ); - private: + protected: struct ProcessorInfo { std::shared_ptr< Processor > fProc; @@ -140,7 +140,7 @@ namespace Nymph /// Also clears the run queue void ClearProcessors(); - private: + protected: ProcessorMap fProcMap; @@ -170,7 +170,7 @@ namespace Nymph /// Remove a breakpoint from a signal bool RemoveBreakpoint( const std::string& signalProcName, const std::string& signalName ); - private: + protected: bool ParseSignalSlotName( const std::string& toParse, std::string& nameOfProc, std::string& nameOfSigSlot ) const; static const char fSigSlotNameSep = ':'; @@ -190,7 +190,7 @@ namespace Nymph /// Clear the run queue void ClearRunQueue(); - private: + protected: struct ThreadSource { PrimaryProcessor* fProc; @@ -243,7 +243,7 @@ namespace Nymph //MEMVAR_SHARED_PTR_CONST( SharedControl, Control ); - private: + protected: //typedef boost::shared_future< KTDataHandle > Future; //void StartSingleThreadedRun(); diff --git a/Testing/TestProcessorToolbox.cc b/Testing/TestProcessorToolbox.cc index 5060a21..aa6e7e9 100644 --- a/Testing/TestProcessorToolbox.cc +++ b/Testing/TestProcessorToolbox.cc @@ -17,6 +17,33 @@ LOGGER( testlog, "TestProcessorToolbox" ); +namespace Nymph +{ + class ProcTBRevealer : public ProcessorToolbox + { + public: + using ProcessorToolbox::ProcessorToolbox; + + bool ParseSignalSlotName( const std::string& toParse, std::string& nameOfProc, std::string& nameOfSigSlot ) const + { + return ProcessorToolbox::ParseSignalSlotName( toParse, nameOfProc, nameOfSigSlot ); + } + + using ProcessorToolbox::ThreadSource; + using ProcessorToolbox::ThreadSourceGroup; + bool AddProcessorToThreadGroup( const std::string& name, ThreadSourceGroup& group ) + { + return ProcessorToolbox::AddProcessorToThreadGroup( name, group ); + } + + void StartMultiThreadedRun() + { + return ProcessorToolbox::StartMultiThreadedRun(); + } + }; +} + + TEST_CASE( "processor_toolbox" ) { using namespace Nymph; @@ -66,7 +93,15 @@ TEST_CASE( "processor_toolbox" ) SECTION( "Connections" ) { - LINFO( testlog, "Connections Tests") + LINFO( testlog, "Connections Tests"); + + std::string toParse( "proc:sigslot" ); + std::string parsedProc, parsedSigSlot; + + ProcTBRevealer revealer; + revealer.ParseSignalSlotName( toParse, parsedProc, parsedSigSlot ); + REQUIRE( parsedProc == "proc" ); + REQUIRE( parsedSigSlot == "sigslot" ); std::string procName1( "testproc-1" ); std::string procName2( "testproc-2" ); From c8f046d3cd962431985f336ec59f9d960fda80fd Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Wed, 22 Dec 2021 16:41:43 -0800 Subject: [PATCH 182/521] Move the test primary processor class definition to TestProc.hh --- Testing/TestPrimaryProcessor.cc | 41 ++------------------------------- Testing/TestProc.hh | 38 ++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 39 deletions(-) diff --git a/Testing/TestPrimaryProcessor.cc b/Testing/TestPrimaryProcessor.cc index 0bb9940..4c7d659 100644 --- a/Testing/TestPrimaryProcessor.cc +++ b/Testing/TestPrimaryProcessor.cc @@ -5,9 +5,7 @@ * Author: N.S. Oblath */ -#include "PrimaryProcessor.hh" -#include "Signal.hh" -#include "Slot.hh" +#include "TestProc.hh" #include "logger.hh" @@ -15,43 +13,8 @@ LOGGER( testlog, "TestPrimaryProcessor" ); -namespace Nymph -{ - // concrete processor class that we can test - // implements Configure() and has its own signal and slot - class TestPrimaryProc : public PrimaryProcessor - { - public: - TestPrimaryProc() : - PrimaryProcessor( "test" ), - fNewValue( 10 ), - fValue( 0 ), - fValueSig( "value", this ), - fValueSlot( "value", this, &TestPrimaryProc::SetValue ) - {} - - virtual ~TestPrimaryProc() - {} - - void Configure( const scarab::param_node& ) - { - return; - } - - bool Run() - { - fValueSig( fNewValue ); - return true; - } +REGISTER_PROCESSOR( Nymph, TestPrimaryProc, "test-primary" ); - MEMVAR( int, NewValue ); - MEMVAR( int, Value ); - - MEMVAR_REF( Signal< int >, ValueSig ); - MEMVAR_REF( Slot< int >, ValueSlot ); - - }; -} TEST_CASE( "primary_processor", "[primary_processor]" ) { diff --git a/Testing/TestProc.hh b/Testing/TestProc.hh index e733127..ce8013d 100644 --- a/Testing/TestProc.hh +++ b/Testing/TestProc.hh @@ -5,6 +5,7 @@ * Author: N.S. Oblath */ +#include "PrimaryProcessor.hh" #include "Processor.hh" #include "Signal.hh" #include "Slot.hh" @@ -64,4 +65,41 @@ namespace Nymph return; } }; + + + // concrete primary processor class that we can test + // implements Configure(), Run(), and has its own signal and slot + class TestPrimaryProc : public PrimaryProcessor + { + public: + TestPrimaryProc( const std::string& name = "test" ) : + PrimaryProcessor( name ), + fNewValue( 10 ), + fValue( 0 ), + fValueSig( "value", this ), + fValueSlot( "value", this, &TestPrimaryProc::SetValue ) + {} + + virtual ~TestPrimaryProc() + {} + + void Configure( const scarab::param_node& ) + { + return; + } + + bool Run() + { + fValueSig( fNewValue ); + return true; + } + + MEMVAR( int, NewValue ); + MEMVAR( int, Value ); + + MEMVAR_REF( Signal< int >, ValueSig ); + MEMVAR_REF( Slot< int >, ValueSlot ); + + }; + } From 0a481abdea84999211fbc77f1ec072f065b0a8e5 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Wed, 22 Dec 2021 16:41:59 -0800 Subject: [PATCH 183/521] Add initial RunQueue tests --- Testing/TestProcessorToolbox.cc | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/Testing/TestProcessorToolbox.cc b/Testing/TestProcessorToolbox.cc index aa6e7e9..65747ef 100644 --- a/Testing/TestProcessorToolbox.cc +++ b/Testing/TestProcessorToolbox.cc @@ -48,7 +48,7 @@ TEST_CASE( "processor_toolbox" ) { using namespace Nymph; - ProcessorToolbox toolbox; + ProcTBRevealer toolbox; SECTION( "AddRemoveProcessors" ) { @@ -98,8 +98,7 @@ TEST_CASE( "processor_toolbox" ) std::string toParse( "proc:sigslot" ); std::string parsedProc, parsedSigSlot; - ProcTBRevealer revealer; - revealer.ParseSignalSlotName( toParse, parsedProc, parsedSigSlot ); + toolbox.ParseSignalSlotName( toParse, parsedProc, parsedSigSlot ); REQUIRE( parsedProc == "proc" ); REQUIRE( parsedSigSlot == "sigslot" ); @@ -146,4 +145,29 @@ TEST_CASE( "processor_toolbox" ) REQUIRE( tp1->Slots().at("second-value")->Connections().size() == 1 ); } + SECTION( "RunQueue" ) + { + LINFO( "RunQueue Tests" ); + + std::string config_str( + "processors:\n" + "- type: test-primary\n" + " name: testprimary\n" + "- type: test-proc\n" + " name: testproc-1\n" + ); + + scarab::param_translator translator; + auto config = translator.read_string( config_str, "yaml" ); + + REQUIRE( toolbox.Configure( config->as_node() ) ); + + ProcTBRevealer::ThreadSourceGroup group; + REQUIRE_FALSE( toolbox.AddProcessorToThreadGroup( "blah", group ) ); + REQUIRE_FALSE( toolbox.AddProcessorToThreadGroup( "testproc-1", group ) ); + REQUIRE( toolbox.AddProcessorToThreadGroup( "testprimary", group ) ); + + // TODO: test public functions for RunQueue in ProcTB + } + } From b5d7657bbe48d137badaaf257ba6ee0d0a0ad6b9 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Thu, 23 Dec 2021 02:40:04 -0800 Subject: [PATCH 184/521] RunQueue modification tests are complete --- Testing/TestProcessorToolbox.cc | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/Testing/TestProcessorToolbox.cc b/Testing/TestProcessorToolbox.cc index 65747ef..fb0a4e6 100644 --- a/Testing/TestProcessorToolbox.cc +++ b/Testing/TestProcessorToolbox.cc @@ -40,6 +40,12 @@ namespace Nymph { return ProcessorToolbox::StartMultiThreadedRun(); } + + using ProcessorToolbox::RunQueue; + RunQueue& GetRunQueue() + { + return fRunQueue; + } }; } @@ -152,7 +158,9 @@ TEST_CASE( "processor_toolbox" ) std::string config_str( "processors:\n" "- type: test-primary\n" - " name: testprimary\n" + " name: testprimary-1\n" + "- type: test-primary\n" + " name: testprimary-2\n" "- type: test-proc\n" " name: testproc-1\n" ); @@ -165,9 +173,27 @@ TEST_CASE( "processor_toolbox" ) ProcTBRevealer::ThreadSourceGroup group; REQUIRE_FALSE( toolbox.AddProcessorToThreadGroup( "blah", group ) ); REQUIRE_FALSE( toolbox.AddProcessorToThreadGroup( "testproc-1", group ) ); - REQUIRE( toolbox.AddProcessorToThreadGroup( "testprimary", group ) ); + REQUIRE( toolbox.AddProcessorToThreadGroup( "testprimary-1", group ) ); + REQUIRE( group.size() == 1 ); + + REQUIRE_FALSE( toolbox.PushBackToRunQueue( "testproc-1" ) ); + REQUIRE( toolbox.PushBackToRunQueue( "testprimary-1" ) ); + REQUIRE( toolbox.GetRunQueue().size() == 1 ); + REQUIRE( toolbox.GetRunQueue().begin()[0].size() == 1 ); + REQUIRE( toolbox.PushBackToRunQueue( "testprimary-2" ) ); + REQUIRE( toolbox.GetRunQueue().size() == 2 ); + REQUIRE( toolbox.GetRunQueue().begin()[0].size() == 1 ); + + toolbox.PopBackOfRunQueue(); + REQUIRE( toolbox.GetRunQueue().size() == 1 ); + + toolbox.ClearRunQueue(); + REQUIRE( toolbox.GetRunQueue().empty() ); + + REQUIRE( toolbox.PushBackToRunQueue( {"testprimary-1", "testprimary-2"} ) ); + REQUIRE( toolbox.GetRunQueue().size() == 1 ); + REQUIRE( toolbox.GetRunQueue()[0].size() == 2 ); - // TODO: test public functions for RunQueue in ProcTB } } From fdfb7ef2ef8e9bd0e130a4f330050313bf3b1021 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Wed, 5 Jan 2022 00:32:12 -0800 Subject: [PATCH 185/521] Added a type-indexed unordered map to the DataFrame class. --- Library/Data/DataFrame.cc | 3 ++- Library/Data/DataFrame.hh | 12 ++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/Library/Data/DataFrame.cc b/Library/Data/DataFrame.cc index 833fdce..1224059 100644 --- a/Library/Data/DataFrame.cc +++ b/Library/Data/DataFrame.cc @@ -9,7 +9,8 @@ namespace Nymph { - DataFrame::DataFrame() + DataFrame::DataFrame() : + fDataObjects() {} DataFrame::~DataFrame() diff --git a/Library/Data/DataFrame.hh b/Library/Data/DataFrame.hh index 8a8b62d..4fa24ef 100644 --- a/Library/Data/DataFrame.hh +++ b/Library/Data/DataFrame.hh @@ -9,6 +9,14 @@ #ifndef NYMPH_DATAFRAME_HH_ #define NYMPH_DATAFRAME_HH_ +#include "Data.hh" + +#include "MemberVariable.hh" + +#include +#include +#include + namespace Nymph { @@ -17,6 +25,10 @@ namespace Nymph public: DataFrame(); virtual ~DataFrame(); + + // typedef used to avoid problems with the comma in the MEMVAR macro + typedef std::unordered_map< std::type_index, std::unique_ptr > DataMap; + MEMVAR_REF( DataMap, DataObjects ); }; } /* namespace Nymph */ From fe90f35e7a80dec9bffe99287c0e0422c8fa5030 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Wed, 5 Jan 2022 00:32:50 -0800 Subject: [PATCH 186/521] Added Data and DataFrame to the library CMakeLists.txt. Added a simple test for DataFrame. --- Library/CMakeLists.txt | 6 ++++++ Testing/CMakeLists.txt | 1 + Testing/TestDataFrame.cc | 20 ++++++++++++++++++++ 3 files changed, 27 insertions(+) create mode 100644 Testing/TestDataFrame.cc diff --git a/Library/CMakeLists.txt b/Library/CMakeLists.txt index 211e52f..53b93c7 100644 --- a/Library/CMakeLists.txt +++ b/Library/CMakeLists.txt @@ -20,6 +20,9 @@ include_directories( BEFORE set( NYMPH_HEADERFILES ${UTIL_DIR}/Exception.hh ${UTIL_DIR}/MemberVariable.hh + + ${DATA_DIR}/Data.hh + ${DATA_DIR}/DataFrame.hh ${PROC_DIR}/ControlAccess.hh ${PROC_DIR}/PrimaryProcessor.hh @@ -30,6 +33,9 @@ set( NYMPH_HEADERFILES set( NYMPH_SOURCEFILES ${UTIL_DIR}/Exception.cc + ${DATA_DIR}/Data.cc + ${DATA_DIR}/DataFrame.cc + ${PROC_DIR}/ControlAccess.cc ${PROC_DIR}/PrimaryProcessor.cc ${PROC_DIR}/Processor.cc diff --git a/Testing/CMakeLists.txt b/Testing/CMakeLists.txt index 29726b0..88aecbb 100644 --- a/Testing/CMakeLists.txt +++ b/Testing/CMakeLists.txt @@ -9,6 +9,7 @@ set( testing_HEADERS set( testing_SOURCES TestControlAccess.cc + TestDataFrame.cc TestPrimaryProcessor.cc TestProcessor.cc TestSignalSlot.cc diff --git a/Testing/TestDataFrame.cc b/Testing/TestDataFrame.cc new file mode 100644 index 0000000..d61096c --- /dev/null +++ b/Testing/TestDataFrame.cc @@ -0,0 +1,20 @@ +/* + * TestDataFrame.cc + * + * Created on: Jan 5, 2022 + * Author: N.S. Oblath + */ + +#include "DataFrame.hh" + +#include "catch.hpp" + + +TEST_CASE( "data_frame", "[data]" ) +{ + using namespace Nymph; + + DataFrame frame; + REQUIRE( frame.DataObjects().empty() ); + +} From a27fe9f0b64294623e0887be11df2a997fc73bdc Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Mon, 10 Jan 2022 16:12:59 -0800 Subject: [PATCH 187/521] Added basic data tests --- Testing/CMakeLists.txt | 1 + Testing/TestData.cc | 28 ++++++++++++++++++++ Testing/TestDataClasses.hh | 54 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 83 insertions(+) create mode 100644 Testing/TestData.cc create mode 100644 Testing/TestDataClasses.hh diff --git a/Testing/CMakeLists.txt b/Testing/CMakeLists.txt index 88aecbb..c9324fe 100644 --- a/Testing/CMakeLists.txt +++ b/Testing/CMakeLists.txt @@ -9,6 +9,7 @@ set( testing_HEADERS set( testing_SOURCES TestControlAccess.cc + TestData.cc TestDataFrame.cc TestPrimaryProcessor.cc TestProcessor.cc diff --git a/Testing/TestData.cc b/Testing/TestData.cc new file mode 100644 index 0000000..8682488 --- /dev/null +++ b/Testing/TestData.cc @@ -0,0 +1,28 @@ +/* + * TestData.cc + * + * Created on: Jan 6, 2022 + * Author: N.S. Oblath + */ + +#include "TestDataClasses.hh" + +#include "catch.hpp" + + +TEST_CASE( "data", "[data]" ) +{ + using namespace Nymph; + + TestData1 data1; + REQUIRE( data1.GetIValue1() == 0 ); + REQUIRE( data1.GetIValue2() == 5 ); + + data1.SetIValue1( 50 ); + REQUIRE( data1.GetIValue1() == 50 ); + + TestData2 data2; + REQUIRE( data2.GetDValue1() == Approx( 0.0 ) ); + REQUIRE( data2.GetDValue2() == Approx( 10.0 ) ); + +} diff --git a/Testing/TestDataClasses.hh b/Testing/TestDataClasses.hh new file mode 100644 index 0000000..c23650a --- /dev/null +++ b/Testing/TestDataClasses.hh @@ -0,0 +1,54 @@ +/* + * TestDataClasses.hh + * + * Created on: Jan 6, 2022 + * Author: N.S. Oblath + */ + +#ifndef NYMPH_TESTING_TESTDATACLASSES +#define NYMPH_TESTING_TESTDATACLASSES + +#include "Data.hh" +#include "MemberVariable.hh" + +#include +namespace Nymph +{ + class TestData1 : public Data + { + public: + TestData1() : + Data(), + fIValue1( 0 ), + fIValue2( 5 ) + { + std::cerr << "in test data 1 constuctor" << std::endl; + } + + virtual ~TestData1() + {} + + MEMVAR( int, IValue1 ); + MEMVAR( int, IValue2 ); + }; + + class TestData2 : public Data + { + public: + TestData2() : + Data(), + fDValue1( 0. ), + fDValue2( 10. ) + {} + + virtual ~TestData2() + {} + + MEMVAR( double, DValue1 ); + MEMVAR( double, DValue2 ); + }; + + +} /* namespace Nymph */ + +#endif /* NYMPH_TESTING_TESTDATACLASSES */ From 49dc444ca081885aad94adefdf958436af09bea2 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Mon, 10 Jan 2022 16:14:15 -0800 Subject: [PATCH 188/521] Fill out DataFrame a bit --- Library/Data/DataFrame.hh | 58 +++++++++++++++++++++++++++++++++++++++ Testing/TestDataFrame.cc | 23 +++++++++++++++- 2 files changed, 80 insertions(+), 1 deletion(-) diff --git a/Library/Data/DataFrame.hh b/Library/Data/DataFrame.hh index 4fa24ef..3a3cb72 100644 --- a/Library/Data/DataFrame.hh +++ b/Library/Data/DataFrame.hh @@ -10,27 +10,85 @@ #define NYMPH_DATAFRAME_HH_ #include "Data.hh" +#include "Exception.hh" #include "MemberVariable.hh" +#include "typename.hh" + #include #include #include namespace Nymph { + struct DataFrameException : virtual public Exception {}; + + /*! + @class DataFrame + + @author N. S. Oblath + + @brief Container for Data objects used during data processing + @details + Individual Data objects are held in an unordered map, indexed by type. + + */ class DataFrame { public: DataFrame(); virtual ~DataFrame(); + /// Returns true if object of type XData exists in the frame; returns false otherwise + template< typename XData > + bool Has() const; + + /// Returns a reference to the object of type XData if it exists in the frame. + /// Creates and returns a reference to an object of type XData if it does not exist. + template< typename XData > + XData& Get(); + + /// Returns a reference to the object of type XData if it exists in the frame. + /// Throws DataFrameException if it does not exist. + template< typename XData > + const XData& Get() const; + // typedef used to avoid problems with the comma in the MEMVAR macro typedef std::unordered_map< std::type_index, std::unique_ptr > DataMap; MEMVAR_REF( DataMap, DataObjects ); }; + + template< typename XData > + bool DataFrame::Has() const + { + return fDataObjects.count( typeid(XData) ) != 0; + } + + template< typename XData > + XData& DataFrame::Get() + { + if( Has< XData >() ) + { + return static_cast< XData& >( *fDataObjects[typeid(XData)] ); + } + + fDataObjects[ typeid(XData) ].reset( new XData() ); + return static_cast< XData& >( *fDataObjects[typeid(XData)] ); + } + + template< typename XData > + const XData& DataFrame::Get() const + { + if( Has< XData >() ) + { + return static_cast< const XData& >( *fDataObjects.at(typeid(XData) )); + } + BOOST_THROW_EXCEPTION( DataFrameException() << "Data type <" << scarab::type(XData()) << "> is not present when const Get() was called" << eom ); + } + } /* namespace Nymph */ #endif /* NYMPH_DATAFRAME_HH_ */ diff --git a/Testing/TestDataFrame.cc b/Testing/TestDataFrame.cc index d61096c..290e350 100644 --- a/Testing/TestDataFrame.cc +++ b/Testing/TestDataFrame.cc @@ -1,10 +1,12 @@ /* * TestDataFrame.cc * - * Created on: Jan 5, 2022 + * Created on: Jan 6, 2022 * Author: N.S. Oblath */ +#include "TestDataClasses.hh" + #include "DataFrame.hh" #include "catch.hpp" @@ -15,6 +17,25 @@ TEST_CASE( "data_frame", "[data]" ) using namespace Nymph; DataFrame frame; + const DataFrame& cFrame = frame; + REQUIRE( frame.DataObjects().empty() ); + REQUIRE_FALSE( frame.Has< TestData1 >() ); + REQUIRE_FALSE( frame.Has< TestData2 >() ); + + // create a data object with Get() + TestData1& data1 = frame.Get< TestData1 >(); + REQUIRE( frame.Has< TestData1 >() ); + // ensure TestData1 object was initialized correctly + REQUIRE( data1.GetIValue1() == 0 ); + REQUIRE( data1.GetIValue2() == 5 ); + + // make sure that we haven't made a copy of the data object + data1.SetIValue1( 50 ); + REQUIRE( data1.GetIValue1() == 50 ); + REQUIRE( frame.Get< TestData1 >().GetIValue1() == 50 ); + // check const access + REQUIRE( cFrame.Get< TestData1 >().GetIValue1() == 50 ); + REQUIRE_THROWS_AS( cFrame.Get< TestData2 >(), DataFrameException ); } From d3a2fb9476ea250f4791b3c3eafa832c3a781807 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Mon, 10 Jan 2022 16:14:24 -0800 Subject: [PATCH 189/521] Add basic exception testing --- Testing/CMakeLists.txt | 1 + Testing/TestException.cc | 35 ++++++++++++++++ Testing/TestExt.cc | 88 ---------------------------------------- 3 files changed, 36 insertions(+), 88 deletions(-) create mode 100644 Testing/TestException.cc delete mode 100644 Testing/TestExt.cc diff --git a/Testing/CMakeLists.txt b/Testing/CMakeLists.txt index c9324fe..08cdc80 100644 --- a/Testing/CMakeLists.txt +++ b/Testing/CMakeLists.txt @@ -11,6 +11,7 @@ set( testing_SOURCES TestControlAccess.cc TestData.cc TestDataFrame.cc + TestException.cc TestPrimaryProcessor.cc TestProcessor.cc TestSignalSlot.cc diff --git a/Testing/TestException.cc b/Testing/TestException.cc new file mode 100644 index 0000000..69511d9 --- /dev/null +++ b/Testing/TestException.cc @@ -0,0 +1,35 @@ +/* + * TestException.cc + * + * Created on: Jan 6, 2022 + * Author: N.S. Oblath + */ + +#include "Exception.hh" + +#include "catch.hpp" + +#include "logger.hh" + +LOGGER( testlog, "TestException" ); + +TEST_CASE( "exception", "[utility]" ) +{ + using namespace Nymph; + + auto throwException = []() { + BOOST_THROW_EXCEPTION( Exception() << "Test exception" << eom ); + }; + + REQUIRE_THROWS_AS( throwException(), Exception ); + + try + { + throwException(); + } + catch(const Exception& e) + { + LWARN( testlog, diagnostic_information(e) ); + } + +} diff --git a/Testing/TestExt.cc b/Testing/TestExt.cc deleted file mode 100644 index 9521af1..0000000 --- a/Testing/TestExt.cc +++ /dev/null @@ -1,88 +0,0 @@ -/* - * TestExt.cc - * - * Created on: Aug 23, 2019 - * Author: N.S. Oblath - */ - -#include "KTExtensible.hh" - -#include "catch.hpp" - -namespace Nymph -{ - class MyBaseClass - { - public: - MyBaseClass() {} - virtual ~MyBaseClass() {} - }; - - class MyClass1 : public KTExtensible< MyClass1, MyBaseClass > - { - public: - MyClass1() : KTExtensible< MyClass1, MyBaseClass >(), fValue() {} - MyClass1( const MyClass1& orig ) : KTExtensible< MyClass1, MyBaseClass >( orig ), fValue( orig.fValue ) {} - virtual ~MyClass1() {}; - public: - int fValue; - }; - - class MyClass2 : public KTExtensible< MyClass2, MyBaseClass > - { - public: - MyClass2() : KTExtensible< MyClass2, MyBaseClass >(), fValue() {} - MyClass2( const MyClass2& orig ) : KTExtensible< MyClass2, MyBaseClass >( orig ), fValue( orig.fValue ) {} - virtual ~MyClass2() {}; - public: - int fValue; - }; - -} - -TEST_CASE( "extensible", "[utility]" ) -{ - using namespace Nymph; - - std::shared_ptr< MyClass1 > data1 = std::make_shared< MyClass1 >(); - data1->fValue = 5; - - MyClass2& data2 = data1->Of< MyClass2 >(); - data2.fValue = 3; - - std::shared_ptr< MyClass2 > data2Shared = data1->Share< MyClass2 >(); - - SECTION( "Basic extensibility and values" ) - { - REQUIRE( data1->Has< MyClass1 >() ); - REQUIRE( data1->Has< MyClass2 >() ); - REQUIRE_FALSE( data2.Has< MyClass1 >() ); - REQUIRE( data2.Has< MyClass2 >() ); - - REQUIRE( data1->fValue == 5 ); - REQUIRE( data2.fValue == 3 ); - - REQUIRE( data2Shared->fValue == 3 ); - - REQUIRE( data1->size() == 2 ); - REQUIRE( data2.size() == 1 ); - } - - std::shared_ptr< MyClass1 > copyOfData1 = std::make_shared< MyClass1 >( *data1 ); - MyClass2& copyOfData2 = copyOfData1->Of< MyClass2 >(); - - SECTION( "Copying data" ) - { - REQUIRE( copyOfData1->fValue == data1->fValue ); - REQUIRE_FALSE( copyOfData1 == data1 ); - REQUIRE( copyOfData2.fValue == data2.fValue ); - } - - std::shared_ptr< MyClass2 > detatchedCopyOfData2 = copyOfData1->Detatch< MyClass2 >(); - - SECTION( "Detatching" ) - { - REQUIRE( copyOfData1->size() == 1 ); - REQUIRE( detatchedCopyOfData2->size() == 1 ); - } -} From 9af5c06a741b4ef74f5a292415b3adc4348e307c Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Mon, 10 Jan 2022 16:14:24 -0800 Subject: [PATCH 190/521] Add basic exception testing --- Testing/CMakeLists.txt | 1 + Testing/TestException.cc | 35 ++++++++++++++++ Testing/TestExt.cc | 88 ---------------------------------------- 3 files changed, 36 insertions(+), 88 deletions(-) create mode 100644 Testing/TestException.cc delete mode 100644 Testing/TestExt.cc diff --git a/Testing/CMakeLists.txt b/Testing/CMakeLists.txt index 29726b0..da40e68 100644 --- a/Testing/CMakeLists.txt +++ b/Testing/CMakeLists.txt @@ -9,6 +9,7 @@ set( testing_HEADERS set( testing_SOURCES TestControlAccess.cc + TestException.cc TestPrimaryProcessor.cc TestProcessor.cc TestSignalSlot.cc diff --git a/Testing/TestException.cc b/Testing/TestException.cc new file mode 100644 index 0000000..69511d9 --- /dev/null +++ b/Testing/TestException.cc @@ -0,0 +1,35 @@ +/* + * TestException.cc + * + * Created on: Jan 6, 2022 + * Author: N.S. Oblath + */ + +#include "Exception.hh" + +#include "catch.hpp" + +#include "logger.hh" + +LOGGER( testlog, "TestException" ); + +TEST_CASE( "exception", "[utility]" ) +{ + using namespace Nymph; + + auto throwException = []() { + BOOST_THROW_EXCEPTION( Exception() << "Test exception" << eom ); + }; + + REQUIRE_THROWS_AS( throwException(), Exception ); + + try + { + throwException(); + } + catch(const Exception& e) + { + LWARN( testlog, diagnostic_information(e) ); + } + +} diff --git a/Testing/TestExt.cc b/Testing/TestExt.cc deleted file mode 100644 index 9521af1..0000000 --- a/Testing/TestExt.cc +++ /dev/null @@ -1,88 +0,0 @@ -/* - * TestExt.cc - * - * Created on: Aug 23, 2019 - * Author: N.S. Oblath - */ - -#include "KTExtensible.hh" - -#include "catch.hpp" - -namespace Nymph -{ - class MyBaseClass - { - public: - MyBaseClass() {} - virtual ~MyBaseClass() {} - }; - - class MyClass1 : public KTExtensible< MyClass1, MyBaseClass > - { - public: - MyClass1() : KTExtensible< MyClass1, MyBaseClass >(), fValue() {} - MyClass1( const MyClass1& orig ) : KTExtensible< MyClass1, MyBaseClass >( orig ), fValue( orig.fValue ) {} - virtual ~MyClass1() {}; - public: - int fValue; - }; - - class MyClass2 : public KTExtensible< MyClass2, MyBaseClass > - { - public: - MyClass2() : KTExtensible< MyClass2, MyBaseClass >(), fValue() {} - MyClass2( const MyClass2& orig ) : KTExtensible< MyClass2, MyBaseClass >( orig ), fValue( orig.fValue ) {} - virtual ~MyClass2() {}; - public: - int fValue; - }; - -} - -TEST_CASE( "extensible", "[utility]" ) -{ - using namespace Nymph; - - std::shared_ptr< MyClass1 > data1 = std::make_shared< MyClass1 >(); - data1->fValue = 5; - - MyClass2& data2 = data1->Of< MyClass2 >(); - data2.fValue = 3; - - std::shared_ptr< MyClass2 > data2Shared = data1->Share< MyClass2 >(); - - SECTION( "Basic extensibility and values" ) - { - REQUIRE( data1->Has< MyClass1 >() ); - REQUIRE( data1->Has< MyClass2 >() ); - REQUIRE_FALSE( data2.Has< MyClass1 >() ); - REQUIRE( data2.Has< MyClass2 >() ); - - REQUIRE( data1->fValue == 5 ); - REQUIRE( data2.fValue == 3 ); - - REQUIRE( data2Shared->fValue == 3 ); - - REQUIRE( data1->size() == 2 ); - REQUIRE( data2.size() == 1 ); - } - - std::shared_ptr< MyClass1 > copyOfData1 = std::make_shared< MyClass1 >( *data1 ); - MyClass2& copyOfData2 = copyOfData1->Of< MyClass2 >(); - - SECTION( "Copying data" ) - { - REQUIRE( copyOfData1->fValue == data1->fValue ); - REQUIRE_FALSE( copyOfData1 == data1 ); - REQUIRE( copyOfData2.fValue == data2.fValue ); - } - - std::shared_ptr< MyClass2 > detatchedCopyOfData2 = copyOfData1->Detatch< MyClass2 >(); - - SECTION( "Detatching" ) - { - REQUIRE( copyOfData1->size() == 1 ); - REQUIRE( detatchedCopyOfData2->size() == 1 ); - } -} From 68a37159c39b11d6c0685fea6eb444263982413b Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Tue, 11 Jan 2022 02:36:03 -0800 Subject: [PATCH 191/521] Swapped out boost::exception for a simplified exception system that records file and line number of the throw with macros. --- Library/CMakeLists.txt | 2 +- Library/Processor/Processor.cc | 38 ++++++------ Library/Processor/Signal.hh | 6 +- Library/Utility/Exception.cc | 5 +- Library/Utility/Exception.hh | 91 ++++++++++++++++++++++++++--- Testing/TestException.cc | 103 ++++++++++++++++++++++++++++++++- 6 files changed, 211 insertions(+), 34 deletions(-) diff --git a/Library/CMakeLists.txt b/Library/CMakeLists.txt index 211e52f..2287e43 100644 --- a/Library/CMakeLists.txt +++ b/Library/CMakeLists.txt @@ -28,7 +28,7 @@ set( NYMPH_HEADERFILES ) set( NYMPH_SOURCEFILES - ${UTIL_DIR}/Exception.cc + #${UTIL_DIR}/Exception.cc ${PROC_DIR}/ControlAccess.cc ${PROC_DIR}/PrimaryProcessor.cc diff --git a/Library/Processor/Processor.cc b/Library/Processor/Processor.cc index 4a56b47..7aa6ac6 100644 --- a/Library/Processor/Processor.cc +++ b/Library/Processor/Processor.cc @@ -68,15 +68,19 @@ namespace Nymph SigMapIt signalIt = fSignals.find(signalName); if( signalIt == fSignals.end() ) { - BOOST_THROW_EXCEPTION( SignalException() << "Unable to connect signal <" + signalName + "> to slot <" + slotName + "> due to a problem with the signal.\n" << - "You may have the signal name wrong." << eom ); + //throw EXCEPT_HERE(SignalException()) << "Unable to connect signal <" + signalName + "> to slot <" + slotName + "> due to a problem with the signal.\n" << + // "You may have the signal name wrong."; +// BOOST_THROW_EXCEPTION( SignalException() << "Unable to connect signal <" + signalName + "> to slot <" + slotName + "> due to a problem with the signal.\n" << +// "You may have the signal name wrong." << eom ); } SlotMapIt slotIt = processor.fSlots.find(slotName); if( slotIt == processor.fSlots.end() ) { - BOOST_THROW_EXCEPTION( SlotException() << "Unable to connect signal <" + signalName + "> to slot <" + slotName + "> due to a problem with the slot." << - "You may have the slot name wrong." << eom ); + //throw EXCEPT_HERE(SlotException()) << "Unable to connect signal <" + signalName + "> to slot <" + slotName + "> due to a problem with the slot." << + // "You may have the slot name wrong."; +// BOOST_THROW_EXCEPTION( SlotException() << "Unable to connect signal <" + signalName + "> to slot <" + slotName + "> due to a problem with the slot." << +// "You may have the slot name wrong." << eom ); } try @@ -86,26 +90,22 @@ namespace Nymph } catch( SignalException& e ) { - e << ErrorMsgInfo< struct proc_Sig_0 >( "Unable to connect signal <" + signalName + "> to slot <" + slotName + "> due to a problem with the signal." ); - e << ErrorMsgInfo< struct proc_Sig_1 >( "You may have the signal name wrong." ); - throw; + //std::throw_with_nested( EXCEPT_HERE(SignalException()) << "Unable to connect signal <" << signalName << "> to slot <" << slotName << "> due to a problem with the signal." << + // " You may have the signal name wrong." ); } catch( SlotException& e ) { - e << ErrorMsgInfo< struct proc_Slot_0 >( "Unable to connect signal <" + signalName + "> to slot <" + slotName + "> due to a problem with the slot." ); - e << ErrorMsgInfo< struct proc_Slot_1 >( "You may have the slot name wrong." ); - throw; + //std::throw_with_nested( EXCEPT_HERE(SlotException()) << "Unable to connect signal <" + signalName + "> to slot <" + slotName + "> due to a problem with the slot." << + // " You may have the slot name wrong." ); } catch( ConnectionException& e ) { - e << ErrorMsgInfo< struct proc_Conn_0 >( "Unable to connect signal <" + signalName + "> to slot <" + slotName + "> due to a problem making the connection." ); - e << ErrorMsgInfo< struct proc_Conn_1 >( "Check that the signatures of the signal and slot match exactly." ); - throw; + //std::throw_with_nested( EXCEPT_HERE(ConnectionException()) << "Unable to connect signal <" << signalName << "> to slot <" << slotName << "> due to a problem making the connection." << + // " Check that the signatures of the signal and slot match exactly." ); } - catch( boost::exception& e ) + catch( std::exception& e ) { - e << ErrorMsgInfo< struct proc_Unkn >( "Unable to connect signal <" + signalName + "> to slot <" + slotName + "> for an unknown reason." ); - throw; + //std::throw_with_nested( EXCEPT_HERE(Exception()) << "Unable to connect signal <" + signalName + "> to slot <" + slotName + "> for an unknown reason." ); } LDEBUG(processorlog, "Connected signal <" << this->Name() << ":" << signalName << "> to slot <" << processor.Name() << ":" << slotName << ">"); @@ -117,11 +117,13 @@ namespace Nymph { if( ! signal ) { - BOOST_THROW_EXCEPTION( SignalException() << "Signal pointer was NULL" << eom ); + //throw EXCEPT_HERE(SignalException()) << "Signal pointer was NULL"; +// BOOST_THROW_EXCEPTION( SignalException() << "Signal pointer was NULL" << eom ); } if( ! slot ) { - BOOST_THROW_EXCEPTION( SlotException() << "Slot pointer was NULL" << eom ); + //throw EXCEPT_HERE(SlotException()) << "Slot pointer was NULL"; +// BOOST_THROW_EXCEPTION( SlotException() << "Slot pointer was NULL" << eom ); } signal->Connect(slot, groupNum); diff --git a/Library/Processor/Signal.hh b/Library/Processor/Signal.hh index 27109b7..1db64c8 100644 --- a/Library/Processor/Signal.hh +++ b/Library/Processor/Signal.hh @@ -141,9 +141,9 @@ namespace Nymph // ensure that the slot is of the correct type if( ! dynamic_cast< Slot< XArgs... >* >( slot ) ) { - BOOST_THROW_EXCEPTION( ConnectionException() << "Trying to connect signal <" << fName << "> to slot <" << slot->Name() << ">, but cannot make the connection:\n" << - "\tUnable to cast from SlotBase to this signal's derived type.\n" << - "\tArgument types do not match" << eom ); + //BOOST_THROW_EXCEPTION( ConnectionException() << "Trying to connect signal <" << fName << "> to slot <" << slot->Name() << ">, but cannot make the connection:\n" << + // "\tUnable to cast from SlotBase to this signal's derived type.\n" << + // "\tArgument types do not match" << eom ); } /* Connection connection; diff --git a/Library/Utility/Exception.cc b/Library/Utility/Exception.cc index 6770e91..d7fa0bb 100644 --- a/Library/Utility/Exception.cc +++ b/Library/Utility/Exception.cc @@ -10,6 +10,9 @@ namespace Nymph { + + +/* removed for trying home-grown exceptions, 1/10/22 Exception::Exception() : boost::exception(), std::exception(), @@ -26,5 +29,5 @@ namespace Nymph Exception::~Exception() throw () { } - +*/ } diff --git a/Library/Utility/Exception.hh b/Library/Utility/Exception.hh index cc7c542..a97446c 100644 --- a/Library/Utility/Exception.hh +++ b/Library/Utility/Exception.hh @@ -9,16 +9,89 @@ #ifndef NYMPH_EXCEPTION_HH_ #define NYMPH_EXCEPTION_HH_ -#include "macros.hh" +#include "MemberVariable.hh" -#include +#include "base_exception.hh" -#include -#include -#include +//#include + +//#include +//#include +//#include namespace Nymph { + + template< typename XDerived > + class BaseException : public scarab::base_exception< XDerived > + { + public: + BaseException(); + BaseException( const std::string& filename, int lineNum ); + ~BaseException() noexcept; + + XDerived& operator()( const std::string& filename, int lineNum ); + XDerived& operator%( const std::string& filename ); + XDerived& operator%( int lineNum ); + + MEMVAR_REF( std::string, AtFilename ); + MEMVAR( int, AtLineNumber ); + }; + + class Exception : public BaseException< Exception > + { + public: + using BaseException< Exception >::BaseException; + ~Exception() = default; + }; + +#define CREATE_EXCEPT_HERE( anException ) anException( __FILE__, __LINE__ ) +#define EXCEPT_HERE( anException ) (anException)( __FILE__, __LINE__ ) + +#define THROW_EXCEPT_HERE( anException ) throw EXCEPT_HERE( Exception() << "test message" ) + + template< typename XDerived > + BaseException< XDerived >::BaseException() : + scarab::base_exception< XDerived >(), + fAtFilename( "unknown" ), + fAtLineNumber( 0 ) + {} + + template< typename XDerived > + BaseException< XDerived >::BaseException( const std::string& filename, int lineNumber ) : + scarab::base_exception< XDerived >(), + fAtFilename( filename ), + fAtLineNumber( lineNumber ) + {} + + template< typename XDerived > + BaseException< XDerived >::~BaseException() noexcept + {} + + template< typename XDerived > + XDerived& BaseException< XDerived >::operator()( const std::string& filename, int lineNumber ) + { + fAtFilename = filename; + fAtLineNumber = lineNumber; + return *static_cast< XDerived* >(this); + } + + template< typename XDerived > + XDerived& BaseException< XDerived >::operator%( const std::string& filename ) + { + fAtFilename = filename; + return *static_cast< XDerived* >(this); + } + + template< typename XDerived > + XDerived& BaseException< XDerived >::operator%( int lineNum ) + { + fAtLineNumber = lineNum; + return *static_cast< XDerived* >(this); + } + + +/* removed for trying home-grown exceptions, 1/10/22 struct MessageEnd {}; static const MessageEnd eom = MessageEnd(); @@ -26,8 +99,8 @@ namespace Nymph template< class XLabel > using ErrorMsgInfo = boost::error_info< XLabel, std::string>; - - /*! +*/ + /* // removed for trying home-grown exceptions, 1/10/22 @class Exception @author N.S. Oblath @@ -68,7 +141,7 @@ namespace Nymph ERROR( my_log, "An exception was caught: " << diagnostic_information( e ) ): } */ - +/* removed for trying home-grown exceptions, 1/10/22 class Exception : virtual public boost::exception, virtual public std::exception { public: @@ -121,7 +194,7 @@ namespace Nymph } return *this; } - +*/ } #endif /* NYMPH_EXCEPTION_HH_ */ diff --git a/Testing/TestException.cc b/Testing/TestException.cc index 69511d9..4e6c032 100644 --- a/Testing/TestException.cc +++ b/Testing/TestException.cc @@ -17,6 +17,106 @@ TEST_CASE( "exception", "[utility]" ) { using namespace Nymph; + Exception blankEx; + REQUIRE( blankEx.what() == std::string() ); + REQUIRE( blankEx.AtFilename() == "unknown" ); + REQUIRE( blankEx.GetAtLineNumber() == 0 ); + + Exception testEx( "some_file", 1 ); + REQUIRE( testEx.AtFilename() == "some_file" ); + REQUIRE( testEx.GetAtLineNumber() == 1 ); + + std::string testMessage("test message 2: "); + int testInt = 5; + testEx << testMessage << testInt; + REQUIRE( testEx.what() == testMessage + std::to_string(testInt) ); + + /*EXCEPT_HERE( Exception testEx );*/ + // uses of __LINE__ need to be on the same line + testEx( __FILE__, __LINE__ ); std::string recordFile( __FILE__ ); int recordLine( __LINE__ ); + LWARN( testlog, "recorded file: " << recordFile ); + LWARN( testlog, "recorded line: " << recordLine ); + REQUIRE( testEx.AtFilename() == recordFile ); + REQUIRE( testEx.GetAtLineNumber() == recordLine ); + + EXCEPT_HERE( testEx ); recordFile = std::string(__FILE__); recordLine = __LINE__; + REQUIRE( testEx.AtFilename() == recordFile ); + REQUIRE( testEx.GetAtLineNumber() == recordLine ); +} + +TEST_CASE( "throw", "[utility]" ) +{ + using namespace Nymph; + + try + { + throw Exception(); + } + catch(const Exception& e) + { + REQUIRE( e.what() == std::string() ); + REQUIRE( e.AtFilename() == "unknown" ); + REQUIRE( e.GetAtLineNumber() == 0 ); + } + + std::string recordFile; + int recordLine = 0; + + try + { + recordFile = std::string(__FILE__); recordLine = __LINE__; + throw Exception( __FILE__, __LINE__ ) << "test message"; + } + catch(const Exception& e) + { + REQUIRE( e.what() == std::string("test message") ); + REQUIRE( e.AtFilename() == recordFile ); + REQUIRE( e.GetAtLineNumber() == recordLine + 1 ); // line number was recorded just before the throw + } + + // Give CREATE_EXCEPT_HERE the class name + try + { + recordFile = std::string(__FILE__); recordLine = __LINE__; + throw CREATE_EXCEPT_HERE( Exception ); + } + catch(const Exception& e) + { + REQUIRE( e.what() == std::string() ); + REQUIRE( e.AtFilename() == recordFile ); + REQUIRE( e.GetAtLineNumber() == recordLine + 1 ); // line number was recorded just before the throw + } + + // Give EXCEPT_HERE an exception + try + { + recordFile = std::string(__FILE__); recordLine = __LINE__; + throw EXCEPT_HERE( Exception() << "test message" ); + } + catch(const Exception& e) + { + REQUIRE( e.what() == std::string("test message") ); + REQUIRE( e.AtFilename() == recordFile ); + REQUIRE( e.GetAtLineNumber() == recordLine + 1 ); // line number was recorded just before the throw + } + + // THROW macro + try + { + recordFile = std::string(__FILE__); recordLine = __LINE__; + THROW_EXCEPT_HERE( Exception() << "test message" ); + } + catch(const Exception& e) + { + REQUIRE( e.what() == std::string("test message") ); + REQUIRE( e.AtFilename() == recordFile ); + REQUIRE( e.GetAtLineNumber() == recordLine + 1 ); // line number was recorded just before the throw + } + + +} + +/* removed for trying home-grown exceptions, 1/10/22 auto throwException = []() { BOOST_THROW_EXCEPTION( Exception() << "Test exception" << eom ); }; @@ -31,5 +131,4 @@ TEST_CASE( "exception", "[utility]" ) { LWARN( testlog, diagnostic_information(e) ); } - -} +*/ From ff80c02129fb6898576de37c59fda81cd86ca9fd Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Tue, 11 Jan 2022 11:14:18 -0800 Subject: [PATCH 192/521] Demonstrate nested exception use --- Testing/TestException.cc | 78 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/Testing/TestException.cc b/Testing/TestException.cc index 4e6c032..b3bb77a 100644 --- a/Testing/TestException.cc +++ b/Testing/TestException.cc @@ -113,7 +113,85 @@ TEST_CASE( "throw", "[utility]" ) REQUIRE( e.GetAtLineNumber() == recordLine + 1 ); // line number was recorded just before the throw } +} + +const unsigned layers = 5; +const std::string firstThrowText( "First throw" ); +const std::string nestedThrowText( "nested throw at layer " ); + +void CatchThrow() +{ + //const static unsigned layers = 5; + static unsigned count = 0; + + try + { + if( count == layers ) + { + throw CREATE_EXCEPT_HERE( Nymph::Exception ) << firstThrowText; + } + else + { + ++count; + CatchThrow(); + return; + } + } + catch(const Nymph::Exception& e) + { + if( count == layers ) + { + REQUIRE( e.what() == firstThrowText ); + } + else + { + std::string what( e.what() ); + REQUIRE( what.substr(0, nestedThrowText.size()) == nestedThrowText ); + } + std::throw_with_nested( EXCEPT_HERE( Nymph::Exception() << nestedThrowText << count-- ) ); + } +} + +// recursive print function +void PrintException( const Nymph::Exception& e, unsigned count = 0 ) +{ + LINFO( testlog, std::string(count, ' ') << "Exception: " << e.what() ); + if( count == layers + 1 ) + { + REQUIRE( e.what() == firstThrowText ); + } + else + { + std::string what( e.what() ); + REQUIRE( what.substr(0, nestedThrowText.size()) == nestedThrowText ); + } + + try + { + std::rethrow_if_nested( e ); + } + catch(const Nymph::Exception& e) + { + PrintException( e, ++count ); + } + return; +} + + +TEST_CASE( "nested_throw", "[utility]" ) +{ + using namespace Nymph; + try + { + CatchThrow(); + } + catch(const Exception& e) + { + + PrintException(e); + } + } /* removed for trying home-grown exceptions, 1/10/22 From 4aabd9fe209151e236bb705c24219c71dd858879 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Tue, 11 Jan 2022 11:32:14 -0800 Subject: [PATCH 193/521] Fix THROW_EXCEPT_HERE and add THROW_NESTED_EXCEPT_HERE --- Library/Utility/Exception.hh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Library/Utility/Exception.hh b/Library/Utility/Exception.hh index a97446c..9c4cc78 100644 --- a/Library/Utility/Exception.hh +++ b/Library/Utility/Exception.hh @@ -48,7 +48,8 @@ namespace Nymph #define CREATE_EXCEPT_HERE( anException ) anException( __FILE__, __LINE__ ) #define EXCEPT_HERE( anException ) (anException)( __FILE__, __LINE__ ) -#define THROW_EXCEPT_HERE( anException ) throw EXCEPT_HERE( Exception() << "test message" ) +#define THROW_EXCEPT_HERE( anException ) throw EXCEPT_HERE( anException ) +#define THROW_NESTED_EXCEPT_HERE( anException ) std::throw_with_nested( EXCEPT_HERE( anException ) ) template< typename XDerived > BaseException< XDerived >::BaseException() : From ed3c820c7b049d5fbef3626f426c901c21f96461 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Tue, 11 Jan 2022 11:32:35 -0800 Subject: [PATCH 194/521] Update exception throwing in Processor and Signal --- Library/Processor/Processor.cc | 26 +++++++++++++------------- Library/Processor/Signal.hh | 4 ++++ Testing/TestException.cc | 4 +--- 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/Library/Processor/Processor.cc b/Library/Processor/Processor.cc index 7aa6ac6..53232f1 100644 --- a/Library/Processor/Processor.cc +++ b/Library/Processor/Processor.cc @@ -68,8 +68,8 @@ namespace Nymph SigMapIt signalIt = fSignals.find(signalName); if( signalIt == fSignals.end() ) { - //throw EXCEPT_HERE(SignalException()) << "Unable to connect signal <" + signalName + "> to slot <" + slotName + "> due to a problem with the signal.\n" << - // "You may have the signal name wrong."; + THROW_EXCEPT_HERE( SignalException() << "Unable to connect signal <" + signalName + "> to slot <" + slotName + "> due to a problem with the signal.\n" << + "You may have the signal name wrong." ); // BOOST_THROW_EXCEPTION( SignalException() << "Unable to connect signal <" + signalName + "> to slot <" + slotName + "> due to a problem with the signal.\n" << // "You may have the signal name wrong." << eom ); } @@ -77,8 +77,8 @@ namespace Nymph SlotMapIt slotIt = processor.fSlots.find(slotName); if( slotIt == processor.fSlots.end() ) { - //throw EXCEPT_HERE(SlotException()) << "Unable to connect signal <" + signalName + "> to slot <" + slotName + "> due to a problem with the slot." << - // "You may have the slot name wrong."; + THROW_EXCEPT_HERE( SlotException() << "Unable to connect signal <" + signalName + "> to slot <" + slotName + "> due to a problem with the slot." << + "You may have the slot name wrong." ); // BOOST_THROW_EXCEPTION( SlotException() << "Unable to connect signal <" + signalName + "> to slot <" + slotName + "> due to a problem with the slot." << // "You may have the slot name wrong." << eom ); } @@ -90,22 +90,22 @@ namespace Nymph } catch( SignalException& e ) { - //std::throw_with_nested( EXCEPT_HERE(SignalException()) << "Unable to connect signal <" << signalName << "> to slot <" << slotName << "> due to a problem with the signal." << - // " You may have the signal name wrong." ); + THROW_NESTED_EXCEPT_HERE( SignalException() << "Unable to connect signal <" << signalName << "> to slot <" << slotName << "> due to a problem with the signal." << + "\tYou may have the signal name wrong." ); } catch( SlotException& e ) { - //std::throw_with_nested( EXCEPT_HERE(SlotException()) << "Unable to connect signal <" + signalName + "> to slot <" + slotName + "> due to a problem with the slot." << - // " You may have the slot name wrong." ); + THROW_NESTED_EXCEPT_HERE( SlotException() << "Unable to connect signal <" + signalName + "> to slot <" + slotName + "> due to a problem with the slot." << + "\tYou may have the slot name wrong." ); } catch( ConnectionException& e ) { - //std::throw_with_nested( EXCEPT_HERE(ConnectionException()) << "Unable to connect signal <" << signalName << "> to slot <" << slotName << "> due to a problem making the connection." << - // " Check that the signatures of the signal and slot match exactly." ); + THROW_NESTED_EXCEPT_HERE( ConnectionException() << "Unable to connect signal <" << signalName << "> to slot <" << slotName << "> due to a problem making the connection." << + "\tCheck that the signatures of the signal and slot match exactly." ); } catch( std::exception& e ) { - //std::throw_with_nested( EXCEPT_HERE(Exception()) << "Unable to connect signal <" + signalName + "> to slot <" + slotName + "> for an unknown reason." ); + THROW_NESTED_EXCEPT_HERE( Exception() << "Unable to connect signal <" + signalName + "> to slot <" + slotName + "> for an unknown reason." ); } LDEBUG(processorlog, "Connected signal <" << this->Name() << ":" << signalName << "> to slot <" << processor.Name() << ":" << slotName << ">"); @@ -117,12 +117,12 @@ namespace Nymph { if( ! signal ) { - //throw EXCEPT_HERE(SignalException()) << "Signal pointer was NULL"; + THROW_EXCEPT_HERE( SignalException() << "Signal pointer was NULL" ); // BOOST_THROW_EXCEPTION( SignalException() << "Signal pointer was NULL" << eom ); } if( ! slot ) { - //throw EXCEPT_HERE(SlotException()) << "Slot pointer was NULL"; + THROW_EXCEPT_HERE( SlotException() << "Slot pointer was NULL" ); // BOOST_THROW_EXCEPTION( SlotException() << "Slot pointer was NULL" << eom ); } diff --git a/Library/Processor/Signal.hh b/Library/Processor/Signal.hh index 1db64c8..6853007 100644 --- a/Library/Processor/Signal.hh +++ b/Library/Processor/Signal.hh @@ -141,6 +141,10 @@ namespace Nymph // ensure that the slot is of the correct type if( ! dynamic_cast< Slot< XArgs... >* >( slot ) ) { + THROW_EXCEPT_HERE( ConnectionException() << "Trying to connect signal <" << fName << "> to slot <" << slot->Name() << ">, but cannot make the connection:\n" << + "\tUnable to cast from SlotBase to this signal's derived type.\n" << + "\tArgument types do not match" ); + //BOOST_THROW_EXCEPTION( ConnectionException() << "Trying to connect signal <" << fName << "> to slot <" << slot->Name() << ">, but cannot make the connection:\n" << // "\tUnable to cast from SlotBase to this signal's derived type.\n" << // "\tArgument types do not match" << eom ); diff --git a/Testing/TestException.cc b/Testing/TestException.cc index b3bb77a..cf08f8e 100644 --- a/Testing/TestException.cc +++ b/Testing/TestException.cc @@ -34,8 +34,6 @@ TEST_CASE( "exception", "[utility]" ) /*EXCEPT_HERE( Exception testEx );*/ // uses of __LINE__ need to be on the same line testEx( __FILE__, __LINE__ ); std::string recordFile( __FILE__ ); int recordLine( __LINE__ ); - LWARN( testlog, "recorded file: " << recordFile ); - LWARN( testlog, "recorded line: " << recordLine ); REQUIRE( testEx.AtFilename() == recordFile ); REQUIRE( testEx.GetAtLineNumber() == recordLine ); @@ -148,7 +146,7 @@ void CatchThrow() std::string what( e.what() ); REQUIRE( what.substr(0, nestedThrowText.size()) == nestedThrowText ); } - std::throw_with_nested( EXCEPT_HERE( Nymph::Exception() << nestedThrowText << count-- ) ); + THROW_NESTED_EXCEPT_HERE( Nymph::Exception() << nestedThrowText << count-- ) ; } } From 0ec8b666ae2515198bea60a2469ecaa08d63a0d7 Mon Sep 17 00:00:00 2001 From: Noah Oblath Date: Tue, 11 Jan 2022 14:31:36 -0800 Subject: [PATCH 195/521] Updated Catch2 to v2.13.8 --- Testing/Catch/catch.hpp | 10391 +++++++++++++++++++++++++++----------- 1 file changed, 7499 insertions(+), 2892 deletions(-) diff --git a/Testing/Catch/catch.hpp b/Testing/Catch/catch.hpp index bdc2f74..db1fed3 100644 --- a/Testing/Catch/catch.hpp +++ b/Testing/Catch/catch.hpp @@ -1,9 +1,9 @@ /* - * Catch v2.3.0 - * Generated: 2018-07-23 10:09:14.936841 + * Catch v2.13.8 + * Generated: 2022-01-03 21:20:09.589503 * ---------------------------------------------------------- * This file has been merged from multiple headers. Please don't edit it directly - * Copyright (c) 2018 Two Blue Cubes Ltd. All rights reserved. + * Copyright (c) 2022 Two Blue Cubes Ltd. All rights reserved. * * Distributed under the Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -14,8 +14,8 @@ #define CATCH_VERSION_MAJOR 2 -#define CATCH_VERSION_MINOR 3 -#define CATCH_VERSION_PATCH 0 +#define CATCH_VERSION_MINOR 13 +#define CATCH_VERSION_PATCH 8 #ifdef __clang__ # pragma clang system_header @@ -36,10 +36,11 @@ # pragma clang diagnostic ignored "-Wcovered-switch-default" # endif #elif defined __GNUC__ - // GCC likes to warn on REQUIREs, and we cannot suppress them - // locally because g++'s support for _Pragma is lacking in older, - // still supported, versions -# pragma GCC diagnostic ignored "-Wparentheses" + // Because REQUIREs trigger GCC's -Wparentheses, and because still + // supported version of g++ have only buggy support for _Pragmas, + // Wparentheses have to be suppressed globally. +# pragma GCC diagnostic ignored "-Wparentheses" // See #674 for details + # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wunused-variable" # pragma GCC diagnostic ignored "-Wpadded" @@ -65,13 +66,16 @@ #if !defined(CATCH_CONFIG_IMPL_ONLY) // start catch_platform.h +// See e.g.: +// https://opensource.apple.com/source/CarbonHeaders/CarbonHeaders-18.1/TargetConditionals.h.auto.html #ifdef __APPLE__ -# include -# if TARGET_OS_OSX == 1 -# define CATCH_PLATFORM_MAC -# elif TARGET_OS_IPHONE == 1 -# define CATCH_PLATFORM_IPHONE -# endif +# include +# if (defined(TARGET_OS_OSX) && TARGET_OS_OSX == 1) || \ + (defined(TARGET_OS_MAC) && TARGET_OS_MAC == 1) +# define CATCH_PLATFORM_MAC +# elif (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE == 1) +# define CATCH_PLATFORM_IPHONE +# endif #elif defined(linux) || defined(__linux) || defined(__linux__) # define CATCH_PLATFORM_LINUX @@ -108,6 +112,7 @@ namespace Catch { // CATCH_CONFIG_COUNTER : is the __COUNTER__ macro supported? // CATCH_CONFIG_WINDOWS_SEH : is Windows SEH supported? // CATCH_CONFIG_POSIX_SIGNALS : are POSIX signals supported? +// CATCH_CONFIG_DISABLE_EXCEPTIONS : Are exceptions enabled? // **************** // Note to maintainers: if new toggles are added please document them // in configuration.md, too @@ -120,40 +125,61 @@ namespace Catch { #ifdef __cplusplus -# if __cplusplus >= 201402L +# if (__cplusplus >= 201402L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201402L) # define CATCH_CPP14_OR_GREATER # endif -# if __cplusplus >= 201703L +# if (__cplusplus >= 201703L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) # define CATCH_CPP17_OR_GREATER # endif #endif -#if defined(CATCH_CPP17_OR_GREATER) -# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS +// Only GCC compiler should be used in this block, so other compilers trying to +// mask themselves as GCC should be ignored. +#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) && !defined(__CUDACC__) && !defined(__LCC__) +# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic push" ) +# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic pop" ) + +# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__) + #endif -#ifdef __clang__ +#if defined(__clang__) + +# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic push" ) +# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic pop" ) + +// As of this writing, IBM XL's implementation of __builtin_constant_p has a bug +// which results in calls to destructors being emitted for each temporary, +// without a matching initialization. In practice, this can result in something +// like `std::string::~string` being called on an uninitialized value. +// +// For example, this code will likely segfault under IBM XL: +// ``` +// REQUIRE(std::string("12") + "34" == "1234") +// ``` +// +// Therefore, `CATCH_INTERNAL_IGNORE_BUT_WARN` is not implemented. +# if !defined(__ibmxl__) && !defined(__CUDACC__) +# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__) /* NOLINT(cppcoreguidelines-pro-type-vararg, hicpp-vararg) */ +# endif + +# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" ) \ + _Pragma( "clang diagnostic ignored \"-Wglobal-constructors\"") + +# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wparentheses\"" ) + +# define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wunused-variable\"" ) -# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ - _Pragma( "clang diagnostic push" ) \ - _Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" ) \ - _Pragma( "clang diagnostic ignored \"-Wglobal-constructors\"") -# define CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \ - _Pragma( "clang diagnostic pop" ) - -# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ - _Pragma( "clang diagnostic push" ) \ - _Pragma( "clang diagnostic ignored \"-Wparentheses\"" ) -# define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \ - _Pragma( "clang diagnostic pop" ) - -# define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \ - _Pragma( "clang diagnostic push" ) \ - _Pragma( "clang diagnostic ignored \"-Wunused-variable\"" ) -# define CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS \ - _Pragma( "clang diagnostic pop" ) +# define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wgnu-zero-variadic-macro-arguments\"" ) + +# define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wunused-template\"" ) #endif // __clang__ @@ -178,6 +204,7 @@ namespace Catch { // Android somehow still does not support std::to_string #if defined(__ANDROID__) # define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING +# define CATCH_INTERNAL_CONFIG_ANDROID_LOGWRITE #endif //////////////////////////////////////////////////////////////////////////////// @@ -199,16 +226,19 @@ namespace Catch { // Required for some versions of Cygwin to declare gettimeofday // see: http://stackoverflow.com/questions/36901803/gettimeofday-not-declared-in-this-scope-cygwin # define _BSD_SOURCE +// some versions of cygwin (most) do not support std::to_string. Use the libstd check. +// https://gcc.gnu.org/onlinedocs/gcc-4.8.2/libstdc++/api/a01053_source.html line 2812-2813 +# if !((__cplusplus >= 201103L) && defined(_GLIBCXX_USE_C99) \ + && !defined(_GLIBCXX_HAVE_BROKEN_VSWPRINTF)) + +# define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING +# endif #endif // __CYGWIN__ //////////////////////////////////////////////////////////////////////////////// // Visual C++ -#ifdef _MSC_VER - -# if _MSC_VER >= 1900 // Visual Studio 2015 or newer -# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS -# endif +#if defined(_MSC_VER) // Universal Windows platform does not support SEH // Or console colours (or console at all...) @@ -218,15 +248,45 @@ namespace Catch { # define CATCH_INTERNAL_CONFIG_WINDOWS_SEH # endif +# if !defined(__clang__) // Handle Clang masquerading for msvc + +// MSVC traditional preprocessor needs some workaround for __VA_ARGS__ +// _MSVC_TRADITIONAL == 0 means new conformant preprocessor +// _MSVC_TRADITIONAL == 1 means old traditional non-conformant preprocessor +# if !defined(_MSVC_TRADITIONAL) || (defined(_MSVC_TRADITIONAL) && _MSVC_TRADITIONAL) +# define CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +# endif // MSVC_TRADITIONAL + +// Only do this if we're not using clang on Windows, which uses `diagnostic push` & `diagnostic pop` +# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION __pragma( warning(push) ) +# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION __pragma( warning(pop) ) +# endif // __clang__ + +#endif // _MSC_VER + +#if defined(_REENTRANT) || defined(_MSC_VER) +// Enable async processing, as -pthread is specified or no additional linking is required +# define CATCH_INTERNAL_CONFIG_USE_ASYNC #endif // _MSC_VER //////////////////////////////////////////////////////////////////////////////// +// Check if we are compiled with -fno-exceptions or equivalent +#if defined(__EXCEPTIONS) || defined(__cpp_exceptions) || defined(_CPPUNWIND) +# define CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED +#endif +//////////////////////////////////////////////////////////////////////////////// // DJGPP #ifdef __DJGPP__ # define CATCH_INTERNAL_CONFIG_NO_WCHAR #endif // __DJGPP__ +//////////////////////////////////////////////////////////////////////////////// +// Embarcadero C++Build +#if defined(__BORLANDC__) + #define CATCH_INTERNAL_CONFIG_POLYFILL_ISNAN +#endif + //////////////////////////////////////////////////////////////////////////////// // Use of __COUNTER__ is suppressed during code analysis in @@ -238,6 +298,58 @@ namespace Catch { #define CATCH_INTERNAL_CONFIG_COUNTER #endif +//////////////////////////////////////////////////////////////////////////////// + +// RTX is a special version of Windows that is real time. +// This means that it is detected as Windows, but does not provide +// the same set of capabilities as real Windows does. +#if defined(UNDER_RTSS) || defined(RTX64_BUILD) + #define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH + #define CATCH_INTERNAL_CONFIG_NO_ASYNC + #define CATCH_CONFIG_COLOUR_NONE +#endif + +#if !defined(_GLIBCXX_USE_C99_MATH_TR1) +#define CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER +#endif + +// Various stdlib support checks that require __has_include +#if defined(__has_include) + // Check if string_view is available and usable + #if __has_include() && defined(CATCH_CPP17_OR_GREATER) + # define CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW + #endif + + // Check if optional is available and usable + # if __has_include() && defined(CATCH_CPP17_OR_GREATER) + # define CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL + # endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) + + // Check if byte is available and usable + # if __has_include() && defined(CATCH_CPP17_OR_GREATER) + # include + # if defined(__cpp_lib_byte) && (__cpp_lib_byte > 0) + # define CATCH_INTERNAL_CONFIG_CPP17_BYTE + # endif + # endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) + + // Check if variant is available and usable + # if __has_include() && defined(CATCH_CPP17_OR_GREATER) + # if defined(__clang__) && (__clang_major__ < 8) + // work around clang bug with libstdc++ https://bugs.llvm.org/show_bug.cgi?id=31852 + // fix should be in clang 8, workaround in libstdc++ 8.2 + # include + # if defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9) + # define CATCH_CONFIG_NO_CPP17_VARIANT + # else + # define CATCH_INTERNAL_CONFIG_CPP17_VARIANT + # endif // defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9) + # else + # define CATCH_INTERNAL_CONFIG_CPP17_VARIANT + # endif // defined(__clang__) && (__clang_major__ < 8) + # endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) +#endif // defined(__has_include) + #if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER) # define CATCH_CONFIG_COUNTER #endif @@ -257,8 +369,20 @@ namespace Catch { # define CATCH_CONFIG_CPP11_TO_STRING #endif -#if defined(CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_NO_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) -# define CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS +#if defined(CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_NO_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_CPP17_OPTIONAL) +# define CATCH_CONFIG_CPP17_OPTIONAL +#endif + +#if defined(CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_NO_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_CPP17_STRING_VIEW) +# define CATCH_CONFIG_CPP17_STRING_VIEW +#endif + +#if defined(CATCH_INTERNAL_CONFIG_CPP17_VARIANT) && !defined(CATCH_CONFIG_NO_CPP17_VARIANT) && !defined(CATCH_CONFIG_CPP17_VARIANT) +# define CATCH_CONFIG_CPP17_VARIANT +#endif + +#if defined(CATCH_INTERNAL_CONFIG_CPP17_BYTE) && !defined(CATCH_CONFIG_NO_CPP17_BYTE) && !defined(CATCH_CONFIG_CPP17_BYTE) +# define CATCH_CONFIG_CPP17_BYTE #endif #if defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT) @@ -269,17 +393,75 @@ namespace Catch { # define CATCH_CONFIG_NEW_CAPTURE #endif +#if !defined(CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED) && !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) +# define CATCH_CONFIG_DISABLE_EXCEPTIONS +#endif + +#if defined(CATCH_INTERNAL_CONFIG_POLYFILL_ISNAN) && !defined(CATCH_CONFIG_NO_POLYFILL_ISNAN) && !defined(CATCH_CONFIG_POLYFILL_ISNAN) +# define CATCH_CONFIG_POLYFILL_ISNAN +#endif + +#if defined(CATCH_INTERNAL_CONFIG_USE_ASYNC) && !defined(CATCH_INTERNAL_CONFIG_NO_ASYNC) && !defined(CATCH_CONFIG_NO_USE_ASYNC) && !defined(CATCH_CONFIG_USE_ASYNC) +# define CATCH_CONFIG_USE_ASYNC +#endif + +#if defined(CATCH_INTERNAL_CONFIG_ANDROID_LOGWRITE) && !defined(CATCH_CONFIG_NO_ANDROID_LOGWRITE) && !defined(CATCH_CONFIG_ANDROID_LOGWRITE) +# define CATCH_CONFIG_ANDROID_LOGWRITE +#endif + +#if defined(CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER) && !defined(CATCH_CONFIG_NO_GLOBAL_NEXTAFTER) && !defined(CATCH_CONFIG_GLOBAL_NEXTAFTER) +# define CATCH_CONFIG_GLOBAL_NEXTAFTER +#endif + +// Even if we do not think the compiler has that warning, we still have +// to provide a macro that can be used by the code. +#if !defined(CATCH_INTERNAL_START_WARNINGS_SUPPRESSION) +# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION +#endif +#if !defined(CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION) +# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION +#endif #if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS) # define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS -# define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS #endif #if !defined(CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS) # define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS -# define CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS #endif #if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS) # define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS -# define CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS +#endif +#if !defined(CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS +#endif + +// The goal of this macro is to avoid evaluation of the arguments, but +// still have the compiler warn on problems inside... +#if !defined(CATCH_INTERNAL_IGNORE_BUT_WARN) +# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) +#endif + +#if defined(__APPLE__) && defined(__apple_build_version__) && (__clang_major__ < 10) +# undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS +#elif defined(__clang__) && (__clang_major__ < 5) +# undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS +#endif + +#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS +#endif + +#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) +#define CATCH_TRY if ((true)) +#define CATCH_CATCH_ALL if ((false)) +#define CATCH_CATCH_ANON(type) if ((false)) +#else +#define CATCH_TRY try +#define CATCH_CATCH_ALL catch (...) +#define CATCH_CATCH_ANON(type) catch (type) +#endif + +#if defined(CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR) && !defined(CATCH_CONFIG_NO_TRADITIONAL_MSVC_PREPROCESSOR) && !defined(CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR) +#define CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR #endif // end catch_compiler_capabilities.h @@ -295,6 +477,10 @@ namespace Catch { #include #include +// We need a dummy global operator<< so we can bring it into Catch namespace later +struct Catch_global_namespace_dummy {}; +std::ostream& operator<<(std::ostream&, Catch_global_namespace_dummy); + namespace Catch { struct CaseSensitive { enum Choice { @@ -321,12 +507,12 @@ namespace Catch { line( _line ) {} - SourceLineInfo( SourceLineInfo const& other ) = default; - SourceLineInfo( SourceLineInfo && ) = default; - SourceLineInfo& operator = ( SourceLineInfo const& ) = default; - SourceLineInfo& operator = ( SourceLineInfo && ) = default; + SourceLineInfo( SourceLineInfo const& other ) = default; + SourceLineInfo& operator = ( SourceLineInfo const& ) = default; + SourceLineInfo( SourceLineInfo&& ) noexcept = default; + SourceLineInfo& operator = ( SourceLineInfo&& ) noexcept = default; - bool empty() const noexcept; + bool empty() const noexcept { return file[0] == '\0'; } bool operator == ( SourceLineInfo const& other ) const noexcept; bool operator < ( SourceLineInfo const& other ) const noexcept; @@ -336,6 +522,11 @@ namespace Catch { std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ); + // Bring in operator<< from global namespace into Catch namespace + // This is necessary because the overload of operator<< above makes + // lookup stop at namespace Catch + using ::operator<<; + // Use this in variadic streaming macros to allow // >> +StreamEndStop // as well as @@ -362,9 +553,10 @@ namespace Catch { } // end namespace Catch #define CATCH_REGISTER_TAG_ALIAS( alias, spec ) \ + CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } \ - CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS + CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION // end catch_tag_alias_autoregistrar.h // start catch_test_registry.h @@ -372,7 +564,6 @@ namespace Catch { // start catch_interfaces_testcase.h #include -#include namespace Catch { @@ -383,8 +574,6 @@ namespace Catch { virtual ~ITestInvoker(); }; - using ITestCasePtr = std::shared_ptr; - class TestCase; struct IConfig; @@ -394,6 +583,7 @@ namespace Catch { virtual std::vector const& getAllTestsSorted( IConfig const& config ) const = 0; }; + bool isThrowSafe( TestCase const& testCase, IConfig const& config ); bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ); std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ); std::vector const& getAllTestCasesSorted( IConfig const& config ); @@ -406,55 +596,30 @@ namespace Catch { #include #include #include +#include namespace Catch { - class StringData; - /// A non-owning string class (similar to the forthcoming std::string_view) /// Note that, because a StringRef may be a substring of another string, - /// it may not be null terminated. c_str() must return a null terminated - /// string, however, and so the StringRef will internally take ownership - /// (taking a copy), if necessary. In theory this ownership is not externally - /// visible - but it does mean (substring) StringRefs should not be shared between - /// threads. + /// it may not be null terminated. class StringRef { public: using size_type = std::size_t; + using const_iterator = const char*; private: - friend struct StringRefTestAccess; - - char const* m_start; - size_type m_size; - - char* m_data = nullptr; - - void takeOwnership(); - static constexpr char const* const s_empty = ""; - public: // construction/ assignment - StringRef() noexcept - : StringRef( s_empty, 0 ) - {} - - StringRef( StringRef const& other ) noexcept - : m_start( other.m_start ), - m_size( other.m_size ) - {} + char const* m_start = s_empty; + size_type m_size = 0; - StringRef( StringRef&& other ) noexcept - : m_start( other.m_start ), - m_size( other.m_size ), - m_data( other.m_data ) - { - other.m_data = nullptr; - } + public: // construction + constexpr StringRef() noexcept = default; StringRef( char const* rawChars ) noexcept; - StringRef( char const* rawChars, size_type size ) noexcept + constexpr StringRef( char const* rawChars, size_type size ) noexcept : m_start( rawChars ), m_size( size ) {} @@ -464,65 +629,333 @@ namespace Catch { m_size( stdString.size() ) {} - ~StringRef() noexcept { - delete[] m_data; - } - - auto operator = ( StringRef const &other ) noexcept -> StringRef& { - delete[] m_data; - m_data = nullptr; - m_start = other.m_start; - m_size = other.m_size; - return *this; + explicit operator std::string() const { + return std::string(m_start, m_size); } - operator std::string() const; - - void swap( StringRef& other ) noexcept; - public: // operators auto operator == ( StringRef const& other ) const noexcept -> bool; - auto operator != ( StringRef const& other ) const noexcept -> bool; + auto operator != (StringRef const& other) const noexcept -> bool { + return !(*this == other); + } - auto operator[] ( size_type index ) const noexcept -> char; + auto operator[] ( size_type index ) const noexcept -> char { + assert(index < m_size); + return m_start[index]; + } public: // named queries - auto empty() const noexcept -> bool { + constexpr auto empty() const noexcept -> bool { return m_size == 0; } - auto size() const noexcept -> size_type { + constexpr auto size() const noexcept -> size_type { return m_size; } - auto numberOfCharacters() const noexcept -> size_type; + // Returns the current start pointer. If the StringRef is not + // null-terminated, throws std::domain_exception auto c_str() const -> char const*; public: // substrings and searches - auto substr( size_type start, size_type size ) const noexcept -> StringRef; + // Returns a substring of [start, start + length). + // If start + length > size(), then the substring is [start, size()). + // If start > size(), then the substring is empty. + auto substr( size_type start, size_type length ) const noexcept -> StringRef; - // Returns the current start pointer. - // Note that the pointer can change when if the StringRef is a substring - auto currentData() const noexcept -> char const*; + // Returns the current start pointer. May not be null-terminated. + auto data() const noexcept -> char const*; - private: // ownership queries - may not be consistent between calls - auto isOwned() const noexcept -> bool; - auto isSubstring() const noexcept -> bool; - }; + constexpr auto isNullTerminated() const noexcept -> bool { + return m_start[m_size] == '\0'; + } - auto operator + ( StringRef const& lhs, StringRef const& rhs ) -> std::string; - auto operator + ( StringRef const& lhs, char const* rhs ) -> std::string; - auto operator + ( char const* lhs, StringRef const& rhs ) -> std::string; + public: // iterators + constexpr const_iterator begin() const { return m_start; } + constexpr const_iterator end() const { return m_start + m_size; } + }; auto operator += ( std::string& lhs, StringRef const& sr ) -> std::string&; auto operator << ( std::ostream& os, StringRef const& sr ) -> std::ostream&; - inline auto operator "" _sr( char const* rawChars, std::size_t size ) noexcept -> StringRef { + constexpr auto operator "" _sr( char const* rawChars, std::size_t size ) noexcept -> StringRef { return StringRef( rawChars, size ); } - } // namespace Catch +constexpr auto operator "" _catch_sr( char const* rawChars, std::size_t size ) noexcept -> Catch::StringRef { + return Catch::StringRef( rawChars, size ); +} + // end catch_stringref.h +// start catch_preprocessor.hpp + + +#define CATCH_RECURSION_LEVEL0(...) __VA_ARGS__ +#define CATCH_RECURSION_LEVEL1(...) CATCH_RECURSION_LEVEL0(CATCH_RECURSION_LEVEL0(CATCH_RECURSION_LEVEL0(__VA_ARGS__))) +#define CATCH_RECURSION_LEVEL2(...) CATCH_RECURSION_LEVEL1(CATCH_RECURSION_LEVEL1(CATCH_RECURSION_LEVEL1(__VA_ARGS__))) +#define CATCH_RECURSION_LEVEL3(...) CATCH_RECURSION_LEVEL2(CATCH_RECURSION_LEVEL2(CATCH_RECURSION_LEVEL2(__VA_ARGS__))) +#define CATCH_RECURSION_LEVEL4(...) CATCH_RECURSION_LEVEL3(CATCH_RECURSION_LEVEL3(CATCH_RECURSION_LEVEL3(__VA_ARGS__))) +#define CATCH_RECURSION_LEVEL5(...) CATCH_RECURSION_LEVEL4(CATCH_RECURSION_LEVEL4(CATCH_RECURSION_LEVEL4(__VA_ARGS__))) + +#ifdef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +#define INTERNAL_CATCH_EXPAND_VARGS(...) __VA_ARGS__ +// MSVC needs more evaluations +#define CATCH_RECURSION_LEVEL6(...) CATCH_RECURSION_LEVEL5(CATCH_RECURSION_LEVEL5(CATCH_RECURSION_LEVEL5(__VA_ARGS__))) +#define CATCH_RECURSE(...) CATCH_RECURSION_LEVEL6(CATCH_RECURSION_LEVEL6(__VA_ARGS__)) +#else +#define CATCH_RECURSE(...) CATCH_RECURSION_LEVEL5(__VA_ARGS__) +#endif + +#define CATCH_REC_END(...) +#define CATCH_REC_OUT + +#define CATCH_EMPTY() +#define CATCH_DEFER(id) id CATCH_EMPTY() + +#define CATCH_REC_GET_END2() 0, CATCH_REC_END +#define CATCH_REC_GET_END1(...) CATCH_REC_GET_END2 +#define CATCH_REC_GET_END(...) CATCH_REC_GET_END1 +#define CATCH_REC_NEXT0(test, next, ...) next CATCH_REC_OUT +#define CATCH_REC_NEXT1(test, next) CATCH_DEFER ( CATCH_REC_NEXT0 ) ( test, next, 0) +#define CATCH_REC_NEXT(test, next) CATCH_REC_NEXT1(CATCH_REC_GET_END test, next) + +#define CATCH_REC_LIST0(f, x, peek, ...) , f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1) ) ( f, peek, __VA_ARGS__ ) +#define CATCH_REC_LIST1(f, x, peek, ...) , f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST0) ) ( f, peek, __VA_ARGS__ ) +#define CATCH_REC_LIST2(f, x, peek, ...) f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1) ) ( f, peek, __VA_ARGS__ ) + +#define CATCH_REC_LIST0_UD(f, userdata, x, peek, ...) , f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1_UD) ) ( f, userdata, peek, __VA_ARGS__ ) +#define CATCH_REC_LIST1_UD(f, userdata, x, peek, ...) , f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST0_UD) ) ( f, userdata, peek, __VA_ARGS__ ) +#define CATCH_REC_LIST2_UD(f, userdata, x, peek, ...) f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1_UD) ) ( f, userdata, peek, __VA_ARGS__ ) + +// Applies the function macro `f` to each of the remaining parameters, inserts commas between the results, +// and passes userdata as the first parameter to each invocation, +// e.g. CATCH_REC_LIST_UD(f, x, a, b, c) evaluates to f(x, a), f(x, b), f(x, c) +#define CATCH_REC_LIST_UD(f, userdata, ...) CATCH_RECURSE(CATCH_REC_LIST2_UD(f, userdata, __VA_ARGS__, ()()(), ()()(), ()()(), 0)) + +#define CATCH_REC_LIST(f, ...) CATCH_RECURSE(CATCH_REC_LIST2(f, __VA_ARGS__, ()()(), ()()(), ()()(), 0)) + +#define INTERNAL_CATCH_EXPAND1(param) INTERNAL_CATCH_EXPAND2(param) +#define INTERNAL_CATCH_EXPAND2(...) INTERNAL_CATCH_NO## __VA_ARGS__ +#define INTERNAL_CATCH_DEF(...) INTERNAL_CATCH_DEF __VA_ARGS__ +#define INTERNAL_CATCH_NOINTERNAL_CATCH_DEF +#define INTERNAL_CATCH_STRINGIZE(...) INTERNAL_CATCH_STRINGIZE2(__VA_ARGS__) +#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +#define INTERNAL_CATCH_STRINGIZE2(...) #__VA_ARGS__ +#define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param)) +#else +// MSVC is adding extra space and needs another indirection to expand INTERNAL_CATCH_NOINTERNAL_CATCH_DEF +#define INTERNAL_CATCH_STRINGIZE2(...) INTERNAL_CATCH_STRINGIZE3(__VA_ARGS__) +#define INTERNAL_CATCH_STRINGIZE3(...) #__VA_ARGS__ +#define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) (INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param)) + 1) +#endif + +#define INTERNAL_CATCH_MAKE_NAMESPACE2(...) ns_##__VA_ARGS__ +#define INTERNAL_CATCH_MAKE_NAMESPACE(name) INTERNAL_CATCH_MAKE_NAMESPACE2(name) + +#define INTERNAL_CATCH_REMOVE_PARENS(...) INTERNAL_CATCH_EXPAND1(INTERNAL_CATCH_DEF __VA_ARGS__) + +#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +#define INTERNAL_CATCH_MAKE_TYPE_LIST2(...) decltype(get_wrapper()) +#define INTERNAL_CATCH_MAKE_TYPE_LIST(...) INTERNAL_CATCH_MAKE_TYPE_LIST2(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__)) +#else +#define INTERNAL_CATCH_MAKE_TYPE_LIST2(...) INTERNAL_CATCH_EXPAND_VARGS(decltype(get_wrapper())) +#define INTERNAL_CATCH_MAKE_TYPE_LIST(...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_MAKE_TYPE_LIST2(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__))) +#endif + +#define INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(...)\ + CATCH_REC_LIST(INTERNAL_CATCH_MAKE_TYPE_LIST,__VA_ARGS__) + +#define INTERNAL_CATCH_REMOVE_PARENS_1_ARG(_0) INTERNAL_CATCH_REMOVE_PARENS(_0) +#define INTERNAL_CATCH_REMOVE_PARENS_2_ARG(_0, _1) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_1_ARG(_1) +#define INTERNAL_CATCH_REMOVE_PARENS_3_ARG(_0, _1, _2) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_2_ARG(_1, _2) +#define INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_0, _1, _2, _3) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_3_ARG(_1, _2, _3) +#define INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_0, _1, _2, _3, _4) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_1, _2, _3, _4) +#define INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_0, _1, _2, _3, _4, _5) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_1, _2, _3, _4, _5) +#define INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_0, _1, _2, _3, _4, _5, _6) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_1, _2, _3, _4, _5, _6) +#define INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_0, _1, _2, _3, _4, _5, _6, _7) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_1, _2, _3, _4, _5, _6, _7) +#define INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_1, _2, _3, _4, _5, _6, _7, _8) +#define INTERNAL_CATCH_REMOVE_PARENS_10_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9) +#define INTERNAL_CATCH_REMOVE_PARENS_11_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_10_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10) + +#define INTERNAL_CATCH_VA_NARGS_IMPL(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N + +#define INTERNAL_CATCH_TYPE_GEN\ + template struct TypeList {};\ + template\ + constexpr auto get_wrapper() noexcept -> TypeList { return {}; }\ + template class...> struct TemplateTypeList{};\ + template class...Cs>\ + constexpr auto get_wrapper() noexcept -> TemplateTypeList { return {}; }\ + template\ + struct append;\ + template\ + struct rewrap;\ + template class, typename...>\ + struct create;\ + template class, typename>\ + struct convert;\ + \ + template \ + struct append { using type = T; };\ + template< template class L1, typename...E1, template class L2, typename...E2, typename...Rest>\ + struct append, L2, Rest...> { using type = typename append, Rest...>::type; };\ + template< template class L1, typename...E1, typename...Rest>\ + struct append, TypeList, Rest...> { using type = L1; };\ + \ + template< template class Container, template class List, typename...elems>\ + struct rewrap, List> { using type = TypeList>; };\ + template< template class Container, template class List, class...Elems, typename...Elements>\ + struct rewrap, List, Elements...> { using type = typename append>, typename rewrap, Elements...>::type>::type; };\ + \ + template