28 #ifndef VC_COMMON_SIMDMASKARRAY_H_
29 #define VC_COMMON_SIMDMASKARRAY_H_
31 #include <type_traits>
33 #include "simdarrayhelper.h"
39 namespace Vc_VERSIONED_NAMESPACE
53 template <
typename T, std::
size_t N,
typename VectorType_>
54 class SimdMaskArray<T, N, VectorType_, N>
57 using VectorType = VectorType_;
58 using vector_type = VectorType;
59 using mask_type =
typename vector_type::Mask;
60 using storage_type = mask_type;
62 friend storage_type &internal_data(SimdMaskArray &m) {
return m.data; }
63 friend const storage_type &internal_data(
const SimdMaskArray &m) {
return m.data; }
65 static constexpr std::size_t size() {
return N; }
66 static constexpr std::size_t Size = size();
68 static_assert(Size == vector_type::Size,
"size mismatch");
70 using vectorentry_type =
typename mask_type::VectorEntryType;
71 using value_type =
typename mask_type::EntryType;
72 using Mask = mask_type;
73 using VectorEntryType = vectorentry_type;
74 using EntryType = value_type;
75 using EntryReference = Vc::Detail::ElementReference<storage_type, SimdMaskArray>;
76 using reference = EntryReference;
77 using Vector = SimdArray<T, N, VectorType, N>;
79 Vc_FREE_STORE_OPERATORS_ALIGNED(
alignof(mask_type));
82 SimdMaskArray() =
default;
85 Vc_INTRINSIC
explicit SimdMaskArray(VectorSpecialInitializerOne one) : data(one) {}
86 Vc_INTRINSIC
explicit SimdMaskArray(VectorSpecialInitializerZero zero) : data(zero) {}
87 Vc_INTRINSIC
explicit SimdMaskArray(
bool b) : data(b) {}
92 template <
typename U,
typename V>
93 Vc_INTRINSIC_L SimdMaskArray(
const SimdMaskArray<U, N, V> &x,
94 enable_if<N == V::Size> = nullarg) Vc_INTRINSIC_R;
95 template <typename U, typename V>
96 Vc_INTRINSIC_L SimdMaskArray(const SimdMaskArray<U, N, V> &x,
97 enable_if<(N > V::Size && N <= 2 * V::Size)> = nullarg)
99 template <typename U, typename V>
100 Vc_INTRINSIC_L SimdMaskArray(const SimdMaskArray<U, N, V> &x,
101 enable_if<(N > 2 * V::Size && N <= 4 * V::Size)> = nullarg)
105 template <typename M, std::
size_t Pieces, std::
size_t Index>
106 Vc_INTRINSIC_L SimdMaskArray(
107 Common::Segment<M, Pieces, Index> &&x,
108 enable_if<Traits::simd_vector_size<M>::value == Size * Pieces> = nullarg) Vc_INTRINSIC_R;
111 template <typename M>
112 Vc_INTRINSIC_L SimdMaskArray(
114 enable_if<(Traits::is_simd_mask<M>::value && !Traits::isSimdMaskArray<M>::value &&
115 Traits::simd_vector_size<M>::value == Size)> = nullarg) Vc_INTRINSIC_R;
118 template <typename U, typename A, typename = enable_if<Vc::Mask<U, A>::Size == N>>
119 operator Vc::Mask<U, A>()
const
125 template <
typename Flags = DefaultLoadTag>
126 Vc_INTRINSIC
explicit SimdMaskArray(
const bool *mem, Flags f = Flags())
131 Vc_INTRINSIC
void load(
const bool *mem) { data.load(mem); }
132 template <
typename Flags> Vc_INTRINSIC
void load(
const bool *mem, Flags f)
137 Vc_INTRINSIC
void store(
bool *mem)
const { data.store(mem); }
138 template <
typename Flags> Vc_INTRINSIC
void store(
bool *mem, Flags f)
const
144 Vc_INTRINSIC Vc_PURE
bool operator==(
const SimdMaskArray &rhs)
const
146 return data == rhs.data;
148 Vc_INTRINSIC Vc_PURE
bool operator!=(
const SimdMaskArray &rhs)
const
150 return data != rhs.data;
154 Vc_INTRINSIC Vc_PURE SimdMaskArray operator!()
const
160 Vc_INTRINSIC SimdMaskArray &operator&=(
const SimdMaskArray &rhs)
165 Vc_INTRINSIC SimdMaskArray &operator|=(
const SimdMaskArray &rhs)
170 Vc_INTRINSIC SimdMaskArray &operator^=(
const SimdMaskArray &rhs)
176 Vc_INTRINSIC Vc_PURE SimdMaskArray
operator&(
const SimdMaskArray &rhs)
const
178 return {data & rhs.data};
180 Vc_INTRINSIC Vc_PURE SimdMaskArray
operator|(
const SimdMaskArray &rhs)
const
182 return {data | rhs.data};
184 Vc_INTRINSIC Vc_PURE SimdMaskArray
operator^(
const SimdMaskArray &rhs)
const
186 return {data ^ rhs.data};
189 Vc_INTRINSIC Vc_PURE SimdMaskArray operator&&(
const SimdMaskArray &rhs)
const
191 return {data && rhs.data};
193 Vc_INTRINSIC Vc_PURE SimdMaskArray operator||(
const SimdMaskArray &rhs)
const
195 return {data || rhs.data};
198 Vc_INTRINSIC Vc_PURE
bool isFull()
const {
return data.isFull(); }
199 Vc_INTRINSIC Vc_PURE
bool isNotEmpty()
const {
return data.isNotEmpty(); }
200 Vc_INTRINSIC Vc_PURE
bool isEmpty()
const {
return data.isEmpty(); }
201 Vc_INTRINSIC Vc_PURE
bool isMix()
const {
return data.isMix(); }
203 Vc_INTRINSIC Vc_PURE
int shiftMask()
const {
return data.shiftMask(); }
205 Vc_INTRINSIC Vc_PURE
int toInt()
const {
return data.toInt(); }
209 static Vc_INTRINSIC value_type
get(
const storage_type &k,
int i) noexcept
213 template <
typename U>
214 static Vc_INTRINSIC
void set(storage_type &k,
int i, U &&v) noexcept(
215 noexcept(std::declval<storage_type &>()[0] = std::declval<U>()))
217 k[i] = std::forward<U>(v);
227 Vc_INTRINSIC Vc_PURE reference operator[](
size_t index) noexcept
229 return {data, int(index)};
231 Vc_INTRINSIC Vc_PURE value_type operator[](
size_t index)
const noexcept
236 Vc_INTRINSIC Vc_PURE
int count()
const {
return data.count(); }
243 Vc_INTRINSIC Vc_PURE
int firstOne()
const {
return data.firstOne(); }
245 template <
typename G>
static Vc_INTRINSIC SimdMaskArray generate(
const G &gen)
247 return {mask_type::generate(gen)};
250 Vc_INTRINSIC Vc_PURE SimdMaskArray
shifted(
int amount)
const
252 return {data.shifted(amount)};
256 template <
typename Op,
typename... Args>
257 static Vc_INTRINSIC SimdMaskArray fromOperation(Op op, Args &&... args)
260 Common::unpackArgumentsAuto(op, r.data, std::forward<Args>(args)...);
265 Vc_INTRINSIC SimdMaskArray(mask_type &&x) : data(std::move(x)) {}
271 alignas(
static_cast<std::size_t
>(
272 Common::BoundedAlignment<Common::NextPowerOfTwo<N>::value *
sizeof(VectorType_) /
273 VectorType_::size()>::value)) storage_type data;
276 template <
typename T, std::
size_t N,
typename VectorType> constexpr std::size_t SimdMaskArray<T, N, VectorType, N>::Size;
277 template <
typename T, std::
size_t N,
typename VectorType>
304 template <
typename T,
size_t N,
typename V,
size_t Wt>
307 static constexpr std::size_t N0 = Common::left_size<N>();
309 using Split = Common::Split<N0>;
312 using storage_type0 = SimdMaskArray<T, N0>;
313 using storage_type1 = SimdMaskArray<T, N - N0>;
314 static_assert(storage_type0::size() == N0,
"");
316 using vector_type = SimdArray<T, N>;
318 friend storage_type0 &internal_data0(SimdMaskArray &m) {
return m.data0; }
319 friend storage_type1 &internal_data1(SimdMaskArray &m) {
return m.data1; }
320 friend const storage_type0 &internal_data0(
const SimdMaskArray &m) {
return m.data0; }
321 friend const storage_type1 &internal_data1(
const SimdMaskArray &m) {
return m.data1; }
323 using mask_type = SimdMaskArray;
326 static constexpr std::size_t
size() {
return N; }
328 static constexpr std::size_t Size = size();
334 static_assert(Size == vector_type::Size,
"size mismatch");
366 template <
typename U,
typename W>
368 : data0(Split::lo(rhs)), data1(Split::hi(rhs))
373 template <
typename M, std::
size_t Pieces, std::
size_t Index>
375 Common::Segment<M, Pieces, Index> &&rhs,
377 : data0(Split::lo(rhs)), data1(Split::hi(rhs))
382 template <
typename M>
383 Vc_INTRINSIC SimdMaskArray(
385 enable_if<(Traits::is_simd_mask<M>::value && !Traits::isSimdMaskArray<M>::value &&
386 Traits::simd_vector_size<M>::value == Size)> = nullarg)
387 : data0(Split::lo(k)), data1(Split::hi(k))
392 template <typename U, typename A, typename = enable_if<Vc::Mask<U, A>::Size == N>>
400 : data0(one), data1(one)
405 : data0(zero), data1(zero)
425 template <
typename Flags = DefaultLoadTag>
436 Vc_INTRINSIC
void load(
const bool *mem)
439 data1.load(mem + storage_type0::size());
448 template <
typename Flags> Vc_INTRINSIC
void load(
const bool *mem, Flags f)
451 data1.load(mem + storage_type0::size(), f);
459 Vc_INTRINSIC
void store(
bool *mem)
const
462 data1.store(mem + storage_type0::size());
471 template <
typename Flags> Vc_INTRINSIC
void store(
bool *mem, Flags f)
const
474 data1.store(mem + storage_type0::size(), f);
481 return data0 == mask.data0 && data1 == mask.data1;
486 return data0 != mask.data0 || data1 != mask.data1;
492 return {!data0, !data1};
520 return {data0 & rhs.data0, data1 & rhs.data1};
525 return {data0 | rhs.data0, data1 | rhs.data1};
530 return {data0 ^ rhs.data0, data1 ^ rhs.data1};
536 return {data0 && rhs.data0, data1 && rhs.data1};
541 return {data0 || rhs.data0, data1 || rhs.data1};
545 Vc_INTRINSIC Vc_PURE
bool isFull()
const {
return data0.isFull() && data1.isFull(); }
547 Vc_INTRINSIC Vc_PURE
bool isNotEmpty()
const {
return data0.isNotEmpty() || data1.isNotEmpty(); }
549 Vc_INTRINSIC Vc_PURE
bool isEmpty()
const {
return data0.isEmpty() && data1.isEmpty(); }
551 Vc_INTRINSIC Vc_PURE
bool isMix()
const {
return !isFull() && !isEmpty(); }
554 Vc_INTRINSIC Vc_PURE
int toInt()
const
556 return data0.toInt() | (data1.toInt() << data0.size());
561 static Vc_INTRINSIC value_type
get(
const SimdMaskArray &o,
int i) noexcept
563 if (i <
int(o.data0.size())) {
566 return o.data1[i - o.data0.size()];
569 template <
typename U>
570 static Vc_INTRINSIC
void set(SimdMaskArray &o,
int i, U &&v) noexcept(
571 noexcept(std::declval<storage_type0 &>()[0] = std::declval<U>()) &&
572 noexcept(std::declval<storage_type1 &>()[0] = std::declval<U>()))
574 if (i <
int(o.data0.size())) {
575 o.data0[i] = std::forward<U>(v);
577 o.data1[i - o.data0.size()] = std::forward<U>(v);
590 Vc_INTRINSIC Vc_PURE reference
operator[](
size_t index) noexcept
592 return {*
this, int(index)};
604 return get(*
this, index);
608 Vc_INTRINSIC Vc_PURE
int count()
const {
return data0.count() + data1.count(); }
612 if (data0.isEmpty()) {
613 return data1.firstOne() + storage_type0::size();
615 return data0.firstOne();
621 return {storage_type0::generate(gen),
622 storage_type1::generate([&](std::size_t i) {
return gen(i + N0); })};
628 if (Vc_IS_UNLIKELY(amount == 0)) {
631 return generate([&](
unsigned i) {
633 const unsigned j = i + amount;
634 return j < size() ?
get(*
this, j) :
false;
639 template <
typename Op,
typename... Args>
640 static Vc_INTRINSIC
SimdMaskArray fromOperation(Op op, Args &&... args)
643 storage_type0::fromOperation(op, Split::lo(args)...),
646 storage_type1::fromOperation(op, Split::hi(std::forward<Args>(args))...)};
651 Vc_INTRINSIC SimdMaskArray(storage_type0 &&x, storage_type1 &&y)
652 : data0(std::move(x)), data1(std::move(y))
660 alignas(
static_cast<std::size_t
>(
661 Common::BoundedAlignment<Common::NextPowerOfTwo<N>::value *
sizeof(V) /
662 V::size()>::value)) storage_type0 data0;
665 template <
typename T, std::
size_t N,
typename V, std::
size_t M>
666 constexpr std::size_t SimdMaskArray<T, N, V, M>::Size;
667 template <
typename T, std::
size_t N,
typename V, std::
size_t M>
677 #include "simd_cast_caller.tcc"
679 #endif // VC_COMMON_SIMDMASKARRAY_H_
bool operator!=(const SimdMaskArray &mask) const
Returns whether the two masks are different in at least one component.
bool isNotEmpty() const
Returns a logical OR of all components.
result_vector_type< L, R > operator|(L &&lhs, R &&rhs)
Applies | component-wise and concurrently.
result_vector_type< L, R > operator^(L &&lhs, R &&rhs)
Applies ^ component-wise and concurrently.
static SimdMaskArray One()
Creates a mask object initialized to one/true.
SimdMaskArray shifted(int amount) const
Returns a mask with components shifted by amount places.
reference operator[](size_t index) noexcept
Return a smart reference to the boolean element at index index.
typename storage_type0::EntryType value_type
The EntryType of masks is always bool, independent of T.
SimdMaskArray(const bool *mem, Flags f=Flags())
Load N boolean values from the consecutive addresses starting at mem.
SimdMaskArray(VectorSpecialInitializerZero zero)
Zero-initialize the new mask object (false).
int firstOne() const
Returns the index of the first one in the mask.
SimdMaskArray operator^(const SimdMaskArray &rhs) const
Returns the component-wise application of a binary XOR to mask.
void load(const bool *mem, Flags f)
Load N boolean values from the consecutive addresses starting at mem.
result_vector_type< L, R >::mask_type operator!=(L &&lhs, R &&rhs)
Applies != component-wise and concurrently.
SimdMaskArray & operator|=(const SimdMaskArray &rhs)
Modifies the mask using an OR operation with mask.
static SimdMaskArray Zero()
Creates a new mask object initialized to zero/false.
bool isEmpty() const
Returns true if components are false, false otherwise.
SimdMaskArray operator&&(const SimdMaskArray &rhs) const
Returns the component-wise application of a logical AND to mask.
Data-parallel arithmetic type with user-defined number of elements.
The value member will either be the number of SIMD vector entries or 0 if T is not a SIMD type...
static constexpr std::size_t size()
Returns the number of boolean components ( ) in a mask of this type.
SimdMaskArray(VectorSpecialInitializerOne one)
Initialize the new mask object to one (true).
Data-parallel mask type with user-defined number of boolean elements.
SimdMaskArray & operator&=(const SimdMaskArray &rhs)
Modifies the mask using an AND operation with mask.
vectorentry_type VectorEntryType
The VectorEntryType, in contrast to EntryType, reveals information about the SIMD implementation...
SimdMaskArray operator!() const
Returns a mask with inverted components.
void load(const bool *mem)
Load N boolean values from the consecutive addresses starting at mem.
SimdMaskArray operator|(const SimdMaskArray &rhs) const
Returns the component-wise application of a binary OR to mask.
SimdMaskArray operator||(const SimdMaskArray &rhs) const
Returns the component-wise application of a logical OR to mask.
void store(bool *mem, Flags f) const
Store N boolean values to the consecutive addresses starting at mem.
Vc::Detail::ElementReference< SimdMaskArray > EntryReference
The reference wrapper type used for accessing individual mask components.
value_type EntryType
The EntryType of masks is always bool, independent of T.
result_vector_type< L, R >::mask_type operator==(L &&lhs, R &&rhs)
Applies == component-wise and concurrently.
int toInt() const
Convert the boolean components of the mask into bits of an integer.
SimdMaskArray & operator^=(const SimdMaskArray &rhs)
Modifies the mask using an XOR operation with mask.
result_vector_type< L, R > operator&(L &&lhs, R &&rhs)
Applies & component-wise and concurrently.
The main SIMD mask class.
value_type operator[](size_t index) const noexcept
Return a copy of the boolean element at index index.
bool isFull() const
Returns a logical AND of all components.
constexpr VectorSpecialInitializerZero Zero
The special object Vc::Zero can be used to construct Vector and Mask objects initialized to zero/fals...
Adapter< S, T, N > shifted(const Adapter< S, T, N > &a, int shift)
Returns a new vectorized object where each entry is shifted by shift.
int count() const
Returns how many components of the mask are true.
constexpr VectorSpecialInitializerOne One
The special object Vc::One can be used to construct Vector and Mask objects initialized to one/true...
void store(bool *mem) const
Store N boolean values to the consecutive addresses starting at mem.
constexpr std::size_t MemoryAlignment
Specifies the most conservative memory alignment necessary for aligned loads and stores of Vector typ...
SimdMaskArray(bool b)
Broadcast constructor.
bool operator==(const SimdMaskArray &mask) const
Returns whether the two masks are equal in all components.
SimdMaskArray operator&(const SimdMaskArray &rhs) const
Returns the component-wise application of a binary AND to mask.
bool isMix() const
Returns !isFull() && !isEmpty().
static SimdMaskArray generate(const G &gen)
Generate a mask object from booleans returned from the function gen.