#pragma once // // This file is distributed under the MIT License. See LICENSE.md for details. // #include #include "llvm/Support/YAMLTraits.h" #include "revng/ADT/KeyedObjectTraits.h" #include "revng/ADT/STLExtras.h" #include "revng/Support/Assert.h" template using KOTKey = decltype(KeyedObjectTraits::key(std::declval())); template using KOTCompare = std::less>; template> class MutableSet; template> class SortedVector; // // is_KeyedObjectContainer // namespace detail { template using no_cv_t = std::remove_cv_t; template class Ref> constexpr bool is_no_cv_specialization_v = is_specialization_v, Ref>; template constexpr bool is_mutableset_v = is_no_cv_specialization_v; template constexpr bool is_sortedvector_v = is_no_cv_specialization_v; template constexpr bool is_KOC_v = is_mutableset_v or is_sortedvector_v; template using enable_if_is_KOC_t = std::enable_if_t, K>; } // namespace detail template constexpr bool is_KeyedObjectContainer_v = detail::is_KOC_v; template using enable_if_is_KeyedObjectContainer_t = detail::enable_if_is_KOC_t; static_assert(is_KeyedObjectContainer_v>); static_assert(is_KeyedObjectContainer_v>); template struct llvm::yaml::SequenceTraits> { static size_t size(IO &io, T &Seq) { return Seq.size(); } class Inserter { private: using value_type = typename T::value_type; using KOT = KeyedObjectTraits; using key_type = decltype(KOT::key(std::declval())); private: T &Seq; decltype(Seq.begin()) It; bool IsOutputting; std::optional BatchInserter; value_type Instance; unsigned Index = 0; public: Inserter(IO &io, T &Seq) : Seq(Seq), It(Seq.begin()), IsOutputting(io.outputting()), Instance(KOT::fromKey(key_type())) { if constexpr (std::is_const_v) { revng_assert(IsOutputting); } else { if (not IsOutputting) BatchInserter.emplace(std::move(Seq.batch_insert())); } } decltype(*It) &preflightElement(unsigned I) { revng_assert(Index == I); ++Index; if (IsOutputting) return *(It++); else return Instance; } void postflightElement(unsigned) { if (not IsOutputting) { BatchInserter->insert(Instance); Instance = KOT::fromKey(key_type()); } }; }; }; // // has_tuple_size // template struct has_tuple_size : std::false_type {}; template struct has_tuple_size{})>> : std::true_type {}; template constexpr bool has_tuple_size_v = has_tuple_size::value; static_assert(has_tuple_size_v>); static_assert(!has_tuple_size_v>); static_assert(!has_tuple_size_v); template using enable_if_tuple_end_t = std::enable_if_t, K>; template using enable_if_not_tuple_end_t = std::enable_if_t, K>; template using enable_if_has_tuple_size_t = std::enable_if_t, R>; // // is_iterable // namespace tupletree::detail { using std::begin; using std::end; // Require the following: // * begin/end // * operator!= // * operator++ // * operator* template decltype(begin(std::declval()) != end(std::declval()), ++std::declval())) &>(), void(*begin(std::declval())), std::true_type{}) is_iterable_impl(int); template std::false_type is_iterable_impl(...); } // namespace tupletree::detail template using is_iterable = decltype(tupletree::detail::is_iterable_impl(0)); template constexpr bool is_iterable_v = is_iterable::value; static_assert(is_iterable_v>); static_assert(!is_iterable_v); // // is_string_like // namespace tupletree::detail { template typename std::is_same().c_str()), const char *>::type has_c_str(int); template std::false_type has_c_str(...); } // namespace tupletree::detail template using has_c_str = typename decltype(tupletree::detail::has_c_str(0))::type; template constexpr bool has_c_str_v = has_c_str::value; static_assert(has_c_str_v>); static_assert(!has_c_str_v); template constexpr bool is_string_like_v = (std::is_convertible_v or has_c_str_v); static_assert(is_string_like_v>); static_assert(is_string_like_v); static_assert(not is_string_like_v>); static_assert(is_string_like_v); // // is_container // template constexpr bool is_container_v = is_iterable_v and not is_string_like_v; namespace detail { template constexpr bool is_cot_v = is_container_v or has_tuple_size_v; } // namespace detail template constexpr bool is_container_or_tuple_v = detail::is_cot_v; namespace detail { template using ei_not_cot_t = std::enable_if_t, K>; } // namespace detail template using enable_if_is_not_container_or_tuple_t = detail::ei_not_cot_t; static_assert(is_container_v>); static_assert(is_container_v>); static_assert(is_container_v>); static_assert(is_container_v>); static_assert(!is_container_v); static_assert(!is_container_v>); static_assert(!is_container_v); template using enable_if_is_container_t = std::enable_if_t, K>; template using enable_if_is_not_container_t = std::enable_if_t, K>; // // is_sorted_container // // TODO: this is not very nice namespace detail { template constexpr bool is_set_v = is_specialization_v; template constexpr bool is_sc_v = is_set_v or is_KeyedObjectContainer_v; } // namespace detail template constexpr bool is_sorted_container_v = detail::is_sc_v; namespace detail { template constexpr bool is_uc_v = is_container_v and not is_sorted_container_v; } template constexpr bool is_unsorted_container_v = detail::is_uc_v; namespace detail { template using ei_isc_t = std::enable_if_t, K>; template using ei_iuc_t = std::enable_if_t, K>; } // namespace detail template using enable_if_is_sorted_container_t = detail::ei_isc_t; template using enable_if_is_unsorted_container_t = detail::ei_iuc_t;