| 1 | /* |
| 2 | Copyright (c) 2005-2021 Intel Corporation |
| 3 | |
| 4 | Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | you may not use this file except in compliance with the License. |
| 6 | You may obtain a copy of the License at |
| 7 | |
| 8 | http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | |
| 10 | Unless required by applicable law or agreed to in writing, software |
| 11 | distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | See the License for the specific language governing permissions and |
| 14 | limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | #ifndef __TBB_detail__range_common_H |
| 18 | #define __TBB_detail__range_common_H |
| 19 | |
| 20 | #include "_config.h" |
| 21 | #include "_utils.h" |
| 22 | #if __TBB_CPP20_CONCEPTS_PRESENT |
| 23 | #include <concepts> |
| 24 | #include <iterator> |
| 25 | #endif |
| 26 | |
| 27 | namespace tbb { |
| 28 | namespace detail { |
| 29 | inline namespace d0 { |
| 30 | |
| 31 | //! Dummy type that distinguishes splitting constructor from copy constructor. |
| 32 | /** |
| 33 | * See description of parallel_for and parallel_reduce for example usages. |
| 34 | * @ingroup algorithms |
| 35 | */ |
| 36 | class split {}; |
| 37 | |
| 38 | //! Type enables transmission of splitting proportion from partitioners to range objects |
| 39 | /** |
| 40 | * In order to make use of such facility Range objects must implement |
| 41 | * splitting constructor with this type passed. |
| 42 | */ |
| 43 | class proportional_split : no_assign { |
| 44 | public: |
| 45 | proportional_split(size_t _left = 1, size_t _right = 1) : my_left(_left), my_right(_right) { } |
| 46 | |
| 47 | size_t left() const { return my_left; } |
| 48 | size_t right() const { return my_right; } |
| 49 | |
| 50 | // used when range does not support proportional split |
| 51 | explicit operator split() const { return split(); } |
| 52 | |
| 53 | private: |
| 54 | size_t my_left, my_right; |
| 55 | }; |
| 56 | |
| 57 | template <typename Range, typename = void> |
| 58 | struct range_split_object_provider { |
| 59 | template <typename PartitionerSplitType> |
| 60 | static split get( PartitionerSplitType& ) { return split(); } |
| 61 | }; |
| 62 | |
| 63 | template <typename Range> |
| 64 | struct range_split_object_provider<Range, |
| 65 | typename std::enable_if<std::is_constructible<Range, Range&, proportional_split&>::value>::type> { |
| 66 | template <typename PartitionerSplitType> |
| 67 | static PartitionerSplitType& get( PartitionerSplitType& split_obj ) { return split_obj; } |
| 68 | }; |
| 69 | |
| 70 | template <typename Range, typename PartitionerSplitType> |
| 71 | auto get_range_split_object( PartitionerSplitType& split_obj ) |
| 72 | -> decltype(range_split_object_provider<Range>::get(split_obj)) { |
| 73 | return range_split_object_provider<Range>::get(split_obj); |
| 74 | } |
| 75 | |
| 76 | #if __TBB_CPP20_CONCEPTS_PRESENT |
| 77 | template <typename Range> |
| 78 | using range_iterator_type = decltype(std::begin(std::declval<Range&>())); |
| 79 | |
| 80 | template <typename Iterator> |
| 81 | using iterator_reference_type = typename std::iterator_traits<Iterator>::reference; |
| 82 | |
| 83 | template <typename Range> |
| 84 | using range_reference_type = iterator_reference_type<range_iterator_type<Range>>; |
| 85 | |
| 86 | template <typename Value> |
| 87 | concept blocked_range_value = std::copyable<Value> && |
| 88 | requires( const std::remove_reference_t<Value>& lhs, const std::remove_reference_t<Value>& rhs ) { |
| 89 | { lhs < rhs } -> relaxed_convertible_to<bool>; |
| 90 | { lhs - rhs } -> std::convertible_to<std::size_t>; |
| 91 | { lhs + (rhs - lhs) } -> std::convertible_to<Value>; |
| 92 | }; |
| 93 | |
| 94 | template <typename T> |
| 95 | concept splittable = std::constructible_from<T, T&, tbb::detail::split>; |
| 96 | |
| 97 | template <typename Range> |
| 98 | concept tbb_range = std::copy_constructible<Range> && |
| 99 | splittable<Range> && |
| 100 | requires( const std::remove_reference_t<Range>& range ) { |
| 101 | { range.empty() } -> relaxed_convertible_to<bool>; |
| 102 | { range.is_divisible() } -> relaxed_convertible_to<bool>; |
| 103 | }; |
| 104 | |
| 105 | template <typename Iterator> |
| 106 | constexpr bool iterator_concept_helper( std::input_iterator_tag ) { |
| 107 | return std::input_iterator<Iterator>; |
| 108 | } |
| 109 | |
| 110 | template <typename Iterator> |
| 111 | constexpr bool iterator_concept_helper( std::random_access_iterator_tag ) { |
| 112 | return std::random_access_iterator<Iterator>; |
| 113 | } |
| 114 | |
| 115 | template <typename Iterator, typename IteratorTag> |
| 116 | concept iterator_satisfies = requires (IteratorTag tag) { |
| 117 | requires iterator_concept_helper<Iterator>(tag); |
| 118 | }; |
| 119 | |
| 120 | template <typename Sequence, typename IteratorTag> |
| 121 | concept container_based_sequence = requires( Sequence& seq ) { |
| 122 | { std::begin(seq) } -> iterator_satisfies<IteratorTag>; |
| 123 | { std::end(seq) } -> iterator_satisfies<IteratorTag>; |
| 124 | }; |
| 125 | #endif // __TBB_CPP20_CONCEPTS_PRESENT |
| 126 | } // namespace d0 |
| 127 | } // namespace detail |
| 128 | } // namespace tbb |
| 129 | |
| 130 | #endif // __TBB_detail__range_common_H |
| 131 | |