summaryrefslogtreecommitdiff
path: root/forstio/codec/message_container.h
diff options
context:
space:
mode:
authorClaudius Holeksa <mail@keldu.de>2023-04-29 18:03:24 +0200
committerClaudius Holeksa <mail@keldu.de>2023-04-29 18:03:24 +0200
commit937e67ff5ae9e770367bfee3100154b6a6957ce7 (patch)
treec09be3b6929ce6fd533c83564a89fe523be7a46f /forstio/codec/message_container.h
parent4e18f3798465ae952e15a2620177421d8b8c1f00 (diff)
Added codec and ammended async build
Diffstat (limited to 'forstio/codec/message_container.h')
-rw-r--r--forstio/codec/message_container.h246
1 files changed, 246 insertions, 0 deletions
diff --git a/forstio/codec/message_container.h b/forstio/codec/message_container.h
new file mode 100644
index 0000000..191052a
--- /dev/null
+++ b/forstio/codec/message_container.h
@@ -0,0 +1,246 @@
+#pragma once
+
+#include "schema.h"
+
+#include <variant>
+#include <vector>
+
+namespace saw {
+template <class T> class message_container;
+
+template <class T, class Container = message_container<T>> class message;
+
+template <size_t N, class... T> struct message_parameter_pack_type;
+
+template <class TN, class... T>
+struct message_parameter_pack_type<0, TN, T...> {
+ using Type = TN;
+};
+
+template <size_t N, class TN, class... T>
+struct message_parameter_pack_type<N, TN, T...> {
+ static_assert(sizeof...(T) > 0, "Exhausted parameters");
+ using Type = typename message_parameter_pack_type<N - 1, T...>::Type;
+};
+
+template <class T, class... TL> struct MessageParameterPackIndex;
+
+template <class T, class... TL> struct MessageParameterPackIndex<T, T, TL...> {
+ static constexpr size_t Value = 0u;
+};
+
+template <class T, class TL0, class... TL>
+struct MessageParameterPackIndex<T, TL0, TL...> {
+ static constexpr size_t Value =
+ 1u + MessageParameterPackIndex<T, TL...>::Value;
+};
+
+/*
+ * Nightmare inducing compiler problems found here. Somehow non-type
+ * StringLiterals cannot be resolved as non-type primitive template values can.
+ * This is the workaround
+ */
+template <string_literal V, string_literal Key0, string_literal... Keys>
+struct message_parameter_key_pack_index_helper {
+ static constexpr size_t Value =
+ (V == Key0)
+ ? (0u)
+ : (1u + message_parameter_key_pack_index_helper<V, Keys...>::Value);
+};
+
+template <string_literal V, string_literal Key0>
+struct message_parameter_key_pack_index_helper<V, Key0> {
+ static constexpr size_t Value = (V == Key0) ? (0u) : (1u);
+};
+
+template <string_literal V, string_literal... Keys>
+struct message_parameter_key_pack_index {
+ static constexpr size_t Value =
+ message_parameter_key_pack_index_helper<V, Keys...>::Value;
+ static_assert(Value < sizeof...(Keys),
+ "Provided StringLiteral doesn't exist in searched list");
+};
+
+template <class T> struct schema_is_array {
+ constexpr static bool Value = false;
+};
+
+template <class T> struct schema_is_array<schema::Array<T>> {
+ constexpr static bool Value = true;
+};
+
+template <class... V, string_literal... Keys>
+class message_container<schema::Struct<schema::NamedMember<V, Keys>...>> {
+private:
+ using ValueType = std::tuple<message<V, message_container<V>>...>;
+ ValueType values_;
+
+public:
+ using SchemaType = schema::Struct<schema::NamedMember<V, Keys>...>;
+
+ template <size_t i>
+ using ElementType = typename message_parameter_pack_type<
+ i, message<V, message_container<V>>...>::Type;
+
+ template <size_t i> ElementType<i> &get() { return std::get<i>(values_); }
+};
+
+/*
+ * Union storage
+ */
+template <class... V, string_literal... Keys>
+class message_container<schema::Union<schema::NamedMember<V, Keys>...>> {
+private:
+ using ValueType = std::variant<message<V, message_container<V>>...>;
+ ValueType value_;
+
+public:
+ using SchemaType = schema::Union<schema::NamedMember<V, Keys>...>;
+
+ template <size_t i>
+ using ElementType = typename message_parameter_pack_type<
+ i, message<V, message_container<V>>...>::Type;
+
+ template <size_t i> ElementType<i> &get() {
+ if (i != value_.index()) {
+ using MessageIV =
+ typename message_parameter_pack_type<i, V...>::Type;
+ value_ = message<MessageIV, message_container<MessageIV>>{};
+ }
+ return std::get<i>(value_);
+ }
+
+ size_t index() const noexcept { return value_.index(); }
+};
+
+/*
+ * Array storage
+ */
+
+template <class T> class message_container<schema::Array<T>> {
+private:
+ using ValueType = std::vector<message<T, message_container<T>>>;
+ ValueType values_;
+
+public:
+ using SchemaType = schema::Array<T>;
+
+ using ElementType = message<T, message_container<T>>;
+
+ message<T, message_container<T>> &get(size_t index) {
+ return values_.at(index);
+ }
+
+ void resize(size_t size) { values_.resize(size); }
+
+ size_t size() const { return values_.size(); }
+};
+
+/*
+ * Tuple storage
+ */
+template <class... T> class message_container<schema::Tuple<T...>> {
+private:
+ using ValueType = std::tuple<message<T, message_container<T>>...>;
+ ValueType values_;
+
+public:
+ using SchemaType = schema::Tuple<T...>;
+
+ template <size_t i>
+ using ElementType = typename message_parameter_pack_type<
+ i, message<T, message_container<T>>...>::Type;
+
+ template <size_t i> ElementType<i> &get() { return std::get<i>(values_); }
+};
+
+/*
+ * Helper for the basic message container, so the class doesn't have to be
+ * specialized 10 times.
+ */
+template <class T> struct PrimitiveTypeHelper;
+
+template <>
+struct PrimitiveTypeHelper<schema::Primitive<schema::SignedInteger, 1>> {
+ using Type = int8_t;
+};
+
+template <>
+struct PrimitiveTypeHelper<schema::Primitive<schema::SignedInteger, 2>> {
+ using Type = int16_t;
+};
+
+template <>
+struct PrimitiveTypeHelper<schema::Primitive<schema::SignedInteger, 4>> {
+ using Type = int32_t;
+};
+
+template <>
+struct PrimitiveTypeHelper<schema::Primitive<schema::SignedInteger, 8>> {
+ using Type = int64_t;
+};
+
+template <>
+struct PrimitiveTypeHelper<schema::Primitive<schema::UnsignedInteger, 1>> {
+ using Type = uint8_t;
+};
+
+template <>
+struct PrimitiveTypeHelper<schema::Primitive<schema::UnsignedInteger, 2>> {
+ using Type = uint16_t;
+};
+
+template <>
+struct PrimitiveTypeHelper<schema::Primitive<schema::UnsignedInteger, 4>> {
+ using Type = uint32_t;
+};
+
+template <>
+struct PrimitiveTypeHelper<schema::Primitive<schema::UnsignedInteger, 8>> {
+ using Type = uint64_t;
+};
+
+template <>
+struct PrimitiveTypeHelper<schema::Primitive<schema::FloatingPoint, 4>> {
+ using Type = float;
+};
+
+template <>
+struct PrimitiveTypeHelper<schema::Primitive<schema::FloatingPoint, 8>> {
+ using Type = double;
+};
+
+template <class T, size_t N> class message_container<schema::Primitive<T, N>> {
+public:
+ using SchemaType = schema::Primitive<T, N>;
+ using ValueType =
+ typename PrimitiveTypeHelper<schema::Primitive<T, N>>::Type;
+
+private:
+ ValueType value_;
+
+public:
+ message_container() : value_{0} {}
+
+ void set(const ValueType &v) { value_ = v; }
+
+ const ValueType &get() const { return value_; }
+};
+
+template <> class message_container<schema::String> {
+public:
+ using SchemaType = schema::String;
+ using ValueType = std::string;
+ using ValueViewType = std::string_view;
+
+private:
+ ValueType value_;
+
+public:
+ void set(ValueType &&v) { value_ = std::move(v); }
+ void set(const ValueType &v) { value_ = v; }
+ void set(const ValueViewType v) { value_ = std::string{v}; }
+
+ const ValueType &get() const { return value_; }
+};
+} // namespace saw