19 #ifndef viskores_cont_BitField_h
20 #define viskores_cont_BitField_h
32 #include <type_traits>
44 struct StorageTagBitField;
46 struct VISKORES_ALWAYS_EXPORT BitFieldMetaData
69 template <
typename WordType>
70 using IsValidWordType =
71 std::integral_constant<bool,
73 std::is_unsigned<WordType>::value &&
75 sizeof(WordType) <=
static_cast<size_t>(BlockSize) &&
77 static_cast<size_t>(BlockSize) %
sizeof(WordType) == 0>;
81 template <
typename WordType>
82 using IsValidWordTypeAtomic =
83 std::integral_constant<bool,
85 std::is_unsigned<WordType>::value &&
87 sizeof(WordType) <=
static_cast<size_t>(BlockSize) &&
89 static_cast<size_t>(BlockSize) %
sizeof(WordType) == 0 &&
108 template <
bool IsConst>
113 template <
typename PortalType,
114 typename PointerType = decltype(std::declval<PortalType>().GetIteratorBegin())>
115 struct HasPointerAccess :
public std::is_pointer<PointerType>
120 template <
typename T>
121 using MaybeConstPointer =
typename std::conditional<IsConst, T const*, T*>::type;
122 using BufferType = MaybeConstPointer<void>;
129 template <
typename WordType>
130 using IsValidWordType = BitFieldTraits::IsValidWordType<WordType>;
133 template <
typename WordType>
134 using IsValidWordTypeAtomic = BitFieldTraits::IsValidWordTypeAtomic<WordType>;
137 "Internal error: Default word type is invalid.");
139 "Device-specific fast word type is invalid.");
142 "Internal error: Default word type is invalid.");
144 "Device-specific fast word type is invalid for atomic operations.");
148 friend class viskores::cont::internal::Storage<bool,
149 viskores::cont::internal::StorageTagBitField>;
152 VISKORES_CONT BitPortalBase(BufferType rawArray, viskores::Id numberOfBits)
154 , NumberOfBits{ numberOfBits }
159 BitPortalBase() noexcept = default;
160 BitPortalBase(const BitPortalBase&) noexcept = default;
161 BitPortalBase(BitPortalBase&&) noexcept = default;
162 BitPortalBase& operator=(const BitPortalBase&) noexcept = default;
163 BitPortalBase& operator=(BitPortalBase&&) noexcept = default;
167 viskores::
Id GetNumberOfBits() const noexcept {
return this->NumberOfBits; }
172 template <
typename WordType = WordTypePreferred>
177 static constexpr
viskores::Id WordBits = WordSize * CHAR_BIT;
178 return (this->NumberOfBits + WordBits - 1) / WordBits;
183 template <
typename WordType = WordTypePreferred>
186 if (this->NumberOfBits == 0)
188 return WordType{ 0 };
194 const auto maxBit = this->NumberOfBits - 1;
195 const auto coord = this->GetBitCoordinateFromIndex<WordType>(maxBit);
197 return (~WordType{ 0 }) >> shift;
202 template <
typename WordType = WordTypePreferred>
208 return {
static_cast<viskores::Id>(bitIdx / BitsPerWord),
217 void SetBit(
viskores::Id bitIdx,
bool val)
const noexcept
220 using WordType = WordTypePreferred;
221 const auto coord = this->GetBitCoordinateFromIndex<WordType>(bitIdx);
222 const auto mask = WordType(1) << coord.BitOffset;
223 WordType* wordAddr = this->GetWordAddress<WordType>(coord.WordIndex);
240 using WordType = WordTypePreferred;
241 const auto coord = this->GetBitCoordinateFromIndex<WordType>(bitIdx);
242 const auto mask = WordType(1) << coord.BitOffset;
245 this->OrWordAtomic(coord.WordIndex, mask);
249 this->AndWordAtomic(coord.WordIndex, ~mask);
258 using WordType = WordTypePreferred;
259 const auto coord = this->GetBitCoordinateFromIndex<WordType>(bitIdx);
260 const auto word = this->GetWord<WordType>(coord.WordIndex);
261 const auto mask = WordType(1) << coord.BitOffset;
262 return (word & mask) != WordType(0);
271 using WordType = WordTypePreferred;
272 const auto coord = this->GetBitCoordinateFromIndex<WordType>(bitIdx);
273 const auto word = this->GetWordAtomic<WordType>(coord.WordIndex);
274 const auto mask = WordType(1) << coord.BitOffset;
275 return (word & mask) != WordType(0);
280 template <
typename WordType = WordTypePreferred>
284 *this->GetWordAddress<WordType>(wordIdx) = word;
289 template <
typename WordType = WordTypePreferred>
294 "Requested WordType does not support atomic"
295 " operations on target execution platform.");
301 template <
typename WordType = WordTypePreferred>
304 return *this->GetWordAddress<WordType>(wordIdx);
309 template <
typename WordType = WordTypePreferred>
313 "Requested WordType does not support atomic"
314 " operations on target execution platform.");
324 using WordType = WordTypePreferred;
325 const auto coord = this->GetBitCoordinateFromIndex<WordType>(bitIdx);
326 const auto mask = WordType(1) << coord.BitOffset;
327 const auto oldWord = this->XorWordAtomic(coord.WordIndex, mask);
328 return (oldWord & mask) != WordType(0);
333 template <
typename WordType = WordTypePreferred>
338 "Requested WordType does not support atomic"
339 " operations on target execution platform.");
340 WordType* addr = this->GetWordAddress<WordType>(wordIdx);
351 using WordType = WordTypePreferred;
352 const auto coord = this->GetBitCoordinateFromIndex<WordType>(bitIdx);
353 const auto bitmask = WordType(1) << coord.BitOffset;
355 const auto wordmask = val ? ~WordType(0) : ~bitmask;
356 const auto oldWord = this->AndWordAtomic(coord.WordIndex, wordmask);
357 return (oldWord & bitmask) != WordType(0);
363 template <
typename WordType = WordTypePreferred>
368 "Requested WordType does not support atomic"
369 " operations on target execution platform.");
370 WordType* addr = this->GetWordAddress<WordType>(wordIdx);
381 using WordType = WordTypePreferred;
382 const auto coord = this->GetBitCoordinateFromIndex<WordType>(bitIdx);
383 const auto bitmask = WordType(1) << coord.BitOffset;
385 const auto wordmask = val ? bitmask : WordType(0);
386 const auto oldWord = this->OrWordAtomic(coord.WordIndex, wordmask);
387 return (oldWord & bitmask) != WordType(0);
393 template <
typename WordType = WordTypePreferred>
398 "Requested WordType does not support atomic"
399 " operations on target execution platform.");
400 WordType* addr = this->GetWordAddress<WordType>(wordIdx);
411 using WordType = WordTypePreferred;
412 const auto coord = this->GetBitCoordinateFromIndex<WordType>(bitIdx);
413 const auto bitmask = WordType(1) << coord.BitOffset;
415 const auto wordmask = val ? bitmask : WordType(0);
416 const auto oldWord = this->XorWordAtomic(coord.WordIndex, wordmask);
417 return (oldWord & bitmask) != WordType(0);
423 template <
typename WordType = WordTypePreferred>
428 "Requested WordType does not support atomic"
429 " operations on target execution platform.");
430 WordType* addr = this->GetWordAddress<WordType>(wordIdx);
441 bool CompareExchangeBitAtomic(
viskores::Id bitIdx,
bool* oldBit,
bool newBit)
const
444 using WordType = WordTypePreferred;
445 const auto coord = this->GetBitCoordinateFromIndex<WordType>(bitIdx);
446 const auto bitmask = WordType(1) << coord.BitOffset;
448 WordType oldWord = this->GetWord<WordType>(coord.WordIndex);
451 bool actualBit = (oldWord & bitmask) != WordType(0);
452 if (actualBit != *oldBit)
457 else if (actualBit == newBit)
465 }
while (!this->CompareExchangeWordAtomic(coord.WordIndex, &oldWord, oldWord ^ bitmask));
476 template <
typename WordType = WordTypePreferred>
479 WordType newWord)
const
483 "Requested WordType does not support atomic"
484 " operations on target execution platform.");
485 WordType* addr = this->GetWordAddress<WordType>(wordIdx);
490 template <
typename WordType>
494 return reinterpret_cast<MaybeConstPointer<WordType>
>(this->Data) + wordId;
497 BufferType Data{
nullptr };
501 using BitPortal = BitPortalBase<false>;
503 using BitPortalConst = BitPortalBase<true>;
509 static constexpr
viskores::Id BlockSize = detail::BitFieldTraits::BlockSize;
520 template <
typename Device>
534 template <
typename WordType>
538 template <
typename WordType,
typename Device =
void>
549 bool operator==(const
BitField& rhs)
const {
return this->Buffer == rhs.Buffer; }
562 template <
typename WordType>
567 return (this->GetNumberOfBits() + WordBits - 1) / WordBits;
580 this->Allocate(numberOfBits, preserve, token);
584 template <
typename ValueType>
590 this->Fill(value, token);
592 template <
typename ValueType>
596 this->AllocateAndFill(numberOfBits, value, token);
606 template <
typename WordType>
611 template <
typename WordType>
615 this->Fill(word, token);
622 this->Fill(value ? ~WordType{ 0 } : WordType{ 0 }, token);
627 this->Fill(value, token);
689 mutable viskores::cont::internal::Buffer
Buffer;
694 #endif // viskores_cont_BitField_h