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();
330 static constexpr std::size_t MemoryAlignment =
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.
value_type operator[](size_t index) const noexcept
Return a copy of the boolean element at index index.
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.
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.
Vector Classes Namespace.
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.