12#include <unordered_map>
16#include "sparta/utils/TieredMap.hpp"
17#include "sparta/utils/Utils.hpp"
19#include "sparta/functional/ArchDataSegment.hpp"
58 typedef ArchDataSegment::offset_type offset_type;
69 typedef std::unordered_map<ArchDataSegment::ident_type, ArchDataSegment*>
LayoutHelperMap;
88 static const offset_type DEFAULT_LINE_SIZE = 512;
127 static void fillValue(uint8_t* buf, uint32_t size, uint64_t fill, uint16_t fill_val_size, uint16_t fill_pattern_offset=0) {
128 switch(fill_val_size) {
130 memset(buf, fill, size);
133 fillWith_<uint16_t>(buf, size,
static_cast<uint16_t
>(fill), fill_pattern_offset);
136 fillWith_<uint32_t>(buf, size,
static_cast<uint32_t
>(fill), fill_pattern_offset);
139 fillWith_<uint64_t>(buf, size,
static_cast<uint64_t
>(fill), fill_pattern_offset);
143 << std::hex << fill <<
" because fill value size was " << std::dec
187 uint32_t initial_val_size,
188 uint8_t* pool_ptr=0) :
192 is_pool_(pool_ptr != 0),
201 alloc_data_.reset(
new uint8_t[size]);
202 data_ = alloc_data_.get();
212 Line & operator=(
const Line &) =
delete;
214 void updateFrom(
const Line& other)
217 memcpy(data_, other.data_, size_);
248 template <
typename StorageT>
250 in.copyLineBytes((
char*)data_, size_);
263 template <
typename StorageT>
265 out.writeLineBytes((
char*)data_, size_);
315 template <
typename T, ByteOrder BO>
316 T
read(offset_type offset, uint32_t idx=0)
const {
317 offset_type loc = offset + (idx*
sizeof(T));
319 "Read at ArchData::line offset 0x" << std::hex
320 << loc <<
" with size " << std::dec <<
sizeof(T) <<
" B");
322 uint8_t* d = data_ + loc;
324 T val = *
reinterpret_cast<T*
>(d);
325 return reorder<T,BO>(val);
335 void read(offset_type offset, offset_type size, uint8_t* data)
const {
337 "Read on ArchData::line offset 0x" << std::hex
338 << offset <<
" with size " << std::dec << size <<
" B");
340 memcpy(data, data_ + offset, size);
353 template <
typename T, ByteOrder BO>
354 void write(offset_type offset,
const T& t, uint32_t idx=0) {
355 offset_type loc = offset + (idx*
sizeof(T));
357 "Write on ArchData::line offset 0x" << std::hex
358 << loc <<
" with size " << std::dec <<
sizeof(T) <<
" B");
360 uint8_t* d = data_ + loc;
363 T& val = *
reinterpret_cast<T*
>(d);
364 val = reorder<T,BO>(t);
375 void write(offset_type offset, offset_type size,
const uint8_t* data)
const {
377 "Read on ArchData::line offset 0x" << std::hex
378 << offset <<
" with size " << std::dec << size <<
" B");
380 memcpy(data_ + offset, data, size);
396 return data_ + offset;
403 uint8_t*
getRawDataPtr(
const offset_type offset) {
return (data_ + offset); }
412 uint8_t * data_ =
nullptr;
413 std::unique_ptr<uint8_t[]> alloc_data_;
449 offset_type line_size=DEFAULT_LINE_SIZE,
452 bool can_free_lines=
true) :
453 owner_node_(owner_node),
454 line_size_(line_size),
456 initial_val_size_(initial_val_size),
459 num_lines_laid_out_(0),
462 layout_padding_waste_(0),
463 layout_line_waste_(0),
464 can_free_lines_(can_free_lines)
467 "ArchData initial_val_size type must be a power of 2 between 1 and 8 inclusive, is "
468 << initial_val_size_);
469 sparta_assert((initial_val_size_ == 8) || (initial >> (uint64_t)(8*initial_val_size_) == 0),
470 "ArchData initial val has nonzero bits above initial_val_size. initial val: "
471 << std::hex << initial_ <<
" initial_val_size:" << std::dec << initial_val_size_);
475 double tmp = log2(line_size);
476 if(tmp != floor(tmp)){
481 line_lsb_ = (offset_type)tmp;
482 line_mask_ = ~((1 << line_lsb_) - 1);
486 line_lsb_ =
sizeof(offset_type) * 8;
487 line_mask_ = (offset_type)0;
491 owner_node_->associateArchData_(
this);
494 all_archdatas_->push_back(
this);
501 owner_node_->disassociateArchData_(
this);
505 auto itr = std::find(all_archdatas_->begin(), all_archdatas_->end(),
this);
507 all_archdatas_->erase(itr);
514 for(LineMap::iterator eitr = line_map_.begin(); eitr != line_map_.end(); ++eitr){
536 throw SpartaException(
"This ArchData has already been laid out. New segments cannot be registered (segment id=")
545 << std::hex << (
void*)seg <<
" with id=0x" << seg->
getLayoutID() <<
" already exists in ArchData @"
546 << (
void*)
this << std::dec;
550 << std::hex <<
"0x" << seg->
getLayoutID() <<
" already exists in ArchData @"
551 << (
void*)
this << std::dec;
555 seg_list_.push_back(seg);
593 LayoutHelperMap::const_iterator it;
596 ArchDataSegment::ident_type lid = seg->getLayoutID();
599 it = helper_map.find(seg->getLayoutID());
600 if(it != helper_map.end()){
602 << it->first <<
" in the same ArchData @" << (
void*)
this;
605 helper_map[seg->getLayoutID()] = seg;
612 placeSegment_(seg, helper_map);
640 if(seg_list_.size() != 0){
642 << seg_list_.size() <<
" segments so it cannot be layed out using layoutRange";
665 "Cannot access this ArchData at offset: 0x"
666 << std::hex << offset <<
" ArchData size= "
674 if((lnitr = line_map_.
find(ln_idx)) ==
nullptr){
675 ln = allocateLine_(ln_idx);
679 ln = line_map_.
find(ln_idx)->second;
699 "Cannot access this ArchData at offset: 0x"
700 << std::hex << offset <<
" ArchData size= "
707 if((lnitr = line_map_.
find(ln_idx)) ==
nullptr){
710 return lnitr->second;
719 if(
false == is_laid_out_){
720 throw SpartaException(
"Cannot get ArchData lines map until layout completes");
740 if(
false == is_laid_out_){
746 for(LineMap::iterator itr = line_map_.begin(); itr != line_map_.end(); ++itr){
754 for(LineMap::iterator itr = line_map_.begin(); itr != line_map_.end(); ++itr){
755 (*itr)->fillWithInitial(initial_, initial_val_size_);
787 return line_map_.
size();
797 return offset >> line_lsb_;
810 return line_size_ * idx;
849 "Generic access validity test on ArchData::line offset 0x" << std::hex
850 << offset <<
" with size " << std::dec << bytes <<
" B");
864 return offset < size_;
875 static_assert(std::is_unsigned<offset_type>::value ==
true);
878 << size <<
") must be larger than 0 and less than line size ("
879 << line_size_ <<
")";
881 if(line_size_ != 0 && size > line_size_){
883 << size <<
") exceeds that of an ArchData line (" << line_size_ <<
")";
902 if(__builtin_expect((offset + size) > size_, 0)){
904 << std::hex << offset+size <<
") extends pased end of ArchData (0x"
905 << size_ <<
") by " << std::dec << (offset + size) - size_ <<
" B";
917 if(__builtin_expect((offset + size) - (offset & line_mask_) > line_size_, 0)){
930 virtual void updateFrom(
const ArchData& other)
933 for (LineMap::const_iterator itr = other.line_map_.begin(); itr != other.line_map_.end(); ++itr) {
934 const Line* other_ln = *itr;
935 if (other_ln !=
nullptr) {
939 if (pln !=
nullptr) {
941 pln->second->updateFrom(*other_ln);
944 Line* ln = allocateLine_(other_idx);
945 ln->updateFrom(*other_ln);
962 template <
typename StorageT>
966 "Saving delta checkpoint to bad ostream for " <<
getOwnerNode()->getLocation());
968 for(LineMap::iterator itr = line_map_.begin(); itr != line_map_.end(); ++itr){
970 if(ln !=
nullptr && ln->
isDirty()){
971 out.beginLine(ln->
getIdx());
983 template <
typename StorageT>
986 "Saving delta checkpoint to bad ostream for " <<
getOwnerNode()->getLocation());
988 for(LineMap::iterator itr = line_map_.begin(); itr != line_map_.end(); ++itr){
991 out.beginLine(ln->
getIdx());
1005 template <
typename StorageT>
1009 "Encountered bad checkpoint data (invalid stream) for " <<
getOwnerNode()->getLocation());
1028 template <
typename StorageT>
1061 owner_node_->associateArchData_(
this);
1078 if(
false == is_laid_out_){
1079 throw SpartaException(
"Cannot get layout size until layout completes");
1095 return initial_val_size_;
1100 return layout_padding_waste_ + layout_line_waste_;
1105 return layout_padding_waste_;
1110 return layout_line_waste_;
1132 if(
false == is_laid_out_){
1133 throw SpartaException(
"Cannot dump ArchData layout until layout completes");
1139 offset_type last_line_off = 0;
1140 offset_type last_end = 0;
1142 dumpLayout_(o, sorted, last_line_off, last_end,
true);
1162 std::vector<std::string> result;
1163 for(LineMap::const_iterator itr = line_map_.begin(); itr != line_map_.end(); ++itr){
1164 const Line* ln = *itr;
1165 std::stringstream state;
1166 state << std::setw(5) << std::hex << ln->
getIdx()
1177 result.push_back(state.str());
1182 uint64_t getNumTiers()
const {
1201 return *all_archdatas_;
1223 template <
typename FillT>
1224 static void fillWith_(uint8_t* buf, uint32_t size, FillT fill, uint16_t buf_offset=0) {
1228 "Cannot have a buf_offset larger than FillT size. Must be buffer offset % fill size");
1231 const FillT shifted_fill = (fill >> (buf_offset * 8)) | (fill << ((
sizeof(FillT) - buf_offset) * 8));
1234 if(
sizeof(FillT) >= size) {
1237 memcpy(buf,
static_cast<const void*
>(&shifted_fill), size);
1244 const uint8_t*
const end = buf + size;
1246 "buf (" << (
void*)buf <<
") was too large and adding size (" << size <<
") rolled over to 0");
1249 const uint8_t*
const stop = end -
sizeof(FillT);
1256 memcpy(
static_cast<void*
>(ptr),
static_cast<const void*
>(&shifted_fill),
sizeof(FillT));
1257 ptr +=
sizeof(FillT);
1258 sparta_assert(ptr >= buf,
"ptr overflowed when adding fill size (" <<
sizeof(FillT) <<
")");
1262 int32_t rem = end - ptr;
1264 "fillWith_ remainder size was 0x" << std::hex << rem
1265 <<
" ptr=" << (
void*)ptr <<
" end=" << (
const void*)end
1266 <<
" sizeof(FillT)=" <<
sizeof(FillT));
1268 "Somehow encountered a null pointer during arithmetic based on a pointer at " << (
void*) buf);
1274 memcpy(
static_cast<void*
>(ptr),
static_cast<const void*
>(&shifted_fill), rem);
1290 void dumpLayout_(std::ostream& o,
1292 offset_type last_line_off,
1293 offset_type last_end,
1294 bool show_line_nums)
const {
1298 o <<
'x' << std::hex << std::setw(5) << std::right << (last_end & line_mask_) <<
": " << std::dec;
1303 SegmentList::const_iterator it;
1304 std::vector<ArchDataSegment*> nestings;
1305 for(it = sorted.begin(); it != sorted.end(); ++it){
1306 offset_type off = (*it)->getOffset();
1309 if(last_line_off != (off & line_mask_)){
1311 dumpSkippedBytes_(o, (off & line_mask_) - last_end,
true,
true);
1315 if(nestings.size() > 0){
1316 dumpLayout_(o, nestings, last_line_off, last_line_off,
false);
1322 o <<
'x' << std::hex << std::setw(5) << std::right << (last_end & line_mask_) <<
": " << std::dec;
1327 last_line_off = (off & line_mask_);
1328 last_end = last_line_off;
1332 nestings.push_back(*it);
1336 offset_type jump = off - last_end;
1337 dumpSkippedBytes_(o, jump,
false,
false);
1340 offset_type size = (*it)->getLayoutSize();
1343 }
else if(size == 2){
1347 for(offset_type i=1; i<size; ++i){
1348 if(i == (offset_type)(size/2)){
1349 o << std::left << std::dec;
1351 o << std::setw(4) << size;
1352 }
else if(size >= 100){
1353 o << std::setw(3) << size;
1354 }
else if(size >= 10){
1355 o << std::setw(2) << size;
1357 o << std::setw(1) << size;
1360 if(size >= 1000 && (i > (size/2)+1 && i < (size/2)+3)){
1362 }
else if(size >= 100 && (i > (size/2)+1 && i < (size/2)+2)){
1364 }
else if(size >= 10 && i == (size/2)+1){
1373 last_end = off + size;
1377 if((last_end & ~line_mask_) == 0){
1378 o <<
'|' << std::endl;
1381 offset_type leftover = line_size_ - (last_end & ~line_mask_);
1382 dumpSkippedBytes_(o, leftover,
true,
true);
1387 if(nestings.size() > 0){
1388 dumpLayout_(o, nestings, last_line_off, last_line_off,
false);
1404 void dumpSkippedBytes_(std::ostream& o,
1407 bool end_row)
const {
1412 }
else if(num <= 16 || !condense){
1414 for(offset_type i=1; i < num; ++i){
1420 o <<
"|+ " << std::dec << num <<
" ";
1435 if(idx * line_size_ > size_){
1436 throw SpartaException(
"Cannot allocate Line at idx ")
1438 <<
" because idx*line_size is 0x"
1439 << std::hex << (idx * line_size_)
1440 <<
"and the current ArchData size is only 0x" << size_;
1446 if(line_map_.
find(idx) !=
nullptr){
1447 throw SpartaException(
"Line is already allocated at index ") << idx;
1452 if(0 == line_size_){
1454 throw SpartaException(
"Cannot allocate a line at index other than 0 when ArchData line size is 0 (infinite)");
1458 Line* ln =
new Line(0, 0, size_, initial_, initial_val_size_);
1470 Line* ln =
new Line(idx, ln_off, line_size_, initial_, initial_val_size_);
1478 line_map_[idx] = ln;
1496 void placeSegment_(ArchDataSegment* seg,
1502 if(seg->isPlaced()){
1512 offset_type placement = 0;
1513 const offset_type size = seg->getLayoutSize();
1514 LayoutHelperMap::iterator it;
1519 ArchDataSegment::ident_type sub_of = seg->getSubsetOf();
1527 it = helper_map.find(sub_of);
1528 if(it == helper_map.end()){
1529 throw SpartaException(
"A Segment with identifier ")
1530 << seg->getLayoutID() <<
" claimed to be a "
1531 <<
"subset of Segment with identifier "
1532 << sub_of <<
", which does not exist in this ArchData";
1534 ArchDataSegment* parent_seg = it->second;
1538 placeSegment_(it->second, helper_map, depth+1);
1541 if(seg->getLayoutSize() + seg->getSubsetOffset() > parent_seg->getLayoutSize()){
1542 throw SpartaException(
"Segment id=")
1543 << seg->getLayoutID() <<
" had size 0x" << std::hex << seg->getLayoutSize()
1544 <<
" and subset offset 0x" << std::hex << seg->getSubsetOffset()
1545 <<
" which makes it larger than the parent id=" << std::dec
1546 << parent_seg->getLayoutID() <<
" with size " << std::hex
1547 << parent_seg->getLayoutSize() <<
" of which it is a child";
1549 placement = parent_seg->getOffset() + seg->getSubsetOffset();
1559 layout_padding_waste_ += delta;
1565 offset_type start_line_addr = size_ & line_mask_;
1566 offset_type end_line_addr = (size_ + size - 1) & line_mask_;
1567 if(start_line_addr != end_line_addr){
1571 offset_type next = (size_ & line_mask_) + line_size_;
1572 layout_line_waste_ += next - size_;
1578 ++num_lines_laid_out_;
1579 }
else if(start_line_addr >= num_lines_laid_out_ * line_size_){
1586 ++num_lines_laid_out_;
1594 seg->place(placement);
1605 TreeNode *owner_node_ =
nullptr;
1610 offset_type line_size_;
1615 const uint64_t initial_;
1620 const uint32_t initial_val_size_;
1625 offset_type line_lsb_;
1630 offset_type line_mask_;
1635 uint32_t num_lines_laid_out_;
1660 uint32_t layout_padding_waste_;
1666 uint32_t layout_line_waste_;
1671 bool can_free_lines_;
1677 static std::vector<const ArchData*> *all_archdatas_;
1685#define SPARTA_ARCHDATA_BODY
Byte order types and byte-swapping routines.
Set of macros for Sparta assertions. Caught by the framework.
#define sparta_abort(...)
Simple variatic assertion that will print a message to std::cerr and call std::terminate()
#define sparta_assert(...)
Simple variadic assertion that will throw a sparta_exception if the condition fails.
Exception class for all of Sparta.
Helpers for enforcing StaticInitialization order.
Basic Node framework in sparta device tree composite pattern.
static const ident_type INVALID_ID
Indicates an invalid ID for an ArchDataSegment or any refinement.
offset_type getOffset() const
Gets the offset of this segment once placed.
ident_type getLayoutID() const
Gets the layout Identifier of this segment.
offset_type getLayoutSize() const
Gets the layout size of this segment (number of bytes)
Line object which composes part of an entire ArchData.
uint8_t * getRawDataPtr(const offset_type offset)
return the raw data pointer for this line for direct read and write. No error checking is performed....
void write(offset_type offset, const T &t, uint32_t idx=0)
Write to this line, reordering bytes based on byte order if required.
void restore(StorageT &in)
Restore data from input buffer.
T read(offset_type offset, uint32_t idx=0) const
Read from this line, reordering bytes based on byte order if required.
const uint8_t * getDataPointer(offset_type offset) const
Gets a pointer to data within this line for direct read access.
Line(line_idx_type idx, offset_type offset, offset_type size, uint64_t initial, uint32_t initial_val_size, uint8_t *pool_ptr=0)
Line constructor.
bool isDirty() const
Has this line been modified since the last save or restore. Immediately after construction,...
void save(StorageT &out)
Store data to output buffer.
offset_type getLayoutSize() const
Size of this line's data including padding. Accessing bytes from this line with an offset greater tha...
Line(const Line &)=delete
Disallow copies, moves, and assignments.
void read(offset_type offset, offset_type size, uint8_t *data) const
Read a number of contiguous bytes from this line.
static const uint32_t QUICK_CHECKPOINT_OFFSET_SIZE
Size of offset and size entries in quick checkpoint.
offset_type getOffset() const
Offset into the owning ArchData.
void flagDirty()
Allows caller to explicitly flag this line as dirty.
void write(offset_type offset, offset_type size, const uint8_t *data) const
Write a number of contiguous bytes to this line.
line_idx_type getIdx() const
Index of this line (typically offset/line_size)
void fillWithInitial(uint64_t initial, uint32_t initial_val_size)
Fills the line's data with the initial value.
static constexpr char QUICK_CHECKPOINT_PREFIX[]
Prefix for Line checkpoint entries.
Contains a set of contiguous line of architectural data which can be referred to by any architected o...
TieredMap< line_idx_type, Line * > LineMap
List of Line pointers.
bool containsAddress(offset_type offset) const noexcept
Determines if this ArchData contains a byte for the specified address.
const TreeNode * getOwnerNode() const
Returns the owner TreeNode.
offset_type getLineOffset(line_idx_type idx) const
Gets offset associated with a particular line that exists in this ArchData.
std::list< Line * > LineList
List of ArchDataSegment.
std::unordered_map< ArchDataSegment::ident_type, ArchDataSegment * > LayoutHelperMap
Helper map for quick lookup from ArchDataSegment::ident_type to an ArchDataSegment*.
uint64_t getInitial() const
Gets the value used to initialize unwritten memory.
line_idx_type getNumAllocatedLines() const
Gets the number of lines with allocated data;.
void dumpLayout(std::ostream &o) const
Prints content of each ArchData Line in order.
const SegmentList getSegments() const
Gets the list of segments within this ArchData.
void setOwnerNode(TreeNode *node)
Set the owner tree node.
static const uint64_t DEFAULT_INITIAL_FILL
Default initial fill value for an ArchData when allocated.
bool isLaidOut() const
Has this ArchData been laid out yet.
uint32_t getInitialValSize() const
Gets the size of the initial value.
std::vector< std::string > getLineStates() const
Gets state information for each line in this ArchData.
void restoreAll(StorageT &in)
Restores a full checkpoint snapshot (not a delta). This removes all lines NOT found in the snapshot d...
std::vector< ArchDataSegment * > LayoutHelperVector
Vector of ArchDataSegment pointers.
void clean()
Deletes (if possible) data held within the ArchData, restoring it to a 'clean-state'....
line_idx_type getLineIndex(offset_type offset) const
Gets Index of a line containing the specified offset.
uint32_t getPaddingWaste() const
Number of bytes wasted during layout because of optimal word-alignment.
static const line_idx_type INVALID_LINE_IDX
Invalid line index.
void layout()
Organizes the Segments into overlapping regions as needed, eventually calling ArchDataSegment::place ...
void restore(StorageT &in)
Restores a delta checkpoint (not a full snapshot). This contains only additive changes.
uint32_t getLineWaste() const
Number of bytes wasted during layout because of line-ending alignment.
void registerSegment(ArchDataSegment *seg)
All constructed segments must register themselves through this method to be laid out within the ArchD...
static const uint16_t DEFAULT_INITIAL_FILL_SIZE
Number of of bytes from DEFAULT_INITIAL_FILL to use as a default.
void saveAll(StorageT &out)
Writes snapshot checkpointing data (all lines) from this ArchData to a stream regardless of dirtiness...
void layoutRange(offset_type size)
Lays out the archdata to contain a range of addresses without specifying any segments.
void reset()
Cleans the ArchData (see clean) then applies all initial values through ArchDataSegment::writeInitial...
const LineMap & getLineMap() const
Only const access is allowed to internal map.
bool canFreeLines() const
Indicates whether this ArchData can free its lines after allocating them. Otherwise,...
static void fillValue(uint8_t *buf, uint32_t size, uint64_t fill, uint16_t fill_val_size, uint16_t fill_pattern_offset=0)
Fill a buffer with a fill pattern.
std::vector< ArchDataSegment * > SegmentList
ArchData line index.
void checkInSingleLine(offset_type offset, offset_type size) const
Determines whether the access defined by offset and size spans multiple ArchData Lines.
void checkCanAccess(offset_type offset, offset_type bytes) const
Determines if an access of size 'bytes' can be performed at the given offset based only on the size o...
offset_type line_idx_type
Represents offsets into this ArchData.
const Line * tryGetLine(offset_type offset) const
Gets the line associated with this offset only if it already exists.
static const offset_type MAX_LINE_SIZE
ArchData construction line size maximum in bytes.
uint32_t getTotalWaste() const
Number of bytes wasted total during layout for any reason.
uint32_t getNumSegments() const
Gets number of segments in this ArchData.
static bool compareSegmentOffsets(const ArchDataSegment *s1, const ArchDataSegment *s2)
Comparison functions for sorting by segment.
ArchData(TreeNode *owner_node=nullptr, offset_type line_size=DEFAULT_LINE_SIZE, uint64_t initial=DEFAULT_INITIAL_FILL, uint16_t initial_val_size=DEFAULT_INITIAL_FILL_SIZE, bool can_free_lines=true)
Constructor.
void checkSegment(offset_type offset, offset_type size) const
Checks that a segment is valid within this archdata by its given offset and size.
offset_type getLineSize() const
Gets the size of a line within this ArchData instance.
void save(StorageT &out)
Writes checkpointing data from this ArchData to a stream.
static const std::vector< const ArchData * > getAllArchDatas()
Static method to return a const vector of all ArchVectors that currently exist.
offset_type getSize() const
Gets the current size of the layout for this ArchData.
Line & getLine(offset_type offset)
Gets the line associated with this offset, allocating a new line if necessary.
void checkDataSize(offset_type size) const
Checks to see that the size of the data is a valid access size.
Used to construct and throw a standard C++ exception. Inherits from std::exception.
Static-initialization order controller.
N-Tier lookup map for sparse-representation of large memory spaces. This is essentially a M-Tree wher...
std::pair< const line_idx_type, Line * > pair_t
This map contains mappings between a unique set of keys to values. This type represents that mapping ...
uint64_t getNumTiers() const
Number of tiers used by this map to represent the entire space containing the largest key added....
const pair_t * find(const KeyT &k) const
Finds a mapping for key k if one exists in this map.
uint64_t size() const
Number of elements allocated in this map.
void clear()
Clears the map. Frees all mappings and data structures.
Node in a composite tree representing a sparta Tree item.
Macros for handling exponential backoff.
bool isPowerOf2(uint64_t x)
Determines if input is 0 or a power of 2.