//****************************************************************************** //** SCATMECH: Polarized Light Scattering C++ Class Library //** //** File: inherit.h //** //** Thomas A. Germer //** Optical Technology Division, National Institute of Standards and Technology //** 100 Bureau Dr. Stop 8443; Gaithersburg, MD 20899-8443 //** Phone: (301) 975-2876; FAX: (301) 975-6991 //** Email: thomas.germer@nist.gov //** //** Version: 6.00 (February 2008) //** //****************************************************************************** #ifndef SCATMECH_INHERIT_H #define SCATMECH_INHERIT_H #include #include "scatmech.h" #include namespace SCATMECH { // // This file defines, amongst other things, the following classes... // class Inheritance; class Model; template class Model_Ptr; template class Model_Maker; class Model_Maker_Base; struct ParameterInfo; class ModelParameterBase; template class ModelParameter; template class ModelPtrParameter; class Get_Model_Ptr; template _Model* _Get_Named_Model(const STRING& name); template _Model* _Get_Model(); typedef std::deque InheritanceList; typedef std::auto_ptr ModelParameterBasePtr; typedef std::deque ModelParameterList; typedef std::deque StringList; /// /// The struct ParameterInfo stores information about a parameter. /// struct ParameterInfo { /// Default constructor. ParameterInfo() {} /// Constructor ParameterInfo( const STRING& _name, ///< The name of the parameter const STRING& _description, ///< Its description const STRING& _type, ///< The data type const STRING& _defaultvalue ///< Its default value ) : name(_name), description(_description), type(_type), defaultvalue(_defaultvalue) {} STRING name; ///< The name of the parameter... STRING description; ///< A description of the parameter... STRING type; ///< The data type for external programs... STRING defaultvalue; ///< The default value for the parameter... }; /// /// @brief Base class for all Model parameters. /// /// It stores the pointer to a member in a Model. /// class ModelParameterBase : public ParameterInfo { public: /// Constructor ModelParameterBase( const STRING& _name, ///< The name of the parameter const STRING& _description, ///< Its description const STRING& _type, ///< The data type const STRING& _defaultvalue, ///< Its default value Inheritance& inherit ///< The inheritance structure to which ///< model this parameter belongs ); /// Set a parameter's value. virtual void set_parameter( const Model* model, ///< Pointer to the specific object const STRING& subparameter, ///< Any subparameters, if applicable const STRING& value ///< A string representation of the value ) const = 0; /// Return a pointer to the instance of the parameter. /// How this pointer is interpreted should depend upon type. virtual void* get_ptr( const Model* model ///< Pointer to the specific object ) const = 0; /// Return the current value of the parameter as a STRING. virtual STRING get_parameter( const Model* model, ///< Pointer to the specific object const STRING& subparameter ///< Any subparameters, if applicable ) const=0; /// Prompts the user for the parameter's value. virtual void AskUser( const Model* model ///< Pointer to the specific object ) const = 0; /// Return parent class' inheritance. Function returns a null pointer /// for a normal parameter, and a pointer the parent class' /// inheritance if it is a Model_Ptr parameter... virtual const Inheritance* get_inheritance( const Model* model=NULL ///< Pointer to the specific object ) const {return (Inheritance*)0; } }; /// /// @brief Base class for all models in SCATMECH /// class Model { public: /// Constructor Model() {recalc=1;} /// Destructor virtual ~Model() {} /// @brief Initialize the model. /// Assigns all the models parameters to their /// default values and should be called after construction. void init(); /// @brief Query the user for parameters. /// A default implementation if this function is /// provided, which can be used under most conditions. virtual void AskUser(); /// Static variable that keeps track of all inherited models. static Inheritance inheritance; /// @brief Return the inheritance of the specific model. /// It should be redefined for every inherited model, so that it will /// return the appropriate model. The DECLARE_MODEL macro does this. virtual const Inheritance& get_inheritance() const {return inheritance;} /// Return a list of all the parameters. void get_parameter_names( StringList& plist ///< Where the list of parameters is returned ) const { get_parameter_names(plist,""); } /// Return information about a specific parameter. ParameterInfo get_parameter_info( const STRING& parameter ///< The name of the parameter ) const; /// Set a parameter to a value. template void set_parameter( const STRING& parameter, ///< The name of the parameter const SETTYPE& value ///< The value to set it to ) { set_parameter_base(parameter,to_string(value)); } /// Set a parameter to a value. void set_parameter( const STRING& parameter, ///< The name of the parameter const char* value ///< The value to set it to ) { set_parameter_base(parameter,std::string(value)); } /// Get the current value of a parameter in string form. STRING get_parameter( const STRING& parameter ///< The parameter name ) const; /// @brief Output parameters to a stream. /// Send a listing of all parameters and their current values to an output stream. void print_parameters( std::ostream& os ///< Output stream ) const; /// Set to 1 to force recalculation. void set_recalc(int _recalc=1) {recalc=_recalc;} /// Returns 1 if any parameter has changed. virtual int get_recalc() {return recalc;} /// Set to keep model quiet during calculations. static void set_quiet(int _quiet) {quiet=_quiet;} /// Returns 1 if model should keep quiet. static int get_quiet() {return quiet;} protected: /// @brief Routine which does housekeeping if recalc!=0. /// All inherited classes which need to perform calculations /// once anytime a parameter changes should define setup(), /// and should begin by calling its parent's setup(). virtual void setup() {recalc=0;} /// @brief Perform housekeeping, if neccessary. /// All routines that need up-to-date information should begin with SETUP(). virtual void SETUP() { if (get_recalc()) setup(); } /// Routine to send messages to the user, void message( const STRING& s ///< Message to be sent ) { if (!quiet) {SCATMECH_output << s << ret; } } /// Routine which handles errors... void error(const STRING& message) const; private: /// @brief Sets a parameter to a value. /// This parameter is a non-templated version which handles /// the core functions of set_parameter. void set_parameter_base( const STRING& parameter, ///< The parameter name const STRING& value ///< String represention of a value ); /// Implementation of same-named function with one parameter. void get_parameter_names( StringList& plist, ///< Receives result of query const STRING& prefix ///< Prefix to add to resulting parameter names ) const; /// @brief Indicates that initialization may need to be carried out. /// Should be set anytime a variable is set. int recalc; /// @brief Indicates model should be verbose. /// Indicates whether or not the model should be verbose during its /// calculations. By default, quiet is zero. static int quiet; }; /// @brief Class that keeps track of class inheritance structure. /// /// class Inheritance keeps track of all of the child classes of a given /// parent class. It enables a specific instance of a child class to be /// created by a menu or by a character string. It keeps track of a name, /// description, parametres, and where the Model is in the Model heirarchy. /// It provides functions for linking to its parents and children and /// progeny (children's children). /// class Inheritance { public: /// Constructor... Inheritance( const STRING& _name, ///< Name of class const STRING& _desc, ///< Description Model_Maker_Base *_maker, ///< Class which creates new instances of class Inheritance *_parent ///< Pointer to Parent inheritance ) : name(_name),description(_desc), maker(_maker),parent(_parent), virt(_maker==0),registered(false) {} /// Return name of the class. const STRING& get_name() const {return name;} /// Return desscription of the class. const STRING& get_description() const {return description;} /// Return true if it is a virtual model bool is_virtual() const {return virt;} /// Return true if model can be instantiated. bool is_instantiable() const {return !virt;} /// @brief Query for child class. /// Print out a list of available child classes and /// return a pointer to the user's choice. Model* get_model() const { return get_model(true); } /// Return a pointer to the named progeny class. Model* get_named_model( const STRING& name ///< Name of class to create instance of ) const { return get_named_model(name,false); } /// Returns parent's Inheritance. const Inheritance* get_parent() const { return parent; } /// @brief Return list of direct children. /// Direct children includes only directly inherited children. const InheritanceList& get_children() const {return children;} /// @brief Return list of all children. /// Progeny includes children, children's children, etc. InheritanceList get_progeny() const { InheritanceList result; get_model_inheritance_list(result,1); return result; } /// Return the Inheritance for a named progeny. const Inheritance* get_named_inheritance( const STRING& model, ///< Name of the model bool nothrow=false ///< Will throw exception if not found. ) const; /// Get list of model parameters. ModelParameterList get_parameters() const { ModelParameterList result; get_parameters(result,true); return result; } /// Get a specific model parameter. const ModelParameterBase* get_modelparameter( const STRING& param ///< Name of parameter ) const; // Return an instance of the model. Model* make() const; /// Return a clone of the model. Model* clone( const Model& m ///< Model to clone ) const; /// @brief Register the class' existence. /// Registers with its own list and with its parent's list. void Register_Model() { if (!registered) { if (parent) parent->add_child(this); registered=true; } } private: friend class ModelParameterBase; /// Adds a class to the list this class' inherited classes... void add_child( const Inheritance* ib ///< Pointer to class inheritance to add ) { children.push_back(ib); } /// Add a model parameter to this model. void add_parameter( ModelParameterBase* mp ///< Pointer to parameter ) { parameters.push_back(mp); } /// A string name for the class STRING name; /// A string description for the class STRING description; /// A list of pointers to inherited classes InheritanceList children; /// Points to the Model's parent's Inheritance. Inheritance* parent; /// The list of parameters for this model. ModelParameterList parameters; /// A flag to indicate if this class is instantiable or not... bool virt; /// A flag to indicate if this class has been registered. bool registered; /// A static flag that indicates whether or not the user /// would like to see descriptions with the class names. static bool show_model_mode; /// The following contains a pointers to the class that contain the /// maker and the registrars for this Model class... std::auto_ptr maker; // // Functions that returns a list of inherited classes and their // descriptions.... // // option = 1 indicates result should be cleared at start // option = 2 indicates that only first level should be traversed void get_model_inheritance_list(InheritanceList& result,int option=1) const; Model* get_model(bool top) const; Model* get_named_model(const STRING& name,bool nothrow) const; void get_parameters(ModelParameterList& result,bool top) const; friend void display_descriptions(const Inheritance* inherit, const InheritanceList& ilist); }; /// @brief Smart pointer to a Model /// /// The template class Model_Ptr<_Model> works similarly to std::auto_ptr, /// except that it makes cloned copies rather than transferring ownership of /// a pointer. It also adds some functions which make use of the SCATMECH /// Inheritance and Model classes. template class Model_Ptr { public: typedef _Model Type; typedef _Model* Ptr; /// Default constructor creates an uninitialized pointer. Model_Ptr() : model(0) {} /// Copy constructor Model_Ptr(const Model_Ptr<_Model>& model_ptr) { if (model_ptr.model) { const Inheritance& i = model_ptr.model->get_inheritance(); model = static_cast<_Model*>(i.clone(*(model_ptr.model))); } else model = 0; } /// Assignment operator Model_Ptr& operator=(const Model_Ptr<_Model>& model_ptr) { if (model) delete model; if (model_ptr.model) { const Inheritance& i = model_ptr.model->get_inheritance(); model = static_cast<_Model*>(i.clone(*(model_ptr.model))); } else model=0; return *this; } /// @brief Constructor with a pointer /// Ownership is transferred. Model_Ptr(Model* m) : model(0) { *this = m;} /// @brief Assignment to a pointer /// Ownership is transferred. Model_Ptr& operator=(Model* m) { if (model) delete model; if (m) { const Inheritance& i = m->get_inheritance(); model = static_cast<_Model*>(m); } else model = 0; return *this; } /// @brief Query the user for an inherited model. /// The constructor with the trivial class Get_Model_Ptr /// gets an instance of the class using the /// Inheritance functionality. Model_Ptr(const Get_Model_Ptr& gm) : model(0) { *this = gm;} /// @brief Query the user for an inherited model. /// The assignment to the trivial class Get_Model_Ptr /// gets an instance of the class using the /// Inheritance functionality. Model_Ptr& operator=(const Get_Model_Ptr& gm) { GetPtr(); return *this; } /// @brief Assignment to a string. /// Gets an instance of the class using the Inheritance functionality which /// has a specific name. Model_Ptr& operator=(const STRING& name) { if (model) delete model; model = _Get_Named_Model<_Model>(name); return *this; } /// @brief Constructor with a string. /// Gets an instance of the class using the Inheritance functionality which /// has a specific name. Model_Ptr(const STRING& name) : model(0) { *this = name;} /// @brief Destructor /// Destructor deletes the pointer if it is valid. ~Model_Ptr() {if (model) delete model;} /// Access elements of model as if Model_Ptr<_Model> were a normal pointer... _Model* operator->() const { if (!model) throw(SCATMECH_exception( "Attempt to access element by null pointer")); return get(); } /// Dereferencing _Model& operator*() const {return *(get());} /// Return the pointer _Model* get() const { return model; } /// Return an instance of _Model using _Model's Inheritance structure... Model_Ptr& GetPtr() { if (model) delete model; model = _Get_Model<_Model>(); return *this; } /// Returns the model's inheritance. static const Inheritance* GetInheritance() { return &(_Model::inheritance); } private: /// The pointer to a Model... _Model* model; }; /// @brief Trivial class used by Model_Ptr<_Model> /// /// Trivial class used by the constructor and operator=() of /// Model_Ptr<_Model> to indicate that get_model must be called... class Get_Model_Ptr {}; /// @brief Class for creating and cloning models /// /// The templated class Model_Maker<_Model> is used by the class Inheritance /// to provide a function which creates a new instance of a class or a clone /// of a class. class Model_Maker_Base { public: /// @brief Create an instance of the model /// It is expected that the programmer will typecast the /// result to a pointer to the approprate model. virtual Model* make() const = 0; /// @brief Create a clone of the model /// It is expected that the programmer will typecast the /// result to a pointer to the approprate model. virtual Model* clone(const Model& model) const = 0; }; /// /// @brief Template class to create and clone specific models /// template class Model_Maker : public Model_Maker_Base { public: Model* make() const { Model* newModel = static_cast(new _Model); newModel->init(); return newModel; } Model* clone(const Model& model) const { return new _Model(static_cast(model)); } }; /// /// @brief Placeholder template for something which is not a model /// template <> class Model_Maker : public Model_Maker_Base { public: Model* make() const {return static_cast(0); } Model* clone(const Model& model) const {return static_cast(0); } }; inline Model* Inheritance::make() const {return maker->make();} inline Model* Inheritance::clone(const Model& m) const {return maker->clone(m);} /// @brief Register all models in the tree of classes /// /// Model that have children define this function, so that the tree /// can be built. This function should be called before any /// calls that search the class tree. void Register( const Model* x ///< Argument used for defining polymorphic function ); /// @brief Returns a pointer to a _Model. /// /// Queries the user for a model, creates an instance of one, and returns /// the pointer to it. It registers the model first. template _Model* _Get_Model() { Register((_Model*)0); return static_cast<_Model*>(_Model::inheritance.get_model()); } /// @brief Returns a pointer to a specified Model. /// /// Creates an instance of the model with the given name. /// It registers the model first. template _Model* _Get_Named_Model( const STRING& name ///< The name of the model (must be a child of _Model) ) { Register((_Model*)0); return static_cast<_Model*>(_Model::inheritance.get_named_model(name)); } /// Macro to register a specific model #define Register_Model(_Model) _Model::inheritance.Register_Model() //#define Get_Model(_Model) SCATMECH::_Get_Model<_Model>() //#define Get_Named_Model(_Model,name) SCATMECH::_Get_Named_Model<_Model>(name) /// Routine to assert that a string is empty inline void AssertNullParameter(const STRING& parameter) { if (parameter!="") throw SCATMECH_exception("No subparameter allowed"); } /// @brief Sets a parameter to a value, given a string. /// /// Used by ModelParameter, the template function ModelParameterSet converts a string /// to a TYPE, using subparameter if the data type handles subparameters. By default, /// it does not allow for non-empty subparameters. New data types, which act as /// model parameters, need to define an explicit template specialization, if it /// allows for subparameters. template void ModelParameterSet( TYPE& variable, ///< A reference to the variable being set const STRING& subparameter, ///< The subparameter to set (default asserts empty) const STRING& value ///< String representation of new value ) { AssertNullParameter(subparameter); variable = from_string(value); } /// @brief Gets a parameter specified by a string. /// /// Used by ModelParameter, the template function ModelParameterGet converts TYPE to /// STRING, using subparameter if the data type handles subparameters. By default, /// it does not allow for non-empty subparameters. New data types, which act as /// model parameters, need to define an explicit template specialization, if it /// allows for subparameters. It returns a string representation of the parameter. template STRING ModelParameterGet( TYPE& variable, ///< Reference to the variable const STRING& subparameter ///< The subparameter to set (default asserts empty) ) { AssertNullParameter(subparameter); return to_string(variable); } /// @brief Query the user for a parameter value /// /// Used by ModelParameter, the template function ModelParameterAskUser sends /// a query to the user and sets the value to the response. New data types, /// which act as model parameters, need to define an explicit template /// specialization, if it has subparameters. template void ModelParameterAskUser( TYPE& variable, ///< Reference to the variable const STRING& prompt ///< The prompt used to query ) { variable = AskUser(prompt,variable); } /// @brief Simple (non-Model_Ptr) parameters /// /// Simple (non-Model_Ptr) parameters use this class template class ModelParameter : public ModelParameterBase { public: ModelParameter(const STRING& _name, const STRING& _description, const STRING& _type, const STRING& _defaultvalue, Inheritance& inherit, TYPE MODEL::*_parameter) : ModelParameterBase(_name,_description,_type,_defaultvalue,inherit), parameter(_parameter) {} virtual void set_parameter(const Model* model, const STRING& subparameter, const STRING& value) const { TYPE &_parameter = ((MODEL*)model)->*parameter; ModelParameterSet(_parameter,subparameter,value); } virtual void AskUser(const Model* model) const { TYPE &_parameter = ((MODEL*)model)->*parameter; ModelParameterAskUser(_parameter,description); } virtual void* get_ptr(const Model* model) const { return (void*)&(((MODEL*)model)->*parameter); } virtual STRING get_parameter(const Model* model, const STRING& subparameter) const { TYPE &_parameter = ((MODEL*)model)->*parameter; return ModelParameterGet(_parameter,subparameter); } private: // Pointer to member variable... TYPE MODEL::*parameter; }; /// @brief Model_Ptr parameters /// Model_Ptr parameters use this class template class ModelPtrParameter : public ModelParameterBase { public: ModelPtrParameter(const STRING& _name, const STRING& _description, const STRING& _type, const STRING& _defaultvalue, Inheritance& inherit, TYPE MODEL::*_parameter) : ModelParameterBase(_name,_description,_type,_defaultvalue,inherit), parameter(_parameter) {} virtual void set_parameter(const Model* model, const STRING& subparameter, const STRING& value) const { TYPE &_parameter = ((MODEL*)model)->*parameter; if (subparameter=="") { // If there is no subparameter, then create an // instance of the model type... Register(TYPE().get()); _parameter = TYPE::GetInheritance()->get_named_model(value); } else { // If there is a subparameter, then send it to the model... _parameter->set_parameter(subparameter,value); } } virtual void AskUser(const Model* model) const { TYPE &_parameter = ((MODEL*)model)->*parameter; SCATMECH_output << description; _parameter = Get_Model_Ptr(); _parameter->AskUser(); } virtual const Inheritance* get_inheritance(const Model* model) const { if (model!=NULL) { return &((((MODEL*)model)->*parameter).get()->get_inheritance()); } else { return TYPE::GetInheritance(); } } virtual void* get_ptr(const Model* model) const { return (void*)((((MODEL*)model)->*parameter).get()); } virtual STRING get_parameter(const Model* model, const STRING& subparameter) const { if (subparameter=="") { return ((MODEL*)model->*parameter).get()->get_inheritance().get_name(); } else { return ((MODEL*)model->*parameter).get()->get_parameter(subparameter); } } private: // A pointer to member for the actual parameter TYPE MODEL::*parameter; }; /// /// @brief Macro used in the declaration of a Model /// /// Each model should have this macro in its declaration. It declares a /// static Inheritance for the model, a get_inheritance() function, and /// a clone() function. /// #define DECLARE_MODEL() \ public: static SCATMECH::Inheritance inheritance; \ public: SCATMECH::Model* clone() const {return inheritance.clone(*this);} \ public: virtual const SCATMECH::Inheritance& get_inheritance() const \ {return inheritance;} /// /// @brief Macro declare a parameter in a class declaration. /// /// Each parameter in a model should be declared using this macro. It declares /// the parameter as protected, member set_ and get_ functions as public, /// and a static private ModelParameter variable. /// /// @param TYPE is the data type for the parameter /// @param PARAMETER is the variable name. /// #define DECLARE_PARAMETER(TYPE,PARAMETER) \ public: const TYPE& get_##PARAMETER() const {return PARAMETER;} \ public: void set_##PARAMETER(const TYPE& x) \ {PARAMETER = x; set_recalc(1);} \ protected: TYPE PARAMETER; \ private: static SCATMECH::ModelParameterBasePtr MP_##PARAMETER; /// /// @brief Macro to define a instantiable model's static Inheritance element /// /// DEFINE_MODEL aids the programmer in defining a Model's /// static Inheritance element. /// /// @param child is the class which has the member inheritance which needs defining. /// @param parent is the parent class /// @param name is a string version of the name of the class /// @param desc is a string description of the class /// #define DEFINE_MODEL(child,parent,name,desc) \ SCATMECH::Inheritance child::inheritance(name, \ desc, \ new SCATMECH::Model_Maker(), \ &parent::inheritance); /// /// @brief Macro to define a non-instantiable model's static Inheritance element /// /// DEFINE_VIRTUAL_MODEL aids the programmer in defining a Model's /// static Inheritance element. /// /// @param child is the class which has the member inheritance which needs defining. /// @param parent is the parent class /// @param name is a string version of the name of the class /// @param desc is a string description of the class /// #define DEFINE_VIRTUAL_MODEL(child,parent,name,desc) \ SCATMECH::Inheritance child::inheritance(name, \ desc, \ 0, \ &parent::inheritance); /// /// @brief Macro to define non-Model_Ptr parameters /// /// DEFINE_PARAMETER defines the static ModelParameter variable associated /// with a specific model parameter. /// /// This macros must follow the DEFINE_MODEL macro for CLASS. /// /// @param CLASS is the Model class /// @param TYPE is the data type for the parameter /// @param PARAMETER is the parameter name. /// @param DESCRIPTION is a string description of the parameter /// @param DEFAULTVALUE is a string representation of the default value /// #define DEFINE_PARAMETER(CLASS,TYPE,PARAMETER,DESCRIPTION,DEFAULTVALUE) \ ModelParameterBasePtr \ CLASS::MP_##PARAMETER( \ new ModelParameter< CLASS , TYPE >(#PARAMETER, \ DESCRIPTION, \ #TYPE, \ DEFAULTVALUE, \ CLASS::inheritance, \ &CLASS::PARAMETER)); /// /// @brief Macro to define Model_Ptr parameters /// /// DEFINE_PARAMETER defines the static ModelPtrParameter variable associated /// with a specific model Model_Ptr parameter. /// /// This macros must follow the DEFINE_MODEL macro for CLASS. /// /// @param CLASS is the Model class /// @param TYPE is the data type for the parameter /// @param PARAMETER is the parameter name. /// @param DESCRIPTION is a string description of the parameter /// @param DEFAULTVALUE is a string representation of the default value /// #define DEFINE_PTRPARAMETER(CLASS,TYPE,PARAMETER,DESCRIPTION,DEFAULTVALUE) \ ModelParameterBasePtr \ CLASS::MP_##PARAMETER( \ new ModelPtrParameter< CLASS , TYPE >(#PARAMETER, \ DESCRIPTION, \ #TYPE, \ DEFAULTVALUE, \ CLASS::inheritance, \ &CLASS::PARAMETER)); } // namespace SCATMECH #endif