Serialbox  2.2.0
Data serialization library and tools for C/C++, Python and Fortran
MetainfoMapImpl.cpp
Go to the documentation of this file.
1 //===-- serialbox/core/MetainfoMapImpl.cpp ------------------------------------------*- C++ -*-===//
2 //
3 // S E R I A L B O X
4 //
5 // This file is distributed under terms of BSD license.
6 // See LICENSE.txt for more information
7 //
8 //===------------------------------------------------------------------------------------------===//
9 //
13 //===------------------------------------------------------------------------------------------===//
14 
16 #include "serialbox/core/Array.h"
18 #include <iostream>
19 
20 namespace serialbox {
21 
22 namespace {
23 
24 struct InsertHelper {
25  // Capture environment
26  MetainfoMapImpl& map;
27  const std::string& key;
28  const json::json& node;
29 
30  // Read value from JSON node (and check if the types match) and insert it into the MetainfoMapImpl
31  // as
32  // type ´T´
33  template <class T, class CheckFunction>
34  void insertAs(CheckFunction&& checkFunction, const char* valueStr) {
35  if(!(node["value"].*checkFunction)())
36  throw Exception("sub-node '%s' not regconized as %s", key, valueStr);
37  T value = node["value"];
38  map.insert(key, value);
39  }
40 
41  // Read value from JSON node as Array of type ´T´ and insert as array of type ´T´ into the
42  // MetainfoMapImpl
43  template <class T>
44  void insertAsArrayOf() {
45  Array<T> array = node["value"];
46  map.insert(key, array);
47  }
48 };
49 
50 } // anonymous namespace
51 
52 std::vector<std::string> MetainfoMapImpl::keys() const {
53  std::vector<std::string> keys;
54  keys.reserve(map_.size());
55  for(auto it = map_.begin(), end = map_.end(); it != end; ++it)
56  keys.push_back(it->first);
57  return keys;
58 }
59 
60 std::vector<TypeID> MetainfoMapImpl::types() const {
61  std::vector<TypeID> types;
62  types.reserve(map_.size());
63  for(auto it = map_.begin(), end = map_.end(); it != end; ++it)
64  types.push_back(it->second.type());
65  return types;
66 }
67 
69  try {
70  return map_.at(key);
71  } catch(std::out_of_range&) {
72  throw Exception("no key '%s' exists", key);
73  }
74 }
75 
78  try {
79  return map_.at(key);
80  } catch(std::out_of_range&) {
81  throw Exception("no key '%s' exists", key);
82  }
83 }
84 
85 json::json MetainfoMapImpl::toJSON() const {
86  json::json jsonNode;
87 
88  if(map_.empty())
89  return jsonNode;
90 
91  for(auto it = map_.cbegin(), end = map_.cend(); it != end; ++it) {
92  const MetainfoValueImpl& value = it->second;
93  const std::string& key = it->first;
94 
95  jsonNode[key]["type_id"] = static_cast<int>(value.type());
96 
97  json::json valueNode;
98  const bool isArray = TypeUtil::isArray(value.type());
99 
100  switch(TypeUtil::getPrimitive(value.type())) {
101  case TypeID::Boolean:
102  if(isArray) {
103  for(const bool& v : value.as<Array<bool>>())
104  valueNode.push_back(v);
105  } else {
106  valueNode = value.as<bool>();
107  }
108  break;
109  case TypeID::Int32:
110  if(isArray) {
111  for(const int& v : value.as<Array<int>>())
112  valueNode.push_back(v);
113  } else {
114  valueNode = value.as<int>();
115  }
116  break;
117  case TypeID::Int64:
118  if(isArray) {
119  for(const std::int64_t& v : value.as<Array<std::int64_t>>())
120  valueNode.push_back(v);
121  } else {
122  valueNode = value.as<std::int64_t>();
123  }
124  break;
125  case TypeID::Float32:
126  if(isArray) {
127  for(const float& v : value.as<Array<float>>())
128  valueNode.push_back(v);
129  } else {
130  valueNode = value.as<float>();
131  }
132  break;
133  case TypeID::Float64:
134  if(isArray) {
135  for(const double& v : value.as<Array<double>>())
136  valueNode.push_back(v);
137  } else {
138  valueNode = value.as<double>();
139  }
140  break;
141  case TypeID::String:
142  if(isArray) {
143  for(const std::string& v : value.as<Array<std::string>>())
144  valueNode.push_back(v);
145  } else {
146  valueNode = value.as<std::string>();
147  }
148  break;
149  default:
150  serialbox_unreachable("Invalid TypeID");
151  }
152 
153  jsonNode[key]["value"] = valueNode;
154  }
155 
156  return jsonNode;
157 }
158 
159 void MetainfoMapImpl::fromJSON(const json::json& jsonNode) {
160  map_.clear();
161 
162  if(jsonNode.is_null() || jsonNode.empty())
163  return;
164 
165  for(auto it = jsonNode.begin(), end = jsonNode.end(); it != end; ++it) {
166 
167  if(!it->count("type_id"))
168  throw Exception("sub-node '%s' has no node 'type_id'", it.key());
169 
170  if(!it->count("value"))
171  throw Exception("sub-node '%s' has no node 'value'", it.key());
172 
173  const json::json& node = it.value();
174  const std::string& key = it.key();
175  const int typeAsInt = node["type_id"];
176  const TypeID type = static_cast<TypeID>(typeAsInt);
177  const bool isArray = TypeUtil::isArray(type);
178 
179  InsertHelper insertHelper{*this, key, node};
180 
181  switch(TypeUtil::getPrimitive(type)) {
182  case TypeID::Boolean:
183  if(isArray) {
184  insertHelper.insertAsArrayOf<bool>();
185  } else {
186  insertHelper.insertAs<bool>(&json::json::is_boolean, "boolean");
187  }
188  break;
189  case TypeID::Int32:
190  if(isArray) {
191  insertHelper.insertAsArrayOf<int>();
192  } else {
193  insertHelper.insertAs<int>(&json::json::is_number_integer, "integer");
194  }
195  break;
196  case TypeID::Int64:
197  if(isArray) {
198  insertHelper.insertAsArrayOf<std::int64_t>();
199  } else {
200  insertHelper.insertAs<std::int64_t>(&json::json::is_number_integer, "integer");
201  }
202  break;
203  case TypeID::Float32:
204  if(isArray) {
205  insertHelper.insertAsArrayOf<float>();
206  } else {
207  insertHelper.insertAs<float>(&json::json::is_number, "floating pointer number");
208  }
209  break;
210  case TypeID::Float64:
211  if(isArray) {
212  insertHelper.insertAsArrayOf<double>();
213  } else {
214  insertHelper.insertAs<double>(&json::json::is_number, "floating pointer number");
215  }
216  break;
217  case TypeID::String:
218  if(isArray) {
219  insertHelper.insertAsArrayOf<std::string>();
220  } else {
221  insertHelper.insertAs<std::string>(&json::json::is_string, "string");
222  }
223  break;
224  default:
225  serialbox_unreachable("Invalid TypeID");
226  }
227  }
228 }
229 
230 std::ostream& operator<<(std::ostream& stream, const MetainfoMapImpl& s) {
231  std::stringstream ss;
232  ss << "{";
233 
234  for(auto it = s.begin(), end = s.end(); it != end; ++it) {
235  ss << "\"" << it->first << "\": ";
236 
237  if(TypeUtil::isArray(it->second.type()))
238  ss << "[" << ArrayUtil::toString(it->second.as<Array<std::string>>()) << "]";
239  else
240  ss << it->second.as<std::string>();
241 
242  auto itCp = it;
243  if(++itCp != s.end())
244  ss << ", ";
245  }
246  ss << "}";
247  return (stream << ss.str());
248 }
249 
250 } // namespace serialbox
TypeID type() const noexcept
Get TypeID.
static std::string toString(const Array< T > &array)
Convert to string.
Definition: Array.h:38
map_type::mapped_type mapped_type
Type of the value (MetainfoMapImpl::Value)
Represent an immutable meta information value as a type-id and type-erased data.
json::json toJSON() const
Convert to JSON.
static bool isArray(TypeID id) noexcept
Check if type is an array of types.
Definition: Type.cpp:91
std::vector< T > Array
Array class used by serialbox to store meta-information.
Definition: Array.h:31
void fromJSON(const json::json &jsonNode)
Construct from JSON node.
std::vector< TypeID > types() const
Get vector of all available keys.
Namespace of the serialbox library.
Definition: Archive.h:25
TypeID
Type-id of types recognized by serialbox.
Definition: Type.h:55
map_type::key_type key_type
Type of the key (std::string)
mapped_type & at(const key_type &key)
Return a reference to mapped value given by key.
std::vector< std::string > keys() const
Get vector of strings of all available keys.
iterator begin() noexcept
Returns an iterator pointing to the first element in the MetainfoMapImpl.
Hash-map of meta-information of the form key = value pair or key = {value1, ..., valueN} ...
static TypeID getPrimitive(TypeID id) noexcept
Return the underlying primitve type.
Definition: Type.cpp:93
T as() const
Convert the value to type T
iterator end() noexcept
Returns an iterator pointing to the past-the-end element in the MetainfoMapImpl.
#define serialbox_unreachable(msg)
Marks that the current location is not supposed to be reachable.
Definition: Unreachable.h:41
std::ostream & operator<<(std::ostream &stream, const FieldID &f)
Convert FieldID to stream.
Definition: FieldID.cpp:26
Exception class which stores a human-readable error description.
Definition: Exception.h:30