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);
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);
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_;
466 offset_type line_size=DEFAULT_LINE_SIZE,
469 bool can_free_lines=
true) :
470 owner_node_(owner_node),
471 line_size_(line_size),
473 initial_val_size_(initial_val_size),
476 num_lines_laid_out_(0),
479 layout_padding_waste_(0),
480 layout_line_waste_(0),
481 can_free_lines_(can_free_lines)
484 "ArchData initial_val_size type must be a power of 2 between 1 and 8 inclusive, is "
485 << initial_val_size_);
486 sparta_assert((initial_val_size_ == 8) || (initial >> (uint64_t)(8*initial_val_size_) == 0),
487 "ArchData initial val has nonzero bits above initial_val_size. initial val: "
488 << std::hex << initial_ <<
" initial_val_size:" << std::dec << initial_val_size_);
492 double tmp = log2(line_size);
493 if(tmp != floor(tmp)){
498 line_lsb_ = (offset_type)tmp;
499 line_mask_ = ~((1 << line_lsb_) - 1);
503 line_lsb_ =
sizeof(offset_type) * 8;
504 line_mask_ = (offset_type)0;
508 owner_node_->associateArchData_(
this);
511 all_archdatas_->push_back(
this);
518 owner_node_->disassociateArchData_(
this);
522 auto itr = std::find(all_archdatas_->begin(), all_archdatas_->end(),
this);
524 all_archdatas_->erase(itr);
531 for(LineMap::iterator eitr = line_map_.begin(); eitr != line_map_.end(); ++eitr){
553 throw SpartaException(
"This ArchData has already been laid out. New segments cannot be registered (segment id=")
562 << std::hex << (
void*)seg <<
" with id=0x" << seg->
getLayoutID() <<
" already exists in ArchData @"
563 << (
void*)
this << std::dec;
567 << std::hex <<
"0x" << seg->
getLayoutID() <<
" already exists in ArchData @"
568 << (
void*)
this << std::dec;
572 seg_list_.push_back(seg);
610 LayoutHelperMap::const_iterator it;
613 ArchDataSegment::ident_type lid = seg->getLayoutID();
616 it = helper_map.find(seg->getLayoutID());
617 if(it != helper_map.end()){
619 << it->first <<
" in the same ArchData @" << (
void*)
this;
622 helper_map[seg->getLayoutID()] = seg;
629 placeSegment_(seg, helper_map);
657 if(seg_list_.size() != 0){
659 << seg_list_.size() <<
" segments so it cannot be layed out using layoutRange";
682 "Cannot access this ArchData at offset: 0x"
683 << std::hex << offset <<
" ArchData size= "
691 if((lnitr = line_map_.
find(ln_idx)) ==
nullptr){
692 ln = allocateLine_(ln_idx);
696 ln = line_map_.
find(ln_idx)->second;
716 "Cannot access this ArchData at offset: 0x"
717 << std::hex << offset <<
" ArchData size= "
724 if((lnitr = line_map_.
find(ln_idx)) ==
nullptr){
727 return lnitr->second;
736 if(
false == is_laid_out_){
737 throw SpartaException(
"Cannot get ArchData lines map until layout completes");
757 if(
false == is_laid_out_){
763 for(LineMap::iterator itr = line_map_.begin(); itr != line_map_.end(); ++itr){
771 for(LineMap::iterator itr = line_map_.begin(); itr != line_map_.end(); ++itr){
772 (*itr)->fillWithInitial(initial_, initial_val_size_);
804 return line_map_.
size();
814 return offset >> line_lsb_;
827 return line_size_ * idx;
866 "Generic access validity test on ArchData::line offset 0x" << std::hex
867 << offset <<
" with size " << std::dec << bytes <<
" B");
881 return offset < size_;
892 static_assert(std::is_unsigned<offset_type>::value ==
true);
895 << size <<
") must be larger than 0 and less than line size ("
896 << line_size_ <<
")";
898 if(line_size_ != 0 && size > line_size_){
900 << size <<
") exceeds that of an ArchData line (" << line_size_ <<
")";
919 if(__builtin_expect((offset + size) > size_, 0)){
921 << std::hex << offset+size <<
") extends pased end of ArchData (0x"
922 << size_ <<
") by " << std::dec << (offset + size) - size_ <<
" B";
934 if(__builtin_expect((offset + size) - (offset & line_mask_) > line_size_, 0)){
947 virtual void updateFrom(
const ArchData& other)
950 for (LineMap::const_iterator itr = other.line_map_.begin(); itr != other.line_map_.end(); ++itr) {
951 const Line* other_ln = *itr;
952 if (other_ln !=
nullptr) {
956 if (pln !=
nullptr) {
958 pln->second->updateFrom(*other_ln);
961 Line* ln = allocateLine_(other_idx);
962 ln->updateFrom(*other_ln);
979 template <
typename StorageT>
983 "Saving delta checkpoint to bad ostream for " <<
getOwnerNode()->getLocation());
985 for(LineMap::iterator itr = line_map_.begin(); itr != line_map_.end(); ++itr){
987 if(ln !=
nullptr && ln->
isDirty()){
988 out.beginLine(ln->
getIdx());
1000 template <
typename StorageT>
1003 "Saving delta checkpoint to bad ostream for " <<
getOwnerNode()->getLocation());
1005 for(LineMap::iterator itr = line_map_.begin(); itr != line_map_.end(); ++itr){
1008 out.beginLine(ln->
getIdx());
1022 template <
typename StorageT>
1026 "Encountered bad checkpoint data (invalid stream) for " <<
getOwnerNode()->getLocation());
1045 template <
typename StorageT>
1078 owner_node_->associateArchData_(
this);
1095 if(
false == is_laid_out_){
1096 throw SpartaException(
"Cannot get layout size until layout completes");
1112 return initial_val_size_;
1117 return layout_padding_waste_ + layout_line_waste_;
1122 return layout_padding_waste_;
1127 return layout_line_waste_;
1149 if(
false == is_laid_out_){
1150 throw SpartaException(
"Cannot dump ArchData layout until layout completes");
1156 offset_type last_line_off = 0;
1157 offset_type last_end = 0;
1159 dumpLayout_(o, sorted, last_line_off, last_end,
true);
1179 std::vector<std::string> result;
1180 for(LineMap::const_iterator itr = line_map_.begin(); itr != line_map_.end(); ++itr){
1181 const Line* ln = *itr;
1182 std::stringstream state;
1183 state << std::setw(5) << std::hex << ln->
getIdx()
1194 result.push_back(state.str());
1199 uint64_t getNumTiers()
const {
1218 return *all_archdatas_;
1240 template <
typename FillT>
1241 static void fillWith_(uint8_t* buf, uint32_t size, FillT fill, uint16_t buf_offset=0) {
1245 "Cannot have a buf_offset larger than FillT size. Must be buffer offset % fill size");
1248 const FillT shifted_fill = (fill >> (buf_offset * 8)) | (fill << ((
sizeof(FillT) - buf_offset) * 8));
1251 if(
sizeof(FillT) >= size) {
1254 memcpy(buf,
static_cast<const void*
>(&shifted_fill), size);
1261 const uint8_t*
const end = buf + size;
1263 "buf (" << (
void*)buf <<
") was too large and adding size (" << size <<
") rolled over to 0");
1266 const uint8_t*
const stop = end -
sizeof(FillT);
1273 memcpy(
static_cast<void*
>(ptr),
static_cast<const void*
>(&shifted_fill),
sizeof(FillT));
1274 ptr +=
sizeof(FillT);
1275 sparta_assert(ptr >= buf,
"ptr overflowed when adding fill size (" <<
sizeof(FillT) <<
")");
1279 int32_t rem = end - ptr;
1281 "fillWith_ remainder size was 0x" << std::hex << rem
1282 <<
" ptr=" << (
void*)ptr <<
" end=" << (
const void*)end
1283 <<
" sizeof(FillT)=" <<
sizeof(FillT));
1285 "Somehow encountered a null pointer during arithmetic based on a pointer at " << (
void*) buf);
1291 memcpy(
static_cast<void*
>(ptr),
static_cast<const void*
>(&shifted_fill), rem);
1307 void dumpLayout_(std::ostream& o,
1309 offset_type last_line_off,
1310 offset_type last_end,
1311 bool show_line_nums)
const {
1315 o <<
'x' << std::hex << std::setw(5) << std::right << (last_end & line_mask_) <<
": " << std::dec;
1320 SegmentList::const_iterator it;
1321 std::vector<ArchDataSegment*> nestings;
1322 for(it = sorted.begin(); it != sorted.end(); ++it){
1323 offset_type off = (*it)->getOffset();
1326 if(last_line_off != (off & line_mask_)){
1328 dumpSkippedBytes_(o, (off & line_mask_) - last_end,
true,
true);
1332 if(nestings.size() > 0){
1333 dumpLayout_(o, nestings, last_line_off, last_line_off,
false);
1339 o <<
'x' << std::hex << std::setw(5) << std::right << (last_end & line_mask_) <<
": " << std::dec;
1344 last_line_off = (off & line_mask_);
1345 last_end = last_line_off;
1349 nestings.push_back(*it);
1353 offset_type jump = off - last_end;
1354 dumpSkippedBytes_(o, jump,
false,
false);
1357 offset_type size = (*it)->getLayoutSize();
1360 }
else if(size == 2){
1364 for(offset_type i=1; i<size; ++i){
1365 if(i == (offset_type)(size/2)){
1366 o << std::left << std::dec;
1368 o << std::setw(4) << size;
1369 }
else if(size >= 100){
1370 o << std::setw(3) << size;
1371 }
else if(size >= 10){
1372 o << std::setw(2) << size;
1374 o << std::setw(1) << size;
1377 if(size >= 1000 && (i > (size/2)+1 && i < (size/2)+3)){
1379 }
else if(size >= 100 && (i > (size/2)+1 && i < (size/2)+2)){
1381 }
else if(size >= 10 && i == (size/2)+1){
1390 last_end = off + size;
1394 if((last_end & ~line_mask_) == 0){
1395 o <<
'|' << std::endl;
1398 offset_type leftover = line_size_ - (last_end & ~line_mask_);
1399 dumpSkippedBytes_(o, leftover,
true,
true);
1404 if(nestings.size() > 0){
1405 dumpLayout_(o, nestings, last_line_off, last_line_off,
false);
1421 void dumpSkippedBytes_(std::ostream& o,
1424 bool end_row)
const {
1429 }
else if(num <= 16 || !condense){
1431 for(offset_type i=1; i < num; ++i){
1437 o <<
"|+ " << std::dec << num <<
" ";
1452 if(idx * line_size_ > size_){
1453 throw SpartaException(
"Cannot allocate Line at idx ")
1455 <<
" because idx*line_size is 0x"
1456 << std::hex << (idx * line_size_)
1457 <<
"and the current ArchData size is only 0x" << size_;
1463 if(line_map_.
find(idx) !=
nullptr){
1464 throw SpartaException(
"Line is already allocated at index ") << idx;
1469 if(0 == line_size_){
1471 throw SpartaException(
"Cannot allocate a line at index other than 0 when ArchData line size is 0 (infinite)");
1475 Line* ln =
new Line(0, 0, size_, initial_, initial_val_size_);
1487 Line* ln =
new Line(idx, ln_off, line_size_, initial_, initial_val_size_);
1495 line_map_[idx] = ln;
1513 void placeSegment_(ArchDataSegment* seg,
1519 if(seg->isPlaced()){
1529 offset_type placement = 0;
1530 const offset_type size = seg->getLayoutSize();
1531 LayoutHelperMap::iterator it;
1536 ArchDataSegment::ident_type sub_of = seg->getSubsetOf();
1544 it = helper_map.find(sub_of);
1545 if(it == helper_map.end()){
1546 throw SpartaException(
"A Segment with identifier ")
1547 << seg->getLayoutID() <<
" claimed to be a "
1548 <<
"subset of Segment with identifier "
1549 << sub_of <<
", which does not exist in this ArchData";
1551 ArchDataSegment* parent_seg = it->second;
1555 placeSegment_(it->second, helper_map, depth+1);
1558 if(seg->getLayoutSize() + seg->getSubsetOffset() > parent_seg->getLayoutSize()){
1559 throw SpartaException(
"Segment id=")
1560 << seg->getLayoutID() <<
" had size 0x" << std::hex << seg->getLayoutSize()
1561 <<
" and subset offset 0x" << std::hex << seg->getSubsetOffset()
1562 <<
" which makes it larger than the parent id=" << std::dec
1563 << parent_seg->getLayoutID() <<
" with size " << std::hex
1564 << parent_seg->getLayoutSize() <<
" of which it is a child";
1566 placement = parent_seg->getOffset() + seg->getSubsetOffset();
1576 layout_padding_waste_ += delta;
1582 offset_type start_line_addr = size_ & line_mask_;
1583 offset_type end_line_addr = (size_ + size - 1) & line_mask_;
1584 if(start_line_addr != end_line_addr){
1588 offset_type next = (size_ & line_mask_) + line_size_;
1589 layout_line_waste_ += next - size_;
1595 ++num_lines_laid_out_;
1596 }
else if(start_line_addr >= num_lines_laid_out_ * line_size_){
1603 ++num_lines_laid_out_;
1611 seg->place(placement);
1622 TreeNode *owner_node_ =
nullptr;
1627 offset_type line_size_;
1632 const uint64_t initial_;
1637 const uint32_t initial_val_size_;
1642 offset_type line_lsb_;
1647 offset_type line_mask_;
1652 uint32_t num_lines_laid_out_;
1677 uint32_t layout_padding_waste_;
1683 uint32_t layout_line_waste_;
1688 bool can_free_lines_;
1694 static std::vector<const ArchData*> *all_archdatas_;
1702#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...
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::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.
std::vector< ArchDataSegment * > SegmentList
ArchData line index.
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...
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.
std::vector< ArchDataSegment * > LayoutHelperVector
Vector of ArchDataSegment pointers.
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.
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.
std::list< Line * > LineList
List of ArchDataSegment.
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.
TieredMap< line_idx_type, Line * > LineMap
List of Line pointers.
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...
uint64_t getNumTiers() const
Number of tiers used by this map to represent the entire space containing the largest key added....
std::pair< const line_idx_type, Line * > pair_t
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.
std::enable_if< std::is_same< boost::mpl::int_< BO >, boost::mpl::int_< BE > >::value, T >::type reorder(const T &t)
bool isPowerOf2(uint64_t x)
Determines if input is 0 or a power of 2.