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