ESPResSo
Extensible Simulation Package for Research on Soft Matter Systems
Loading...
Searching...
No Matches
Factory.hpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2010-2022 The ESPResSo project
3 * Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010
4 * Max-Planck-Institute for Polymer Research, Theory Group
5 *
6 * This file is part of ESPResSo.
7 *
8 * ESPResSo is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * ESPResSo is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22#ifndef UTILS_FACTORY_HPP
23#define UTILS_FACTORY_HPP
24
25#include <cassert>
26#include <exception>
27#include <memory>
28#include <stdexcept>
29#include <string>
30#include <typeindex>
31#include <unordered_map>
32
33namespace Utils {
34
35/**
36 * @brief Factory template.
37 *
38 * Can be used to construct registered instances of classes derived
39 * from the base type (`T`) by name.
40 * One registry per base type (`T`). To get a new one,
41 * use new type ( `struct NewT : public T {};` ).
42 * To add a new type it has to be given a name an a function of type
43 * `%Factory<T>::%builder_type` to create an instance has to be provided.
44 * The class contains a default implementation for the creation
45 * function (`%Factory<T>::%builder<Derived>`) which just calls
46 * new to create an instance. A user provided function could
47 * be used to use a non-default constructor, or to allocate memory
48 * for the instance in a specific way, e.g. by placing all new instances
49 * in a vector.
50 *
51 * Example usage:
52 * @code{.cpp}
53 * struct A {};
54 * struct B : public A {};
55 * struct C : public A {
56 * C(int c) : m_c(c) {}
57 * int m_c;
58 * };
59 *
60 * // Register B as 'b' with default builder:
61 * Factory<A>::register_new<B>("b");
62 * // Register C as 'c' with user_defined builder:
63 * Factory<A>::register_new("c", []() -> typename Factory<A>::pointer_type {
64 * return new C(5); });
65 *
66 * // Create a B
67 * auto b = Factory<A>::make("b");
68 * assert(dynamic_cast<B *>(b.get()));
69 *
70 * // Create a C
71 * auto c = Factory<A>::make("c");
72 * assert(dynamic_cast<C *>(c.get())->m_c == 5);
73 * @endcode
74 */
75template <
76 /** The base type of the instances created by this factory */
77 class T>
78class Factory {
79public:
80 /** The returned pointer type */
81 using pointer_type = std::unique_ptr<T>;
82 /** Type of the constructor functions */
84
85public:
86 /**
87 * @brief Construct an instance by name.
88 */
89 pointer_type make(const std::string &name) const {
90 try {
91 auto builder = m_map.at(name);
92 return assert(builder), builder();
93 } catch (std::out_of_range const &) {
94 throw std::domain_error("Class '" + name + "' not found.");
95 }
96 }
97
98 /**
99 * @brief Check if the factory knows how to make `name`.
100 *
101 * @param name Given name to check.
102 * @return Whether we know how to make a `name`.
103 */
104 bool has_builder(const std::string &name) const {
105 return not(m_map.find(name) == m_map.end());
106 }
107
108 /**
109 * @brief Register a new type with the default construction function.
110 *
111 * @param name Given name for the type, has to be unique in this Factory<T>.
112 */
113 template <typename Derived> void register_new(const std::string &name) {
114 m_map[name] = []() { return pointer_type(new Derived()); };
115 m_type_map[typeid(Derived)] = name;
116 }
117
118 /**
119 * @brief Look up name for type.
120 *
121 * For an object whose type can be created by
122 * the factory this returns the name under which
123 * it is registered. This will consider the
124 * dynamic type of polymorphic objects, e.g. it
125 * will return the name of the most derived type.
126 *
127 * @param o Object whose type is to be considered.
128 * @throw std::out_of_range If the type is not registered.
129 *
130 * @return Name by which T can be made.
131 */
132 const std::string &type_name(T const &o) const {
133 return m_type_map.at(typeid(o));
134 }
135
136private:
137 /** Maps names to construction functions. */
138 std::unordered_map<std::string, builder_type> m_map;
139 /** Maps types to names */
140 std::unordered_map<std::type_index, std::string> m_type_map;
141};
142} /* namespace Utils */
143
144#endif
Factory template.
Definition Factory.hpp:78
void register_new(const std::string &name)
Register a new type with the default construction function.
Definition Factory.hpp:113
pointer_type make(const std::string &name) const
Construct an instance by name.
Definition Factory.hpp:89
const std::string & type_name(T const &o) const
Look up name for type.
Definition Factory.hpp:132
std::unique_ptr< T > pointer_type
The returned pointer type.
Definition Factory.hpp:81
pointer_type(*)() builder_type
Type of the constructor functions.
Definition Factory.hpp:83
bool has_builder(const std::string &name) const
Check if the factory knows how to make name.
Definition Factory.hpp:104