36 #ifndef INFACT_FACTORY_H_
37 #define INFACT_FACTORY_H_
42 #include <unordered_map>
43 #include <unordered_set>
62 #define INFACT_ADD_PARAM(param) initializers.Add(#param, &_ ## param)
75 #define INFACT_ADD_PARAM_(param) initializers.Add(#param, ¶m ## _)
79 #define INFACT_ADD_REQUIRED_PARAM(param) \
80 initializers.Add(#param, &_ ## param, true)
83 #define INFACT_ADD_REQUIRED_PARAM_(param) \
84 initializers.Add(#param, ¶m ## _, true)
93 #define INFACT_ADD_TEMPORARY(type, var) \
94 initializers.Add(#var, static_cast<type *>(nullptr))
124 #define INFACT_ADD_REQUIRED_TEMPORARY(type, var) \
125 initializers.Add(#var, static_cast<type *>(nullptr), true)
132 using std::ostringstream;
133 using std::shared_ptr;
134 using std::unordered_map;
135 using std::unordered_set;
153 template <
typename T>
205 template <
typename T>
220 template <
typename T>
289 template <
typename T>
314 if (typed_var_map !=
nullptr) {
341 typedef unordered_map<string, MemberInitializer *>::const_iterator
345 typedef unordered_map<string, MemberInitializer *>::iterator
iterator;
351 for (
iterator init_it = initializers_.begin();
352 init_it != initializers_.end();
354 delete init_it->second;
376 void Add(
const string &name, T *member,
bool required =
false) {
377 if (initializers_.find(name) != initializers_.end()) {
378 ostringstream err_ss;
379 err_ss <<
"Initializers::Add: error: two members have the same name: "
412 return initializers_.find(name);
420 return initializers_.find(name);
423 unordered_map<string, MemberInitializer *> initializers_;
436 virtual void Clear() = 0;
438 virtual const string BaseName()
const = 0;
462 factories_ =
new vector<FactoryBase *>();
465 factories_->push_back(factory);
470 for (vector<FactoryBase *>::iterator it = factories_->begin();
471 it != factories_->end();
483 if (factories_ ==
nullptr) {
484 cerr <<
"FactoryContainer::begin: error: no FactoryBase instances!"
487 return factories_->begin();
490 if (factories_ ==
nullptr) {
491 cerr <<
"FactoryContainer::begin: error: no FactoryBase instances!"
494 return factories_->end();
504 cerr <<
"Number of factories: " << factories_->size() <<
"." << endl;
505 for (vector<FactoryBase *>::iterator factory_it = factories_->begin();
506 factory_it != factories_->end();
508 unordered_set<string> registered;
509 (*factory_it)->CollectRegistered(registered);
510 os <<
"Factory<" << (*factory_it)->BaseName() <<
"> can construct:\n";
511 for (unordered_set<string>::const_iterator it = registered.begin();
512 it != registered.end();
514 os <<
"\t" << *it <<
"\n";
520 static int initialized_;
521 static vector<FactoryBase *> *factories_;
530 template <
typename T>
592 template <
typename T>
767 shared_ptr<Environment> env_ptr(env ==
nullptr ?
772 (st.
Peek() ==
"nullptr" || st.
Peek() ==
"NULL")) {
775 return shared_ptr<T>();
778 ostringstream err_ss;
779 err_ss <<
"Factory<" <<
BaseName() <<
">: "
780 <<
"error: expected type specifier token but found "
786 string type = st.
Next();
789 if (st.
Peek() !=
"(") {
790 ostringstream err_ss;
791 err_ss <<
"Factory<" <<
BaseName() <<
">: "
792 <<
"error: expected '(' at stream position "
799 typename unordered_map<string, const Constructor<T> *>::iterator cons_it =
800 cons_table_->find(type);
801 if (cons_it == cons_table_->end()) {
802 ostringstream err_ss;
803 err_ss <<
"Factory<" <<
BaseName() <<
">: "
804 <<
"error: unknown type: \"" << type <<
"\"";
807 shared_ptr<T> instance(cons_it->second->NewInstance());
811 instance->RegisterInitializers(initializers);
814 while (st.
Peek() !=
")") {
817 ostringstream err_ss;
818 err_ss <<
"Factory<" <<
BaseName() <<
">: "
819 <<
"error: expected token of type IDENTIFIER at "
822 << st.
Peek() <<
"\"";
826 string member_name = st.
Next();
828 if (init_it == initializers.end()) {
829 ostringstream err_ss;
830 err_ss <<
"Factory<" <<
BaseName() <<
">: "
831 <<
"error: unknown member name \"" << member_name
832 <<
"\" in initializer list for type " << type <<
" at stream "
833 <<
"position " << member_name_start;
840 bool saw_member_init_open_paren = st.
Peek() ==
"(";
841 bool saw_member_init_equals_sign = st.
Peek() ==
"=";
842 if (!saw_member_init_open_paren && !saw_member_init_equals_sign) {
843 ostringstream err_ss;
844 err_ss <<
"Factory<" <<
BaseName() <<
">: "
845 <<
"error initializing member " << member_name <<
": "
846 <<
"expected '(' or '=' at stream position "
853 member_initializer->
Init(st, env_ptr.get());
856 if (saw_member_init_open_paren) {
857 if (st.
Peek() !=
")") {
858 ostringstream err_ss;
859 err_ss <<
"Factory<" <<
BaseName() <<
">: "
860 <<
"error initializing member " << member_name <<
": "
861 <<
"saw '(' at stream position " << member_init_start
862 <<
"; expected ')' at stream position "
871 if (st.
Peek() !=
"," && st.
Peek() !=
")") {
872 ostringstream err_ss;
873 err_ss <<
"Factory<" <<
BaseName() <<
">: "
874 <<
"error initializing member " << member_name <<
": "
875 <<
"expected ',' or ')' at stream position "
880 if (st.
Peek() ==
",") {
886 if (st.
Peek() !=
")") {
887 ostringstream err_ss;
888 err_ss <<
"Factory<" <<
BaseName() <<
">: "
889 <<
"error at initializer list end: "
890 <<
"expected ')' at stream position "
899 init_it != initializers.end();
902 if (member_initializer->
Required() &&
904 ostringstream err_ss;
905 err_ss <<
"Factory<" <<
BaseName() <<
">: "
906 <<
"error: initialization for member with name \""
907 << init_it->first <<
"\" required but not found (current "
908 <<
"stream position: " << st.
tellg() <<
")";
913 size_t end = st.
tellg();
915 string stream_str = st.
str();
917 string init_str = stream_str.substr(start, end - start);
919 instance->PostInit(env_ptr.get(), init_str);
924 shared_ptr<T>
CreateOrDie(
const string &spec,
const string err_msg,
932 virtual const string BaseName()
const {
return base_name_; }
942 return initialized_ && cons_table_->find(type) != cons_table_->end();
948 for (
typename unordered_map<
string,
const Constructor<T> *>::iterator it =
949 cons_table_->begin();
950 it != cons_table_->end();
952 registered.insert(it->first);
958 bool is_primitive =
false;
964 bool is_primitive =
false;
977 cons_table_ =
new unordered_map<string, const Constructor<T> *>();
981 typename unordered_map<string, const Constructor<T> *>::iterator cons_it =
982 cons_table_->find(type);
983 if (cons_it == cons_table_->end()) {
984 (*cons_table_)[type] = p;
988 return cons_it->second;
999 for (
typename unordered_map<
string,
const Constructor<T> *>::iterator it =
1000 cons_table_->begin();
1001 it != cons_table_->end();
1012 static int initialized_;
1014 static unordered_map<string, const Constructor<T> *> *cons_table_;
1015 static const char *base_name_;
1020 template <
typename T>
1021 unordered_map<string, const Constructor<T> *> *
1022 Factory<T>::cons_table_ = 0;
1030 #define DEFINE_CONS_CLASS(TYPE,NAME,BASE) \
1031 class NAME ## Constructor : public infact::Constructor<BASE> { \
1032 public: virtual BASE *NewInstance() const { return new TYPE(); } };
1044 #define REGISTER_NAMED(TYPE,NAME,BASE) \
1045 DEFINE_CONS_CLASS(TYPE,NAME,BASE) \
1046 static const infact::Constructor<BASE> *NAME ## _my_protoype = \
1047 infact::Factory<BASE>::Register(string(#NAME), new NAME ## Constructor());
1051 #define IMPLEMENT_FACTORY(BASE) \
1052 template<> int infact::Factory<BASE>::initialized_ = 0; \
1053 template<> const char *infact::Factory<BASE>::base_name_ = #BASE;
virtual VarMapBase * CreateVarMap(Environment *env) const =0
TypedMemberInitializer(const string &name, T *member, bool required=false)
A concrete implementation of the MemberInitializer base class, holding a pointer to a typed member th...
MemberInitializer(const string &name, bool required)
Initializes this base class.
virtual VarMapBase * CreateVectorVarMap(Environment *env) const =0
unordered_map< string, MemberInitializer * >::iterator iterator
Forward the iterator typedef of the internal data structure, to make code compact and readable...
virtual void Init(StreamTokenizer &st, Environment *env)
Initializes this instance based on the following tokens obtained from the specified StreamTokenizer...
static void Clear()
Clears this container of factories.
virtual ~TypedMemberInitializer()
virtual ~FactoryConstructible()
Destroys this instance.
iterator find(const string &name)
Returns an iterator pointing to the MemberInitializer associated with the specified name...
iterator end()
Returns an iterator pointing to the end of the map from member names to pointers to TypedMemberInitia...
An interface with a single virtual method that constructs a concrete instance of the abstract type T...
shared_ptr< T > CreateOrDie(const string &spec, const string err_msg, Environment *env=nullptr)
virtual void Clear()=0
Clears the (possibly static) data of this factory.
const_iterator find(const string &name) const
Returns a const_iterator pointing to the MemberInitializer associated with the specified name...
virtual bool Required() const
Whether this member is required to be initialized in a spec string.
vector< FactoryBase * >::iterator iterator
virtual void PostInit(const Environment *env, const string &init_str)
Does any additional initialization after an instance of this class has been constructed, crucially giving access to the Environment that was in use and modified during construction by the Factory::CreateOrDie method.
virtual void RegisterInitializers(Initializers &initializers)
Registers data members of this class for initialization when an instance is constructed via the Facto...
static void Print(ostream &os)
Prints the base typenames for all factories along with a list of all concrete subtypes those factorie...
We use the templated class TypeName to be able to take an actual C++ type and get the type name strin...
string Next()
Returns the next token in the token stream.
virtual int Initialized() const
Returns the number of times this member initializer’s Init method has been invoked.
virtual T * NewInstance() const =0
unordered_map< string, MemberInitializer * >::const_iterator const_iterator
Forward the const_iterator typedef of the internal data structure, to make code compact and readable...
Initializers()
Constructs a new instance.
Provides an error handling function that optionally throws an exception.
string name_
The name of this member.
int initialized_
The number of times this member initializer’s Init method has been invoked.
iterator begin()
Returns an iterator pointing to the beginning of the map from member names to pointers to TypedMember...
const_iterator end() const
Returns a const iterator pointing to the end of the map from member names to pointers to TypedMemberI...
const_iterator begin() const
Returns a const iterator pointing to the beginning of the map from member names to pointers to TypedM...
Factory for dynamically created instance of the specified type.
bool Get(const string &varname, T *value) const
Assigns the value of the specified variable to the object pointed to by the value parameter...
Factory()
Constructs a new factory.
A container to hold the mapping between named variables of a specific type and their values...
TokenType PeekTokenType() const
Returns the type of the next token, or EOF_TYPE if there is no next token.
A container for all the member initializers for a particular Factory-constructible instance...
virtual Environment * Copy() const =0
Returns a copy of this environment.
virtual ~MemberInitializer()
Destroys this instance.
A concrete, typed implementation of the MemberInitializer base class.
string str()
Returns the entire sequence of characters read so far by this stream tokenizer as a newly constructed...
A simple class for tokenizing a stream of tokens for the formally specified language used to construc...
static Environment * CreateEmpty()
A static factory method to create a new, empty Environment instance.
Provides the StreamTokenizer class.
virtual const string BaseName() const
Returns the name of the base type of objects constructed by this factory.
static bool IsRegistered(const string &type)
Returns whether the specified type has been registered with this factory (where registration happens ...
static const Constructor< T > * Register(const string &type, const Constructor< T > *p)
The method used by the REGISTER_NAMED macro to ensure that subclasses add themselves to the factory...
virtual ~Initializers()
Destroys this instance.
An interface for an environment in which variables of various types are mapped to their values...
static const char * TypeName(TokenType token_type)
Returns a string type name for the specified TokenType constant.
size_t PeekTokenStart() const
Returns the next token’s start position, or the byte position of the underlying byte stream if there ...
virtual void CollectRegistered(unordered_set< string > ®istered) const
Collects the names of types registered with this factory.
Provides an interface for an Environment, which contains a map from variables of a specific type (pri...
virtual const string BaseName() const =0
Returns the name of the base type of objects constructed by this factory.
void Error(const std::string &message)
Reports an error encountered during parsing and/or construction of an object.
string Peek() const
Returns the next token that would be returned by the Next method.
An interface simply to make it easier to implement Factory-constructible types by implementing both r...
shared_ptr< T > CreateOrDie(StreamTokenizer &st, Environment *env=nullptr)
Dynamically creates an object, whose type and initialization are contained in a specification string...
virtual VarMapBase * CreateVectorVarMap(Environment *env) const
TokenType
The set of types of tokens read by this stream tokenizer.
bool required_
Whether this member is required to be initialized.
static void Add(FactoryBase *factory)
Adds the specified factory to this container of factories.
static void ClearStatic()
Clears all static data associated with this class.
A class to hold all Factory instances that have been created.
virtual string Name()
Returns the name of the member initialized by this instance, as it should appear in a spec string par...
An interface for all Factory instances, specifying a few pure virtual methods.
An interface for data member initializers of members of a Factory-constructible object.
virtual VarMapBase * GetVarMap(const string &varname)=0
Retrieves the VarMap instance for the specified variable.
void Add(const string &name, T *member, bool required=false)
This method is the raison d'etre of this class: a method to make it easy to add all supported types o...
virtual void CollectRegistered(unordered_set< string > ®istered) const =0
Collects the names of types registered with this factory.
size_t tellg() const
Returns the number of bytes read from the underlying byte stream just after scanning the most recent ...
virtual void Init(StreamTokenizer &st, Environment *env)=0
Initializes this instance based on the following tokens obtained from the specified StreamTokenizer...
virtual void ReadAndSet(const string &varname, StreamTokenizer &st, const string type="")=0
Sets the specified variable to the value obtained from the following tokens available from the specif...
A base class for a mapping from variables of a specific type to their values.
virtual void Clear()
Clears this factory of all (possibly static) data.
virtual VarMapBase * CreateVarMap(Environment *env) const