245 lines
6.2 KiB
C++
245 lines
6.2 KiB
C++
#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 MessageParameterPackType;
|
|
|
|
template <class TN, class... T> struct MessageParameterPackType<0, TN, T...> {
|
|
using Type = TN;
|
|
};
|
|
|
|
template <size_t N, class TN, class... T>
|
|
struct MessageParameterPackType<N, TN, T...> {
|
|
static_assert(sizeof...(T) > 0, "Exhausted parameters");
|
|
using Type = typename MessageParameterPackType<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 MessageParameterKeyPackIndexHelper {
|
|
static constexpr size_t Value =
|
|
(V == Key0)
|
|
? (0u)
|
|
: (1u + MessageParameterKeyPackIndexHelper<V, Keys...>::Value);
|
|
};
|
|
|
|
template <string_literal V, string_literal Key0>
|
|
struct MessageParameterKeyPackIndexHelper<V, Key0> {
|
|
static constexpr size_t Value = (V == Key0) ? (0u) : (1u);
|
|
};
|
|
|
|
template <string_literal V, string_literal... Keys>
|
|
struct MessageParameterKeyPackIndex {
|
|
static constexpr size_t Value =
|
|
MessageParameterKeyPackIndexHelper<V, Keys...>::Value;
|
|
static_assert(Value < sizeof...(Keys),
|
|
"Provided StringLiteral doesn't exist in searched list");
|
|
};
|
|
|
|
template <class T> struct SchemaIsArray {
|
|
constexpr static bool Value = false;
|
|
};
|
|
|
|
template <class T> struct SchemaIsArray<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 MessageParameterPackType<
|
|
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 MessageParameterPackType<
|
|
i, message<V, message_container<V>>...>::Type;
|
|
|
|
template <size_t i> ElementType<i> &get() {
|
|
if (i != value_.index()) {
|
|
using MessageIV = typename MessageParameterPackType<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 MessageParameterPackType<
|
|
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
|