#pragma once #include #include #include #include #include #include #include #include #include #include #include "schema.hpp" #include "schema_meta.hpp" namespace saw { namespace encode { struct Native { static constexpr string_literal name = "encode::Native"; }; } template class codec; /* * Helper for the basic message container, so the class doesn't have to be * specialized 10 times. */ template struct native_data_type; template <> struct native_data_type> { using type = int8_t; }; template <> struct native_data_type> { using type = int16_t; }; template <> struct native_data_type> { using type = int32_t; }; template <> struct native_data_type> { using type = int64_t; }; template <> struct native_data_type> { using type = uint8_t; }; template <> struct native_data_type> { using type = uint16_t; }; template <> struct native_data_type> { using type = uint32_t; }; template <> struct native_data_type> { using type = uint64_t; }; template <> struct native_data_type> { using type = float; }; template <> struct native_data_type> { using type = double; }; template class data { private: static_assert(always_false, "Type not supported."); }; template<> class data { public: using Schema = schema::Void; using MetaSchema = schema::Void; }; template<> class data { public: using Schema = schema::Bool; using MetaSchema = schema::Void; private: bool value_; public: data():value_{false}{} data(data):value_{false}{} SAW_DEFAULT_COPY(data); SAW_DEFAULT_MOVE(data); void set(bool val){ value_ = val; } bool get() const { return value_; } }; template class data, encode::Native> { public: using Schema = schema::Primitive; using MetaSchema = typename meta_schema::MetaSchema; private: typename native_data_type::type value_; public: data():value_{}{} data(data):value_{}{} SAW_DEFAULT_COPY(data); SAW_DEFAULT_MOVE(data); data(typename native_data_type::type value__): value_{std::move(value__)}{} void set(typename native_data_type::type val){ value_ = val; } typename native_data_type::type get() const {return value_;} data operator*(const data& rhs)const{ return {get() * rhs.get()}; } data operator/(const data& rhs)const{ return {get() / rhs.get()}; } data operator+(const data& rhs)const{ return {get() + rhs.get()}; } data& operator+=(const data& rhs)const{ value_ += rhs.get(); return *this; } data& operator-=(const data& rhs)const{ value_ -= rhs.get(); return *this; } data operator-(const data& rhs)const{ return {get() - rhs.get()}; } template bool operator==(const data& rhs)const{ return get() == rhs.get(); } template bool operator<(const data& rhs) const { return get() < rhs.get(); } /** * Casts */ template data cast_to() const { auto raw_to = static_cast::type>(value_); return {raw_to}; } }; /** * Mixed precision class for native formats */ template class data, schema::Primitive>, encode::Native>{ public: using Schema = schema::MixedPrecision, schema::Primitive>; using MetaSchema = typename meta_schema::MetaSchema; private: data value_; public: data():value_{}{} data(data):value_{}{} data(typename saw::native_data_type::type val__):value_{static_cast::type>(val__)}{} typename saw::native_data_type::type get() const { return value_.template cast_to().get(); } data(const saw::data& val){ value_ = val.template cast_to(); } void set(typename saw::native_data_type::type val){ value_.set(static_cast(val)); } data operator*(const data& rhs) const { using CalcType = typename native_data_type::type; CalcType left = static_cast(value_.get()); CalcType right = static_cast(rhs.get()); return {left * right}; } data operator*(const data& rhs) const { using CalcType = typename native_data_type::type; CalcType left = static_cast(value_.get()); CalcType right = rhs.get(); return {left * right}; } data operator/(const data& rhs)const{ using CalcType = typename native_data_type::type; CalcType left = static_cast(value_.get()); CalcType right = static_cast(rhs.get()); return {left / right}; } data operator+(const data& rhs)const{ using CalcType = typename native_data_type::type; CalcType left = static_cast(value_.get()); CalcType right = static_cast(rhs.get()); return {left + right}; } data& operator+=(const data& rhs)const{ *this = *this + rhs.get(); return *this; } data operator-(const data& rhs)const{ using CalcType = typename native_data_type::type; CalcType left = static_cast(value_.get()); CalcType right = static_cast(rhs.get()); return {left - right}; } data& operator-=(const data& rhs) const { *this = *this - rhs.get(); return *this; } template bool operator==(const data& rhs)const{ return get() == rhs.get(); } template bool operator<(const data& rhs) const { return get() < rhs.get(); } }; /* template class data>, encode::Native { public: using Schema = schema::Ref>; private: ref>::type> orig_; public: data(ref>::type> orig__): orig_{orig__} {} /// @TODO what do we really want to return? data, encode::Native> operator+(const data& rhs) const { data> prim; return prim; } }; */ /** * Union type for native data classes */ template class data...>, encode::Native> { public: using Schema = schema::Union...>; using MetaSchema = typename meta_schema::MetaSchema; private: std::variant...> value_; template struct init_helper { static void apply(std::variant...>& val, data&& init){ if( init.index() == i ){ auto& val_i = val.template init(); val_i = {std::move(init.template get())}; return; } if constexpr ( (i+1u) < sizeof...(T) ){ init_helper::apply(val, init); } } }; public: data() = default; data(data init){ if constexpr ( 0u < sizeof...(T) ){ init_helper<0u>::apply(value_, std::move(init)); } } SAW_DEFAULT_COPY(data); SAW_DEFAULT_MOVE(data); template void set(data::value, T...>::type, encode::Native> val){ value_ = std::move(val); } template data::value, T...>::type, encode::Native>& init(){ value_.template emplace::value>(); return get(); } template bool holds_alternative() const { return (parameter_key_pack_index::value == value_.index()); } template data::value, T...>::type, encode::Native>& get(){ return std::get::value>(value_); } template const data::value, T...>::type, encode::Native>& get() const{ return std::get::value>(value_); } }; /** * Data class which represents a struct in the native format. */ template class data...>, encode::Native> { public: using Schema = schema::Struct...>; using MetaSchema = typename meta_schema::MetaSchema; private: /** * Tuple storing the member values. */ std::tuple...> value_; template struct init_helper { static void apply(std::tuple...>& val, data&& init){ auto& val_i = val.template get(); auto& init_i = init.template get(); val_i = {std::move(init_i)}; if constexpr ( (i+1u) < sizeof...(T) ){ init_helper::apply(val, init); } } }; public: /** * Default constructor. */ data() = default; data(data init){ if constexpr ( 0u < sizeof...(T) ){ init_helper<0u>::apply(value_, std::move(init)); } } SAW_DEFAULT_COPY(data); SAW_DEFAULT_MOVE(data); /** * Get the member value based on the string_literal. */ template data< typename parameter_pack_type< parameter_key_pack_index< literal, literals... >::value , T...>::type , encode::Native>& get(){ return std::get::value>(value_); } /** * Get the member value based on the string_literal. */ template const data< typename parameter_pack_type< parameter_key_pack_index< literal, literals... >::value , T...>::type , encode::Native>& get() const { return std::get::value>(value_); } /** * Return the amount of members. */ constexpr size_t size() const { return sizeof...(T); } }; template class data, encode::Native> { public: using Schema = schema::Tuple; using MetaSchema = typename meta_schema::MetaSchema; private: std::tuple...> value_; template struct init_helper { static void apply(std::tuple...>& val, data&& init){ auto& val_i = val.template get(); auto& init_i = init.template get(); val_i = {std::move(init_i)}; if constexpr ( (i+1u) < sizeof...(T) ){ init_helper::apply(val, init); } } }; public: data() = default; data(data init){ if constexpr ( 0u < sizeof...(T) ){ init_helper<0u>::apply(value_, std::move(init)); } } SAW_DEFAULT_COPY(data); SAW_DEFAULT_MOVE(data); template data::type, encode::Native>& get(){ return std::get(value_); } template const data::type, encode::Native>& get() const{ return std::get(value_); } constexpr size_t size() const { return sizeof...(T); } }; template class data, encode::Native> { public: using Schema = schema::Map; using MetaSchema = typename meta_schema::MetaSchema; private: std::map, data> vals_; public: data() = default; SAW_DEFAULT_COPY(data); SAW_DEFAULT_MOVE(data); data(data init){} error_or emplace(ref> key, ref> value){ auto insert = vals_.emplace(std::make_pair(std::move(key()), std::move(value()))); if(!insert.second){ return make_error(); } return make_void(); } error_or erase(ref> key){ auto erase = vals_.erase(key()); if(erase == 0u){ return make_error(); } return make_void(); } error_or>> find(ref> key){ auto find = vals_.find(key()); if(find == vals_.end()){ return make_error(); } return ptr>{find->second}; } }; template class data, encode::Native> { public: using Schema = schema::Array; using MetaSchema = typename meta_schema::MetaSchema; private: // data> dims_; std::array dims_; std::vector> value_; uint64_t get_full_size() const { uint64_t s = 1; for(uint64_t iter = 0; iter < Dim; ++iter){ s *= dims_.at(iter); } return s; } public: data(): value_{} { for(auto& iter : dims_){ iter = 0u; } } SAW_DEFAULT_COPY(data); SAW_DEFAULT_MOVE(data); data(const std::array& i): dims_{i}, value_{} { value_.resize(get_full_size()); } data(data init) { for(uint64_t i = 0; i < Dim; ++i){ dims_.at(i) = init.at(i).get(); } value_.resize(get_full_size()); } template error_or add(saw::data data){ /** @todo * Generally the last dimension can always accept a element so to say. * Changing the others would require moving data due to the stride changing. * Since the last dimension doesn't affect the stride, we don't need reordering there. * But I want a quick solution for one dimension so here we are. * * I can always ignore strides and use a stacked std::vector * std::vector> and so on. * But for now I'm keeping the strides. Smaller chunks of memory aren't to bad either * though. * I'll probably change it to the smaller chunks */ static_assert(Dim == 1, "Currently can't deal with higher dims"); static_assert(i < Dim, "Can't add to dimension. Index i larger than dimension size"); try { value_.emplace_back(std::move(data)); }catch(const std::exception& e){ (void) e; return make_error(); } ++dims_.at(i); return void_t{}; } template data(Dims... size_): data{{static_cast(size_)...}} { static_assert(sizeof...(Dims)==Dim, "Argument size must be equal to the Dimension"); } data& at(const std::array& ind){ return value_.at(this->get_flat_index(ind)); } const data& at(const std::array& ind) const { return value_.at(this->get_flat_index(ind)); } template data& at(Dims... i){ return value_.at(this->get_flat_index(std::array{static_cast(i)...})); } template const data& at(Dims... i) const { return value_.at(this->get_flat_index(std::array{static_cast(i)...})); } data& at(const data>& i){ return value_.at(this->get_flat_index(i)); } const data& at(const data>& i)const{ return value_.at(this->get_flat_index(i)); } std::size_t get_dim_size(uint64_t i) const { return dims_.at(i); } size_t size() const { return value_.size();} data> get_dims() const { return {dims_}; } private: template uint64_t get_flat_index(const U& i) const { static_assert( std::is_same_v>> or std::is_same_v>, "Unsupported type" ); assert(value_.size() == get_full_size()); uint64_t s = 0; uint64_t stride = 1; for(uint64_t iter = 0; iter < Dim; ++iter){ uint64_t ind = [](auto val) -> uint64_t { using V = std::decay_t; if constexpr (std::is_same_v>){ return val.get(); }else if constexpr (std::is_same_v){ return val; }else{ static_assert(always_false, "Cases exhausted"); } }(i.at(iter)); assert(ind < dims_.at(iter)); s += ind * stride; stride *= dims_.at(iter); } return s; } }; template class data, encode::Native> { public: using Schema = schema::FixedArray; using MetaSchema = typename meta_schema::MetaSchema; private: //using inner_type = std::array, multiply_helper::value>; //std::unique_ptr value_; using ArrayT = std::array, ct_multiply::value>; ArrayT value_; public: data() = default; data(data){} data(const std::array, ct_multiply::value>& value__): value_{value__} {} data& at(const std::array& ind){ return value_.at(this->get_flat_index(ind)); } const data& at(const std::array& ind) const { return value_.at(this->get_flat_index(ind)); } template data& at(data... i) { return value_.at(this->get_flat_index({i...})); } template const data& at(data... i) const { return value_.at(this->get_flat_index({i...})); } template data& at(Dims... i) { return value_.at(this->get_flat_index({i...})); } template const data& at(Dims... i) const { return value_.at(this->get_flat_index({i...})); } data& at(const data>& i){ return value_.at(this->get_flat_index(i)); } const data& at(const data>& i)const{ return value_.at(this->get_flat_index(i)); } template uint64_t get_dim_size() const { return parameter_pack_value::value; } data> get_dims() const { return {std::array{D...}}; } private: uint64_t get_flat_index(const std::array& i) const { uint64_t s = 0; uint64_t stride = 1; constexpr static std::array dims_{D...}; for(uint64_t iter = 0; iter < sizeof...(D); ++iter){ assert(i.at(iter) < dims_.at(iter)); s += i.at(iter) * stride; stride *= dims_.at(iter); } return s; } }; /** * Data type representing string. */ template<> class data { public: using Schema = schema::String; using MetaSchema = typename meta_schema::MetaSchema; private: /** * The native way to represent strings. */ std::string value_; public: data() = default; data(uint64_t size__){ value_.resize(size__); } data(data init){ value_.resize(init.get()); } SAW_DEFAULT_COPY(data); SAW_DEFAULT_MOVE(data); data(std::string value__):value_{std::move(value__)}{} /** * Return the length of the string. */ std::size_t size() const { return value_.size(); } /** * set the inner string to str. */ void set(std::string str){ value_ = std::move(str); } /** * Get a char reference at position i. */ char& at(size_t i) { return value_.at(i); } /** * Get a char reference at position i. */ const char& at(size_t i) const { return value_.at(i); } char get_at(size_t i) const{ return value_.at(i); } void set_at(size_t i, char val){ value_.at(i) = val; } std::string_view stl_view() { return value_; } std::string stl_string() const { return value_; } template bool operator==(const data& rhs) const { if(size() != rhs.size()){ return false; } bool eq = true; for(uint64_t i = 0; i < size(); ++i){ eq = eq && (get_at(i) == rhs.get_at(i)); } return eq; } /** * Check if a string_view is equal to this type. */ bool operator==(const std::string_view& val)const{ return value_ == val; } }; }