GMP 0.3.0
Generative Metaprogramming library for C++
Loading...
Searching...
No Matches
object_factory.hpp
Go to the documentation of this file.
1// ___ __ __ ___
2// / __| \/ | _ \ GMP(Generative Metaprogramming)
3// | (_ | |\/| | _/ version 0.3.0
4// \___|_| |_|_| https://github.com/lkimuk/gmp
5//
6// SPDX-FileCopyrightText: 2020-2026 Miles Li <https://www.cppmore.com/>
7// SPDX-License-Identifier: MIT
8//
9// This file is part of the GMP (Generative Metaprogramming) library.
10// Full project source: https://github.com/lkimuk/gmp
11//
12// This object factory implementation was originally written by the same author
13// for the okdp library in 2020 and later adapted for GMP:
14// https://github.com/lkimuk/okdp
15
16#ifndef GMP_DP_OBJECT_FACTORY_HPP_
17#define GMP_DP_OBJECT_FACTORY_HPP_
18
19#include <functional>
20#include <map>
21#include <memory>
22#include <stdexcept>
23#include <string>
24
25#include <gmp/dp/singleton.hpp>
26#include <gmp/macro/macro.hpp>
27
28#if GMP_CPP_AT_LEAST(20)
29#include <concepts>
30#endif // C++20 or later
31
32namespace gmp {
33
56template <typename AbstractProduct, typename... ConstructorArgs>
57class object_factory : public singleton<object_factory<AbstractProduct, ConstructorArgs...>> {
59
60public:
70 template <typename T>
71#if GMP_CPP_AT_LEAST(20)
72 requires std::derived_from<T, AbstractProduct>
73#endif
75 // Registers T into object factory
81 register_type(const std::string& key) {
82 this_type::instance().map_.emplace(key,
83 [](const ConstructorArgs&... args) { return new T(args...); });
84 }
85 };
86
95 void unregister_type(const std::string& key) {
96 this_type::instance().map_.erase(key);
97 }
98
115 AbstractProduct* create(const std::string& key, const ConstructorArgs&... args) {
116 if (this_type::instance().map_.find(key) == this_type::instance().map_.end())
117 throw std::invalid_argument("Unknown object type passed to factory!");
118 return this_type::instance().map_[key](args...);
119 }
120
130 std::shared_ptr<AbstractProduct> create_shared(
131 const std::string& key, const ConstructorArgs&... args) {
132 return std::shared_ptr<AbstractProduct>(create(key, args...));
133 }
134
144 std::unique_ptr<AbstractProduct> create_unique(
145 const std::string& key, const ConstructorArgs&... args) {
146 return std::unique_ptr<AbstractProduct>(create(key, args...));
147 }
148
149private:
150 std::map<std::string, std::function<AbstractProduct*(const ConstructorArgs&... args)>> map_;
151};
152
153#define _GMP_GET_CONCRETE_PRODUCT_CLASS(ConcreteProduct) GMP_IF_THEN_ELSE(GMP_IS_TUPLE(ConcreteProduct), GMP_GET_TUPLE, ConcreteProduct)GMP_IF(GMP_IS_TUPLE(ConcreteProduct), (1, ConcreteProduct))
154#define _GMP_GET_CONSTRUCTOR_TYPES(ConstructorArgs) GMP_IF_THEN_ELSE(GMP_IS_TUPLE(ConstructorArgs), GMP_REMOVE_PARENS, ConstructorArgs)GMP_IF(GMP_IS_TUPLE(ConstructorArgs), (ConstructorArgs))
155#define GMP_FACTORY_REGISTER_WITH_ARGS(AbstractProduct, ConstructorArgs, ConcreteProduct) \
156 static gmp::object_factory<AbstractProduct, _GMP_GET_CONSTRUCTOR_TYPES(ConstructorArgs)>::register_type<_GMP_GET_CONCRETE_PRODUCT_CLASS(ConcreteProduct)> \
157 GMP_CONCATS(gmp_reg_, AbstractProduct, _, _GMP_GET_CONCRETE_PRODUCT_CLASS(ConcreteProduct))(GMP_IF_THEN_ELSE(GMP_IS_TUPLE(ConcreteProduct), GMP_STRINGIFY(GMP_GET_TUPLE(0, ConcreteProduct)), GMP_STRINGIFY(ConcreteProduct)));
158#define GMP_FACTORY_REGISTER_NO_ARGS(AbstractProduct, ConcreteProduct) \
159 static gmp::object_factory<AbstractProduct>::register_type<_GMP_GET_CONCRETE_PRODUCT_CLASS(ConcreteProduct)> \
160 GMP_CONCATS(gmp_reg_, AbstractProduct, _, _GMP_GET_CONCRETE_PRODUCT_CLASS(ConcreteProduct))(GMP_IF_THEN_ELSE(GMP_IS_TUPLE(ConcreteProduct), GMP_STRINGIFY(GMP_GET_TUPLE(0, ConcreteProduct)), GMP_STRINGIFY(ConcreteProduct)));
161
184#define GMP_FACTORY_REGISTER(AbstractProduct, ConstructorArgs, ...) \
185 _GMP_FACTORY_REGISTER_IMPL(AbstractProduct, ConstructorArgs, __VA_ARGS__)
186#define _GMP_FACTORY_REGISTER_IMPL(AbstractProduct, ConstructorArgs, ...) \
187 _GMP_FACTORY_REGISTER_IMPL_COMPAT_MSVC(AbstractProduct, ConstructorArgs, GMP_IS_EMPTY(__VA_ARGS__), GMP_TUPLE_EMPTY(ConstructorArgs), __VA_ARGS__)
188#define _GMP_FACTORY_REGISTER_IMPL_COMPAT_MSVC(AbstractProduct, ConstructorArgs, _0, _1, ...) \
189 GMP_EXPAND( GMP_OVERLOAD_INVOKE(_GMP_FACTORY_REGISTER_WHEN, _0, _1)(AbstractProduct, ConstructorArgs, __VA_ARGS__) )
190#define _GMP_FACTORY_REGISTER_WHEN_1(...)
191#define _GMP_FACTORY_REGISTER_WHEN_0_1(AbstractProduct, ConstructorArgs, ConcreteProduct, ...) \
192 GMP_FACTORY_REGISTER_NO_ARGS(AbstractProduct, ConcreteProduct) \
193 GMP_IF(GMP_BOOL(GMP_SIZE_OF_VAARGS(__VA_ARGS__)), _GMP_FACTORY_REGISTER_WHEN_1_CONTINUE) GMP_IF(GMP_BOOL(GMP_SIZE_OF_VAARGS(__VA_ARGS__)), (AbstractProduct, ConstructorArgs, __VA_ARGS__))
194#define _GMP_FACTORY_REGISTER_WHEN_0_0(AbstractProduct, ConstructorArgs, ConcreteProduct, ...) \
195 GMP_FACTORY_REGISTER_WITH_ARGS(AbstractProduct, ConstructorArgs, ConcreteProduct) \
196 GMP_IF(GMP_BOOL(GMP_SIZE_OF_VAARGS(__VA_ARGS__)), _GMP_FACTORY_REGISTER_WHEN_1_CONTINUE) GMP_IF(GMP_BOOL(GMP_SIZE_OF_VAARGS(__VA_ARGS__)), (AbstractProduct, ConstructorArgs, __VA_ARGS__))
197#define _GMP_FACTORY_REGISTER_WHEN_1_CONTINUE(AbstractProduct, ConstructorArgs, ...) \
198 GMP_DEFER(_GMP_FACTORY_REGISTER_INDIRECT)()(AbstractProduct, ConstructorArgs, __VA_ARGS__)
199#define _GMP_FACTORY_REGISTER_INDIRECT() _GMP_FACTORY_REGISTER_IMPL
200
203} // namespace gmp
204
205#endif // GMP_DP_OBJECT_FACTORY_HPP_
A singleton-backed runtime factory that creates products by string key.
void unregister_type(const std::string &key)
Remove a previously registered product key from the factory.
AbstractProduct * create(const std::string &key, const ConstructorArgs &... args)
Create a concrete product with raw new semantics.
std::unique_ptr< AbstractProduct > create_unique(const std::string &key, const ConstructorArgs &... args)
Create a concrete product and return it as std::unique_ptr.
std::shared_ptr< AbstractProduct > create_shared(const std::string &key, const ConstructorArgs &... args)
Create a concrete product and return it as std::shared_ptr.
CRTP-based singleton helper with optional dead-reference recovery.
Definition singleton.hpp:54
consteval auto enum_values()
Get all enumerator values of an enumeration type at compile-time.
Definition meta.hpp:155
Definition lock.hpp:21
Register a concrete product type under a string key.
register_type(const std::string &key)
Register T with the specified lookup key.