2022-01-20 18:27:56 +00:00
|
|
|
// This file Copyright © 2008-2022 Mnemosyne LLC.
|
2022-02-07 16:25:02 +00:00
|
|
|
// It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only),
|
2022-01-20 18:27:56 +00:00
|
|
|
// or any future license endorsed by Mnemosyne LLC.
|
|
|
|
// License text can be found in the licenses/ folder.
|
2009-06-15 00:11:06 +00:00
|
|
|
|
2021-09-19 20:41:35 +00:00
|
|
|
#include <algorithm>
|
2022-04-02 00:48:09 +00:00
|
|
|
#include <array>
|
2022-07-27 21:53:39 +00:00
|
|
|
#include <climits> // SIZE_MAX
|
2021-10-24 20:43:36 +00:00
|
|
|
#include <vector>
|
2009-06-15 00:11:06 +00:00
|
|
|
|
2022-04-22 11:54:35 +00:00
|
|
|
#include "tr-popcount.h"
|
|
|
|
|
2009-06-15 00:11:06 +00:00
|
|
|
#include "transmission.h"
|
2021-10-24 20:43:36 +00:00
|
|
|
|
2009-06-15 00:11:06 +00:00
|
|
|
#include "bitfield.h"
|
2017-06-08 07:24:12 +00:00
|
|
|
#include "tr-assert.h"
|
2011-02-23 03:54:04 +00:00
|
|
|
|
2011-03-28 16:31:05 +00:00
|
|
|
/****
|
|
|
|
*****
|
|
|
|
****/
|
|
|
|
|
2021-10-24 20:43:36 +00:00
|
|
|
namespace
|
|
|
|
{
|
|
|
|
|
2022-04-02 00:48:09 +00:00
|
|
|
[[nodiscard]] constexpr size_t getBytesNeeded(size_t bit_count) noexcept
|
2021-10-24 20:43:36 +00:00
|
|
|
{
|
2022-04-21 14:28:38 +00:00
|
|
|
/* NB: If can guarantee bit_count <= SIZE_MAX - 8 then faster logic
|
2022-04-17 15:54:38 +00:00
|
|
|
is ((bit_count + 7) >> 3). */
|
2021-10-24 20:43:36 +00:00
|
|
|
return (bit_count >> 3) + ((bit_count & 7) != 0 ? 1 : 0);
|
|
|
|
}
|
|
|
|
|
2022-04-22 11:54:35 +00:00
|
|
|
/* Used only in cases where it can be guranteed bit_count <= SIZE_MAX - 8 */
|
|
|
|
[[nodiscard]] constexpr size_t getBytesNeededSafe(size_t bit_count) noexcept
|
|
|
|
{
|
|
|
|
return ((bit_count + 7) >> 3);
|
|
|
|
}
|
|
|
|
|
2021-12-17 05:47:51 +00:00
|
|
|
void setAllTrue(uint8_t* array, size_t bit_count)
|
2021-10-24 20:43:36 +00:00
|
|
|
{
|
|
|
|
uint8_t constexpr Val = 0xFF;
|
2022-04-22 11:54:35 +00:00
|
|
|
/* Only ever called internally with in-use bit counts. Impossible
|
|
|
|
for bitcount > SIZE_MAX - 8. */
|
|
|
|
size_t const n = getBytesNeededSafe(bit_count);
|
2021-10-24 20:43:36 +00:00
|
|
|
|
|
|
|
if (n > 0)
|
|
|
|
{
|
|
|
|
std::fill_n(array, n, Val);
|
2022-04-22 11:54:35 +00:00
|
|
|
/* -bit_count & 7U. Since bitcount is unsigned do ~bitcount +
|
|
|
|
1 to replace -bitcount as linters warn about negating
|
|
|
|
unsigned types. Any compiler will optimize ~x + 1 to -x in
|
|
|
|
the backend. */
|
2022-07-27 14:03:13 +00:00
|
|
|
uint32_t const shift = ((~bit_count) + 1) & 7U;
|
2022-04-22 11:54:35 +00:00
|
|
|
array[n - 1] = Val << shift;
|
2021-10-24 20:43:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-17 15:54:38 +00:00
|
|
|
/* Switch to std::popcount if project upgrades to c++20 or newer */
|
2022-04-22 11:54:35 +00:00
|
|
|
[[nodiscard]] uint32_t doPopcount(uint8_t flags) noexcept
|
2022-04-17 15:54:38 +00:00
|
|
|
{
|
2022-04-22 11:54:35 +00:00
|
|
|
/* If flags are ever expanded to use machine words instead of
|
|
|
|
uint8_t popcnt64 is also available */
|
|
|
|
return tr_popcnt<uint8_t>::count(flags);
|
2022-04-17 15:54:38 +00:00
|
|
|
}
|
|
|
|
|
2022-04-22 11:54:35 +00:00
|
|
|
[[nodiscard]] size_t rawCountFlags(uint8_t const* flags, size_t n) noexcept
|
2022-04-02 00:48:09 +00:00
|
|
|
{
|
|
|
|
auto ret = size_t{};
|
|
|
|
|
|
|
|
for (auto const* const end = flags + n; flags != end; ++flags)
|
|
|
|
{
|
2022-04-17 15:54:38 +00:00
|
|
|
ret += doPopcount(*flags);
|
2022-04-02 00:48:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2021-10-24 20:43:36 +00:00
|
|
|
} // namespace
|
|
|
|
|
|
|
|
/****
|
|
|
|
*****
|
|
|
|
****/
|
|
|
|
|
2022-04-02 00:48:09 +00:00
|
|
|
size_t tr_bitfield::countFlags() const noexcept
|
2011-03-30 04:14:57 +00:00
|
|
|
{
|
2022-04-02 00:48:09 +00:00
|
|
|
return rawCountFlags(std::data(flags_), std::size(flags_));
|
2011-03-30 04:14:57 +00:00
|
|
|
}
|
|
|
|
|
2022-04-02 00:48:09 +00:00
|
|
|
size_t tr_bitfield::countFlags(size_t begin, size_t end) const noexcept
|
2011-03-28 16:31:05 +00:00
|
|
|
{
|
2022-04-17 15:54:38 +00:00
|
|
|
auto ret = size_t{};
|
2019-03-17 04:07:48 +00:00
|
|
|
size_t const first_byte = begin >> 3U;
|
|
|
|
size_t const last_byte = (end - 1) >> 3U;
|
2012-12-05 17:29:46 +00:00
|
|
|
|
2021-10-16 14:04:19 +00:00
|
|
|
if (bit_count_ == 0)
|
2017-04-19 12:04:45 +00:00
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
2011-03-28 16:31:05 +00:00
|
|
|
|
2021-10-24 20:43:36 +00:00
|
|
|
if (first_byte >= std::size(flags_))
|
2017-04-19 12:04:45 +00:00
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
2011-03-29 16:39:30 +00:00
|
|
|
|
2017-06-08 07:24:12 +00:00
|
|
|
TR_ASSERT(begin < end);
|
2021-10-24 20:43:36 +00:00
|
|
|
TR_ASSERT(!std::empty(flags_));
|
2011-03-28 16:31:05 +00:00
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
if (first_byte == last_byte)
|
2011-03-28 16:31:05 +00:00
|
|
|
{
|
2021-10-24 20:43:36 +00:00
|
|
|
uint8_t val = flags_[first_byte];
|
2011-03-28 16:31:05 +00:00
|
|
|
|
2022-04-17 15:54:38 +00:00
|
|
|
auto i = begin & 7U;
|
2017-04-19 12:04:45 +00:00
|
|
|
val <<= i;
|
2022-04-17 15:54:38 +00:00
|
|
|
i = (begin - end) & 7U;
|
2017-04-19 12:04:45 +00:00
|
|
|
val >>= i;
|
2022-04-17 15:54:38 +00:00
|
|
|
ret = doPopcount(val);
|
2011-03-28 16:31:05 +00:00
|
|
|
}
|
2017-04-19 12:04:45 +00:00
|
|
|
else
|
2011-03-28 16:31:05 +00:00
|
|
|
{
|
2021-10-24 20:43:36 +00:00
|
|
|
size_t const walk_end = std::min(std::size(flags_), last_byte);
|
2017-04-19 12:04:45 +00:00
|
|
|
|
|
|
|
/* first byte */
|
2022-04-17 15:54:38 +00:00
|
|
|
size_t const first_shift = begin & 7U;
|
2021-10-26 18:02:07 +00:00
|
|
|
uint8_t val = flags_[first_byte];
|
2017-05-13 22:38:31 +00:00
|
|
|
val <<= first_shift;
|
2022-04-17 15:54:38 +00:00
|
|
|
/* No need to shift back val for correct popcount. */
|
|
|
|
ret = doPopcount(val);
|
2017-04-19 12:04:45 +00:00
|
|
|
|
|
|
|
/* middle bytes */
|
2022-04-17 15:54:38 +00:00
|
|
|
|
2022-04-22 11:54:35 +00:00
|
|
|
/* Use 2x accumulators to help alleviate high latency of
|
|
|
|
popcnt instruction on many architectures. */
|
2022-04-17 15:54:38 +00:00
|
|
|
size_t tmp_accum = 0;
|
|
|
|
for (size_t i = first_byte + 1; i < walk_end;)
|
2017-04-19 12:04:45 +00:00
|
|
|
{
|
2022-04-17 15:54:38 +00:00
|
|
|
tmp_accum += doPopcount(flags_[i]);
|
2022-08-02 23:34:53 +00:00
|
|
|
i += 2;
|
|
|
|
if (i > walk_end)
|
2022-04-17 15:54:38 +00:00
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
ret += doPopcount(flags_[i - 1]);
|
2017-04-19 12:04:45 +00:00
|
|
|
}
|
2022-04-17 15:54:38 +00:00
|
|
|
ret += tmp_accum;
|
2012-12-05 17:29:46 +00:00
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
/* last byte */
|
2021-10-24 20:43:36 +00:00
|
|
|
if (last_byte < std::size(flags_))
|
2012-12-05 17:29:46 +00:00
|
|
|
{
|
2022-04-22 11:54:35 +00:00
|
|
|
/* -end & 7U. Since bitcount is unsigned do ~end + 1 to
|
|
|
|
replace -end as linters warn about negating unsigned
|
|
|
|
types. Any compiler will optimize ~x + 1 to -x in the
|
|
|
|
backend. */
|
|
|
|
uint32_t const last_shift = (~end + 1) & 7U;
|
2021-10-24 20:43:36 +00:00
|
|
|
val = flags_[last_byte];
|
2017-05-13 22:38:31 +00:00
|
|
|
val >>= last_shift;
|
2022-04-17 15:54:38 +00:00
|
|
|
/* No need to shift back val for correct popcount. */
|
|
|
|
ret += doPopcount(val);
|
2011-03-30 04:14:57 +00:00
|
|
|
}
|
2011-03-28 16:31:05 +00:00
|
|
|
}
|
|
|
|
|
2021-10-24 20:43:36 +00:00
|
|
|
TR_ASSERT(ret <= (begin - end));
|
2017-04-19 12:04:45 +00:00
|
|
|
return ret;
|
2009-06-15 00:11:06 +00:00
|
|
|
}
|
|
|
|
|
2021-10-24 20:43:36 +00:00
|
|
|
size_t tr_bitfield::count(size_t begin, size_t end) const
|
2011-03-28 16:31:05 +00:00
|
|
|
{
|
2021-10-24 20:43:36 +00:00
|
|
|
if (hasAll())
|
2017-04-19 12:04:45 +00:00
|
|
|
{
|
2021-10-24 20:43:36 +00:00
|
|
|
return end - begin;
|
|
|
|
}
|
2012-12-13 02:00:45 +00:00
|
|
|
|
2021-10-24 20:43:36 +00:00
|
|
|
if (hasNone())
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
2012-12-13 02:00:45 +00:00
|
|
|
|
2021-10-24 20:43:36 +00:00
|
|
|
return countFlags(begin, end);
|
|
|
|
}
|
|
|
|
|
2011-03-28 16:31:05 +00:00
|
|
|
/***
|
|
|
|
****
|
|
|
|
***/
|
|
|
|
|
2021-12-15 21:25:42 +00:00
|
|
|
bool tr_bitfield::isValid() const
|
2011-03-28 16:31:05 +00:00
|
|
|
{
|
2021-12-15 21:25:42 +00:00
|
|
|
return std::empty(flags_) || true_count_ == countFlags();
|
2011-03-30 04:14:57 +00:00
|
|
|
}
|
|
|
|
|
2021-10-24 20:43:36 +00:00
|
|
|
std::vector<uint8_t> tr_bitfield::raw() const
|
2011-04-05 00:29:42 +00:00
|
|
|
{
|
2022-04-22 11:54:35 +00:00
|
|
|
/* Impossible for bit_count_ to exceed SIZE_MAX - 8 */
|
|
|
|
auto const n = getBytesNeededSafe(bit_count_);
|
2012-12-05 17:29:46 +00:00
|
|
|
|
2021-10-24 20:43:36 +00:00
|
|
|
if (!std::empty(flags_))
|
|
|
|
{
|
|
|
|
return flags_;
|
|
|
|
}
|
2011-04-05 00:29:42 +00:00
|
|
|
|
2021-10-24 20:43:36 +00:00
|
|
|
auto raw = std::vector<uint8_t>(n);
|
2012-12-05 17:29:46 +00:00
|
|
|
|
2021-10-24 20:43:36 +00:00
|
|
|
if (hasAll())
|
2013-07-29 04:19:15 +00:00
|
|
|
{
|
2022-03-22 19:01:07 +00:00
|
|
|
setAllTrue(std::data(raw), bit_count_);
|
2013-07-29 04:19:15 +00:00
|
|
|
}
|
2021-10-24 20:43:36 +00:00
|
|
|
|
|
|
|
return raw;
|
2011-03-28 16:31:05 +00:00
|
|
|
}
|
|
|
|
|
2021-10-24 20:43:36 +00:00
|
|
|
void tr_bitfield::ensureBitsAlloced(size_t n)
|
2009-06-15 00:11:06 +00:00
|
|
|
{
|
2021-10-24 20:43:36 +00:00
|
|
|
bool const has_all = hasAll();
|
2011-03-28 16:31:05 +00:00
|
|
|
|
2022-04-22 11:54:35 +00:00
|
|
|
/* Cant use getBytesNeededSafe as n can be > SIZE_MAX - 8. */
|
2021-10-24 20:43:36 +00:00
|
|
|
size_t const bytes_needed = has_all ? getBytesNeeded(std::max(n, true_count_)) : getBytesNeeded(n);
|
2011-03-30 04:14:57 +00:00
|
|
|
|
2021-10-24 20:43:36 +00:00
|
|
|
if (std::size(flags_) < bytes_needed)
|
2011-03-30 04:14:57 +00:00
|
|
|
{
|
2021-10-24 20:43:36 +00:00
|
|
|
flags_.resize(bytes_needed);
|
|
|
|
if (has_all)
|
|
|
|
{
|
|
|
|
setAllTrue(std::data(flags_), true_count_);
|
|
|
|
}
|
2011-03-30 04:14:57 +00:00
|
|
|
}
|
2021-10-24 20:43:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool tr_bitfield::ensureNthBitAlloced(size_t nth)
|
|
|
|
{
|
|
|
|
// count is zero-based, so we need to allocate nth+1 bits before setting the nth */
|
|
|
|
if (nth == SIZE_MAX)
|
2017-04-19 12:04:45 +00:00
|
|
|
{
|
2021-10-24 20:43:36 +00:00
|
|
|
return false;
|
2017-04-19 12:04:45 +00:00
|
|
|
}
|
2014-06-29 01:43:27 +00:00
|
|
|
|
2021-10-24 20:43:36 +00:00
|
|
|
ensureBitsAlloced(nth + 1);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-04-02 00:48:09 +00:00
|
|
|
void tr_bitfield::freeArray() noexcept
|
2021-10-24 20:43:36 +00:00
|
|
|
{
|
|
|
|
flags_ = std::vector<uint8_t>{};
|
2011-03-28 16:31:05 +00:00
|
|
|
}
|
|
|
|
|
2022-04-02 00:48:09 +00:00
|
|
|
void tr_bitfield::setTrueCount(size_t n) noexcept
|
2011-03-28 16:31:05 +00:00
|
|
|
{
|
2022-04-01 23:00:51 +00:00
|
|
|
TR_ASSERT(bit_count_ == 0 || n <= bit_count_);
|
2015-12-27 16:34:47 +00:00
|
|
|
|
2021-10-24 20:43:36 +00:00
|
|
|
true_count_ = n;
|
|
|
|
have_all_hint_ = n == bit_count_;
|
|
|
|
have_none_hint_ = n == 0;
|
2011-03-28 16:31:05 +00:00
|
|
|
|
2021-10-24 20:43:36 +00:00
|
|
|
if (hasAll() || hasNone())
|
2017-04-19 12:04:45 +00:00
|
|
|
{
|
2021-10-24 20:43:36 +00:00
|
|
|
freeArray();
|
2017-04-19 12:04:45 +00:00
|
|
|
}
|
2021-10-24 20:43:36 +00:00
|
|
|
|
2021-12-15 21:25:42 +00:00
|
|
|
TR_ASSERT(isValid());
|
2021-10-24 20:43:36 +00:00
|
|
|
}
|
|
|
|
|
2022-04-02 00:48:09 +00:00
|
|
|
void tr_bitfield::rebuildTrueCount() noexcept
|
2021-10-24 20:43:36 +00:00
|
|
|
{
|
|
|
|
setTrueCount(countFlags());
|
|
|
|
}
|
|
|
|
|
2022-04-02 00:48:09 +00:00
|
|
|
void tr_bitfield::incrementTrueCount(size_t inc) noexcept
|
2021-10-24 20:43:36 +00:00
|
|
|
{
|
|
|
|
TR_ASSERT(bit_count_ == 0 || inc <= bit_count_);
|
|
|
|
TR_ASSERT(bit_count_ == 0 || true_count_ <= bit_count_ - inc);
|
|
|
|
|
|
|
|
setTrueCount(true_count_ + inc);
|
|
|
|
}
|
|
|
|
|
2022-04-02 00:48:09 +00:00
|
|
|
void tr_bitfield::decrementTrueCount(size_t dec) noexcept
|
2021-10-24 20:43:36 +00:00
|
|
|
{
|
|
|
|
TR_ASSERT(bit_count_ == 0 || dec <= bit_count_);
|
|
|
|
TR_ASSERT(bit_count_ == 0 || true_count_ >= dec);
|
|
|
|
|
|
|
|
setTrueCount(true_count_ - dec);
|
2015-12-27 16:34:47 +00:00
|
|
|
}
|
|
|
|
|
2011-03-28 16:31:05 +00:00
|
|
|
/****
|
|
|
|
*****
|
|
|
|
****/
|
|
|
|
|
2021-10-24 20:43:36 +00:00
|
|
|
tr_bitfield::tr_bitfield(size_t bit_count)
|
|
|
|
: bit_count_{ bit_count }
|
2011-02-23 03:54:04 +00:00
|
|
|
{
|
2021-12-15 21:25:42 +00:00
|
|
|
TR_ASSERT(isValid());
|
2021-10-24 20:43:36 +00:00
|
|
|
}
|
|
|
|
|
2022-04-02 00:48:09 +00:00
|
|
|
void tr_bitfield::setHasNone() noexcept
|
2021-10-24 20:43:36 +00:00
|
|
|
{
|
|
|
|
freeArray();
|
2021-10-16 14:04:19 +00:00
|
|
|
true_count_ = 0;
|
2021-10-24 20:43:36 +00:00
|
|
|
have_all_hint_ = false;
|
|
|
|
have_none_hint_ = true;
|
2021-10-11 17:29:14 +00:00
|
|
|
|
2021-12-15 21:25:42 +00:00
|
|
|
TR_ASSERT(isValid());
|
2009-06-15 00:11:06 +00:00
|
|
|
}
|
|
|
|
|
2022-04-02 00:48:09 +00:00
|
|
|
void tr_bitfield::setHasAll() noexcept
|
2011-03-28 16:31:05 +00:00
|
|
|
{
|
2021-10-24 20:43:36 +00:00
|
|
|
freeArray();
|
|
|
|
true_count_ = bit_count_;
|
|
|
|
have_all_hint_ = true;
|
|
|
|
have_none_hint_ = false;
|
2021-10-16 14:04:19 +00:00
|
|
|
|
2021-12-15 21:25:42 +00:00
|
|
|
TR_ASSERT(isValid());
|
2011-03-28 16:31:05 +00:00
|
|
|
}
|
|
|
|
|
2021-11-08 00:25:45 +00:00
|
|
|
void tr_bitfield::setRaw(uint8_t const* raw, size_t byte_count)
|
2011-03-28 16:31:05 +00:00
|
|
|
{
|
2022-03-09 23:43:42 +00:00
|
|
|
flags_.assign(raw, raw + byte_count);
|
2012-12-05 17:29:46 +00:00
|
|
|
|
2021-11-08 00:25:45 +00:00
|
|
|
// ensure any excess bits at the end of the array are set to '0'.
|
2022-04-22 11:54:35 +00:00
|
|
|
if (byte_count == getBytesNeededSafe(bit_count_))
|
2012-12-05 17:29:46 +00:00
|
|
|
{
|
2022-03-24 13:31:00 +00:00
|
|
|
auto const excess_bit_count = byte_count * 8 - bit_count_;
|
2021-10-24 20:43:36 +00:00
|
|
|
|
|
|
|
TR_ASSERT(excess_bit_count <= 7);
|
2017-04-19 12:04:45 +00:00
|
|
|
|
2019-07-14 12:40:41 +00:00
|
|
|
if (excess_bit_count != 0)
|
2017-04-19 12:04:45 +00:00
|
|
|
{
|
2021-10-24 20:43:36 +00:00
|
|
|
flags_.back() &= 0xff << excess_bit_count;
|
2017-04-19 12:04:45 +00:00
|
|
|
}
|
2011-09-26 22:50:42 +00:00
|
|
|
}
|
|
|
|
|
2021-10-24 20:43:36 +00:00
|
|
|
rebuildTrueCount();
|
2011-03-28 16:31:05 +00:00
|
|
|
}
|
|
|
|
|
2021-10-24 20:43:36 +00:00
|
|
|
void tr_bitfield::setFromBools(bool const* flags, size_t n)
|
2011-09-20 23:39:40 +00:00
|
|
|
{
|
2021-10-24 20:43:36 +00:00
|
|
|
size_t trueCount = 0;
|
2011-09-20 23:39:40 +00:00
|
|
|
|
2021-10-24 20:43:36 +00:00
|
|
|
freeArray();
|
|
|
|
ensureBitsAlloced(n);
|
2011-09-20 23:39:40 +00:00
|
|
|
|
2021-10-24 20:43:36 +00:00
|
|
|
for (size_t i = 0; i < n; ++i)
|
2011-03-28 16:31:05 +00:00
|
|
|
{
|
2021-10-24 20:43:36 +00:00
|
|
|
if (flags[i])
|
2020-09-10 23:50:46 +00:00
|
|
|
{
|
2021-10-24 20:43:36 +00:00
|
|
|
++trueCount;
|
|
|
|
flags_[i >> 3U] |= (0x80 >> (i & 7U));
|
2020-09-10 23:50:46 +00:00
|
|
|
}
|
2011-03-28 16:31:05 +00:00
|
|
|
}
|
2021-10-24 20:43:36 +00:00
|
|
|
|
|
|
|
setTrueCount(trueCount);
|
2009-06-15 00:11:06 +00:00
|
|
|
}
|
|
|
|
|
2021-10-24 20:43:36 +00:00
|
|
|
void tr_bitfield::set(size_t nth, bool value)
|
2009-06-15 00:11:06 +00:00
|
|
|
{
|
2021-10-24 20:43:36 +00:00
|
|
|
if (test(nth) == value)
|
2017-04-19 12:04:45 +00:00
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2021-10-17 15:34:36 +00:00
|
|
|
|
2021-10-24 20:43:36 +00:00
|
|
|
if (!ensureNthBitAlloced(nth))
|
2009-06-15 00:11:06 +00:00
|
|
|
{
|
2017-04-19 12:04:45 +00:00
|
|
|
return;
|
2009-06-15 00:11:06 +00:00
|
|
|
}
|
2017-04-19 12:04:45 +00:00
|
|
|
|
2022-04-17 15:54:38 +00:00
|
|
|
/* Already tested that val != nth bit so just swap */
|
2022-04-27 00:51:24 +00:00
|
|
|
auto& byte = flags_[nth >> 3U];
|
2022-05-23 02:22:34 +00:00
|
|
|
#ifdef TR_ENABLE_ASSERTS
|
2022-04-27 00:51:24 +00:00
|
|
|
auto const old_byte_pop = doPopcount(byte);
|
2022-05-23 02:22:34 +00:00
|
|
|
#endif
|
2022-04-27 00:51:24 +00:00
|
|
|
byte ^= 0x80 >> (nth & 7U);
|
2022-05-23 02:22:34 +00:00
|
|
|
#ifdef TR_ENABLE_ASSERTS
|
2022-04-27 00:51:24 +00:00
|
|
|
auto const new_byte_pop = doPopcount(byte);
|
2022-05-23 02:22:34 +00:00
|
|
|
#endif
|
2022-04-17 15:54:38 +00:00
|
|
|
|
2021-10-24 20:43:36 +00:00
|
|
|
if (value)
|
2017-04-19 12:04:45 +00:00
|
|
|
{
|
2022-04-27 00:51:24 +00:00
|
|
|
++true_count_;
|
|
|
|
TR_ASSERT(old_byte_pop + 1 == new_byte_pop);
|
2017-04-19 12:04:45 +00:00
|
|
|
}
|
2021-10-24 20:43:36 +00:00
|
|
|
else
|
2021-10-16 14:04:19 +00:00
|
|
|
{
|
2022-04-27 00:51:24 +00:00
|
|
|
--true_count_;
|
|
|
|
TR_ASSERT(new_byte_pop + 1 == old_byte_pop);
|
2011-03-28 16:31:05 +00:00
|
|
|
}
|
2022-04-27 00:51:24 +00:00
|
|
|
have_all_hint_ = true_count_ == bit_count_;
|
|
|
|
have_none_hint_ = true_count_ == 0;
|
2009-06-15 00:11:06 +00:00
|
|
|
}
|
|
|
|
|
2021-10-24 20:43:36 +00:00
|
|
|
/* Sets bit range [begin, end) to 1 */
|
2021-11-25 18:26:51 +00:00
|
|
|
void tr_bitfield::setSpan(size_t begin, size_t end, bool value)
|
2009-06-15 00:11:06 +00:00
|
|
|
{
|
2021-11-25 20:30:13 +00:00
|
|
|
// bounds check
|
|
|
|
end = std::min(end, bit_count_);
|
|
|
|
if (end == 0 || begin >= end)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-04-17 15:54:38 +00:00
|
|
|
// NB: count(begin, end) can be quite expensive. Might be worth it
|
|
|
|
// to fuse the count and set loop
|
2021-10-24 20:43:36 +00:00
|
|
|
size_t const old_count = count(begin, end);
|
|
|
|
size_t const new_count = value ? (end - begin) : 0;
|
2022-04-17 15:54:38 +00:00
|
|
|
// did anything change?
|
2021-10-24 20:43:36 +00:00
|
|
|
if (old_count == new_count)
|
2017-04-19 12:04:45 +00:00
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2021-10-17 15:34:36 +00:00
|
|
|
|
2021-10-24 20:43:36 +00:00
|
|
|
--end;
|
|
|
|
if (!ensureNthBitAlloced(end))
|
2017-04-19 12:04:45 +00:00
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2014-06-29 01:43:27 +00:00
|
|
|
|
2022-03-24 13:31:00 +00:00
|
|
|
auto walk = begin >> 3;
|
|
|
|
auto const last_byte = end >> 3;
|
2021-10-16 14:04:19 +00:00
|
|
|
|
2022-04-17 15:54:38 +00:00
|
|
|
unsigned char first_mask = 0xff >> (begin & 7U);
|
2022-04-22 11:54:35 +00:00
|
|
|
unsigned char last_mask = 0xff << ((~end) & 7U);
|
2021-10-24 20:43:36 +00:00
|
|
|
if (value)
|
2009-06-15 00:11:06 +00:00
|
|
|
{
|
2022-04-22 11:54:35 +00:00
|
|
|
|
2021-10-24 20:43:36 +00:00
|
|
|
if (walk == last_byte)
|
|
|
|
{
|
|
|
|
flags_[walk] |= first_mask & last_mask;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
flags_[walk] |= first_mask;
|
2022-04-17 15:54:38 +00:00
|
|
|
/* last_byte is expected to be hot in cache due to earlier
|
|
|
|
count(begin, end) */
|
2021-10-24 20:43:36 +00:00
|
|
|
flags_[last_byte] |= last_mask;
|
|
|
|
if (++walk < last_byte)
|
|
|
|
{
|
2022-03-24 13:31:00 +00:00
|
|
|
std::fill_n(std::data(flags_) + walk, last_byte - walk, 0xff);
|
2021-10-24 20:43:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
incrementTrueCount(new_count - old_count);
|
2009-06-15 00:11:06 +00:00
|
|
|
}
|
2021-10-24 20:43:36 +00:00
|
|
|
else
|
|
|
|
{
|
2022-04-17 15:54:38 +00:00
|
|
|
first_mask = ~first_mask;
|
2022-04-22 11:54:35 +00:00
|
|
|
last_mask = ~last_mask;
|
2021-10-24 20:43:36 +00:00
|
|
|
if (walk == last_byte)
|
|
|
|
{
|
|
|
|
flags_[walk] &= first_mask | last_mask;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
flags_[walk] &= first_mask;
|
2022-04-17 15:54:38 +00:00
|
|
|
/* last_byte is expected to be hot in cache due to earlier
|
|
|
|
count(begin, end) */
|
2021-10-24 20:43:36 +00:00
|
|
|
flags_[last_byte] &= last_mask;
|
|
|
|
if (++walk < last_byte)
|
|
|
|
{
|
2022-03-24 13:31:00 +00:00
|
|
|
std::fill_n(std::data(flags_) + walk, last_byte - walk, 0);
|
2021-10-24 20:43:36 +00:00
|
|
|
}
|
|
|
|
}
|
2009-06-15 00:11:06 +00:00
|
|
|
|
2021-10-24 20:43:36 +00:00
|
|
|
decrementTrueCount(old_count);
|
|
|
|
}
|
2011-02-23 03:54:04 +00:00
|
|
|
}
|