palimpsest v3.0.0
Loading...
Searching...
No Matches
palimpsest — Fast serializable C++ dictionaries

CI Documentation Coverage C++ version Release

The palimpsest library implements a Dictionary type for C++ meant for fast value updates and serialization. It is called palimpsest because dictionaries are designed for frequent rewritings (values change fast) on the same support (keys change slow).

Example

Let's fill a dictionary and print it to the standard output:

#include <iostream>
int main() {
Dictionary world;
world("name") = "example";
world("temperature") = 28.0;
auto& bodies = world("bodies");
bodies("plane")("orientation") = Eigen::Quaterniond{0.9239, 0.3827, 0., 0.};
bodies("plane")("position") = Eigen::Vector3d{0.0, 0.0, 100.0};
bodies("truck")("orientation") = Eigen::Quaterniond::Identity();
bodies("truck")("position") = Eigen::Vector3d{42.0, 0.0, 0.0};
std::cout << world << std::endl;
return EXIT_SUCCESS;
}
Dictionary of values and sub-dictionaries.
Definition: Dictionary.h:96

This code outputs:

{"bodies": {"truck": {"position": [42, 0.5, 0], "orientation": [1, 0, 0, 0]},
"plane": {"position": [0.1, 0, 100], "orientation": [0.9239, 0.3827, 0, 0]}},
"temperature": 28, "name": "example"}

We can serialize the dictionary to file:

world.write("world.mpack");

And deserialize it likewise:

Dictionary world_bis;
world_bis.read("world.mpack");
std::cout << world_bis << std::endl;

Dictionaries can also be serialized to bytes for transmission over TCP, memory-mapped files, telegraph lines, etc. Check out the examples directory for more advanced use cases.

Comparison to Python dictionaries

Palimpsest will feel familiar if you are used to Python dictionaries, as its API is a subset of Python's dict:

Python dict Palimpsest Dictionary
dict.clear Dictionary::clear
dict.copy Dictionaries are move-only
copy.deepcopy Dictionary::deepcopy
dict.fromkeys Dictionary::fromkeys
dict.get Dictionary::get
dict.items Dictionary::items
dict.keys Dictionary::keys
dict.pop Dictionary::pop
dict.popitem Dictionary::popitem
dict.setdefault Dictionary::setdefault
dict.update Dictionary::update
dict.values Dictionary::values

There are a few differences:

  • Dictionaries are move-only: there is no copy function matching Python's dict.copy, but Dictionary::deepcopy matches Python's copy.deepcopy.
  • Dictionaries do not conserve insertion order, whereas insertion order conservation is guaranteed in Python since version 3.7 of the language.

Features and non-features

The two main assumptions in palimpsest dictionaries are that:

  • Keys are strings.
  • Values hold either a sub-dictionary or a type that can be unambiguously serialized.

Features

  • Returns references to any stored value or sub-dictionary
  • Built-in support for Eigen
  • Print dictionaries to standard output as JSON
  • Serialize to and deserialize from MessagePack

Non-features

  • Dictionaries are move-only (deep copies are possible, but now shallow copies)
  • Types need to deserialize unambiguously (e.g., positive integers always deserialize to unsigned)
  • Array values are mostly limited to Eigen tensors (matrix, quaternion, vector)

If any of these design decisions doesn't match what you are looking for, you can also check out a list of alternative libraries below.

Installation

Bazel

Add to your WORKSPACE file the http_archive instruction from the release page.

You can then define C++ targets that depend on @palimpsest:

cc_binary(
name = "my-target",
srcs = ["my-target.cpp"],
deps = ["@palimpsest"],
)

CMake

Make sure Eigen, fmt and spdlog are installed system-wise, for instance on Debian-based distributions:

sudo apt install libeigen3-dev libfmt-dev libspdlog-dev

Then follow the standard CMake procedure:

mkdir build && cd build
cmake .. -DCMAKE_BUILD_TYPE=Release
make -j4
make install

Note that by default MPack will be built and installed from the third_party folder. Set -DBUILD_MPACK=OFF if you already have MPack 1.1 or later installed on your system.

See also

The Dictionary class in palimpsest derives from two classes of the mc_rtc robotics framework: mc_rtc::Configuration (similar API, based on RapidJSON) and mc_rtc::DataStore (general value types, but not serializable).

If some of the design decisions in palimpsest don't match your requirements, you can also check out the following alternatives:

  • JSON for Modern C++: most user-friendly library of this list, serializes to MessagePack and other binary formats, but not designed for speed.
  • mjlib: includes a telemetry library if your use case is more specifically in robotics or embedded systems.
  • Protocol Buffers: good fit if you have a fixed schema (keys don't change at all) that you want to serialize to and from.
  • RapidJSON: low memory footprint, can serialize to MessagePack using other related projects, but has linear lookup complexity as it stores dictionaries as lists of key-value pairs.
  • simdjson: uses SIMD instructions and microparallel algorithms to parse JSON (reportedly 4x faster than RapidJSON and 25x faster than JSON for Modern C++).