ESPResSo
Extensible Simulation Package for Research on Soft Matter Systems
Loading...
Searching...
No Matches
AutoParameters.hpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2010-2022 The ESPResSo project
3 *
4 * This file is part of ESPResSo.
5 *
6 * ESPResSo is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * ESPResSo is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#pragma once
21
25
26#include <algorithm>
27#include <span>
28#include <stdexcept>
29#include <string>
30#include <type_traits>
31#include <unordered_map>
32#include <utility>
33#include <vector>
34
35namespace ScriptInterface {
36
37/**
38 * @brief Bind parameters in the script interface.
39 *
40 * This class implements @c ScriptInterfaceBase, binding
41 * the parameters added by add_parameters or by the constructor.
42 * To use it, derive from this class and add parameters. For example,
43 * given a class A
44 * ~~~{.cpp}
45 * class A {
46 * public:
47 * int i() { return m_i; }
48 * private:
49 * int m_i;
50 * };
51 * ~~~
52 * that should have @c i exposed, this can be achieved by extending it
53 * like this:
54 * ~~~{.cpp}
55 * class A : public AutoParameters {
56 * public:
57 * A() : AutoParameters({"name_for_i", i}) {}
58 * int i() { return m_i; }
59 * private:
60 * int m_i;
61 * };
62 * ~~~
63 *
64 * If there is more complicated logic needed, specific setters and
65 * getters can be provided. E.g. given a class B like
66 * ~~~{.cpp}
67 * class B {
68 * public:
69 * void set_i(int);
70 * int get_i();
71 * private:
72 * int m_i;
73 * };
74 * ~~~
75 * we can use a lambdas to set and get the parameter like this:
76 * ~~~{.cpp}
77 * class B : public AutoParameters {
78 * public:
79 * B() : AutoParameters({"name_for_i",
80 * [this](Variant const& v) {set_i(get_value<int>(v));},
81 * [this]() {return get_i();}
82 * }) {}
83 * void set_i(int);
84 * int get_i();
85 * private:
86 * int m_i;
87 * };
88 * ~~~
89 * (this has to be captured in the lambdas to have access to the member
90 * functions of the class).
91 */
92template <typename Derived, typename Base = ObjectHandle>
93class AutoParameters : public Base {
94 static_assert(std::is_base_of_v<ObjectHandle, Base>);
95
96public:
97 /** @brief Exception thrown when accessing an unknown parameter */
98 struct UnknownParameter : public Exception {
99 explicit UnknownParameter(std::string const &name)
100 : Exception("Unknown parameter '" + name + "'.") {}
101 };
102
103 /** @brief Exception thrown when writing to a read-only parameter */
104 struct WriteError : public Exception {
105 explicit WriteError(std::string const &name)
106 : Exception("Parameter '" + name + "' is read-only.") {}
107 };
108
109protected:
110 // NOLINTNEXTLINE(bugprone-crtp-constructor-accessibility)
111 AutoParameters() = default;
112 // NOLINTNEXTLINE(bugprone-crtp-constructor-accessibility)
113 explicit AutoParameters(std::vector<AutoParameter> &&params) {
114 add_parameters(std::move(params));
115 }
116
117 void add_parameters(std::vector<AutoParameter> &&params) {
118 for (auto const &p : params) {
119 if (m_parameters.count(p.name)) {
120 m_parameters.erase(p.name);
121 if (auto const it = std::ranges::find(m_key_order, p.name);
122 it != m_key_order.end()) {
123 m_key_order.erase(it);
124 }
125 }
126 m_key_order.emplace_back(p.name);
127 m_parameters.emplace(p.name, std::move(p));
128 }
129 }
130
131 auto const &get_parameter_insertion_order() const { return m_key_order; }
132
133public:
134 /* ObjectHandle implementation */
135 std::span<const boost::string_ref> valid_parameters() const final {
136 static std::vector<boost::string_ref> valid_params;
137 valid_params.clear();
138
139 for (auto const &p : m_parameters) {
140 valid_params.emplace_back(p.first);
141 }
142
143 return valid_params;
144 }
145
146 Variant get_parameter(const std::string &name) const final {
147 try {
148 return m_parameters.at(name).get();
149 } catch (std::out_of_range const &) {
150 throw UnknownParameter{name};
151 }
152 }
153
154 void do_set_parameter(const std::string &name, const Variant &value) final {
155 try {
156 m_parameters.at(name).set(value);
157 } catch (AutoParameter::WriteError const &) {
158 throw WriteError{name};
159 } catch (std::out_of_range const &) {
160 throw UnknownParameter{name};
161 }
162 }
163
164 std::vector<std::pair<std::string, Variant>>
165 serialize_parameters() const final {
166 std::vector<std::pair<std::string, Variant>> parameter_pack{};
167 auto const params = this->get_parameters();
168 for (auto const &key : m_key_order) {
169 parameter_pack.emplace_back(key, params.at(key));
170 }
171 return parameter_pack;
172 }
173
174private:
175 /** @brief Data structure for the stored parameters. */
176 std::unordered_map<std::string, AutoParameter> m_parameters;
177 /** @brief Keep track of the insertion order of parameters. */
178 std::vector<std::string> m_key_order;
179};
180} // namespace ScriptInterface
Bind parameters in the script interface.
AutoParameters(std::vector< AutoParameter > &&params)
void do_set_parameter(const std::string &name, const Variant &value) final
std::span< const boost::string_ref > valid_parameters() const final
Variant get_parameter(const std::string &name) const final
std::vector< std::pair< std::string, Variant > > serialize_parameters() const final
void add_parameters(std::vector< AutoParameter > &&params)
auto const & get_parameter_insertion_order() const
VariantMap get_parameters() const
Get current parameters.
boost::string_ref name() const
boost::make_recursive_variant< None, bool, int, std::size_t, double, std::string, ObjectRef, Utils::Vector3b, Utils::Vector3i, Utils::Vector2d, Utils::Vector3d, Utils::Vector4d, std::vector< int >, std::vector< double >, std::vector< boost::recursive_variant_ >, std::unordered_map< int, boost::recursive_variant_ >, std::unordered_map< std::string, boost::recursive_variant_ > >::type Variant
Possible types for parameters.
Definition Variant.hpp:67
static SteepestDescentParameters params
Currently active steepest descent instance.
Exception thrown when accessing an unknown parameter.
Exception thrown when writing to a read-only parameter.