2023-06-23 13:40:05 +00:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <memory>
|
|
|
|
#include <cstdint>
|
|
|
|
#include <string>
|
|
|
|
#include <vector>
|
|
|
|
#include <map>
|
|
|
|
#include <set>
|
|
|
|
#include <limits>
|
|
|
|
|
|
|
|
#include <boost/optional.hpp>
|
|
|
|
|
|
|
|
namespace Preserves {
|
|
|
|
template <typename T, typename Atom, ValueKind kind>
|
|
|
|
class Atomic: public ValueImpl<T> {
|
|
|
|
protected:
|
|
|
|
Atom value;
|
|
|
|
public:
|
|
|
|
Atomic(Atom const& value) : value(value) {}
|
|
|
|
Atom& _value() { return value; }
|
|
|
|
Atom const& _value() const { return value; }
|
|
|
|
ValueKind value_kind() const { return kind; }
|
|
|
|
};
|
|
|
|
|
|
|
|
#define PRESERVES_ATOMIC_VALUE_CLASS(Name, a_t, r_t, VK, getter, extra) \
|
|
|
|
template <typename T = class GenericEmbedded> \
|
|
|
|
class Name: public Atomic<T, a_t, VK> { \
|
|
|
|
public: \
|
|
|
|
Name(a_t const& value) : Atomic<T, a_t, VK>(value) {} \
|
|
|
|
boost::optional<r_t> getter() const override { return this->value; } \
|
|
|
|
extra \
|
|
|
|
}
|
|
|
|
|
|
|
|
PRESERVES_ATOMIC_VALUE_CLASS(Boolean, bool, bool, ValueKind::Boolean, as_bool,
|
|
|
|
BinaryWriter& write(BinaryWriter& w) const override {
|
|
|
|
return w << this->_value();
|
|
|
|
});
|
|
|
|
PRESERVES_ATOMIC_VALUE_CLASS(Float, float, float, ValueKind::Float, as_float,
|
|
|
|
BinaryWriter& write(BinaryWriter& w) const override {
|
|
|
|
return w << this->_value();
|
|
|
|
}
|
|
|
|
boost::optional<double> as_double() const override {
|
|
|
|
return this->value;
|
|
|
|
});
|
|
|
|
PRESERVES_ATOMIC_VALUE_CLASS(Double, double, double, ValueKind::Double, as_double,
|
|
|
|
BinaryWriter& write(BinaryWriter& w) const override {
|
|
|
|
return w << this->_value();
|
|
|
|
});
|
|
|
|
PRESERVES_ATOMIC_VALUE_CLASS(Uint64, uint64_t, uint64_t, ValueKind::SignedInteger, as_unsigned,
|
|
|
|
BinaryWriter& write(BinaryWriter& w) const override {
|
|
|
|
return w << this->_value();
|
|
|
|
}
|
|
|
|
boost::optional<int64_t> as_signed() const override {
|
|
|
|
if (this->value <= uint64_t(std::numeric_limits<int64_t>::max())) {
|
|
|
|
return this->value;
|
|
|
|
} else {
|
|
|
|
return boost::none;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
boost::optional<float> as_float() const override {
|
|
|
|
if (uint64_t(float(this->value)) == this->value) {
|
|
|
|
return float(this->value);
|
|
|
|
} else {
|
|
|
|
return boost::none;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
boost::optional<double> as_double() const override {
|
|
|
|
if (uint64_t(double(this->value)) == this->value) {
|
|
|
|
return double(this->value);
|
|
|
|
} else {
|
|
|
|
return boost::none;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
PRESERVES_ATOMIC_VALUE_CLASS(Int64, int64_t, int64_t, ValueKind::SignedInteger, as_signed,
|
|
|
|
BinaryWriter& write(BinaryWriter& w) const override {
|
|
|
|
return w << this->_value();
|
|
|
|
}
|
|
|
|
boost::optional<uint64_t> as_unsigned() const override {
|
|
|
|
if (this->value >= 0) {
|
|
|
|
return this->value;
|
|
|
|
} else {
|
|
|
|
return boost::none;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
boost::optional<float> as_float() const override {
|
|
|
|
if (int64_t(float(this->value)) == this->value) {
|
|
|
|
return float(this->value);
|
|
|
|
} else {
|
|
|
|
return boost::none;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
boost::optional<double> as_double() const override {
|
|
|
|
if (int64_t(double(this->value)) == this->value) {
|
|
|
|
return double(this->value);
|
|
|
|
} else {
|
|
|
|
return boost::none;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
PRESERVES_ATOMIC_VALUE_CLASS(BigNum, std::vector<uint8_t>, std::vector<uint8_t> const&, ValueKind::SignedInteger, as_bignum,
|
|
|
|
BinaryWriter& write(BinaryWriter& w) const override {
|
|
|
|
return w.bignum(this->_value());
|
|
|
|
});
|
|
|
|
PRESERVES_ATOMIC_VALUE_CLASS(String, std::string, std::string const&, ValueKind::String, as_string,
|
|
|
|
BinaryWriter& write(BinaryWriter& w) const override {
|
|
|
|
return w.string(this->_value());
|
|
|
|
});
|
|
|
|
PRESERVES_ATOMIC_VALUE_CLASS(ByteString, std::vector<uint8_t>, std::vector<uint8_t> const&, ValueKind::ByteString, as_bytes,
|
|
|
|
BinaryWriter& write(BinaryWriter& w) const override {
|
|
|
|
return w.bytes(this->_value());
|
|
|
|
});
|
|
|
|
PRESERVES_ATOMIC_VALUE_CLASS(Symbol, std::string, std::string const&, ValueKind::Symbol, as_symbol,
|
|
|
|
BinaryWriter& write(BinaryWriter& w) const override {
|
|
|
|
return w.symbol(this->_value());
|
|
|
|
});
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
class Record: public ValueImpl<T> {
|
|
|
|
public:
|
|
|
|
Value<T> labelValue;
|
|
|
|
std::vector<Value<T>> fields;
|
|
|
|
|
|
|
|
Record(Value<T> const& label) : labelValue(label), fields() {}
|
|
|
|
Record(Value<T> const& label, std::vector<Value<T>> const& fields) : labelValue(label), fields(fields) {}
|
|
|
|
ValueKind value_kind() const { return ValueKind::Record; }
|
|
|
|
boost::optional<Value<T>> label() const override { return labelValue; }
|
|
|
|
size_t size() const { return fields.size(); }
|
|
|
|
boost::optional<Value<T>> get(size_t index) const {
|
|
|
|
if (index < size()) {
|
|
|
|
return fields[index];
|
|
|
|
} else {
|
|
|
|
return boost::none;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
bool add(Value<T> const& value) override {
|
|
|
|
fields.push_back(value);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
bool set(size_t index, Value<T> const& value) override {
|
|
|
|
if (index < size()) {
|
|
|
|
fields[index] = value;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
bool operator<(Record<T> const& other) const {
|
|
|
|
if (labelValue < other.labelValue) return true;
|
|
|
|
if (other.labelValue < labelValue) return false;
|
|
|
|
return fields < other.fields;
|
|
|
|
}
|
|
|
|
BinaryWriter& write(BinaryWriter& w) const override {
|
|
|
|
return w.record(labelValue, fields);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
template <typename T = class GenericEmbedded>
|
|
|
|
class Sequence: public ValueImpl<T> {
|
|
|
|
public:
|
|
|
|
std::vector<Value<T>> values;
|
|
|
|
|
|
|
|
Sequence() : values() {}
|
|
|
|
Sequence(std::vector<Value<T>> const& values) : values(values) {}
|
|
|
|
ValueKind value_kind() const { return ValueKind::Sequence; }
|
|
|
|
boost::optional<std::vector<Value<T>> const&> as_sequence() const override {
|
|
|
|
return values;
|
|
|
|
}
|
|
|
|
size_t size() const override { return values.size(); }
|
|
|
|
boost::optional<Value<T>> get(size_t index) const override {
|
|
|
|
if (index < size()) {
|
|
|
|
return values[index];
|
|
|
|
} else {
|
|
|
|
return boost::none;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
bool add(Value<T> const& value) override {
|
|
|
|
values.push_back(value);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
bool set(size_t index, Value<T> const& value) override {
|
|
|
|
if (index < size()) {
|
|
|
|
values[index] = value;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
BinaryWriter& write(BinaryWriter& w) const override {
|
|
|
|
return w.sequence(values);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
template <typename T = class GenericEmbedded>
|
|
|
|
class Set: public ValueImpl<T> {
|
|
|
|
public:
|
|
|
|
std::set<Value<T>> values;
|
|
|
|
|
|
|
|
Set() : values() {}
|
|
|
|
Set(std::set<Value<T>> const& values) : values(values) {}
|
|
|
|
ValueKind value_kind() const { return ValueKind::Set; }
|
|
|
|
boost::optional<std::set<Value<T>> const&> as_set() const override {
|
|
|
|
return values;
|
|
|
|
}
|
|
|
|
size_t size() const override { return values.size(); }
|
|
|
|
bool contains(Value<T> const& key) const override { return values.count(key) > 0; }
|
|
|
|
bool add(Value<T> const& value) override {
|
|
|
|
return values.insert(value).second;
|
|
|
|
}
|
|
|
|
bool erase(Value<T> const& value) override {
|
|
|
|
return values.erase(value) > 0;
|
|
|
|
}
|
|
|
|
BinaryWriter& write(BinaryWriter& w) const override {
|
|
|
|
return w.set(values);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
template <typename T = class GenericEmbedded>
|
|
|
|
class Dictionary: public ValueImpl<T> {
|
|
|
|
public:
|
|
|
|
std::map<Value<T>, Value<T>> values;
|
|
|
|
|
|
|
|
Dictionary() : values() {}
|
|
|
|
Dictionary(std::map<Value<T>, Value<T>> const& values) : values(values) {}
|
|
|
|
ValueKind value_kind() const { return ValueKind::Dictionary; }
|
|
|
|
boost::optional<std::map<Value<T>, Value<T>> const&> as_dictionary() const override {
|
|
|
|
return values;
|
|
|
|
}
|
|
|
|
size_t size() const override { return values.size(); }
|
|
|
|
bool contains(Value<T> const& key) const override { return values.count(key) > 0; }
|
|
|
|
boost::optional<Value<T>> get(Value<T> const& key) const override {
|
|
|
|
auto i = values.find(key);
|
|
|
|
if (i == values.end()) return boost::none;
|
|
|
|
return i->second;
|
|
|
|
}
|
|
|
|
bool set(Value<T> const& key, Value<T> const& value) override {
|
|
|
|
return values.emplace(key, value).second;
|
|
|
|
}
|
|
|
|
bool erase(Value<T> const& key) override {
|
|
|
|
return values.erase(key) > 0;
|
|
|
|
}
|
|
|
|
BinaryWriter& write(BinaryWriter& w) const override {
|
|
|
|
return w.dictionary(values);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
template <typename T = class GenericEmbedded>
|
|
|
|
class Embedded: public ValueImpl<T> {
|
|
|
|
public:
|
|
|
|
std::shared_ptr<T> value;
|
|
|
|
|
|
|
|
Embedded(std::shared_ptr<T> const& value) : value(value) {}
|
|
|
|
ValueKind value_kind() const { return ValueKind::Embedded; }
|
|
|
|
boost::optional<std::shared_ptr<T>> as_embedded() const override {
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
BinaryWriter& write(BinaryWriter& w) const override {
|
|
|
|
w << BinaryTag::Embedded;
|
|
|
|
return value->write(w);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
class GenericEmbedded: public Value<GenericEmbedded> {
|
|
|
|
public:
|
|
|
|
GenericEmbedded(std::shared_ptr<ValueImpl<GenericEmbedded>> p) :
|
|
|
|
Value(p)
|
|
|
|
{}
|
|
|
|
|
|
|
|
static std::shared_ptr<GenericEmbedded> wrap(Value<> v) {
|
|
|
|
return std::make_shared<GenericEmbedded>(v._impl());
|
|
|
|
}
|
|
|
|
|
|
|
|
BinaryWriter& write(BinaryWriter& w) const {
|
|
|
|
return (*this)->write(w);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2023-06-23 14:54:19 +00:00
|
|
|
template <typename T>
|
|
|
|
class AnnotatedValue: public ValueImpl<T> {
|
|
|
|
std::vector<Value<T>> anns;
|
2023-06-23 20:28:31 +00:00
|
|
|
Value<T> underlying;
|
2023-06-23 14:54:19 +00:00
|
|
|
|
|
|
|
friend class ValueImpl<T>;
|
|
|
|
|
|
|
|
protected:
|
|
|
|
Value<T> internal_annotate(std::shared_ptr<ValueImpl<T>> const& self, Value<T> const &ann) {
|
|
|
|
if (self.use_count() == 1) {
|
|
|
|
anns.push_back(ann);
|
|
|
|
return self;
|
|
|
|
} else {
|
2023-06-23 20:28:31 +00:00
|
|
|
auto a = std::make_shared<AnnotatedValue<T>>(std::vector<Value<T>>(anns), underlying);
|
2023-06-23 14:54:19 +00:00
|
|
|
a->anns.push_back(ann);
|
|
|
|
return Value<T>(a);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public:
|
2023-06-23 20:28:31 +00:00
|
|
|
AnnotatedValue(std::vector<Value<T>> &&anns, Value<T> const& v) : anns(anns), underlying(v) {}
|
2023-06-23 14:54:19 +00:00
|
|
|
|
|
|
|
ValueKind value_kind() const override { return underlying.value_kind(); }
|
|
|
|
bool is_mutable() const override { return underlying.is_mutable(); }
|
|
|
|
|
|
|
|
boost::optional<bool> as_bool() const override { return underlying.as_bool(); }
|
|
|
|
boost::optional<float> as_float() const override { return underlying.as_float(); }
|
|
|
|
boost::optional<double> as_double() const override { return underlying.as_double(); }
|
|
|
|
boost::optional<uint64_t> as_unsigned() const override { return underlying.as_unsigned(); }
|
|
|
|
boost::optional<int64_t> as_signed() const override { return underlying.as_signed(); }
|
|
|
|
boost::optional<std::vector<uint8_t> const&> as_bignum() const override { return underlying.as_bignum(); }
|
|
|
|
boost::optional<std::string const&> as_string() const override { return underlying.as_string(); }
|
|
|
|
boost::optional<std::vector<uint8_t> const&> as_bytes() const override { return underlying.as_bytes(); }
|
|
|
|
boost::optional<std::string const&> as_symbol() const override { return underlying.as_symbol(); }
|
|
|
|
boost::optional<Record<T> const&> as_record() const override { return underlying.as_record(); }
|
|
|
|
boost::optional<std::vector<Value<T>> const&> as_sequence() const override { return underlying.as_sequence(); }
|
|
|
|
boost::optional<std::set<Value<T>> const&> as_set() const override { return underlying.as_set(); }
|
|
|
|
boost::optional<std::map<Value<T>,Value<T>> const&> as_dictionary() const override { return underlying.as_dictionary(); }
|
|
|
|
boost::optional<std::shared_ptr<T>> as_embedded() const override { return underlying.as_embedded(); }
|
|
|
|
|
|
|
|
boost::optional<Value<T>> label() const override { return underlying.label(); }
|
|
|
|
size_t size() const override { return underlying.size(); }
|
|
|
|
bool contains(Value<T> const& key) const override { return underlying.contains(key); }
|
|
|
|
boost::optional<Value<T>> get(Value<T> const& key) const override { return underlying.get(key); }
|
|
|
|
boost::optional<Value<T>> get(size_t index) const override { return underlying.get(index); }
|
|
|
|
|
|
|
|
bool add(Value<T> const& item) override {
|
|
|
|
return underlying->add(item);
|
|
|
|
}
|
|
|
|
bool set(Value<T> const& key, Value<T> const& value) override {
|
|
|
|
return underlying->set(key, value);
|
|
|
|
}
|
|
|
|
bool set(size_t index, Value<T> const& value) override {
|
|
|
|
return underlying->set(index, value);
|
|
|
|
}
|
|
|
|
bool erase(Value<T> const& key) override {
|
|
|
|
return underlying->erase(key);
|
|
|
|
}
|
|
|
|
|
|
|
|
boost::optional<std::vector<Value<T>> const&> annotations() const override {
|
|
|
|
return anns;
|
|
|
|
}
|
|
|
|
|
|
|
|
BinaryWriter& write(BinaryWriter &w) const override {
|
2023-10-14 19:29:09 +00:00
|
|
|
return w.annotated(underlying, anns);
|
2023-06-23 14:54:19 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
Value<T> Value<T>::annotate(Value<T> const& ann) const {
|
|
|
|
return p->internal_annotate(p, ann);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
Value<T> ValueImpl<T>::internal_annotate(std::shared_ptr<ValueImpl<T>> const& self, Value<T> const &ann) {
|
2023-06-23 20:28:31 +00:00
|
|
|
auto a = std::make_shared<AnnotatedValue<T>>(std::vector<Value<T>>(), Value<T>(self));
|
2023-06-23 14:54:19 +00:00
|
|
|
a->anns.push_back(ann);
|
|
|
|
return Value<T>(a);
|
|
|
|
}
|
|
|
|
|
2023-06-23 13:40:05 +00:00
|
|
|
template <typename T>
|
|
|
|
Value<T> Value<T>::from_bool(bool b)
|
|
|
|
{
|
|
|
|
return Value<T>(new Boolean<T>(b));
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
Value<T> Value<T>::from_float(float f)
|
|
|
|
{
|
|
|
|
return Value<T>(new Float<T>(f));
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
Value<T> Value<T>::from_double(double d)
|
|
|
|
{
|
|
|
|
return Value<T>(new Double<T>(d));
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
Value<T> Value<T>::from_int(uint64_t i)
|
|
|
|
{
|
|
|
|
return Value<T>(new Uint64<T>(i));
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
Value<T> Value<T>::from_int(int64_t i) {
|
|
|
|
return Value<T>(new Int64<T>(i));
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
Value<T> Value<T>::from_string(std::string const& s) {
|
|
|
|
return Value<T>(new String<T>(s));
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
Value<T> Value<T>::sequence(std::vector<Value<T>> const& values) {
|
|
|
|
return Value<T>(new Sequence<T>(values));
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
Value<T> Value<T>::from_embedded(std::shared_ptr<T> const& v) {
|
|
|
|
return Value<T>(new Embedded<T>(v));
|
|
|
|
}
|
2023-06-23 14:54:19 +00:00
|
|
|
}
|