#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: 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_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(int64_t i) { return from_int(i); } static Value from(std::string 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 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 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: ValueImpl { protected: Atom value; public: Atomic(Atom value) : value(value) {} ValueKind value_kind() const { return kind; } }; #define PRESERVES_ATOMIC_VALUE_CLASS(Name, a_t, r_t, VK, getter, extra) \ template \ class Name: Atomic { \ 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,); 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; } }); 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; } }); 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: 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; } }; template class Sequence: 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: 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: 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: ValueImpl { public: std::shared_ptr value; Embedded(std::shared_ptr const& value) : value() {} ValueKind value_kind() const { return ValueKind::Embedded; } boost::optional> as_embedded() const override { return value; } }; }