diff options
Diffstat (limited to 'modules/codec/c++/csv.hpp')
-rw-r--r-- | modules/codec/c++/csv.hpp | 216 |
1 files changed, 216 insertions, 0 deletions
diff --git a/modules/codec/c++/csv.hpp b/modules/codec/c++/csv.hpp new file mode 100644 index 0000000..1cb4263 --- /dev/null +++ b/modules/codec/c++/csv.hpp @@ -0,0 +1,216 @@ +#pragma once + +#include <forstio/error.h> +#include <forstio/buffer.h> + +#include "data.hpp +#include "stream_value.hpp + +namespace saw { +namespace encode { +struct Csv {}; +} + +namespace impl { +template<typename Schema, typename FromDecode> +struct csv_encode { + static_assert(always_false<Schema, FromDecode>, "Case not supported"); +}; + +template<typename T, size_t Dim, typename FromDecode> +struct csv_encode<schema::Array<T,Dim>, FromDecode> { + static_assert(Dim == 1, "Only one dimension is allowed."); + static_assert(!is_array<T>::value, "Array of an array is not allowed."); + static_assert(is_tuple<T>::value || is_struct<T>::value, "Only struct or tuples allowed inside a csv array"); + + using Schema = schema::Array<T,Dim>; + + static error_or<void> encode(const data<Schema, FromDecode>& from, buffer& to){ + if constexpr (is_struct<T>::value){ + auto eov = csv_encode<T,FromDecode>::encode_header(to); + if(eov.is_error()){ + return eov; + } + } + + for(std::size_t i = 0; i < from.size(); ++i){ + auto eov = csv_encode<T,FromDecode>::encode(from.at(i), to); + if(eov.is_error()){ + return eov; + } + } + + return void_t{}; + } +}; + +template<typename... V, string_literal... K, typename FromDecode> +struct csv_encode<schema::Struct<schema::Member<V,K>...>, FromDecode> { + using Schema = schema::Struct<schema::Member<V,K>...>; + + template<size_t i> + static error_or<void> encode_header_i(buffer& to){ + // Encode string + // + constexpr auto str_view = parameter_key_pack_type<i, K...>::literal; + + for(auto& iter : str_view.view()){ + auto eov = stream_value<schema::Int8>::encode(iter, to); + if(eov.is_error()){ + return eov; + } + } + + // Go to next string + if constexpr ( (i+1) < sizeof...(K)){ + /** + * Replace this with col separator + */ + constexpr std::string_view lit = ","; + for(int8_t iter : lit){ + auto eov = stream_value<schema::Int8>::encode(iter, to); + if(eov.is_error()){ + return eov; + } + } + return encode_header_i<i+1>(to); + } + + { + /** + * Replace this with row separator + */ + constexpr std::string_view lit = "\r\n"; + for(int8_t iter : lit){ + auto eov = stream_value<schema::Int8>::encode(iter, to); + if ( eov.is_error()){ + return eov; + } + } + } + + return make_void(); + } + + static error_or<void> encode_header(buffer& to){ + return encode_header_i<0>(to); + } + + template<size_t i> + static error_or<void> encode_i(const data<Schema, FromDecode>& from, buffer& to){ + constexpr auto str_view = parameter_key_pack_type<i,K...>::literal; + + { + auto eov = csv_encode<typename parameter_pack_type<i,V...>::type, FromDecode>::encode(from.template get<str_view>(), to); + if(eov.is_error()){ + return eov; + } + } + + if constexpr ( (i+1) < sizeof...(K)){ + /** + * Replace this with col separator + */ + constexpr std::string_view lit = ","; + for(int8_t iter : lit){ + auto eov = stream_value<schema::Int8>::encode(iter, to); + if(eov.is_error()){ + return eov; + } + } + return encode_i<i+1>(from, to); + } + { + /** + * Replace this with row separator + */ + constexpr std::string_view lit = "\r\n"; + for(int8_t iter : lit){ + auto eov = stream_value<schema::Int8>::encode(iter, to); + if ( eov.is_error()){ + return eov; + } + } + } + + return make_void(); + } + + static error_or<void> encode(const data<Schema, FromDecode>& from, buffer& to){ + return encode_i<0>(from, to); + } +}; + +template<typename FromDecode> +struct csv_encode<schema::String, FromDecode> { + using Schema = schema::String; + + static error_or<void> encode(const data<Schema, FromDecode>& from, buffer& to){ + for(size_t i = 0; i < from.size(); ++i){ + auto eov = stream_value<schema::Int8>::encode(from.at(i), to); + if(eov.is_error()){ + return eov; + } + } + return make_void(); + } +}; + +template<class T, size_t N, typename FromDecode> +struct csv_encode<schema::Primitive<T,N>, FromDecode> { + using Schema = schema::Primitive<T,N>; + + static error_or<void> encode(const data<Schema, FromDecode>& from, buffer& to){ + std::string to_str; + try { + to_str = std::to_string(from.get()); + }catch(const std::exception& ){ + return make_error<err::out_of_memory>(); + } + for(auto iter : to_str){ + auto eov = stream_value<schema::Int8>::encode(iter, to); + if(eov.is_error()){ + return eov; + } + } + return make_void(); + } +}; +} + +template<typename Schema> +class data<Schema, encode::Csv> { + private: + ring_buffer buffer_; + public: + data() = default; + + buffer& get_buffer(){ + return buffer_; + } +}; + +template<typename Schema> +class codec<Schema, encode::Csv> { + static_assert(is_array<Schema>::value, "Only an Array is allowed as a base value"); +public: + template<typename FromEncode> + static error_or<void> encode(const data<Schema, FromEncode>& from, data<Schema,encode::Csv>& to){ + buffer_view buff_v{to.get_buffer()}; + + auto eov = impl::csv_encode<Schema, FromEncode>::encode(from, buff_v); + if(eov.is_error()){ + return eov; + } + to.get_buffer().write_advance(buff_v.write_offset()); + + return eov; + } + + template<typename ToDecode> + static error_or<void> decode(data<Schema,encode::Csv>& from, data<Schema, ToDecode>& to){ + + return make_error<err::not_implemented>(); + } +}; +} |