Vc  1.3.2-dev
SIMD Vector Classes for C++
array
1 /* This file is part of the Vc library. {{{
2 Copyright © 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 //===---------------------------- array -----------------------------------===//
28 //
29 // The LLVM Compiler Infrastructure
30 //
31 // This file is dual licensed under the MIT and the University of Illinois Open
32 // Source Licenses. See LICENSE.TXT for details.
33 //
34 //===----------------------------------------------------------------------===//
35 
36 #ifndef VC_INCLUDE_VC_ARRAY_
37 #define VC_INCLUDE_VC_ARRAY_
38 
39 #include <type_traits>
40 #include <utility>
41 #include <iterator>
42 #include <algorithm>
43 #include <stdexcept>
44 
45 #include "common/subscript.h"
46 
47 namespace Vc_VERSIONED_NAMESPACE
48 {
49 template <class T, size_t Size> struct array {
50  // types:
51  typedef array self_;
52  typedef T value_type;
53  typedef value_type& reference;
54  typedef const value_type& const_reference;
55  typedef value_type* iterator;
56  typedef const value_type* const_iterator;
57  typedef value_type* pointer;
58  typedef const value_type* const_pointer;
59  typedef size_t size_type;
60  typedef ptrdiff_t difference_type;
61  typedef std::reverse_iterator<iterator> reverse_iterator;
62  typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
63 
64  value_type elems_[Size > 0 ? Size : 1];
65 
66  // No explicit construct/copy/destroy for aggregate type
67  void fill(const value_type& u_) { std::fill_n(elems_, Size, u_); }
68  void swap(array& a_) noexcept(std::swap(std::declval<T &>(), std::declval<T &>()))
69  {
70  std::swap_ranges(elems_, elems_ + Size, a_.elems_);
71  }
72 
73  // iterators:
74  iterator begin() noexcept { return iterator(elems_); }
75  const_iterator begin() const noexcept { return const_iterator(elems_); }
76  iterator end() noexcept { return iterator(elems_ + Size); }
77  const_iterator end() const noexcept { return const_iterator(elems_ + Size); }
78  reverse_iterator rbegin() noexcept { return reverse_iterator(end()); }
79  const_reverse_iterator rbegin() const noexcept
80  {
81  return const_reverse_iterator(end());
82  }
83  reverse_iterator rend() noexcept { return reverse_iterator(begin()); }
84  const_reverse_iterator rend() const noexcept
85  {
86  return const_reverse_iterator(begin());
87  }
88 
89  const_iterator cbegin() const noexcept { return begin(); }
90  const_iterator cend() const noexcept { return end(); }
91  const_reverse_iterator crbegin() const noexcept { return rbegin(); }
92  const_reverse_iterator crend() const noexcept { return rend(); }
93  // capacity:
94  constexpr size_type size() const noexcept { return Size; }
95  constexpr size_type max_size() const noexcept { return Size; }
96  constexpr bool empty() const noexcept { return Size == 0; }
97  // element access:
98  reference operator[](size_type n_) { return elems_[n_]; }
99  constexpr const_reference operator[](size_type n_) const { return elems_[n_]; }
100 
101  /**
102  * \name Data-Parallel Subscripting for Gather & Scatter
103  */
104  ///@{
105  template <typename I>
106  Vc_ALWAYS_INLINE auto operator[](I&& arg_)
107  -> decltype(subscript_operator(*this, std::forward<I>(arg_)))
108  {
109  return subscript_operator(*this, std::forward<I>(arg_));
110  }
111 
112  template <typename I>
113  Vc_ALWAYS_INLINE auto operator[](I&& arg_) const
114  -> decltype(subscript_operator(*this, std::forward<I>(arg_)))
115  {
116  return subscript_operator(*this, std::forward<I>(arg_));
117  }
118  ///@}
119 
120  reference at(size_type n_);
121  constexpr const_reference at(size_type n_) const;
122 
123  reference front() { return elems_[0]; }
124  constexpr const_reference front() const { return elems_[0]; }
125  reference back() { return elems_[Size > 0 ? Size - 1 : 0]; }
126  constexpr const_reference back() const { return elems_[Size > 0 ? Size - 1 : 0]; }
127  value_type* data() noexcept { return elems_; }
128  const value_type* data() const noexcept { return elems_; }
129 };
130 
131 template <class T, size_t Size>
132 typename array<T, Size>::reference array<T, Size>::at(size_type n_)
133 {
134  if (n_ >= Size) {
135  throw std::out_of_range("array::at");
136  }
137  return elems_[n_];
138 }
139 
140 template <class T, size_t Size>
141 constexpr typename array<T, Size>::const_reference array<T, Size>::at(size_type n_) const
142 {
143  return n_ >= Size ? (throw std::out_of_range("array::at"), elems_[0]) : elems_[n_];
144 }
145 
146 template <class T, size_t Size>
147 inline bool operator==(const array<T, Size>& x_, const array<T, Size>& y_)
148 {
149  return std::equal(x_.elems_, x_.elems_ + Size, y_.elems_);
150 }
151 
152 template <class T, size_t Size>
153 inline bool operator!=(const array<T, Size>& x_, const array<T, Size>& y_)
154 {
155  return !(x_ == y_);
156 }
157 
158 template <class T, size_t Size>
159 inline bool operator<(const array<T, Size>& x_, const array<T, Size>& y_)
160 {
161  return std::lexicographical_compare(x_.elems_, x_.elems_ + Size, y_.elems_,
162  y_.elems_ + Size);
163 }
164 
165 template <class T, size_t Size>
166 inline bool operator>(const array<T, Size>& x_, const array<T, Size>& y_)
167 {
168  return y_ < x_;
169 }
170 
171 template <class T, size_t Size>
172 inline bool operator<=(const array<T, Size>& x_, const array<T, Size>& y_)
173 {
174  return !(y_ < x_);
175 }
176 
177 template <class T, size_t Size>
178 inline bool operator>=(const array<T, Size>& x_, const array<T, Size>& y_)
179 {
180  return !(x_ < y_);
181 }
182 
183 /**\name non-member begin & end
184  * Implement the non-member begin & end functions in the %Vc namespace so that ADL works
185  * and `begin(some_vc_array)` always works.
186  */
187 ///@{
188 template <typename T, std::size_t N>
189 inline auto begin(array<T, N>& arr) -> decltype(arr.begin())
190 {
191  return arr.begin();
192 }
193 template <typename T, std::size_t N>
194 inline auto begin(const array<T, N>& arr) -> decltype(arr.begin())
195 {
196  return arr.begin();
197 }
198 template <typename T, std::size_t N>
199 inline auto end(array<T, N>& arr) -> decltype(arr.end())
200 {
201  return arr.end();
202 }
203 template <typename T, std::size_t N>
204 inline auto end(const array<T, N>& arr) -> decltype(arr.end())
205 {
206  return arr.end();
207 }
208 ///@}
209 
210 namespace Traits
211 {
212 template <typename T, std::size_t N>
213 struct has_no_allocated_data_impl<Vc::array<T, N>> : public std::true_type
214 {
215 };
216 template <typename T, std::size_t N>
217 struct has_contiguous_storage_impl<Vc::array<T, N>> : public std::true_type
218 {
219 };
220 
221 static_assert(has_no_allocated_data<const volatile Vc::array<int, 256> &>::value, "");
222 static_assert(has_no_allocated_data<const volatile Vc::array<int, 256>>::value, "");
223 static_assert(has_no_allocated_data<volatile Vc::array<int, 256> &>::value, "");
224 static_assert(has_no_allocated_data<volatile Vc::array<int, 256>>::value, "");
225 static_assert(has_no_allocated_data<const Vc::array<int, 256> &>::value, "");
226 static_assert(has_no_allocated_data<const Vc::array<int, 256>>::value, "");
227 static_assert(has_no_allocated_data<Vc::array<int, 256>>::value, "");
228 static_assert(has_no_allocated_data<Vc::array<int, 256> &>::value, "");
229 static_assert(has_no_allocated_data<Vc::array<int, 256> &&>::value, "");
230 
231 } // namespace Traits
232 } // namespace Vc
233 
234 namespace std
235 {
236 template <class T, size_t Size>
237 inline
238 #ifdef Vc_MSVC
239  // MSVC fails to do SFINAE correctly and gets totally confused:
240  // error C2433: 'type': 'inline' not permitted on data declarations
241  // error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
242  // error C2061: syntax error: identifier 'swap'
243  void
244 #else
245  typename enable_if<is_same<void, decltype(swap(declval<T&>(), declval<T&>()))>::value,
246  void>::type
247 #endif
248  swap(const Vc::array<T, Size>& x_,
249  const Vc::array<T, Size>& y_) noexcept(swap(declval<T&>(), declval<T&>()))
250 {
251  x_.swap(y_);
252 }
253 
254 template <class T, size_t Size>
255 class tuple_size<Vc::array<T, Size>> : public integral_constant<size_t, Size>
256 {
257 };
258 
259 template <size_t I, class T, size_t Size> class tuple_element<I, Vc::array<T, Size>>
260 {
261 public:
262  typedef T type;
263 };
264 
265 template <size_t I, class T, size_t Size>
266 inline constexpr typename std::enable_if<(I < Size), T&>::type get(
267  Vc::array<T, Size>& a_) noexcept
268 {
269  return a_.elems_[I];
270 }
271 
272 template <size_t I, class T, size_t Size>
273 inline constexpr typename std::enable_if<(I < Size), const T&>::type get(
274  const Vc::array<T, Size>& a_) noexcept
275 {
276  return a_.elems_[I];
277 }
278 
279 template <size_t I, class T, size_t Size>
280 inline constexpr typename std::enable_if<(I < Size), T&&>::type get(
281  Vc::array<T, Size>&& a_) noexcept
282 {
283  return std::move(a_.elems_[I]);
284 }
285 } // namespace std
286 
287 #endif // VC_INCLUDE_VC_ARRAY_
288 
289 // vim: ft=cpp foldmethod=marker