From fac9e8bec1983fa9dff8f447fef106e427dfec26 Mon Sep 17 00:00:00 2001 From: "Claudius \"keldu\" Holeksa" Date: Thu, 20 Jul 2023 17:02:05 +0200 Subject: c++: Renamed src to c++ --- c++/codec/.nix/derivation.nix | 30 ++++ c++/codec/SConscript | 38 +++++ c++/codec/SConstruct | 66 +++++++ c++/codec/data.h | 317 ++++++++++++++++++++++++++++++++++ c++/codec/forst.h | 13 ++ c++/codec/schema.h | 93 ++++++++++ c++/codec/simple.h | 389 ++++++++++++++++++++++++++++++++++++++++++ c++/codec/stream_value.h | 64 +++++++ 8 files changed, 1010 insertions(+) create mode 100644 c++/codec/.nix/derivation.nix create mode 100644 c++/codec/SConscript create mode 100644 c++/codec/SConstruct create mode 100644 c++/codec/data.h create mode 100644 c++/codec/forst.h create mode 100644 c++/codec/schema.h create mode 100644 c++/codec/simple.h create mode 100644 c++/codec/stream_value.h (limited to 'c++/codec') diff --git a/c++/codec/.nix/derivation.nix b/c++/codec/.nix/derivation.nix new file mode 100644 index 0000000..768dc6e --- /dev/null +++ b/c++/codec/.nix/derivation.nix @@ -0,0 +1,30 @@ +{ lib +, stdenvNoCC +, scons +, clang +, clang-tools +, version +, forstio +}: + +let + +in stdenvNoCC.mkDerivation { + pname = "forstio-codec"; + inherit version; + src = ./..; + + enableParallelBuilding = true; + + buildInputs = [ + forstio.core + ]; + + nativeBuildInputs = [ + scons + clang + clang-tools + ]; + + outputs = ["out" "dev"]; +} diff --git a/c++/codec/SConscript b/c++/codec/SConscript new file mode 100644 index 0000000..c038d42 --- /dev/null +++ b/c++/codec/SConscript @@ -0,0 +1,38 @@ +#!/bin/false + +import os +import os.path +import glob + + +Import('env') + +dir_path = Dir('.').abspath + +# Environment for base library +codec_env = env.Clone(); + +codec_env.sources = sorted(glob.glob(dir_path + "/*.cpp")) +codec_env.headers = sorted(glob.glob(dir_path + "/*.h")) + +env.sources += codec_env.sources; +env.headers += codec_env.headers; + +## Shared lib +objects_shared = [] +codec_env.add_source_files(objects_shared, codec_env.sources, shared=True); +codec_env.library_shared = codec_env.SharedLibrary('#build/forstio-codec', [objects_shared]); + +## Static lib +objects_static = [] +codec_env.add_source_files(objects_static, codec_env.sources, shared=False); +codec_env.library_static = codec_env.StaticLibrary('#build/forstio-codec', [objects_static]); + +# Set Alias +env.Alias('library_codec', [codec_env.library_shared, codec_env.library_static]); + +env.targets += ['library_codec']; + +# Install +env.Install('$prefix/lib/', [codec_env.library_shared, codec_env.library_static]); +env.Install('$prefix/include/forstio/codec/', [codec_env.headers]); diff --git a/c++/codec/SConstruct b/c++/codec/SConstruct new file mode 100644 index 0000000..0d7b7c6 --- /dev/null +++ b/c++/codec/SConstruct @@ -0,0 +1,66 @@ +#!/usr/bin/env python3 + +import sys +import os +import os.path +import glob +import re + + +if sys.version_info < (3,): + def isbasestring(s): + return isinstance(s,basestring) +else: + def isbasestring(s): + return isinstance(s, (str,bytes)) + +def add_kel_source_files(self, sources, filetype, lib_env=None, shared=False, target_post=""): + + if isbasestring(filetype): + dir_path = self.Dir('.').abspath + filetype = sorted(glob.glob(dir_path+"/"+filetype)) + + for path in filetype: + target_name = re.sub( r'(.*?)(\.cpp|\.c\+\+)', r'\1' + target_post, path ) + if shared: + target_name+='.os' + sources.append( self.SharedObject( target=target_name, source=path ) ) + else: + target_name+='.o' + sources.append( self.StaticObject( target=target_name, source=path ) ) + pass + +def isAbsolutePath(key, dirname, env): + assert os.path.isabs(dirname), "%r must have absolute path syntax" % (key,) + +env_vars = Variables( + args=ARGUMENTS +) + +env_vars.Add('prefix', + help='Installation target location of build results and headers', + default='/usr/local/', + validator=isAbsolutePath +) + +env=Environment(ENV=os.environ, variables=env_vars, CPPPATH=[], + CPPDEFINES=['SAW_UNIX'], + CXXFLAGS=['-std=c++20','-g','-Wall','-Wextra'], + LIBS=['forstio-core']) +env.__class__.add_source_files = add_kel_source_files +env.Tool('compilation_db'); +env.cdb = env.CompilationDatabase('compile_commands.json'); + +env.objects = []; +env.sources = []; +env.headers = []; +env.targets = []; + +Export('env') +SConscript('SConscript') + +env.Alias('cdb', env.cdb); +env.Alias('all', [env.targets]); +env.Default('all'); + +env.Alias('install', '$prefix') diff --git a/c++/codec/data.h b/c++/codec/data.h new file mode 100644 index 0000000..8ff06dc --- /dev/null +++ b/c++/codec/data.h @@ -0,0 +1,317 @@ +#pragma once + +#include +#include + +#include + +#include +#include +#include +#include + +#include "schema.h" + +namespace saw { +namespace encode { +struct Native {}; +} +template +class codec; +/* + * Helper for the basic message container, so the class doesn't have to be + * specialized 10 times. + */ +template struct native_data_type; + +template <> +struct native_data_type> { + using type = int8_t; +}; + +template <> +struct native_data_type> { + using type = int16_t; +}; + +template <> +struct native_data_type> { + using type = int32_t; +}; + +template <> +struct native_data_type> { + using type = int64_t; +}; + +template <> +struct native_data_type> { + using type = uint8_t; +}; + +template <> +struct native_data_type> { + using type = uint16_t; +}; + +template <> +struct native_data_type> { + using type = uint32_t; +}; + +template <> +struct native_data_type> { + using type = uint64_t; +}; + +template <> +struct native_data_type> { + using type = float; +}; + +template <> +struct native_data_type> { + using type = double; +}; + +template +class data { +private: + static_assert(always_false, "Type not supported"); +}; + +template +class data...>, encode::Native> { +private: + std::variant...> value_; +public: + data() = default; + + SAW_DEFAULT_COPY(data); + SAW_DEFAULT_MOVE(data); + + template + void set(data::value, T...>::type, encode::Native> val){ + value_ = std::move(val); + } + + template + data::value, T...>::type, encode::Native>& init(){ + value_ = data::value, T...>::type, encode::Native>{}; + return get(); + } + + template + bool holds_alternative() const { + return (parameter_key_pack_index::value == value_.index()); + } + + template + data::value, T...>::type, encode::Native>& get(){ + return std::get::value>(value_); + } + + template + const data::value, T...>::type, encode::Native>& get() const{ + return std::get::value>(value_); + } +}; + +template +class data...>, encode::Native> { +private: + std::tuple...> value_; +public: + data() = default; + SAW_DEFAULT_COPY(data); + SAW_DEFAULT_MOVE(data); + + template + data< + typename parameter_pack_type< + parameter_key_pack_index< + literal, literals... + >::value + , T...>::type + , encode::Native>& get(){ + return std::get::value>(value_); + } + + template + const data< + typename parameter_pack_type< + parameter_key_pack_index< + literal, literals... + >::value + , T...>::type + , encode::Native>& get() const { + return std::get::value>(value_); + } + + constexpr size_t size() const { + return sizeof...(T); + } +}; + +template +class data, encode::Native> { +private: + std::tuple...> value_; +public: + data() = default; + SAW_DEFAULT_COPY(data); + SAW_DEFAULT_MOVE(data); + + template + data::type, encode::Native>& get(){ + return std::get(value_); + } + + template + const data::type, encode::Native>& get() const{ + return std::get(value_); + } + + constexpr size_t size() const { + return sizeof...(T); + } +}; + +template +class data, encode::Native> { + private: + std::array dims_; + std::vector> value_; + + std::size_t get_full_size() const { + std::size_t s = 1; + + for(std::size_t iter = 0; iter < Dim; ++iter){ + assert(dims_.at(iter) > 0); + s *= dims_.at(iter); + } + + return s; + } + public: + data() = default; + SAW_DEFAULT_COPY(data); + SAW_DEFAULT_MOVE(data); + + data(const std::array& i): + dims_{i}, + value_{} + { + value_.resize(get_full_size()); + } + + template + data(Dims... size_): + data{{size_...}} + { + static_assert(sizeof...(Dims)==Dim, "Argument size must be equal to the Dimension"); + } + + data& at(const std::array& ind){ + return value_.at(this->get_flat_index(ind)); + } + + const data& at(const std::array& ind) const { + return value_.at(this->get_flat_index(ind)); + } + + template + data& at(Dims... i){ + return value_.at(this->get_flat_index({i...})); + } + + template + const data& at(Dims... i) const { + return value_.at(this->get_flat_index({i...})); + } + + std::size_t get_dim_size(std::size_t i) const { + return dims_.at(i); + } + + 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<> +class data { +private: + std::string value_; +public: + data() = default; + SAW_DEFAULT_COPY(data); + SAW_DEFAULT_MOVE(data); + + data(std::string value__):value_{std::move(value__)}{} + data(std::size_t size_){ + value_.resize(size_); + } + + std::size_t size() const { + return value_.size(); + } + + void set(std::string str){ + value_ = std::move(str); + } + + char& at(size_t i) { + return value_.at(i); + } + + const char& at(size_t i) const { + return value_.at(i); + } + + char get_at(size_t i) const{ + return value_.at(i); + } + + void set_at(size_t i, char val){ + value_.at(i) = val; + } + + bool operator==(const std::string_view& val)const{ + return value_ == val; + } +}; + +template +class data, encode::Native> { +private: + typename native_data_type>::type value_; +public: + data():value_{{}}{}; + SAW_DEFAULT_COPY(data); + SAW_DEFAULT_MOVE(data); + + data(typename native_data_type>::type value__): + value_{std::move(value__)}{} + + void set(typename native_data_type>::type val){ + value_ = val; + } + + typename native_data_type>::type get() const {return value_;} +}; + + +} diff --git a/c++/codec/forst.h b/c++/codec/forst.h new file mode 100644 index 0000000..cadf78e --- /dev/null +++ b/c++/codec/forst.h @@ -0,0 +1,13 @@ +#pragma once + +#include "data.h" + +namespace saw { +namespace encode { +struct KelForst {}; +} + +class data { + +}; +} diff --git a/c++/codec/schema.h b/c++/codec/schema.h new file mode 100644 index 0000000..2f63fe9 --- /dev/null +++ b/c++/codec/schema.h @@ -0,0 +1,93 @@ +#pragma once + +#include +#include + +namespace saw { +namespace schema { +// NOLINTBEGIN +template struct Member {}; + +template struct Struct { + static_assert( + always_false, + "This schema template doesn't support this type of template argument"); +}; + +template +struct Struct...> {}; + +template struct Union { + static_assert( + always_false, + "This schema template doesn't support this type of template argument"); +}; + +template +struct Union...> {}; + +template struct Array {}; + +template struct is_array { + constexpr static bool value = false; +}; + +template struct is_array> { + constexpr static bool value = true; +}; + +template struct FixedArray {}; + +template struct Tuple {}; + +/** + * This acts as a separator of different encodings being mashed together + */ +template +class Wrapper {}; + +struct String {}; + +struct SignedInteger {}; +struct UnsignedInteger {}; +struct FloatingPoint {}; + +template struct Primitive { + static_assert(((std::is_same_v || + std::is_same_v)&&(N == 1 || N == 2 || + N == 4 || N == 8)) || + (std::is_same_v && (N == 4 || N == 8)), + "Primitive Type is not supported"); +}; + +using Int8 = Primitive; +using Int16 = Primitive; +using Int32 = Primitive; +using Int64 = Primitive; + +using UInt8 = Primitive; +using UInt16 = Primitive; +using UInt32 = Primitive; +using UInt64 = Primitive; + +using Float32 = Primitive; +using Float64 = Primitive; + +/** + * Classes enabling Rpc calls + */ +template +struct Function {}; + +template struct Interface { + static_assert( + always_false, + "This schema template doesn't support this type of template argument"); +}; + +template +struct Interface...> {}; + +// NOLINTEND +} // namespace schema +} // namespace saw diff --git a/c++/codec/simple.h b/c++/codec/simple.h new file mode 100644 index 0000000..8760754 --- /dev/null +++ b/c++/codec/simple.h @@ -0,0 +1,389 @@ +#pragma once + +#include "data.h" +#include "stream_value.h" + +#include +#include + +namespace saw { +namespace encode { +struct KelSimple {}; +} + +template +class data { +private: + ring_buffer buffer_; +public: + data() = default; + + buffer& get_buffer(){ + return buffer_; + } +}; + +namespace impl { +template +class kelsimple_encode { + static_assert(always_false, "This schema type is not being handled by the kelsimple encoding."); +}; + +template +struct kelsimple_encode, FromEnc> { + static error_or encode(const data, FromEnc>& from, buffer& to){ + auto eov = stream_value>::encode(from.get(), to); + return eov; + } +}; + +template +struct kelsimple_encode, FromEnc> { + template + static error_or encode_level(const data, FromEnc>& from, buffer& to, std::array& index){ + if constexpr (Dim == Level){ + return kelsimple_encode::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(from, to, index); + if(eov.is_error()){ + return eov; + } + } + } + return void_t{}; + } + + static error_or encode(const data, FromEnc>& from, buffer& to){ + { + for(uint64_t i = 0; i < Dim; ++i){ + auto eov = stream_value::encode(from.get_dim_size(i), to); + if(eov.is_error()){ + return eov; + } + } + } + { + std::array index; + std::fill(index.begin(), index.end(), 0); + + return encode_level<0>(from, to, index); + } + return void_t{}; + } +}; + +template +struct kelsimple_encode...>,FromEnc> { + template + static error_or encode_member(const data...>, FromEnc>& from, buffer& to){ + using Type = typename parameter_pack_type::type; + constexpr string_literal Literal = parameter_key_pack_type::literal; + { + auto eov = kelsimple_encode::encode(from.template get(), to); + if(eov.is_error()){ + return eov; + } + } + if constexpr ((i+1) < sizeof...(T)){ + auto eov = encode_member(from, to); + if(eov.is_error()){ + return eov; + } + } + return void_t{}; + } + + static error_or encode(const data...>, FromEnc>& from, buffer& to){ + return encode_member<0>(from, to); + } +}; + +template +struct kelsimple_encode...>,FromEnc> { + template + static error_or encode_member(const data...>, FromEnc>& from, buffer& to){ + using Type = typename parameter_pack_type::type; + constexpr string_literal Literal = parameter_key_pack_type::literal; + if (from.template holds_alternative()) { + { + auto eov = stream_value::encode(static_cast(i), to); + if(eov.is_error()){ + return eov; + } + } + { + auto eov = kelsimple_encode::encode(from.template get(), to); + if(eov.is_error()){ + return eov; + } + } + } + + if constexpr ( (i+1) < sizeof...(T) ){ + auto eov = encode_member(from, to); + if(eov.is_error()){ + return eov; + } + } + return void_t{}; + } + + static error_or encode(const data...>, FromEnc>& from, buffer& to){ + return encode_member<0>(from, to); + } +}; + +template +struct kelsimple_encode, FromEnc> { + template + static error_or encode_member(const data, FromEnc>& from, buffer& to){ + using Type = typename parameter_pack_type::type; + { + auto eov = kelsimple_encode::encode(from.template get(), to); + } + if constexpr ((i+1) < sizeof...(T)){ + auto eov = encode_member(from, to); + if(eov.is_error()){ + return eov; + } + } + return void_t{}; + } + + static error_or encode(const data, FromEnc>& from, buffer& to){ + return encode_member<0>(from, to); + } +}; + +template +struct kelsimple_encode { + static error_or encode(const data& from, buffer& to){ + const auto str_size = from.size(); + typename native_data_type::type str_len = static_cast(str_size); + { + auto eov = stream_value::encode(str_len, to); + if(eov.is_error()){ + return eov; + } + } + + for(std::size_t i = 0; i < str_size; ++i){ + auto eov = stream_value::encode(from.at(i), to); + if(eov.is_error()){ + return eov; + } + } + + return void_t{}; + } +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +template +class kelsimple_decode { + static_assert(always_false, "This schema type is not being handled by the kelsimple encoding."); +}; + +template +struct kelsimple_decode, FromEnc> { + static error_or decode(buffer& from, data, FromEnc>& to){ + typename native_data_type>::type val{}; + auto eov = stream_value>::decode(val, from); + if (eov.is_value()) { + to.set(val); + } + return eov; + } + +}; + +template +struct kelsimple_decode, FromEnc> { + template + static error_or decode_level(buffer& from, data, FromEnc>& to, std::array& index){ + if constexpr (Level == Dim){ + return kelsimple_decode::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(from, to, index); + if(eov.is_error()){ + return eov; + } + } + } + return void_t{}; + } + + static error_or decode(buffer& from, data, FromEnc>& to){ + { + std::array dims{}; + for(std::size_t i = 0; i < Dim; ++i){ + uint64_t val{}; + auto eov = stream_value::decode(val, from); + if(eov.is_error()){ + return eov; + } + dims.at(i) = static_cast(val); + } + to = data,FromEnc>{dims}; + } + { + std::array index{}; + return decode_level<0>(from, to, index); + } + return void_t{}; + } +}; +template +struct kelsimple_decode...>,FromEnc> { + template + static error_or decode_member(buffer& from, data...>, FromEnc>& to){ + using Type = typename parameter_pack_type::type; + constexpr string_literal Literal = parameter_key_pack_type::literal; + { + auto eov = kelsimple_decode::decode(from, to.template get()); + if(eov.is_error()){ + return eov; + } + } + if constexpr ((i+1) < sizeof...(T)){ + auto eov = decode_member(from, to); + if(eov.is_error()){ + return eov; + } + } + return void_t{}; + + } + static error_or decode(buffer& from, data...>, FromEnc>& to){ + return decode_member<0>(from, to); + } + +}; + +template +struct kelsimple_decode...>,FromEnc> { + template + static error_or decode_member(buffer& from, data...>, FromEnc>& to, uint64_t val){ + using Type = typename parameter_pack_type::type; + constexpr string_literal Literal = parameter_key_pack_type::literal; + + if( i == val ){ + to.template set(data{}); + auto eov = kelsimple_decode::decode(from, to.template get()); + if(eov.is_error()){ + return eov; + } + return void_t{}; + } + + if constexpr ((i+1) < sizeof...(T)){ + auto eov = decode_member(from, to, val); + if(eov.is_error()){ + return eov; + } + } + return void_t{}; + + } + static error_or decode(buffer& from, data...>, FromEnc>& to){ + uint64_t val{}; + auto eov = stream_value::decode(val, from); + if(eov.is_error()){ + return eov; + } + if ( val >= sizeof...(T) ){ + return make_error(); + } + return decode_member<0>(from, to, val); + } + +}; + +template +struct kelsimple_decode,FromEnc> { + template + static error_or decode_member(buffer& from, data, FromEnc>& to){ + using Type = typename parameter_pack_type::type; + { + auto eov = kelsimple_decode::decode(from, to.template get()); + } + if constexpr ((i+1) < sizeof...(T)){ + auto eov = decode_member(from, to); + if(eov.is_error()){ + return eov; + } + } + return void_t{}; + + } + static error_or decode(buffer& from, data, FromEnc>& to){ + return decode_member<0>(from, to); + } + +}; +template +struct kelsimple_decode { + static error_or decode(buffer& from, data& to){ + { + uint64_t val{}; + auto eov = stream_value::decode(val, from); + if(eov.is_error()){ + return eov; + } + to = data{val}; + } + const std::size_t str_size = to.size(); + for(std::size_t i = 0; i < str_size; ++i){ + int8_t val{}; + auto eov = stream_value::decode(val, from); + if(eov.is_error()){ + return eov; + } + to.set_at(i, val); + } + return void_t{}; + } +}; + +} + +template +class codec { +public: + struct config { + size_t depth = 16; + size_t length = 1024; + }; +private: + config cfg_; +public: + codec() = default; + + SAW_FORBID_COPY(codec); + SAW_DEFAULT_MOVE(codec); + + template + error_or encode(const data& from_enc, data& to_enc){ + buffer_view buff_v{to_enc.get_buffer()}; + + auto eov = impl::kelsimple_encode::encode(from_enc, buff_v); + + to_enc.get_buffer().write_advance(buff_v.write_offset()); + + return eov; + } + + template + error_or decode(data& from_dec, data& to){ + buffer_view buff_v{from_dec.get_buffer()}; + + auto eov = impl::kelsimple_decode::decode(buff_v, to); + + return eov; + } +}; +} diff --git a/c++/codec/stream_value.h b/c++/codec/stream_value.h new file mode 100644 index 0000000..09203cb --- /dev/null +++ b/c++/codec/stream_value.h @@ -0,0 +1,64 @@ +#pragma once + +#include "schema.h" + +#include +#include + +#include +#include + +namespace saw { +/** + * Helper class to encode/decode any primtive type into/from litte endian. + * The shift class does this by shifting bytes. This type of procedure is + * platform independent. So it does not matter if the memory layout is + * little endian or big endian + */ +template class shift_stream_value { + static_assert(always_false, "Shift Stream Value only supports Primitives"); +}; + +template class shift_stream_value> { +public: + inline static error_or decode(typename native_data_type>::type &val, buffer &buff) { + if (buff.read_composite_length() < N) { + return make_error(); + } + + typename native_data_type>::type raw = 0; + + for (size_t i = 0; i < N; ++i) { + raw |= (static_cast>::type>(buff.read(i)) << (i * 8)); + } + + memcpy(&val, &raw, N); + buff.read_advance(N); + + return void_t{}; + } + + inline static error_or encode(const typename native_data_type>::type &val, buffer &buff) { + error err = buff.write_require_length(N); + if (err.failed()) { + return err; + } + + typename native_data_type>::type raw{}; + memcpy(&raw, &val, N); + + for (size_t i = 0; i < N; ++i) { + buff.write(i) = raw >> (i * 8); + } + + buff.write_advance(N); + + return void_t{}; + } + + inline static size_t size() { return N; } +}; + +template using stream_value = shift_stream_value; + +} // namespace saw -- cgit v1.2.3