SST  11.0.0
StructuralSimulationToolkit
elementbuilder.h
1 // Copyright 2009-2021 NTESS. Under the terms
2 // of Contract DE-NA0003525 with NTESS, the U.S.
3 // Government retains certain rights in this software.
4 //
5 // Copyright (c) 2009-2021, NTESS
6 // All rights reserved.
7 //
8 // This file is part of the SST software package. For license
9 // information, see the LICENSE file in the top level directory of the
10 // distribution.
11 
12 #ifndef SST_CORE_FACTORY_INFO_H
13 #define SST_CORE_FACTORY_INFO_H
14 
15 #include "sst/core/eli/elibase.h"
16 #include <type_traits>
17 
18 namespace SST {
19 namespace ELI {
20 
21 template <class Base, class... Args>
22 struct Builder
23 {
24  typedef Base* (*createFxn)(Args...);
25 
26  virtual Base* create(Args... ctorArgs) = 0;
27 
28  template <class NewBase>
29  using ChangeBase = Builder<NewBase,Args...>;
30 };
31 
32 template <class Base, class... CtorArgs>
34 {
35  public:
36  using BaseBuilder = Builder<Base,CtorArgs...>;
37 
38  BuilderLibrary(const std::string& name) :
39  name_(name)
40  {
41  }
42 
43  BaseBuilder* getBuilder(const std::string& name) {
44  auto iter = factories_.find(name);
45  if (iter == factories_.end()){
46  return nullptr;
47  } else {
48  return iter->second;
49  }
50  }
51 
52  const std::map<std::string, BaseBuilder*>& getMap() const {
53  return factories_;
54  }
55 
56  void readdBuilder(const std::string& name, BaseBuilder* fact){
57  factories_[name] = fact;
58  }
59 
60  bool addBuilder(const std::string& elem, BaseBuilder* fact){
61  readdBuilder(elem, fact);
62  return addLoader(name_, elem, fact);
63  }
64 
65  template <class NewBase>
66  using ChangeBase = BuilderLibrary<NewBase,CtorArgs...>;
67 
68  private:
69  bool addLoader(const std::string& elemlib, const std::string& elem, BaseBuilder* fact);
70 
71  std::map<std::string, BaseBuilder*> factories_;
72 
73  std::string name_;
74 };
75 
76 template <class Base, class... CtorArgs>
78  public:
79  using Library=BuilderLibrary<Base,CtorArgs...>;
80  using BaseFactory=typename Library::BaseBuilder;
81  using Map=std::map<std::string,Library*>;
82 
83  static Library* getLibrary(const std::string& name){
84  if (!libraries){
85  libraries = new std::map<std::string,Library*>;
86  }
87  auto iter = libraries->find(name);
88  if (iter == libraries->end()){
89  auto* info = new Library(name);
90  (*libraries)[name] = info;
91  return info;
92  } else {
93  return iter->second;
94  }
95  }
96 
97  template <class NewBase>
98  using ChangeBase = BuilderLibraryDatabase<NewBase,CtorArgs...>;
99 
100  private:
101  // Database - needs to be a pointer for static init order
102  static Map* libraries;
103 };
104 
105 template <class Base, class... CtorArgs> typename BuilderLibraryDatabase<Base,CtorArgs...>::Map*
106  BuilderLibraryDatabase<Base,CtorArgs...>::libraries = nullptr;
107 
108 template <class Base, class Builder, class... CtorArgs>
109 struct BuilderLoader : public LibraryLoader {
110  BuilderLoader(const std::string& elemlib,
111  const std::string& elem,
112  Builder* builder) :
113  elemlib_(elemlib), elem_(elem), builder_(builder)
114  {
115  }
116 
117  void load() override {
119  ->readdBuilder(elem_,builder_);
120  }
121 
122  private:
123  std::string elemlib_;
124  std::string elem_;
125  Builder* builder_;
126 };
127 
128 template <class Base, class... CtorArgs>
129 bool BuilderLibrary<Base,CtorArgs...>::addLoader(const std::string& elemlib, const std::string& elem,
130  BaseBuilder *fact){
131  auto loader = new BuilderLoader<Base,BaseBuilder,CtorArgs...>(elemlib, elem, fact);
132  return ELI::LoadedLibraries::addLoader(elemlib, elem, loader);
133 }
134 
135 template <class Base, class T>
137  static bool isLoaded() {
138  return loaded;
139  }
140 
141  static const bool loaded;
142 };
143 
144 template <class Base, class T> const bool InstantiateBuilder<Base,T>::loaded
145  = Base::Ctor::template add<T>();
146 
147 template <class Base, class T, class Enable=void>
148 struct Allocator
149 {
150  template <class... Args>
151  T* operator()(Args&&... args){
152  return new T(std::forward<Args>(args)...);
153  }
154 };
155 
156 template <class Base, class T>
158 {
159  template <class... Args>
160  Base* operator()(Args&&... ctorArgs) {
161  if (!cached_){
162  cached_ = new T(std::forward<Args>(ctorArgs)...);
163  }
164  return cached_;
165  }
166 
167  static Base* cached_;
168 };
169 template <class Base, class T>
170  Base* CachedAllocator<Base,T>::cached_ = nullptr;
171 
172 template <class T, class Base, class... Args>
173 struct DerivedBuilder : public Builder<Base,Args...>
174 {
175  Base* create(Args... ctorArgs) override {
176  return Allocator<Base,T>()(std::forward<Args>(ctorArgs)...);
177  }
178 };
179 
180 
181 template <class T, class U>
182 struct is_tuple_constructible : public std::false_type {};
183 
184 template <class T, class... Args>
185 struct is_tuple_constructible<T, std::tuple<Args...>> :
186  public std::is_constructible<T, Args...>
187 {
188 };
189 
191  template <class T, class... Args>
192  static BuilderLibrary<T,Args...>* getLibrary(const std::string& name){
194  }
195 };
196 
197 template <class Base, class CtorTuple>
198 struct ElementsBuilder {};
199 
200 template <class Base, class... Args>
201 struct ElementsBuilder<Base, std::tuple<Args...>>
202 {
203  static BuilderLibrary<Base,Args...>* getLibrary(const std::string& name){
205  }
206 
207  template <class T> static Builder<Base,Args...>* makeBuilder(){
208  return new DerivedBuilder<T,Base,Args...>();
209  }
210 
211 };
212 
213 
214 /**
215  @class ExtendedCtor
216  Implements a constructor for a derived base as usually happens with subcomponents, e.g.
217  class U extends API extends Subcomponent. You can construct U as either an API*
218  or a Subcomponent* depending on usage.
219 */
220 template <class NewCtor, class OldCtor>
222 {
223  template <class T>
224  using is_constructible = typename NewCtor::template is_constructible<T>;
225 
226  /**
227  The derived Ctor can "block" the more abstract Ctor, meaning an object
228  should only be instantiated as the most derived type. enable_if here
229  checks if both the derived API and the parent API are still valid
230  */
231  template <class T>
232  static typename std::enable_if<OldCtor::template is_constructible<T>::value,bool>::type
233  add(){
234  //if abstract, force an allocation to generate meaningful errors
235  return NewCtor::template add<T>() && OldCtor::template add<T>();
236  }
237 
238  template <class T>
239  static typename std::enable_if<!OldCtor::template is_constructible<T>::value,bool>::type
240  add(){
241  //if abstract, force an allocation to generate meaningful errors
242  return NewCtor::template add<T>();
243  }
244 
245  template <class __NewCtor>
246  using ExtendCtor = ExtendedCtor<__NewCtor, ExtendedCtor<NewCtor,OldCtor>>;
247 
248  template <class NewBase>
249  using ChangeBase = typename NewCtor::template ChangeBase<NewBase>;
250 };
251 
252 template <class Base, class... Args>
254 {
255  template <class T>
256  using is_constructible = std::is_constructible<T,Args...>;
257 
258  template <class T> static bool add(){
259  //if abstract, force an allocation to generate meaningful errors
260  auto* fact = new DerivedBuilder<T,Base,Args...>;
261  return Base::addBuilder(T::ELI_getLibrary(),T::ELI_getName(),fact);
262  }
263 
264  template <class NewBase>
265  using ChangeBase = SingleCtor<NewBase, Args...>;
266 
267  template <class NewCtor>
268  using ExtendCtor = ExtendedCtor<NewCtor, SingleCtor<Base,Args...>>;
269 };
270 
271 template <class Base, class Ctor, class... Ctors>
272 struct CtorList : public CtorList<Base,Ctors...>
273 {
274  template <class T> //if T is constructible with Ctor arguments
275  using is_constructible = typename std::conditional<is_tuple_constructible<T,Ctor>::value,
276  std::true_type, //yes, constructible
277  typename CtorList<Base,Ctors...>::template is_constructible<T> //not constructible here but maybe later
278  >::type;
279 
280  template <class T, int NumValid=0, class U=T>
281  static typename std::enable_if<std::is_abstract<U>::value || is_tuple_constructible<U,Ctor>::value, bool>::type
282  add(){
283  //if abstract, force an allocation to generate meaningful errors
284  auto* fact = ElementsBuilder<Base,Ctor>::template makeBuilder<U>();
285  Base::addBuilder(T::ELI_getLibrary(),T::ELI_getName(),fact);
286  return CtorList<Base,Ctors...>::template add<T,NumValid+1>();
287  }
288 
289  template <class T, int NumValid=0, class U=T>
290  static typename std::enable_if<!std::is_abstract<U>::value && !is_tuple_constructible<U,Ctor>::value, bool>::type
291  add(){
292  return CtorList<Base,Ctors...>::template add<T,NumValid>();
293  }
294 
295  template <class NewBase>
296  using ChangeBase = CtorList<NewBase, Ctor, Ctors...>;
297 
298 };
299 
300 template <int NumValid>
302  static constexpr bool atLeastOneValidCtor = true;
303 };
304 
305 template <> class NoValidConstructorsForDerivedType<0> {};
306 
307 template <class Base> struct CtorList<Base,void>
308 {
309  template <class T>
310  using is_constructible = std::false_type;
311 
312  template <class T,int numValidCtors>
313  static bool add(){
315  }
316 };
317 
318 }
319 }
320 
321 #define ELI_CTOR(...) std::tuple<__VA_ARGS__>
322 #define ELI_DEFAULT_CTOR() std::tuple<>
323 
324 #define SST_ELI_CTORS_COMMON(...) \
325  using Ctor = ::SST::ELI::CtorList<__LocalEliBase,__VA_ARGS__,void>; \
326  template <class __TT, class... __CtorArgs> \
327  using DerivedBuilder = ::SST::ELI::DerivedBuilder<__LocalEliBase,__TT,__CtorArgs...>; \
328  template <class... __InArgs> static SST::ELI::BuilderLibrary<__LocalEliBase,__InArgs...>* \
329  getBuilderLibraryTemplate(const std::string& name){ \
330  return ::SST::ELI::BuilderDatabase::getLibrary<__LocalEliBase,__InArgs...>(name); \
331  } \
332  template <class __TT> static bool addDerivedBuilder(const std::string& lib, const std::string& elem){ \
333  return Ctor::template add<0,__TT>(lib,elem); \
334  } \
335 
336 #define SST_ELI_DECLARE_CTORS(...) \
337  SST_ELI_CTORS_COMMON(ELI_FORWARD_AS_ONE(__VA_ARGS__)) \
338  template <class... Args> static bool addBuilder(const std::string& elemlib, const std::string& elem, \
339  SST::ELI::Builder<__LocalEliBase,Args...>* builder){ \
340  return getBuilderLibraryTemplate<Args...>(elemlib)->addBuilder(elem, builder); \
341  }
342 
343 #define SST_ELI_DECLARE_CTORS_EXTERN(...) \
344  SST_ELI_CTORS_COMMON(ELI_FORWARD_AS_ONE(__VA_ARGS__))
345 
346 //VA_ARGS here
347 // 0) Base name
348 // 1) List of ctor args
349 #define SST_ELI_BUILDER_TYPEDEFS(...) \
350  using BaseBuilder = ::SST::ELI::Builder<__VA_ARGS__>; \
351  using BuilderLibrary = ::SST::ELI::BuilderLibrary<__VA_ARGS__>; \
352  using BuilderLibraryDatabase = ::SST::ELI::BuilderLibraryDatabase<__VA_ARGS__>; \
353  template <class __TT> using DerivedBuilder = ::SST::ELI::DerivedBuilder<__TT,__VA_ARGS__>;
354 
355 #define SST_ELI_BUILDER_FXNS() \
356  static BuilderLibrary* getBuilderLibrary(const std::string& name){ \
357  return BuilderLibraryDatabase::getLibrary(name); \
358  } \
359  static bool addBuilder(const std::string& elemlib, const std::string& elem, BaseBuilder* builder){ \
360  return getBuilderLibrary(elemlib)->addBuilder(elem,builder); \
361  }
362 
363 //I can make some extra using typedefs because I have only a single ctor
364 #define SST_ELI_DECLARE_CTOR(...) \
365  using Ctor = ::SST::ELI::SingleCtor<__LocalEliBase,__VA_ARGS__>; \
366  SST_ELI_BUILDER_TYPEDEFS(__LocalEliBase,__VA_ARGS__) \
367  SST_ELI_BUILDER_FXNS()
368 
369 #define SST_ELI_BUILDER_FXNS_EXTERN() \
370  static BuilderLibrary* getBuilderLibrary(const std::string& name); \
371  static bool addBuilder(const std::string& elemlib, const std::string& elem, BaseBuilder* builder);
372 
373 #define SST_ELI_DECLARE_CTOR_EXTERN(...) \
374  using Ctor = ::SST::ELI::SingleCtor<__LocalEliBase,__VA_ARGS__>; \
375  SST_ELI_BUILDER_TYPEDEFS(__LocalEliBase,__VA_ARGS__); \
376  SST_ELI_BUILDER_FXNS_EXTERN()
377 
378 #define SST_ELI_DEFINE_CTOR_EXTERN(base) \
379  bool base::addBuilder(const std::string& elemlib, const std::string& elem, BaseBuilder* builder){ \
380  return getBuilderLibrary(elemlib)->addBuilder(elem,builder); \
381  } \
382  base::BuilderLibrary* base::getBuilderLibrary(const std::string& elemlib){ \
383  return BuilderLibraryDatabase::getLibrary(elemlib); \
384  }
385 
386 //I can make some extra using typedefs because I have only a single ctor
387 #define SST_ELI_DECLARE_DEFAULT_CTOR() \
388  using Ctor = ::SST::ELI::SingleCtor<__LocalEliBase>; \
389  SST_ELI_BUILDER_TYPEDEFS(__LocalEliBase) \
390  SST_ELI_BUILDER_FXNS()
391 
392 #define SST_ELI_DECLARE_DEFAULT_CTOR_EXTERN() \
393  SST_ELI_DEFAULT_CTOR_COMMON() \
394  SST_ELI_BUILDER_FXNS_EXTERN()
395 
396 #define SST_ELI_EXTEND_CTOR() \
397  using Ctor = ::SST::ELI::ExtendedCtor<LocalCtor, __ParentEliBase::Ctor>;
398 
399 #define SST_ELI_SAME_BASE_CTOR() \
400  using LocalCtor = __ParentEliBase::Ctor::ChangeBase<__LocalEliBase>; \
401  SST_ELI_EXTEND_CTOR() \
402  using BaseBuilder = typename __ParentEliBase::BaseBuilder::template ChangeBase<__LocalEliBase>; \
403  using BuilderLibrary = __ParentEliBase::BuilderLibrary::ChangeBase<__LocalEliBase>; \
404  using BuilderLibraryDatabase = __ParentEliBase::BuilderLibraryDatabase::ChangeBase<__LocalEliBase>; \
405  SST_ELI_BUILDER_FXNS()
406 
407 #define SST_ELI_NEW_BASE_CTOR(...) \
408  using LocalCtor = ::SST::ELI::SingleCtor<__LocalEliBase,__VA_ARGS__>; \
409  SST_ELI_EXTEND_CTOR() \
410  SST_ELI_BUILDER_TYPEDEFS(__LocalEliBase, __VA_ARGS__) \
411  SST_ELI_BUILDER_FXNS()
412 
413 #define SST_ELI_DEFAULT_BASE_CTOR() \
414  using LocalCtor = ::SST::ELI::SingleCtor<__LocalEliBase>; \
415  SST_ELI_EXTEND_CTOR() \
416  SST_ELI_BUILDER_TYPEDEFS(__LocalEliBase) \
417  SST_ELI_BUILDER_FXNS()
418 
419 
420 #endif
421 
Definition: elementbuilder.h:182
Definition: elementbuilder.h:198
Definition: elementbuilder.h:109
Definition: elementbuilder.h:272
Definition: elementbuilder.h:33
Definition: elementbuilder.h:173
Definition: elementbuilder.h:190
Definition: elementbuilder.h:301
Definition: elibase.h:107
Definition: elementbuilder.h:148
Definition: elementbuilder.h:136
static std::enable_if< OldCtor::template is_constructible< T >::value, bool >::type add()
The derived Ctor can &quot;block&quot; the more abstract Ctor, meaning an object should only be instantiated as...
Definition: elementbuilder.h:233
Definition: elementbuilder.h:77
Definition: elementbuilder.h:253
Definition: elementbuilder.h:22
Implements a constructor for a derived base as usually happens with subcomponents, e.g.
Definition: elementbuilder.h:221
Definition: elementbuilder.h:157
static bool addLoader(const std::string &lib, const std::string &name, LibraryLoader *loader)
Definition: elibase.cc:29