ESPResSo
Extensible Simulation Package for Research on Soft Matter Systems
Loading...
Searching...
No Matches
packed_variant.hpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2020-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#ifndef SCRIPT_INTERFACE_PACKED_VARIANT_HPP
20#define SCRIPT_INTERFACE_PACKED_VARIANT_HPP
21
22#include "Variant.hpp"
23
24#include <cstddef>
25#include <functional>
26#include <string>
27#include <unordered_map>
28#include <utility>
29#include <vector>
30
31namespace ScriptInterface {
32using ObjectId = std::size_t;
33
34/**
35 * @brief Id for object.
36 *
37 * This assigns every ObjectHandle a unique id.
38 */
40 // NOLINTNEXTLINE(bugprone-sizeof-expression)
41 static_assert(sizeof(const ObjectHandle *) <= sizeof(ObjectId));
42 // Use the pointer value as the unique identifier.
43 // This function is only called on the head node.
44 return reinterpret_cast<ObjectId>(p);
45}
46
47/**
48 * @brief Packed version of @ref Variant.
49 *
50 * When packing variants by @ref PackVisitor, objects of type
51 * @ref ObjectRef are packed as @ref ObjectId. Other than that,
52 * all other types allowed in @ref Variant must appear here.
53 */
54using PackedVariant = boost::make_recursive_variant<
55 None, bool, int, std::size_t, double, std::string, ObjectId,
57 Utils::Vector4d, std::vector<int>, std::vector<double>,
58 std::vector<boost::recursive_variant_>,
59 std::unordered_map<int, boost::recursive_variant_>,
60 std::unordered_map<std::string, boost::recursive_variant_>>::type;
61
62using PackedMap = std::vector<std::pair<std::string, PackedVariant>>;
63
64/**
65 * @brief Visitor that converts a Variant to a PackedVariant.
66 *
67 * While packing, keeps track of all the ObjectRef values that
68 * were encountered and stores them. This also keeps the
69 * referees alive if there are no other owners.
70 */
71struct PackVisitor : boost::static_visitor<PackedVariant> {
72private:
73 mutable std::unordered_map<ObjectId, ObjectRef> m_objects;
74
75public:
76 /** @brief Map of objects whose references were replaced by ids. */
77 auto const &objects() const { return m_objects; }
78
79 /* For the vector, we recurse into each element. */
80 auto operator()(const std::vector<Variant> &vec) const {
81 std::vector<PackedVariant> ret(vec.size());
82
83 boost::transform(vec, ret.begin(), [this](const Variant &v) {
84 return boost::apply_visitor(*this, v);
85 });
86
87 return ret;
88 }
89
90 /* For the map, we recurse into each element. */
91 template <typename K>
92 auto operator()(const std::unordered_map<K, Variant> &map) const {
93 std::unordered_map<K, PackedVariant> ret{};
94
95 for (auto const &it : map) {
96 ret.insert({it.first, boost::apply_visitor(*this, it.second)});
97 }
98
99 return ret;
100 }
101
102 /* For object references we store the object reference, and
103 * replace it by just an id. */
104 PackedVariant operator()(const ObjectRef &so_ptr) const {
105 auto const oid = object_id(so_ptr.get());
106 m_objects[oid] = so_ptr;
107
108 return oid;
109 }
110
111 /* Regular value are just verbatim copied into the result. */
112 template <class T> PackedVariant operator()(T &&val) const {
113 return std::forward<T>(val);
114 }
115};
116
117/**
118 * @brief Visitor that converts a PackedVariant to a Variant.
119 *
120 * ObjectId are replaced according to the provided object map.
121 */
122struct UnpackVisitor : boost::static_visitor<Variant> {
123 std::unordered_map<ObjectId, ObjectRef> const &objects;
124
125 explicit UnpackVisitor(std::unordered_map<ObjectId, ObjectRef> const &objects)
126 : objects(objects) {}
127
128 /* For the vector, we recurse into each element. */
129 auto operator()(const std::vector<PackedVariant> &vec) const {
130 std::vector<Variant> ret(vec.size());
131
132 boost::transform(vec, ret.begin(), [this](const PackedVariant &v) {
133 return boost::apply_visitor(*this, v);
134 });
135
136 return ret;
137 }
138
139 /* For the map, we recurse into each element. */
140 template <typename K>
141 auto operator()(const std::unordered_map<K, PackedVariant> &map) const {
142 std::unordered_map<K, Variant> ret{};
143
144 for (auto const &it : map) {
145 ret.insert({it.first, boost::apply_visitor(*this, it.second)});
146 }
147
148 return ret;
149 }
150
151 /* Regular value are just verbatim copied into the result. */
152 template <class T> Variant operator()(T &&val) const {
153 return std::forward<T>(val);
154 }
155
156 /* For object id's they are replaced by references according to the map. */
157 Variant operator()(const ObjectId &id) const { return objects.at(id); }
158};
159
160/**
161 * @brief Transform a Variant to a PackedVariant
162 *
163 * Applies @ref PackVisitor to a @ref Variant.
164 *
165 * @param v Input Variant
166 * @return Packed variant.
167 */
168inline PackedVariant pack(const Variant &v) {
169 return boost::apply_visitor(PackVisitor(), v);
170}
171
172/**
173 * @brief Unpack a PackedVariant.
174 *
175 * Applies @ref UnpackVisitor to a @ref Variant.
176 *
177 * @param v Packed Variant.
178 * @param objects Map of ids to reference.
179 * @return Transformed variant.
180 */
182 std::unordered_map<ObjectId, ObjectRef> const &objects) {
183 return boost::apply_visitor(UnpackVisitor(objects), v);
184}
185
186/**
187 * @brief Pack a VariantMap.
188 *
189 * Applies @ref pack to every value in the
190 * input map.
191 */
192inline PackedMap pack(const VariantMap &v) {
193 PackedMap ret(v.size());
194
195 boost::transform(v, ret.begin(), [](auto const &kv) {
196 return std::pair<std::string, PackedVariant>{kv.first, pack(kv.second)};
197 });
198
199 return ret;
200}
201
202/**
203 * @brief Unpack a PackedMap.
204 *
205 * Applies @ref unpack to every value in the
206 * input map.
207 */
208inline VariantMap
210 std::unordered_map<ObjectId, ObjectRef> const &objects) {
211 VariantMap ret;
212
213 boost::transform(
214 v, std::inserter(ret, ret.end()),
215 [&objects](auto const &kv) -> std::pair<std::string, Variant> {
216 return {kv.first, unpack(kv.second, objects)};
217 });
218
219 return ret;
220}
221} // namespace ScriptInterface
222
223#endif
Type to indicate no value in Variant.
Base class for interface handles.
PackedVariant pack(const Variant &v)
Transform a Variant to a PackedVariant.
std::shared_ptr< ObjectHandle > ObjectRef
Definition Variant.hpp:59
std::unordered_map< std::string, Variant > VariantMap
Definition Variant.hpp:82
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:80
std::vector< std::pair< std::string, PackedVariant > > PackedMap
Variant unpack(const PackedVariant &v, std::unordered_map< ObjectId, ObjectRef > const &objects)
Unpack a PackedVariant.
std::size_t ObjectId
boost::make_recursive_variant< None, bool, int, std::size_t, double, std::string, ObjectId, 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 PackedVariant
Packed version of Variant.
ObjectId object_id(const ObjectHandle *p)
Id for object.
Utils::Vector< bool, 3 > Vector3b
Definition Variant.hpp:54
VectorXd< 3 > Vector3d
Definition Vector.hpp:157
VectorXd< 2 > Vector2d
Definition Vector.hpp:156
VectorXi< 3 > Vector3i
Definition Vector.hpp:166
VectorXd< 4 > Vector4d
Definition Vector.hpp:158
Visitor that converts a Variant to a PackedVariant.
auto operator()(const std::unordered_map< K, Variant > &map) const
PackedVariant operator()(const ObjectRef &so_ptr) const
PackedVariant operator()(T &&val) const
auto operator()(const std::vector< Variant > &vec) const
auto const & objects() const
Map of objects whose references were replaced by ids.
Visitor that converts a PackedVariant to a Variant.
auto operator()(const std::vector< PackedVariant > &vec) const
UnpackVisitor(std::unordered_map< ObjectId, ObjectRef > const &objects)
Variant operator()(const ObjectId &id) const
Variant operator()(T &&val) const
auto operator()(const std::unordered_map< K, PackedVariant > &map) const
std::unordered_map< ObjectId, ObjectRef > const & objects