34618Fermer34620
WarptenLe 08/08/2018 à 20:24
template <typename Field, size_t Arity = 1, bool I = false>
        struct field_t
        {
            static_assert(Arity > 0 && Arity <= 200, "Invalid cardinality");
            static_assert(I ? (Arity == 1) : true, "Arrays can't be keys");

            constexpr static const size_t size = sizeof(Field) * Arity;
            constexpr static const size_t element_size = sizeof(Field);
            constexpr static const size_t arity = Arity;

            using element_type = Field;

            constexpr static const bool is_index  = I;
            constexpr static const bool is_array  = arity > 1;
            constexpr static const bool is_string = std::is_same<element_type, const char*>::value;

            using member_type            = typename std::conditional<is_array, std::array<element_type, arity>, element_type>::type;
            using const_member_type      = typename std::add_const<member_type>::type;
            using lref_member_type       = typename std::add_lvalue_reference<member_type>::type;
            using const_lref_member_type = typename std::add_const<lref_member_type>::type;
            using rref_member_type       = typename std::add_rvalue_reference<member_type>::type;

            field_t(const field_t& other) {
                value = other.value;
            }

            field_t(field_t&& other) {
                value = std::move(other.value);
            }

            field_t() {
            }

            explicit field_t(member_type value_)
            {
                value = value_;
            }

            field_t(rref_member_type value_)
            {
                value = std::move(value_);
            }

            field_t(const_lref_member_type value_)
            {
                value = value_;
            }

            field_t& operator = (const_lref_member_type value_)
            {
                value = value_;
                return *this;
            }

            field_t& operator = (rref_member_type value_)
            {
                value = std::move(value_);
                return *this;
            }

            inline operator member_type() const
            {
                return value;
            }

            //inline auto operator [] (size_t index) const -> typename std::enable_if<arity != 1, const element_type&>::type
            //{
            //    return value[index];
            //}

            //inline auto operator [] (size_t index) -> typename std::enable_if<arity != 1, element_type&>::type
            //{
            //    return value[index];
            //}
        private:
            member_type value;
        };

        template <size_t N = 1>
        using string_t = field_t<const char*, N, false>;

        using index_t = field_t<std::uint32_t, 1, true>;
        using locstring_t = string_t<16>;

        using u64_t    = field_t<std::uint64_t>;
        using u32_t    = field_t<std::uint32_t>;
        using u16_t    = field_t<std::uint16_t>;
        using u8_t     = field_t<std::uint8_t>;
        using i64_t    = field_t<std::int64_t>;
        using i32_t    = field_t<std::int32_t>;
        using i16_t    = field_t<std::int16_t>;
        using i8_t     = field_t<std::int8_t>;
        using single_t = field_t<float>;

        template <typename Enum, typename... Members>
        struct record_t : private std::tuple<Members...>
        {
        private:
            using is_scoped_enum = std::integral_constant<bool, std::is_enum<Enum>::value && !std::is_convertible<Enum, int>::value>;

        public:

            static_assert(is_scoped_enum::value, "Must use get<>() with scoped enums");
            static_assert(sizeof...(Members) > 0, "Can't have an empty structure.");

            constexpr static const size_t size = sizeof...(Members);

            template <size_t Idx>
            using member = typename details::nth_element<Idx, Members...>;

            template <Enum Idx>
            inline auto get()
            {
                typedef typename std::underlying_type<Enum>::type enum_underlying_type;

                return std::get<static_cast<enum_underlying_type>(Idx)>(*this);
            }
        };