Modernize/bitfield.cc: Make into C++ (#1917)

* Modernize bitfield.cc: Grouped member functions into the struct; C++ construction

* Modernize bitfield.cc: Naming style similar to qt/ C++ source

* Modernize bitfield.cc: Bitfield test updated to new API

* Modernize bitfield.cc: Renames for private functions

* Modernize bitfield.cc: Formatting

* Modernize bitfield.cc: Remove struct in 'struct Bitfield' and update commented code too

Co-authored-by: Charles Kerr <charles@charleskerr.com>
This commit is contained in:
Dmytro Lytovchenko 2021-10-11 19:29:14 +02:00 committed by GitHub
parent ac41837ae9
commit 39376f2105
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 422 additions and 405 deletions

View File

@ -37,41 +37,41 @@ static constexpr int8_t const trueBitCount[256] = {
4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8, //
};
static constexpr size_t countArray(tr_bitfield const* b)
constexpr size_t Bitfield::countArray() const
{
size_t ret = 0;
size_t i = b->alloc_count;
size_t i = this->alloc_count_;
while (i > 0)
{
ret += trueBitCount[b->bits[--i]];
ret += trueBitCount[this->bits_[--i]];
}
return ret;
}
static constexpr size_t countRange(tr_bitfield const* b, size_t begin, size_t end)
size_t Bitfield::countRangeImpl(size_t begin, size_t end) const
{
size_t ret = 0;
size_t const first_byte = begin >> 3U;
size_t const last_byte = (end - 1) >> 3U;
if (b->bit_count == 0)
if (this->bit_count_ == 0)
{
return 0;
}
if (first_byte >= b->alloc_count)
if (first_byte >= this->alloc_count_)
{
return 0;
}
TR_ASSERT(begin < end);
TR_ASSERT(b->bits != nullptr);
TR_ASSERT(this->bits_ != nullptr);
if (first_byte == last_byte)
{
uint8_t val = b->bits[first_byte];
uint8_t val = this->bits_[first_byte];
int i = begin - (first_byte * 8);
val <<= i;
@ -84,11 +84,11 @@ static constexpr size_t countRange(tr_bitfield const* b, size_t begin, size_t en
}
else
{
size_t const walk_end = std::min(b->alloc_count, last_byte);
size_t const walk_end = std::min(this->alloc_count_, last_byte);
/* first byte */
size_t const first_shift = begin - (first_byte * 8);
uint8_t val = b->bits[first_byte];
uint8_t val = this->bits_[first_byte];
val <<= first_shift;
val >>= first_shift;
ret += trueBitCount[val];
@ -96,14 +96,14 @@ static constexpr size_t countRange(tr_bitfield const* b, size_t begin, size_t en
/* middle bytes */
for (size_t i = first_byte + 1; i < walk_end; ++i)
{
ret += trueBitCount[b->bits[i]];
ret += trueBitCount[this->bits_[i]];
}
/* last byte */
if (last_byte < b->alloc_count)
if (last_byte < this->alloc_count_)
{
size_t const last_shift = (last_byte + 1) * 8 - end;
val = b->bits[last_byte];
val = this->bits_[last_byte];
val >>= last_shift;
val <<= last_shift;
ret += trueBitCount[val];
@ -114,39 +114,24 @@ static constexpr size_t countRange(tr_bitfield const* b, size_t begin, size_t en
return ret;
}
size_t tr_bitfieldCountRange(tr_bitfield const* b, size_t begin, size_t end)
bool Bitfield::readBit(size_t n) const
{
if (tr_bitfieldHasAll(b))
{
return end - begin;
}
if (tr_bitfieldHasNone(b))
{
return 0;
}
return countRange(b, begin, end);
}
bool tr_bitfieldHas(tr_bitfield const* b, size_t n)
{
if (tr_bitfieldHasAll(b))
if (this->hasAll())
{
return true;
}
if (tr_bitfieldHasNone(b))
if (this->hasNone())
{
return false;
}
if (n >> 3U >= b->alloc_count)
if (n >> 3U >= this->alloc_count_)
{
return false;
}
return (b->bits[n >> 3U] << (n & 7U) & 0x80) != 0;
return (this->bits_[n >> 3U] << (n & 7U) & 0x80) != 0;
}
/***
@ -155,33 +140,27 @@ bool tr_bitfieldHas(tr_bitfield const* b, size_t n)
#ifdef TR_ENABLE_ASSERTS
static bool tr_bitfieldIsValid(tr_bitfield const* b)
bool Bitfield::isValid() const
{
TR_ASSERT(b != nullptr);
TR_ASSERT((b->alloc_count == 0) == (b->bits == nullptr));
TR_ASSERT(b->bits == nullptr || b->true_count == countArray(b));
TR_ASSERT((this->alloc_count_ == 0) == (this->bits_ == nullptr));
TR_ASSERT(this->bits_ == nullptr || this->true_count_ == this->countArray());
return true;
}
#endif
size_t tr_bitfieldCountTrueBits(tr_bitfield const* b)
size_t Bitfield::countBits() const
{
TR_ASSERT(tr_bitfieldIsValid(b));
TR_ASSERT(this->isValid());
return b->true_count;
return this->true_count_;
}
static constexpr size_t get_bytes_needed(size_t bit_count)
{
return (bit_count >> 3) + ((bit_count & 7) != 0 ? 1 : 0);
}
static void set_all_true(uint8_t* array, size_t bit_count)
void Bitfield::setBitsInArray(uint8_t* array, size_t bit_count)
{
uint8_t const val = 0xFF;
size_t const n = get_bytes_needed(bit_count);
size_t const n = getStorageSize(bit_count);
if (n > 0)
{
@ -191,231 +170,227 @@ static void set_all_true(uint8_t* array, size_t bit_count)
}
}
void* tr_bitfieldGetRaw(tr_bitfield const* b, size_t* byte_count)
void* Bitfield::getRaw(size_t* byte_count) const
{
TR_ASSERT(b->bit_count > 0);
TR_ASSERT(this->bit_count_ > 0);
size_t const n = get_bytes_needed(b->bit_count);
uint8_t* bits = tr_new0(uint8_t, n);
size_t const n = getStorageSize(this->bit_count_);
uint8_t* newBits = tr_new0(uint8_t, n);
if (b->alloc_count != 0)
if (this->alloc_count_ != 0)
{
TR_ASSERT(b->alloc_count <= n);
memcpy(bits, b->bits, b->alloc_count);
TR_ASSERT(this->alloc_count_ <= n);
std::memcpy(newBits, this->bits_, this->alloc_count_);
}
else if (tr_bitfieldHasAll(b))
else if (this->hasAll())
{
set_all_true(bits, b->bit_count);
setBitsInArray(newBits, this->bit_count_);
}
*byte_count = n;
return bits;
return newBits;
}
static void tr_bitfieldEnsureBitsAlloced(tr_bitfield* b, size_t n)
void Bitfield::ensureBitsAlloced(size_t n)
{
size_t bytes_needed;
bool const has_all = tr_bitfieldHasAll(b);
bool const has_all = this->hasAll();
if (has_all)
{
bytes_needed = get_bytes_needed(std::max(n, b->true_count));
bytes_needed = getStorageSize(std::max(n, this->true_count_));
}
else
{
bytes_needed = get_bytes_needed(n);
bytes_needed = getStorageSize(n);
}
if (b->alloc_count < bytes_needed)
if (this->alloc_count_ < bytes_needed)
{
b->bits = tr_renew(uint8_t, b->bits, bytes_needed);
memset(b->bits + b->alloc_count, 0, bytes_needed - b->alloc_count);
b->alloc_count = bytes_needed;
this->bits_ = tr_renew(uint8_t, this->bits_, bytes_needed);
std::memset(this->bits_ + this->alloc_count_, 0, bytes_needed - this->alloc_count_);
this->alloc_count_ = bytes_needed;
if (has_all)
{
set_all_true(b->bits, b->true_count);
setBitsInArray(this->bits_, this->true_count_);
}
}
}
static bool tr_bitfieldEnsureNthBitAlloced(tr_bitfield* b, size_t nth)
bool Bitfield::ensureNthBitAlloced(size_t nth)
{
/* count is zero-based, so we need to allocate nth+1 bits before setting the nth */
// count is zero-based, so we need to allocate nth+1 bits before setting the nth
if (nth == SIZE_MAX)
{
return false;
}
tr_bitfieldEnsureBitsAlloced(b, nth + 1);
this->ensureBitsAlloced(nth + 1);
return true;
}
static void tr_bitfieldFreeArray(tr_bitfield* b)
void Bitfield::freeArray()
{
tr_free(b->bits);
b->bits = nullptr;
b->alloc_count = 0;
tr_free(this->bits_);
this->bits_ = nullptr;
this->alloc_count_ = 0;
}
static void tr_bitfieldSetTrueCount(tr_bitfield* b, size_t n)
void Bitfield::setTrueCount(size_t n)
{
TR_ASSERT(b->bit_count == 0 || n <= b->bit_count);
TR_ASSERT(this->bit_count_ == 0 || n <= this->bit_count_);
b->true_count = n;
this->true_count_ = n;
if (tr_bitfieldHasAll(b) || tr_bitfieldHasNone(b))
if (this->hasAll() || this->hasNone())
{
tr_bitfieldFreeArray(b);
this->freeArray();
}
TR_ASSERT(tr_bitfieldIsValid(b));
TR_ASSERT(this->isValid());
}
static void tr_bitfieldRebuildTrueCount(tr_bitfield* b)
void Bitfield::rebuildTrueCount()
{
tr_bitfieldSetTrueCount(b, countArray(b));
this->setTrueCount(this->countArray());
}
static void tr_bitfieldIncTrueCount(tr_bitfield* b, size_t i)
void Bitfield::incTrueCount(size_t i)
{
TR_ASSERT(b->bit_count == 0 || i <= b->bit_count);
TR_ASSERT(b->bit_count == 0 || b->true_count <= b->bit_count - i);
TR_ASSERT(this->bit_count_ == 0 || i <= this->bit_count_);
TR_ASSERT(this->bit_count_ == 0 || this->true_count_ <= this->bit_count_ - i);
tr_bitfieldSetTrueCount(b, b->true_count + i);
this->setTrueCount(this->true_count_ + i);
}
static void tr_bitfieldDecTrueCount(tr_bitfield* b, size_t i)
void Bitfield::decTrueCount(size_t i)
{
TR_ASSERT(b->bit_count == 0 || i <= b->bit_count);
TR_ASSERT(b->bit_count == 0 || b->true_count >= i);
TR_ASSERT(this->bit_count_ == 0 || i <= this->bit_count_);
TR_ASSERT(this->bit_count_ == 0 || this->true_count_ >= i);
tr_bitfieldSetTrueCount(b, b->true_count - i);
this->setTrueCount(this->true_count_ - i);
}
/****
*****
****/
void tr_bitfieldConstruct(tr_bitfield* b, size_t bit_count)
Bitfield::Bitfield(size_t bit_count)
{
b->bit_count = bit_count;
b->true_count = 0;
b->bits = nullptr;
b->alloc_count = 0;
b->have_all_hint = false;
b->have_none_hint = false;
this->bit_count_ = bit_count;
this->true_count_ = 0;
this->bits_ = nullptr;
this->alloc_count_ = 0;
this->hint_ = NORMAL;
TR_ASSERT(tr_bitfieldIsValid(b));
TR_ASSERT(this->isValid());
}
void tr_bitfieldSetHasNone(tr_bitfield* b)
void Bitfield::setHasNone()
{
tr_bitfieldFreeArray(b);
b->true_count = 0;
b->have_all_hint = false;
b->have_none_hint = true;
this->freeArray();
this->true_count_ = 0;
this->hint_ = HAS_NONE;
TR_ASSERT(tr_bitfieldIsValid(b));
TR_ASSERT(this->isValid());
}
void tr_bitfieldSetHasAll(tr_bitfield* b)
void Bitfield::setHasAll()
{
tr_bitfieldFreeArray(b);
b->true_count = b->bit_count;
b->have_all_hint = true;
b->have_none_hint = false;
this->freeArray();
this->true_count_ = this->bit_count_;
this->hint_ = HAS_ALL;
TR_ASSERT(tr_bitfieldIsValid(b));
TR_ASSERT(this->isValid());
}
void tr_bitfieldSetFromBitfield(tr_bitfield* b, tr_bitfield const* src)
void Bitfield::setFromBitfield(Bitfield const& src)
{
if (tr_bitfieldHasAll(src))
if (src.hasAll())
{
tr_bitfieldSetHasAll(b);
this->setHasAll();
}
else if (tr_bitfieldHasNone(src))
else if (src.hasNone())
{
tr_bitfieldSetHasNone(b);
this->setHasNone();
}
else
{
tr_bitfieldSetRaw(b, src->bits, src->alloc_count, true);
this->setRaw(src.bits_, src.alloc_count_, true);
}
}
void tr_bitfieldSetRaw(tr_bitfield* b, void const* bits, size_t byte_count, bool bounded)
void Bitfield::setRaw(void const* newBits, size_t byte_count, bool bounded)
{
tr_bitfieldFreeArray(b);
b->true_count = 0;
this->freeArray();
this->true_count_ = 0;
if (bounded)
{
byte_count = std::min(byte_count, get_bytes_needed(b->bit_count));
byte_count = std::min(byte_count, getStorageSize(this->bit_count_));
}
b->bits = static_cast<uint8_t*>(tr_memdup(bits, byte_count));
b->alloc_count = byte_count;
this->bits_ = static_cast<uint8_t*>(tr_memdup(newBits, byte_count));
this->alloc_count_ = byte_count;
if (bounded)
{
/* ensure the excess bits are set to '0' */
int const excess_bit_count = byte_count * 8 - b->bit_count;
/* ensure the excess newBits are set to '0' */
int const excess_bit_count = byte_count * 8 - this->bit_count_;
TR_ASSERT(excess_bit_count >= 0);
TR_ASSERT(excess_bit_count <= 7);
if (excess_bit_count != 0)
{
b->bits[b->alloc_count - 1] &= 0xff << excess_bit_count;
this->bits_[this->alloc_count_ - 1] &= 0xff << excess_bit_count;
}
}
tr_bitfieldRebuildTrueCount(b);
this->rebuildTrueCount();
}
void tr_bitfieldSetFromFlags(tr_bitfield* b, bool const* flags, size_t n)
void Bitfield::setFromFlags(bool const* flags, size_t n)
{
size_t trueCount = 0;
tr_bitfieldFreeArray(b);
tr_bitfieldEnsureBitsAlloced(b, n);
this->freeArray();
this->ensureBitsAlloced(n);
for (size_t i = 0; i < n; ++i)
{
if (flags[i] && b->bits != nullptr)
if (flags[i] && this->bits_ != nullptr)
{
++trueCount;
b->bits[i >> 3U] |= (0x80 >> (i & 7U));
this->bits_[i >> 3U] |= (0x80 >> (i & 7U));
}
}
tr_bitfieldSetTrueCount(b, trueCount);
this->setTrueCount(trueCount);
}
void tr_bitfieldAdd(tr_bitfield* b, size_t nth)
void Bitfield::setBit(size_t bit)
{
if (!tr_bitfieldHas(b, nth) && tr_bitfieldEnsureNthBitAlloced(b, nth))
if (!this->readBit(bit) && this->ensureNthBitAlloced(bit))
{
size_t const offset = nth >> 3U;
size_t const offset = bit >> 3U;
if ((b->bits != nullptr) && (offset < b->alloc_count))
if ((this->bits_ != nullptr) && (offset < this->alloc_count_))
{
b->bits[offset] |= 0x80 >> (nth & 7U);
tr_bitfieldIncTrueCount(b, 1);
this->bits_[offset] |= 0x80 >> (bit & 7U);
this->incTrueCount(1);
}
}
}
/* Sets bit range [begin, end) to 1 */
void tr_bitfieldAddRange(tr_bitfield* b, size_t begin, size_t end)
void Bitfield::setBitRange(size_t begin, size_t end)
{
size_t sb;
size_t eb;
unsigned char sm;
unsigned char em;
size_t const diff = (end - begin) - tr_bitfieldCountRange(b, begin, end);
size_t const diff = (end - begin) - this->countRange(begin, end);
if (diff == 0)
{
@ -424,7 +399,7 @@ void tr_bitfieldAddRange(tr_bitfield* b, size_t begin, size_t end)
end--;
if (end >= b->bit_count || begin > end)
if (end >= this->bit_count_ || begin > end)
{
return;
}
@ -434,48 +409,47 @@ void tr_bitfieldAddRange(tr_bitfield* b, size_t begin, size_t end)
eb = end >> 3;
em = 0xff << (7 - (end & 7));
if (!tr_bitfieldEnsureNthBitAlloced(b, end))
if (!this->ensureNthBitAlloced(end))
{
return;
}
if (sb == eb)
{
b->bits[sb] |= sm & em;
this->bits_[sb] |= sm & em;
}
else
{
b->bits[sb] |= sm;
b->bits[eb] |= em;
this->bits_[sb] |= sm;
this->bits_[eb] |= em;
if (++sb < eb)
{
memset(b->bits + sb, 0xff, eb - sb);
std::memset(this->bits_ + sb, 0xff, eb - sb);
}
}
tr_bitfieldIncTrueCount(b, diff);
this->incTrueCount(diff);
}
void tr_bitfieldRem(tr_bitfield* b, size_t nth)
void Bitfield::clearBit(size_t bit)
{
TR_ASSERT(tr_bitfieldIsValid(b));
TR_ASSERT(this->isValid());
if (tr_bitfieldHas(b, nth) && tr_bitfieldEnsureNthBitAlloced(b, nth))
if (this->readBit(bit) && this->ensureNthBitAlloced(bit))
{
b->bits[nth >> 3U] &= 0xff7f >> (nth & 7U);
tr_bitfieldDecTrueCount(b, 1);
this->bits_[bit >> 3U] &= 0xff7f >> (bit & 7U);
this->decTrueCount(1);
}
}
/* Clears bit range [begin, end) to 0 */
void tr_bitfieldRemRange(tr_bitfield* b, size_t begin, size_t end)
void Bitfield::clearBitRange(size_t begin, size_t end)
{
size_t sb;
size_t eb;
unsigned char sm;
unsigned char em;
size_t const diff = tr_bitfieldCountRange(b, begin, end);
size_t const diff = this->countRange(begin, end);
if (diff == 0)
{
@ -484,7 +458,7 @@ void tr_bitfieldRemRange(tr_bitfield* b, size_t begin, size_t end)
end--;
if (end >= b->bit_count || begin > end)
if (end >= this->bit_count_ || begin > end)
{
return;
}
@ -494,25 +468,25 @@ void tr_bitfieldRemRange(tr_bitfield* b, size_t begin, size_t end)
eb = end >> 3;
em = ~(0xff << (7 - (end & 7)));
if (!tr_bitfieldEnsureNthBitAlloced(b, end))
if (!this->ensureNthBitAlloced(end))
{
return;
}
if (sb == eb)
{
b->bits[sb] &= sm | em;
this->bits_[sb] &= sm | em;
}
else
{
b->bits[sb] &= sm;
b->bits[eb] &= em;
this->bits_[sb] &= sm;
this->bits_[eb] &= em;
if (++sb < eb)
{
memset(b->bits + sb, 0, eb - sb);
std::memset(this->bits_ + sb, 0, eb - sb);
}
}
tr_bitfieldDecTrueCount(b, diff);
this->decTrueCount(diff);
}

View File

@ -14,78 +14,133 @@
#include "transmission.h"
#include "tr-macros.h"
#include "tr-assert.h"
/** @brief Implementation of the BitTorrent spec's Bitfield array of bits */
struct tr_bitfield
/// @brief Implementation of the BitTorrent spec's Bitfield array of bits
struct Bitfield
{
uint8_t* bits = nullptr;
size_t alloc_count = 0;
public:
/***
**** life cycle
***/
explicit Bitfield(size_t bit_count);
size_t bit_count = 0;
Bitfield()
: Bitfield(0)
{
}
size_t true_count = 0;
~Bitfield()
{
this->setHasNone();
}
/* Special cases for when full or empty but we don't know the bitCount.
This occurs when a magnet link's peers send have all / have none */
bool have_all_hint = false;
bool have_none_hint = false;
/***
****
***/
void setHasAll();
void setHasNone();
/// @brief Sets one bit
void setBit(size_t bit);
/// @brief Sets bit range [begin, end) to 1
void setBitRange(size_t begin, size_t end);
/// @brief Clears one bit
void clearBit(size_t bit);
/// @brief Clears bit range [begin, end) to 0
void clearBitRange(size_t begin, size_t end);
/***
****
***/
[[nodiscard]] size_t countRange(size_t begin, size_t end) const
{
if (this->hasAll())
{
return end - begin;
}
if (this->hasNone())
{
return 0;
}
return this->countRangeImpl(begin, end);
}
[[nodiscard]] size_t countBits() const;
[[nodiscard]] constexpr bool hasAll() const
{
return this->bit_count_ != 0 ? (this->true_count_ == this->bit_count_) : this->hint_ == HAS_ALL;
}
[[nodiscard]] constexpr bool hasNone() const
{
return this->bit_count_ != 0 ? (this->true_count_ == 0) : this->hint_ == HAS_NONE;
}
[[nodiscard]] bool readBit(size_t n) const;
/***
****
***/
void setFromFlags(bool const* bytes, size_t n);
void setFromBitfield(Bitfield const& src);
void setRaw(void const* newBits, size_t byte_count, bool bounded);
void* getRaw(size_t* byte_count) const;
[[nodiscard]] size_t getBitCount() const
{
return bit_count_;
}
private:
[[nodiscard]] constexpr size_t countArray() const;
[[nodiscard]] size_t countRangeImpl(size_t begin, size_t end) const;
static void setBitsInArray(uint8_t* array, size_t bit_count);
static constexpr size_t getStorageSize(size_t bit_count)
{
return (bit_count >> 3) + ((bit_count & 7) != 0 ? 1 : 0);
}
void ensureBitsAlloced(size_t n);
bool ensureNthBitAlloced(size_t nth);
void freeArray();
void setTrueCount(size_t n);
void rebuildTrueCount();
void incTrueCount(size_t i);
void decTrueCount(size_t i);
#ifdef TR_ENABLE_ASSERTS
[[nodiscard]] bool isValid() const;
#endif
uint8_t* bits_ = nullptr;
size_t alloc_count_ = 0;
size_t bit_count_ = 0;
size_t true_count_ = 0;
enum OperationMode
{
/// @brief Normal operation: storage of bytes contains bits to set or clear
NORMAL,
/// @brief If bit_count_==0, storage is inactive, consider all bits to be 1
HAS_ALL,
/// @brief If bit_count_==0, storage is inactive, consider all bits to be 0
HAS_NONE,
};
// Special cases for when full or empty but we don't know the bitCount.
// This occurs when a magnet link's peers send have all / have none
OperationMode hint_ = NORMAL;
};
/***
****
***/
void tr_bitfieldSetHasAll(tr_bitfield*);
void tr_bitfieldSetHasNone(tr_bitfield*);
void tr_bitfieldAdd(tr_bitfield*, size_t bit);
void tr_bitfieldRem(tr_bitfield*, size_t bit);
void tr_bitfieldAddRange(tr_bitfield*, size_t begin, size_t end);
void tr_bitfieldRemRange(tr_bitfield*, size_t begin, size_t end);
/***
**** life cycle
***/
void tr_bitfieldConstruct(tr_bitfield*, size_t bit_count);
static inline void tr_bitfieldDestruct(tr_bitfield* b)
{
tr_bitfieldSetHasNone(b);
}
/***
****
***/
void tr_bitfieldSetFromFlags(tr_bitfield*, bool const* bytes, size_t n);
void tr_bitfieldSetFromBitfield(tr_bitfield*, tr_bitfield const*);
void tr_bitfieldSetRaw(tr_bitfield*, void const* bits, size_t byte_count, bool bounded);
void* tr_bitfieldGetRaw(tr_bitfield const* b, size_t* byte_count);
/***
****
***/
size_t tr_bitfieldCountRange(tr_bitfield const*, size_t begin, size_t end);
size_t tr_bitfieldCountTrueBits(tr_bitfield const* b);
constexpr bool tr_bitfieldHasAll(tr_bitfield const* b)
{
return b->bit_count != 0 ? (b->true_count == b->bit_count) : b->have_all_hint;
}
constexpr bool tr_bitfieldHasNone(tr_bitfield const* b)
{
return b->bit_count != 0 ? (b->true_count == 0) : b->have_none_hint;
}
bool tr_bitfieldHas(tr_bitfield const* b, size_t n);

View File

@ -21,29 +21,29 @@ static void tr_cpReset(tr_completion* cp)
cp->sizeNow = 0;
cp->sizeWhenDoneIsDirty = true;
cp->haveValidIsDirty = true;
tr_bitfieldSetHasNone(&cp->blockBitfield);
cp->blockBitfield->setHasNone();
}
void tr_cpConstruct(tr_completion* cp, tr_torrent* tor)
{
cp->tor = tor;
tr_bitfieldConstruct(&cp->blockBitfield, tor->blockCount);
cp->blockBitfield = new Bitfield(tor->blockCount);
tr_cpReset(cp);
}
void tr_cpBlockInit(tr_completion* cp, tr_bitfield const* b)
void tr_cpBlockInit(tr_completion* cp, Bitfield const& b)
{
tr_cpReset(cp);
/* set blockBitfield */
tr_bitfieldSetFromBitfield(&cp->blockBitfield, b);
// set blockBitfield
cp->blockBitfield->setFromBitfield(b);
/* set sizeNow */
cp->sizeNow = tr_bitfieldCountTrueBits(&cp->blockBitfield);
// set sizeNow
cp->sizeNow = cp->blockBitfield->countBits();
TR_ASSERT(cp->sizeNow <= cp->tor->blockCount);
cp->sizeNow *= cp->tor->blockSize;
if (tr_bitfieldHas(b, cp->tor->blockCount - 1))
if (b.readBit(cp->tor->blockCount - 1))
{
cp->sizeNow -= (cp->tor->blockSize - cp->tor->lastBlockSize);
}
@ -93,7 +93,7 @@ void tr_cpPieceRem(tr_completion* cp, tr_piece_index_t piece)
cp->haveValidIsDirty = true;
cp->sizeWhenDoneIsDirty = true;
tr_bitfieldRemRange(&cp->blockBitfield, f, l + 1);
cp->blockBitfield->clearBitRange(f, l + 1);
}
void tr_cpPieceAdd(tr_completion* cp, tr_piece_index_t piece)
@ -116,7 +116,7 @@ void tr_cpBlockAdd(tr_completion* cp, tr_block_index_t block)
{
tr_piece_index_t const piece = tr_torBlockPiece(cp->tor, block);
tr_bitfieldAdd(&cp->blockBitfield, block);
cp->blockBitfield->setBit(block);
cp->sizeNow += tr_torBlockCountBytes(tor, block);
cp->haveValidIsDirty = true;
@ -182,10 +182,10 @@ uint64_t tr_cpSizeWhenDone(tr_completion const* ccp)
tr_block_index_t l;
tr_torGetPieceBlockRange(cp->tor, p, &f, &l);
n = tr_bitfieldCountRange(&cp->blockBitfield, f, l + 1);
n = cp->blockBitfield->countRange(f, l + 1);
n *= cp->tor->blockSize;
if (l == cp->tor->blockCount - 1 && tr_bitfieldHas(&cp->blockBitfield, l))
if (l == cp->tor->blockCount - 1 && cp->blockBitfield->readBit(l))
{
n -= cp->tor->blockSize - cp->tor->lastBlockSize;
}
@ -232,7 +232,7 @@ void tr_cpGetAmountDone(tr_completion const* cp, float* tab, int tabCount)
tr_block_index_t l;
tr_piece_index_t const piece = (tr_piece_index_t)i * interval;
tr_torGetPieceBlockRange(cp->tor, piece, &f, &l);
tab[i] = tr_bitfieldCountRange(&cp->blockBitfield, f, l + 1) / (float)(l + 1 - f);
tab[i] = cp->blockBitfield->countRange(f, l + 1) / (float)(l + 1 - f);
}
}
}
@ -248,7 +248,7 @@ size_t tr_cpMissingBlocksInPiece(tr_completion const* cp, tr_piece_index_t piece
tr_block_index_t f;
tr_block_index_t l;
tr_torGetPieceBlockRange(cp->tor, piece, &f, &l);
return (l + 1 - f) - tr_bitfieldCountRange(&cp->blockBitfield, f, l + 1);
return (l + 1 - f) - cp->blockBitfield->countRange(f, l + 1);
}
}
@ -268,14 +268,14 @@ size_t tr_cpMissingBytesInPiece(tr_completion const* cp, tr_piece_index_t piece)
if (f != l)
{
/* nb: we don't pass the usual l+1 here to tr_bitfieldCountRange().
/* nb: we don't pass the usual l+1 here to Bitfield::countRange().
It's faster to handle the last block separately because its size
needs to be checked separately. */
haveBytes = tr_bitfieldCountRange(&cp->blockBitfield, f, l);
haveBytes = cp->blockBitfield->countRange(f, l);
haveBytes *= cp->tor->blockSize;
}
if (tr_bitfieldHas(&cp->blockBitfield, l)) /* handle the last block */
if (cp->blockBitfield->readBit(l)) /* handle the last block */
{
haveBytes += tr_torBlockCountBytes(cp->tor, l);
}
@ -296,7 +296,7 @@ bool tr_cpFileIsComplete(tr_completion const* cp, tr_file_index_t i)
tr_block_index_t f;
tr_block_index_t l;
tr_torGetFileBlockRange(cp->tor, i, &f, &l);
return tr_bitfieldCountRange(&cp->blockBitfield, f, l + 1) == (l + 1 - f);
return cp->blockBitfield->countRange(f, l + 1) == (l + 1 - f);
}
}
@ -306,14 +306,14 @@ void* tr_cpCreatePieceBitfield(tr_completion const* cp, size_t* byte_count)
void* ret;
tr_piece_index_t n;
tr_bitfield pieces;
n = cp->tor->info.pieceCount;
tr_bitfieldConstruct(&pieces, n);
Bitfield pieces(n);
if (tr_cpHasAll(cp))
{
tr_bitfieldSetHasAll(&pieces);
pieces.setHasAll();
}
else if (!tr_cpHasNone(cp))
{
@ -324,12 +324,11 @@ void* tr_cpCreatePieceBitfield(tr_completion const* cp, size_t* byte_count)
flags[i] = tr_cpPieceIsComplete(cp, i);
}
tr_bitfieldSetFromFlags(&pieces, flags, n);
pieces.setFromFlags(flags, n);
tr_free(flags);
}
ret = tr_bitfieldGetRaw(&pieces, byte_count);
tr_bitfieldDestruct(&pieces);
ret = pieces.getRaw(byte_count);
return ret;
}

