From 0bd38cdec70c3a07467fccd81b570b754996eb95 Mon Sep 17 00:00:00 2001 From: Claudius Holeksa Date: Tue, 27 Jun 2023 19:16:46 +0200 Subject: c++,codec-json,codec: Working on fixes for JSON Array decoding. Test failing currently --- src/codec-json/json.tmpl.h | 147 +++++++++++++++++++++++++++++++++++++++++++-- src/codec/data.h | 39 ++++++------ tests/codec-json.cpp | 21 ++++++- 3 files changed, 180 insertions(+), 27 deletions(-) diff --git a/src/codec-json/json.tmpl.h b/src/codec-json/json.tmpl.h index 063595d..4f4d6f4 100644 --- a/src/codec-json/json.tmpl.h +++ b/src/codec-json/json.tmpl.h @@ -1,6 +1,7 @@ #pragma once #include +#include namespace saw { namespace impl { @@ -387,30 +388,164 @@ struct json_decode, RootSchema, ToDecode> { } }; +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: + iss< struct json_decode, RootSchema, ToDecode> { template - static error_or decode_level(buffer_view& buff, data, ToDecode>& to, std::array& index){ + 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) { - auto eov = json_decode::decode(buff, to.at(index)); + json_helper::skip_whitespace(buff); + to.push_back({}); + auto eov = json_decode::decode(buff, to.back()); if(eov.is_error()){ return eov; } } else { assert(buff.read() == '['); buff.read_advance(1); - if( buff.read_composite_length() == 0 ){ - return make_error(); - } 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(const std::vector>& flat, data, ToDecode>& to, std::array& index, std::size_t& flat_index) { + if constexpr ( Level == D ){ + to.at(index) = flat.at(flat_index); + ++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; + } + } + } + } + static error_or decode(buffer_view& buff, data, ToDecode>& to){ std::array index; - return decode_level<0>(buff, to, 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/src/codec/data.h b/src/codec/data.h index 397aed1..76be8e5 100644 --- a/src/codec/data.h +++ b/src/codec/data.h @@ -187,19 +187,6 @@ class data, encode::Native> { return s; } - - std::size_t get_index(const std::array& i) const { - std::size_t s = 0; - - std::size_t stride = 1; - - for(std::size_t iter = 0; iter < Dim; ++iter){ - s += i.at(iter) * stride; - stride *= dims_.at(iter); - } - - return s; - } public: data() = default; SAW_DEFAULT_COPY(data); @@ -220,21 +207,21 @@ class data, encode::Native> { } data& at(const std::array& ind){ - return value_.at(this->get_index(ind)); + return value_.at(this->get_flat_index(ind)); } const data& at(const std::array& ind) const { - return value_.at(this->get_index(ind)); + return value_.at(this->get_flat_index(ind)); } template data& at(Dims... i){ - return value_.at(this->get_index({i...})); + return value_.at(this->get_flat_index({i...})); } template const data& at(Dims... i) const { - return value_.at(this->get_index({i...})); + return value_.at(this->get_flat_index({i...})); } std::size_t get_dim_size(std::size_t i) const { @@ -242,6 +229,20 @@ class data, encode::Native> { } size_t size() const { return value_.size();} + +private: + std::size_t get_flat_index(const std::array& i) const { + std::size_t s = 0; + + std::size_t stride = 1; + + for(std::size_t iter = 0; iter < Dim; ++iter){ + s += i.at(iter) * stride; + stride *= dims_.at(iter); + } + + return s; + } }; template<> @@ -282,8 +283,8 @@ public: value_.at(i) = val; } - bool operator==(const data& data){ - return value_ == data.value_; + bool operator==(const std::string_view& val)const{ + return value_ == val; } }; diff --git a/tests/codec-json.cpp b/tests/codec-json.cpp index fec82b0..9406a5c 100644 --- a/tests/codec-json.cpp +++ b/tests/codec-json.cpp @@ -259,15 +259,24 @@ SAW_TEST("Three Dim Array write"){ native.at(1,0,0).set("foo"); native.at(1,0,1).set("bar"); - codec json_codec; + codec codec; - error_or eov = json_codec.encode(native, json); + error_or eov = codec.encode(native, json); SAW_EXPECT(eov.is_value(), "Encoding error"); std::string_view str_v = "[[[\"multi\",\"baz\"]],[[\"foo\",\"bar\"]]]"; std::string enc_val = convert_to_string(json.get_buffer()); SAW_EXPECT(enc_val == str_v, std::string{"Array not encoded correctly. Encoded: "} + enc_val + std::string{" Expected: "} + std::string{str_v}); + + native = {}; + eov = codec.decode(json, native); + SAW_EXPECT(eov.is_value(), "Decoding error"); + SAW_EXPECT(native.at(0,0,0) == "multi", "Invalid Value at 0,0,0"); + SAW_EXPECT(native.at(0,0,1) == "baz", "Invalid Value at 0,0,1"); + SAW_EXPECT(native.at(1,0,0) == "foo", "Invalid Value at 1,0,0"); + SAW_EXPECT(native.at(1,0,1) == "bar", "Invalid Value at 1,0,1"); + } SAW_TEST("Struct write"){ @@ -287,6 +296,14 @@ SAW_TEST("Struct write"){ std::string enc_val = convert_to_string(json.get_buffer()); SAW_EXPECT(enc_val == str_v, std::string{"Struct not encoded correctly. Encoded: "} + enc_val + std::string{" Expected: "} + std::string{str_v}); + + /* + native = {}; + eov = json_codec.decode(json, native); + SAW_EXPECT(eov.is_value(), "Decoding error"); + SAW_EXPECT(native.get<"foo">().get() == 5, "Invalid value for foo"); + SAW_EXPECT(native.get<"bar">().get() == "baz", "Invalid value for bar"); + */ } SAW_TEST("Int8 read"){ -- cgit v1.2.3