diff options
Diffstat (limited to 'modules/codec/c++/data.hpp')
-rw-r--r-- | modules/codec/c++/data.hpp | 451 |
1 files changed, 451 insertions, 0 deletions
diff --git a/modules/codec/c++/data.hpp b/modules/codec/c++/data.hpp new file mode 100644 index 0000000..3aebc89 --- /dev/null +++ b/modules/codec/c++/data.hpp @@ -0,0 +1,451 @@ +#pragma once + +#include <forstio/common.h> +#include <forstio/error.h> +#include <forstio/templates.h> + +#include <cassert> + +#include <array> +#include <concepts> +#include <variant> +#include <vector> + +#include "schema.hpp + +namespace saw { +namespace encode { +struct Native {}; +} +template<typename Schema, typename Encode> +class codec; +/* + * Helper for the basic message container, so the class doesn't have to be + * specialized 10 times. + */ +template <class T> struct native_data_type; + +template <> +struct native_data_type<schema::Primitive<schema::SignedInteger, 1>> { + using type = int8_t; +}; + +template <> +struct native_data_type<schema::Primitive<schema::SignedInteger, 2>> { + using type = int16_t; +}; + +template <> +struct native_data_type<schema::Primitive<schema::SignedInteger, 4>> { + using type = int32_t; +}; + +template <> +struct native_data_type<schema::Primitive<schema::SignedInteger, 8>> { + using type = int64_t; +}; + +template <> +struct native_data_type<schema::Primitive<schema::UnsignedInteger, 1>> { + using type = uint8_t; +}; + +template <> +struct native_data_type<schema::Primitive<schema::UnsignedInteger, 2>> { + using type = uint16_t; +}; + +template <> +struct native_data_type<schema::Primitive<schema::UnsignedInteger, 4>> { + using type = uint32_t; +}; + +template <> +struct native_data_type<schema::Primitive<schema::UnsignedInteger, 8>> { + using type = uint64_t; +}; + +template <> +struct native_data_type<schema::Primitive<schema::FloatingPoint, 4>> { + using type = float; +}; + +template <> +struct native_data_type<schema::Primitive<schema::FloatingPoint, 8>> { + using type = double; +}; + +template<typename T, typename Encoding = encode::Native> +class data { +private: + static_assert(always_false<T>, "Type not supported"); +}; + +template<typename... T, string_literal... literals> +class data<schema::Union<schema::Member<T, literals>...>, encode::Native> { +private: + std::variant<data<T,encode::Native>...> value_; +public: + data() = default; + + SAW_DEFAULT_COPY(data); + SAW_DEFAULT_MOVE(data); + + template<string_literal lit> + void set(data<typename parameter_pack_type<parameter_key_pack_index<lit, literals...>::value, T...>::type, encode::Native> val){ + value_ = std::move(val); + } + + template<string_literal lit> + data<typename parameter_pack_type<parameter_key_pack_index<lit, literals...>::value, T...>::type, encode::Native>& init(){ + value_ = data<typename parameter_pack_type<parameter_key_pack_index<lit, literals...>::value, T...>::type, encode::Native>{}; + return get<lit>(); + } + + template<string_literal lit> + bool holds_alternative() const { + return (parameter_key_pack_index<lit, literals...>::value == value_.index()); + } + + template<string_literal lit> + data<typename parameter_pack_type<parameter_key_pack_index<lit, literals...>::value, T...>::type, encode::Native>& get(){ + return std::get<parameter_key_pack_index<lit, literals...>::value>(value_); + } + + template<string_literal lit> + const data<typename parameter_pack_type<parameter_key_pack_index<lit, literals...>::value, T...>::type, encode::Native>& get() const{ + return std::get<parameter_key_pack_index<lit, literals...>::value>(value_); + } +}; + +template<typename... T, string_literal... literals> +class data<schema::Struct<schema::Member<T, literals>...>, encode::Native> { +private: + std::tuple<data<T,encode::Native>...> value_; +public: + data() = default; + SAW_DEFAULT_COPY(data); + SAW_DEFAULT_MOVE(data); + + template<string_literal literal> + data< + typename parameter_pack_type< + parameter_key_pack_index< + literal, literals... + >::value + , T...>::type + , encode::Native>& get(){ + return std::get<parameter_key_pack_index<literal, literals...>::value>(value_); + } + + template<string_literal literal> + const data< + typename parameter_pack_type< + parameter_key_pack_index< + literal, literals... + >::value + , T...>::type + , encode::Native>& get() const { + return std::get<parameter_key_pack_index<literal, literals...>::value>(value_); + } + + constexpr size_t size() const { + return sizeof...(T); + } +}; + +template<typename... T> +class data<schema::Tuple<T...>, encode::Native> { +private: + std::tuple<data<T,encode::Native>...> value_; +public: + data() = default; + SAW_DEFAULT_COPY(data); + SAW_DEFAULT_MOVE(data); + + template<size_t i> + data<typename parameter_pack_type<i,T...>::type, encode::Native>& get(){ + return std::get<i>(value_); + } + + template<size_t i> + const data<typename parameter_pack_type<i,T...>::type, encode::Native>& get() const{ + return std::get<i>(value_); + } + + constexpr size_t size() const { + return sizeof...(T); + } +}; + +template<typename T, size_t Dim> +class data<schema::Array<T,Dim>, encode::Native> { + private: + std::array<uint64_t, Dim> dims_; + std::vector<data<T, encode::Native>> 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() = default; + SAW_DEFAULT_COPY(data); + SAW_DEFAULT_MOVE(data); + + data(const std::array<uint64_t, Dim>& i): + dims_{i}, + value_{} + { + value_.resize(get_full_size()); + } + + template<size_t i = 0> + error_or<void> add(saw::data<T,encode::Native> 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<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<err::out_of_memory>(); + } + + ++dims_.at(i); + + return void_t{}; + } + + template<std::integral... Dims> + data(Dims... size_): + data{{static_cast<std::size_t>(size_)...}} + { + static_assert(sizeof...(Dims)==Dim, "Argument size must be equal to the Dimension"); + } + + data<T, encode::Native>& at(const std::array<std::size_t, Dim>& ind){ + return value_.at(this->get_flat_index(ind)); + } + + const data<T, encode::Native>& at(const std::array<std::size_t, Dim>& ind) const { + return value_.at(this->get_flat_index(ind)); + } + + template<std::integral... Dims> + data<T, encode::Native>& at(Dims... i){ + return value_.at(this->get_flat_index({static_cast<uint64_t>(i)...})); + } + + template<std::integral... Dims> + const data<T, encode::Native>& at(Dims... i) const { + return value_.at(this->get_flat_index({static_cast<uint64_t>(i)...})); + } + + data<T,encode::Native>& at(const data<schema::FixedArray<schema::UInt64,Dim>>& i){ + return value_.at(this->get_flat_index(i)); + } + + const data<T,encode::Native>& at(const data<schema::FixedArray<schema::UInt64,Dim>>& 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<schema::FixedArray<schema::UInt64, Dim>> get_dims() const { + return {dims_}; + } + +private: + uint64_t get_flat_index(const std::array<uint64_t, Dim>& i) const { + return get_flat_index(data<schema::FixedArray<schema::UInt64,Dim>>{i}); + } + + uint64_t get_flat_index(const data<schema::FixedArray<schema::UInt64,Dim>>& i) const { + 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<typename T, uint64_t... D> +class data<schema::FixedArray<T,D...>, encode::Native> { +private: + //using inner_type = std::array<data<T, encode::Native>, multiply_helper<Dims...>::value>; + //std::unique_ptr<inner_type> value_; + using ArrayT = std::array<data<T, encode::Native>, ct_multiply<uint64_t, D...>::value>; + ArrayT value_; + +public: + data() = default; + + data(const std::array<typename native_data_type<T>::type, ct_multiply<uint64_t, D...>::value>& data) requires (is_primitive<T>::value) + { + for(uint64_t i = 0; i < ct_multiply<uint64_t, D...>::value; ++i){ + value_.at(i).set(data.at(i)); + } + } + + data<T, encode::Native>& at(const std::array<uint64_t, sizeof...(D)>& ind){ + return value_.at(this->get_flat_index(ind)); + } + + const data<T, encode::Native>& at(const std::array<uint64_t, sizeof...(D)>& ind) const { + return value_.at(this->get_flat_index(ind)); + } + + template<std::integral... Dims> + data<T, encode::Native>& at(Dims... i) { + return value_.at(this->get_flat_index({i...})); + } + + template<std::integral... Dims> + const data<T, encode::Native>& at(Dims... i) const { + return value_.at(this->get_flat_index({i...})); + } + + data<T, encode::Native>& at(const data<schema::FixedArray<schema::UInt64, sizeof...(D)>>& i){ + return value_.at(this->get_flat_index(i)); + } + + const data<T, encode::Native>& at(const data<schema::FixedArray<schema::UInt64, sizeof...(D)>>& i)const{ + return value_.at(this->get_flat_index(i)); + } + + template<uint64_t i> + uint64_t get_dim_size() const { + return parameter_pack_value<i, uint64_t, D...>::value; + } + + data<schema::FixedArray<schema::UInt64, sizeof...(D)>> get_dims() const { + return {std::array<uint64_t, sizeof...(D)>{D...}}; + } +private: + uint64_t get_flat_index(const std::array<uint64_t, sizeof...(D)>& i) const { + uint64_t s = 0; + + uint64_t stride = 1; + + constexpr static std::array<uint64_t, sizeof...(D)> 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<schema::String, encode::Native> { +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<typename T, size_t N> +class data<schema::Primitive<T,N>, encode::Native> { +private: + typename native_data_type<schema::Primitive<T,N>>::type value_; +public: + data():value_{}{} + + SAW_DEFAULT_COPY(data); + SAW_DEFAULT_MOVE(data); + + data(typename native_data_type<schema::Primitive<T,N>>::type value__): + value_{std::move(value__)}{} + + void set(typename native_data_type<schema::Primitive<T,N>>::type val){ + value_ = val; + } + + typename native_data_type<schema::Primitive<T,N>>::type get() const {return value_;} + + data<schema::Primitive<T,N>, encode::Native> operator*(const saw::data<schema::Primitive<T,N>, encode::Native>& rhs)const{ + return {get() * rhs.get()}; + } + + data<schema::Primitive<T,N>, encode::Native> operator/(const saw::data<schema::Primitive<T,N>, encode::Native>& rhs)const{ + return {get() / rhs.get()}; + } + + data<schema::Primitive<T,N>, encode::Native> operator+(const saw::data<schema::Primitive<T,N>, encode::Native>& rhs)const{ + return {get() + rhs.get()}; + } + + data<schema::Primitive<T,N>, encode::Native> operator-(const saw::data<schema::Primitive<T,N>, encode::Native>& rhs)const{ + return {get() - rhs.get()}; + } +}; + + +} |