15 #include <spdlog/spdlog.h>
22 #include <unordered_map>
26 #include "palimpsest/exceptions/TypeError.h"
27 #include "palimpsest/internal/Allocator.h"
28 #include "palimpsest/internal/is_valid_hash.h"
29 #include "palimpsest/internal/type_name.h"
30 #include "palimpsest/json/write.h"
31 #include "palimpsest/mpack/Writer.h"
32 #include "palimpsest/mpack/read.h"
33 #include "palimpsest/mpack/write.h"
37 using exceptions::TypeError;
108 Value(
const Value &) =
delete;
111 Value &
operator=(
const Value &) =
delete;
114 Value(Value &&) =
default;
127 template <
typename T>
130 reinterpret_cast<uint8_t *
>(internal::Allocator<T>().allocate(1)));
138 void deserialize(mpack_node_t node) { deserialize_(*
this, node); }
144 void print(std::ostream &stream)
const { print_(*
this, stream); }
150 void serialize(mpack::Writer &writer)
const {
151 serialize_(*
this, writer.mpack_writer());
158 template <
typename T,
typename... ArgsT>
160 this->type_name = &internal::type_name<T>;
161 this->same = &internal::is_valid_hash<T, ArgsT...>;
162 deserialize_ = [](Value &
self, mpack_node_t node) {
163 T *cast_buffer =
reinterpret_cast<T *
>(
self.buffer.get());
164 mpack::read<T>(node, *cast_buffer);
166 destroy_ = [](Value &
self) {
167 T *p =
reinterpret_cast<T *
>(
self.buffer.release());
169 internal::Allocator<T>().deallocate(p, 1);
171 print_ = [](
const Value &
self, std::ostream &stream) {
172 const T *cast_buffer =
reinterpret_cast<const T *
>(
self.buffer.get());
173 json::write<T>(stream, *cast_buffer);
175 serialize_ = [](
const Value &
self, mpack_writer_t *writer) {
176 const T *cast_buffer =
reinterpret_cast<const T *
>(
self.buffer.get());
177 mpack::write<T>(writer, *cast_buffer);
179 return *(
reinterpret_cast<T *
>(this->buffer.get()));
188 template <
typename T>
189 T &get_reference()
const {
190 if (!this->same(
typeid(T).hash_code())) {
191 std::string cast_type = this->type_name();
192 throw TypeError(__FILE__, __LINE__,
193 "Object has type \"" + cast_type +
194 "\" but is being cast to type \"" +
195 typeid(T).name() +
"\".");
197 return *(
reinterpret_cast<T *
>(this->buffer.get()));
202 std::unique_ptr<uint8_t[]> buffer =
nullptr;
205 const char *(*type_name)();
208 bool (*same)(std::size_t);
212 void (*deserialize_)(Value &, mpack_node_t);
215 void (*destroy_)(Value &);
218 void (*print_)(
const Value &, std::ostream &);
221 void (*serialize_)(
const Value &, mpack_writer_t *);
261 bool has(
const std::string &key)
const noexcept {
262 return (
map_.find(key) !=
map_.end());
266 std::vector<std::string>
keys() const noexcept;
269 unsigned size() const noexcept {
return map_.size(); }
278 template <
typename T>
281 throw TypeError(__FILE__, __LINE__,
"Object is not a value.");
283 return value_.get_reference<T>();
292 template <
typename T>
293 const T &
as()
const {
295 throw TypeError(__FILE__, __LINE__,
"Object is not a value.");
297 return const_cast<const T &
>(
value_.get_reference<T>());
308 template <
typename T>
309 T &
get(
const std::string &key) {
310 return const_cast<T &
>(get_<T>(key));
321 template <
typename T>
322 const T &
get(
const std::string &key)
const {
336 template <
typename T>
337 const T &
get(
const std::string &key,
const T &default_value)
const {
338 auto it =
map_.find(key);
339 if (it !=
map_.end()) {
340 if (it->second->is_map()) {
341 throw TypeError(__FILE__, __LINE__,
342 "Object at key \"" + key +
343 "\" is a dictionary, cannot get a single value "
345 "mean to use operator()?");
348 return it->second->value_.get_reference<T>();
349 }
catch (
const TypeError &e) {
352 "Object for key \"" + key +
353 "\" does not have the same type as the stored type. Stored " +
354 it->second->value_.type_name() +
" but requested " +
355 typeid(T).name() +
".");
358 return default_value;
376 template <
typename T,
typename... ArgsT,
typename... Args>
377 T &
insert(
const std::string &key, Args &&...args) {
379 throw TypeError(__FILE__, __LINE__,
380 "Cannot insert at key \"" + key +
381 "\" in non-dictionary object of type \"" +
382 value_.type_name() +
"\".");
385 if (!child.is_empty()) {
387 "[Dictionary::insert] Key \"{}\" already exists. Returning existing "
388 "value rather than creating a new one.",
392 child.value_.allocate<T>();
393 new (child.value_.buffer.get()) T(std::forward<Args>(args)...);
394 T &ret = child.value_.setup<T, ArgsT...>();
408 template <
typename T>
414 become<T>(new_value);
417 auto &internal_value =
value_.get_reference<T>();
418 internal_value = new_value;
432 return operator=<std::string>(std::string(c_string));
439 void remove(
const std::string &key) noexcept;
442 void clear() noexcept;
471 Dictionary &operator()(const std::
string &key);
487 const
Dictionary &operator()(const std::
string &key) const;
495 size_t serialize(std::vector<
char> &buffer) const;
501 void write(const std::
string &filename) const;
507 void read(const std::
string &filename);
528 void update(mpack_node_t node);
531 operator
bool &() {
return this->as<bool>(); }
534 operator const bool &()
const {
return this->as<bool>(); }
537 operator int8_t &() {
return this->as<int8_t>(); }
540 operator const int8_t &()
const {
return this->as<int8_t>(); }
543 operator int16_t &() {
return this->as<int16_t>(); }
546 operator const int16_t &()
const {
return this->as<int16_t>(); }
549 operator int32_t &() {
return this->as<int32_t>(); }
552 operator const int32_t &()
const {
return this->as<int32_t>(); }
555 operator int64_t &() {
return this->as<int64_t>(); }
558 operator const int64_t &()
const {
return this->as<int64_t>(); }
561 operator uint8_t &() {
return this->as<uint8_t>(); }
564 operator const uint8_t &()
const {
return this->as<uint8_t>(); }
567 operator uint16_t &() {
return this->as<uint16_t>(); }
570 operator const uint16_t &()
const {
return this->as<uint16_t>(); }
573 operator uint32_t &() {
return this->as<uint32_t>(); }
576 operator const uint32_t &()
const {
return this->as<uint32_t>(); }
579 operator uint64_t &() {
return this->as<uint64_t>(); }
582 operator const uint64_t &()
const {
return this->as<uint64_t>(); }
585 operator float &() {
return this->as<float>(); }
588 operator const float &()
const {
return this->as<float>(); }
591 operator double &() {
return this->as<double>(); }
594 operator const double &()
const {
return this->as<double>(); }
597 operator std::string &() {
return this->as<std::string>(); }
600 operator const std::string &()
const {
return this->as<std::string>(); }
603 operator Eigen::Vector2d &() {
return this->as<Eigen::Vector2d>(); }
606 operator const Eigen::Vector2d &()
const {
607 return this->as<Eigen::Vector2d>();
611 operator Eigen::Vector3d &() {
return this->as<Eigen::Vector3d>(); }
614 operator const Eigen::Vector3d &()
const {
615 return this->as<Eigen::Vector3d>();
619 operator Eigen::VectorXd &() {
return this->as<Eigen::VectorXd>(); }
622 operator const Eigen::VectorXd &()
const {
623 return this->as<Eigen::VectorXd>();
627 operator Eigen::Quaterniond &() {
return this->as<Eigen::Quaterniond>(); }
630 operator const Eigen::Quaterniond &()
const {
631 return this->as<Eigen::Quaterniond>();
635 operator Eigen::Matrix3d &() {
return this->as<Eigen::Matrix3d>(); }
638 operator const Eigen::Matrix3d &()
const {
639 return this->as<Eigen::Matrix3d>();
651 template <
typename T,
typename... ArgsT,
typename... Args>
655 new (
value_.buffer.get()) T(std::forward<Args>(args)...);
656 value_.setup<T, ArgsT...>();
668 template <
typename T>
669 const T &get_(
const std::string &key)
const {
670 const auto &child_value = get_child_value_(key);
672 return child_value.get_reference<T>();
673 }
catch (
const TypeError &e) {
674 throw TypeError(__FILE__, __LINE__,
675 "Object at key \"" + key +
"\" has type \"" +
676 child_value.type_name() +
677 "\", but is being cast to type \"" +
678 typeid(T).name() +
"\".");
690 const Value &get_child_value_(
const std::string &key)
const;
699 void insert_at_key_(
const std::string &key,
const mpack_node_t &value);
705 void serialize_(mpack::Writer &writer)
const;
712 std::unordered_map<std::string, std::unique_ptr<Dictionary>>
map_;
721 struct formatter<
palimpsest::Dictionary> :
public formatter<string_view> {
722 template <
typename FormatContext>
724 -> decltype(ctx.out()) {
725 std::ostringstream oss;
727 return formatter<string_view>::format(oss.str(), ctx);
Dictionary of values and sub-dictionaries.
Dictionary & operator=(const T &new_value)
Assign value directly.
Dictionary(Dictionary &&)=default
Default move constructor.
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.
T & as()
Get reference to the internal value.
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.
const T & as() const
Const variant of as.
bool is_empty() const noexcept
We are empty if and only if we are a dictionary with no element.
T & get(const std::string &key)
Get reference to the object at a given key.
const T & get(const std::string &key, const T &default_value) const
Get object at a given key if it exists, or a default value otherwise.
Dictionary()=default
Default constructor.
friend std::ostream & operator<<(std::ostream &stream, const Dictionary &dict)
Output stream operator for printing.
void remove(const std::string &key) noexcept
Remove a key-value pair from the dictionary.
Dictionary(const Dictionary &)=delete
No copy constructor.
Dictionary & operator=(const char *c_string)
Assignment operator for C-style strings.
const T & get(const std::string &key) const
Const variant of get.
void become(Args &&...args)
bool has(const std::string &key) const noexcept
Check whether a key is in the dictionary.
~Dictionary()=default
Default destructor.
T & insert(const std::string &key, Args &&...args)
Create an object at a given key and return a reference to it.
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.
Dictionary & operator=(Dictionary &&)=default
Default move assignment operator.
Dictionary & operator=(const Dictionary &)=delete
No copy assignment operator.
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.