Reaktoro  v2.9.2
A unified framework for modeling chemically reactive systems
Data.hpp
1 // Reaktoro is a unified framework for modeling chemically reactive systems.
2 //
3 // Copyright (C) 2014-2020 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/Types.hpp>
22 #include <Reaktoro/Common/TraitsUtils.hpp>
23 #include <Reaktoro/Core/Param.hpp>
24 
25 namespace Reaktoro {
26 
27 // ================================================================================================
28 // TODO: Implement Data::with(key_name, key_value) to find entries in lists. Example:
29 //
30 // params["Species"].with("Name", "H2O(aq)")["StandardThermoModel"]["HKF"]["Gf"]
31 //
32 // Implement also Data::get(string_path_to_parameter) such as:
33 //
34 // params.get("Species:Name=H2O(aq):StandardThermoModel:HKF:Gf")
35 // params.get("Species:Formula=Ca++:StandardThermoModel:HKF:Gf")
36 // ================================================================================================
37 
40 class Data
41 {
42 public:
44  Data();
45 
47  static auto parse(Chars text) -> Data;
48 
50  static auto parse(String const& text) -> Data;
51 
53  static auto parse(std::istream& text) -> Data;
54 
56  static auto parseYaml(Chars text) -> Data;
57 
59  static auto parseYaml(String const& text) -> Data;
60 
62  static auto parseYaml(std::istream& text) -> Data;
63 
65  static auto parseJson(Chars text) -> Data;
66 
68  static auto parseJson(String const& text) -> Data;
69 
71  static auto parseJson(std::istream& text) -> Data;
72 
75  static auto load(String const& path) -> Data;
76 
78  static auto loadYaml(String const& path) -> Data;
79 
81  static auto loadJson(String const& path) -> Data;
82 
84  auto asBoolean() const -> bool;
85 
87  auto asString() const -> String const&;
88 
90  auto asInteger() const -> int;
91 
93  auto asFloat() const -> double;
94 
96  auto asParam() const -> Param const&;
97 
99  auto asDict() const -> Dict<String, Data> const&;
100 
102  auto asList() const -> Vec<Data> const&;
103 
105  auto asNull() const -> Nullptr;
106 
108  auto isBoolean() const -> bool;
109 
111  auto isString() const -> bool;
112 
114  auto isInteger() const -> bool;
115 
117  auto isFloat() const -> bool;
118 
120  auto isParam() const -> bool;
121 
123  auto isDict() const -> bool;
124 
126  auto isList() const -> bool;
127 
129  auto isNull() const -> bool;
130 
133  auto operator[](String const& key) const -> Data const&;
134 
137  auto operator[](Index const& index) const -> Data const&;
138 
143  auto operator[](String const& key) -> Data&;
144 
148  auto operator[](Index const& index) -> Data&;
149 
152  auto at(String const& key) const -> Data const&;
153 
156  auto at(Index const& index) const -> Data const&;
157 
159  struct Opt
160  {
161  Data const*const ptrdata = nullptr;
162 
164  template<typename T>
165  auto to(T& obj) const -> void
166  {
167  if(ptrdata)
168  obj = ptrdata->as<T>();
169  }
170  };
171 
174  auto optional(String const& key) const -> Opt;
175 
178  auto required(String const& key) const -> Data const&;
179 
181  auto with(String const& attribute, String const& value) const -> Data const&;
182 
184  auto add(Data data) -> void;
185 
187  auto add(String const& key, Data data) -> void;
188 
190  auto update(Data const& data) -> void;
191 
193  auto reset() -> void;
194 
196  auto exists(String const& key) const -> bool;
197 
199  auto dump() const -> String;
200 
202  auto dumpYaml() const -> String;
203 
205  auto dumpJson() const -> String;
206 
208  auto save(String const& filepath) const -> void;
209 
211  auto saveYaml(String const& filepath) const -> void;
212 
214  auto saveJson(String const& filepath) const -> void;
215 
217  auto repr() const -> String;
218 
220  template<typename T>
221  struct Encode
222  {
224  static auto eval(Data& data, T const& obj) -> void
225  {
226  errorif(true, "Cannot convert an object of type ", typeid(T).name(), " to Data because Encode::eval was not defined for it.");
227  }
228  };
229 
231  template<typename T>
232  struct Decode
233  {
235  static auto eval(Data const& data, T& obj) -> void
236  {
237  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.");
238  }
239  };
240 
242  template<typename T>
243  auto operator=(T const& obj) -> Data&
244  {
245  assign(obj);
246  return *this;
247  }
248 
250  template<typename T>
251  explicit operator T() const
252  {
253  return as<T>();
254  }
255 
257  template<typename T>
258  Data(T const& obj)
259  {
260  assign(obj);
261  }
262 
264  template<typename T>
265  auto assign(T const& obj) -> void
266  {
267  if constexpr(isOneOf<T, bool, int, double, String, Param, Vec<Data>, Dict<String, Data>, Nullptr>)
268  tree = obj;
269  else if constexpr(Reaktoro::isInteger<T>)
270  tree = static_cast<int>(obj);
271  else if constexpr(isFloatingPoint<T> || isSame<T, real>)
272  tree = static_cast<double>(obj);
273  else {
274  reset();
275  Encode<T>::eval(*this, obj);
276  }
277  }
278 
280  auto assign(char obj) -> void
281  {
282  tree = String(1, obj);
283  }
284 
286  auto assign(Chars obj) -> void
287  {
288  tree = String(obj);
289  }
290 
292  template<typename T>
293  auto as() const -> T
294  {
295  if constexpr(isOneOf<T, bool, String, Param, Vec<Data>, Dict<String, Data>>) {
296  const bool convertable = std::any_cast<T>(&tree);
297  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.");
298  return std::any_cast<T const&>(tree);
299  }
300  if constexpr(Reaktoro::isInteger<T>)
301  return asInteger();
302  if constexpr(isFloatingPoint<T> || isSame<T, real>)
303  return asFloat();
304  else {
305  T obj;
306  Decode<T>::eval(*this, obj);
307  return obj;
308  }
309  }
310 
312  template<typename T>
313  auto to(T& obj) const -> void
314  {
315  obj = as<T>();
316  }
317 
318 private:
319  Any tree;
320 };
321 
322 #define REAKTORO_DATA_ENCODE_DECLARE(T, ...) \
323  \
324  template<__VA_ARGS__> struct Data::Encode<T> { static auto eval(Data& data, const T& obj) -> void; };
325 
326 #define REAKTORO_DATA_ENCODE_DEFINE(T, ...) \
327  \
328  auto Data::Encode<T>::eval(Data& data, const T& obj) -> void
329 
330 #define REAKTORO_DATA_DECODE_DECLARE(T, ...) \
331  \
332  template<__VA_ARGS__> struct Data::Decode<T> { static auto eval(const Data& data, T& obj) -> void; };
333 
334 #define REAKTORO_DATA_DECODE_DEFINE(T, ...) \
335  \
336  auto Data::Decode<T>::eval(const Data& data, T& obj) -> void
337 
338 #define REAKTORO_COMMA ,
339 
340 REAKTORO_DATA_ENCODE_DECLARE(Vec<T>, typename T);
341 REAKTORO_DATA_DECODE_DECLARE(Vec<T>, typename T);
342 
343 REAKTORO_DATA_ENCODE_DECLARE(Array<T REAKTORO_COMMA N>, typename T, std::size_t N);
344 REAKTORO_DATA_DECODE_DECLARE(Array<T REAKTORO_COMMA N>, typename T, std::size_t N);
345 
346 REAKTORO_DATA_ENCODE_DECLARE(Pair<A REAKTORO_COMMA B>, typename A, typename B);
347 REAKTORO_DATA_DECODE_DECLARE(Pair<A REAKTORO_COMMA B>, typename A, typename B);
348 
349 REAKTORO_DATA_ENCODE_DECLARE(Map<K REAKTORO_COMMA T>, typename K, typename T);
350 REAKTORO_DATA_DECODE_DECLARE(Map<K REAKTORO_COMMA T>, typename K, typename T);
351 
352 REAKTORO_DATA_ENCODE_DECLARE(Dict<K REAKTORO_COMMA T>, typename K, typename T);
353 REAKTORO_DATA_DECODE_DECLARE(Dict<K REAKTORO_COMMA T>, typename K, typename T);
354 
355 template<typename T>
356 REAKTORO_DATA_ENCODE_DEFINE(Vec<T>, typename T)
357 {
358  for(auto const& x : obj)
359  data.add(x);
360 }
361 
362 template<typename T>
363 REAKTORO_DATA_DECODE_DEFINE(Vec<T>, typename T)
364 {
365  for(auto const& x : data.asList())
366  obj.push_back(x.as<T>());
367 }
368 
369 template<typename T, std::size_t N>
370 REAKTORO_DATA_ENCODE_DEFINE(Array<T REAKTORO_COMMA N>, typename T, std::size_t N)
371 {
372  for(auto const& x : obj)
373  data.add(x);
374 }
375 
376 template<typename T, std::size_t N>
377 REAKTORO_DATA_DECODE_DEFINE(Array<T REAKTORO_COMMA N>, typename T, std::size_t N)
378 {
379  auto i = 0;
380  for(auto const& x : data.asList())
381  obj[i++] = x.as<T>();
382 }
383 
384 template<typename A, typename B>
385 REAKTORO_DATA_ENCODE_DEFINE(Pair<A REAKTORO_COMMA B>, typename A, typename B)
386 {
387  data.add(obj.first);
388  data.add(obj.second);
389 }
390 
391 template<typename A, typename B>
392 REAKTORO_DATA_DECODE_DEFINE(Pair<A REAKTORO_COMMA B>, typename A, typename B)
393 {
394  auto const& l = data.asList();
395  errorif(l.size() != 2, "Converting from Data to Pair requires the Data object to be a list with two entries.");
396  obj.first = l[0].as<A>();
397  obj.second = l[1].as<B>();
398 }
399 
400 template<typename K, typename T>
401 REAKTORO_DATA_ENCODE_DEFINE(Map<K REAKTORO_COMMA T>, typename K, typename T)
402 {
403  for(auto const& [k, v] : obj)
404  data.add(k, v);
405 }
406 
407 template<typename K, typename T>
408 REAKTORO_DATA_DECODE_DEFINE(Map<K REAKTORO_COMMA T>, typename K, typename T)
409 {
410  for(auto const& [k, v] : data.asDict())
411  obj[k] = v.template as<T>();
412 }
413 
414 template<typename K, typename T>
415 REAKTORO_DATA_ENCODE_DEFINE(Dict<K REAKTORO_COMMA T>, typename K, typename T)
416 {
417  for(auto const& [k, v] : obj)
418  data.add(k, v);
419 }
420 
421 template<typename K, typename T>
422 REAKTORO_DATA_DECODE_DEFINE(Dict<K REAKTORO_COMMA T>, typename K, typename T)
423 {
424  for(auto const& [k, v] : data.asDict())
425  obj[k] = v.template as<T>();
426 }
427 
428 } // namespace Reaktoro
The class used to store and retrieve data for assemblying chemical systems.
Definition: Data.hpp:41
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:265
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:243
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:280
auto asParam() const -> Param const &
Return this Data object as a Param object.
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:313
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:293
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.
auto isParam() const -> bool
Return true if this Data object is a Param object.
Data(T const &obj)
Construct a Data object from one of type T.
Definition: Data.hpp:258
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:286
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.
A type used to represent the value of a parameter and its lower and upper bounds.
Definition: Param.hpp:32
#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:28
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:36
Used to allow conversion of Data objects to objects with custom types.
Definition: Data.hpp:233
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:235
Used to allow conversion of objects with custom types to Data objects.
Definition: Data.hpp:222
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:224
Used as the return type of method Data::optional.
Definition: Data.hpp:160
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:165