ezconfig
Create C++ Objects from Yaml and Json
Loading...
Searching...
No Matches
factory.hpp
Go to the documentation of this file.
1// Copyright (c) 2023 Petter Nilsson. MIT License. https://github.com/pettni/ezconfig
2
8#pragma once
9
10#include <functional>
11#include <map>
12#include <memory>
13#include <sstream>
14
15#include "global.hpp"
16
17namespace ezconfig {
18
29template<bool many, typename Base, typename... Args>
31{
32public:
33 using OutputT = std::conditional_t<many, std::vector<std::unique_ptr<Base>>, std::unique_ptr<Base>>;
34 using GeneratorT = std::function<OutputT(Args...)>;
35
42 void add(const std::string & tag, GeneratorT factory)
43 {
44 if (m_tags.contains(tag)) { throw std::logic_error("Tag '" + tag + "' already present"); }
45 m_tags[tag] = std::move(factory);
46 }
47
51 OutputT create(const std::string & tag, auto &&... args)
52 {
53 if (auto it = m_tags.find(tag); it != m_tags.end()) {
54 return std::invoke(it->second, std::forward<decltype(args)>(args)...);
55 } else {
56 std::stringstream ss;
57 ss << "Could not find tag '" << tag << "'. ";
58 ss << "Available tags: [";
59 for (auto i = 0u; const auto & [tag_i, f] : m_tags) {
60 ss << "'" << tag_i << "'";
61 if (++i < m_tags.size()) { ss << ", "; }
62 }
63 ss << "]";
64 throw std::logic_error(ss.str());
65 }
66 }
67
68protected:
69 std::map<std::string, GeneratorT> m_tags;
70};
71
75template<typename Base, typename... Args>
76using Factory = GeneralFactory<false, Base, Args...>;
77
81template<typename Base, typename... Args>
82using ManyFactory = GeneralFactory<false, Base, Args...>;
83
85template<bool many, typename Base, typename... Args>
86struct has_factory : public std::false_type
87{};
88
90template<typename Base, typename... Args>
91concept Constructible = requires { has_factory<false, Base, Args...>::value == true; };
92
94template<typename Base, typename... Args>
95concept ManyConstructible = requires { has_factory<true, Base, Args...>::value == true; };
96
98#define EZ_GENERAL_FACTORY_DECLARE(many, Base, ...) \
99 EZ_GLOBAL_DECLARE(ezconfig::GeneralFactory<many, Base __VA_OPT__(, ) __VA_ARGS__>); \
100 template<> \
101 struct ezconfig::has_factory<many, Base __VA_OPT__(, ) __VA_ARGS__> : public std::true_type \
102 {}
103
105#define EZ_GENERAL_FACTORY_DEFINE(many, Base, ...) \
106 EZ_GLOBAL_DEFINE(ezconfig::GeneralFactory<many, Base __VA_OPT__(, ) __VA_ARGS__>)
107
109#define EZ_GENERAL_FACTORY_INSTANCE(many, Base, ...) \
110 EZ_GLOBAL_INSTANCE(ezconfig::GeneralFactory<many, Base __VA_OPT__(, ) __VA_ARGS__>)
111
113#define EZ_GENERAL_FACTORY_REGISTER(many, tag, creator, Base, ...) \
114 EZ_STATIC_INVOKE( \
115 &ezconfig::GeneralFactory<many, Base __VA_OPT__(, ) __VA_ARGS__>::add, \
116 EZ_GENERAL_FACTORY_INSTANCE(many, Base, __VA_ARGS__), \
117 tag, \
118 creator)
119
120#define EZ_FACTORY_DECLARE(Base, ...) EZ_GENERAL_FACTORY_DECLARE(false, Base, __VA_ARGS__)
121#define EZ_FACTORY_DEFINE(Base, ...) EZ_GENERAL_FACTORY_DEFINE(false, Base, __VA_ARGS__)
122#define EZ_FACTORY_INSTANCE(Base, ...) EZ_GENERAL_FACTORY_INSTANCE(false, Base, __VA_ARGS__)
123#define EZ_FACTORY_REGISTER(tag, creator, Base, ...) EZ_GENERAL_FACTORY_REGISTER(false, tag, creator, Base, __VA_ARGS__)
124
125} // namespace ezconfig
A Factory creates objects in a class hierarchy.
Definition factory.hpp:31
OutputT create(const std::string &tag, auto &&... args)
Create an object.
Definition factory.hpp:51
void add(const std::string &tag, GeneratorT factory)
Add a factory method to the factory.
Definition factory.hpp:42
Concept that identifies existing factories.
Definition factory.hpp:91
Concept that identifies existing factories.
Definition factory.hpp:95
Utilities to define and maintain a global instance.
Type trait that marks existing factories.
Definition factory.hpp:87