Vc  1.4.0
SIMD Vector Classes for C++
gatherinterface.h
1 /* This file is part of the Vc library. {{{
2 Copyright © 2014-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_CURRENT_CLASS_NAME
29 #error "incorrect use of common/gatherinterface.h: Vc_CURRENT_CLASS_NAME must be defined to the current class name for declaring constructors."
30 #endif
31 
33 // gathers
34 // A gather takes the following arguments:
35 // 1. A const pointer to memory of any type that can convert to EntryType
36 // 2. An indexes “vector”. The requirement is that the type implements the subscript operator,
37 // stores «Size» valid index values, and each offset to the pointer above yields a valid
38 // memory location for reading.
39 // 3. Optionally the third argument may be a mask. The mask disables several memory reads and
40 // thus removes the requirements in (2.) for the disabled entries.
41 
42 private:
53  // enable_if<std::can_convert<MT, EntryType>::value &&
54  // has_subscript_operator<IT>::value>
55  template <typename MT, typename IT>
56  inline void gatherImplementation(const MT *mem, const IT &indexes);
57 
62  template <typename MT, typename IT>
63  inline void gatherImplementation(const MT *mem, const IT &indexes, MaskArgument mask);
64 
73  template <typename IT, typename = enable_if<std::is_pointer<IT>::value ||
74  Traits::is_simd_vector<IT>::value>>
75  static Vc_INTRINSIC const IT &adjustIndexParameter(const IT &indexes)
76  {
77  return indexes;
78  }
79 
90  template <
91  typename IT,
92  typename = enable_if<
93  !std::is_pointer<IT>::value && !Traits::is_simd_vector<IT>::value &&
94  std::is_lvalue_reference<decltype(std::declval<const IT &>()[0])>::value>>
95  static Vc_INTRINSIC decltype(std::addressof(std::declval<const IT &>()[0]))
96  adjustIndexParameter(const IT &i)
97  {
98  return std::addressof(i[0]);
99  }
100 
108  template <typename IT>
109  static Vc_INTRINSIC enable_if<
110  !std::is_pointer<IT>::value && !Traits::is_simd_vector<IT>::value &&
111  !std::is_lvalue_reference<decltype(std::declval<const IT &>()[0])>::value,
112  IT>
113  adjustIndexParameter(const IT &i)
114  {
115  return i;
116  }
117 
118 public:
119 #define Vc_ASSERT_GATHER_PARAMETER_TYPES_ \
120  static_assert( \
121  std::is_convertible<MT, EntryType>::value, \
122  "The memory pointer needs to point to a type that can be converted to the " \
123  "EntryType of this SIMD vector type."); \
124  static_assert( \
125  Vc::Traits::has_subscript_operator<IT>::value, \
126  "The indexes argument must be a type that implements the subscript operator."); \
127  static_assert( \
128  !Traits::is_simd_vector<IT>::value || \
129  Traits::simd_vector_size<IT>::value >= Size, \
130  "If you use a SIMD vector for the indexes parameter, the index vector must " \
131  "have at least as many entries as this SIMD vector."); \
132  static_assert( \
133  !std::is_array<T>::value || \
134  (std::rank<T>::value == 1 && \
135  (std::extent<T>::value == 0 || std::extent<T>::value >= Size)), \
136  "If you use a simple array for the indexes parameter, the array must have " \
137  "at least as many entries as this SIMD vector.")
138 
189 
192  template <typename MT, typename IT,
193  typename = enable_if<Traits::has_subscript_operator<IT>::value>>
194  Vc_INTRINSIC Vc_CURRENT_CLASS_NAME(const MT *mem, const IT &indexes)
195  {
196  Vc_ASSERT_GATHER_PARAMETER_TYPES_;
197  gatherImplementation(mem, adjustIndexParameter(indexes));
198  }
199 
201  template <typename MT, typename IT,
202  typename = enable_if<Vc::Traits::has_subscript_operator<IT>::value>>
203  Vc_INTRINSIC Vc_CURRENT_CLASS_NAME(const MT *mem, const IT &indexes,
204  MaskArgument mask)
205  {
206  Vc_ASSERT_GATHER_PARAMETER_TYPES_;
207  gatherImplementation(mem, adjustIndexParameter(indexes), mask);
208  }
209 
211  template <typename MT, typename IT,
212  typename = enable_if<Vc::Traits::has_subscript_operator<IT>::value>>
213  Vc_INTRINSIC void gather(const MT *mem, const IT &indexes)
214  {
215  Vc_ASSERT_GATHER_PARAMETER_TYPES_;
216  gatherImplementation(mem, adjustIndexParameter(indexes));
217  }
218 
220  template <typename MT, typename IT,
221  typename = enable_if<Vc::Traits::has_subscript_operator<IT>::value>>
222  Vc_INTRINSIC void gather(const MT *mem, const IT &indexes, MaskArgument mask)
223  {
224  Vc_ASSERT_GATHER_PARAMETER_TYPES_;
225  gatherImplementation(mem, adjustIndexParameter(indexes), mask);
226  }
228 
229 #include "gatherinterface_deprecated.h"
230 
237  template <typename MT, typename IT>
239  Vc_INTRINSIC void gather(const Common::GatherArguments<MT, IT> &args)
240  {
241  gather(args.address, adjustIndexParameter(args.indexes));
242  }
243 
244  template <typename MT, typename IT>
245  Vc_INTRINSIC void gather(const Common::GatherArguments<MT, IT> &args, MaskArgument mask)
246  {
247  gather(args.address, adjustIndexParameter(args.indexes), mask);
248  }
250 
251 #undef Vc_ASSERT_GATHER_PARAMETER_TYPES_