|
3 | 3 |
|
4 | 4 | #pragma once |
5 | 5 |
|
6 | | -#include "templates/keyedVector.h" |
7 | 6 | #include "templates/orderedMap.h" |
8 | | -#include "templates/resolvableKeyedVector.h" |
9 | | -#include <map> |
10 | 7 | #include <toml11/toml.hpp> |
11 | 8 | #include <vector> |
12 | 9 |
|
13 | 10 | // The type we use for the nodes of our serialisation tree |
14 | 11 | using SerialisedValue = toml::basic_value<toml::discard_comments, dissolve::OrderedMap, std::vector>; |
15 | 12 |
|
16 | | -// We need a way at compile time to detect all the types of smart |
17 | | -// pointers for things that can be serialised |
18 | | -template <typename T> |
19 | | -concept serialisablePointer = requires(T a, std::string tag, SerialisedValue target) { a->serialise(tag, target); }; |
20 | | - |
21 | | -// An interface for classes that can be serialised into an input file |
22 | | -class Serialisable |
| 13 | +namespace Serialisable |
23 | 14 | { |
24 | | - public: |
25 | | - Serialisable() = default; |
26 | | - virtual ~Serialisable() = default; |
27 | | - // Express as a serialisable value |
28 | | - virtual void serialise(std::string tag, SerialisedValue &target) const = 0; |
29 | | - // Read values from a serialisable value |
30 | | - virtual void deserialise(const SerialisedValue &node) {} |
31 | | - |
32 | | - /* Functions that hook into the toml11 library */ |
33 | | - // Wrapper for deserialise that toml11 will check for |
34 | | - void from_toml(const toml::value &node) { deserialise(node); } |
35 | | - // Wrapper for serialise that toml11 will check for |
36 | | - SerialisedValue into_toml() const |
37 | | - { |
38 | | - SerialisedValue result; |
39 | | - serialise("inner", result); |
40 | | - return result["inner"]; |
41 | | - } |
42 | | - |
43 | | - // Perform an action on a child node in a table if the node exists. |
44 | | - // This cuts out quite a bit of boilerplate. |
45 | | - template <typename Lambda> static bool optionalOn(const SerialisedValue &node, std::string name, Lambda action) |
46 | | - { |
47 | | - if (node.contains(name)) |
48 | | - { |
49 | | - auto child = toml::find(node, name); |
50 | | - if (!node.is_uninitialized()) |
51 | | - action(child); |
52 | | - return true; |
53 | | - } |
54 | | - |
55 | | - return false; |
56 | | - } |
57 | | - // Place the named value into the supplied object, but only if it exists |
58 | | - template <typename T, typename U> bool getIfPresent(const SerialisedValue &node, std::string name, U &destination) |
59 | | - { |
60 | | - if (!node.contains(name)) |
61 | | - return false; |
62 | | - destination = toml::find<T>(node, name); |
63 | | - return true; |
64 | | - } |
65 | | - // A helper function to add elements of a vector to a node under the named heading |
66 | | - template <serialisablePointer T> |
67 | | - static void fromVectorToTable(const std::vector<T> &vector, std::string name, SerialisedValue &node) |
68 | | - { |
69 | | - fromVectorToTable(vector, name, node, [](const auto &item) { return item->name().data(); }); |
70 | | - } |
71 | | - // A helper function to add elements of a vector to a node |
72 | | - template <typename T, typename Lambda> |
73 | | - static SerialisedValue fromVectorToTable(const std::vector<T> &vector, Lambda getName) |
74 | | - { |
75 | | - SerialisedValue group; |
76 | | - for (const auto &value : vector) |
77 | | - value->serialise(getName(value), group); |
78 | | - return group; |
79 | | - }; |
80 | | - // A helper function to add elements of a KeyedVector to a node |
81 | | - template <typename KeyClass, typename ValueClass, typename Lambda> |
82 | | - static SerialisedValue fromVectorToTable(const KeyedVector<KeyClass, ValueClass> &keyedVector, Lambda getName) |
83 | | - { |
84 | | - SerialisedValue group; |
85 | | - for (const auto &[key, value] : keyedVector) |
86 | | - group[std::string(getName(key))] = value; |
87 | | - return group; |
88 | | - }; |
89 | | - // A helper function to add elements of a ResolvableKeyedVector to a node |
90 | | - template <typename KeyClass, typename ValueClass> |
91 | | - static SerialisedValue fromVectorToTable(const ResolvableKeyedVector<KeyClass, ValueClass> &keyedVector) |
92 | | - { |
93 | | - SerialisedValue group; |
94 | | - for (const auto &[resolvable, value] : keyedVector) |
95 | | - group[std::string(resolvable.name())] = value; |
96 | | - return group; |
97 | | - } |
98 | | - template <typename KeyClass, typename ValueClass, typename Lambda> |
99 | | - static SerialisedValue fromVectorToTable(const ResolvableKeyedVector<KeyClass, ValueClass> &keyedVector, Lambda getInner) |
100 | | - { |
101 | | - SerialisedValue group; |
102 | | - for (const auto &[resolvable, value] : keyedVector) |
103 | | - group[std::string(resolvable.name())] = getInner(value); |
104 | | - return group; |
105 | | - } |
106 | | - // A helper function to add elements of a vector to a node under the named heading |
107 | | - template <typename T, typename Lambda> |
108 | | - static void fromVectorToTable(const std::vector<T> &vector, std::string name, SerialisedValue &node, Lambda getName) |
109 | | - { |
110 | | - if (vector.empty()) |
111 | | - return; |
112 | | - node[name] = fromVectorToTable(vector, getName); |
113 | | - }; |
114 | | - // A helper function to add elements of a vector to a node. This |
115 | | - // is more generic than fromVectorToTable and the later could be |
116 | | - // be implemented in terms of this function, but the two template |
117 | | - // types conflict with the resolution of other overloads. While |
118 | | - // this could be solved with C++20 Concepts, it's probably better |
119 | | - // to just remove the other overloads. That should be another |
120 | | - // issue before TOML is merged. |
121 | | - template <typename T, typename Lambda, typename Lambda2> |
122 | | - static SerialisedValue fromVectorToMap(const std::vector<T> &vector, Lambda getName, Lambda2 getValue) |
123 | | - { |
124 | | - SerialisedValue group; |
125 | | - for (auto &value : vector) |
126 | | - group[getName(value)] = getValue(value); |
127 | | - return group; |
128 | | - }; |
129 | | - // A helper function to add the elements of a vector to a node under a name |
130 | | - template <typename T> |
131 | | - static void fromVector(const std::vector<std::unique_ptr<T>> &vector, std::string name, SerialisedValue &node) |
132 | | - { |
133 | | - fromVector(vector, name, node, |
134 | | - [](const auto &item) |
135 | | - { |
136 | | - SerialisedValue outer; |
137 | | - item->serialise("inner", outer); |
138 | | - return outer["inner"]; |
139 | | - }); |
140 | | - } |
141 | | - // A helper function to add the elements of a vector to a node under a name |
142 | | - template <typename T> |
143 | | - static void fromVector(const std::vector<std::shared_ptr<T>> &vector, std::string name, SerialisedValue &node) |
144 | | - { |
145 | | - fromVector(vector, name, node, [](const auto &item) { return item->serialise(); }); |
146 | | - } |
147 | | - // A helper function to add the elements of a vector to a node under a name |
148 | | - template <typename T> static void fromVector(const std::vector<T> &vector, std::string name, SerialisedValue &node) |
149 | | - { |
150 | | - fromVector(vector, name, node, |
151 | | - [](const auto &item) |
152 | | - { |
153 | | - SerialisedValue outer; |
154 | | - item.serialise("inner", outer); |
155 | | - return outer["inner"]; |
156 | | - }); |
157 | | - } |
158 | | - // A helper function to add the elements of a vector to a node under a name |
159 | | - template <typename T, typename Lambda> |
160 | | - static void fromVector(const std::vector<T> &vector, std::string name, SerialisedValue &node, Lambda toSerial) |
161 | | - { |
162 | | - if (vector.empty()) |
163 | | - return; |
164 | | - node[name] = fromVector(vector, toSerial); |
165 | | - } |
166 | | - // A helper function to add the elements of a vector to a node under a name |
167 | | - template <typename T, typename Lambda> static SerialisedValue fromVector(const std::vector<T> &vector, Lambda toSerial) |
168 | | - { |
169 | | - SerialisedValue result = SerialisedValue::array_type{}; |
170 | | - std::transform(vector.begin(), vector.end(), std::back_inserter(result), toSerial); |
171 | | - return result; |
172 | | - } |
173 | | - // A helper function to add the elements of a ranged object to a node under a name |
174 | | - template <std::ranges::input_range Range, typename Lambda> |
175 | | - static SerialisedValue fromRange(const Range &range, Lambda toSerial) |
176 | | - { |
177 | | - SerialisedValue result = SerialisedValue::array_type{}; |
178 | | - std::ranges::transform(range, std::back_inserter(result), toSerial); |
179 | | - return result; |
180 | | - } |
181 | | - // A helper function to add the elements of a map to a node under a name |
182 | | - template <typename K, typename V> static void fromMap(const std::map<K, V> &map, std::string name, SerialisedValue &node) |
183 | | - { |
184 | | - SerialisedValue result; |
185 | | - for (auto &[key, value] : map) |
186 | | - if constexpr (serialisablePointer<V>) |
187 | | - value->serialise(std::format("{}", key), result); |
188 | | - else if constexpr (std::is_base_of_v<Serialisable, V>) |
189 | | - value.serialise(std::format("{}", key), result); |
190 | | - else |
191 | | - // We use the direct value (with casting) instead of |
192 | | - // value.serialise() to handle the case where the value |
193 | | - // is a raw type (e.g. int) |
194 | | - result[std::format("{}", key)] = value; |
195 | | - if (!map.empty()) |
196 | | - node[name] = result; |
197 | | - } |
198 | | - // A helper function to add the elements of a map to a node under a name |
199 | | - // Only add values that pass the test lambda |
200 | | - template <typename K, typename V, typename Lambda> |
201 | | - static void fromMap(const std::map<K, V> &map, std::string name, SerialisedValue &node, Lambda filter) |
202 | | - { |
203 | | - SerialisedValue result; |
204 | | - bool changed = false; |
205 | | - for (auto &[key, value] : map) |
206 | | - { |
207 | | - if (!filter(key, value)) |
208 | | - continue; |
209 | | - changed = true; |
210 | | - if constexpr (serialisablePointer<V>) |
211 | | - value->serialise(std::string(key), result); |
212 | | - else |
213 | | - // We use the direct value (with casting) instead of |
214 | | - // value.serialise() to handle the case where the value |
215 | | - // is a raw type (e.g. int) |
216 | | - result[std::string(key)] = value; |
217 | | - } |
218 | | - if (changed) |
219 | | - node[name] = result; |
220 | | - } |
221 | 15 |
|
222 | | - // Act over each value in a node table, if the key exists |
223 | | - template <typename Lambda> static void toMap(const SerialisedValue &node, Lambda action) |
224 | | - { |
225 | | - for (auto &[key, value] : node.as_table()) |
226 | | - action(key, value); |
227 | | - } |
| 16 | +void serialiseOnto(const int a, std::string tag, SerialisedValue &target); |
| 17 | +void serialiseOnto(const double a, std::string tag, SerialisedValue &target); |
| 18 | +void serialiseOnto(const std::string a, std::string tag, SerialisedValue &target); |
| 19 | +} // namespace Serialisable |
228 | 20 |
|
229 | | - // Act over each value in a node table, if the key exists |
230 | | - template <typename Lambda> static void toMap(const SerialisedValue &node, std::string key, Lambda action) |
231 | | - { |
232 | | - if (!node.contains(key)) |
233 | | - return; |
234 | | - |
235 | | - for (auto &[subKey, value] : toml::find<SerialisedValue::table_type>(node, key)) |
236 | | - action(subKey, value); |
237 | | - } |
238 | | - |
239 | | - // Act over each value in a node array |
240 | | - template <typename Lambda> static void toVector(const SerialisedValue &node, Lambda action) |
241 | | - { |
242 | | - for (auto &item : node.as_array()) |
243 | | - action(item); |
244 | | - } |
245 | | - |
246 | | - // Act over each value in a node table, if the key exists |
247 | | - template <typename Lambda> static void toVector(const SerialisedValue &node, std::string key, Lambda action) |
248 | | - { |
249 | | - if (!node.contains(key)) |
250 | | - return; |
| 21 | +namespace Deserialisable |
| 22 | +{ |
251 | 23 |
|
252 | | - toVector(node.at(key), action); |
253 | | - } |
254 | | -}; |
| 24 | +void deserialiseOnto(bool &a, const SerialisedValue &target); |
| 25 | +void deserialiseOnto(int &a, const SerialisedValue &target); |
| 26 | +void deserialiseOnto(long &a, const SerialisedValue &target); |
| 27 | +void deserialiseOnto(float &a, const SerialisedValue &target); |
| 28 | +void deserialiseOnto(double &a, const SerialisedValue &target); |
| 29 | +void deserialiseOnto(std::string &a, const SerialisedValue &target); |
| 30 | +} // namespace Deserialisable |
0 commit comments