309 lines
14 KiB
C++
309 lines
14 KiB
C++
#pragma once
|
|
|
|
#include <memory>
|
|
#include <cstdint>
|
|
#include <string>
|
|
#include <vector>
|
|
#include <map>
|
|
#include <set>
|
|
#include <limits>
|
|
|
|
#include <boost/optional.hpp>
|
|
|
|
namespace Preserves {
|
|
|
|
enum class ValueKind {
|
|
Boolean,
|
|
Float,
|
|
Double,
|
|
SignedInteger,
|
|
String,
|
|
ByteString,
|
|
Symbol,
|
|
|
|
Record,
|
|
Sequence,
|
|
Set,
|
|
Dictionary,
|
|
|
|
Embedded,
|
|
};
|
|
|
|
template <typename T = class GenericEmbedded> class Record;
|
|
template <typename T = class GenericEmbedded> class ValueImpl;
|
|
|
|
template <typename T = class GenericEmbedded>
|
|
class Value {
|
|
std::shared_ptr<ValueImpl<T>> p;
|
|
|
|
public:
|
|
Value(std::shared_ptr<ValueImpl<T>> const& p) : p(p) {}
|
|
Value(ValueImpl<T> *p) : p(p) {}
|
|
|
|
std::shared_ptr<ValueImpl<T>> _impl() const { return p; }
|
|
|
|
static Value from_bool(bool b);
|
|
static Value from_float(float f);
|
|
static Value from_double(double d);
|
|
static Value from_int(uint64_t i);
|
|
static Value from_int(int64_t i);
|
|
static Value from_string(std::string const& s);
|
|
static Value from_bytes(std::vector<uint8_t> const& v);
|
|
static Value from_bytes(std::vector<char> const& v);
|
|
static Value from_bytes(void *p, size_t len);
|
|
static Value from_symbol(std::string const& s);
|
|
|
|
static Value record(Record<T> const& r);
|
|
static Value record(Value const& label, std::vector<Value> const& fields);
|
|
static Value sequence(std::vector<Value> const& items);
|
|
static Value set(std::set<Value> const& items);
|
|
static Value dictionary(std::map<Value, Value> const& entries);
|
|
|
|
static Value from_embedded(std::shared_ptr<T> const& p);
|
|
|
|
static Value from_unsigned(uint64_t i) { return from_int(i); }
|
|
static Value from_signed(int64_t i) { return from_int(i); }
|
|
static Value from_bignum(std::vector<uint8_t> const& v);
|
|
|
|
static Value from_number(uint64_t i) { return from_int(i); }
|
|
static Value from_number(int64_t i) { return from_int(i); }
|
|
static Value from_number(float f) { return from_float(f); }
|
|
static Value from_number(double d) { return from_double(d); }
|
|
|
|
static Value from(bool b) { return from_bool(b); }
|
|
static Value from(float f) { return from_float(f); }
|
|
static Value from(double d) { return from_double(d); }
|
|
static Value from(uint64_t i) { return from_int(i); }
|
|
static Value from(unsigned i) { return from_int(uint64_t(i)); }
|
|
static Value from(int64_t i) { return from_int(i); }
|
|
static Value from(signed i) { return from_int(int64_t(i)); }
|
|
static Value from(std::string const& s) { return from_string(s); }
|
|
static Value from(char const* s) { return from_string(s); }
|
|
static Value from(std::vector<uint8_t> const& v) { return from_bytes(v); }
|
|
static Value from(std::vector<char> const& v) { return from_bytes(v); }
|
|
static Value from(void *p, size_t len) { return from_bytes(p, len); }
|
|
static Value from(Record<T> const& r) { return record(r); }
|
|
static Value from(Value const& label, std::vector<Value> const& fields) { return record(label, fields); }
|
|
static Value from(std::vector<Value> const& items) { return sequence(items); }
|
|
static Value from(std::set<Value> const& items) { return set(items); }
|
|
static Value from(std::map<Value, Value> const& entries) { return dictionary(entries); }
|
|
|
|
ValueImpl<T>& operator*() const { return *p; }
|
|
ValueImpl<T>* operator->() const { return p.get(); }
|
|
|
|
ValueKind value_kind() const;
|
|
bool is_mutable() const;
|
|
|
|
bool is_bool() const { return value_kind() == ValueKind::Boolean; }
|
|
bool is_float() const { return value_kind() == ValueKind::Float; }
|
|
bool is_double() const { return value_kind() == ValueKind::Double; }
|
|
bool is_int() const { return value_kind() == ValueKind::SignedInteger; }
|
|
bool is_string() const { return value_kind() == ValueKind::String; }
|
|
bool is_bytes() const { return value_kind() == ValueKind::ByteString; }
|
|
bool is_symbol() const { return value_kind() == ValueKind::Symbol; }
|
|
bool is_record() const { return value_kind() == ValueKind::Record; }
|
|
bool is_sequence() const { return value_kind() == ValueKind::Sequence; }
|
|
bool is_set() const { return value_kind() == ValueKind::Set; }
|
|
bool is_dictionary() const { return value_kind() == ValueKind::Dictionary; }
|
|
|
|
boost::optional<bool> as_bool() const;
|
|
bool to_bool() const { return as_bool().value(); }
|
|
|
|
boost::optional<float> as_float() const;
|
|
float to_float() const { return as_float().value(); }
|
|
|
|
boost::optional<double> as_double() const;
|
|
double to_double() const { return as_double().value(); }
|
|
|
|
boost::optional<uint64_t> as_unsigned() const;
|
|
uint64_t to_unsigned() const { return as_unsigned().value(); }
|
|
|
|
boost::optional<int64_t> as_signed() const;
|
|
int64_t to_signed() const { return as_signed().value(); }
|
|
|
|
boost::optional<std::vector<uint8_t> const&> as_bignum() const;
|
|
std::vector<uint8_t> const& to_bignum() const { return as_bignum().value(); }
|
|
|
|
boost::optional<std::string const&> as_string() const;
|
|
std::string const& to_string() const { return as_string().value(); }
|
|
|
|
boost::optional<std::vector<uint8_t> const&> as_bytes() const;
|
|
std::vector<uint8_t> const& to_bytes() const { return as_bytes().value(); }
|
|
|
|
boost::optional<std::string const&> as_symbol() const;
|
|
std::string const& to_symbol() const { return as_symbol().value(); }
|
|
|
|
boost::optional<Record<T> const&> as_record() const;
|
|
Record<T> const& to_record() const { return as_record().value(); };
|
|
|
|
boost::optional<std::vector<Value> const&> as_sequence() const;
|
|
std::vector<Value> const& to_sequence() const { return as_sequence().value(); }
|
|
|
|
boost::optional<std::set<Value> const&> as_set() const;
|
|
std::set<Value> const& to_set() const { return as_set().value(); }
|
|
|
|
boost::optional<std::map<Value,Value> const&> as_dictionary() const;
|
|
std::map<Value,Value> const& to_dictionary() const { return as_dictionary().value(); }
|
|
|
|
boost::optional<std::shared_ptr<T>> as_embedded() const;
|
|
std::shared_ptr<T> to_embedded() const { return as_embedded().value(); }
|
|
|
|
Value annotate(Value const& ann) const;
|
|
boost::optional<std::vector<Value> const&> annotations() const;
|
|
|
|
boost::optional<Value> label() const;
|
|
size_t size() const;
|
|
bool contains(Value const& key) const;
|
|
boost::optional<Value> get(Value const& key) const;
|
|
Value operator[](Value const& key) const { return get(key).value(); }
|
|
boost::optional<Value> get(size_t index) const;
|
|
Value operator[](size_t index) const { return get(index).value(); }
|
|
};
|
|
|
|
class BinaryWriter; // forward declaration; see preserves_binary_writer.hpp
|
|
|
|
template <typename T>
|
|
class ValueImpl {
|
|
protected:
|
|
virtual Value<T> internal_annotate(std::shared_ptr<ValueImpl<T>> const& self, Value<T> const& ann);
|
|
|
|
friend class Value<T>;
|
|
public:
|
|
virtual ~ValueImpl() {}
|
|
|
|
virtual ValueKind value_kind() const = 0;
|
|
virtual bool is_mutable() const { return false; }
|
|
|
|
virtual boost::optional<bool> as_bool() const { return boost::none; }
|
|
virtual boost::optional<float> as_float() const { return boost::none; }
|
|
virtual boost::optional<double> as_double() const { return boost::none; }
|
|
virtual boost::optional<uint64_t> as_unsigned() const { return boost::none; }
|
|
virtual boost::optional<int64_t> as_signed() const { return boost::none; }
|
|
virtual boost::optional<std::vector<uint8_t> const&> as_bignum() const { return boost::none; }
|
|
virtual boost::optional<std::string const&> as_string() const { return boost::none; }
|
|
virtual boost::optional<std::vector<uint8_t> const&> as_bytes() const { return boost::none; }
|
|
virtual boost::optional<std::string const&> as_symbol() const { return boost::none; }
|
|
virtual boost::optional<Record<T> const&> as_record() const { return boost::none; }
|
|
virtual boost::optional<std::vector<Value<T>> const&> as_sequence() const { return boost::none; }
|
|
virtual boost::optional<std::set<Value<T>> const&> as_set() const { return boost::none; }
|
|
virtual boost::optional<std::map<Value<T>,Value<T>> const&> as_dictionary() const { return boost::none; }
|
|
virtual boost::optional<std::shared_ptr<T>> as_embedded() const { return boost::none; }
|
|
|
|
virtual boost::optional<Value<T>> label() const { return boost::none; }
|
|
virtual size_t size() const { return 0; }
|
|
virtual bool contains(Value<T> const& /* key */) const { return false; }
|
|
virtual boost::optional<Value<T>> get(Value<T> const& /* key */) const { return boost::none; }
|
|
virtual boost::optional<Value<T>> get(size_t /* index */) const { return boost::none; }
|
|
|
|
virtual bool add(Value<T> const& /* item */) {
|
|
throw std::runtime_error("Cannot add item to Preserves value");
|
|
}
|
|
virtual bool set(Value<T> const& /* key */, Value<T> const& /* value */) {
|
|
throw std::runtime_error("Cannot set item by key in Preserves value");
|
|
}
|
|
virtual bool set(size_t /* index */, Value<T> const& /* value */) {
|
|
throw std::runtime_error("Cannot set item by index in Preserves value");
|
|
}
|
|
virtual bool erase(Value<T> const& /* key */) {
|
|
throw std::runtime_error("Cannot erase item in Preserves value");
|
|
}
|
|
|
|
virtual boost::optional<std::vector<Value<T>> const&> annotations() const { return boost::none; }
|
|
|
|
virtual BinaryWriter& write(BinaryWriter& w) const = 0;
|
|
};
|
|
|
|
template <typename T> ValueKind Value<T>::value_kind() const { return p->value_kind(); }
|
|
template <typename T> bool Value<T>::is_mutable() const { return p->is_mutable(); }
|
|
|
|
#define PRESERVES_DELEGATE_CAST(t, name) \
|
|
template <typename T> boost::optional<t> Value<T>::name() const { return p->name(); }
|
|
PRESERVES_DELEGATE_CAST(bool, as_bool);
|
|
PRESERVES_DELEGATE_CAST(float, as_float);
|
|
PRESERVES_DELEGATE_CAST(double, as_double);
|
|
PRESERVES_DELEGATE_CAST(uint64_t, as_unsigned);
|
|
PRESERVES_DELEGATE_CAST(int64_t, as_signed);
|
|
PRESERVES_DELEGATE_CAST(std::vector<uint8_t> const&, as_bignum);
|
|
PRESERVES_DELEGATE_CAST(std::string const&, as_string);
|
|
PRESERVES_DELEGATE_CAST(std::vector<uint8_t> const&, as_bytes);
|
|
PRESERVES_DELEGATE_CAST(std::string const&, as_symbol);
|
|
PRESERVES_DELEGATE_CAST(Record<T> const&, as_record);
|
|
PRESERVES_DELEGATE_CAST(std::vector<Value<T>> const&, as_sequence);
|
|
PRESERVES_DELEGATE_CAST(std::set<Value<T>> const&, as_set);
|
|
#define COMMA ,
|
|
PRESERVES_DELEGATE_CAST(std::map<Value<T> COMMA Value<T>> const&, as_dictionary);
|
|
#undef COMMA
|
|
PRESERVES_DELEGATE_CAST(std::shared_ptr<T>, as_embedded);
|
|
#undef PRESERVES_DELEGATE_CAST
|
|
|
|
template <typename T> boost::optional<Value<T>> Value<T>::label() const { return p->label(); }
|
|
template <typename T> bool Value<T>::contains(Value const& key) const { return p->contains(key); }
|
|
template <typename T> boost::optional<Value<T>> Value<T>::get(Value<T> const& key) const { return p->get(key); }
|
|
template <typename T> boost::optional<Value<T>> Value<T>::get(size_t index) const { return p->get(index); }
|
|
template <typename T> size_t Value<T>::size() const { return p->size(); }
|
|
|
|
inline bool bignum_lt(std::vector<uint8_t> const& a, std::vector<uint8_t> const& b) {
|
|
bool aNegative = (a.size() > 0) && (a[0] & 0x80);
|
|
bool bNegative = (b.size() > 0) && (b[0] & 0x80);
|
|
if (aNegative != bNegative) return aNegative;
|
|
if (aNegative) {
|
|
if (a.size() > b.size()) return true;
|
|
if (a.size() < b.size()) return false;
|
|
return a < b;
|
|
} else {
|
|
if (a.size() > b.size()) return false;
|
|
if (a.size() < b.size()) return true;
|
|
return a < b;
|
|
}
|
|
}
|
|
|
|
template <typename T>
|
|
bool operator<(Value<T> const& a, Value<T> const &b) {
|
|
auto aKind = a.value_kind();
|
|
auto bKind = b.value_kind();
|
|
if (aKind < bKind) return true;
|
|
if (bKind < aKind) return false;
|
|
switch (aKind) {
|
|
case ValueKind::Boolean: return a.to_bool() < b.to_bool();
|
|
case ValueKind::Float: return a.to_float() < b.to_float();
|
|
case ValueKind::Double: return a.to_double() < b.to_double();
|
|
case ValueKind::SignedInteger: {
|
|
if (auto av = a.as_signed()) {
|
|
if (auto bv = b.as_signed()) {
|
|
return *av < *bv;
|
|
} else {
|
|
return true;
|
|
}
|
|
} else {
|
|
if (auto bv = b.as_signed()) {
|
|
return false;
|
|
} else {
|
|
if (auto av = a.as_unsigned()) {
|
|
if (auto bv = b.as_unsigned()) {
|
|
return *av < *bv;
|
|
} else {
|
|
return true;
|
|
}
|
|
} else {
|
|
if (auto bv = b.as_unsigned()) {
|
|
return false;
|
|
} else {
|
|
return bignum_lt(a.to_bignum(), b.to_bignum());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
case ValueKind::String: return a.to_string() < b.to_string();
|
|
case ValueKind::ByteString: return a.to_bytes() < b.to_bytes();
|
|
case ValueKind::Symbol: return a.to_symbol() < b.to_symbol();
|
|
case ValueKind::Record: return a.to_record() < b.to_record();
|
|
case ValueKind::Sequence: return a.to_sequence() < b.to_sequence();
|
|
case ValueKind::Set: return a.to_set() < b.to_set();
|
|
case ValueKind::Dictionary: return a.to_dictionary() < b.to_dictionary();
|
|
case ValueKind::Embedded: return *a.to_embedded() < *b.to_embedded();
|
|
default: throw std::runtime_error("Invalid ValueKind");
|
|
}
|
|
}
|
|
}
|