Loading [MathJax]/extensions/tex2jax.js
ESPResSo
Extensible Simulation Package for Research on Soft Matter Systems
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages Concepts
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