20 #include "palimpsest/exceptions/KeyError.h"
21 #include "palimpsest/exceptions/TypeError.h"
22 #include "palimpsest/mpack/eigen.h"
26 using exceptions::KeyError;
27 using exceptions::TypeError;
28 using mpack::mpack_node_matrix3d;
29 using mpack::mpack_node_quaterniond;
30 using mpack::mpack_node_vector2d;
31 using mpack::mpack_node_vector3d;
32 using mpack::mpack_node_vectorXd;
41 mpack_tree_init_data(&tree, data,
size);
42 mpack_tree_parse(&tree);
43 const auto status = mpack_tree_error(&tree);
44 if (status != mpack_ok) {
45 spdlog::error(
"MPack tree error: \"{}\", skipping Dictionary::update",
46 mpack_error_to_string(status));
49 update(mpack_tree_root(&tree));
50 mpack_tree_destroy(&tree);
54 if (mpack_node_type(node) == mpack_type_nil) {
64 if (mpack_node_type(node) != mpack_type_map) {
65 throw TypeError(__FILE__, __LINE__,
66 std::string(
"Expecting a map, not ") +
67 mpack_type_to_string(mpack_node_type(node)));
70 for (
size_t i = 0; i < mpack_node_map_count(node); ++i) {
71 const mpack_node_t key_node = mpack_node_map_key_at(node, i);
72 const mpack_node_t value_node = mpack_node_map_value_at(node, i);
73 const std::string key = {mpack_node_str(key_node),
74 mpack_node_strlen(key_node)};
75 auto it =
map_.find(key);
76 if (it ==
map_.end()) {
77 this->insert_at_key_(key, value_node);
80 it->second->update(value_node);
81 }
catch (
const TypeError &e) {
82 throw TypeError(e,
" ← at key \"" + key +
"\"");
88 void Dictionary::insert_at_key_(
const std::string &key,
89 const mpack_node_t &value) {
90 switch (mpack_node_type(value)) {
92 this->insert<bool>(key, mpack_node_bool(value));
95 this->insert<int>(key, mpack_node_int(value));
98 this->insert<unsigned>(key, mpack_node_uint(value));
100 case mpack_type_float:
101 this->insert<float>(key, mpack_node_float(value));
103 case mpack_type_double:
104 this->insert<double>(key, mpack_node_double(value));
107 this->insert<std::string>(
108 key, std::string{mpack_node_str(value), mpack_node_strlen(value)});
110 case mpack_type_array: {
111 size_t length = mpack_node_array_length(value);
113 throw TypeError(__FILE__, __LINE__,
114 std::string(
"Cannot deserialize an empty list "
115 "(precludes type inference) at key \"") +
118 mpack_node_t first_item = mpack_node_array_at(value, 0);
119 mpack_type_t array_type = mpack_node_type(first_item);
120 if (array_type == mpack_type_double) {
123 this->insert<Eigen::Vector2d>(key, mpack_node_vector2d(value));
126 this->insert<Eigen::Vector3d>(key, mpack_node_vector3d(value));
129 this->insert<Eigen::Quaterniond>(key,
130 mpack_node_quaterniond(value));
133 this->insert<Eigen::Matrix3d>(key, mpack_node_matrix3d(value));
136 this->insert<Eigen::VectorXd>(key, mpack_node_vectorXd(value));
139 }
else if (array_type == mpack_type_array) {
142 this->insert<std::vector<Eigen::VectorXd>>(key, length);
143 for (
unsigned index = 0; index < length; ++index) {
144 mpack_node_t sub_array = mpack_node_array_at(value, index);
145 mpack_type_t sub_type = mpack_node_type(sub_array);
146 if (sub_type != mpack_type_array) {
147 throw TypeError(__FILE__, __LINE__,
148 std::string(
"Encountered non-array item ") +
149 mpack_type_to_string(sub_type) +
150 " while parsing array of arrays at key \"" +
153 unsigned sub_length = mpack_node_array_length(sub_array);
154 Eigen::VectorXd &vector = new_vec_vec[index];
155 vector.resize(sub_length);
156 for (Eigen::Index j = 0; j < sub_length; ++j) {
157 vector(j) = mpack_node_double(mpack_node_array_at(sub_array, j));
161 throw TypeError(__FILE__, __LINE__,
162 std::string(
"Unsupported array of ") +
163 mpack_type_to_string(array_type) +
164 " elements encountered at key \"" + key +
"\"");
174 throw TypeError(__FILE__, __LINE__,
175 std::string(
"Cannot insert values of type ") +
176 mpack_type_to_string(mpack_node_type(value)));
181 std::vector<std::string> out;
182 out.reserve(
map_.size());
183 for (
const auto &key_child :
map_) {
184 out.push_back(key_child.first);
190 auto it = map_.find(key);
191 if (it == map_.end()) {
192 spdlog::error(
"[Dictionary::remove] No key to remove at \"{}\"", key);
200 throw TypeError(__FILE__, __LINE__,
201 "Cannot look up at key \"" + key +
202 "\" in non-dictionary object of type \"" +
203 value_.type_name() +
"\".");
205 auto [it, _] =
map_.try_emplace(key, std::make_unique<Dictionary>());
211 throw TypeError(__FILE__, __LINE__,
212 "Cannot lookup at key \"" + key +
213 "\" in non-dictionary object of type \"" +
214 value_.type_name() +
"\".");
216 const auto it =
map_.find(key);
217 if (it ==
map_.end()) {
218 throw KeyError(key, __FILE__, __LINE__,
219 "Since the dictionary is const it cannot be created.");
226 input.open(filename, std::ifstream::binary | std::ios::ate);
227 std::streamsize
size = input.tellg();
228 input.seekg(0, std::ios::beg);
229 std::vector<char> buffer(
size);
230 input.read(buffer.data(),
size);
236 std::vector<char> buffer;
239 std::ofstream output;
240 output.open(filename, std::ofstream::binary);
241 output.write(buffer.data(),
static_cast<int>(
size));
246 mpack::Writer writer(buffer);
248 return writer.finish();
251 void Dictionary::serialize_(mpack::Writer &writer)
const {
257 writer.start_map(
size);
258 for (
const auto &key_child :
map_) {
259 const auto &key = key_child.first;
260 const auto &child = *key_child.second;
262 child.serialize_(writer);
267 const Dictionary::Value &Dictionary::get_child_value_(
268 const std::string &key)
const {
269 const auto it =
map_.find(key);
270 if (it ==
map_.end()) {
271 throw KeyError(key, __FILE__, __LINE__,
"");
272 }
else if (!it->second->is_value()) {
273 throw TypeError(__FILE__, __LINE__,
274 "Child at key \"" + key +
"\" is not a value");
276 return it->second->value_;
283 dict.
value_.print(stream);
286 bool is_first =
true;
287 for (
const auto &key_child : dict.
map_) {
288 const auto &key = key_child.first;
289 const auto &child = key_child.second;
295 stream <<
"\"" << key <<
"\": " << *child;
Dictionary of values and sub-dictionaries.
Value value_
Internal value, used if we are a value.
std::unordered_map< std::string, std::unique_ptr< Dictionary > > map_
Key-value map, used if we are a map.
void read(const std::string &filename)
Update dictionary from a MessagePack binary file.
bool is_map() const noexcept
We are a (potentially empty) map if and only if the value is empty.
void update(const char *data, size_t size)
Update dictionary from raw MessagePack data.
unsigned size() const noexcept
Return the number of keys in the dictionary.
bool is_empty() const noexcept
We are empty if and only if we are a dictionary with no element.
void remove(const std::string &key) noexcept
Remove a key-value pair from the dictionary.
Dictionary & operator()(const std::string &key)
Return a reference to the dictionary at key, performing an insertion if such a key does not already e...
size_t serialize(std::vector< char > &buffer) const
Serialize to raw MessagePack data.
std::vector< std::string > keys() const noexcept
Return the list of keys of the dictionary.
void write(const std::string &filename) const
Write MessagePack serialization to a binary file.
void clear() noexcept
Remove all entries from the dictionary.
bool is_value() const noexcept
We are a value if and only if the internal value is non-empty.
std::ostream & operator<<(std::ostream &stream, const Dictionary &dict)