diff --git a/include/cereal/cereal.hpp b/include/cereal/cereal.hpp index 72038346..88cc68d2 100644 --- a/include/cereal/cereal.hpp +++ b/include/cereal/cereal.hpp @@ -45,6 +45,8 @@ #include "cereal/details/helpers.hpp" #include "cereal/types/base_class.hpp" +#include "cereal/external/ctti/type_id.hpp" + namespace cereal { // ###################################################################### @@ -269,8 +271,9 @@ namespace cereal { \ static std::uint32_t registerVersion() \ { \ - ::cereal::detail::StaticObject::getInstance().mapping.emplace( \ - std::type_index(typeid(TYPE)).hash_code(), VERSION_NUMBER ); \ + ::cereal::detail::StaticObject::getInstance().mapping \ + .emplace(std::hash()(ctti::type_id()), \ + VERSION_NUMBER); \ return VERSION_NUMBER; \ } \ static inline const std::uint32_t version = registerVersion(); \ @@ -285,8 +288,9 @@ namespace cereal static const std::uint32_t version; \ static std::uint32_t registerVersion() \ { \ - ::cereal::detail::StaticObject::getInstance().mapping.emplace( \ - std::type_index(typeid(TYPE)).hash_code(), VERSION_NUMBER ); \ + ::cereal::detail::StaticObject::getInstance().mapping \ + .emplace(std::hash()(ctti::type_id()), \ + VERSION_NUMBER); \ return VERSION_NUMBER; \ } \ CEREAL_UNUSED_FUNCTION \ @@ -595,7 +599,7 @@ namespace cereal template inline std::uint32_t registerClassVersion() { - static const auto hash = std::type_index(typeid(T)).hash_code(); + static const auto hash = std::hash()(ctti::type_id()); const auto insertResult = itsVersionedTypes.insert( hash ); const auto lock = detail::StaticObject::lock(); const auto version = @@ -1013,7 +1017,7 @@ namespace cereal template inline std::uint32_t loadClassVersion() { - static const auto hash = std::type_index(typeid(T)).hash_code(); + static const auto hash = std::hash()(ctti::type_id()); auto lookupResult = itsVersionedTypes.find( hash ); if( lookupResult != itsVersionedTypes.end() ) // already exists diff --git a/include/cereal/details/traits.hpp b/include/cereal/details/traits.hpp index e1fda1d9..21db6b45 100644 --- a/include/cereal/details/traits.hpp +++ b/include/cereal/details/traits.hpp @@ -42,6 +42,8 @@ #include "cereal/macros.hpp" #include "cereal/access.hpp" +#include "cereal/external/ctti/type_id.hpp" + namespace cereal { namespace traits @@ -1146,15 +1148,15 @@ namespace cereal { template base_class_id(T const * const t) : - type(typeid(T)), + type(ctti::type_id()), ptr(t), - hash(std::hash()(typeid(T)) ^ (std::hash()(t) << 1)) + hash(std::hash()(ctti::type_id()) ^ (std::hash()(t) << 1)) { } bool operator==(base_class_id const & other) const { return (type == other.type) && (ptr == other.ptr); } - std::type_index type; + ctti::type_id_t type; void const * ptr; size_t hash; }; diff --git a/include/cereal/external/ctti/LICENSE.md b/include/cereal/external/ctti/LICENSE.md new file mode 100644 index 00000000..0d5309a2 --- /dev/null +++ b/include/cereal/external/ctti/LICENSE.md @@ -0,0 +1,21 @@ +The MIT License + +Copyright (c) 2015 Manuel Sánchez + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/include/cereal/external/ctti/detail/algorithm.hpp b/include/cereal/external/ctti/detail/algorithm.hpp new file mode 100644 index 00000000..4ad9cc8f --- /dev/null +++ b/include/cereal/external/ctti/detail/algorithm.hpp @@ -0,0 +1,47 @@ +#ifndef CTTI_DETAIL_ALGORITHM_HPP +#define CTTI_DETAIL_ALGORITHM_HPP + +#include + +namespace ctti +{ + +namespace detail +{ + +template +constexpr const T* begin(const T(&array)[N]) +{ + return &array[0]; +} + +template +constexpr const T* end(const T(&array)[N]) +{ + return &array[N]; +} + +template +constexpr bool equal_range(LhsIt lhsBegin, LhsIt lhsEnd, RhsIt rhsBegin, RhsIt rhsEnd) +{ + return (lhsBegin != lhsEnd && rhsBegin != rhsEnd) ? *lhsBegin == *rhsBegin && + equal_range(lhsBegin + 1, lhsEnd, rhsBegin + 1, rhsEnd) : (lhsBegin == lhsEnd && rhsBegin == rhsEnd); +} + +template +constexpr const T& max(const T& lhs, const T& rhs) +{ + return (lhs >= rhs) ? lhs : rhs; +} + +template +constexpr const T& min(const T& lhs, const T& rhs) +{ + return (lhs <= rhs) ? lhs : rhs; +} + +} + +} + +#endif // CTTI_DETAIL_ALGORITHM_HPP diff --git a/include/cereal/external/ctti/detail/cstring.hpp b/include/cereal/external/ctti/detail/cstring.hpp new file mode 100644 index 00000000..1c92c694 --- /dev/null +++ b/include/cereal/external/ctti/detail/cstring.hpp @@ -0,0 +1,125 @@ +#ifndef CTTI_DETAIL_CSTRING_HPP +#define CTTI_DETAIL_CSTRING_HPP + +#include "hash.hpp" +#include "algorithm.hpp" +#include +#include + +namespace ctti +{ + +namespace detail +{ + +class cstring +{ +public: + template + constexpr cstring(const char (&str)[N]) : + cstring{&str[0], N - 1} + {} + + constexpr cstring(const char* begin, std::size_t length) : + _str{begin}, + _length{length} + {} + + constexpr cstring(const char* begin, const char* end) : + cstring{begin, static_cast(end - begin)} + {} + + constexpr cstring(const char* begin) : + cstring{begin, length(begin)} + {} + + static constexpr std::size_t length(const char* str) + { + return *str ? 1 + length(str + 1) : 0; + } + + constexpr std::size_t length() const + { + return _length; + } + + constexpr std::size_t size() const + { + return length(); + } + + constexpr hash_t hash() const + { + return fnv1a_hash(length(), begin()); + } + + std::string cppstring() const + { + return {begin(), end()}; + } + + std::string str() const + { + return cppstring(); + } + + constexpr const char* begin() const + { + return _str; + } + + constexpr const char* end() const + { + return _str + _length; + } + + constexpr char operator[](std::size_t i) const + { + return _str[i]; + } + + constexpr const char* operator()(std::size_t i) const + { + return _str + i; + } + + constexpr cstring operator()(std::size_t begin, std::size_t end) const + { + return {_str + begin, _str + end}; + } + + constexpr cstring pad(std::size_t begin_offset, std::size_t end_offset) const + { + return operator()(begin_offset, size() - end_offset); + } + + friend std::ostream& operator<<(std::ostream& os, const cstring& str) + { + for(const char c : str) + { + os << c; + } + + return os; + } + +private: + const char* _str; + std::size_t _length; +}; + +constexpr bool operator==(const cstring& lhs, const cstring& rhs) +{ + return ctti::detail::equal_range(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); +} + +constexpr bool operator!=(const cstring& lhs, const cstring& rhs) +{ + return !(lhs == rhs); +} + +} + +} + +#endif // CTTI_DETAIL_CSTRING_HPP diff --git a/include/cereal/external/ctti/detail/entity_name.hpp b/include/cereal/external/ctti/detail/entity_name.hpp new file mode 100644 index 00000000..d367df94 --- /dev/null +++ b/include/cereal/external/ctti/detail/entity_name.hpp @@ -0,0 +1,46 @@ +#ifndef CTTI_DETAIL_ENTITY_NAME_HPP +#define CTTI_DETAIL_ENTITY_NAME_HPP + +#include "cstring.hpp" + +namespace ctti +{ + +namespace detail +{ + +class entity_name +{ +public: + constexpr entity_name(const ctti::detail::cstring& str) : + _str{str} + {} + + constexpr ctti::detail::cstring str() const + { + return _str; + } + + constexpr ctti::detail::cstring operator[](std::size_t i) const + { + return colon_scan(_str.begin(), _str.end(), i); + } + +private: + ctti::detail::cstring _str; + + constexpr ctti::detail::cstring colon_scan(const char* begin, const char* end, std::size_t i) const + { + return (begin == end) ? {begin, end} : + (i == 0) ? {begin, end} + (colon_count == 0 && *begin == ':') ? colon_scan(++begin, end, i, ++colon_count) : + (colon_count == 1 && *begin == ':') ? colon_scan(++begin, end, i - 1, 0) + ( + } +}; + +} + +} + +#endif // CTTI_DETAIL_ENTITY_NAME_HPP diff --git a/include/cereal/external/ctti/detail/hash.hpp b/include/cereal/external/ctti/detail/hash.hpp new file mode 100644 index 00000000..1ecc8f39 --- /dev/null +++ b/include/cereal/external/ctti/detail/hash.hpp @@ -0,0 +1,32 @@ +#ifndef CTTI_DETAIL_HASH_HPP +#define CTTI_DETAIL_HASH_HPP + +#include + +namespace ctti +{ + namespace detail + { + // From https://github.com/foonathan/string_id. As usually, thanks Jonathan. + + using hash_t = std::uint64_t; + + // See http://www.isthe.com/chongo/tech/comp/fnv/#FNV-param + constexpr hash_t fnv_basis = 14695981039346656037ull; + constexpr hash_t fnv_prime = 1099511628211ull; + + // FNV-1a 64 bit hash + constexpr hash_t fnv1a_hash(std::size_t n, const char *str, hash_t hash = fnv_basis) + { + return n > 0 ? fnv1a_hash(n - 1, str + 1, (hash ^ *str) * fnv_prime) : hash; + } + + template + constexpr hash_t fnv1a_hash(const char (&array)[N]) + { + return fnv1a_hash(N - 1, &array[0]); + } + } +} + +#endif /* CTTI_DETAIL_HASH_HPP */ diff --git a/include/cereal/external/ctti/detail/language_features.hpp b/include/cereal/external/ctti/detail/language_features.hpp new file mode 100644 index 00000000..f262a360 --- /dev/null +++ b/include/cereal/external/ctti/detail/language_features.hpp @@ -0,0 +1,18 @@ +#ifndef CTTI_LANGUAGE_FEATURES_HPP +#define CTTI_LANGUAGE_FEATURES_HPP + +#ifdef __cpp_variable_templates +#define CTTI_HAS_VARIABLE_TEMPLATES +#endif // __cpp_variable_templates + +#define CTTI_HAS_CONSTEXPR_PRETTY_FUNCTION + +#if defined(__GCC__) && __GCC__ < 5 +#undef CTTI_HAS_CONSTEXPR_PRETTY_FUNCTION +#endif // GCC 4.x + +#ifdef __clang__ +#define CTTI_HAS_ENUM_AWARE_PRETTY_FUNCTION +#endif // __clang__ + +#endif // CTTI_LANGUAGE_FEATURES_HPP diff --git a/include/cereal/external/ctti/detail/meta.hpp b/include/cereal/external/ctti/detail/meta.hpp new file mode 100644 index 00000000..a32126a6 --- /dev/null +++ b/include/cereal/external/ctti/detail/meta.hpp @@ -0,0 +1,825 @@ +#ifndef CTTI_UTILITY_META_H +#define CTTI_UTILITY_META_H + +#include +#include +#include +#include + +namespace ctti +{ + +namespace meta +{ + template + using decay_t = typename std::decay::type; + + template + struct assert; + + template + struct assert : assert + { + static_assert(B::value, "Assertion failed"); + }; + + template<> + struct assert<> {}; + + template + using void_t = typename std::conditional= 0, void, T>::type; + + template + struct identity + { + using type = T; + }; + + template + using type_t = typename Metafunction::type; + + template + using enable_if_t = typename std::enable_if::type; + + template + using apply_t = type_t>; + + template + struct sequence_apply; + + template class Seq, typename... Ts> + struct sequence_apply> + { + using type = apply_t; + }; + + template + using sequence_apply_t = type_t>; + + template + using uint8_t = std::integral_constant; + template + using uint16_t = std::integral_constant; + template + using uint32_t = std::integral_constant; + template + using uint64_t = std::integral_constant; + + template + using int8_t = std::integral_constant; + template + using int16_t = std::integral_constant; + template + using int32_t = std::integral_constant; + template + using int64_t = std::integral_constant; + + template + using size_t = std::integral_constant; + + template + using bool_ = std::integral_constant; + using true_ = bool_; + using false_ = bool_; + + template + using char_ = std::integral_constant; + + template + struct is_integral : false_ {}; + template + struct is_integral> : + true_ + {}; + + template>> + constexpr decltype(T::value) value() + { + return T::value; + } + + template class Function> + struct defer + { + template + struct apply + { + template::value> + struct result + { + using type = Instance; + }; + + template + struct result + { + using type = type_t; + }; + + using type = type_t>>; + }; + }; + + struct and_ + { + template + struct apply : assert< + is_integral, + is_integral + > + { + using type = bool_; + }; + }; + + template + using and_t = apply_t; + + struct or_ + { + template + struct apply : assert< + is_integral, + is_integral + > + { + using type = bool_; + }; + }; + + template + using or_t = apply_t; + + struct add_ + { + template + struct apply : assert< + is_integral, + is_integral + > + { + using type = std::integral_constant; + }; + }; + + struct div_ + { + template + struct apply : assert< + is_integral, + is_integral + > + { + using type = std::integral_constant; + }; + }; + + template + using add_t = apply_t; + + template + using div_t = apply_t; + + struct greater + { + template + struct apply : assert< + is_integral, + is_integral + > + { + using type = bool_<(Lhs::value > Rhs::value)>; + }; + }; + struct greater_or_equal + { + template + struct apply : assert< + is_integral, + is_integral + > + { + using type = bool_<(Lhs::value >= Rhs::value)>; + }; + }; + struct less + { + template + struct apply : assert< + is_integral, + is_integral + > + { + using type = bool_<(Lhs::value < Rhs::value)>; + }; + }; + struct less_or_equal + { + template + struct apply : assert< + is_integral, + is_integral + > + { + using type = bool_<(Lhs::value <= Rhs::value)>; + }; + }; + + template + struct list + { + static constexpr std::size_t size = sizeof...(Ts); + }; + + template + constexpr std::size_t list::size; + + template + struct list_size; + + template class Sequence, typename... Ts> + struct list_size> : public size_t + {}; + + template + using string = list...>; + + + template + struct functor + { + static_assert(sizeof(Seq) != sizeof(Seq), "Type is not a sequence"); + }; + + template class Seq, typename... Ts> + struct functor> + { + template + struct apply + { + using type = Seq; + }; + + template class Seq2, typename... Us> + struct apply> + { + using type = Seq; + }; + }; + + template + using apply_functor = apply_t, Ts...>; + + template + using functor_t = apply_functor; + + template + struct cat; + + template class Seq, + typename... Lhs, typename... Rhs> + struct cat, Seq> + { + using type = Seq; + }; + + template + using cat_t = type_t>; + + template + using index_t = std::integral_constant; + + template + using integer_sequence = list...>; + + template + using index_sequence = list...>; + + namespace detail + { + template + struct split; + + template class Seq, std::size_t Index, + typename... Left, typename Head, typename... Tail> + struct split, Index, Seq> + { + using next = split, Index - 1, Seq>; + + using before = typename next::before; + using left = typename next::left; + using head = typename next::head; + using right = typename next::right; + using after = typename next::after; + }; + + template class Seq, + typename... Left, typename Head, typename... Tail> + struct split, 0, Seq> + { + using before = Seq; + using left = Seq; + using head = Head; + using right = Seq; + using after = Seq; + }; + + template class Seq, + typename Head> + struct split, 0, Seq<>> + { + using before = Seq<>; + using left = Seq; + using head = Head; + using right = Seq; + using after = Seq<>; + }; + } + + template + using pack_split = detail::split, Index, list>; + template + using pack_split_left_t = typename pack_split::left; + template + using pack_get_t = typename pack_split::head; + template + using pack_split_right_t = typename pack_split::right; + template + using pack_split_before_t = typename pack_split::before; + template + using pack_split_after_t = typename pack_split::after; + template + using pack_head_t = pack_get_t<0, Ts...>; + template + using pack_tail_t = pack_split_after_t<0, Ts...>; + + template + struct split; + template class Seq, typename... Ts> + struct split> + { + using splitter = detail::split, Index, Seq>; + + using before = typename splitter::before; + using left = typename splitter::left; + using head = typename splitter::head; + using right = typename splitter::right; + using after = typename splitter::after; + }; + template + using split_left_t = typename split::left; + template + using get_t = typename split::head; + template + using split_right_t = typename split::right; + template + using split_before_t = typename split::before; + template + using split_after_t = typename split::after; + template + using head_t = get_t<0, Seq>; + template + using tail_t = split_after_t<0, Seq>; + + + template + using pack_prepend_t = list; + template + using pack_append_t = list; + template + using pack_insert_t = cat_t, T>, pack_split_right_t>; + template + using pack_remove_t = cat_t, pack_split_after_t>; + + template + struct prepend; + template class Seq, typename... Ts> + struct prepend> + { + using type = Seq; + }; + template + struct append; + template class Seq, typename... Ts> + struct append> + { + using type = Seq; + }; + + template + using prepend_t = type_t>; + template + using append_t = type_t>; + template + using insert_t = cat_t, T>, split_right_t>; + template + using remove_t = cat_t, split_after_t>; + + namespace detail + { + template + struct merge; + + template class Sequence, typename... Ts, typename LhsHead, typename... LhsTail, typename RhsHead, typename... RhsTail, typename Compare> + struct merge, Sequence, Sequence, Compare> + { + using next_result = typename std::conditional< + apply_t::value, + Sequence, + Sequence + >::type; + using next_lhs = typename std::conditional< + apply_t::value, + Sequence, + Sequence + >::type; + using next_rhs = typename std::conditional< + apply_t::value, + Sequence, + Sequence + >::type; + + using type = type_t< + merge< + next_result, + next_lhs, + next_rhs, + Compare + > + >; + }; + + template class Sequence, typename... Ts, typename LhsHead, typename... LhsTail, typename Compare> + struct merge, Sequence, Sequence<>, Compare> + { + using type = Sequence; + }; + + template class Sequence, typename... Ts, typename RhsHead, typename... RhsTail, typename Compare> + struct merge, Sequence<>, Sequence, Compare> + { + using type = Sequence; + }; + + template class Sequence, typename... Ts, typename Compare> + struct merge, Sequence<>, Sequence<>, Compare> + { + using type = Sequence; + }; + } + + template + using merge = detail::merge, Lhs, Rhs, Compare>; + + template + using merge_t = type_t>; + + namespace detail + { + namespace mergesort + { + template + struct mergesort + { + using left = split_left_t< div_t, int32_t<2>>::value, List>; + using right = split_after_t, int32_t<2>>::value, List>; + + using left_sorted = type_t>; + using right_sorted = type_t>; + + using type = merge_t; + }; + + template class Sequence, typename Compare> + struct mergesort, Compare> + { + using type = Sequence<>; + }; + + template class Sequence, typename T, typename Compare> + struct mergesort, Compare> + { + using type = Sequence; + }; + + template class Sequence, typename T, typename U, typename Compare> + struct mergesort, Compare> + { + template::value> + struct apply + { + using type = Sequence; + }; + + template + struct apply + { + using type = Sequence; + }; + + using type = type_t>; + }; + } + } + + template + using sort = detail::mergesort::mergesort; + + template + using sort_t = type_t>; + + template + struct pair + { + using key = Key; + using value = Value; + }; + + template + using key_t = typename Pair::key; + template + using value_t = typename Pair::value; + + template + struct inherit : Ts... {}; + + template + struct inherit> : Ts... {}; + + namespace detail + { + template + struct aggregate; + + template class Seq, typename T, typename... Ts> + struct aggregate> : public + aggregate> + { + aggregate() = delete; + aggregate(const aggregate&) = delete; + aggregate(aggregate&&) = delete; + aggregate& operator=(const aggregate&) = delete; + aggregate& operator=(aggregate&&) = delete; + + T member; + }; + + template class Seq> + struct aggregate> + { + aggregate() = delete; + aggregate(const aggregate&) = delete; + aggregate(aggregate&&) = delete; + aggregate& operator=(const aggregate&) = delete; + aggregate& operator=(aggregate&&) = delete; + }; + } + + template + using aggregate = ::ctti::meta::detail::aggregate<::ctti::meta::list>; + + template + struct map; + + template + struct map...> + { + using keys = list; + using values = list; + using pairs = list...>; + + struct key_not_found {}; + + template + using at_key = type_t*>(nullptr)))>; + private: + template + static identity lookup(pair*); + + template + static identity lookup(...); + }; + + template + using keys_t = typename Map::keys; + template + using values_t = typename Map::values; + template + using pairs_t = typename Map::pairs; + template + using at_key = typename Map::template at_key; + + template + struct pack_fmap + { + using type = list...>; + }; + + template + struct fmap; + + template class Seq, typename... Ts> + struct fmap> + { + using type = Seq...>; + }; + + namespace detail + { + template + struct filter; + + template class Seq, typename... Filtered, typename Head, typename... Tail> + struct filter, Seq> + { + template>()> + struct next + { + using type = Seq; + }; + + template + struct next<_Head, false> + { + using type = Seq; + }; + + using type = type_t>, Seq>>; + }; + + template class Seq, typename... Filtered> + struct filter, Seq<>> + { + using type = Seq; + }; + } + + template + struct foldl; + + template class Seq, typename Head, typename... Tail> + struct foldl> + { + using type = type_t< + foldl, + Seq + > + >; + }; + + template class Seq> + struct foldl> + { + using type = Seed; + }; + + template + struct foldr; + + template class Seq, typename Head, typename... Tail> + struct foldr> + { + using type = apply_t< + Function, Head, + type_t>> + >; + }; + + template class Seq> + struct foldr> + { + using type = Seed; + }; + + template + using pack_fmap_t = type_t>; + template + using fmap_t = type_t>; + + template + using pack_foldl = foldl>; + template + using pack_foldl_t = type_t>; + template + using foldl_t = type_t>; + + template + using pack_foldr = foldr>; + template + using pack_foldr_t = type_t>; + template + using foldr_t = type_t>; + + template + using filter = detail::filter, Seq>; + template + using filter_t = type_t>; + template + using pack_filter = detail::filter, list>; + template + using pack_filter_t = type_t>; + + template + using any_of = foldl; + template + using any_of_t = foldl_t; + template + using pack_any_of = pack_foldl; + template + using pack_any_of_t = pack_foldl_t; + + template + using any_of = foldl; + template + using any_of_t = foldl_t; + template + using pack_any_of = pack_foldl; + template + using pack_any_of_t = pack_foldl_t; + + template + using join = foldl, apply_functor>, apply_functor, Seqs...>>; + template + using join_t = type_t>; + + namespace detail + { + template class Seq, std::size_t N> + struct make_index_sequence + { + static constexpr std::size_t n = (N % 2) ? ((N - 1) / 2) : (N / 2); + static constexpr std::size_t m = N - n; + + struct adder + { + template + struct apply + { + using type = apply_t, T>; + }; + }; + + using type = cat_t< + type_t>, + fmap_t>> + >; + }; + + template class Seq> + struct make_index_sequence + { + using type = Seq>; + }; + + template class Seq> + struct make_index_sequence + { + using type = Seq<>; + }; + } + + template class Seq = list> + using make_index_sequence = type_t>; + template + using make_index_sequence_for = make_index_sequence; + template + struct to_index_sequence; + template class Seq, typename... Ts> + struct to_index_sequence> + { + using type = make_index_sequence; + }; + template + using to_index_sequence_t = type_t>; + + template + using make_index_sequence_from_sequence = ctti::meta::functor_t, ctti::meta::to_index_sequence_t>; + + namespace detail + { + template + void foreach(ctti::meta::list, ctti::meta::index_sequence, Function function) + { + (void)function; + [](...){}(std::array{{(function(ctti::meta::identity(), ctti::meta::size_t()), 0)..., 0}}); + } + } + + template + void foreach(Function function) + { + ctti::meta::detail::foreach(ctti::meta::apply_functor, Sequence>(), ctti::meta::make_index_sequence_from_sequence(), function); + } +} + +} + +#endif // CTTI_UTILITY_META_H diff --git a/include/cereal/external/ctti/detail/name_filters.hpp b/include/cereal/external/ctti/detail/name_filters.hpp new file mode 100644 index 00000000..4fe208c1 --- /dev/null +++ b/include/cereal/external/ctti/detail/name_filters.hpp @@ -0,0 +1,77 @@ +#ifndef CTTI_DETAIL_NAMEFILTERS_HPP +#define CTTI_DETAIL_NAMEFILTERS_HPP + +#include "cstring.hpp" + +namespace ctti +{ + +namespace detail +{ + +constexpr ctti::detail::cstring filter_prefix(const ctti::detail::cstring& str, const ctti::detail::cstring& prefix) +{ + return str.size() >= prefix.size() ? (str(0, prefix.size()) == prefix ? str(prefix.size(), str.size()) : str) : str; +} + +constexpr ctti::detail::cstring leftpad(const ctti::detail::cstring& str) +{ + return (str.size() > 0 && str[0] == ' ') ? leftpad(str(1, str.size())) : str; +} + +constexpr ctti::detail::cstring filter_class(const ctti::detail::cstring& type_name) +{ + return leftpad(filter_prefix(leftpad(type_name), "class")); +} + +constexpr ctti::detail::cstring filter_struct(const ctti::detail::cstring& type_name) +{ + return leftpad(filter_prefix(leftpad(type_name), "struct")); +} + +constexpr ctti::detail::cstring filter_typename_prefix(const ctti::detail::cstring& type_name) +{ + return filter_struct(filter_class(type_name)); +} + +namespace +{ + +constexpr const char* find_ith_impl(const ctti::detail::cstring& name, const ctti::detail::cstring& substring, const char* res, std::size_t i, bool infinite = false) +{ + return (name.length() >= substring.length()) ? + ((name(0, substring.length()) == substring) ? + ((i == 0) ? + name.begin() + : + find_ith_impl(name(substring.length(), name.length()), substring, name.begin(), i - 1, infinite)) + : + find_ith_impl(name(1, name.length()), substring, res, i, infinite)) + : + (!infinite) ? name.end() : res; +} + +} + +constexpr const char* find_ith(const ctti::detail::cstring& name, const ctti::detail::cstring& substring, std::size_t i) +{ + return find_ith_impl(name, substring, name.end(), i); +} + +constexpr const char* find_last(const ctti::detail::cstring& name, const ctti::detail::cstring& substring) +{ + return find_ith_impl(name, substring, name.end(), -1, true); +} + +constexpr const char* find(const ctti::detail::cstring& name, const ctti::detail::cstring& substring) +{ + return find_ith(name, substring, 0); +} + + + +} + +} + +#endif // CTTI_DETAIL_NAMEFILTERS_HPP diff --git a/include/cereal/external/ctti/detail/preprocessor.hpp b/include/cereal/external/ctti/detail/preprocessor.hpp new file mode 100644 index 00000000..ff838f9a --- /dev/null +++ b/include/cereal/external/ctti/detail/preprocessor.hpp @@ -0,0 +1,7 @@ +#ifndef CTTI_DETAIL_PREPROCESSOR_HPP +#define CTTI_DETAIL_PREPROCESSOR_HPP + +#define CTTI_PP_STR_IMPL(x) #x +#define CTTI_PP_STR(x) CTTI_PP_STR_IMPL(x) + +#endif // CTTI_DETAIL_PREPROCESSOR_HPP diff --git a/include/cereal/external/ctti/detail/pretty_function.hpp b/include/cereal/external/ctti/detail/pretty_function.hpp new file mode 100644 index 00000000..22a2ed8e --- /dev/null +++ b/include/cereal/external/ctti/detail/pretty_function.hpp @@ -0,0 +1,78 @@ +// +// Created by manu343726 on 4/08/15. +// + +#ifndef CTTI_PRETTY_FUNCTION_HPP +#define CTTI_PRETTY_FUNCTION_HPP + +#include "cstring.hpp" + +#if defined(__clang__) + #define CTTI_PRETTY_FUNCTION __PRETTY_FUNCTION__ +#elif defined(__GNUC__) && !defined(__clang__) + #define CTTI_PRETTY_FUNCTION __PRETTY_FUNCTION__ +#elif defined(_MSC_VER) + #define CTTI_PRETTY_FUNCTION __FUNCSIG__ +#else + #error "No support for this compiler." +#endif + +namespace ctti +{ + +namespace pretty_function +{ + +template +constexpr ctti::detail::cstring type() +{ + return {CTTI_PRETTY_FUNCTION}; +} + +template +constexpr ctti::detail::cstring value() +{ + return {CTTI_PRETTY_FUNCTION}; +} + +} + +} + +#if defined(__clang__) + #define CTTI_TYPE_PRETTY_FUNCTION_PREFIX "ctti::detail::cstring ctti::pretty_function::type() [T = " + #define CTTI_TYPE_PRETTY_FUNCTION_SUFFIX "]" +#elif defined(__GNUC__) && !defined(__clang__) + #define CTTI_TYPE_PRETTY_FUNCTION_PREFIX "constexpr ctti::detail::cstring ctti::pretty_function::type() [with T = " + #define CTTI_TYPE_PRETTY_FUNCTION_SUFFIX "]" +#elif defined(_MSC_VER) + #define CTTI_TYPE_PRETTY_FUNCTION_PREFIX "struct ctti::detail::cstring __cdecl ctti::pretty_function::type<" + #define CTTI_TYPE_PRETTY_FUNCTION_SUFFIX ">(void)" +#else + #error "No support for this compiler." +#endif + +#define CTTI_TYPE_PRETTY_FUNCTION_LEFT (sizeof(CTTI_TYPE_PRETTY_FUNCTION_PREFIX) - 1) +#define CTTI_TYPE_PRETTY_FUNCTION_RIGHT (sizeof(CTTI_TYPE_PRETTY_FUNCTION_SUFFIX) - 1) + +#if defined(__clang__) + #define CTTI_VALUE_PRETTY_FUNCTION_PREFIX "ctti::detail::cstring ctti::pretty_function::value() [T = " + #define CTTI_VALUE_PRETTY_FUNCTION_SEPARATOR "; Value = " + #define CTTI_VALUE_PRETTY_FUNCTION_SUFFIX "]" +#elif defined(__GNUC__) && !defined(__clang__) + #define CTTI_VALUE_PRETTY_FUNCTION_PREFIX "constexpr ctti::detail::cstring ctti::pretty_function::value() [with T = " + #define CTTI_VALUE_PRETTY_FUNCTION_SEPARATOR "; T Value = " + #define CTTI_VALUE_PRETTY_FUNCTION_SUFFIX "]" +#elif defined(_MSC_VER) + #define CTTI_VALUE_PRETTY_FUNCTION_PREFIX "struct ctti::detail::cstring __cdecl ctti::pretty_function::value<" + #define CTTI_VALUE_PRETTY_FUNCTION_SEPARATOR "; T Value = " + #define CTTI_VALUE_PRETTY_FUNCTION_SUFFIX ">(void)" +#else + #error "No support for this compiler." +#endif + +#define CTTI_VALUE_PRETTY_FUNCTION_LEFT (sizeof(CTTI_VALUE_PRETTY_FUNCTION_PREFIX) - 1) +#define CTTI_VALUE_PRETTY_FUNCTION_SEPARATION (sizeof(CTTI_VALUE_PRETTY_FUNCTION_SEPARATOR) - 1) +#define CTTI_VALUE_PRETTY_FUNCTION_RIGHT (sizeof(CTTI_VALUE_PRETTY_FUNCTION_SUFFIX) - 1) + +#endif //CTTI_PRETTY_FUNCTION_HPP diff --git a/include/cereal/external/ctti/detailed_nameof.hpp b/include/cereal/external/ctti/detailed_nameof.hpp new file mode 100644 index 00000000..23af837e --- /dev/null +++ b/include/cereal/external/ctti/detailed_nameof.hpp @@ -0,0 +1,35 @@ +#ifndef CTTI_DETAILED_NAMEOF_HPP +#define CTTI_DETAILED_NAMEOF_HPP + +#include +#include +#include + +namespace ctti +{ + + +template +constexpr name_t detailed_nameof() +{ + return {ctti::nameof()}; +} + +template +constexpr name_t detailed_nameof() +{ + return {ctti::nameof()}; +} + +#ifdef CTTI_HAS_VARIABLE_TEMPLATES +template +constexpr ctti::name_t detailed_nameof_v = ctti::detailed_nameof(); + +// CONSIDER USING detailed_nameof_v INSTEAD +template +constexpr ctti::name_t detailed_nameof_value_v = ctti::detailed_nameof(); +#endif // CTTI_HAS_VARIABLE_TEMPLATES + +} + +#endif // CTTI_DETAILED_NAMEOF_HPP diff --git a/include/cereal/external/ctti/hash_literal.hpp b/include/cereal/external/ctti/hash_literal.hpp new file mode 100644 index 00000000..f6b4afbc --- /dev/null +++ b/include/cereal/external/ctti/hash_literal.hpp @@ -0,0 +1,20 @@ +#ifndef CTTI_HASH_LITERAL_HPP +#define CTTI_HASH_LITERAL_HPP + +#include + +#ifdef CTI_HASH_LITERAL_NAMESPACE +namespace CTTI_HASH_LITERAL_NAMESPACE +{ +#endif // CTTI_HASH_LITERAL_NAMESPACE + +constexpr std::uint64_t operator"" _sh(const char* str, std::size_t length) +{ + return ctti::detail::cstring{str, length}.hash(); +} + +#ifdef CTTI_HASH_LITERAL_NAMESPACE +} +#endif // CTTI_HASH_LITERAL_NAMESPACE + +#endif // CTTI_HASH_LITERAL_HPP diff --git a/include/cereal/external/ctti/map.hpp b/include/cereal/external/ctti/map.hpp new file mode 100644 index 00000000..be933fa4 --- /dev/null +++ b/include/cereal/external/ctti/map.hpp @@ -0,0 +1,79 @@ +#ifndef CTTI_MAP_HPP +#define CTTI_MAP_HPP + +#include + +namespace ctti +{ + +struct default_symbol_mapping_function +{ + constexpr default_symbol_mapping_function() = default; + + template + void operator()(const Source& source, SourceSymbol, Sink& sink, SinkSymbol) const + { + ctti::set_member_value(sink, ctti::get_member_value(source)); + } +}; + +template +void map(const Source& source, Sink& sink, const Function& function) +{ + function(source, SourceSymbol(), sink, SinkSymbol()); +} + +template +void map(const Source& source, Sink& sink) +{ + ctti::map(source, sink, ctti::default_symbol_mapping_function()); +} + +template +struct symbol_mapping +{ + constexpr symbol_mapping(Function function) : + function{function} + {} + + Function function; + + template + auto operator()(const Source& source, SourceSymbol, Sink& sink, SinkSymbol) const -> + ctti::meta::void_t()(source, SourceSymbol(), sink, SinkSymbol()))> + { + function(source, SourceSymbol(), sink, SinkSymbol()); + } + + template + auto operator()(const Source& source, SourceSymbol, Sink& sink, SinkSymbol) const -> + ctti::meta::void_t()(ctti::get_member_value(source), ctti::type_tag>()))> + { + ctti::set_member_value(sink, function( + ctti::get_member_value(source), + ctti::type_tag>() + )); + } +}; + +template +constexpr ctti::symbol_mapping> mapping(const Function& function) +{ + return {function}; +} + +template +constexpr ctti::symbol_mapping mapping() +{ + return {ctti::default_symbol_mapping_function()}; +} + +template +void map(const Source& source, Sink& sink, const ctti::symbol_mapping&... mapping) +{ + [](...){}((map(source, sink, mapping), 0)...); +} + +} + +#endif // CTTI_MAP_HPP diff --git a/include/cereal/external/ctti/model.hpp b/include/cereal/external/ctti/model.hpp new file mode 100644 index 00000000..134743d7 --- /dev/null +++ b/include/cereal/external/ctti/model.hpp @@ -0,0 +1,45 @@ +#ifndef CTTI_MODEL_HPP +#define CTTI_MODEL_HPP + +#include +#include +#include + +namespace ctti +{ + +template +struct model +{ + using symbols = ctti::meta::list; +}; + +template +ctti::model<> ctti_model(ctti::type_tag); + +namespace detail +{ + template + struct get_model + { + using type = decltype(ctti_model(ctti::type_tag())); + }; + + template + struct get_model> + { + using type = typename T::ctti_model; + }; +} + +template +using get_model = typename ctti::detail::get_model::type; + +template +struct has_model : public ctti::meta::bool_< + (ctti::meta::list_size>() > 0) +> {}; + +} + +#endif // CTTI_MODEL_HPP diff --git a/include/cereal/external/ctti/name.hpp b/include/cereal/external/ctti/name.hpp new file mode 100644 index 00000000..36f8fe22 --- /dev/null +++ b/include/cereal/external/ctti/name.hpp @@ -0,0 +1,86 @@ +#ifndef CTTI_NAME_HPP +#define CTTI_NAME_HPP + +#include +#include + +namespace ctti +{ + +struct name_t +{ + constexpr name_t(const ctti::detail::cstring& full_name) : + _full_name{full_name} + {} + + constexpr ctti::detail::cstring name() const + { + return ctti::detail::find_last(_full_name, "::") == _full_name.end() ? + _full_name : ctti::detail::cstring{ctti::detail::find_last(_full_name, "::") + 2, _full_name.end()}; + } + + constexpr ctti::detail::cstring full_name() const + { + return _full_name; + } + + constexpr ctti::detail::cstring full_homogeneous_name() const + { + return ctti::detail::filter_prefix(full_name(), "&"); + } + + constexpr ctti::detail::cstring qualifier(std::size_t i) const + { + return (i > 0) ? get_qualifier( + ctti::detail::find_ith(_full_name, "::", i - 1) + 2, + ctti::detail::find_ith(_full_name, "::", i) + ) : (ctti::detail::find_ith(_full_name, "::", i) != _full_name.end()) ? + ctti::detail::cstring{_full_name.begin(), ctti::detail::find_ith(_full_name, "::", i)} : + ctti::detail::cstring{""}; + } + +private: + ctti::detail::cstring _full_name; + + constexpr ctti::detail::cstring right(const ctti::detail::cstring& str) const + { + return {ctti::detail::min(_full_name.end(), str.begin()), _full_name.end()}; + } + + constexpr ctti::detail::cstring left(const char* end) const + { + return (end < _full_name.end()) ? + ctti::detail::cstring{_full_name.begin(), end} + : + ctti::detail::cstring{""}; + } + + constexpr ctti::detail::cstring get_name(const ctti::detail::cstring& name) const + { + return (name != "") ? name : _full_name; + } + + constexpr ctti::detail::cstring get_qualifier(const char* begin, const char* end) const + { + return get_qualifier_impl(begin, end); + } + + constexpr ctti::detail::cstring get_qualifier_impl(const char* begin, const char* end) const + { + return (end == _full_name.end()) ? ctti::detail::cstring{""} : ctti::detail::cstring{begin, end}; + } +}; + +constexpr bool operator==(const name_t& lhs, const name_t rhs) +{ + return lhs.full_name() == rhs.full_name(); +} + +constexpr bool operator!=(const name_t& lhs, const name_t rhs) +{ + return !(lhs == rhs); +} + +} + +#endif // CTTI_NAME_HPP diff --git a/include/cereal/external/ctti/nameof.hpp b/include/cereal/external/ctti/nameof.hpp new file mode 100644 index 00000000..9dbfb946 --- /dev/null +++ b/include/cereal/external/ctti/nameof.hpp @@ -0,0 +1,149 @@ +#ifndef CTTI_NAMEOF_HPP +#define CTTI_NAMEOF_HPP + +#include "detail/pretty_function.hpp" +#include "detail/name_filters.hpp" +#include "detail/meta.hpp" +#include "detail/language_features.hpp" +#include "type_tag.hpp" +#include "static_value.hpp" +#include +#include + +namespace ctti +{ + +template +constexpr ctti::detail::cstring nameof(); + +template +constexpr ctti::detail::cstring nameof(); + +namespace detail +{ + +template +struct TypeNameLength : + std::integral_constant< + std::size_t, + ctti::nameof().length() + > +{}; + +template +struct TypeNameLength : + std::integral_constant< + std::size_t, + ctti::nameof().length() + > +{}; + +template +struct TypeNameLength::value>::type> : + std::integral_constant< + std::size_t, + ctti::nameof().length() + > +{}; + +} + +template +constexpr ctti::detail::cstring nameof(); + +namespace detail +{ + +template +struct another_level_of_indirection {}; + +template +struct nameof_impl +{ + static constexpr ctti::detail::cstring apply() + { + return ctti::detail::filter_typename_prefix(ctti::pretty_function::type().pad( + CTTI_TYPE_PRETTY_FUNCTION_LEFT, + CTTI_TYPE_PRETTY_FUNCTION_RIGHT + )); + } +}; + +template +struct nameof_impl> +{ + static constexpr ctti::detail::cstring apply() + { + return T::ctti_nameof(); + } +}; + +template +struct nameof_impl>, void> +{ + static constexpr ctti::detail::cstring apply() + { + return ctti::pretty_function::value().pad( + CTTI_VALUE_PRETTY_FUNCTION_LEFT + ctti::detail::TypeNameLength::value + CTTI_VALUE_PRETTY_FUNCTION_SEPARATION, + CTTI_VALUE_PRETTY_FUNCTION_RIGHT + ); + } +}; + +template +struct nameof_impl, void> +{ + static constexpr ctti::detail::cstring apply() + { + return ctti::nameof(); + } +}; + +} + +template +constexpr ctti::detail::cstring ctti_nameof(ctti::type_tag) +{ + return ctti::detail::nameof_impl::apply(); +} + +template +constexpr ctti::detail::cstring ctti_nameof(ctti::static_value) +{ + return ctti::detail::nameof_impl>>::apply(); +} + +template +constexpr ctti::detail::cstring nameof() +{ + using namespace ctti; + return ctti_nameof(ctti::type_tag()); +} + +template +constexpr ctti::detail::cstring nameof() +{ + using namespace ctti; + return ctti_nameof(ctti::static_value()); +} + +#ifdef CTTI_HAS_VARIABLE_TEMPLATES +template +constexpr ctti::detail::cstring nameof_v = ctti::nameof(); + +// CONSIDER USING nameof_v INSTEAD +template +constexpr ctti::detail::cstring nameof_value_v = ctti::nameof(); +#endif // CTTI_HAS_VARIABLE_TEMPLATES + +} + +namespace std +{ +constexpr ctti::detail::cstring ctti_nameof(ctti::type_tag) +{ + return "std::string"; +} +} + +#endif // CTTI_NAMEOF_HPP diff --git a/include/cereal/external/ctti/serialization.hpp b/include/cereal/external/ctti/serialization.hpp new file mode 100644 index 00000000..3df4e04c --- /dev/null +++ b/include/cereal/external/ctti/serialization.hpp @@ -0,0 +1,656 @@ +#ifndef CTTI_SERIALIZATION_HPP +#define CTTI_SERIALIZATION_HPP + +#include +#include +#include +#include +#include +#include +#include + +namespace ctti +{ + +namespace serialization +{ + +template +void serialize(Formatter formatter, Output& output, const T& value); + +template +void serialize(Writer writer, const T& value); + +template +void deserialize(Reader reader, T& value); + +namespace detail +{ + template(), bool EmptyModel = ctti::meta::list_size>() == 0> + struct serialize + { + using Model = ctti::get_model; + + template + struct loop_body + { + Writer* writer; + const T* value; + + template + void operator()(SymbolIdentity, Index) + { + using Symbol = ctti::meta::type_t; + constexpr std::size_t index = Index(); + + writer->value(Symbol::symbol().str(), ctti::get_member_value(*value)); + + if(index + 1 < ctti::meta::list_size()) + { + writer->value_separator(); + } + } + }; + + template + static void apply(Writer& writer, const T& value) + { + loop_body loop_body{&writer, &value}; + + writer.begin_object(value); + ctti::meta::foreach(loop_body); + writer.end_object(value); + } + }; + + template + struct serialize + { + using Model = ctti::get_model; + + template + struct loop_body + { + Writer* writer; + const T* value; + + template + void operator()(SymbolIdentity, Index) + { + using Symbol = ctti::meta::type_t; + + if(Symbol::template get_member() == *value) + { + // Found the enumeration value with this value + writer->raw_value(Symbol::symbol().str()); + } + } + }; + + template + static void apply(Writer& writer, const T& value) + { + loop_body loop_body{&writer, &value}; + ctti::meta::foreach(loop_body); + } + }; + + template + struct serialize + { + template + static void apply(Writer& writer, const T& value) + { + writer.value(value); + } + }; + + template::value, bool HasModel = ctti::has_model::value> + struct deserialize + { + using Model = ctti::get_model; + + template + struct loop_body + { + Reader* reader; + T* value; + + template + void operator()(SymbolIdentity, Index) + { + using Symbol = ctti::meta::type_t; + reader->value(Symbol::symbol().str(), ctti::get_member_value(*value)); + } + }; + + template + static void apply(Reader& reader, T& value) + { + loop_body loop_body{&reader, &value}; + ctti::meta::foreach(loop_body); + } + }; + + template + struct deserialize + { + using Model = ctti::get_model; + + template + struct loop_body + { + T* value; + InputValue input_value; + + template + void operator()(SymbolIdentity, Index) + { + using Symbol = ctti::meta::type_t; + + if(static_cast::type>(Symbol::template get_member()) == + static_cast::type>(input_value)) + { + *value = Symbol::template get_member(); + } + } + }; + + template + struct loop_body + { + T* value; + std::string input_value; + + template + void operator()(SymbolIdentity, Index) + { + using Symbol = ctti::meta::type_t; + + if(Symbol::symbol().str() == input_value) + { + *value = Symbol::template get_member(); + } + } + }; + + struct callback + { + template + T operator()(const InputValue& input_value) + { + T output_value{}; + ctti::meta::foreach(loop_body{&output_value, input_value}); + return output_value; + } + }; + + template + static void apply(Reader& reader, T& value) + { + reader.enum_value(value, callback()); + } + }; + + template + struct deserialize + { + template + static void apply(Reader& reader, T& value) + { + reader.value(value); + } + }; +} + +template +struct Writer +{ + Writer(Formatter formatter, Output& output) : + _formatter{formatter}, + _output{&output} + {} + + void value_separator() + { + _formatter.value_separator(*_output); + } + + template + void raw_value(const T& value) + { + _formatter.raw_value(*_output, value); + } + + template + void value(const T& value) + { + _formatter.value(*_output, value); + } + + template + void value(const std::string& name, const T& value) + { + _formatter.value(*_output, name, value); + } + + template + void begin_object(const T& object) + { + _formatter.begin_object(*_output, object); + } + + template + void end_object(const T& object) + { + _formatter.end_object(*_output, object); + } + +private: + Formatter _formatter; + Output* _output; +}; + +template +Writer make_writer(Formatter formatter, Output& output) +{ + return {formatter, output}; +} + +struct ostream_otuput +{ + ostream_otuput(std::ostream& os) : + os(&os) + {} + + template + void write(const T& value) + { + (*os) << value; + } + +private: + std::ostream* os; +}; + +struct json_formatter +{ + template + void raw_value(Output& output, const T& value) + { + output.write(value); + } + + template + void value_separator(Output& out) + { + out.write(", "); + } + + template + void begin_object(Output& out, const T&) + { + out.write("{"); + } + + template + void end_object(Output& out, const T&) + { + out.write("}"); + } + + template + void value(Output& out, const std::string& name, const T& value) + { + out.write("\""); out.write(name); out.write("\": "); this->value(out, value); + } + + template + void value(Output& out, const T& value) + { + write_value(out, value, ctti::meta::bool_>() == 0>()); + } + + template + void value(Output& out, const std::string& value) + { + out.write("\""); out.write(value); out.write("\""); + } + + template + void value(Output& out, const std::vector& vector) + { + out.write("["); + + for(std::size_t i = 0; i < vector.size(); ++i) + { + ctti::serialization::serialize(*this, out, vector[i]); + + if(i + 1 < vector.size()) + { + out.write(", "); + } + } + + out.write("]"); + } + + template + void value(Output& out, const std::array& array) + { + out.write("["); + + for(std::size_t i = 0; i < array.size(); ++i) + { + ctti::serialization::serialize(*this, out, array[i]); + + if(i + 1 < array.size()) + { + out.write(", "); + } + } + + out.write("]"); + } + + template + void value(Output& out, const std::unordered_map& map) + { + out.write("["); + std::size_t i = 0; + + for(const auto& keyValue : map) + { + out.write("{"); + ctti::serialization::serialize(*this, out, keyValue.first); + out.write(": "); + ctti::serialization::serialize(*this, out, keyValue.second); + out.write("}"); + + if(i + 1 < map.size()) + { + out.write(", "); + } + + ++i; + } + + out.write("]"); + } + + template + void value(Output& out, const std::tuple& tuple) + { + out.write("("); + ctti::meta::foreach>(tuple_loop_body_t{&tuple, this, &out}); + out.write(")"); + } + +private: + template + struct tuple_loop_body_t + { + const std::tuple* tuple; + json_formatter* self; + Output* out; + + template + void operator()(ctti::meta::identity, ctti::meta::size_t) const + { + ctti::serialization::serialize(*self, *out, std::get(*tuple)); + + if(Index + 1 < sizeof...(Ts)) + { + out->write(", "); + } + } + }; + + template + void write_value(Output& out, const T& value, ctti::meta::true_) + { + out.write(value); + } + + template + void write_value(Output& out, const T& value, ctti::meta::false_) + { + ctti::serialization::serialize(*this, out, value); + } +}; + +struct json_writer +{ + json_writer(nlohmann::json& current_object) : + _current_object{¤t_object} + {} + + template + ctti::meta::enable_if_t::value> value(const std::string& name, const T& value) + { + ctti::serialization::serialize(json_writer((*_current_object)[name]), value); + } + + template + ctti::meta::enable_if_t::value> value(const std::string& name, const T& value) + { + (*_current_object)[name] = nlohmann::json(value); + } + + template + void raw_value(const T& value) + { + *_current_object = nlohmann::json(value); + } + + template + ctti::meta::enable_if_t::value> value(const T& value) + { + ctti::serialization::serialize(json_writer(*_current_object), value); + } + + template + ctti::meta::enable_if_t::value> value(const T& value) + { + raw_value(value); + } + + template + void begin_object(const T&) + { + } + + template + void end_object(const T&) + { + } + + void value_separator() {} + +private: + nlohmann::json* _current_object; +}; + +struct json_reader +{ + json_reader(const nlohmann::json& json) : + _current_object{&json} + {} + + template + ctti::meta::enable_if_t::value> value(T& value) + { + ctti::serialization::deserialize(json_reader(*_current_object), value); + } + + template + ctti::meta::enable_if_t::value> value(T& value) + { + value = _current_object->get(); + } + + template + void enum_value(T& value, Function callback) + { + if(_current_object->is_number()) + { + value = callback(_current_object->get::type>()); + } + else if(_current_object->is_string()) + { + value = callback(_current_object->get()); + } + } + + template + ctti::meta::enable_if_t::value> value(const std::string& name, T& value) + { + ctti::serialization::deserialize(json_reader((*_current_object)[name]), value); + } + + template + ctti::meta::enable_if_t::value> value(const std::string& name, T& value) + { + auto subobject = (*_current_object)[name]; + value = subobject.get(); + } + + template + void value(const std::string& name, std::unordered_map& map) + { + value((*_current_object)[name], map); + } + + template + void value(std::unordered_map& map) + { + value(*_current_object, map); + } + +private: + const nlohmann::json* _current_object; + + template + void value(const nlohmann::json& json, std::unordered_map& map) + { + assert(json.is_array()); + + for(const auto& key_value_object : json) + { + // maps are serialized as key, value arrays, where key value pairs are arrays too + assert(key_value_object.is_array()); + assert(key_value_object.size() == 2); + + const auto& key = key_value_object[0]; + const auto& value = key_value_object[1]; + + Key deserialized_key; + Value deserialized_value; + ctti::serialization::deserialize(json_reader(key), deserialized_key); + ctti::serialization::deserialize(json_reader(value), deserialized_value); + + map[std::move(deserialized_key)] = std::move(deserialized_value); + } + } +}; + +struct enum_from_string_reader +{ + enum_from_string_reader(const std::string& input) : + _input{input} + {} + + template + void enum_value(T& value, Callback callback) + { + value = callback(_input); + } + +private: + std::string _input; +}; + +struct enum_to_string_writer +{ + enum_to_string_writer(std::string& output) : + _output{&output} + {} + + void raw_value(const std::string& enum_value) + { + *_output = enum_value; + } + +private: + std::string* _output; +}; + +template +ctti::meta::enable_if_t::value && std::is_enum::value, std::string> enum_to_string(const Enum value) +{ + std::string output; + ctti::serialization::serialize(ctti::serialization::enum_to_string_writer(output), value); + return output; +} + +template +ctti::meta::enable_if_t::value && std::is_enum::value, Enum> enum_from_string(const std::string& enum_string) +{ + Enum enum_value{}; + ctti::serialization::deserialize(ctti::serialization::enum_from_string_reader(enum_string), enum_value); + return enum_value; +} + +template +void serialize(Writer writer, const T& value) +{ + ctti::serialization::detail::serialize::apply(writer, value); +} + +template +void serialize(Formatter formatter, Output& output, const T& value) +{ + auto writer = ctti::serialization::make_writer(formatter, output); + ctti::serialization::serialize(writer, value); +} + +template +void serialize(Formatter formatter, Output output, const T& value) +{ + auto writer = ctti::serialization::make_writer(formatter, output); + ctti::serialization::serialize(writer, value); +} + +template +void deserialize(Reader reader, T& value) +{ + ctti::serialization::detail::deserialize::apply(reader, value); +} + +namespace detail +{ + template>() == 0, typename = void> + struct is_default_ostream_serializable : public ctti::meta::false_ {}; + + template + struct is_default_ostream_serializable> : public ctti::meta::true_ {}; + + template + struct is_default_ostream_serializable().ctti_ostream_print())>> : public ctti::meta::true_ {}; + + template + struct is_default_ostream_serializable>()))>> : public ctti::meta::true_ {}; +} + +} + +} + +template +ctti::meta::enable_if_t::value, std::ostream&> operator<<(std::ostream& os, const T& value) +{ + ctti::serialization::serialize(ctti::serialization::json_formatter(), ctti::serialization::ostream_otuput(os), value); + return os; +} + +#endif // CTTI_SERIALIZATION_HPP diff --git a/include/cereal/external/ctti/static_value.hpp b/include/cereal/external/ctti/static_value.hpp new file mode 100644 index 00000000..4c21e036 --- /dev/null +++ b/include/cereal/external/ctti/static_value.hpp @@ -0,0 +1,52 @@ +#ifndef CTTI_DETAIL_STATIC_VALUE_HPP +#define CTTI_DETAIL_STATIC_VALUE_HPP + +namespace ctti +{ + +template +struct static_value +{ + constexpr static_value() = default; + using value_type = T; + static constexpr value_type value = Value; + + constexpr operator value_type() const + { + return Value; + } + + constexpr value_type get() const + { + return Value; + } + + friend constexpr bool operator==(const static_value& lhs, const value_type rhs) + { + return lhs.get() == rhs; + } + + friend constexpr bool operator==(const value_type lhs, const static_value& rhs) + { + return rhs == lhs; + } + + friend constexpr bool operator!=(const static_value& lhs, const value_type rhs) + { + return !(lhs == rhs); + } + + friend constexpr bool operator!=(const value_type lhs, const static_value& rhs) + { + return !(lhs == rhs); + } +}; + +template +constexpr T static_value::value; + +} + +#define CTTI_STATIC_VALUE(x) ::ctti::static_value + +#endif // CTTI_DETAIL_STATIC_VALUE_HPP diff --git a/include/cereal/external/ctti/symbol.hpp b/include/cereal/external/ctti/symbol.hpp new file mode 100644 index 00000000..fce58e1d --- /dev/null +++ b/include/cereal/external/ctti/symbol.hpp @@ -0,0 +1,242 @@ +#ifndef CTTI_SYMBOL_HPP +#define CTTI_SYMBOL_HPP + +#include +#include +#include +#include +#include + +#define CTTI_DEFINE_SYMBOL(name) \ + struct name { \ + constexpr name() {} \ + \ + static constexpr ctti::detail::cstring symbol() { \ + return CTTI_PP_STR(name); \ + } \ + \ + static constexpr std::uint64_t hash() { \ + return symbol().hash(); \ + } \ + \ + template::value, typename = void> \ + struct impl \ + { \ + static constexpr bool is_member_of() { \ + return false; \ + } \ + \ + using member_type = std::nullptr_t; \ + \ + static constexpr member_type get_member() { \ + return nullptr; \ + } \ + \ + static constexpr ctti::detail::cstring member_name() { \ + return CTTI_PP_STR(name); \ + } \ + }; \ + \ + template \ + struct impl> { \ + static constexpr bool is_member_of() { \ + return true; \ + } \ + \ + using member_type = decltype(&T::name); \ + \ + static constexpr member_type get_member() { \ + return &T::name; \ + } \ + \ + static constexpr ctti::detail::cstring member_name() { \ + return ctti::nameof(); \ + } \ + }; \ + \ + template \ + struct impl> { \ + static constexpr bool is_member_of() { \ + return true; \ + } \ + \ + using member_type = decltype(T::name); \ + \ + static constexpr member_type get_member() { \ + return T::name; \ + } \ + \ + static constexpr ctti::detail::cstring member_name() { \ + return CTTI_PP_STR(name); \ + } \ + }; \ + \ + template \ + using member_type = typename impl::member_type; \ + \ + template \ + static constexpr bool is_member_of() { \ + return impl::is_member_of(); \ + } \ + \ + template \ + static constexpr member_type get_member() { \ + return impl::get_member(); \ + } \ + \ + template \ + static constexpr ctti::name_t detailed_name() { \ + return ctti::detailed_nameof())>(); \ + } \ + \ + template \ + static constexpr ctti::detail::cstring member_name() { \ + return impl::member_name(); \ + } \ + \ + template \ + using value_type = typename ::ctti::detail::member_traits>::value_type; \ + }; \ + \ + name ctti_symbol_from_hash(::ctti::meta::uint64_t) + + +namespace ctti +{ + +namespace detail +{ + +template +struct member_traits; + +template +struct member_traits +{ + using value_type = T; + using pointer_type = T Class::*; + + template + static constexpr const value_type& get(const Obj& object, pointer_type member) + { + return object.*member; + } + + template + static constexpr value_type& get(Obj& object, pointer_type member) + { + return object.*member; + } + + template + static void set(Obj& object, pointer_type member, Value&& value) + { + get(object, member) = std::forward(value); + } +}; + +template +struct member_traits +{ + using value_type = T; + using pointer_type = T (Class::*)(Args...); + + template + static constexpr value_type get(const Obj& object, pointer_type member, _Args&&... args) + { + return (object.*member)(std::forward<_Args>(args)...); + } + + template + static void set(Obj& object, pointer_type member, _Args&&... args) + { + get(object, member, std::forward<_Args>(args)...); + } +}; + +template +struct member_traits +{ + using pointer_type = void (Class::*)(Arg); + using value_type = ctti::meta::decay_t; + + template + static void set(Obj& object, pointer_type member, _Arg&& arg) + { + (object.*member)(std::forward<_Arg>(arg)); + } +}; + +template +struct member_traits +{ + using value_type = T; + using pointer_type = T (Class::*)(Args...) const; + + template + static constexpr value_type get(const Obj& object, pointer_type member, _Args&&... args) + { + return (object.*member)(std::forward<_Args>(args)...); + } +}; + +template +constexpr auto member_traits_get(const T& object, Member member, Args&&... args) + -> const typename member_traits::value_type& +{ + return member_traits::get(object, member, std::forward(args)...); +} + +template +constexpr auto member_traits_get(T& object, Member member, Args&&... args) + -> typename member_traits::value_type& +{ + return member_traits::get(object, member, std::forward(args)...); +} + +template +void member_traits_set(T& object, Member member, Args&&... args) +{ + member_traits::set(object, member, std::forward(args)...); +} + +template +struct no_symbol_for_hash {}; + +} + +template +constexpr const typename Symbol::template value_type& get_member_value(const T& object, Args&&... args) +{ + static_assert(Symbol::template is_member_of(), "not a member of the class"); + return ctti::detail::member_traits_get(object, Symbol::template get_member(), std::forward(args)...); +} + +template +typename Symbol::template value_type& +get_member_value(T& object, Args&&... args) +{ + static_assert(Symbol::template is_member_of(), "not a member of the class"); + return ctti::detail::member_traits_get(object, Symbol::template get_member(), std::forward(args)...); +} + +template +void set_member_value(const T& object, Args&&... args) +{ + static_assert(Symbol::template is_member_of(), "not a member of the class"); + ctti::detail::member_traits_set(object, Symbol::template get_member(), std::forward(args)...); +} + +template +void set_member_value(T& object, Args&&... args) +{ + static_assert(Symbol::template is_member_of(), "not a member of the class"); + ctti::detail::member_traits_set(object, Symbol::template get_member(), std::forward(args)...); +} + +} + +template +ctti::detail::no_symbol_for_hash ctti_symbol_from_hash(Hash); + +#endif // CTTI_SYMBOL_HPP diff --git a/include/cereal/external/ctti/symbol_from_hash.hpp b/include/cereal/external/ctti/symbol_from_hash.hpp new file mode 100644 index 00000000..cdd8fcef --- /dev/null +++ b/include/cereal/external/ctti/symbol_from_hash.hpp @@ -0,0 +1,15 @@ +#ifndef CTTI_SYMBOL_FROM_HASH_HPP +#define CTTI_SYMBOL_FROM_HASH_HPP + +#include + +namespace ctti +{ + +template +using symbol_from_hash = decltype(ctti_symbol_from_hash(ctti::meta::uint64_t())); + +} + + +#endif // CTTI_SYMBOL_FROM_HASH_HPP diff --git a/include/cereal/external/ctti/tie.hpp b/include/cereal/external/ctti/tie.hpp new file mode 100644 index 00000000..738f3e19 --- /dev/null +++ b/include/cereal/external/ctti/tie.hpp @@ -0,0 +1,70 @@ +#ifndef CTTI_TIE_HPP +#define CTTI_TIE_HPP + +#include +#include +#include + +namespace ctti +{ + +namespace detail +{ + +template +struct tie_t; + +template +struct tie_t, ctti::meta::list> +{ + constexpr tie_t(Refs&... refs) : + _refs{refs...} + {} + + template + void operator=(const T& object) + { + assign(object, ctti::meta::make_index_sequence_for()); + } + +private: + template + using Symbol = ctti::meta::pack_get_t; + + + template::template is_member_of() + >::type> + void assign_member(const T& object) + { + std::get(_refs) = ctti::get_member_value>(object); + } + + template::template is_member_of() + >::type> + void assign_member(const T& object) + {} + + template + void assign(const T& object, ctti::meta::index_sequence) + { + [](...){}((tie_t::assign_member(object), 42)...); + } + + std::tuple _refs; +}; + +} + +template +constexpr ctti::detail::tie_t< + ctti::meta::list, ctti::meta::list +> tie(Refs&... refs) +{ + return {refs...}; +} + +} + +#endif // CTTI_TIE_HPP diff --git a/include/cereal/external/ctti/type_id.hpp b/include/cereal/external/ctti/type_id.hpp new file mode 100644 index 00000000..ec58dc87 --- /dev/null +++ b/include/cereal/external/ctti/type_id.hpp @@ -0,0 +1,201 @@ +// +// Created by manu343726 on 4/08/15. +// + +#ifndef CTTI_HASH_HPP +#define CTTI_HASH_HPP + +#include +#include "detail/hash.hpp" +#include "detail/cstring.hpp" +#include "nameof.hpp" + +#ifdef CTTI_DEBUG_ID_FUNCTIONS +#include +#include + +#ifndef CTTI_CONSTEXPR_ID +#define CTTI_CONSTEXPR_ID +#endif +#else +#ifndef CTTI_CONSTEXPR_ID +#define CTTI_CONSTEXPR_ID constexpr +#endif +#endif +namespace ctti +{ + struct type_id_t + { + constexpr type_id_t(const detail::cstring& name) : + name_{name} + {} + + constexpr type_id_t() : + type_id_t{"void"} + {} + + type_id_t& operator=(const type_id_t&) = default; + + constexpr detail::hash_t hash() const + { + return name_.hash(); + } + + constexpr const detail::cstring& name() const + { + return name_; + } + + friend constexpr bool operator==(const type_id_t& lhs, const type_id_t& rhs) + { + return lhs.hash() == rhs.hash(); + } + + friend constexpr bool operator!=(const type_id_t& lhs, const type_id_t& rhs) + { + return !(lhs == rhs); + } + + private: + detail::cstring name_; + }; + + struct unnamed_type_id_t + { + constexpr unnamed_type_id_t(const detail::hash_t hash) : + _hash{hash} + {} + + constexpr unnamed_type_id_t(const type_id_t& id) : + _hash{id.hash()} + {} + + unnamed_type_id_t& operator=(const unnamed_type_id_t&) = default; + + constexpr detail::hash_t hash() const + { + return _hash; + } + + friend constexpr bool operator==(const unnamed_type_id_t& lhs, const unnamed_type_id_t& rhs) + { + return lhs.hash() == rhs.hash(); + } + + friend constexpr bool operator!=(const unnamed_type_id_t& lhs, const unnamed_type_id_t& rhs) + { + return !(lhs == rhs); + } + + private: + detail::hash_t _hash; + }; + + using type_index = unnamed_type_id_t; // To mimic std::type_index when using maps + + + template + constexpr ctti::unnamed_type_id_t id_from_name(const char (&typeName)[N]) + { + return detail::fnv1a_hash(typeName); + } + + constexpr ctti::unnamed_type_id_t id_from_name(const char* typeName, std::size_t length) + { + return detail::fnv1a_hash(length, typeName); + } + + constexpr ctti::unnamed_type_id_t id_from_name(const ctti::detail::cstring& name) + { + return detail::fnv1a_hash(name.size(), name.begin()); + } + + // Inline to prevent ODR violation + inline ctti::unnamed_type_id_t id_from_name(const std::string& typeName) + { + return detail::fnv1a_hash(typeName.size(), typeName.data()); + } + + namespace detail + { + template + CTTI_CONSTEXPR_ID ctti::type_id_t type_id() + { + return { ctti::nameof() }; + } + + template + CTTI_CONSTEXPR_ID ctti::unnamed_type_id_t unnamed_type_id() + { + return { id_from_name(ctti::nameof()) }; + } + } + + /** + * Returns type information at compile-time for a value + * of type T. Decay is applied to argument type first, use + * ctti::type_id() to preserve references and cv qualifiers. + */ + template + constexpr type_id_t type_id(T&&) + { + return detail::type_id::type>(); + } + + /** + * Returns type information at compile-time for type T. + */ + template + constexpr type_id_t type_id() + { + return detail::type_id(); + } + + /** + * Returns unnamed type information at compile-time for a value + * of type T. Decay is applied to argument type first, use + * ctti::type_id() to preserve references and cv qualifiers. + */ + template + constexpr unnamed_type_id_t unnamed_type_id(T&&) + { + return detail::unnamed_type_id::type>(); + } + + /** + * Returns unnamed type information at compile-time for type T. + */ + template + constexpr unnamed_type_id_t unnamed_type_id() + { + return detail::unnamed_type_id(); + } + + //assert commented out, GCC 5.2.0 ICE here. + //static_assert(type_id() == type_id(), "ctti::type_id_t instances must be constant expressions"); +} + +namespace std +{ + template<> + struct hash + { + constexpr std::size_t operator()(const ctti::type_id_t& id) const + { + // quiet warning about possible loss of data + return std::size_t(id.hash()); + } + }; + + template<> + struct hash + { + constexpr std::size_t operator()(const ctti::unnamed_type_id_t& id) const + { + // quiet warning about possible loss of data + return std::size_t(id.hash()); + } + }; +} + +#endif //CTTI_HASH_HPP diff --git a/include/cereal/external/ctti/type_tag.hpp b/include/cereal/external/ctti/type_tag.hpp new file mode 100644 index 00000000..d98bd21e --- /dev/null +++ b/include/cereal/external/ctti/type_tag.hpp @@ -0,0 +1,16 @@ +#ifndef CTTI_TYPE_TAG_HPP +#define CTTI_TYPE_TAG_HPP + +namespace ctti +{ + +template +struct type_tag +{ + constexpr type_tag() = default; + using type = T; +}; + +} + +#endif // CTTI_TYPE_TAG_HPP