Vc  1.3.3-dev
SIMD Vector Classes for C++
algorithms.h
1 /* This file is part of the Vc library. {{{
2 Copyright © 2013-2015 Matthias Kretz <kretz@kde.org>
3 
4 Redistribution and use in source and binary forms, with or without
5 modification, are permitted provided that the following conditions are met:
6  * Redistributions of source code must retain the above copyright
7  notice, this list of conditions and the following disclaimer.
8  * Redistributions in binary form must reproduce the above copyright
9  notice, this list of conditions and the following disclaimer in the
10  documentation and/or other materials provided with the distribution.
11  * Neither the names of contributing organizations nor the
12  names of its contributors may be used to endorse or promote products
13  derived from this software without specific prior written permission.
14 
15 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
19 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 
26 }}}*/
27 
28 #ifndef VC_COMMON_ALGORITHMS_H_
29 #define VC_COMMON_ALGORITHMS_H_
30 
31 #include "macros.h"
32 
33 namespace Vc_VERSIONED_NAMESPACE
34 {
44 template<typename Mask> constexpr bool all_of(const Mask &m) { return m.isFull(); }
48 constexpr bool all_of(bool b) { return b; }
49 
53 template<typename Mask> constexpr bool any_of(const Mask &m) { return m.isNotEmpty(); }
57 constexpr bool any_of(bool b) { return b; }
58 
62 template<typename Mask> constexpr bool none_of(const Mask &m) { return m.isEmpty(); }
66 constexpr bool none_of(bool b) { return !b; }
67 
72 template<typename Mask> constexpr bool some_of(const Mask &m) { return m.isMix(); }
76 constexpr bool some_of(bool) { return false; }
78 
79 #ifdef DOXYGEN
80 
107 template <class InputIt, class UnaryFunction>
108 UnaryFunction simd_for_each(InputIt first, InputIt last, UnaryFunction f);
109 #else
110 template <class InputIt, class UnaryFunction,
111  class ValueType = typename std::iterator_traits<InputIt>::value_type>
112 inline enable_if<
113  std::is_arithmetic<ValueType>::value &&
114  Traits::is_functor_argument_immutable<UnaryFunction, Vector<ValueType>>::value,
115  UnaryFunction>
116 simd_for_each(InputIt first, InputIt last, UnaryFunction f)
117 {
118  typedef Vector<ValueType> V;
119  typedef Scalar::Vector<ValueType> V1;
120  for (; reinterpret_cast<std::uintptr_t>(std::addressof(*first)) &
121  (V::MemoryAlignment - 1) &&
122  first != last;
123  ++first) {
124  f(V1(std::addressof(*first), Vc::Aligned));
125  }
126  const auto lastV = last - V::Size + 1;
127  for (; first < lastV; first += V::Size) {
128  f(V(std::addressof(*first), Vc::Aligned));
129  }
130  for (; first != last; ++first) {
131  f(V1(std::addressof(*first), Vc::Aligned));
132  }
133  return std::move(f);
134 }
135 
136 template <typename InputIt, typename UnaryFunction>
137 inline enable_if<
138  std::is_arithmetic<typename std::iterator_traits<InputIt>::value_type>::value &&
139  !Traits::is_functor_argument_immutable<
140  UnaryFunction,
142  UnaryFunction>
143 simd_for_each(InputIt first, InputIt last, UnaryFunction f)
144 {
146  typedef Scalar::Vector<typename std::iterator_traits<InputIt>::value_type> V1;
147  for (; reinterpret_cast<std::uintptr_t>(std::addressof(*first)) &
148  (V::MemoryAlignment - 1) &&
149  first != last;
150  ++first) {
151  V1 tmp(std::addressof(*first), Vc::Aligned);
152  f(tmp);
153  tmp.store(std::addressof(*first), Vc::Aligned);
154  }
155  const auto lastV = last - V::Size + 1;
156  for (; first < lastV; first += V::Size) {
157  V tmp(std::addressof(*first), Vc::Aligned);
158  f(tmp);
159  tmp.store(std::addressof(*first), Vc::Aligned);
160  }
161  for (; first != last; ++first) {
162  V1 tmp(std::addressof(*first), Vc::Aligned);
163  f(tmp);
164  tmp.store(std::addressof(*first), Vc::Aligned);
165  }
166  return std::move(f);
167 }
168 #endif
169 
170 template <typename InputIt, typename UnaryFunction>
171 inline enable_if<
172  !std::is_arithmetic<typename std::iterator_traits<InputIt>::value_type>::value,
173  UnaryFunction>
174 simd_for_each(InputIt first, InputIt last, UnaryFunction f)
175 {
176  return std::for_each(first, last, std::move(f));
177 }
178 
180 template <typename InputIt, typename UnaryFunction>
181 inline enable_if<
182  std::is_arithmetic<typename std::iterator_traits<InputIt>::value_type>::value &&
183  Traits::is_functor_argument_immutable<
184  UnaryFunction,
186  UnaryFunction>
187 simd_for_each_n(InputIt first, std::size_t count, UnaryFunction f)
188 {
189  typename std::make_signed<size_t>::type len = count;
191  typedef Scalar::Vector<typename std::iterator_traits<InputIt>::value_type> V1;
192  for (; reinterpret_cast<std::uintptr_t>(std::addressof(*first)) &
193  (V::MemoryAlignment - 1) &&
194  len != 0;
195  --len, ++first) {
196  f(V1(std::addressof(*first), Vc::Aligned));
197  }
198  for (; len >= int(V::Size); len -= V::Size, first += V::Size) {
199  f(V(std::addressof(*first), Vc::Aligned));
200  }
201  for (; len != 0; --len, ++first) {
202  f(V1(std::addressof(*first), Vc::Aligned));
203  }
204  return std::move(f);
205 }
206 
207 template <typename InputIt, typename UnaryFunction>
208 inline enable_if<
209  std::is_arithmetic<typename std::iterator_traits<InputIt>::value_type>::value &&
210  !Traits::is_functor_argument_immutable<
211  UnaryFunction,
213  UnaryFunction>
214 simd_for_each_n(InputIt first, std::size_t count, UnaryFunction f)
215 {
216  typename std::make_signed<size_t>::type len = count;
218  typedef Scalar::Vector<typename std::iterator_traits<InputIt>::value_type> V1;
219  for (; reinterpret_cast<std::uintptr_t>(std::addressof(*first)) &
220  (V::MemoryAlignment - 1) &&
221  len != 0;
222  --len, ++first) {
223  V1 tmp(std::addressof(*first), Vc::Aligned);
224  f(tmp);
225  tmp.store(std::addressof(*first), Vc::Aligned);
226  }
227  for (; len >= int(V::Size); len -= V::Size, first += V::Size) {
228  V tmp(std::addressof(*first), Vc::Aligned);
229  f(tmp);
230  tmp.store(std::addressof(*first), Vc::Aligned);
231  }
232  for (; len != 0; --len, ++first) {
233  V1 tmp(std::addressof(*first), Vc::Aligned);
234  f(tmp);
235  tmp.store(std::addressof(*first), Vc::Aligned);
236  }
237  return std::move(f);
238 }
239 
240 #ifdef Vc_CXX17
241 #ifdef Vc_GCC
242 // GCC specific workaround because stdlibc++ doesn't have
243 // std::for_each_n implemented yet.
244 template <typename InputIt, typename UnaryFunction>
245 inline enable_if<!std::is_arithmetic<typename InputIt::value_type>::value, UnaryFunction>
246 simd_for_each_n(InputIt first, std::size_t count, UnaryFunction f)
247 {
248  for (std::size_t i = 0; i < count; ++i, static_cast<void>(++first))
249  std::apply(f, *first);
250  return first;
251 }
252 #else
253 template <typename InputIt, typename UnaryFunction>
254 inline enable_if<
255  !std::is_arithmetic<typename std::iterator_traits<InputIt>::value_type>::value,
256  UnaryFunction>
257 simd_for_each_n(InputIt first, std::size_t count, UnaryFunction f)
258 {
259  return std::for_each_n(first, count, std::move(f));
260 }
261 #endif
262 #endif
263 
264 } // namespace Vc
265 
266 #endif // VC_COMMON_ALGORITHMS_H_
The main vector class for expressing data parallelism.
Definition: types.h:44
constexpr bool any_of(bool b)
Returns b.
Definition: algorithms.h:57
enable_if< !std::is_arithmetic< typename std::iterator_traits< InputIt >::value_type >::value, UnaryFunction > simd_for_each(InputIt first, InputIt last, UnaryFunction f)
Vc variant of the std::for_each algorithm.
Definition: algorithms.h:174
bool isFull() const
Returns a logical AND of all components.
constexpr bool none_of(bool b)
Returns !b.
Definition: algorithms.h:66
constexpr bool all_of(bool b)
Returns b.
Definition: algorithms.h:48
constexpr AlignedTag Aligned
Use this object for a flags parameter to request aligned loads and stores.
constexpr bool some_of(bool)
Returns false.
Definition: algorithms.h:76
The main SIMD mask class.
Definition: mask.h:41
bool isNotEmpty() const
Returns a logical OR of all components.
constexpr std::size_t MemoryAlignment
Specifies the most conservative memory alignment necessary for aligned loads and stores of Vector typ...
Definition: vector.h:218
bool isEmpty() const
Returns true if components are false, false otherwise.
bool isMix() const
Returns !isFull() && !isEmpty().