Begin sketch of C++ implementation
This commit is contained in:
parent
fe12a8d775
commit
69010737b9
|
@ -0,0 +1,3 @@
|
|||
m.output.txt
|
||||
m
|
||||
.vscode
|
|
@ -0,0 +1,8 @@
|
|||
m: main.cpp preserves.hpp preserves_text.hpp
|
||||
gcc -Wall -Wextra -Werror -g3 -o $@ main.cpp
|
||||
|
||||
go: m
|
||||
cat ../../tests/samples.bin | ./m | tee m.output.txt
|
||||
|
||||
clean:
|
||||
rm -f m
|
|
@ -0,0 +1,5 @@
|
|||
#include "preserves.hpp"
|
||||
|
||||
int main() {
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,348 @@
|
|||
#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 Record;
|
||||
template <typename T> class ValueImpl;
|
||||
|
||||
template <typename T>
|
||||
class Value {
|
||||
std::shared_ptr<ValueImpl<T>> 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<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_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<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::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<Value> to_embedded() const { return as_embedded().value(); }
|
||||
|
||||
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(); }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class ValueImpl {
|
||||
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::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");
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T> inline ValueKind Value<T>::value_kind() const { return p->value_kind(); }
|
||||
template <typename T> inline bool Value<T>::is_mutable() const { return p->is_mutable(); }
|
||||
|
||||
template <typename T, typename Atom, ValueKind kind>
|
||||
class Atomic: ValueImpl<T> {
|
||||
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 <typename T> \
|
||||
class Name: Atomic<T, a_t, VK> { \
|
||||
boost::optional<r_t> 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<int64_t> as_signed() const override {
|
||||
if (this->value <= uint64_t(std::numeric_limits<int64_t>::max())) {
|
||||
return this->value;
|
||||
} else {
|
||||
return boost::none;
|
||||
}
|
||||
});
|
||||
PRESERVES_ATOMIC_VALUE_CLASS(Int64, int64_t, int64_t, ValueKind::SignedInteger, as_signed,
|
||||
boost::optional<uint64_t> 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<uint8_t>, std::vector<uint8_t> const&, ValueKind::ByteString, as_bytes,);
|
||||
PRESERVES_ATOMIC_VALUE_CLASS(Symbol, std::string, std::string const&, ValueKind::Symbol, as_symbol,);
|
||||
|
||||
template <typename T>
|
||||
class Record: 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;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class Sequence: 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;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class Set: 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;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class Dictionary: 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;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class Embedded: ValueImpl<T> {
|
||||
public:
|
||||
std::shared_ptr<T> value;
|
||||
|
||||
Embedded(std::shared_ptr<T> const& value) : value() {}
|
||||
ValueKind value_kind() const { return ValueKind::Embedded; }
|
||||
boost::optional<std::shared_ptr<T>> as_embedded() const override {
|
||||
return value;
|
||||
}
|
||||
};
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "preserves.hpp"
|
||||
|
||||
namespace Preserves {
|
||||
template <typename T>
|
||||
class TextReader {
|
||||
public:
|
||||
TextReader(std::istream& i);
|
||||
};
|
||||
}
|
Loading…
Reference in New Issue