View File

@ -20,7 +20,9 @@ struct tr_completion
{
tr_torrent* tor;
tr_bitfield blockBitfield;
// Changed to non-owning pointer temporarily till tr_completion becomes C++-constructible and destructible
// TODO: remove * and own the value
Bitfield* blockBitfield;
/* number of bytes we'll have when done downloading. [0..info.totalSize]
DON'T access this directly; it's a lazy field.
@ -48,11 +50,11 @@ struct tr_completion
void tr_cpConstruct(tr_completion*, tr_torrent*);
void tr_cpBlockInit(tr_completion* cp, tr_bitfield const* blocks);
void tr_cpBlockInit(tr_completion* cp, Bitfield const& blocks);
static inline void tr_cpDestruct(tr_completion* cp)
{
tr_bitfieldDestruct(&cp->blockBitfield);
delete cp->blockBitfield;
}
/**
@ -80,12 +82,12 @@ constexpr uint64_t tr_cpHaveTotal(tr_completion const* cp)
static inline bool tr_cpHasAll(tr_completion const* cp)
{
return tr_torrentHasMetadata(cp->tor) && tr_bitfieldHasAll(&cp->blockBitfield);
return tr_torrentHasMetadata(cp->tor) && cp->blockBitfield->hasAll();
}
static inline bool tr_cpHasNone(tr_completion const* cp)
{
return !tr_torrentHasMetadata(cp->tor) || tr_bitfieldHasNone(&cp->blockBitfield);
return !tr_torrentHasMetadata(cp->tor) || cp->blockBitfield->hasNone();
}
/**
@ -113,7 +115,7 @@ void tr_cpBlockAdd(tr_completion* cp, tr_block_index_t i);
static inline bool tr_cpBlockIsComplete(tr_completion const* cp, tr_block_index_t i)
{
return tr_bitfieldHas(&cp->blockBitfield, i);
return cp->blockBitfield->readBit(i);
}
/***

View File

@ -57,7 +57,7 @@ struct tr_peer_event
PeerEventType eventType;
uint32_t pieceIndex; /* for GOT_BLOCK, GOT_HAVE, CANCEL, ALLOWED, SUGGEST */
struct tr_bitfield* bitfield; /* for GOT_BITFIELD */
Bitfield* bitfield; /* for GOT_BITFIELD */
uint32_t offset; /* for GOT_BLOCK */
uint32_t length; /* for GOT_BLOCK + GOT_PIECE_DATA */
int err; /* errno for GOT_ERROR */
@ -103,8 +103,8 @@ public:
/** how complete the peer's copy of the torrent is. [0.0...1.0] */
float progress = 0.0f;
struct tr_bitfield blame = {};
struct tr_bitfield have = {};
Bitfield blame;
Bitfield have;
/* the client name.
For BitTorrent peers, this is the app name derived from the `v' string in LTEP's handshake dictionary */

View File

@ -246,9 +246,9 @@ tr_peer::tr_peer(tr_torrent const* tor, peer_atom* atom_in)
: session{ tor->session }
, atom{ atom_in }
, swarm{ tor->swarm }
, blame{ tor->blockCount }
, have{ tor->info.pieceCount }
{
tr_bitfieldConstruct(&have, tor->info.pieceCount);
tr_bitfieldConstruct(&blame, tor->blockCount);
}
static void peerDeclinedAllRequests(tr_swarm*, tr_peer const*);
@ -260,9 +260,6 @@ tr_peer::~tr_peer()
peerDeclinedAllRequests(swarm, this);
}
tr_bitfieldDestruct(&have);
tr_bitfieldDestruct(&blame);
if (atom != nullptr)
{
atom->peer = nullptr;
@ -416,7 +413,7 @@ static void replicationNew(tr_swarm* s)
{
auto const* const peer = static_cast<tr_peer const*>(tr_ptrArrayNth(&s->peers, peer_i));
if (tr_bitfieldHas(&peer->have, piece_i))
if (peer->have.readBit(piece_i))
{
++r;
}
@ -1197,7 +1194,7 @@ static void tr_incrReplicationOfPiece(tr_swarm* s, size_t const index)
/**
* Increases the replication count of pieces present in the bitfield
*/
static void tr_incrReplicationFromBitfield(tr_swarm* s, tr_bitfield const* b)
static void tr_incrReplicationFromBitfield(tr_swarm* s, Bitfield const* b)
{
TR_ASSERT(replicationExists(s));
@ -1205,7 +1202,7 @@ static void tr_incrReplicationFromBitfield(tr_swarm* s, tr_bitfield const* b)
for (size_t i = 0, n = s->tor->info.pieceCount; i < n; ++i)
{
if (tr_bitfieldHas(b, i))
if (b->readBit(i))
{
++rep[i];
}
@ -1234,23 +1231,23 @@ static void tr_incrReplication(tr_swarm* s)
/**
* Decrease the replication count of pieces present in the bitset.
*/
static void tr_decrReplicationFromBitfield(tr_swarm* s, tr_bitfield const* b)
static void tr_decrReplicationFromBitfield(tr_swarm* s, Bitfield const* b)
{
TR_ASSERT(replicationExists(s));
TR_ASSERT(s->pieceReplicationSize == s->tor->info.pieceCount);
if (tr_bitfieldHasAll(b))
if (b->hasAll())
{
for (size_t i = 0; i < s->pieceReplicationSize; ++i)
{
--s->pieceReplication[i];
}
}
else if (!tr_bitfieldHasNone(b))
else if (!b->hasNone())
{
for (size_t i = 0; i < s->pieceReplicationSize; ++i)
{
if (tr_bitfieldHas(b, i))
if (b->readBit(i))
{
--s->pieceReplication[i];
}
@ -1287,7 +1284,7 @@ void tr_peerMgrGetNextRequests(
TR_ASSERT(numwant > 0);
tr_swarm* s;
tr_bitfield const* const have = &peer->have;
Bitfield const* const have = &peer->have;
/* walk through the pieces and find blocks that should be requested */
s = tor->swarm;
@ -1326,7 +1323,7 @@ void tr_peerMgrGetNextRequests(
struct weighted_piece* p = pieces + i;
/* if the peer has this piece that we want... */
if (tr_bitfieldHas(have, p->index))
if (have->readBit(p->index))
{
tr_block_index_t first;
tr_block_index_t last;
@ -1572,7 +1569,7 @@ static void peerSuggestedPiece(
}
/* don't ask for it if they don't have it */
if (!tr_bitfieldHas(peer->have, pieceIndex))
if (!peer->have.readBit(pieceIndex))
{
return;
}
@ -1666,7 +1663,7 @@ void tr_peerMgrPieceCompleted(tr_torrent* tor, tr_piece_index_t p)
if (!pieceCameFromPeers)
{
pieceCameFromPeers = tr_bitfieldHas(&peer->blame, p);
pieceCameFromPeers = peer->blame.readBit(p);
}
}
@ -2231,7 +2228,7 @@ void tr_peerMgrGotBadPiece(tr_torrent* tor, tr_piece_index_t pieceIndex)
{
auto* const peer = static_cast<tr_peer*>(tr_ptrArrayNth(&s->peers, i));
if (tr_bitfieldHas(&peer->blame, pieceIndex))
if (peer->blame.readBit(pieceIndex))
{
tordbg(
s,
@ -2503,19 +2500,19 @@ void tr_peerMgrRemoveTorrent(tr_torrent* tor)
void tr_peerUpdateProgress(tr_torrent* tor, tr_peer* peer)
{
tr_bitfield const* have = &peer->have;
Bitfield const* have = &peer->have;
if (tr_bitfieldHasAll(have))
if (have->hasAll())
{
peer->progress = 1.0;
}
else if (tr_bitfieldHasNone(have))
else if (have->hasNone())
{
peer->progress = 0.0;
}
else
{
float const true_count = tr_bitfieldCountTrueBits(have);
float const true_count = have->countBits();
if (tr_torrentHasMetadata(tor))
{
@ -2523,7 +2520,7 @@ void tr_peerUpdateProgress(tr_torrent* tor, tr_peer* peer)
}
else /* without pieceCount, this result is only a best guess... */
{
peer->progress = true_count / (have->bit_count + 1);
peer->progress = true_count / static_cast<float>(have->getBitCount() + 1);
}
}
@ -2598,7 +2595,7 @@ void tr_peerMgrTorrentAvailability(tr_torrent const* tor, int8_t* tab, unsigned
{
for (int j = 0; j < peerCount; ++j)
{
if (tr_bitfieldHas(&peers[j]->have, piece))
if (peers[j]->have.readBit(piece))
{
++tab[i];
}
@ -2887,7 +2884,7 @@ static bool isPeerInteresting(tr_torrent* const tor, bool const* const piece_is_
for (tr_piece_index_t i = 0; i < tor->info.pieceCount; ++i)
{
if (piece_is_interesting[i] && tr_bitfieldHas(&peer->have, i))
if (piece_is_interesting[i] && peer->have.readBit(i))
{
return true;
}

View File

@ -483,7 +483,7 @@ public:
publish(e);
}
void publishClientGotBitfield(tr_bitfield* bitfield)
void publishClientGotBitfield(Bitfield* bitfield)
{
auto e = tr_peer_event{};
e.eventType = TR_PEER_CLIENT_GOT_BITFIELD;
@ -1677,9 +1677,9 @@ static ReadState readBtMessage(tr_peerMsgsImpl* msgs, struct evbuffer* inbuf, si
}
/* a peer can send the same HAVE message twice... */
if (!tr_bitfieldHas(&msgs->have, ui32))
if (!msgs->have.readBit(ui32))
{
tr_bitfieldAdd(&msgs->have, ui32);
msgs->have.setBit(ui32);
msgs->publishClientGotHave(ui32);
}
@ -1691,7 +1691,7 @@ static ReadState readBtMessage(tr_peerMsgsImpl* msgs, struct evbuffer* inbuf, si
uint8_t* tmp = tr_new(uint8_t, msglen);
dbgmsg(msgs, "got a bitfield");
tr_peerIoReadBytes(msgs->io, inbuf, tmp, msglen);
tr_bitfieldSetRaw(&msgs->have, tmp, msglen, tr_torrentHasMetadata(msgs->torrent));
msgs->have.setRaw(tmp, msglen, tr_torrentHasMetadata(msgs->torrent));
msgs->publishClientGotBitfield(&msgs->have);
updatePeerProgress(msgs);
tr_free(tmp);
@ -1785,8 +1785,8 @@ static ReadState readBtMessage(tr_peerMsgsImpl* msgs, struct evbuffer* inbuf, si
if (fext)
{
tr_bitfieldSetHasAll(&msgs->have);
TR_ASSERT(tr_bitfieldHasAll(&msgs->have));
msgs->have.setHasAll();
TR_ASSERT(msgs->have.hasAll());
msgs->publishClientGotHaveAll();
updatePeerProgress(msgs);
}
@ -1803,7 +1803,7 @@ static ReadState readBtMessage(tr_peerMsgsImpl* msgs, struct evbuffer* inbuf, si
if (fext)
{
tr_bitfieldSetHasNone(&msgs->have);
msgs->have.setHasNone();
msgs->publishClientGotHaveNone();
updatePeerProgress(msgs);
}
@ -1899,7 +1899,7 @@ static int clientGotBlock(tr_peerMsgsImpl* msgs, struct evbuffer* data, struct p
return err;
}
tr_bitfieldAdd(&msgs->blame, req->index);
msgs->blame.setBit(req->index);
msgs->publishGotBlock(req);
return 0;
}

View File

@ -17,7 +17,6 @@
class tr_peer;
struct tr_address;
struct tr_bitfield;
struct tr_peerIo;
struct tr_torrent;

View File

@ -471,20 +471,21 @@ static uint64_t loadFilenames(tr_variant* dict, tr_torrent* tor)
****
***/
static void bitfieldToBenc(tr_bitfield const* b, tr_variant* benc)
// TODO: Refactor this into a constructor for tr_variant
static void bitfieldToBenc(Bitfield const* b, tr_variant* benc)
{
if (tr_bitfieldHasAll(b))
if (b->hasAll())
{
tr_variantInitStr(benc, "all", 3);
}
else if (tr_bitfieldHasNone(b))
else if (b->hasNone())
{
tr_variantInitStr(benc, "none", 4);
}
else
{
size_t byte_count = 0;
auto* raw = static_cast<uint8_t*>(tr_bitfieldGetRaw(b, &byte_count));
auto* raw = static_cast<uint8_t*>(b->getRaw(&byte_count));
tr_variantInitRaw(benc, raw, byte_count);
tr_free(raw);
}
@ -569,7 +570,7 @@ static void saveProgress(tr_variant* dict, tr_torrent* tor)
}
/* add the blocks bitfield */
bitfieldToBenc(&tor->completion.blockBitfield, tr_variantDictAdd(prog, TR_KEY_blocks));
bitfieldToBenc(tor->completion.blockBitfield, tr_variantDictAdd(prog, TR_KEY_blocks));
}
static uint64_t loadProgress(tr_variant* dict, tr_torrent* tor)
@ -590,7 +591,6 @@ static uint64_t loadProgress(tr_variant* dict, tr_torrent* tor)
uint8_t const* raw;
size_t rawlen;
tr_variant* l;
struct tr_bitfield blocks = {};
if (tr_variantDictFindList(prog, TR_KEY_time_checked, &l))
{
@ -661,7 +661,8 @@ static uint64_t loadProgress(tr_variant* dict, tr_torrent* tor)
}
err = nullptr;
tr_bitfieldConstruct(&blocks, tor->blockCount);
Bitfield blocks(tor->blockCount);
tr_variant const* const b = tr_variantDictFind(prog, TR_KEY_blocks);
if (b != nullptr)
@ -675,22 +676,22 @@ static uint64_t loadProgress(tr_variant* dict, tr_torrent* tor)
}
else if (buflen == 3 && memcmp(buf, "all", 3) == 0)
{
tr_bitfieldSetHasAll(&blocks);
blocks.setHasAll();
}
else if (buflen == 4 && memcmp(buf, "none", 4) == 0)
{
tr_bitfieldSetHasNone(&blocks);
blocks.setHasNone();
}
else
{
tr_bitfieldSetRaw(&blocks, buf, buflen, true);
blocks.setRaw(buf, buflen, true);
}
}
else if (tr_variantDictFindStr(prog, TR_KEY_have, &str, nullptr))
{
if (strcmp(str, "all") == 0)
{
tr_bitfieldSetHasAll(&blocks);
blocks.setHasAll();
}
else
{
@ -699,7 +700,7 @@ static uint64_t loadProgress(tr_variant* dict, tr_torrent* tor)
}
else if (tr_variantDictFindRaw(prog, TR_KEY_bitfield, &raw, &rawlen))
{
tr_bitfieldSetRaw(&blocks, raw, rawlen, true);
blocks.setRaw(raw, rawlen, true);
}
else
{
@ -712,10 +713,9 @@ static uint64_t loadProgress(tr_variant* dict, tr_torrent* tor)
}
else
{
tr_cpBlockInit(&tor->completion, &blocks);
tr_cpBlockInit(&tor->completion, blocks);
}
tr_bitfieldDestruct(&blocks);
ret = TR_FR_PROGRESS;
}

View File

@ -1500,9 +1500,7 @@ enum
static void turtleUpdateTable(struct tr_turtle_info* t)
{
tr_bitfield* b = &t->minutes;
tr_bitfieldSetHasNone(b);
t->minutes->setHasNone();
for (int day = 0; day < 7; ++day)
{
@ -1518,7 +1516,7 @@ static void turtleUpdateTable(struct tr_turtle_info* t)
for (time_t i = begin; i < end; ++i)
{
tr_bitfieldAdd(b, (i + day * MINUTES_PER_DAY) % MINUTES_PER_WEEK);
t->minutes->setBit((i + day * MINUTES_PER_DAY) % MINUTES_PER_WEEK);
}
}
}
@ -1572,7 +1570,7 @@ static bool getInTurtleTime(struct tr_turtle_info const* t)
minute_of_the_week = MINUTES_PER_WEEK - 1;
}
return tr_bitfieldHas(&t->minutes, minute_of_the_week);
return t->minutes->readBit(minute_of_the_week);
}
static constexpr tr_auto_switch_state_t autoSwitchState(bool enabled)
@ -1604,7 +1602,7 @@ static void turtleBootstrap(tr_session* session, struct tr_turtle_info* turtle)
turtle->changedByUser = false;
turtle->autoTurtleState = TR_AUTO_SWITCH_UNUSED;
tr_bitfieldConstruct(&turtle->minutes, MINUTES_PER_WEEK);
turtle->minutes = new Bitfield(MINUTES_PER_WEEK);
turtleUpdateTable(turtle);
@ -2102,7 +2100,7 @@ void tr_sessionClose(tr_session* session)
/* free the session memory */
tr_variantFree(&session->removedTorrents);
delete session->bandwidth;
tr_bitfieldDestruct(&session->turtle.minutes);
delete session->turtle.minutes;
tr_session_id_free(session->session_id);
tr_lockFree(session->lock);

View File

@ -95,7 +95,9 @@ struct tr_turtle_info
/* bitfield of all the minutes in a week.
* Each bit's value indicates whether the scheduler wants turtle
* limits on or off at that given minute in the week. */
tr_bitfield minutes;
// Changed to non-owning pointer temporarily till tr_turtle_info becomes C++-constructible and destructible
// TODO: remove * and own the value
Bitfield* minutes;
/* recent action that was done by turtle's automatic switch */
tr_auto_switch_state_t autoTurtleState;

View File

@ -1458,7 +1458,7 @@ static uint64_t countFileBytesCompleted(tr_torrent const* tor, tr_file_index_t i
/* the middle blocks */
if (first + 1 < last)
{
uint64_t u = tr_bitfieldCountRange(&tor->completion.blockBitfield, first + 1, last);
uint64_t u = tor->completion.blockBitfield->countRange(first + 1, last);
u *= tor->blockSize;
total += u;
}

View File

@ -67,7 +67,7 @@ public:
, bandwidth(tor->bandwidth)
{
// init parent bits
tr_bitfieldSetHasAll(&have);
have.setHasAll();
tr_peerUpdateProgress(tor, this);
file_urls.resize(tr_torrentInfo(tor)->fileCount);

View File

@ -22,12 +22,11 @@ TEST(Bitfield, countRange)
int const bit_count = 100 + tr_rand_int_weak(1000);
// generate a random bitfield
tr_bitfield bf;
tr_bitfieldConstruct(&bf, bit_count);
Bitfield bf(bit_count);
for (int j = 0, n = tr_rand_int_weak(bit_count); j < n; ++j)
{
tr_bitfieldAdd(&bf, tr_rand_int_weak(bit_count));
bf.setBit(tr_rand_int_weak(bit_count));
}
int begin = tr_rand_int_weak(bit_count);
@ -49,169 +48,161 @@ TEST(Bitfield, countRange)
unsigned long count1 = {};
for (auto j = begin; j < end; ++j)
{
if (tr_bitfieldHas(&bf, j))
if (bf.readBit(j))
{
++count1;
}
}
auto const count2 = tr_bitfieldCountRange(&bf, begin, end);
auto const count2 = bf.countRange(begin, end);
EXPECT_EQ(count1, count2);
// cleanup
tr_bitfieldDestruct(&bf);
}
}
TEST(Bitfields, bitfields)
{
unsigned int bitcount = 500;
tr_bitfield field;
Bitfield field(bitcount);
tr_bitfieldConstruct(&field, bitcount);
/* test tr_bitfieldAdd */
/* test Bitfield::setBit */
for (unsigned int i = 0; i < bitcount; i++)
{
if (i % 7 == 0)
{
tr_bitfieldAdd(&field, i);
field.setBit(i);
}
}
for (unsigned int i = 0; i < bitcount; i++)
{
EXPECT_EQ(tr_bitfieldHas(&field, i), (i % 7 == 0));
EXPECT_EQ(field.readBit(i), (i % 7 == 0));
}
/* test tr_bitfieldAddRange */
tr_bitfieldAddRange(&field, 0, bitcount);
/* test Bitfield::setBitRange */
field.setBitRange(0, bitcount);
for (unsigned int i = 0; i < bitcount; i++)
{
EXPECT_TRUE(tr_bitfieldHas(&field, i));
EXPECT_TRUE(field.readBit(i));
}
/* test tr_bitfieldRem */
/* test Bitfield::clearBit */
for (unsigned int i = 0; i < bitcount; i++)
{
if (i % 7 != 0)
{
tr_bitfieldRem(&field, i);
field.clearBit(i);
}
}
for (unsigned int i = 0; i < bitcount; i++)
{
EXPECT_EQ(tr_bitfieldHas(&field, i), (i % 7 == 0));
EXPECT_EQ(field.readBit(i), (i % 7 == 0));
}
/* test tr_bitfieldRemRange in the middle of a boundary */
tr_bitfieldAddRange(&field, 0, 64);
tr_bitfieldRemRange(&field, 4, 21);
/* test Bitfield::clearBitRange in the middle of a boundary */
field.setBitRange(0, 64);
field.clearBitRange(4, 21);
for (unsigned int i = 0; i < 64; i++)
{
EXPECT_EQ(tr_bitfieldHas(&field, i), (i < 4 || i >= 21));
EXPECT_EQ(field.readBit(i), (i < 4 || i >= 21));
}
/* test tr_bitfieldRemRange on the boundaries */
tr_bitfieldAddRange(&field, 0, 64);
tr_bitfieldRemRange(&field, 8, 24);
/* test Bitfield::clearBitRange on the boundaries */
field.setBitRange(0, 64);
field.clearBitRange(8, 24);
for (unsigned int i = 0; i < 64; i++)
{
EXPECT_EQ(tr_bitfieldHas(&field, i), (i < 8 || i >= 24));
EXPECT_EQ(field.readBit(i), (i < 8 || i >= 24));
}
/* test tr_bitfieldRemRange when begin & end is on the same word */
tr_bitfieldAddRange(&field, 0, 64);
tr_bitfieldRemRange(&field, 4, 5);
/* test Bitfield::clearBitRange when begin & end is on the same word */
field.setBitRange(0, 64);
field.clearBitRange(4, 5);
for (unsigned int i = 0; i < 64; i++)
{
EXPECT_EQ(tr_bitfieldHas(&field, i), (i < 4 || i >= 5));
EXPECT_EQ(field.readBit(i), (i < 4 || i >= 5));
}
/* test tr_bitfieldAddRange */
tr_bitfieldRemRange(&field, 0, 64);
tr_bitfieldAddRange(&field, 4, 21);
/* test Bitfield::setBitRange */
field.clearBitRange(0, 64);
field.setBitRange(4, 21);
for (unsigned int i = 0; i < 64; i++)
{
EXPECT_EQ(tr_bitfieldHas(&field, i), (4 <= i && i < 21));
EXPECT_EQ(field.readBit(i), (4 <= i && i < 21));
}
/* test tr_bitfieldAddRange on the boundaries */
tr_bitfieldRemRange(&field, 0, 64);
tr_bitfieldAddRange(&field, 8, 24);
/* test Bitfield::setBitRange on the boundaries */
field.clearBitRange(0, 64);
field.setBitRange(8, 24);
for (unsigned int i = 0; i < 64; i++)
{
EXPECT_EQ(tr_bitfieldHas(&field, i), (8 <= i && i < 24));
EXPECT_EQ(field.readBit(i), (8 <= i && i < 24));
}
/* test tr_bitfieldAddRange when begin & end is on the same word */
tr_bitfieldRemRange(&field, 0, 64);
tr_bitfieldAddRange(&field, 4, 5);
/* test Bitfield::setBitRange when begin & end is on the same word */
field.clearBitRange(0, 64);
field.setBitRange(4, 5);
for (unsigned int i = 0; i < 64; i++)
{
EXPECT_EQ(tr_bitfieldHas(&field, i), (4 <= i && i < 5));
EXPECT_EQ(field.readBit(i), (4 <= i && i < 5));
}
tr_bitfieldDestruct(&field);
}
TEST(Bitfields, hasAllNone)
{
tr_bitfield field;
{
Bitfield field(3);
tr_bitfieldConstruct(&field, 3);
EXPECT_TRUE(!field.hasAll());
EXPECT_TRUE(field.hasNone());
EXPECT_TRUE(!tr_bitfieldHasAll(&field));
EXPECT_TRUE(tr_bitfieldHasNone(&field));
field.setBit(0);
EXPECT_TRUE(!field.hasAll());
EXPECT_TRUE(!field.hasNone());
tr_bitfieldAdd(&field, 0);
EXPECT_TRUE(!tr_bitfieldHasAll(&field));
EXPECT_TRUE(!tr_bitfieldHasNone(&field));
field.clearBit(0);
field.setBit(1);
EXPECT_TRUE(!field.hasAll());
EXPECT_TRUE(!field.hasNone());
tr_bitfieldRem(&field, 0);
tr_bitfieldAdd(&field, 1);
EXPECT_TRUE(!tr_bitfieldHasAll(&field));
EXPECT_TRUE(!tr_bitfieldHasNone(&field));
field.clearBit(1);
field.setBit(2);
EXPECT_TRUE(!field.hasAll());
EXPECT_TRUE(!field.hasNone());
tr_bitfieldRem(&field, 1);
tr_bitfieldAdd(&field, 2);
EXPECT_TRUE(!tr_bitfieldHasAll(&field));
EXPECT_TRUE(!tr_bitfieldHasNone(&field));
field.setBit(0);
field.setBit(1);
EXPECT_TRUE(field.hasAll());
EXPECT_TRUE(!field.hasNone());
tr_bitfieldAdd(&field, 0);
tr_bitfieldAdd(&field, 1);
EXPECT_TRUE(tr_bitfieldHasAll(&field));
EXPECT_TRUE(!tr_bitfieldHasNone(&field));
field.setHasNone();
EXPECT_TRUE(!field.hasAll());
EXPECT_TRUE(field.hasNone());
tr_bitfieldSetHasNone(&field);
EXPECT_TRUE(!tr_bitfieldHasAll(&field));
EXPECT_TRUE(tr_bitfieldHasNone(&field));
field.setHasAll();
EXPECT_TRUE(field.hasAll());
EXPECT_TRUE(!field.hasNone());
}
tr_bitfieldSetHasAll(&field);
EXPECT_TRUE(tr_bitfieldHasAll(&field));
EXPECT_TRUE(!tr_bitfieldHasNone(&field));
{
Bitfield field(0);
tr_bitfieldDestruct(&field);
tr_bitfieldConstruct(&field, 0);
EXPECT_TRUE(!field.hasAll());
EXPECT_TRUE(!field.hasNone());
EXPECT_TRUE(!tr_bitfieldHasAll(&field));
EXPECT_TRUE(!tr_bitfieldHasNone(&field));
field.setHasNone();
EXPECT_TRUE(!field.hasAll());
EXPECT_TRUE(field.hasNone());
tr_bitfieldSetHasNone(&field);
EXPECT_TRUE(!tr_bitfieldHasAll(&field));
EXPECT_TRUE(tr_bitfieldHasNone(&field));
tr_bitfieldSetHasAll(&field);
EXPECT_TRUE(tr_bitfieldHasAll(&field));
EXPECT_TRUE(!tr_bitfieldHasNone(&field));
tr_bitfieldDestruct(&field);
field.setHasAll();
EXPECT_TRUE(field.hasAll());
EXPECT_TRUE(!field.hasNone());
}
}