diff --git a/include/burst/iterator/detail/uniform_range_tuple_please.hpp b/include/burst/iterator/detail/uniform_range_tuple_please.hpp new file mode 100644 index 00000000..89e00d31 --- /dev/null +++ b/include/burst/iterator/detail/uniform_range_tuple_please.hpp @@ -0,0 +1,63 @@ +#ifndef BURST_ITERATOR_DETAIL_MERGE_ITERATOR_HPP +#define BURST_ITERATOR_DETAIL_MERGE_ITERATOR_HPP + +#include +#include +#include + +#include + +#include +#include + +namespace burst +{ + namespace detail + { + /*! + \brief + Перегрузка для случая, когда все переданные диапазоны имеют один и тот же тип + + \see merge_iterator + */ + template + auto uniform_range_tuple_please_impl (std::tuple ranges, std::true_type) + { + static_assert(are_same_v, ""); + return ranges; + } + + /*! + \brief + Перегрузка для случая, когда переданные диапазоны разнотипны + + \see merge_iterator + */ + template + auto uniform_range_tuple_please_impl (std::tuple ranges, std::false_type) + { + static_assert(not are_same_v, ""); + return by_all(to_any_range, ranges); + } + + /*! + \brief + Сделать из кортежа возможно разнотипных диапазонов кортеж заведомо однотипных + диапазонов + + \returns + Если диапазоны изначально однотипны, то возвращается изначальный кортеж, в + противном случае создаётся кортеж, в котором каждый из диапазонов приведён к + boost::any_range. + + \see merge_iterator + */ + template + auto uniform_range_tuple_please (std::tuple ranges) + { + return uniform_range_tuple_please_impl(ranges, are_same{}); + } + } +} + +#endif // BURST_ITERATOR_DETAIL_MERGE_ITERATOR_HPP diff --git a/include/burst/iterator/merge_iterator.hpp b/include/burst/iterator/merge_iterator.hpp index 574c7878..c7b58471 100644 --- a/include/burst/iterator/merge_iterator.hpp +++ b/include/burst/iterator/merge_iterator.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -21,6 +22,7 @@ #include #include #include +#include #include namespace burst @@ -206,10 +208,11 @@ namespace burst template auto make_merge_iterator (std::tuple ranges, Compare compare) { + auto common_ranges = detail::uniform_range_tuple_please(ranges); return make_merge_iterator ( - burst::own_as_range(burst::apply(burst::make_range_vector, ranges)), + burst::own_as_range(burst::apply(burst::make_range_vector, common_ranges)), std::move(compare) ); } @@ -252,11 +255,8 @@ namespace burst template auto make_merge_iterator (std::tuple ranges) { - return - make_merge_iterator - ( - burst::own_as_range(burst::apply(burst::make_range_vector, ranges)) - ); + auto common_ranges = detail::uniform_range_tuple_please(ranges); + return make_merge_iterator(own_as_range(burst::apply(make_range_vector, common_ranges))); } //! Функция для создания итератора на конец слияния с предикатом. diff --git a/include/burst/range/to_any_range.hpp b/include/burst/range/to_any_range.hpp new file mode 100644 index 00000000..38e11e8c --- /dev/null +++ b/include/burst/range/to_any_range.hpp @@ -0,0 +1,27 @@ +#ifndef BURST_RANGE_TO_ANY_RANGE_HPP +#define BURST_RANGE_TO_ANY_RANGE_HPP + +#include +#include + +#include + +namespace burst +{ + template + struct to_any_range_t + { + template + constexpr auto operator () (Range && range) const + { + using value_type = range_value_t; + using reference_type = range_reference_t; + return boost::any_range(range); + } + }; + + template + constexpr auto to_any_range = to_any_range_t{}; +} // namespace burst + +#endif // BURST_RANGE_TO_ANY_RANGE_HPP diff --git a/include/burst/type_traits/are_same.hpp b/include/burst/type_traits/are_same.hpp new file mode 100644 index 00000000..2b45dccd --- /dev/null +++ b/include/burst/type_traits/are_same.hpp @@ -0,0 +1,17 @@ +#ifndef BURST_TYPE_TRAITS_ARE_SAME_HPP +#define BURST_TYPE_TRAITS_ARE_SAME_HPP + +#include + +#include + +namespace burst +{ + template + struct are_same: std::is_same, type_list> {}; + + template + constexpr const auto are_same_v = are_same::value; +} // namespace burst + +#endif // BURST_TYPE_TRAITS_ARE_SAME_HPP diff --git a/include/burst/type_traits/type_list.hpp b/include/burst/type_traits/type_list.hpp new file mode 100644 index 00000000..b961b223 --- /dev/null +++ b/include/burst/type_traits/type_list.hpp @@ -0,0 +1,10 @@ +#ifndef BURST_TYPE_TRAITS_TYPE_LIST_HPP +#define BURST_TYPE_TRAITS_TYPE_LIST_HPP + +namespace burst +{ + template + struct type_list {}; +} // namespace burst + +#endif // BURST_TYPE_TRAITS_TYPE_LIST_HPP diff --git a/test/burst/range/merge.cpp b/test/burst/range/merge.cpp index a34d187d..43fe1089 100644 --- a/test/burst/range/merge.cpp +++ b/test/burst/range/merge.cpp @@ -1,3 +1,4 @@ +#include #include #include #include @@ -83,4 +84,28 @@ TEST_SUITE("merge") auto expected_collection = {0, 1, 2, 3, 4, 5, 6, 7, 8}; CHECK(merged_range == expected_collection); } + + TEST_CASE("Можно сливать диапазоны разных типов") + { + auto one = burst::make_vector({0, 3, 6, 9}); + auto two = burst::make_list({1, 4, 7, 10}); + auto three = burst::make_deque({2, 5, 8, 11}); + + auto merged_range = burst::merge(std::tie(one, two, three)); + + auto expected_collection = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}; + CHECK(merged_range == expected_collection); + } + + TEST_CASE("Можно сливать с предикатом диапазоны разных типов") + { + auto one = burst::make_vector({9, 6, 3, 0}); + auto two = burst::make_list({10, 7, 4, 1}); + auto three = burst::make_deque({11, 8, 5, 2}); + + auto merged_range = burst::merge(std::tie(one, two, three), std::greater<>{}); + + auto expected_collection = {11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}; + CHECK(merged_range == expected_collection); + } }