From 8dad985328e2183b224300aa992951131956fdb3 Mon Sep 17 00:00:00 2001 From: "Claudius \"keldu\" Holeksa" Date: Tue, 23 Jan 2024 13:12:11 +0100 Subject: core,codec-json,codec-minecraft,codec-netcdf,codec,io-tls,io,io_codec,window,window-opengl: Renamed file endings and changed includes --- modules/codec-json/c++/json.h | 120 ------ modules/codec-json/c++/json.hpp | 120 ++++++ modules/codec-json/c++/json.tmpl.h | 734 ----------------------------------- modules/codec-json/c++/json.tmpl.hpp | 734 +++++++++++++++++++++++++++++++++++ 4 files changed, 854 insertions(+), 854 deletions(-) delete mode 100644 modules/codec-json/c++/json.h create mode 100644 modules/codec-json/c++/json.hpp delete mode 100644 modules/codec-json/c++/json.tmpl.h create mode 100644 modules/codec-json/c++/json.tmpl.hpp (limited to 'modules/codec-json/c++') diff --git a/modules/codec-json/c++/json.h b/modules/codec-json/c++/json.h deleted file mode 100644 index bc60ee9..0000000 --- a/modules/codec-json/c++/json.h +++ /dev/null @@ -1,120 +0,0 @@ -#pragma once - -#include -#include -#include - -#include - -namespace saw { -namespace encode { -struct Json {}; -} - -template -class data { -private: - ring_buffer buffer_; -public: - data():buffer_{}{} - - data(std::size_t ring_size_):buffer_{ring_size_}{} - - data(ring_buffer buff_): - buffer_{std::move(buff_)} - {} - - data(const std::string_view& view__): - buffer_{view__.size()} - { - auto ptr = reinterpret_cast(view__.data()); - if(!ptr){ - return; - } - buffer_.push(*ptr, view__.size()); - } - - buffer& get_buffer(){ - return buffer_; - } - - const buffer& get_buffer() const { - return buffer_; - } - - error push(uint8_t val){ - return buffer_.push(val); - } - - std::size_t get_size() const { - return buffer_.read_composite_length(); - } - - uint8_t& at(std::size_t i){ - return buffer_.read(i); - } - - const uint8_t& at(std::size_t i) const { - return buffer_.read(i); - } -}; -} - -#include "json.tmpl.h" - -namespace saw { - -/** - * Codec class for json - */ -template -class codec { -public: - struct config { - size_t depth = 16; - size_t length = 1024; - }; -private: - config cfg_; -public: - /** - * Default constructor - */ - codec(){} - - /** - * Constructor - */ - codec(config cfg__):cfg_{std::move(cfg__)}{} - - SAW_FORBID_COPY(codec); - SAW_DEFAULT_MOVE(codec); - - template - error_or encode(const data& from_encode, data& to_encode){ - // To Be encoded - buffer_view buff_v{to_encode.get_buffer()}; - auto eov = impl::json_encode::encode(from_encode, buff_v); - if(eov.is_error()){ - return std::move(eov.get_error()); - } - to_encode.get_buffer().write_advance(buff_v.write_offset()); - - return void_t{}; - } - - template - error_or decode(data& from_decode, data& to_decode){ - buffer_view buff_v{from_decode.get_buffer()}; - - auto eov = impl::json_decode::decode(buff_v, to_decode); - if(eov.is_error()){ - return std::move(eov.get_error()); - } - from_decode.get_buffer().read_advance(buff_v.read_offset()); - - return void_t {}; - } -}; -} - diff --git a/modules/codec-json/c++/json.hpp b/modules/codec-json/c++/json.hpp new file mode 100644 index 0000000..d81a508 --- /dev/null +++ b/modules/codec-json/c++/json.hpp @@ -0,0 +1,120 @@ +#pragma once + +#include +#include +#include + +#include + +namespace saw { +namespace encode { +struct Json {}; +} + +template +class data { +private: + ring_buffer buffer_; +public: + data():buffer_{}{} + + data(std::size_t ring_size_):buffer_{ring_size_}{} + + data(ring_buffer buff_): + buffer_{std::move(buff_)} + {} + + data(const std::string_view& view__): + buffer_{view__.size()} + { + auto ptr = reinterpret_cast(view__.data()); + if(!ptr){ + return; + } + buffer_.push(*ptr, view__.size()); + } + + buffer& get_buffer(){ + return buffer_; + } + + const buffer& get_buffer() const { + return buffer_; + } + + error push(uint8_t val){ + return buffer_.push(val); + } + + std::size_t get_size() const { + return buffer_.read_composite_length(); + } + + uint8_t& at(std::size_t i){ + return buffer_.read(i); + } + + const uint8_t& at(std::size_t i) const { + return buffer_.read(i); + } +}; +} + +#include "json.tmpl.hpp + +namespace saw { + +/** + * Codec class for json + */ +template +class codec { +public: + struct config { + size_t depth = 16; + size_t length = 1024; + }; +private: + config cfg_; +public: + /** + * Default constructor + */ + codec(){} + + /** + * Constructor + */ + codec(config cfg__):cfg_{std::move(cfg__)}{} + + SAW_FORBID_COPY(codec); + SAW_DEFAULT_MOVE(codec); + + template + error_or encode(const data& from_encode, data& to_encode){ + // To Be encoded + buffer_view buff_v{to_encode.get_buffer()}; + auto eov = impl::json_encode::encode(from_encode, buff_v); + if(eov.is_error()){ + return std::move(eov.get_error()); + } + to_encode.get_buffer().write_advance(buff_v.write_offset()); + + return void_t{}; + } + + template + error_or decode(data& from_decode, data& to_decode){ + buffer_view buff_v{from_decode.get_buffer()}; + + auto eov = impl::json_decode::decode(buff_v, to_decode); + if(eov.is_error()){ + return std::move(eov.get_error()); + } + from_decode.get_buffer().read_advance(buff_v.read_offset()); + + return void_t {}; + } +}; +} + diff --git a/modules/codec-json/c++/json.tmpl.h b/modules/codec-json/c++/json.tmpl.h deleted file mode 100644 index 84f0058..0000000 --- a/modules/codec-json/c++/json.tmpl.h +++ /dev/null @@ -1,734 +0,0 @@ -#pragma once - -#include -#include - -#include - -namespace saw { -namespace impl { -template -class json_encode { - static_assert(always_false, "This schema type is not being handled by the json encoding."); -}; - -template -struct json_encode, RootSchema, FromEncode> { - static error_or encode(const data, FromEncode>& from, buffer& to) { - auto val = from.get(); - std::array data; - auto tc_result = std::to_chars(reinterpret_cast(data.data()), reinterpret_cast(data.data())+data.size(), val); - - if(tc_result.ec != std::errc{}){ - return make_error(); - } - - size_t bytes_written = 0; - for(char* ptr = reinterpret_cast(data.data()); ptr != tc_result.ptr; ++ptr){ - ++bytes_written; - } - - auto& buff = to; - error err = buff.write_require_length(bytes_written); - if(!err.template is_type()){ - return std::move(err); - } - - for(char* ptr = reinterpret_cast(data.data()); ptr != tc_result.ptr; ++ptr){ - uint8_t* un_ptr = reinterpret_cast(ptr); - buff.push(un_ptr[0]); - } - - return void_t{}; - } -}; - -template -struct json_encode { - static error_or encode(const data& from, buffer& to) { - { - auto err = to.push('"'); - if(!err.template is_type()){ - return err; - } - } - for(std::size_t i = 0; i < from.size(); ++i){ - auto err = to.push(from.get_at(i)); - if(!err.template is_type()){ - return err; - } - } - { - auto err = to.push('"'); - if(!err.template is_type()){ - return err; - } - } - - return void_t{}; - } -}; - -template -struct json_encode, RootSchema, FromEncode> { - template - static error_or encode_element(const data, FromEncode>& from, buffer& to){ - auto eov = json_encode::type, RootSchema, FromEncode>::encode(from.template get(), to); - - if(eov.is_error()){ - return eov; - } - - if constexpr ( (i+1) < sizeof...(T)){ - { - auto eov_ele = to.push(','); - if(!eov_ele.template is_type()){ - return eov_ele; - } - } - { - auto eov_ele = encode_element(from, to); - if(eov_ele.is_error()){ - return eov_ele; - } - } - - - } - return void_t{}; - } - - static error_or encode(const data, FromEncode>& from, buffer& to) { - { - auto err = to.push('['); - if(!err.template is_type()){ - return err; - } - } - if constexpr ( sizeof...(T) > 0 ){ - auto eov = encode_element<0>(from, to); - if(eov.is_error()){ - return eov; - } - } - { - auto err = to.push(']'); - if(!err.template is_type()){ - return err; - } - } - - return void_t{}; - } -}; - -template -struct json_encode, RootSchema, FromEncode> { - template - static error_or encode_level(const data, FromEncode>& from, buffer& to, std::array& index){ - if constexpr (Level == D){ - auto eov = json_encode::encode(from.at(index), to); - if(eov.is_error()){ - return eov; - } - } else { - { - auto err = to.push('['); - if(!err.template is_type()){ - return err; - } - } - for(std::size_t i = 0; i < from.get_dim_size(Level); ++i){ - if( i > 0 ){ - auto err = to.push(','); - if(!err.template is_type()){ - return err; - } - } - { - index[Level] = i; - auto eov = encode_level(from, to, index); - if(eov.is_error()){ - return eov; - } - } - } - { - auto err = to.push(']'); - if(!err.template is_type()){ - return err; - } - } - } - return void_t{}; - } - - static error_or encode(const data, FromEncode>& from, buffer& to) { - std::array index; - return encode_level<0>(from, to, index); - } -}; - -template -struct json_encode...>, RootSchema, FromEncode> { - - template - static error_or encode_element(const data...>, FromEncode>& from, buffer& to){ - // Encode the name - { - std::string_view view = parameter_key_pack_type::literal.view(); - error err = to.push('"'); - if(!err.template is_type()){ - return err; - } - err = to.push(*reinterpret_cast(view.data()), view.size()); - if(!err.template is_type()){ - return err; - } - err = to.push('"'); - if(!err.template is_type()){ - return err; - } - } - // Add the separator - { - auto eov_ele = to.push(':'); - if(!eov_ele.template is_type()){ - return eov_ele; - } - } - - // Encode the value - auto eov = json_encode::type, RootSchema, FromEncode>::encode(from.template get::literal>(), to); - - // Go to the next element - if constexpr ( (i+1) < sizeof...(T)){ - { - auto eov_ele = to.push(','); - if(!eov_ele.template is_type()){ - return eov_ele; - } - } - { - auto eov_ele = encode_element(from, to); - if(eov_ele.is_error()){ - return eov_ele; - } - } - - - } - - return void_t{}; - } - static error_or encode(const data...>, FromEncode>& from, buffer& to) { - { - auto err = to.push('{'); - if(!err.template is_type()){ - return err; - } - } - if constexpr ( sizeof...(T) > 0 ){ - auto eov = encode_element<0>(from, to); - if(eov.is_error()){ - return eov; - } - } - { - auto err = to.push('}'); - if(!err.template is_type()){ - return err; - } - } - - return void_t{}; - } -}; - -template -struct json_encode...>, RootSchema, FromEncode> { - - template - static error_or encode_element(const data...>, FromEncode>& from, buffer& to){ - if(from.template holds_alternative::literal>()){ - // Encode the name - { - std::string_view view = parameter_key_pack_type::literal.view(); - error err = to.push('"'); - if(!err.template is_type()){ - return err; - } - err = to.push(*reinterpret_cast(view.data()), view.size()); - if(!err.template is_type()){ - return err; - } - err = to.push('"'); - if(!err.template is_type()){ - return err; - } - } - // Add the separator - { - auto eov_ele = to.push(':'); - if(!eov_ele.template is_type()){ - return eov_ele; - } - } - - // Encode the value - auto eov = json_encode::type, RootSchema, FromEncode>::encode(from.template get::literal>(), to); - } - // Go to the next element - if constexpr ( (i+1) < sizeof...(T)){ - { - auto eov_ele = encode_element(from, to); - if(eov_ele.is_error()){ - return eov_ele; - } - } - - - } - - return void_t{}; - } - static error_or encode(const data...>, FromEncode>& from, buffer& to) { - { - auto err = to.push('{'); - if(!err.template is_type()){ - return err; - } - } - if constexpr ( sizeof...(T) > 0 ){ - auto eov = encode_element<0>(from, to); - if(eov.is_error()){ - return eov; - } - } - { - auto err = to.push('}'); - if(!err.template is_type()){ - return err; - } - } - - return void_t{}; - } -}; - -struct json_helper { - static bool is_whitespace(int8_t ch) { - return ch == '\t' || ch == ' ' || ch == '\r' || ch == '\n'; - } - - static void skip_whitespace(buffer_view& buff) { - while(buff.read_composite_length() > 0 && json_helper::is_whitespace(buff.read())) { - buff.read_advance(1); - } - } -}; - -template -struct json_decode; - -template -struct json_decode, RootSchema, ToDecode> { - static error_or decode(buffer_view& buff, data, ToDecode>& to) { - assert( - ( buff.read() >= '0' && buff.read() <= '9') - || ( buff.read() == '+' || buff.read() == '-') - ); - - std::size_t offset = 0; - - if (buff.read() == '-'){ - ++offset; - } else if (buff.read() == '+'){ - return make_error(); - } - if (offset >= buff.read_composite_length()) { - return make_error(); - } - if (buff.read(offset) >= '1' && buff.read(offset) <= '9') { - ++offset; - - if(offset >= buff.read_composite_length()) { - return make_error(); - } - - while(1){ - if (buff.read(offset) >= '0' && buff.read(offset) <= '9') { - ++offset; - - if(offset >= buff.read_composite_length()) { - break; - } - continue; - } - break; - } - } else if (buff.read(offset) == '0' ) { - ++offset; - } else { - return make_error(); - } - - { - std::string_view num_view{reinterpret_cast(&buff.read()), offset}; - typename native_data_type>::type result; - auto fc_result = std::from_chars(num_view.data(), num_view.data() + num_view.size(), result); - if(fc_result.ec != std::errc{}){ - return make_error(); - } - - to.set(result); - } - buff.read_advance(offset); - - return void_t{}; - } -}; - -template -struct json_decode { - static error_or decode(buffer_view& buff, data& to){ - assert(buff.read() == '"'); - buff.read_advance(1); - - std::stringstream iss; - bool string_done = false; - while(!string_done){ - if(buff.read_composite_length() == 0){ - return make_error(); - } - - switch(buff.read()){ - case '\\':{ - buff.read_advance(1); - if(buff.read_composite_length() == 0){ - return make_error(); - } - switch(buff.read()){ - case '\\': - case '/': - case '"': - iss<< buff.read(); - break; - case 'b': - iss<<'\b'; - break; - case 'f': - iss<<'\f'; - break; - case 'n': - iss<<'\n'; - break; - case 'r': - iss<<'\r'; - break; - case 't': - iss<<'\t'; - break; - case 'u': { - buff.read_advance(1); - if(buff.read_composite_length() < 4){ - return make_error(); - } - iss<<'?'; - iss<<'?'; - iss<<'?'; - iss<<'?'; - - buff.read_advance(3); - } break; - } - } break; - case '"': - string_done = true; - break; - default:{ - // Avoids Control sequences - if(buff.read() >= ' ' && buff.read() <= '~'){ - iss<(); - } - } while( buff.read() < 0 ); - iss<<'?'; - } - break; - } - } - buff.read_advance(1); - } - - std::string raw = iss.str(); - to.set(std::move(raw)); - - return void_t{}; - } -}; - -template -struct json_decode...>, RootSchema, ToDecode> { - template - static error_or decode_field_search(buffer_view& buff, data...>, ToDecode>& to, std::array& fields, const data& search_name){ - if constexpr ( i < sizeof...(T)){ - using Type = typename parameter_pack_type::type; - constexpr static string_literal Literal = parameter_key_pack_type::literal; - if(search_name == Literal.view()){ - if(fields[i]){ - return make_error(); - } - fields[i] = true; - auto eov = json_decode::decode(buff, to.template get()); - if(eov.is_error()){ - return eov; - } - }else { - decode_field_search(buff, to, fields, search_name); - } - }else { - return make_error(); - } - return void_t{}; - } - - static error_or decode_fields(buffer_view& buff, data...>, ToDecode>& to, std::array& fields){ - for(;;){ - data name; - auto eov = json_decode::decode(buff, name); - if(eov.is_error()){ - return eov; - } - json_helper::skip_whitespace(buff); - if(buff.read_composite_length() == 0){ - return make_error(); - } - if(buff.read() != ':'){ - return make_error(); - } - buff.read_advance(1); - json_helper::skip_whitespace(buff); - if(buff.read_composite_length() == 0){ - return make_error(); - } - { - auto eov = decode_field_search<0>(buff, to, fields, name); - if(eov.is_error()){ - return eov; - } - } - json_helper::skip_whitespace(buff); - if(buff.read_composite_length() == 0){ - return make_error(); - } - if(buff.read() == ','){ - buff.read_advance(1); - }else if(buff.read() == '}'){ - // If not all fields are set, the dataset is incomplete - for(auto& iter : fields){ - if(!iter){ - return make_error(); - } - } - buff.read_advance(1); - return void_t{}; - }else{ - return make_error(); - } - json_helper::skip_whitespace(buff); - if(buff.read_composite_length() == 0){ - return make_error(); - } - } - return void_t{}; - } - - static error_or decode(buffer_view& buff, data...>, ToDecode>& to){ - std::array found_fields; - std::fill(found_fields.begin(), found_fields.end(), false); - - assert(buff.read() == '{'); - buff.read_advance(1); - json_helper::skip_whitespace(buff); - if(buff.read_composite_length() == 0){ - return make_error(); - } - - // Check if there are no elements present in the JSON Struct - if(buff.read() == '}'){ - if(sizeof...(T) > 0){ - return make_error(); - } - buff.read_advance(1); - return void_t{}; - } - - auto eov = decode_fields(buff, to, found_fields); - if(eov.is_error()){ - return eov; - } - - return void_t{}; - } -}; - -template -struct json_decode, RootSchema, ToDecode> { - template - static error_or decode_element(buffer_view& buff, data, ToDecode>& to){ - if constexpr (i < sizeof...(T)){ - if constexpr ( i > 0 ){ - if(buff.read() != ','){ - return make_error(); - } - buff.read_advance(1); - if(buff.read_composite_length() == 0){ - return make_error(); - } - } - using Type = typename parameter_pack_type::type; - - auto eov = json_decode::decode(buff, to.template get()); - if(eov.is_error()){ - return eov; - } - json_helper::skip_whitespace(buff); - if(buff.read_composite_length() == 0){ - return make_error(); - } - - eov = decode_element(buff, to); - if(eov.is_error()){ - return eov; - } - }else{ - if(buff.read() != ']'){ - return make_error(); - } - buff.read_advance(1); - } - return void_t{}; - } - - static error_or decode(buffer_view& buff, data, ToDecode>& to){ - assert(buff.read() == '['); - buff.read_advance(1); - - json_helper::skip_whitespace(buff); - if(buff.read_composite_length() == 0){ - return make_error(); - } - - auto eov = decode_element<0>(buff, to); - if(eov.is_error()){ - return eov; - } - - return void_t{}; - } -}; - -// The whole std::vector approach is hacky af. ToDo change it maybe? -template -struct json_decode, RootSchema, ToDecode> { - template - static error_or decode_flat_level(buffer_view& buff, std::vector>& to, std::array& index, std::array& dims, bool log_dim){ - if constexpr (Level == D) { - json_helper::skip_whitespace(buff); - try { - to.push_back({}); - }catch(std::exception& e){ - return make_error(); - } - auto eov = json_decode::decode(buff, to.back()); - if(eov.is_error()){ - return eov; - } - } else { - assert(buff.read() == '['); - buff.read_advance(1); - - json_helper::skip_whitespace(buff); - if ( buff.read_composite_length() == 0 ){ - return make_error(); - } - - index[Level] = 0; - for(;;){ - // We should have an element right now - auto eov = decode_flat_level(buff,to,index,dims, index[Level] == 0 && log_dim); - if(eov.is_error()){ - return eov; - } - json_helper::skip_whitespace(buff); - if ( buff.read_composite_length() == 0 ){ - return make_error(); - } - - ++index[Level]; - if(buff.read() == ','){ - buff.read_advance(1); - } else if(buff.read() == ']'){ - buff.read_advance(1); - break; - } else { - return make_error(); - } - json_helper::skip_whitespace(buff); - if ( buff.read_composite_length() == 0 ){ - return make_error(); - } - } - if(log_dim){ - dims[Level] = index[Level]; - }else if (dims[Level] != index[Level]){ - return make_error(); - } - } - return void_t{}; - } - - template - static error_or decode_unflat_level(std::vector>& flat, data, ToDecode>& to, std::array& index, std::size_t& flat_index) { - if constexpr ( Level == D ){ - auto& flat_data = flat.at(flat_index); - to.at(index) = std::move(flat_data); - ++flat_index; - }else { - const std::size_t dim_size = to.get_dim_size(Level); - for(index[Level] = 0; index[Level] < dim_size; ++index[Level]){ - - auto eov = decode_unflat_level(flat, to, index, flat_index); - if(eov.is_error()){ - return eov; - } - } - } - return void_t{}; - } - - static error_or decode(buffer_view& buff, data, ToDecode>& to){ - std::array index; - std::array dims; - std::fill(dims.begin(), dims.end(), 0); - std::vector> flat_array; - auto eov = decode_flat_level<0>(buff, flat_array, index, dims, true); - if(eov.is_error()){ - return eov; - } - - to = {dims}; - std::size_t flat_index = 0; - - return decode_unflat_level<0>(flat_array, to, index, flat_index); - } -}; -} -} diff --git a/modules/codec-json/c++/json.tmpl.hpp b/modules/codec-json/c++/json.tmpl.hpp new file mode 100644 index 0000000..84f0058 --- /dev/null +++ b/modules/codec-json/c++/json.tmpl.hpp @@ -0,0 +1,734 @@ +#pragma once + +#include +#include + +#include + +namespace saw { +namespace impl { +template +class json_encode { + static_assert(always_false, "This schema type is not being handled by the json encoding."); +}; + +template +struct json_encode, RootSchema, FromEncode> { + static error_or encode(const data, FromEncode>& from, buffer& to) { + auto val = from.get(); + std::array data; + auto tc_result = std::to_chars(reinterpret_cast(data.data()), reinterpret_cast(data.data())+data.size(), val); + + if(tc_result.ec != std::errc{}){ + return make_error(); + } + + size_t bytes_written = 0; + for(char* ptr = reinterpret_cast(data.data()); ptr != tc_result.ptr; ++ptr){ + ++bytes_written; + } + + auto& buff = to; + error err = buff.write_require_length(bytes_written); + if(!err.template is_type()){ + return std::move(err); + } + + for(char* ptr = reinterpret_cast(data.data()); ptr != tc_result.ptr; ++ptr){ + uint8_t* un_ptr = reinterpret_cast(ptr); + buff.push(un_ptr[0]); + } + + return void_t{}; + } +}; + +template +struct json_encode { + static error_or encode(const data& from, buffer& to) { + { + auto err = to.push('"'); + if(!err.template is_type()){ + return err; + } + } + for(std::size_t i = 0; i < from.size(); ++i){ + auto err = to.push(from.get_at(i)); + if(!err.template is_type()){ + return err; + } + } + { + auto err = to.push('"'); + if(!err.template is_type()){ + return err; + } + } + + return void_t{}; + } +}; + +template +struct json_encode, RootSchema, FromEncode> { + template + static error_or encode_element(const data, FromEncode>& from, buffer& to){ + auto eov = json_encode::type, RootSchema, FromEncode>::encode(from.template get(), to); + + if(eov.is_error()){ + return eov; + } + + if constexpr ( (i+1) < sizeof...(T)){ + { + auto eov_ele = to.push(','); + if(!eov_ele.template is_type()){ + return eov_ele; + } + } + { + auto eov_ele = encode_element(from, to); + if(eov_ele.is_error()){ + return eov_ele; + } + } + + + } + return void_t{}; + } + + static error_or encode(const data, FromEncode>& from, buffer& to) { + { + auto err = to.push('['); + if(!err.template is_type()){ + return err; + } + } + if constexpr ( sizeof...(T) > 0 ){ + auto eov = encode_element<0>(from, to); + if(eov.is_error()){ + return eov; + } + } + { + auto err = to.push(']'); + if(!err.template is_type()){ + return err; + } + } + + return void_t{}; + } +}; + +template +struct json_encode, RootSchema, FromEncode> { + template + static error_or encode_level(const data, FromEncode>& from, buffer& to, std::array& index){ + if constexpr (Level == D){ + auto eov = json_encode::encode(from.at(index), to); + if(eov.is_error()){ + return eov; + } + } else { + { + auto err = to.push('['); + if(!err.template is_type()){ + return err; + } + } + for(std::size_t i = 0; i < from.get_dim_size(Level); ++i){ + if( i > 0 ){ + auto err = to.push(','); + if(!err.template is_type()){ + return err; + } + } + { + index[Level] = i; + auto eov = encode_level(from, to, index); + if(eov.is_error()){ + return eov; + } + } + } + { + auto err = to.push(']'); + if(!err.template is_type()){ + return err; + } + } + } + return void_t{}; + } + + static error_or encode(const data, FromEncode>& from, buffer& to) { + std::array index; + return encode_level<0>(from, to, index); + } +}; + +template +struct json_encode...>, RootSchema, FromEncode> { + + template + static error_or encode_element(const data...>, FromEncode>& from, buffer& to){ + // Encode the name + { + std::string_view view = parameter_key_pack_type::literal.view(); + error err = to.push('"'); + if(!err.template is_type()){ + return err; + } + err = to.push(*reinterpret_cast(view.data()), view.size()); + if(!err.template is_type()){ + return err; + } + err = to.push('"'); + if(!err.template is_type()){ + return err; + } + } + // Add the separator + { + auto eov_ele = to.push(':'); + if(!eov_ele.template is_type()){ + return eov_ele; + } + } + + // Encode the value + auto eov = json_encode::type, RootSchema, FromEncode>::encode(from.template get::literal>(), to); + + // Go to the next element + if constexpr ( (i+1) < sizeof...(T)){ + { + auto eov_ele = to.push(','); + if(!eov_ele.template is_type()){ + return eov_ele; + } + } + { + auto eov_ele = encode_element(from, to); + if(eov_ele.is_error()){ + return eov_ele; + } + } + + + } + + return void_t{}; + } + static error_or encode(const data...>, FromEncode>& from, buffer& to) { + { + auto err = to.push('{'); + if(!err.template is_type()){ + return err; + } + } + if constexpr ( sizeof...(T) > 0 ){ + auto eov = encode_element<0>(from, to); + if(eov.is_error()){ + return eov; + } + } + { + auto err = to.push('}'); + if(!err.template is_type()){ + return err; + } + } + + return void_t{}; + } +}; + +template +struct json_encode...>, RootSchema, FromEncode> { + + template + static error_or encode_element(const data...>, FromEncode>& from, buffer& to){ + if(from.template holds_alternative::literal>()){ + // Encode the name + { + std::string_view view = parameter_key_pack_type::literal.view(); + error err = to.push('"'); + if(!err.template is_type()){ + return err; + } + err = to.push(*reinterpret_cast(view.data()), view.size()); + if(!err.template is_type()){ + return err; + } + err = to.push('"'); + if(!err.template is_type()){ + return err; + } + } + // Add the separator + { + auto eov_ele = to.push(':'); + if(!eov_ele.template is_type()){ + return eov_ele; + } + } + + // Encode the value + auto eov = json_encode::type, RootSchema, FromEncode>::encode(from.template get::literal>(), to); + } + // Go to the next element + if constexpr ( (i+1) < sizeof...(T)){ + { + auto eov_ele = encode_element(from, to); + if(eov_ele.is_error()){ + return eov_ele; + } + } + + + } + + return void_t{}; + } + static error_or encode(const data...>, FromEncode>& from, buffer& to) { + { + auto err = to.push('{'); + if(!err.template is_type()){ + return err; + } + } + if constexpr ( sizeof...(T) > 0 ){ + auto eov = encode_element<0>(from, to); + if(eov.is_error()){ + return eov; + } + } + { + auto err = to.push('}'); + if(!err.template is_type()){ + return err; + } + } + + return void_t{}; + } +}; + +struct json_helper { + static bool is_whitespace(int8_t ch) { + return ch == '\t' || ch == ' ' || ch == '\r' || ch == '\n'; + } + + static void skip_whitespace(buffer_view& buff) { + while(buff.read_composite_length() > 0 && json_helper::is_whitespace(buff.read())) { + buff.read_advance(1); + } + } +}; + +template +struct json_decode; + +template +struct json_decode, RootSchema, ToDecode> { + static error_or decode(buffer_view& buff, data, ToDecode>& to) { + assert( + ( buff.read() >= '0' && buff.read() <= '9') + || ( buff.read() == '+' || buff.read() == '-') + ); + + std::size_t offset = 0; + + if (buff.read() == '-'){ + ++offset; + } else if (buff.read() == '+'){ + return make_error(); + } + if (offset >= buff.read_composite_length()) { + return make_error(); + } + if (buff.read(offset) >= '1' && buff.read(offset) <= '9') { + ++offset; + + if(offset >= buff.read_composite_length()) { + return make_error(); + } + + while(1){ + if (buff.read(offset) >= '0' && buff.read(offset) <= '9') { + ++offset; + + if(offset >= buff.read_composite_length()) { + break; + } + continue; + } + break; + } + } else if (buff.read(offset) == '0' ) { + ++offset; + } else { + return make_error(); + } + + { + std::string_view num_view{reinterpret_cast(&buff.read()), offset}; + typename native_data_type>::type result; + auto fc_result = std::from_chars(num_view.data(), num_view.data() + num_view.size(), result); + if(fc_result.ec != std::errc{}){ + return make_error(); + } + + to.set(result); + } + buff.read_advance(offset); + + return void_t{}; + } +}; + +template +struct json_decode { + static error_or decode(buffer_view& buff, data& to){ + assert(buff.read() == '"'); + buff.read_advance(1); + + std::stringstream iss; + bool string_done = false; + while(!string_done){ + if(buff.read_composite_length() == 0){ + return make_error(); + } + + switch(buff.read()){ + case '\\':{ + buff.read_advance(1); + if(buff.read_composite_length() == 0){ + return make_error(); + } + switch(buff.read()){ + case '\\': + case '/': + case '"': + iss<< buff.read(); + break; + case 'b': + iss<<'\b'; + break; + case 'f': + iss<<'\f'; + break; + case 'n': + iss<<'\n'; + break; + case 'r': + iss<<'\r'; + break; + case 't': + iss<<'\t'; + break; + case 'u': { + buff.read_advance(1); + if(buff.read_composite_length() < 4){ + return make_error(); + } + iss<<'?'; + iss<<'?'; + iss<<'?'; + iss<<'?'; + + buff.read_advance(3); + } break; + } + } break; + case '"': + string_done = true; + break; + default:{ + // Avoids Control sequences + if(buff.read() >= ' ' && buff.read() <= '~'){ + iss<(); + } + } while( buff.read() < 0 ); + iss<<'?'; + } + break; + } + } + buff.read_advance(1); + } + + std::string raw = iss.str(); + to.set(std::move(raw)); + + return void_t{}; + } +}; + +template +struct json_decode...>, RootSchema, ToDecode> { + template + static error_or decode_field_search(buffer_view& buff, data...>, ToDecode>& to, std::array& fields, const data& search_name){ + if constexpr ( i < sizeof...(T)){ + using Type = typename parameter_pack_type::type; + constexpr static string_literal Literal = parameter_key_pack_type::literal; + if(search_name == Literal.view()){ + if(fields[i]){ + return make_error(); + } + fields[i] = true; + auto eov = json_decode::decode(buff, to.template get()); + if(eov.is_error()){ + return eov; + } + }else { + decode_field_search(buff, to, fields, search_name); + } + }else { + return make_error(); + } + return void_t{}; + } + + static error_or decode_fields(buffer_view& buff, data...>, ToDecode>& to, std::array& fields){ + for(;;){ + data name; + auto eov = json_decode::decode(buff, name); + if(eov.is_error()){ + return eov; + } + json_helper::skip_whitespace(buff); + if(buff.read_composite_length() == 0){ + return make_error(); + } + if(buff.read() != ':'){ + return make_error(); + } + buff.read_advance(1); + json_helper::skip_whitespace(buff); + if(buff.read_composite_length() == 0){ + return make_error(); + } + { + auto eov = decode_field_search<0>(buff, to, fields, name); + if(eov.is_error()){ + return eov; + } + } + json_helper::skip_whitespace(buff); + if(buff.read_composite_length() == 0){ + return make_error(); + } + if(buff.read() == ','){ + buff.read_advance(1); + }else if(buff.read() == '}'){ + // If not all fields are set, the dataset is incomplete + for(auto& iter : fields){ + if(!iter){ + return make_error(); + } + } + buff.read_advance(1); + return void_t{}; + }else{ + return make_error(); + } + json_helper::skip_whitespace(buff); + if(buff.read_composite_length() == 0){ + return make_error(); + } + } + return void_t{}; + } + + static error_or decode(buffer_view& buff, data...>, ToDecode>& to){ + std::array found_fields; + std::fill(found_fields.begin(), found_fields.end(), false); + + assert(buff.read() == '{'); + buff.read_advance(1); + json_helper::skip_whitespace(buff); + if(buff.read_composite_length() == 0){ + return make_error(); + } + + // Check if there are no elements present in the JSON Struct + if(buff.read() == '}'){ + if(sizeof...(T) > 0){ + return make_error(); + } + buff.read_advance(1); + return void_t{}; + } + + auto eov = decode_fields(buff, to, found_fields); + if(eov.is_error()){ + return eov; + } + + return void_t{}; + } +}; + +template +struct json_decode, RootSchema, ToDecode> { + template + static error_or decode_element(buffer_view& buff, data, ToDecode>& to){ + if constexpr (i < sizeof...(T)){ + if constexpr ( i > 0 ){ + if(buff.read() != ','){ + return make_error(); + } + buff.read_advance(1); + if(buff.read_composite_length() == 0){ + return make_error(); + } + } + using Type = typename parameter_pack_type::type; + + auto eov = json_decode::decode(buff, to.template get()); + if(eov.is_error()){ + return eov; + } + json_helper::skip_whitespace(buff); + if(buff.read_composite_length() == 0){ + return make_error(); + } + + eov = decode_element(buff, to); + if(eov.is_error()){ + return eov; + } + }else{ + if(buff.read() != ']'){ + return make_error(); + } + buff.read_advance(1); + } + return void_t{}; + } + + static error_or decode(buffer_view& buff, data, ToDecode>& to){ + assert(buff.read() == '['); + buff.read_advance(1); + + json_helper::skip_whitespace(buff); + if(buff.read_composite_length() == 0){ + return make_error(); + } + + auto eov = decode_element<0>(buff, to); + if(eov.is_error()){ + return eov; + } + + return void_t{}; + } +}; + +// The whole std::vector approach is hacky af. ToDo change it maybe? +template +struct json_decode, RootSchema, ToDecode> { + template + static error_or decode_flat_level(buffer_view& buff, std::vector>& to, std::array& index, std::array& dims, bool log_dim){ + if constexpr (Level == D) { + json_helper::skip_whitespace(buff); + try { + to.push_back({}); + }catch(std::exception& e){ + return make_error(); + } + auto eov = json_decode::decode(buff, to.back()); + if(eov.is_error()){ + return eov; + } + } else { + assert(buff.read() == '['); + buff.read_advance(1); + + json_helper::skip_whitespace(buff); + if ( buff.read_composite_length() == 0 ){ + return make_error(); + } + + index[Level] = 0; + for(;;){ + // We should have an element right now + auto eov = decode_flat_level(buff,to,index,dims, index[Level] == 0 && log_dim); + if(eov.is_error()){ + return eov; + } + json_helper::skip_whitespace(buff); + if ( buff.read_composite_length() == 0 ){ + return make_error(); + } + + ++index[Level]; + if(buff.read() == ','){ + buff.read_advance(1); + } else if(buff.read() == ']'){ + buff.read_advance(1); + break; + } else { + return make_error(); + } + json_helper::skip_whitespace(buff); + if ( buff.read_composite_length() == 0 ){ + return make_error(); + } + } + if(log_dim){ + dims[Level] = index[Level]; + }else if (dims[Level] != index[Level]){ + return make_error(); + } + } + return void_t{}; + } + + template + static error_or decode_unflat_level(std::vector>& flat, data, ToDecode>& to, std::array& index, std::size_t& flat_index) { + if constexpr ( Level == D ){ + auto& flat_data = flat.at(flat_index); + to.at(index) = std::move(flat_data); + ++flat_index; + }else { + const std::size_t dim_size = to.get_dim_size(Level); + for(index[Level] = 0; index[Level] < dim_size; ++index[Level]){ + + auto eov = decode_unflat_level(flat, to, index, flat_index); + if(eov.is_error()){ + return eov; + } + } + } + return void_t{}; + } + + static error_or decode(buffer_view& buff, data, ToDecode>& to){ + std::array index; + std::array dims; + std::fill(dims.begin(), dims.end(), 0); + std::vector> flat_array; + auto eov = decode_flat_level<0>(buff, flat_array, index, dims, true); + if(eov.is_error()){ + return eov; + } + + to = {dims}; + std::size_t flat_index = 0; + + return decode_unflat_level<0>(flat_array, to, index, flat_index); + } +}; +} +} -- cgit v1.2.3