#pragma once #include #include #include #include #include #include #include #include namespace Preserves { enum class ValueKind { Boolean, 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_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(double d) { return from_double(d); } static Value from(bool b) { return from_bool(b); } 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_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_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(); } Value annotate(Value const& ann) const; boost::optional const&> annotations() const; 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(); } }; class BinaryWriter; // forward declaration; see preserves_binary_writer.hpp template class ValueImpl { protected: virtual Value internal_annotate(std::shared_ptr> const& self, Value const& ann); friend class Value; 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_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"); } virtual boost::optional> const&> annotations() const { return boost::none; } virtual BinaryWriter& write(BinaryWriter& w) const = 0; }; template ValueKind Value::value_kind() const { return p->value_kind(); } template bool Value::is_mutable() const { return p->is_mutable(); } #define PRESERVES_DELEGATE_CAST(t, name) \ template boost::optional Value::name() const { return p->name(); } PRESERVES_DELEGATE_CAST(bool, as_bool); 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::label() const { return p->label(); } template bool Value::contains(Value const& key) const { return p->contains(key); } template boost::optional> Value::get(Value const& key) const { return p->get(key); } template boost::optional> Value::get(size_t index) const { return p->get(index); } template size_t Value::size() const { return p->size(); } inline 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::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"); } } }