#pragma once #include "schema.h" namespace saw { template class MessageContainer; template > class Message; template struct MessageParameterPackType; template struct MessageParameterPackType<0, TN, T...> { using Type = TN; }; template struct MessageParameterPackType { static_assert(sizeof...(T) > 0, "Exhausted parameters"); using Type = typename MessageParameterPackType::Type; }; template struct MessageParameterPackIndex; template struct MessageParameterPackIndex { static constexpr size_t Value = 0u; }; template struct MessageParameterPackIndex { static constexpr size_t Value = 1u + MessageParameterPackIndex::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 struct MessageParameterKeyPackIndexHelper { static constexpr size_t Value = (V == Key0) ? (0u) : (1u + MessageParameterKeyPackIndexHelper::Value); }; template struct MessageParameterKeyPackIndexHelper { static constexpr size_t Value = (V == Key0) ? (0u) : (1u); }; template struct MessageParameterKeyPackIndex { static constexpr size_t Value = MessageParameterKeyPackIndexHelper::Value; static_assert(Value < sizeof...(Keys), "Provided StringLiteral doesn't exist in searched list"); }; template struct SchemaIsArray { constexpr static bool Value = false; }; template struct SchemaIsArray> { constexpr static bool Value = true; }; template class MessageContainer...>> { private: using ValueType = std::tuple>...>; ValueType values; public: using SchemaType = schema::Struct...>; template using ElementType = typename MessageParameterPackType< i, Message>...>::Type; template ElementType &get() { return std::get(values); } }; /* * Union storage */ template class MessageContainer...>> { private: using ValueType = std::variant>...>; ValueType value; public: using SchemaType = schema::Union...>; template using ElementType = typename MessageParameterPackType< i, Message>...>::Type; template ElementType &get() { if (i != value.index()) { using MessageIV = typename MessageParameterPackType::Type; value = Message>{}; } return std::get(value); } size_t index() const noexcept { return value.index(); } }; /* * Array storage */ template class MessageContainer> { private: using ValueType = std::vector>>; ValueType values; public: using SchemaType = schema::Array; using ElementType = Message>; Message> &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 MessageContainer> { private: using ValueType = std::tuple>...>; ValueType values; public: using SchemaType = schema::Tuple; template using ElementType = typename MessageParameterPackType< i, Message>...>::Type; template ElementType &get() { return std::get(values); } }; /* * Helper for the basic message container, so the class doesn't have to be * specialized 10 times. */ template struct PrimitiveTypeHelper; template <> struct PrimitiveTypeHelper> { using Type = int8_t; }; template <> struct PrimitiveTypeHelper> { using Type = int16_t; }; template <> struct PrimitiveTypeHelper> { using Type = int32_t; }; template <> struct PrimitiveTypeHelper> { using Type = int64_t; }; template <> struct PrimitiveTypeHelper> { using Type = uint8_t; }; template <> struct PrimitiveTypeHelper> { using Type = uint16_t; }; template <> struct PrimitiveTypeHelper> { using Type = uint32_t; }; template <> struct PrimitiveTypeHelper> { using Type = uint64_t; }; template <> struct PrimitiveTypeHelper> { using Type = float; }; template <> struct PrimitiveTypeHelper> { using Type = double; }; template class MessageContainer> { public: using SchemaType = schema::Primitive; using ValueType = typename PrimitiveTypeHelper>::Type; private: ValueType value; public: MessageContainer() : value{0} {} void set(const ValueType &v) { value = v; } const ValueType &get() const { return value; } }; template <> class MessageContainer { 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