#pragma once #include #include #include #include #include #include #include #include #include #include "schema.hpp" namespace saw { namespace encode { struct 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...>, encode::Native> { private: std::variant...> value_; public: data() = default; 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_); } }; template class data...>, encode::Native> { private: std::tuple...> value_; public: data() = default; SAW_DEFAULT_COPY(data); SAW_DEFAULT_MOVE(data); template data< typename parameter_pack_type< parameter_key_pack_index< literal, literals... >::value , T...>::type , encode::Native>& get(){ return std::get::value>(value_); } 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_); } constexpr size_t size() const { return sizeof...(T); } }; template class data, encode::Native> { private: std::tuple...> value_; public: data() = default; 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> { private: std::array dims_; std::vector> value_; uint64_t get_full_size() const { uint64_t s = 1; for(uint64_t iter = 0; iter < Dim; ++iter){ assert(dims_.at(iter) > 0); s *= dims_.at(iter); } return s; } public: data(){ std::fill(dims_.begin(), dims_.end(), 0u); value_.resize(get_full_size()); } SAW_DEFAULT_COPY(data); SAW_DEFAULT_MOVE(data); data(const std::array& i): dims_{i}, value_{} { 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({static_cast(i)...})); } template const data& at(Dims... i) const { return value_.at(this->get_flat_index({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(std::size_t i) const { return dims_.at(i); } size_t size() const { return value_.size();} data> get_dims() const { return {dims_}; } private: uint64_t get_flat_index(const std::array& i) const { return get_flat_index(data>{i}); } uint64_t get_flat_index(const data>& i) const { assert(value_.size() == get_full_size()); uint64_t s = 0; uint64_t stride = 1; for(uint64_t iter = 0; iter < Dim; ++iter){ assert(i.at(iter).get() < dims_.at(iter)); s += i.at(iter).get() * stride; stride *= dims_.at(iter); } return s; } }; template class data, encode::Native> { 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(const std::array::type, ct_multiply::value>& data) requires (is_primitive::value) { for(uint64_t i = 0; i < ct_multiply::value; ++i){ value_.at(i).set(data.at(i)); } } 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({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; } }; template<> class data { private: std::string value_; public: data() = default; SAW_DEFAULT_COPY(data); SAW_DEFAULT_MOVE(data); data(std::string value__):value_{std::move(value__)}{} data(std::size_t size_){ value_.resize(size_); } std::size_t size() const { return value_.size(); } void set(std::string str){ value_ = std::move(str); } char& at(size_t i) { return value_.at(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; } bool operator==(const std::string_view& val)const{ return value_ == val; } }; template class data, encode::Native> { private: typename native_data_type>::type value_; public: 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, encode::Native> operator*(const data, encode::Native>& rhs)const{ return {get() * rhs.get()}; } data, encode::Native> operator/(const data, encode::Native>& rhs)const{ return {get() / rhs.get()}; } data, encode::Native> operator+(const data, encode::Native>& rhs)const{ return {get() + rhs.get()}; } data, encode::Native> operator-(const data, encode::Native>& rhs)const{ return {get() - rhs.get()}; } template bool operator==(const data, Enc>& rhs)const{ return get() == rhs.get(); } template bool operator<(const data, Enc>& rhs) const { return get() < rhs.get(); } }; }