15#include <spdlog/spdlog.h>
22#include <unordered_map>
28#include "palimpsest/json/write.h"
29#include "palimpsest/mpack/Writer.h"
30#include "palimpsest/mpack/read.h"
31#include "palimpsest/mpack/write.h"
134 bool has(
const std::string &key)
const noexcept {
135 return (
map_.find(key) !=
map_.end());
155 std::vector<std::string>
keys() const noexcept;
180 std::vector<std::pair<std::
string, std::reference_wrapper<const
Dictionary>>>
181 items() const noexcept;
204 std::vector<std::reference_wrapper<const
Dictionary>>
values() const noexcept;
207 unsigned size() const noexcept {
return map_.size(); }
216 template <
typename T>
219 throw TypeError(__FILE__, __LINE__,
"Object is not a value.");
230 template <
typename T>
231 const T &
as()
const {
233 throw TypeError(__FILE__, __LINE__,
"Object is not a value.");
254 template <
typename T>
255 T &
get(
const std::string &key) {
256 return const_cast<T &
>(get_<T>(key));
273 template <
typename T>
274 const T &
get(
const std::string &key)
const {
296 template <
typename T>
297 const T &
get(
const std::string &key,
const T &default_value)
const {
298 auto it =
map_.find(key);
299 if (it !=
map_.end()) {
300 if (it->second->is_map()) {
302 "Object at key \"" + key +
303 "\" is a dictionary, cannot get a single value "
305 "mean to use operator()?");
308 return it->second->value_.get_reference<T>();
312 "Object for key \"" + key +
313 "\" does not have the same type as the stored type. Stored " +
314 it->second->value_.type_name() +
" but requested " +
315 typeid(T).name() +
".");
318 return default_value;
336 template <
typename T,
typename... ArgsT,
typename... Args>
337 T &
insert(
const std::string &key, Args &&...args) {
340 "Cannot insert at key \"" + key +
341 "\" in non-dictionary object of type \"" +
345 if (!child.is_empty()) {
347 "[Dictionary::insert] Key \"{}\" already exists. Returning existing "
348 "value rather than creating a new one.",
352 child.value_.allocate<T>();
353 new (child.value_.buffer.get()) T(std::forward<Args>(args)...);
354 T &ret = child.value_.setup<T, ArgsT...>();
384 template <
typename T>
385 T &
setdefault(
const std::string &key,
const T &default_value) {
388 "Cannot insert at key \"" + key +
389 "\" in non-dictionary object of type \"" +
392 auto it =
map_.find(key);
393 if (it !=
map_.end()) {
394 if (it->second->is_map()) {
396 "Object at key \"" + key +
397 "\" is a dictionary, cannot get a single value "
399 "mean to use operator()?");
402 return it->second->value_.get_reference<T>();
406 "Object for key \"" + key +
407 "\" does not have the same type as the stored type. Stored " +
408 it->second->value_.type_name() +
" but requested " +
409 typeid(T).name() +
".");
413 child.value_.allocate<T>();
414 new (child.value_.buffer.get()) T(default_value);
415 T &ret = child.value_.setup<T>();
429 template <
typename T>
435 become<T>(new_value);
439 internal_value = new_value;
453 return operator= <std::string>(std::string(c_string));
460 void remove(
const std::string &key)
noexcept;
484 template <
typename T>
485 T
pop(
const std::string &key) {
486 const T value = get<T>(key);
514 template <
typename T>
515 T
pop(
const std::string &key,
const T &default_value) {
516 auto it =
map_.find(key);
517 if (it ==
map_.end()) {
518 return default_value;
520 if (it->second->is_map()) {
522 "Object at key \"" + key +
523 "\" is a dictionary, cannot pop a single value "
527 const T value = it->second->value_.get_reference<T>();
533 "Object for key \"" + key +
534 "\" does not have the same type as the requested type. Stored " +
535 it->second->value_.type_name() +
" but requested " +
536 typeid(T).name() +
".");
564 std::pair<std::string, Dictionary>
popitem();
578 void clear() noexcept;
607 Dictionary &operator()(const std::
string &key);
623 const
Dictionary &operator()(const std::
string &key) const;
664 template <typename Container, typename T>
667 for (
const auto &key :
keys) {
692 template <
typename Container>
695 for (
const auto &key :
keys) {
707 size_t serialize(std::vector<char> &buffer)
const;
713 void write(
const std::string &filename)
const;
719 void read(
const std::string &filename);
770 operator bool &() {
return this->as<bool>(); }
773 operator const bool &()
const {
return this->as<bool>(); }
776 operator int8_t &() {
return this->as<int8_t>(); }
779 operator const int8_t &()
const {
return this->as<int8_t>(); }
782 operator int16_t &() {
return this->as<int16_t>(); }
785 operator const int16_t &()
const {
return this->as<int16_t>(); }
788 operator int32_t &() {
return this->as<int32_t>(); }
791 operator const int32_t &()
const {
return this->as<int32_t>(); }
794 operator int64_t &() {
return this->as<int64_t>(); }
797 operator const int64_t &()
const {
return this->as<int64_t>(); }
800 operator uint8_t &() {
return this->as<uint8_t>(); }
803 operator const uint8_t &()
const {
return this->as<uint8_t>(); }
806 operator uint16_t &() {
return this->as<uint16_t>(); }
809 operator const uint16_t &()
const {
return this->as<uint16_t>(); }
812 operator uint32_t &() {
return this->as<uint32_t>(); }
815 operator const uint32_t &()
const {
return this->as<uint32_t>(); }
818 operator uint64_t &() {
return this->as<uint64_t>(); }
821 operator const uint64_t &()
const {
return this->as<uint64_t>(); }
824 operator float &() {
return this->as<float>(); }
827 operator const float &()
const {
return this->as<float>(); }
830 operator double &() {
return this->as<double>(); }
833 operator const double &()
const {
return this->as<double>(); }
836 operator std::string &() {
return this->as<std::string>(); }
839 operator const std::string &()
const {
return this->as<std::string>(); }
842 operator Eigen::Vector2d &() {
return this->as<Eigen::Vector2d>(); }
845 operator const Eigen::Vector2d &()
const {
846 return this->as<Eigen::Vector2d>();
850 operator Eigen::Vector3d &() {
return this->as<Eigen::Vector3d>(); }
853 operator const Eigen::Vector3d &()
const {
854 return this->as<Eigen::Vector3d>();
858 operator Eigen::VectorXd &() {
return this->as<Eigen::VectorXd>(); }
861 operator const Eigen::VectorXd &()
const {
862 return this->as<Eigen::VectorXd>();
866 operator Eigen::Quaterniond &() {
return this->as<Eigen::Quaterniond>(); }
869 operator const Eigen::Quaterniond &()
const {
870 return this->as<Eigen::Quaterniond>();
874 operator Eigen::Matrix3d &() {
return this->as<Eigen::Matrix3d>(); }
877 operator const Eigen::Matrix3d &()
const {
878 return this->as<Eigen::Matrix3d>();
890 template <
typename T,
typename... ArgsT,
typename... Args>
894 new (
value_.
buffer.get()) T(std::forward<Args>(args)...);
906 void deserialize_(mpack_node_t node);
916 template <
typename T>
917 const T &get_(
const std::string &key)
const {
918 const auto &child_value = get_child_value_(key);
920 return child_value.get_reference<T>();
921 }
catch (
const TypeError &e) {
922 throw TypeError(__FILE__, __LINE__,
923 "Object at key \"" + key +
"\" has type \"" +
924 child_value.type_name() +
925 "\", but is being cast to type \"" +
926 typeid(T).name() +
"\".");
938 const Value &get_child_value_(
const std::string &key)
const;
947 void insert_at_key_(
const std::string &key,
const mpack_node_t &value);
953 void serialize_(mpack::Writer &writer)
const;
960 std::unordered_map<std::string, std::unique_ptr<Dictionary>>
map_;
965#include "palimpsest/internal/fmt_formatter.h"
Dictionary of values and sub-dictionaries.
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.
Dictionary & operator=(const T &new_value)
Assign value directly.
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 deserialize(const char *data, size_t size)
Update dictionary from raw MessagePack data.
unsigned size() const noexcept
Return the number of keys in the dictionary.
std::pair< std::string, Dictionary > popitem()
Remove and return a (key, value) pair from the dictionary.
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 & operator=(Dictionary &&)=default
Default move assignment operator.
T pop(const std::string &key)
Remove a key-value pair from the dictionary and return its value.
T & as()
Get reference to the internal value.
bool is_empty() const noexcept
We are empty if and only if we are a dictionary with no element.
Dictionary & operator=(const char *c_string)
Assignment operator for C-style strings.
static Dictionary deepcopy(const Dictionary &other)
Create a deep copy of an existing dictionary.
T & insert(const std::string &key, Args &&...args)
Create an object at a given key and return a reference to it.
Dictionary & operator=(const Dictionary &)=delete
No copy assignment operator.
Dictionary()=default
Default constructor.
const T & get(const std::string &key) const
Const variant of get.
void remove(const std::string &key) noexcept
Remove a key-value pair from the dictionary.
T & get(const std::string &key)
Get reference to the object at a given key.
Dictionary(const Dictionary &)=delete
No copy constructor.
const T & as() const
Const variant of as.
void update(const Dictionary &other)
Update dictionary from another dictionary.
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 & setdefault(const std::string &key, const T &default_value)
If key is in the dictionary, return its value.
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.
T pop(const std::string &key, const T &default_value)
Remove a key-value pair from the dictionary and return its value, or return a default value if the ke...
std::vector< std::pair< std::string, std::reference_wrapper< const Dictionary > > > items() const noexcept
Return an iterable view of the dictionary's (key, value) pairs.
static Dictionary fromkeys(const Container &keys)
Create a new dictionary with keys from an iterable container and all values set to empty dictionaries...
friend std::ostream & operator<<(std::ostream &stream, const Dictionary &dict)
Output stream operator for printing.
void write(const std::string &filename) const
Write MessagePack serialization to a binary file.
void clear() noexcept
Remove all entries from the dictionary.
Dictionary difference(const Dictionary &other) const
Compute the difference between this dictionary and another.
std::vector< std::reference_wrapper< const Dictionary > > values() const noexcept
Return an iterable view of the dictionary's values.
bool is_value() const noexcept
We are a value if and only if the internal value is non-empty.
static Dictionary fromkeys(const Container &keys, const T &value)
Create a new dictionary with keys from an iterable container and all values set to the same value.
Internal wrapper around an object and its type information.
T & setup()
Allocate object and register internal functions.
void allocate()
Allocate the internal buffer.
T & get_reference() const
Cast value to its object's type after checking that it matches T.
std::unique_ptr< uint8_t[]> buffer
Internal buffer that holds the actual object.
const char *(* type_name)()
Function returning the name of the object's type.
Requested type doesn't match the one already in the dictionary.