31 template<
typename SizeT,
typename Op>
34 *
reinterpret_cast<SizeT*
>(final_value.local_data_) =
35 Op()(*
reinterpret_cast<const SizeT*
>(in.remote_data_),
36 *
reinterpret_cast<const SizeT*
>(rh_bits.remote_data_));
40 template<
typename SizeT>
43 *
reinterpret_cast<SizeT*
>(final_value.local_data_) =
44 std::bit_not<SizeT>()(*
reinterpret_cast<const SizeT*
>(in.remote_data_));
48 template<
typename SizeT>
51 *
reinterpret_cast<SizeT*
>(final_value.local_data_) =
52 (*
reinterpret_cast<const SizeT*
>(in.remote_data_)) >> amount;
56 template<
typename SizeT>
59 *
reinterpret_cast<SizeT*
>(final_value.local_data_) =
60 (*
reinterpret_cast<const SizeT*
>(in.remote_data_)) << amount;
66 if(
nullptr == local_data_)
68 if(num_bytes_ <= local_storage_.size()) {
69 local_data_ = local_storage_.data();
72 local_storage_alt_.reset(
new uint8_t[num_bytes_]);
73 local_data_ = local_storage_alt_.get();
75 ::memset(local_data_, 0, num_bytes_);
76 ::memcpy(local_data_, remote_data_, num_bytes_);
77 remote_data_ = local_data_;
88 local_data_(local_storage_.
data()),
89 remote_data_(local_data_),
92 if(num_bytes > local_storage_.size()) {
93 local_storage_alt_.reset(
new uint8_t[num_bytes]);
94 local_data_ = local_storage_alt_.get();
95 remote_data_ = local_data_;
97 ::memset(local_data_, 0, num_bytes_);
107 template<
class DataT>
110 local_data_(local_storage_.
data()),
111 remote_data_(local_data_),
112 num_bytes_(num_bytes)
114 if(num_bytes > local_storage_.size()) {
115 local_storage_alt_.reset(
new uint8_t[num_bytes]);
116 local_data_ = local_storage_alt_.get();
117 remote_data_ = local_data_;
119 ::memset(local_data_, 0, num_bytes_);
132 local_data_(data_ptr),
133 remote_data_(local_data_),
134 num_bytes_(num_bytes)
146 num_bytes_(num_bytes)
161 num_bytes_(orig.num_bytes_)
163 if(num_bytes_ <= local_storage_.size()) {
164 local_storage_ = orig.local_storage_;
165 local_data_ = orig.local_data_ ==
nullptr ? nullptr : local_storage_.data();
167 else if (orig.local_data_ ==
nullptr) {
168 local_data_ =
nullptr;
171 local_storage_alt_.reset(
new uint8_t[orig.
getSize()]);
172 local_data_ = local_storage_alt_.get();
173 ::memcpy(local_data_, orig.local_data_, num_bytes_);
175 remote_data_ = orig.local_data_ == orig.remote_data_ ? local_data_ : orig.remote_data_;
186 num_bytes_(orig.num_bytes_)
188 if(num_bytes_ <= local_storage_.size()) {
189 local_storage_ = std::move(orig.local_storage_);
190 local_data_ = (orig.local_data_ ==
nullptr ? nullptr : local_storage_.data());
192 else if (orig.local_data_ ==
nullptr) {
193 local_data_ =
nullptr;
196 local_storage_alt_ = std::move(orig.local_storage_alt_);
197 local_data_ = local_storage_alt_.get();
199 remote_data_ = (orig.local_data_ == orig.remote_data_ ? local_data_ : orig.remote_data_);
200 orig.local_data_ =
nullptr;
201 orig.remote_data_ =
nullptr;
211 if(num_bytes_ == 8) {
212 return bitMerge_<uint64_t, std::bit_or<uint64_t>>(*
this, rh_bits);
214 else if(num_bytes_ == 4) {
215 return bitMerge_<uint32_t, std::bit_or<uint32_t>>(*
this, rh_bits);
217 else if(num_bytes_ > 8)
221 for(uint32_t idx = 0; idx < num_bytes_; idx += 8)
223 *
reinterpret_cast<uint64_t*
>(final_value.local_data_ + idx) =
224 *
reinterpret_cast<const uint64_t*
>(remote_data_ + idx) |
225 *
reinterpret_cast<const uint64_t*
>(rh_bits.remote_data_ + idx);
229 else if(num_bytes_ == 2) {
230 return bitMerge_<uint16_t, std::bit_or<uint16_t>>(*
this, rh_bits);
232 else if(num_bytes_ == 1) {
233 return bitMerge_<uint8_t, std::bit_or<uint8_t>>(*
this, rh_bits);
247 if(num_bytes_ == 8) {
248 return bitMerge_<uint64_t, std::bit_and<uint64_t>>(*
this, rh_bits);
250 else if(num_bytes_ == 4) {
251 return bitMerge_<uint32_t, std::bit_and<uint32_t>>(*
this, rh_bits);
253 else if(num_bytes_ > 8)
257 for(uint32_t idx = 0; idx < num_bytes_; idx += 8)
259 *
reinterpret_cast<uint64_t*
>(final_value.local_data_ + idx) =
260 *
reinterpret_cast<const uint64_t*
>(remote_data_ + idx) &
261 *
reinterpret_cast<const uint64_t*
>(rh_bits.remote_data_ + idx);
265 else if(num_bytes_ == 2) {
266 return bitMerge_<uint16_t, std::bit_and<uint16_t>>(*
this, rh_bits);
268 else if(num_bytes_ == 1) {
269 return bitMerge_<uint8_t, std::bit_and<uint8_t>>(*
this, rh_bits);
282 if(num_bytes_ == 8) {
283 return bitNot_<uint64_t>(*
this);
285 else if(num_bytes_ == 4) {
286 return bitNot_<uint32_t>(*
this);
288 else if(num_bytes_ > 8)
292 for(uint32_t idx = 0; idx < num_bytes_; idx += 8)
294 *
reinterpret_cast<uint64_t*
>(final_value.local_data_ + idx) =
295 ~*
reinterpret_cast<const uint64_t*
>(remote_data_ + idx);
299 else if(num_bytes_ == 2) {
300 return bitNot_<uint16_t>(*
this);
302 else if(num_bytes_ == 1) {
303 return bitNot_<uint8_t>(*
this);
315 if(num_bytes_ == 8) {
316 return bitShiftRight_<uint64_t>(*
this, shift);
318 else if(num_bytes_ == 4) {
319 return bitShiftRight_<uint32_t>(*
this, shift);
321 else if(num_bytes_ > 8)
324 const uint64_t * src_data =
reinterpret_cast<const uint64_t*
>(remote_data_);
325 uint64_t * final_data =
reinterpret_cast<uint64_t*
>(final_value.local_data_);
326 const uint32_t num_dbl_words = num_bytes_ / 8;
329 const uint32_t double_word_shift_count = shift / 64;
356 uint32_t src_idx = double_word_shift_count;
357 for(uint32_t dest_idx = 0; src_idx < num_dbl_words; ++dest_idx, ++src_idx) {
358 *(final_data + dest_idx) = *(src_data + src_idx);
365 const auto double_words_to_micro_shift = (num_dbl_words - double_word_shift_count);
366 if(double_words_to_micro_shift > 0)
368 const uint32_t remaining_bits_to_shift = shift % 64;
369 if(remaining_bits_to_shift)
371 const uint64_t prev_dbl_word_bits_dropped_mask =
372 (uint64_t)(-(remaining_bits_to_shift != 0) &
373 (-1 >> ((
sizeof(uint64_t) * 8) - remaining_bits_to_shift)));
374 const uint32_t prev_dbl_word_bit_pos = 64 - remaining_bits_to_shift;
378 *(final_data + idx) >>= remaining_bits_to_shift;
379 if(++idx == double_words_to_micro_shift) {
382 const uint64_t bits_pulled_in =
383 (*(final_data + idx) & prev_dbl_word_bits_dropped_mask) << prev_dbl_word_bit_pos;
384 *(final_data + (idx - 1)) |= bits_pulled_in;
390 else if(num_bytes_ == 2) {
391 return bitShiftRight_<uint16_t>(*
this, shift);
393 else if(num_bytes_ == 1) {
394 return bitShiftRight_<uint8_t>(*
this, shift);
407 if(num_bytes_ == 8) {
408 return bitShiftLeft_<uint64_t>(*
this, shift);
410 else if(num_bytes_ == 4) {
411 return bitShiftLeft_<uint32_t>(*
this, shift);
413 else if(num_bytes_ > 8)
416 const uint64_t * src_data =
reinterpret_cast<const uint64_t*
>(remote_data_);
417 uint64_t * final_data =
reinterpret_cast<uint64_t*
>(final_value.local_data_);
418 const uint32_t num_dbl_words = num_bytes_ / 8;
421 const uint32_t double_word_shift_count = shift / 64;
448 uint32_t dest_idx = double_word_shift_count;
449 for(uint32_t src_idx = 0; dest_idx < num_dbl_words; ++dest_idx, ++src_idx) {
450 *(final_data + dest_idx) = *(src_data + src_idx);
457 const uint32_t remaining_bits_to_shift = shift % 64;
458 if(remaining_bits_to_shift)
460 const int32_t double_words_to_micro_shift = (num_dbl_words - double_word_shift_count);
461 if(double_words_to_micro_shift > 0)
463 const uint64_t prev_dbl_word_bit_pos = 64 - remaining_bits_to_shift;
464 const uint64_t prev_dbl_word_bits_dropped_mask =
465 (uint64_t)(-(prev_dbl_word_bit_pos != 0) &
466 (std::numeric_limits<uint64_t>::max() << prev_dbl_word_bit_pos));
467 int32_t idx = num_dbl_words - 1;
470 *(final_data + idx) <<= remaining_bits_to_shift;
472 if(idx < 0) {
break; }
473 const uint64_t bits_dropped_from_next_double_word =
474 (*(final_data + idx) & prev_dbl_word_bits_dropped_mask) >> prev_dbl_word_bit_pos;
475 *(final_data + (idx + 1)) |= bits_dropped_from_next_double_word;
481 else if(num_bytes_ == 2) {
482 return bitShiftLeft_<uint16_t>(*
this, shift);
484 else if(num_bytes_ == 1) {
485 return bitShiftLeft_<uint8_t>(*
this, shift);
494 if(num_bytes_ == 8) {
495 *
reinterpret_cast<uint64_t*
>(local_data_) |=
496 *
reinterpret_cast<const uint64_t*
>(rh_bits.remote_data_);
498 else if(num_bytes_ == 4) {
499 *
reinterpret_cast<uint32_t*
>(local_data_) |=
500 *
reinterpret_cast<const uint32_t*
>(rh_bits.remote_data_);
502 else if(num_bytes_ > 8)
505 for(uint32_t idx = 0; idx < num_bytes_; idx += 8)
507 *
reinterpret_cast<uint64_t*
>(local_data_ + idx) |=
508 *
reinterpret_cast<const uint64_t*
>(rh_bits.remote_data_ + idx);
511 else if(num_bytes_ == 2) {
512 *
reinterpret_cast<uint16_t*
>(local_data_) |=
513 *
reinterpret_cast<const uint16_t*
>(rh_bits.remote_data_);
515 else if(num_bytes_ == 1) {
516 *
reinterpret_cast<uint8_t*
>(local_data_) |=
517 *
reinterpret_cast<const uint8_t*
>(rh_bits.remote_data_);
529 if(num_bytes_ == 8) {
530 *
reinterpret_cast<uint64_t*
>(local_data_) =
531 (*
reinterpret_cast<const uint64_t*
>(remote_data_)) << shift;
533 else if(num_bytes_ == 4) {
534 *
reinterpret_cast<uint32_t*
>(local_data_) =
535 (*
reinterpret_cast<const uint32_t*
>(remote_data_)) << shift;
537 else if(num_bytes_ > 8)
539 uint64_t * src_data =
reinterpret_cast<uint64_t*
>(local_data_);
540 uint64_t * final_data =
reinterpret_cast<uint64_t*
>(local_data_);
541 const uint32_t num_dbl_words = num_bytes_ / 8;
544 const uint32_t double_word_shift_count = shift / 64;
571 if(double_word_shift_count > 0)
573 uint32_t dest_idx = double_word_shift_count;
574 for(uint32_t src_idx = 0; dest_idx < num_dbl_words; ++dest_idx, ++src_idx) {
575 *(final_data + dest_idx) = *(src_data + src_idx);
576 *(src_data + src_idx) = 0;
584 const uint32_t remaining_bits_to_shift = shift % 64;
585 if(remaining_bits_to_shift)
587 const int32_t double_words_to_micro_shift = (num_dbl_words - double_word_shift_count);
588 if(double_words_to_micro_shift > 0)
590 const uint64_t prev_dbl_word_bit_pos = 64 - remaining_bits_to_shift;
591 const uint64_t prev_dbl_word_bits_dropped_mask =
592 (uint64_t)(-(prev_dbl_word_bit_pos != 0) &
593 (std::numeric_limits<uint64_t>::max() << prev_dbl_word_bit_pos));
594 int32_t idx = num_dbl_words - 1;
597 *(final_data + idx) <<= remaining_bits_to_shift;
599 if(idx < 0) {
break; }
600 const uint64_t bits_dropped_from_next_double_word =
601 (*(final_data + idx) & prev_dbl_word_bits_dropped_mask) >> prev_dbl_word_bit_pos;
602 *(final_data + (idx + 1)) |= bits_dropped_from_next_double_word;
607 else if(num_bytes_ == 2) {
608 *
reinterpret_cast<uint16_t*
>(local_data_) =
609 (*
reinterpret_cast<const uint16_t*
>(remote_data_)) << shift;
611 else if(num_bytes_ == 1) {
612 *
reinterpret_cast<uint8_t*
>(local_data_) =
613 (*
reinterpret_cast<const uint8_t*
>(remote_data_)) << shift;
622 template<
class DataT>
623 std::enable_if_t<std::is_integral_v<DataT>,
bool>
626 return *(
reinterpret_cast<const DataT*
>(remote_data_)) == dat;
635 return (num_bytes_ == other.num_bytes_) &&
636 (::memcmp(remote_data_, other.remote_data_, num_bytes_) == 0);
646 template<
class DataT>
647 void set(
const DataT & masked_bits) {
650 ::memcpy(local_data_,
reinterpret_cast<const uint8_t*
>(&masked_bits),
sizeof(DataT));
660 void fill(
const uint8_t fill_data) {
662 ::memset(local_data_, fill_data, num_bytes_);
671 return remote_data_ + idx;
695 template <
typename T,
696 typename =
typename std::enable_if<std::is_integral<T>::value>::type>
699 ::memcpy(&ret_data, remote_data_, std::min(
sizeof(T), (
size_t)num_bytes_));
707 uint32_t
getSize()
const {
return num_bytes_; }
715 const auto mem_data_plus_one = remote_data_ + 1;
716 return (::memcmp(remote_data_, mem_data_plus_one, num_bytes_ - 1) == 0);
729 std::array<uint8_t, 8> local_storage_;
730 std::unique_ptr<uint8_t[]> local_storage_alt_;
731 uint8_t * local_data_ =
nullptr;
732 const uint8_t * remote_data_ =
nullptr;
733 const uint64_t num_bytes_ = 0;
Set of macros for Sparta assertions. Caught by the framework.
#define sparta_assert(...)
Simple variadic assertion that will throw a sparta_exception if the condition fails.
uint32_t getSize() const
Get the number of bytes.
RegisterBits operator~() const
"not" this class
void set(const DataT &masked_bits)
Set the given masked_bits in this RegisterBits instance.
const uint8_t * operator[](const uint32_t idx) const
Get the data offset at the given index.
uint8_t * data()
Get the internal data pointer.
RegisterBits operator>>(uint32_t shift) const
Shift this instance right and return a copy.
RegisterBits(std::nullptr_t)
Create a nullptr version of the data. This would be an invalid class.
RegisterBits(const uint64_t num_bytes)
Create an empty class with the given number of bytes.
T dataAs() const
Get the internal data as the given dta type.
bool operator==(const RegisterBits &other) const
Compare the register bits to another.
bool none() const
Returns true if no bits are set.
std::enable_if_t< std::is_integral_v< DataT >, bool > operator==(const DataT dat) const
Compare the register bits to the given data.
RegisterBits operator<<(uint32_t shift) const
Shift this instance left and return a copy.
bool any() const
Returns true if any bit is set.
void fill(const uint8_t fill_data)
Fill the RegisterBits with the given fill_data.
RegisterBits(const RegisterBits &orig)
Make a copy.
RegisterBits(uint8_t *data_ptr, const size_t num_bytes)
Create a class pointing into the given data, of the given size.
void operator<<=(uint32_t shift)
Shift this instance left.
RegisterBits(RegisterBits &&orig)
Move.
RegisterBits(const uint8_t *data, const size_t num_bytes)
Create a class pointing into the given data constantly, of the given size.
RegisterBits(const uint64_t num_bytes, const DataT &data)
Create a class with the given number of bytes and initialize it to the given data.
const uint8_t * data() const
Get the internal data pointer.
RegisterBits operator&(const RegisterBits &rh_bits) const
"and" together two classes
RegisterBits operator|(const RegisterBits &rh_bits) const
"or" together two classes
Macros for handling exponential backoff.