diff --git a/include/gp/containers/buffer.hpp b/include/gp/containers/buffer.hpp index 3508005..cf13227 100644 --- a/include/gp/containers/buffer.hpp +++ b/include/gp/containers/buffer.hpp @@ -25,6 +25,11 @@ namespace gp{ , end_elem{end_ptr} {} + constexpr buffer(associated_iterator beg_ptr, associated_iterator end_ptr) + : begin_elem{beg_ptr} + , end_elem{end_ptr} + {} + constexpr buffer(T* beg_ptr, std::size_t sz) : begin_elem{beg_ptr} , end_elem{beg_ptr+sz} diff --git a/include/gp/ipc/envelope/cbor.hpp b/include/gp/ipc/envelope/cbor.hpp index 336934f..b2c0e52 100644 --- a/include/gp/ipc/envelope/cbor.hpp +++ b/include/gp/ipc/envelope/cbor.hpp @@ -93,6 +93,258 @@ namespace gp { return (float)*this; } }; + + + + + + + + + + + + + + + + + + + + + + template + vector& push_as_cbor(vector&, T); + + template + vector& push_as_cbor(vector&, T&); + + inline vector& push_integer_with_header_as_cbor(vector& src, uint8_t header, uint64_t value) { + auto norm_v = (value<0) ? -value : value; + if(norm_v <= 23) { + src.push_back(header+norm_v); + } else if(norm_v < (1ll<<8ll)) { + src.push_back(header+24); + src.push_back(norm_v); + } else if(norm_v < (1ll<<16ll)) { + endian_wrapper wrapper = norm_v; + src.push_back(header+25); + for(auto byte : wrapper.bytes) { + src.push_back(byte); + } + } else if(norm_v < (1ll<<32ll)) { + endian_wrapper wrapper = norm_v; + src.push_back(header+26); + for(auto byte : wrapper.bytes) { + src.push_back(byte); + } + } else { + endian_wrapper wrapper = norm_v; + src.push_back(header+27); + for(auto byte : wrapper.bytes) { + src.push_back(byte); + } + } + return src; + } + + /** + * @brief Pushes an integer as CBOR on the vector + * + * @param src the vector on which the push happens + * @param value the value to push, can be signed + * @return vector& the same reference that was received for the source + */ + template<> + vector& push_as_cbor(vector& src, int64_t& value) { + uint8_t sign = (value<0) ? 0b00100000 : 0; + auto norm_v = (value<0) ? -value : value; + return push_integer_with_header_as_cbor(src, sign, norm_v); + } + + /** + * @brief Pushes an unsigned integer as CBOR on the vector + * + * @param src the vector on which the push happens + * @param value the value to push, cannot be signed + * @return vector& the same reference that was received for the source + */ + template<> + vector& push_as_cbor(vector& src, uint64_t& value) { + return push_integer_with_header_as_cbor(src, 0, value); + } + + template<> + vector& push_as_cbor(vector& src, std::nullptr_t) { + src.push_back(0b11110110); + return src; + } + + struct cbor_undefined{}; + + template<> + vector& push_as_cbor(vector& src, cbor_undefined) { + src.push_back(0b11110111); + return src; + } + + template<> + vector& push_as_cbor(vector& src, bool value) { + src.push_back(0b11110100+(value ? 1 : 0)); + return src; + } + + template<> + vector& push_as_cbor>(vector& src, gp::buffer value) { + push_integer_with_header_as_cbor(src, (uint8_t)0b01000000, value.size()); + for(auto byte : value) { + src.push_back(byte); + } + return src; + } + + struct cbor_array_initiator { + size_t size; + }; + + struct cbor_associative_array_initiator { + size_t size; + }; + + template<> + vector& push_as_cbor(vector& src, cbor_array_initiator value) { + return push_integer_with_header_as_cbor(src, (uint8_t)0b10000000, value.size); + } + + template<> + vector& push_as_cbor(vector& src, cbor_associative_array_initiator value) { + return push_integer_with_header_as_cbor(src, (uint8_t)0b10100000, value.size); + } + + template + vector& push_as_cbor(vector& src, gp::pair& value) { + push_as_cbor(src,value.first); + return push_as_cbor(src,value.second); + } + + struct cbor_tag_initiator { + union { + size_t as_integer; + cbor_tags tag; + }; + }; + + template<> + vector& push_as_cbor(vector& src, cbor_tag_initiator value) { + return push_integer_with_header_as_cbor(src, (uint8_t)0b11000000, value.as_integer); + } + + using parsing_state = gp::buffer; + + template + gp::pair, parsing_state> read_cbor(parsing_state state); + + inline gp::pair, parsing_state> pull_arbitrary_integer_from_cbor(parsing_state state) { + auto local = (uint8_t)0b00011111 & (uint8_t)*state.begin(); + if(local <= 23) { + return {*state.begin(), {state.begin()+1, state.end()}}; + } else { + switch((cbor_oths)local) { + case cbor_oths::byte: { + if(state.size() < 2) return {nullopt, state}; + return {*(state.begin()+1), {state.begin()+2, state.end()}}; + } + case cbor_oths::word: { + if(state.size() < 3) return {nullopt, state}; + return { + uint16_t(*(state.slice_start(3).slice_end(2).cast>().begin().data)), + {state.begin()+3, state.end()} + }; + } + case cbor_oths::dword: { + if(state.size() < 5) return {nullopt, state}; + return { + uint32_t(*(state.slice_start(5).slice_end(4).cast>().begin().data)), + {state.begin()+5, state.end()} + }; + } + case cbor_oths::qword: { + if(state.size() < 9) return {nullopt, state}; + return { + uint64_t(*(state.slice_start(9).slice_end(8).cast>().begin().data)), + {state.begin()+9, state.end()} + }; + } + default: { + return {nullopt, state}; + } + } + } + } + + template<> + gp::pair, parsing_state> read_cbor(parsing_state state) { + if(state.size()) return {nullopt, state}; + auto type = cbor_type(((uint8_t)0b11100000 & (uint8_t)*state.begin()) >> 5); + + int64_t sign = type == cbor_type::nint ? -1 : 1; + + switch(type) { + case cbor_type::uint: + case cbor_type::nint: + { + auto[value, new_state] = pull_arbitrary_integer_from_cbor(state); + if(value.has_value()) return {value.value() * sign, new_state}; + break; + } + default: + break; + } + return {nullopt, state}; + } + + template<> + gp::pair, parsing_state> read_cbor(parsing_state state) { + if(state.size()) return {nullopt, state}; + auto type = cbor_type(((uint8_t)0b11100000 & (uint8_t)*state.begin()) >> 5); + + switch(type) { + case cbor_type::uint: + { + auto[value, new_state] = pull_arbitrary_integer_from_cbor(state); + if(value.has_value()) return {value.value(), new_state}; + break; + } + default: + break; + } + return {nullopt, state}; + } + + + + + + + + + + + + + + + + + + + + + + + + struct cbor_floating_point final { using backing = gp::fixed_variant< diff --git a/include/gp/math/boolean/bitops.hpp b/include/gp/math/boolean/bitops.hpp index 3858efd..0e6fedc 100644 --- a/include/gp/math/boolean/bitops.hpp +++ b/include/gp/math/boolean/bitops.hpp @@ -1,5 +1,7 @@ #pragma once +#include "gp/containers/array.hpp" + #include #include @@ -54,7 +56,10 @@ namespace gp{ template struct endian_wrapper { - T value; + union{ + T value; + gp::array bytes; + }; endian_wrapper(){}; endian_wrapper(T v) : value{ mode == endian::native ? v : swap_endian(v)