summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClaudius Holeksa <mail@keldu.de>2023-06-26 15:25:29 +0200
committerClaudius Holeksa <mail@keldu.de>2023-06-26 15:25:29 +0200
commit44b97c0c13c3cb05a5fed70326285b45bc7b37a6 (patch)
treebf26986e1b8f7415e4e3b72301cdde521efa5b6a
parent9b5fdb05609c24a03d4e0e4386e9eadbfe6c5405 (diff)
c++,codec: Added kelsimple array and struct decoding / encoding
-rw-r--r--src/codec/data.h14
-rw-r--r--src/codec/simple.h166
-rw-r--r--src/codec/stream_value.h34
-rw-r--r--tests/codec.cpp114
4 files changed, 303 insertions, 25 deletions
diff --git a/src/codec/data.h b/src/codec/data.h
index 5cb1267..a43fdd8 100644
--- a/src/codec/data.h
+++ b/src/codec/data.h
@@ -195,16 +195,18 @@ class data<schema::Array<T,Dim>, encode::Native> {
SAW_DEFAULT_COPY(data);
SAW_DEFAULT_MOVE(data);
+ data(const std::array<std::size_t, Dim>& i):
+ dims_{i},
+ value_{}
+ {
+ value_.resize(get_full_size());
+ }
+
template<std::integral... Dims>
data(Dims... size_):
- dims_{size_...},
- value_{}
+ data{{size_...}}
{
- for(auto& iter : dims_){
- assert(iter > 0);
- }
static_assert(sizeof...(Dims)==Dim, "Argument size must be equal to the Dimension");
- value_.resize(get_full_size());
}
data<T, encode::Native>& at(const std::array<std::size_t, Dim>& ind){
diff --git a/src/codec/simple.h b/src/codec/simple.h
index 1b6cf0d..ad66f66 100644
--- a/src/codec/simple.h
+++ b/src/codec/simple.h
@@ -1,6 +1,12 @@
#pragma once
#include "data.h"
+#include "stream_value.h"
+
+#include <iostream>
+
+#include <forstio/core/buffer.h>
+#include <forstio/core/error.h>
namespace saw {
namespace encode {
@@ -15,7 +21,7 @@ public:
data() = default;
buffer& get_buffer(){
- return buffer;
+ return buffer_;
}
};
@@ -25,13 +31,152 @@ class kelsimple_encode {
static_assert(always_false<Schema, FromEnc>, "This schema type is not being handled by the kelsimple encoding.");
};
-template<typename T, size_t N, typename Schema, typename FromEnc>
+template<typename T, size_t N, typename FromEnc>
struct kelsimple_encode<schema::Primitive<T,N>, FromEnc> {
static error_or<void> encode(const data<schema::Primitive<T,N>, FromEnc>& from, buffer& to){
-
+ auto eov = stream_value<schema::Primitive<T,N>>::encode(from.get(), to);
+ return eov;
+ }
+};
+
+template<typename T, size_t Dim, typename FromEnc>
+struct kelsimple_encode<schema::Array<T,Dim>, FromEnc> {
+ template<std::size_t Level>
+ static error_or<void> encode_level(const data<schema::Array<T,Dim>, FromEnc>& from, buffer& to, std::array<std::size_t, Dim>& index){
+ if constexpr (Dim == Level){
+ return kelsimple_encode<T,FromEnc>::encode(from.at(index), to);
+ } else {
+ const std::size_t dim_size = from.get_dim_size(Level);
+ for(index[Level] = 0; (index.at(Level) < dim_size); ++index[Level]){
+ auto eov = encode_level<Level+1>(from, to, index);
+ if(eov.is_error()){
+ return eov;
+ }
+ }
+ }
+ return void_t{};
+ }
+
+ static error_or<void> encode(const data<schema::Array<T,Dim>, FromEnc>& from, buffer& to){
+ {
+ for(uint64_t i = 0; i < Dim; ++i){
+ auto eov = stream_value<schema::UInt64>::encode(from.get_dim_size(i), to);
+ if(eov.is_error()){
+ return eov;
+ }
+ }
+ }
+ {
+ std::array<std::size_t, Dim> index;
+ std::fill(index.begin(), index.end(), 0);
+
+ return encode_level<0>(from, to, index);
+ }
+ return void_t{};
+ }
+};
+
+template<typename... T, string_literal... Lits, typename FromEnc>
+struct kelsimple_encode<schema::Struct<schema::Member<T,Lits>...>,FromEnc> {
+ template<std::size_t i>
+ static error_or<void> encode_member(const data<schema::Struct<schema::Member<T,Lits>...>, FromEnc>& from, buffer& to){
+ using Type = typename parameter_pack_type<i,T...>::type;
+ constexpr string_literal Literal = parameter_key_pack_type<i, Lits...>::literal;
+ {
+ auto eov = kelsimple_encode<Type, FromEnc>::encode(from.template get<Literal>(), to);
+ }
+ if constexpr ((i+1) < sizeof...(T)){
+ auto eov = encode_member<i+1>(from, to);
+ if(eov.is_error()){
+ return eov;
+ }
+ }
+ return void_t{};
+ }
+
+ static error_or<void> encode(const data<schema::Struct<schema::Member<T,Lits>...>, FromEnc>& from, buffer& to){
+ return encode_member<0>(from, to);
+ }
+};
+
+template<typename Schema, typename FromEnc>
+class kelsimple_decode {
+ static_assert(always_false<Schema, FromEnc>, "This schema type is not being handled by the kelsimple encoding.");
+};
+
+template<typename T, size_t N, typename FromEnc>
+struct kelsimple_decode<schema::Primitive<T,N>, FromEnc> {
+ static error_or<void> decode(buffer& from, data<schema::Primitive<T,N>, FromEnc>& to){
+ typename native_data_type<schema::Primitive<T,N>>::type val{};
+ auto eov = stream_value<schema::Primitive<T,N>>::decode(val, from);
+ if (eov.is_value()) {
+ to.set(val);
+ }
+ return eov;
+ }
+
+};
+template<typename T, size_t Dim, typename FromEnc>
+struct kelsimple_decode<schema::Array<T,Dim>, FromEnc> {
+ template<std::size_t Level>
+ static error_or<void> decode_level(buffer& from, data<schema::Array<T,Dim>, FromEnc>& to, std::array<std::size_t, Dim>& index){
+ if constexpr (Level == Dim){
+ return kelsimple_decode<T, FromEnc>::decode(from, to.at(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_level<Level+1>(from, to, index);
+ if(eov.is_error()){
+ return eov;
+ }
+ }
+ }
+ return void_t{};
+ }
+
+ static error_or<void> decode(buffer& from, data<schema::Array<T,Dim>, FromEnc>& to){
+ {
+ std::array<std::size_t, Dim> dims{};
+ for(std::size_t i = 0; i < Dim; ++i){
+ uint64_t val{};
+ auto eov = stream_value<schema::UInt64>::decode(val, from);
+ if(eov.is_error()){
+ return eov;
+ }
+ dims.at(i) = static_cast<std::size_t>(val);
+ }
+ to = data<schema::Array<T,Dim>,FromEnc>{dims};
+ }
+ {
+ std::array<std::size_t, Dim> index{};
+ return decode_level<0>(from, to, index);
+ }
+ return void_t{};
+ }
+};
+template<typename... T, string_literal... Lits, typename FromEnc>
+struct kelsimple_decode<schema::Struct<schema::Member<T,Lits>...>,FromEnc> {
+ template<std::size_t i>
+ static error_or<void> decode_member(buffer& from, data<schema::Struct<schema::Member<T,Lits>...>, FromEnc>& to){
+ using Type = typename parameter_pack_type<i,T...>::type;
+ constexpr string_literal Literal = parameter_key_pack_type<i, Lits...>::literal;
+ {
+ auto eov = kelsimple_decode<Type, FromEnc>::decode(from, to.template get<Literal>());
+ }
+ if constexpr ((i+1) < sizeof...(T)){
+ auto eov = decode_member<i+1>(from, to);
+ if(eov.is_error()){
+ return eov;
+ }
+ }
return void_t{};
+
}
+ static error_or<void> decode(buffer& from, data<schema::Struct<schema::Member<T,Lits>...>, FromEnc>& to){
+ return decode_member<0>(from, to);
+ }
+
};
}
@@ -54,9 +199,20 @@ public:
error_or<void> encode(const data<Schema, FromEnc>& from_enc, data<Schema, encode::KelSimple>& to_enc){
buffer_view buff_v{to_enc.get_buffer()};
- auto eov = kelsimple_encode::encode(from_env, buff_v);
+ auto eov = impl::kelsimple_encode<Schema, FromEnc>::encode(from_enc, buff_v);
- return void_t{};
+ to_enc.get_buffer().write_advance(buff_v.write_offset());
+
+ return eov;
+ }
+
+ template<typename ToDec>
+ error_or<void> decode(data<Schema, encode::KelSimple>& from_dec, data<Schema, ToDec>& to){
+ buffer_view buff_v{from_dec.get_buffer()};
+
+ auto eov = impl::kelsimple_decode<Schema,ToDec>::decode(buff_v, to);
+
+ return eov;
}
};
}
diff --git a/src/codec/stream_value.h b/src/codec/stream_value.h
index df1334b..09203cb 100644
--- a/src/codec/stream_value.h
+++ b/src/codec/stream_value.h
@@ -1,7 +1,9 @@
#pragma once
-#include "buffer.h"
-#include "error.h"
+#include "schema.h"
+
+#include <forstio/core/buffer.h>
+#include <forstio/core/error.h>
#include <cstdint>
#include <cstring>
@@ -13,44 +15,48 @@ namespace saw {
* platform independent. So it does not matter if the memory layout is
* little endian or big endian
*/
-template <typename T, size_t N> class ShiftStreamValue {
+template<typename T> class shift_stream_value {
+ static_assert(always_false<T>, "Shift Stream Value only supports Primitives");
+};
+
+template <typename T, size_t N> class shift_stream_value<schema::Primitive<T,N>> {
public:
inline static error_or<void> decode(typename native_data_type<schema::Primitive<T,N>>::type &val, buffer &buff) {
- if (buff.read_composite_length() < sizeof(T)) {
+ if (buff.read_composite_length() < N) {
return make_error<err::buffer_exhausted>();
}
typename native_data_type<schema::Primitive<schema::UnsignedInteger,N>>::type raw = 0;
- for (size_t i = 0; i < sizeof(T); ++i) {
- raw |= (static_cast<uint64_t>(buff.read(i)) << (i * 8));
+ for (size_t i = 0; i < N; ++i) {
+ raw |= (static_cast<typename native_data_type<schema::Primitive<T,N>>::type>(buff.read(i)) << (i * 8));
}
- memcpy(&val, &raw, sizeof(T));
- buff.read_advance(sizeof(T));
+ memcpy(&val, &raw, N);
+ buff.read_advance(N);
return void_t{};
}
inline static error_or<void> encode(const typename native_data_type<schema::Primitive<T,N>>::type &val, buffer &buff) {
- error err = buff.write_require_length(sizeof(T));
+ error err = buff.write_require_length(N);
if (err.failed()) {
return err;
}
typename native_data_type<schema::Primitive<schema::UnsignedInteger,N>>::type raw{};
- memcpy(&raw, &val, sizeof(T));
+ memcpy(&raw, &val, N);
- for (size_t i = 0; i < sizeof(T); ++i) {
- buffer.write(i) = raw >> (i * 8);
+ for (size_t i = 0; i < N; ++i) {
+ buff.write(i) = raw >> (i * 8);
}
- buffer.write_advance(sizeof(T));
+ buff.write_advance(N);
return void_t{};
}
- inline static size_t size() const { return N; }
+ inline static size_t size() { return N; }
};
template <typename T> using stream_value = shift_stream_value<T>;
diff --git a/tests/codec.cpp b/tests/codec.cpp
index 09e7228..5186df3 100644
--- a/tests/codec.cpp
+++ b/tests/codec.cpp
@@ -1,5 +1,6 @@
#include <forstio/test/suite.h>
#include <forstio/codec/data.h>
+#include <forstio/codec/simple.h>
namespace {
namespace schema {
@@ -10,6 +11,10 @@ using OneDimArray = Array<Int32,1>;
using TwoDimArray = Array<Int32,2>;
using ThreeDimArray = Array<Int32,3>;
+using TestStruct = Struct<
+ Member<TwoDimArray, "two_dim_array">,
+ Member<UInt64, "number">
+>;
}
SAW_TEST("One Dimensional Array") {
using namespace saw;
@@ -75,4 +80,113 @@ SAW_TEST("Three Dimensional Array") {
}
SAW_EXPECT(sum == 124750, std::to_string(sum) + " is not 124750. Expected that data stays correct");
}
+
+SAW_TEST("KelSimple UInt16 write"){
+ using namespace saw;
+ data<schema::UInt16, encode::Native> native;
+ data<schema::UInt16, encode::KelSimple> simple;
+
+ codec<schema::UInt16, encode::KelSimple> codec;
+
+ auto& buff = simple.get_buffer();
+
+ for(uint16_t i = 0; i < 256; ++i){
+ for(uint16_t j = 0; j < 256; ++j){
+ native.set(i + j * 256);
+ error_or<void> eov = codec.encode(native, simple);
+ SAW_EXPECT(eov.is_value(), "Encoding error");
+
+ SAW_EXPECT(buff.read_composite_length() == 2, "Written incorrect size");
+ SAW_EXPECT((buff.read(0) == i && buff.read(1) == j), std::string{"Incorrect values in encoding: "} + std::to_string(static_cast<uint16_t>(buff.read(0))) + " " + std::to_string(static_cast<uint16_t>(buff.read(1))));
+ buff.read_advance(2);
+
+ }
+ }
+}
+
+SAW_TEST("KelSimple UInt32 write"){
+ using namespace saw;
+ data<schema::UInt32, encode::Native> native;
+ data<schema::UInt32, encode::KelSimple> simple;
+
+ codec<schema::UInt32, encode::KelSimple> codec;
+
+ auto& buff = simple.get_buffer();
+
+ for(uint16_t i = 0; i < 256; ++i){
+ for(uint16_t j = 0; j < 256; ++j){
+ native.set(i + j * 256 * 256);
+ error_or<void> eov = codec.encode(native, simple);
+ SAW_EXPECT(eov.is_value(), "Encoding error");
+
+ SAW_EXPECT(buff.read_composite_length() == 4, "Written incorrect size");
+ SAW_EXPECT((buff.read(0) == i && buff.read(1) == 0 && buff.read(2) == j && buff.read(3) == 0), std::string{"Incorrect values in encoding: "} + std::to_string(static_cast<uint16_t>(buff.read(0))) + " " + std::to_string(static_cast<uint16_t>(buff.read(1))));
+ buff.read_advance(4);
+
+ }
+ }
+}
+
+SAW_TEST("KelSimple Array write and read back"){
+ using namespace saw;
+ data<schema::TwoDimArray, encode::Native> native{2,3};
+ data<schema::TwoDimArray, encode::KelSimple> simple;
+
+ codec<schema::TwoDimArray, encode::KelSimple> codec;
+
+ for(std::size_t i = 0; i < 2; ++i) {
+ for(std::size_t j = 0; j < 3; ++j){
+ native.at(i,j).set(i+2*j);
+ }
+ }
+
+ auto eov = codec.encode(native,simple);
+ SAW_EXPECT(eov.is_value(), "Encoding error");
+
+ for(std::size_t i = 0; i < 2; ++i) {
+ for(std::size_t j = 0; j < 3; ++j){
+ native.at(i,j).set(0);
+ }
+ }
+
+ eov = codec.decode(simple, native);
+ SAW_EXPECT(eov.is_value(), "Decoding error");
+
+ for(std::size_t i = 0; i < 2; ++i) {
+ for(std::size_t j = 0; j < 3; ++j){
+ SAW_EXPECT(native.at(i,j).get() == static_cast<int32_t>(i+2*j), "Values incorrectly decoded");
+ }
+ }
+}
+
+SAW_TEST("KelSimple Struct write and read back"){
+ using namespace saw;
+
+ data<schema::TestStruct,encode::Native> native;
+ data<schema::TestStruct,encode::KelSimple> simple;
+
+ auto& tda = native.template get<"two_dim_array">();
+ tda = {1,2};
+
+ tda.at(0,0).set(5);
+ tda.at(0,1).set(3);
+ native.template get<"number">().set(410);
+
+ codec<schema::TestStruct, encode::KelSimple> codec;
+
+ auto eov = codec.encode(native, simple);
+ SAW_EXPECT(eov.is_value(), "Encoding error");
+
+ // Reset values
+ native = {};
+
+ eov = codec.decode(simple, native);
+ SAW_EXPECT(eov.is_value(), "Decoding error");
+
+ auto& dec_tda = native.template get<"two_dim_array">();
+
+ SAW_EXPECT(dec_tda.at(0,0).get() == 5, "Incorrect Decoding in array 0,0");
+ SAW_EXPECT(dec_tda.at(0,1).get() == 3, "Incorrect Decoding in array 0,1");
+ SAW_EXPECT(native.template get<"number">().get() == 410, "Incorrect Decoding in number");
+}
}