#pragma once #include #include #include #include #include #include #include #include namespace Preserves { enum class ValueKind { Boolean, Float, Double, SignedInteger, String, ByteString, Symbol, Record, Sequence, Set, Dictionary, Embedded, }; template class Record; template class ValueImpl; template class Value { std::shared_ptr> p; public: Value(std::shared_ptr> const& p) : p(p) {} Value(ValueImpl *p) : p(p) {} std::shared_ptr> _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 const& v); static Value from_bytes(std::vector const& v); static Value from_bytes(void *p, size_t len); static Value from_symbol(std::string const& s); static Value record(Record const& r); static Value record(Value const& label, std::vector const& fields); static Value sequence(std::vector const& items); static Value set(std::set const& items); static Value dictionary(std::map const& entries); static Value from_embedded(std::shared_ptr 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 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 const& v) { return from_bytes(v); } static Value from(std::vector const& v) { return from_bytes(v); } static Value from(void *p, size_t len) { return from_bytes(p, len); } static Value from(Record const& r) { return record(r); } static Value from(Value const& label, std::vector const& fields) { return record(label, fields); } static Value from(std::vector const& items) { return sequence(items); } static Value from(std::set const& items) { return set(items); } static Value from(std::map const& entries) { return dictionary(entries); } ValueImpl& operator*() const { return *p; } ValueImpl* 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 as_bool() const; bool to_bool() const { return as_bool().value(); } boost::optional as_float() const; float to_float() const { return as_float().value(); } boost::optional as_double() const; double to_double() const { return as_double().value(); } boost::optional as_unsigned() const; uint64_t to_unsigned() const { return as_unsigned().value(); } boost::optional as_signed() const; int64_t to_signed() const { return as_signed().value(); } boost::optional const&> as_bignum() const; std::vector const& to_bignum() const { return as_bignum().value(); } boost::optional as_string() const; std::string const& to_string() const { return as_string().value(); } boost::optional const&> as_bytes() const; std::vector const& to_bytes() const { return as_bytes().value(); } boost::optional as_symbol() const; std::string const& to_symbol() const { return as_symbol().value(); } boost::optional const&> as_record() const; Record const& to_record() const { return as_record().value(); }; boost::optional const&> as_sequence() const; std::vector const& to_sequence() const { return as_sequence().value(); } boost::optional const&> as_set() const; std::set const& to_set() const { return as_set().value(); } boost::optional const&> as_dictionary() const; std::map const& to_dictionary() const { return as_dictionary().value(); } boost::optional> as_embedded() const; std::shared_ptr to_embedded() const { return as_embedded().value(); } boost::optional label() const; size_t size() const; bool contains(Value const& key) const; boost::optional get(Value const& key) const; Value operator[](Value const& key) const { return get(key).value(); } boost::optional get(size_t index) const; Value operator[](size_t index) const { return get(index).value(); } }; template class ValueImpl { public: virtual ~ValueImpl() {} virtual ValueKind value_kind() const = 0; virtual bool is_mutable() const { return false; } virtual boost::optional as_bool() const { return boost::none; } virtual boost::optional as_float() const { return boost::none; } virtual boost::optional as_double() const { return boost::none; } virtual boost::optional as_unsigned() const { return boost::none; } virtual boost::optional as_signed() const { return boost::none; } virtual boost::optional const&> as_bignum() const { return boost::none; } virtual boost::optional as_string() const { return boost::none; } virtual boost::optional const&> as_bytes() const { return boost::none; } virtual boost::optional as_symbol() const { return boost::none; } virtual boost::optional const&> as_record() const { return boost::none; } virtual boost::optional> const&> as_sequence() const { return boost::none; } virtual boost::optional> const&> as_set() const { return boost::none; } virtual boost::optional,Value> const&> as_dictionary() const { return boost::none; } virtual boost::optional> as_embedded() const { return boost::none; } virtual boost::optional> label() const { return boost::none; } virtual size_t size() const { return 0; } virtual bool contains(Value const& /* key */) const { return false; } virtual boost::optional> get(Value const& /* key */) const { return boost::none; } virtual boost::optional> get(size_t /* index */) const { return boost::none; } virtual bool add(Value const& /* item */) { throw std::runtime_error("Cannot add item to Preserves value"); } virtual bool set(Value const& /* key */, Value const& /* value */) { throw std::runtime_error("Cannot set item by key in Preserves value"); } virtual bool set(size_t /* index */, Value const& /* value */) { throw std::runtime_error("Cannot set item by index in Preserves value"); } virtual bool erase(Value const& /* key */) { throw std::runtime_error("Cannot erase item in Preserves value"); } }; template inline ValueKind Value::value_kind() const { return p->value_kind(); } template inline bool Value::is_mutable() const { return p->is_mutable(); } template class Atomic: public ValueImpl { protected: Atom value; public: Atomic(Atom const& value) : value(value) {} Atom& _value() { return value; } ValueKind value_kind() const { return kind; } }; #define PRESERVES_ATOMIC_VALUE_CLASS(Name, a_t, r_t, VK, getter, extra) \ template \ class Name: public Atomic { \ public: \ Name(a_t const& value) : Atomic(value) {} \ boost::optional getter() const override { return this->value; } \ extra \ } PRESERVES_ATOMIC_VALUE_CLASS(Boolean, bool, bool, ValueKind::Boolean, as_bool,); PRESERVES_ATOMIC_VALUE_CLASS(Float, float, float, ValueKind::Float, as_float, boost::optional as_double() const override { return this->value; }); PRESERVES_ATOMIC_VALUE_CLASS(Double, double, double, ValueKind::Double, as_double,); PRESERVES_ATOMIC_VALUE_CLASS(Uint64, uint64_t, uint64_t, ValueKind::SignedInteger, as_unsigned, boost::optional as_signed() const override { if (this->value <= uint64_t(std::numeric_limits::max())) { return this->value; } else { return boost::none; } } boost::optional as_float() const override { if (uint64_t(float(this->value)) == this->value) { return float(this->value); } else { return boost::none; } } boost::optional 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, boost::optional as_unsigned() const override { if (this->value >= 0) { return this->value; } else { return boost::none; } } boost::optional as_float() const override { if (int64_t(float(this->value)) == this->value) { return float(this->value); } else { return boost::none; } } boost::optional 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, std::vector const&, ValueKind::SignedInteger, as_bignum,); PRESERVES_ATOMIC_VALUE_CLASS(String, std::string, std::string const&, ValueKind::String, as_string,); PRESERVES_ATOMIC_VALUE_CLASS(ByteString, std::vector, std::vector const&, ValueKind::ByteString, as_bytes,); PRESERVES_ATOMIC_VALUE_CLASS(Symbol, std::string, std::string const&, ValueKind::Symbol, as_symbol,); template class Record: public ValueImpl { public: Value labelValue; std::vector> fields; Record(Value const& label) : labelValue(label), fields() {} Record(Value const& label, std::vector> const& fields) : labelValue(label), fields(fields) {} ValueKind value_kind() const { return ValueKind::Record; } boost::optional> label() const override { return labelValue; } size_t size() const { return fields.size(); } boost::optional> get(size_t index) const { if (index < size()) { return fields[index]; } else { return boost::none; } } bool add(Value const& value) override { fields.push_back(value); return true; } bool set(size_t index, Value const& value) override { if (index < size()) { fields[index] = value; } return false; } bool operator<(Record const& other) const { if (labelValue < other.labelValue) return true; if (other.labelValue < labelValue) return false; return fields < other.fields; } }; template class Sequence: public ValueImpl { public: std::vector> values; Sequence() : values() {} Sequence(std::vector> const& values) : values(values) {} ValueKind value_kind() const { return ValueKind::Sequence; } boost::optional> const&> as_sequence() const override { return values; } size_t size() const override { return values.size(); } boost::optional> get(size_t index) const override { if (index < size()) { return values[index]; } else { return boost::none; } } bool add(Value const& value) override { values.push_back(value); return true; } bool set(size_t index, Value const& value) override { if (index < size()) { values[index] = value; } return false; } }; template class Set: public ValueImpl { public: std::set> values; Set() : values() {} Set(std::set> const& values) : values(values) {} ValueKind value_kind() const { return ValueKind::Set; } boost::optional> const&> as_set() const override { return values; } size_t size() const override { return values.size(); } bool contains(Value const& key) const override { return values.count(key) > 0; } bool add(Value const& value) override { return values.insert(value).second; } bool erase(Value const& value) override { return values.erase(value) > 0; } }; template class Dictionary: public ValueImpl { public: std::map, Value> values; Dictionary() : values() {} Dictionary(std::map, Value> const& values) : values(values) {} ValueKind value_kind() const { return ValueKind::Dictionary; } boost::optional, Value> const&> as_dictionary() const override { return values; } size_t size() const override { return values.size(); } bool contains(Value const& key) const override { return values.count(key) > 0; } boost::optional> get(Value const& key) const override { auto i = values.find(key); if (i == values.end()) return boost::none; return i->second; } bool set(Value const& key, Value const& value) override { return values.emplace(key, value).second; } bool erase(Value const& key) override { return values.erase(key) > 0; } }; template class Embedded: public ValueImpl { public: std::shared_ptr value; Embedded(std::shared_ptr const& value) : value(value) {} ValueKind value_kind() const { return ValueKind::Embedded; } boost::optional> as_embedded() const override { return value; } }; class GenericEmbedded: public Value { public: GenericEmbedded(std::shared_ptr> p) : Value(p) {} static std::shared_ptr wrap(Value<> v) { return std::make_shared(v._impl()); } }; template Value Value::from_bool(bool b) { return Value(new Boolean(b)); } template Value Value::from_float(float f) { return Value(new Float(f)); } template Value Value::from_double(double d) { return Value(new Double(d)); } template Value Value::from_int(uint64_t i) { return Value(new Uint64(i)); } template Value Value::from_int(int64_t i) { return Value(new Int64(i)); } template Value Value::from_string(std::string const& s) { return Value(new String(s)); } template Value Value::sequence(std::vector> const& values) { return Value(new Sequence(values)); } template Value Value::from_embedded(std::shared_ptr const& v) { return Value(new Embedded(v)); } #define PRESERVES_DELEGATE_CAST(t, name) \ template boost::optional Value::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 const&, as_bignum); PRESERVES_DELEGATE_CAST(std::string const&, as_string); PRESERVES_DELEGATE_CAST(std::vector const&, as_bytes); PRESERVES_DELEGATE_CAST(std::string const&, as_symbol); PRESERVES_DELEGATE_CAST(Record const&, as_record); PRESERVES_DELEGATE_CAST(std::vector> const&, as_sequence); PRESERVES_DELEGATE_CAST(std::set> const&, as_set); #define COMMA , PRESERVES_DELEGATE_CAST(std::map COMMA Value> const&, as_dictionary); #undef COMMA PRESERVES_DELEGATE_CAST(std::shared_ptr, as_embedded); #undef PRESERVES_DELEGATE_CAST template boost::optional> Value::get(size_t index) const { return p->get(index); } template size_t Value::size() const { return p->size(); } bool bignum_lt(std::vector const& a, std::vector 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 bool operator<(Value const& a, Value 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"); } } }