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