#pragma once #include "schema.h" #include #include namespace saw { template class message_container; template > class message; template struct message_parameter_pack_type; template struct message_parameter_pack_type<0, TN, T...> { using Type = TN; }; template struct message_parameter_pack_type { static_assert(sizeof...(T) > 0, "Exhausted parameters"); using Type = typename message_parameter_pack_type::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 message_parameter_key_pack_index_helper { static constexpr size_t Value = (V == Key0) ? (0u) : (1u + message_parameter_key_pack_index_helper::Value); }; template struct message_parameter_key_pack_index_helper { static constexpr size_t Value = (V == Key0) ? (0u) : (1u); }; template struct message_parameter_key_pack_index { static constexpr size_t Value = message_parameter_key_pack_index_helper::Value; static_assert(Value < sizeof...(Keys), "Provided StringLiteral doesn't exist in searched list"); }; template struct schema_is_array { constexpr static bool Value = false; }; template struct schema_is_array> { constexpr static bool Value = true; }; template class message_container...>> { private: using ValueType = std::tuple>...>; ValueType values_; public: using SchemaType = schema::Struct...>; template using ElementType = typename message_parameter_pack_type< i, message>...>::Type; template ElementType &get() { return std::get(values_); } }; /* * Union storage */ template class message_container...>> { private: using ValueType = std::variant>...>; ValueType value_; public: using SchemaType = schema::Union...>; template using ElementType = typename message_parameter_pack_type< i, message>...>::Type; template ElementType &get() { if (i != value_.index()) { using MessageIV = typename message_parameter_pack_type::Type; value_ = message>{}; } return std::get(value_); } size_t index() const noexcept { return value_.index(); } }; /* * Array storage */ template class message_container> { 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 message_container> { private: using ValueType = std::tuple>...>; ValueType values_; public: using SchemaType = schema::Tuple; template using ElementType = typename message_parameter_pack_type< 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 message_container> { public: using SchemaType = schema::Primitive; using ValueType = typename PrimitiveTypeHelper>::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 { 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