summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/codec-json/json.tmpl.h147
-rw-r--r--src/codec/data.h39
-rw-r--r--tests/codec-json.cpp21
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 <charconv>
+#include <sstream>
namespace saw {
namespace impl {
@@ -387,30 +388,164 @@ struct json_decode<schema::Primitive<T,N>, RootSchema, ToDecode> {
}
};
+template<typename RootSchema, typename ToDecode>
+struct json_decode<schema::String, RootSchema, ToDecode> {
+ static error_or<void> decode(buffer_view& buff, data<schema::String, ToDecode>& 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<err::buffer_exhausted>();
+ }
+
+ switch(buff.read()){
+ case '\\':{
+ buff.read_advance(1);
+ if(buff.read_composite_length() == 0){
+ return make_error<err::buffer_exhausted>();
+ }
+ 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<err::buffer_exhausted>();
+ }
+ iss<<'?';
+ iss<<'?';
+ iss<<'?';
+ iss<<'?';
+
+ buff.read_advance(3);
+ } break;
+ }
+ } break;
+ case '"':
+ string_done = true;
+ break;
+ default:
+ iss<<buff.read();
+ break;
+ }
+ buff.read_advance(1);
+ }
+
+ std::string raw = iss.str();
+ to.set(std::move(raw));
+
+ return void_t{};
+ }
+};
+
+// The whole std::vector approach is hacky af
template<typename T, size_t D, typename RootSchema, typename ToDecode>
struct json_decode<schema::Array<T,D>, RootSchema, ToDecode> {
template<size_t Level>
- static error_or<void> decode_level(buffer_view& buff, data<schema::Array<T,D>, ToDecode>& to, std::array<std::size_t, D>& index){
+ static error_or<void> decode_flat_level(buffer_view& buff, std::vector<data<T, encode::Native>>& to, std::array<std::size_t, D>& index, std::array<std::size_t, D>& dims, bool log_dim){
if constexpr (Level == D) {
- auto eov = json_decode<T, RootSchema, ToDecode>::decode(buff, to.at(index));
+ json_helper::skip_whitespace(buff);
+ to.push_back({});
+ auto eov = json_decode<T, RootSchema, ToDecode>::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<err::buffer_exhausted>();
- }
json_helper::skip_whitespace(buff);
+ if ( buff.read_composite_length() == 0 ){
+ return make_error<err::buffer_exhausted>();
+ }
+
+ index[Level] = 0;
+ for(;;){
+ // We should have an element right now
+ auto eov = decode_flat_level<Level+1>(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<err::buffer_exhausted>();
+ }
+
+ ++index[Level];
+ if(buff.read(',')){
+ buff.read_advance(1);
+ } else if(buff.read(']')){
+ buff.read_advance(1);
+ break;
+ } else {
+ return make_error<err::invalid_state>();
+ }
+ json_helper::skip_whitespace(buff);
+ if ( buff.read_composite_length() == 0 ){
+ return make_error<err::buffer_exhausted>();
+ }
+ }
+ if(log_dim){
+ dims[Level] = index[Level];
+ }else if (dims[Level] != index[Level]){
+ return make_error<err::invalid_state>();
+ }
}
return void_t{};
}
+ template<std::size_t Level>
+ static error_or<void> decode_unflat_level(const std::vector<data<T,encode::Native>>& flat, data<schema::Array<T,D>, ToDecode>& to, std::array<std::size_t, D>& 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<Level+1>(flat, to, index, flat_index);
+ if(eov.is_error()){
+ return eov;
+ }
+ }
+ }
+ }
+
static error_or<void> decode(buffer_view& buff, data<schema::Array<T,D>, ToDecode>& to){
std::array<std::size_t, D> index;
- return decode_level<0>(buff, to, index);
+ std::array<std::size_t, D> dims;
+ std::fill(dims.begin(), dims.end(), 0);
+ std::vector<data<T,encode::Native>> 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<schema::Array<T,Dim>, encode::Native> {
return s;
}
-
- std::size_t get_index(const std::array<std::size_t, Dim>& 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<schema::Array<T,Dim>, encode::Native> {
}
data<T, encode::Native>& at(const std::array<std::size_t, Dim>& ind){
- return value_.at(this->get_index(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_index(ind));
+ return value_.at(this->get_flat_index(ind));
}
template<std::integral... Dims>
data<T, encode::Native>& at(Dims... i){
- return value_.at(this->get_index({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_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<schema::Array<T,Dim>, encode::Native> {
}
size_t size() const { return value_.size();}
+
+private:
+ std::size_t get_flat_index(const std::array<std::size_t, Dim>& 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<schema::String, encode::Native>& 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<schema::TestMultiArray, encode::Json> json_codec;
+ codec<schema::TestMultiArray, encode::Json> codec;
- error_or<void> eov = json_codec.encode(native, json);
+ error_or<void> 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"){