Reaktoro  v2.11.0
A unified framework for modeling chemically reactive systems
Data.hpp
1 // Reaktoro is a unified framework for modeling chemically reactive systems.
2 //
3 // Copyright © 2014-2024 Allan Leal
4 //
5 // This library is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU Lesser General Public
7 // License as published by the Free Software Foundation; either
8 // version 2.1 of the License, or (at your option) any later version.
9 //
10 // This library is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // Lesser General Public License for more details.
14 //
15 // You should have received a copy of the GNU Lesser General Public License
16 // along with this library. If not, see <http://www.gnu.org/licenses/>.
17 
18 #pragma once
19 
20 // Reaktoro includes
21 #include <Reaktoro/Common/Exception.hpp>
22 #include <Reaktoro/Common/TraitsUtils.hpp>
23 #include <Reaktoro/Common/Types.hpp>
24 
25 namespace Reaktoro {
26 
29 class Data
30 {
31 public:
33  Data();
34 
36  static auto parse(Chars text) -> Data;
37 
39  static auto parse(String const& text) -> Data;
40 
42  static auto parse(std::istream& text) -> Data;
43 
45  static auto parseYaml(Chars text) -> Data;
46 
48  static auto parseYaml(String const& text) -> Data;
49 
51  static auto parseYaml(std::istream& text) -> Data;
52 
54  static auto parseJson(Chars text) -> Data;
55 
57  static auto parseJson(String const& text) -> Data;
58 
60  static auto parseJson(std::istream& text) -> Data;
61 
64  static auto load(String const& path) -> Data;
65 
67  static auto loadYaml(String const& path) -> Data;
68 
70  static auto loadJson(String const& path) -> Data;
71 
73  auto asBoolean() const -> bool;
74 
76  auto asString() const -> String const&;
77 
79  auto asInteger() const -> int;
80 
82  auto asFloat() const -> double;
83 
85  auto asDict() const -> Dict<String, Data> const&;
86 
88  auto asList() const -> Vec<Data> const&;
89 
91  auto asNull() const -> Nullptr;
92 
94  auto isBoolean() const -> bool;
95 
97  auto isString() const -> bool;
98 
100  auto isInteger() const -> bool;
101 
103  auto isFloat() const -> bool;
104 
106  auto isDict() const -> bool;
107 
109  auto isList() const -> bool;
110 
112  auto isNull() const -> bool;
113 
116  auto operator[](String const& key) const -> Data const&;
117 
120  auto operator[](Index const& index) const -> Data const&;
121 
126  auto operator[](String const& key) -> Data&;
127 
131  auto operator[](Index const& index) -> Data&;
132 
135  auto at(String const& key) const -> Data const&;
136 
139  auto at(Index const& index) const -> Data const&;
140 
142  struct Opt
143  {
144  Data const*const ptrdata = nullptr;
145 
147  template<typename T>
148  auto to(T& obj) const -> void
149  {
150  if(ptrdata)
151  obj = ptrdata->as<T>();
152  }
153  };
154 
157  auto optional(String const& key) const -> Opt;
158 
161  auto required(String const& key) const -> Data const&;
162 
164  auto with(String const& attribute, String const& value) const -> Data const&;
165 
167  auto add(Data data) -> void;
168 
170  auto add(String const& key, Data data) -> void;
171 
173  auto update(Data const& data) -> void;
174 
176  auto reset() -> void;
177 
179  auto exists(String const& key) const -> bool;
180 
182  auto dump() const -> String;
183 
185  auto dumpYaml() const -> String;
186 
188  auto dumpJson() const -> String;
189 
191  auto save(String const& filepath) const -> void;
192 
194  auto saveYaml(String const& filepath) const -> void;
195 
197  auto saveJson(String const& filepath) const -> void;
198 
200  auto repr() const -> String;
201 
203  template<typename T>
204  struct Encode
205  {
207  static auto eval(Data& data, T const& obj) -> void
208  {
209  errorif(true, "Cannot convert an object of type ", typeid(T).name(), " to Data because Encode::eval was not defined for it.");
210  }
211  };
212 
214  template<typename T>
215  struct Decode
216  {
218  static auto eval(Data const& data, T& obj) -> void
219  {
220  errorif(true, "Cannot convert an object a Data object to an object of type ", typeid(T).name(), " because Decode::eval was not defined for it.");
221  }
222  };
223 
225  template<typename T>
226  auto operator=(T const& obj) -> Data&
227  {
228  assign(obj);
229  return *this;
230  }
231 
233  template<typename T>
234  explicit operator T() const
235  {
236  return as<T>();
237  }
238 
240  template<typename T>
241  Data(T const& obj)
242  {
243  assign(obj);
244  }
245 
247  template<typename T>
248  auto assign(T const& obj) -> void
249  {
250  if constexpr(isOneOf<T, bool, int, double, String, Vec<Data>, Dict<String, Data>, Nullptr>)
251  tree = obj;
252  else if constexpr(Reaktoro::isInteger<T>)
253  tree = static_cast<int>(obj);
254  else if constexpr(isFloatingPoint<T> || isSame<T, real>)
255  tree = static_cast<double>(obj);
256  else {
257  reset();
258  Encode<T>::eval(*this, obj);
259  }
260  }
261 
263  auto assign(char obj) -> void
264  {
265  tree = String(1, obj);
266  }
267 
269  auto assign(Chars obj) -> void
270  {
271  tree = String(obj);
272  }
273 
275  template<typename T>
276  auto as() const -> T
277  {
278  if constexpr(isOneOf<T, bool, String, Vec<Data>, Dict<String, Data>>) {
279  const bool convertable = std::any_cast<T>(&tree);
280  errorif(!convertable, "Could not convert from Data object to an object of type ", typeid(T).name(), " because this is not the type of the data stored nor it is convertible to that type.");
281  return std::any_cast<T const&>(tree);
282  }
283  if constexpr(Reaktoro::isInteger<T>)
284  return asInteger();
285  if constexpr(isFloatingPoint<T> || isSame<T, real>)
286  return asFloat();
287  else {
288  T obj;
289  Decode<T>::eval(*this, obj);
290  return obj;
291  }
292  }
293 
295  template<typename T>
296  auto to(T& obj) const -> void
297  {
298  obj = as<T>();
299  }
300 
301 private:
302  Any tree;
303 };
304 
305 #define REAKTORO_DATA_ENCODE_DECLARE(T, ...) \
306  \
307  template<__VA_ARGS__> struct Data::Encode<T> { static auto eval(Data& data, const T& obj) -> void; };
308 
309 #define REAKTORO_DATA_ENCODE_DEFINE(T, ...) \
310  \
311  auto Data::Encode<T>::eval(Data& data, const T& obj) -> void
312 
313 #define REAKTORO_DATA_DECODE_DECLARE(T, ...) \
314  \
315  template<__VA_ARGS__> struct Data::Decode<T> { static auto eval(const Data& data, T& obj) -> void; };
316 
317 #define REAKTORO_DATA_DECODE_DEFINE(T, ...) \
318  \
319  auto Data::Decode<T>::eval(const Data& data, T& obj) -> void
320 
321 #define REAKTORO_COMMA ,
322 
323 REAKTORO_DATA_ENCODE_DECLARE(Vec<T>, typename T);
324 REAKTORO_DATA_DECODE_DECLARE(Vec<T>, typename T);
325 
326 REAKTORO_DATA_ENCODE_DECLARE(Array<T REAKTORO_COMMA N>, typename T, std::size_t N);
327 REAKTORO_DATA_DECODE_DECLARE(Array<T REAKTORO_COMMA N>, typename T, std::size_t N);
328 
329 REAKTORO_DATA_ENCODE_DECLARE(Pair<A REAKTORO_COMMA B>, typename A, typename B);
330 REAKTORO_DATA_DECODE_DECLARE(Pair<A REAKTORO_COMMA B>, typename A, typename B);
331 
332 REAKTORO_DATA_ENCODE_DECLARE(Map<K REAKTORO_COMMA T>, typename K, typename T);
333 REAKTORO_DATA_DECODE_DECLARE(Map<K REAKTORO_COMMA T>, typename K, typename T);
334 
335 REAKTORO_DATA_ENCODE_DECLARE(Dict<K REAKTORO_COMMA T>, typename K, typename T);
336 REAKTORO_DATA_DECODE_DECLARE(Dict<K REAKTORO_COMMA T>, typename K, typename T);
337 
338 template<typename T>
339 REAKTORO_DATA_ENCODE_DEFINE(Vec<T>, typename T)
340 {
341  for(auto const& x : obj)
342  data.add(x);
343 }
344 
345 template<typename T>
346 REAKTORO_DATA_DECODE_DEFINE(Vec<T>, typename T)
347 {
348  for(auto const& x : data.asList())
349  obj.push_back(x.as<T>());
350 }
351 
352 template<typename T, std::size_t N>
353 REAKTORO_DATA_ENCODE_DEFINE(Array<T REAKTORO_COMMA N>, typename T, std::size_t N)
354 {
355  for(auto const& x : obj)
356  data.add(x);
357 }
358 
359 template<typename T, std::size_t N>
360 REAKTORO_DATA_DECODE_DEFINE(Array<T REAKTORO_COMMA N>, typename T, std::size_t N)
361 {
362  auto i = 0;
363  for(auto const& x : data.asList())
364  obj[i++] = x.as<T>();
365 }
366 
367 template<typename A, typename B>
368 REAKTORO_DATA_ENCODE_DEFINE(Pair<A REAKTORO_COMMA B>, typename A, typename B)
369 {
370  data.add(obj.first);
371  data.add(obj.second);
372 }
373 
374 template<typename A, typename B>
375 REAKTORO_DATA_DECODE_DEFINE(Pair<A REAKTORO_COMMA B>, typename A, typename B)
376 {
377  auto const& l = data.asList();
378  errorif(l.size() != 2, "Converting from Data to Pair requires the Data object to be a list with two entries.");
379  obj.first = l[0].as<A>();
380  obj.second = l[1].as<B>();
381 }
382 
383 template<typename K, typename T>
384 REAKTORO_DATA_ENCODE_DEFINE(Map<K REAKTORO_COMMA T>, typename K, typename T)
385 {
386  for(auto const& [k, v] : obj)
387  data.add(k, v);
388 }
389 
390 template<typename K, typename T>
391 REAKTORO_DATA_DECODE_DEFINE(Map<K REAKTORO_COMMA T>, typename K, typename T)
392 {
393  for(auto const& [k, v] : data.asDict())
394  obj[k] = v.template as<T>();
395 }
396 
397 template<typename K, typename T>
398 REAKTORO_DATA_ENCODE_DEFINE(Dict<K REAKTORO_COMMA T>, typename K, typename T)
399 {
400  for(auto const& [k, v] : obj)
401  data.add(k, v);
402 }
403 
404 template<typename K, typename T>
405 REAKTORO_DATA_DECODE_DEFINE(Dict<K REAKTORO_COMMA T>, typename K, typename T)
406 {
407  for(auto const& [k, v] : data.asDict())
408  obj[k] = v.template as<T>();
409 }
410 
411 } // namespace Reaktoro
The class used to store and retrieve data for assemblying chemical systems.
Definition: Data.hpp:30
auto asList() const -> Vec< Data > const &
Return this Data object as a list object.
auto isNull() const -> bool
Return true if this Data object is a null value.
auto assign(T const &obj) -> void
Assign an object of type T to this Data object.
Definition: Data.hpp:248
auto dump() const -> String
Return a YAML formatted string representing the state of this Data object.
auto dumpYaml() const -> String
Return a YAML formatted string representing the state of this Data object.
auto add(String const &key, Data data) -> void
Add a Data object with given key to this Data object, which becomes a dictionary if not already.
auto saveYaml(String const &filepath) const -> void
Save the state of this Data object into a YAML formatted file.
auto dumpJson() const -> String
Return a JSON formatted string representing the state of this Data object.
auto repr() const -> String
Return a YAML formatted string representing the state of this Data object.
auto operator=(T const &obj) -> Data &
Assign an object of type T to this Data object.
Definition: Data.hpp:226
auto asFloat() const -> double
Return this Data object as a float number.
Data()
Construct a default Data instance with null value.
auto assign(char obj) -> void
Assign a char to this Data object.
Definition: Data.hpp:263
auto asString() const -> String const &
Return this Data object as a string.
static auto parseJson(String const &text) -> Data
Return a Data object by parsing a JSON formatted string.
static auto parseYaml(Chars text) -> Data
Return a Data object by parsing an YAML formatted string.
static auto parseJson(Chars text) -> Data
Return a Data object by parsing a JSON formatted string.
auto exists(String const &key) const -> bool
Return true if a child Data object exists with given key, presuming this Data object is a dictionary.
static auto parseYaml(String const &text) -> Data
Return a Data object by parsing an YAML formatted string.
auto to(T &obj) const -> void
Decode this Data object into an object of type T.
Definition: Data.hpp:296
auto isFloat() const -> bool
Return true if this Data object is a float number.
auto isString() const -> bool
Return true if this Data object is a string.
static auto parseJson(std::istream &text) -> Data
Return a Data object by parsing a JSON formatted string.
auto optional(String const &key) const -> Opt
Return an optional child Data object with given key, presuming this Data object is a dictionary.
static auto load(String const &path) -> Data
Return a Data object by parsing either an YAML or JSON formatted file at a given path.
auto isBoolean() const -> bool
Return true if this Data object is a boolean value.
auto at(String const &key) const -> Data const &
Return the child Data object with given key, presuming this Data object is a dictionary.
auto reset() -> void
Reset this Data object to a null state, deleting its current stored data.
static auto parse(Chars text) -> Data
Return a Data object by parsing an YAML formatted string.
auto isDict() const -> bool
Return true if this Data object is a dictionary object.
static auto loadJson(String const &path) -> Data
Return a Data object by parsing a JSON formatted file at a given path.
auto saveJson(String const &filepath) const -> void
Save the state of this Data object into a JSON formatted file.
auto update(Data const &data) -> void
Update this Data object with data given in another, with key-value pairs being either added or overwr...
auto as() const -> T
Convert this Data object into an object of type T.
Definition: Data.hpp:276
auto asNull() const -> Nullptr
Return this Data object as a nullptr value.
static auto parse(String const &text) -> Data
Return a Data object by parsing an YAML formatted string.
auto add(Data data) -> void
Add a Data object to this Data object, which becomes a list if not already.
Data(T const &obj)
Construct a Data object from one of type T.
Definition: Data.hpp:241
auto required(String const &key) const -> Data const &
Return a required to exist child Data object with given key, presuming this Data object is a dictiona...
auto asDict() const -> Dict< String, Data > const &
Return this Data object as a dictionary object.
auto assign(Chars obj) -> void
Assign a raw string to this Data object.
Definition: Data.hpp:269
auto isInteger() const -> bool
Return true if this Data object is an integer number.
auto with(String const &attribute, String const &value) const -> Data const &
Return the child Data object whose attribute has a given value, presuming this Data object is a list.
auto asBoolean() const -> bool
Return this Data object as a boolean value.
static auto parse(std::istream &text) -> Data
Return a Data object by parsing an YAML formatted string.
auto isList() const -> bool
Return true if this Data object is a list object.
auto save(String const &filepath) const -> void
Save the state of this Data object into a YAML formatted file.
static auto parseYaml(std::istream &text) -> Data
Return a Data object by parsing an YAML formatted string.
auto asInteger() const -> int
Return this Data object as an integer number.
static auto loadYaml(String const &path) -> Data
Return a Data object by parsing an YAML formatted file at a given path.
#define errorif(condition,...)
Define a macro to raise a runtime exception if condition is true.
Definition: Exception.hpp:140
The namespace containing all components of the Reaktoro library.
Definition: Algorithms.hpp:29
std::nullptr_t Nullptr
Convenient alias for std::nullptr_t.
Definition: Types.hpp:128
std::vector< T > Vec
Convenient alias for std::vector<T>.
Definition: Types.hpp:66
std::string String
Convenient alias for std::string.
Definition: Types.hpp:52
std::size_t Index
Define a type that represents an index.
Definition: Index.hpp:26
const char * Chars
Convenient alias for const char*.
Definition: Types.hpp:49
std::any Any
Convenient alias for std::any.
Definition: Types.hpp:125
auto index(const Container &c, const T &x) -> std::size_t
Return the index of item x in container c or the number of items if not found.
Definition: Algorithms.hpp:37
Used to allow conversion of Data objects to objects with custom types.
Definition: Data.hpp:216
static auto eval(Data const &data, T &obj) -> void
Evaluate the conversion of a Data object to an object with custom type.
Definition: Data.hpp:218
Used to allow conversion of objects with custom types to Data objects.
Definition: Data.hpp:205
static auto eval(Data &data, T const &obj) -> void
Evaluate the conversion of an object with custom type to a Data object.
Definition: Data.hpp:207
Used as the return type of method Data::optional.
Definition: Data.hpp:143
auto to(T &obj) const -> void
Decode this Opt object into an object of type T, or leave it unchanged if no data is available.
Definition: Data.hpp:148