1 | /* |
2 | Copyright (c) 2017-2019 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_blocked_rangeNd_H |
18 | #define __TBB_blocked_rangeNd_H |
19 | |
20 | #if ! TBB_PREVIEW_BLOCKED_RANGE_ND |
21 | #error Set TBB_PREVIEW_BLOCKED_RANGE_ND to include blocked_rangeNd.h |
22 | #endif |
23 | |
24 | #include "tbb_config.h" |
25 | |
26 | // tbb::blocked_rangeNd requires C++11 support |
27 | #if __TBB_CPP11_PRESENT && __TBB_CPP11_ARRAY_PRESENT && __TBB_CPP11_TEMPLATE_ALIASES_PRESENT |
28 | |
29 | #include "internal/_template_helpers.h" // index_sequence, make_index_sequence |
30 | |
31 | #include <array> |
32 | #include <algorithm> // std::any_of |
33 | #include <type_traits> // std::is_same, std::enable_if |
34 | |
35 | #include "tbb/blocked_range.h" |
36 | |
37 | namespace tbb { |
38 | namespace internal { |
39 | |
40 | /* |
41 | The blocked_rangeNd_impl uses make_index_sequence<N> to automatically generate a ctor with |
42 | exactly N arguments of the type tbb::blocked_range<Value>. Such ctor provides an opportunity |
43 | to use braced-init-list parameters to initialize each dimension. |
44 | Use of parameters, whose representation is a braced-init-list, but they're not |
45 | std::initializer_list or a reference to one, produces a non-deduced context |
46 | within template argument deduction. |
47 | |
48 | NOTE: blocked_rangeNd must be exactly a templated alias to the blocked_rangeNd_impl |
49 | (and not e.g. a derived class), otherwise it would need to declare its own ctor |
50 | facing the same problem that the impl class solves. |
51 | */ |
52 | |
53 | template<typename Value, unsigned int N, typename = make_index_sequence<N>> |
54 | class blocked_rangeNd_impl; |
55 | |
56 | template<typename Value, unsigned int N, std::size_t... Is> |
57 | class blocked_rangeNd_impl<Value, N, index_sequence<Is...>> { |
58 | public: |
59 | //! Type of a value. |
60 | using value_type = Value; |
61 | |
62 | private: |
63 | |
64 | //! Helper type to construct range with N tbb::blocked_range<value_type> objects. |
65 | template<std::size_t> |
66 | using dim_type_helper = tbb::blocked_range<value_type>; |
67 | |
68 | public: |
69 | blocked_rangeNd_impl() = delete; |
70 | |
71 | //! Constructs N-dimensional range over N half-open intervals each represented as tbb::blocked_range<Value>. |
72 | blocked_rangeNd_impl(const dim_type_helper<Is>&... args) : my_dims{ {args...} } {} |
73 | |
74 | //! Dimensionality of a range. |
75 | static constexpr unsigned int ndims() { return N; } |
76 | |
77 | //! Range in certain dimension. |
78 | const tbb::blocked_range<value_type>& dim(unsigned int dimension) const { |
79 | __TBB_ASSERT(dimension < N, "out of bound" ); |
80 | return my_dims[dimension]; |
81 | } |
82 | |
83 | //------------------------------------------------------------------------ |
84 | // Methods that implement Range concept |
85 | //------------------------------------------------------------------------ |
86 | |
87 | //! True if at least one dimension is empty. |
88 | bool empty() const { |
89 | return std::any_of(my_dims.begin(), my_dims.end(), [](const tbb::blocked_range<value_type>& d) { |
90 | return d.empty(); |
91 | }); |
92 | } |
93 | |
94 | //! True if at least one dimension is divisible. |
95 | bool is_divisible() const { |
96 | return std::any_of(my_dims.begin(), my_dims.end(), [](const tbb::blocked_range<value_type>& d) { |
97 | return d.is_divisible(); |
98 | }); |
99 | } |
100 | |
101 | #if __TBB_USE_PROPORTIONAL_SPLIT_IN_BLOCKED_RANGES |
102 | //! Static field to support proportional split. |
103 | static const bool is_splittable_in_proportion = true; |
104 | |
105 | blocked_rangeNd_impl(blocked_rangeNd_impl& r, proportional_split proportion) : my_dims(r.my_dims) { |
106 | do_split(r, proportion); |
107 | } |
108 | #endif |
109 | |
110 | blocked_rangeNd_impl(blocked_rangeNd_impl& r, split proportion) : my_dims(r.my_dims) { |
111 | do_split(r, proportion); |
112 | } |
113 | |
114 | private: |
115 | __TBB_STATIC_ASSERT(N != 0, "zero dimensional blocked_rangeNd can't be constructed" ); |
116 | |
117 | //! Ranges in each dimension. |
118 | std::array<tbb::blocked_range<value_type>, N> my_dims; |
119 | |
120 | template<typename split_type> |
121 | void do_split(blocked_rangeNd_impl& r, split_type proportion) { |
122 | __TBB_STATIC_ASSERT((is_same_type<split_type, split>::value |
123 | || is_same_type<split_type, proportional_split>::value), |
124 | "type of split object is incorrect" ); |
125 | __TBB_ASSERT(r.is_divisible(), "can't split not divisible range" ); |
126 | |
127 | auto my_it = std::max_element(my_dims.begin(), my_dims.end(), [](const tbb::blocked_range<value_type>& first, const tbb::blocked_range<value_type>& second) { |
128 | return (first.size() * second.grainsize() < second.size() * first.grainsize()); |
129 | }); |
130 | |
131 | auto r_it = r.my_dims.begin() + (my_it - my_dims.begin()); |
132 | |
133 | my_it->my_begin = tbb::blocked_range<value_type>::do_split(*r_it, proportion); |
134 | |
135 | // (!(my_it->my_begin < r_it->my_end) && !(r_it->my_end < my_it->my_begin)) equals to |
136 | // (my_it->my_begin == r_it->my_end), but we can't use operator== due to Value concept |
137 | __TBB_ASSERT(!(my_it->my_begin < r_it->my_end) && !(r_it->my_end < my_it->my_begin), |
138 | "blocked_range has been split incorrectly" ); |
139 | } |
140 | }; |
141 | |
142 | } // namespace internal |
143 | |
144 | template<typename Value, unsigned int N> |
145 | using blocked_rangeNd = internal::blocked_rangeNd_impl<Value, N>; |
146 | |
147 | } // namespace tbb |
148 | |
149 | #endif /* __TBB_CPP11_PRESENT && __TBB_CPP11_ARRAY_PRESENT && __TBB_CPP11_TEMPLATE_ALIASES_PRESENT */ |
150 | #endif /* __TBB_blocked_rangeNd_H */ |
151 | |