openmbvcppinterface 3.1.0 OpenMBV C++ Interface

objectfactory.h
1 /* Copyright (C) 2004-2010 OpenMBV Development Team
2 *
3 * This library is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public
5 * License as published by the Free Software Foundation; either
6 * version 2.1 of the License, or (at your option) any later version.
7 *
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16 *
17 * Contact: friedrich.at.gc@googlemail.com
18 */
19
20 #ifndef _OPENMBV_OBJECTFACTORY_H_
21 #define _OPENMBV_OBJECTFACTORY_H_
22
23 #include <map>
24 #include <stdexcept>
25 #include <typeinfo>
26 #include <typeindex>
27 #include <mbxmlutilshelper/dom.h>
28 #include <xercesc/dom/DOMElement.hpp>
29 #include <openmbvcppinterface/object.h>
30
31 namespace OpenMBV {
32
33 class Object;
34
38 class ObjectFactory {
39
40 public:
41
45 template<class CreateType>
46 static void registerXMLName(const MBXMLUtils::FQN &name) {
47 registerXMLNamePrivate(name, &defaultCTor<CreateType>);
48 registerTypePrivate<CreateType>(&copyCTor<CreateType>);
49 }
50
54 template<class ContainerType>
55 static std::shared_ptr<ContainerType> create(const xercesc::DOMElement *element) {
56 // just check if ContainerType is derived from Object if not throw a compile error
57 static_assert(std::is_convertible<ContainerType*, Object*>::value,
58 "In OpenMBV::ObjectFactory::create<ContainerType>(...) ContainerType must be derived from Object.");
59 // return NULL if no input is supplied
60 if(element==nullptr) return {};
61 // loop over all all registered types corresponding to element->ValueStr()
62 auto range=instance().registeredName.equal_range(MBXMLUtils::E(element)->getTagName());
63 for(auto it=range.first; it!=range.second; it++) {
64 // allocate a new object using the defaultCTor function pointer
65 std::shared_ptr<Object> ele=it->second();
66 // try to cast ele up to ContainerType
67 std::shared_ptr<ContainerType> ret=std::dynamic_pointer_cast<ContainerType>(ele);
68 // if possible, return it
69 if(ret)
70 return ret;
71 }
72 // no matching element found: throw error
73 throw std::runtime_error("No class named "+MBXMLUtils::X()%element->getTagName()+" found which is of type "+
74 typeid(ContainerType).name()+".");
75 }
76
78 template<class CreateType>
79 static std::shared_ptr<CreateType> create() {
80 return std::shared_ptr<CreateType>(new CreateType, &deleter<CreateType>);
81 }
82
86 template<class ContainerType>
87 static std::shared_ptr<ContainerType> create(const std::shared_ptr<ContainerType> &t) {
88 // return NULL if no input is supplied
89 if(t==nullptr) return {};
90 // find item
91 auto &tRef=*t;
92 auto it=instance().registeredType.find(std::type_index(typeid(tRef)));
93 // not found?
94 if(it==instance().registeredType.end())
95 throw std::runtime_error(std::string("No class type ")+typeid(tRef).name()+" found in ObjectFactory.");
96 // allocate a new object using the copyCTor function pointer
97 return std::static_pointer_cast<ContainerType>(it->second(t));
98 }
99
100 static void addErrorMsg(const std::string &msg);
101 static std::string getAndClearErrorMsg();
102
103 private:
104
105 // a pointer to a function allocating an object
106 using DefaultCTor = std::shared_ptr<Object> (*)();
107 using CopyCTor = std::shared_ptr<Object> (*)(const std::shared_ptr<Object>&);
108
109 // convinence typedefs
110 using MapName = std::multimap<MBXMLUtils::FQN, DefaultCTor>;
111 using MapNameIt = typename MapName::iterator;
112 using MapType = std::map<std::type_index, CopyCTor>;
113 using MapTypeIt = typename MapType::iterator;
114
115 // private ctor
116 ObjectFactory() = default;
117
118 static void registerXMLNamePrivate(const MBXMLUtils::FQN &name, DefaultCTor alloc);
119
120 template<class CreateType>
121 static void registerTypePrivate(CopyCTor alloc) {
122 instance().registeredType.emplace(std::type_index(typeid(CreateType)), alloc);
123 }
124
125 // create an singleton instance of the object factory.
126 // only declaration here and defition and explicit instantation for all Object in objectfactory.cc (required for Windows)
127 static ObjectFactory& instance();
128
129 // a multimap of all registered types
130 MapName registeredName;
131 MapType registeredType;
132
133 // a wrapper to allocate an object of type CreateType by the default ctor: used by create(xercesc::DOMElement *)
134 template<class CreateType>
135 static std::shared_ptr<Object> defaultCTor() {
136 return std::shared_ptr<CreateType>(new CreateType, &deleter<CreateType>);
137 }
138
139 // a wrapper to allocate an object of type CreateType by the copy ctor: used by create(const std::shared_ptr<Object>&)
140 template<class CreateType>
141 static std::shared_ptr<Object> copyCTor(const std::shared_ptr<Object> &t) {
142 auto tCast=std::static_pointer_cast<CreateType>(t);
143 return std::shared_ptr<CreateType>(new CreateType(*tCast), &deleter<CreateType>);
144 }
145
146 // a wrapper to deallocate an object of type T: all dtors are protected but ObjectFactory is a friend of all classes
147 template<class T>
148 static void deleter(T *t) { delete t; }
149
150 static std::string errorMsg;
151 };
152
156 template<class CreateType>
157 class ObjectFactoryRegisterXMLNameHelper {
158
159 public:
160
162 ObjectFactoryRegisterXMLNameHelper(const MBXMLUtils::FQN &name) noexcept {
163 try {
164 ObjectFactory::registerXMLName<CreateType>(name);
165 }
166 catch(std::exception &ex) {
167 ObjectFactory::addErrorMsg(ex.what());
168 }
169 catch(...) {
170 ObjectFactory::addErrorMsg("Unknown error");
171 }
172 };
173
174 };
175
176 }
177
180 #define OPENMBV_OBJECTFACTORY_REGISTERXMLNAME(ThisType, name) \
181 static OpenMBV::ObjectFactoryRegisterXMLNameHelper<ThisType> BOOST_PP_CAT(objectFactoryRegistrationDummyVariable_, __LINE__)(name);
182
183
184 #endif
OpenMBV::ObjectFactoryRegisterXMLNameHelper::ObjectFactoryRegisterXMLNameHelper
ObjectFactoryRegisterXMLNameHelper(const MBXMLUtils::FQN &name) noexcept
Definition: objectfactory.h:162
OpenMBV::ObjectFactory::create
static std::shared_ptr< ContainerType > create(const xercesc::DOMElement *element)
Definition: objectfactory.h:55
MBXMLUtils::FQN
OpenMBV::ObjectFactory
Definition: objectfactory.h:38
MBXMLUtils::X
OpenMBV::ObjectFactory::registerXMLName
static void registerXMLName(const MBXMLUtils::FQN &name)
Definition: objectfactory.h:46
OpenMBV::ObjectFactory::create
static std::shared_ptr< ContainerType > create(const std::shared_ptr< ContainerType > &t)
Definition: objectfactory.h:87
OpenMBV::ObjectFactoryRegisterXMLNameHelper
Definition: objectfactory.h:157
OpenMBV::ObjectFactory::create
static std::shared_ptr< CreateType > create()
Definition: objectfactory.h:79