243 lines
5.5 KiB
C++
243 lines
5.5 KiB
C++
#pragma once
|
|
|
|
#include "./cbor-walker.h"
|
|
|
|
struct StorageDummy {
|
|
template<class V>
|
|
void operator()(const char *, V &) {}
|
|
};
|
|
|
|
struct StorageExample {
|
|
template<class V>
|
|
void operator()(const char */*key*/, V &v) {
|
|
value(v);
|
|
}
|
|
|
|
private:
|
|
void value(int64_t &v) {};
|
|
void value(uint64_t &v) {};
|
|
void value(int32_t &v) {};
|
|
void value(uint32_t &v) {};
|
|
void value(int16_t &v) {};
|
|
void value(uint16_t &v) {};
|
|
void value(int8_t &v) {};
|
|
void value(uint8_t &v) {};
|
|
void value(float &v) {};
|
|
void value(double &v) {};
|
|
void value(bool &v) {};
|
|
|
|
template<class Item>
|
|
void value(std::vector<Item> &array) {
|
|
for (auto &item : array) {
|
|
value(item);
|
|
}
|
|
}
|
|
|
|
template<class V>
|
|
void value(V &v) {
|
|
v.state(*this);
|
|
}
|
|
};
|
|
|
|
namespace _impl {
|
|
template<class Fallback, class MaybeVoid=void>
|
|
struct VoidFallback {
|
|
using T = MaybeVoid;
|
|
};
|
|
template<class Fallback>
|
|
struct VoidFallback<Fallback, void> {
|
|
using T = Fallback;
|
|
};
|
|
}
|
|
|
|
template<bool compact=false, class SubClassCRTP=void>
|
|
struct StorageCborWriter {
|
|
StorageCborWriter(const signalsmith::cbor::CborWriter &writer, std::vector<unsigned char> *buffer=nullptr) : cbor(writer) {
|
|
if (buffer) buffer->resize(0);
|
|
|
|
if (compact) {
|
|
cbor.addTag(0xCB68ADED); // turns into "2store..." when base64-encoded
|
|
cbor.openArray();
|
|
} else {
|
|
cbor.openMap();
|
|
}
|
|
}
|
|
StorageCborWriter(std::vector<unsigned char> &cborBuffer) : StorageCborWriter(signalsmith::cbor::CborWriter(cborBuffer), &cborBuffer) {}
|
|
~StorageCborWriter() {
|
|
cbor.close();
|
|
}
|
|
|
|
template<class V>
|
|
void operator()(const char *key, V &value) {
|
|
if (!compact) cbor.addUtf8(key);
|
|
writeValue(value);
|
|
}
|
|
|
|
protected:
|
|
signalsmith::cbor::CborWriter cbor;
|
|
|
|
#define STORAGE_BASIC_INT(V) \
|
|
void writeValue(V &value) { \
|
|
cbor.addInt(value); \
|
|
}
|
|
STORAGE_BASIC_INT(int64_t)
|
|
STORAGE_BASIC_INT(uint64_t)
|
|
STORAGE_BASIC_INT(int32_t)
|
|
STORAGE_BASIC_INT(uint32_t)
|
|
STORAGE_BASIC_INT(int16_t)
|
|
STORAGE_BASIC_INT(uint16_t)
|
|
STORAGE_BASIC_INT(int8_t)
|
|
STORAGE_BASIC_INT(uint8_t)
|
|
#undef STORAGE_BASIC_INT
|
|
|
|
void writeValue(float &value) {
|
|
cbor.addFloat(value);
|
|
}
|
|
void writeValue(double &value) {
|
|
cbor.addFloat(value);
|
|
}
|
|
void writeValue(bool &value) {
|
|
cbor.addBool(value);
|
|
}
|
|
|
|
void writeValue(const char *cStr) {
|
|
cbor.addUtf8(cStr);
|
|
}
|
|
|
|
template<class Item>
|
|
void writeValue(std::vector<Item> &array) {
|
|
cbor.openArray(array.size());
|
|
for (auto &item : array) {
|
|
writeValue(item);
|
|
}
|
|
}
|
|
#define STORAGE_TYPED_ARRAY(T) \
|
|
void writeValue(std::vector<T> &array) { \
|
|
cbor.addTypedArray(array.data(), array.size()); \
|
|
}
|
|
STORAGE_TYPED_ARRAY(uint8_t)
|
|
STORAGE_TYPED_ARRAY(int8_t)
|
|
STORAGE_TYPED_ARRAY(uint16_t)
|
|
STORAGE_TYPED_ARRAY(int16_t)
|
|
STORAGE_TYPED_ARRAY(uint32_t)
|
|
STORAGE_TYPED_ARRAY(int32_t)
|
|
STORAGE_TYPED_ARRAY(uint64_t)
|
|
STORAGE_TYPED_ARRAY(int64_t)
|
|
STORAGE_TYPED_ARRAY(float)
|
|
STORAGE_TYPED_ARRAY(double)
|
|
#undef STORAGE_TYPED_ARRAY
|
|
|
|
using SubStorage = typename _impl::VoidFallback<StorageCborWriter, SubClassCRTP>::T;
|
|
|
|
template<class Obj>
|
|
void writeValue(Obj &obj) {
|
|
cbor.openMap();
|
|
obj.state(*(SubStorage *)this);
|
|
cbor.close();
|
|
}
|
|
};
|
|
|
|
template<bool compact=false, class SubClassCRTP=void>
|
|
struct StorageCborReader {
|
|
using Cbor = signalsmith::cbor::TaggedCborWalker;
|
|
|
|
StorageCborReader(Cbor c) : cbor(c) {
|
|
if (compact) {
|
|
if (cbor.isArray()) cbor = cbor.enter();
|
|
} else {
|
|
if (cbor.isMap()) cbor = cbor.enter();
|
|
}
|
|
}
|
|
StorageCborReader(const std::vector<unsigned char> &v) : StorageCborReader(Cbor(v)) {}
|
|
|
|
template<class V>
|
|
void operator()(const char *key, V &v) {
|
|
if (filterKeyBytes != nullptr) {
|
|
if (!keyMatch(key, filterKeyBytes, filterKeyLength)) return;
|
|
} else if (!compact) {
|
|
if (!cbor.isUtf8()) return; // We expect a string key
|
|
if (!keyMatch(key, (const char *)cbor.bytes(), cbor.length())) {
|
|
return; // key doesn't match
|
|
}
|
|
cbor++;
|
|
}
|
|
readValue(v);
|
|
}
|
|
|
|
private:
|
|
template<class Obj>
|
|
void readValue(Obj &obj) {
|
|
if (compact) {
|
|
// No keys, no filters
|
|
return obj.state(*(SubClass *)this);
|
|
}
|
|
|
|
if (!cbor.isMap()) return;
|
|
|
|
cbor = cbor.forEachPair([&](Cbor key, Cbor value){
|
|
if (!key.isUtf8()) return;
|
|
|
|
const char *fkb = filterKeyBytes;
|
|
size_t fkl = filterKeyLength;
|
|
|
|
// Temporarily set key, and scan the object for that property
|
|
filterKeyBytes = (const char *)key.bytes();
|
|
filterKeyLength = key.length();
|
|
cbor = value;
|
|
obj.state(*(SubClass *)this);
|
|
|
|
filterKeyBytes = fkb;
|
|
filterKeyLength = fkl;
|
|
});
|
|
}
|
|
|
|
#define STORAGE_BASIC_TYPE(V) \
|
|
void readValue(V &v) { \
|
|
v = V(cbor++); \
|
|
}
|
|
STORAGE_BASIC_TYPE(int64_t)
|
|
STORAGE_BASIC_TYPE(uint64_t)
|
|
STORAGE_BASIC_TYPE(int32_t)
|
|
STORAGE_BASIC_TYPE(uint32_t)
|
|
STORAGE_BASIC_TYPE(int16_t)
|
|
STORAGE_BASIC_TYPE(uint16_t)
|
|
STORAGE_BASIC_TYPE(int8_t)
|
|
STORAGE_BASIC_TYPE(uint8_t)
|
|
STORAGE_BASIC_TYPE(float)
|
|
STORAGE_BASIC_TYPE(double)
|
|
STORAGE_BASIC_TYPE(bool)
|
|
#undef STORAGE_BASIC_TYPE
|
|
|
|
void readValue(std::string &v) {
|
|
v = (cbor++).utf8();
|
|
}
|
|
|
|
template<class Item>
|
|
void readValue(std::vector<Item> &array) {
|
|
if (!cbor.isArray()) return;
|
|
size_t length = 0;
|
|
cbor = cbor.forEach([&](Cbor item, size_t index){
|
|
length = index + 1;
|
|
if (array.size() < length) array.resize(length);
|
|
|
|
cbor = item;
|
|
readValue(array[index]);
|
|
});
|
|
array.resize(length);
|
|
}
|
|
protected:
|
|
Cbor cbor;
|
|
|
|
const char *filterKeyBytes = nullptr;
|
|
size_t filterKeyLength = 0;
|
|
|
|
static bool keyMatch(const char *key, const char *filterKeyBytes, size_t filterKeyLength) {
|
|
for (size_t i = 0; i < filterKeyLength; ++i) {
|
|
if (key[i] != filterKeyBytes[i]) return false;
|
|
}
|
|
return key[filterKeyLength] == 0;
|
|
}
|
|
|
|
using SubClass = typename _impl::VoidFallback<StorageCborReader, SubClassCRTP>::T;
|
|
};
|