From 85eed22c0eb3d5c786944b4f8a08c4b21914d83d Mon Sep 17 00:00:00 2001 From: Parker Levin Date: Tue, 16 Sep 2025 05:35:42 -0700 Subject: [PATCH 1/8] NO_REPEAT_RANDOM using Sample Without Replacement 2nd attempt --- sound/effect.h | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/sound/effect.h b/sound/effect.h index 25f1f502e..7d1930be8 100644 --- a/sound/effect.h +++ b/sound/effect.h @@ -5,6 +5,14 @@ #include "../common/atomic.h" #include "../common/file_reader.h" +#ifndef NO_REPEAT_RANDOM_BUFFER_SIZE_BITS +#define NO_REPEAT_RANDOM_BUFFER_SIZE_BITS 24 +#endif + +#if NO_REPEAT_RANDOM_BUFFER_SIZE_BITS > 256 +#define NO_REPEAT_RANDOM_BUFFER_SIZE_BITS 256 +#endif + class Effect; Effect* all_effects = NULL; @@ -175,6 +183,11 @@ class Effect { paired_ = false; #ifdef KILL_OLD_PLAYERS killable_ = false; +#endif +#ifdef NO_REPEAT_RANDOM + for (size_t i = 0; i < NO_REPEAT_RANDOM_BUFFER_SIZE_BITS; ++i) available_[i] = available_mark_; + last_ = -1; + last_subid_ = -1; #endif } static int altnum(const char* s) { @@ -379,6 +392,10 @@ class Effect { } #ifdef NO_REPEAT_RANDOM + // Storage for random sampling without replacement. + bool available_[NO_REPEAT_RANDOM_BUFFER_SIZE_BITS]; + bool available_mark_ = false; + int16_t last_ = -1; int16_t last_subid_ = -1; @@ -406,6 +423,32 @@ class Effect { int random_subid(int filenum) { if (!sub_files_) return 0; +#ifdef NO_REPEAT_RANDOM + size_t total_files = files_found() * sub_files_; + if (total_files > 2 && total_files <= NO_REPEAT_RANDOM_BUFFER_SIZE_BITS) { + const uint8_t start = filenum * files_found(); + const uint8_t end = start + sub_files_ - 1; + + uint8_t n = 0; + for (uint8_t i = start; i <= end; ++i) n += available_[i] == available_mark_ && (last_ != filenum || last_subid_ != i % sub_files_); + if (!n) { + for (uint8_t i = start; i <= end; ++i) available_[i] = available_mark_; + n = sub_files_; + } + + uint8_t nth_ret = RANDOMIZE(n, -1); + for (uint8_t i = start; i <= end; ++i) { + if (available_[i] != available_mark_ || (last_ == filenum && last_subid_ == i % sub_files_)) continue; + if (!nth_ret) { + available_[i] = !available_mark_; + last_ = i / sub_files_; + last_subid_ = i % sub_files_; + return last_subid_; + } + nth_ret--; + } + } +#endif int ret = RANDOMIZE(sub_files_, last_ == filenum ? last_subid_ : -1); #ifdef NO_REPEAT_RANDOM last_subid_ = ret; @@ -430,6 +473,35 @@ class Effect { (file_type_ == FileType::SOUND || paired_)) { n = std::min(SaberBase::sound_number, num_files - 1); } else { +#ifdef NO_REPEAT_RANDOM + size_t total_files = files_found() * number_of_subfiles(); + if (total_files > 2 && total_files <= NO_REPEAT_RANDOM_BUFFER_SIZE_BITS) { + uint8_t n = 0; + for (uint8_t i = 0; i < total_files; ++i) { + const int16_t file = sub_files_ ? i / sub_files_ : i; + const int16_t subfile = sub_files_ ? i % sub_files_ : 0; + n += available_[i] == available_mark_ && (last_ != file || (sub_files_ && last_subid_ != subfile)); + } + if (!n) { + available_mark_ = !available_mark_; + n = total_files; + } + + uint8_t nth_ret = RANDOMIZE(n, -1); + for (uint8_t i = 0; i < total_files; ++i) { + const int16_t file = sub_files_ ? i / sub_files_ : i; + const int16_t subfile = sub_files_ ? i % sub_files_ : 0; + if (available_[i] != available_mark_ || (last_ == file && (!sub_files_ || last_subid_ == subfile))) continue; + if (!nth_ret) { + available_[i] = !available_mark_; + last_ = file; + if (sub_files_) last_subid_ = subfile; + return FileID(this, last_, sub_files_ ? last_subid_ : 0); + } + nth_ret--; + } + } +#endif n = RANDOMIZE(num_files, last_); } int subid = random_subid(n); From d2455791146ac9d8437917a4f497400696da070f Mon Sep 17 00:00:00 2001 From: Parker Levin Date: Wed, 1 Oct 2025 23:37:42 -0700 Subject: [PATCH 2/8] Use BitSet instead of Boolean Array --- common/arg_parser.h | 23 ++++++++++ sound/effect.h | 108 +++++++++++++++++++++++--------------------- 2 files changed, 79 insertions(+), 52 deletions(-) diff --git a/common/arg_parser.h b/common/arg_parser.h index 122abf1a4..73a7e676e 100644 --- a/common/arg_parser.h +++ b/common/arg_parser.h @@ -141,6 +141,12 @@ class BitSet { bits_[i] = 0; } } + void fill(size_t bit = SIZE) { + for (size_t i = 0; i < NELEM(bits_); i++) { + bits_[i] = ~uint32_t(0); + if (i == (bit >> 5) && !!(bit & 31)) bits_[i] >>= 32 - (bit & 31); + } + } size_t popcount() const { size_t ret = 0; for (size_t i = 0; i < NELEM(bits_); i++) { @@ -148,6 +154,13 @@ class BitSet { } return ret; } + size_t popcount_subset(size_t first, size_t last) const { + size_t ret = 0; + for (size_t i = first; i <= last; i++) { + ret += get(i); + } + return ret; + } size_t next(size_t bit) const { for (size_t i = 1; i <= SIZE; i++) { size_t j = (bit + i) % SIZE; @@ -172,6 +185,16 @@ class BitSet { } return 0; } + size_t nth_subset(int bit, size_t first, size_t last) const { + for (size_t i = first; i <= last; i++) { + if (get(i)) { + if (bit-- <= 0) { + return i; + } + } + } + return 0; + } void operator>>=(int bits) { if (!bits) return; for (int i = 0; i < (int)SIZE; i++) { diff --git a/sound/effect.h b/sound/effect.h index 7d1930be8..941a81d49 100644 --- a/sound/effect.h +++ b/sound/effect.h @@ -5,12 +5,16 @@ #include "../common/atomic.h" #include "../common/file_reader.h" -#ifndef NO_REPEAT_RANDOM_BUFFER_SIZE_BITS -#define NO_REPEAT_RANDOM_BUFFER_SIZE_BITS 24 +#ifdef RANDOM_SAMPLE_WITHOUT_REPLACEMENT +#include "../common/arg_parser.h" + +#ifndef SAMPLE_WITHOUT_REPLACEMENT_BUFFER_SIZE_BITS +#define SAMPLE_WITHOUT_REPLACEMENT_BUFFER_SIZE_BITS 32 #endif -#if NO_REPEAT_RANDOM_BUFFER_SIZE_BITS > 256 -#define NO_REPEAT_RANDOM_BUFFER_SIZE_BITS 256 +#if SAMPLE_WITHOUT_REPLACEMENT_BUFFER_SIZE_BITS > 256 +#define SAMPLE_WITHOUT_REPLACEMENT_BUFFER_SIZE_BITS 256 +#endif #endif class Effect; @@ -185,7 +189,9 @@ class Effect { killable_ = false; #endif #ifdef NO_REPEAT_RANDOM - for (size_t i = 0; i < NO_REPEAT_RANDOM_BUFFER_SIZE_BITS; ++i) available_[i] = available_mark_; +#ifdef RANDOM_SAMPLE_WITHOUT_REPLACEMENT + available_.clear(); +#endif last_ = -1; last_subid_ = -1; #endif @@ -392,9 +398,12 @@ class Effect { } #ifdef NO_REPEAT_RANDOM + +#ifdef RANDOM_SAMPLE_WITHOUT_REPLACEMENT // Storage for random sampling without replacement. - bool available_[NO_REPEAT_RANDOM_BUFFER_SIZE_BITS]; - bool available_mark_ = false; + // Each bit tracks a specific File. `1` marks as available to select. + BitSet available_; +#endif int16_t last_ = -1; int16_t last_subid_ = -1; @@ -424,30 +433,32 @@ class Effect { int random_subid(int filenum) { if (!sub_files_) return 0; #ifdef NO_REPEAT_RANDOM - size_t total_files = files_found() * sub_files_; - if (total_files > 2 && total_files <= NO_REPEAT_RANDOM_BUFFER_SIZE_BITS) { - const uint8_t start = filenum * files_found(); - const uint8_t end = start + sub_files_ - 1; - - uint8_t n = 0; - for (uint8_t i = start; i <= end; ++i) n += available_[i] == available_mark_ && (last_ != filenum || last_subid_ != i % sub_files_); - if (!n) { - for (uint8_t i = start; i <= end; ++i) available_[i] = available_mark_; - n = sub_files_; - } +#ifdef RANDOM_SAMPLE_WITHOUT_REPLACEMENT + const size_t total_files = files_found() * number_of_subfiles(); + if (total_files > 2 && total_files <= SAMPLE_WITHOUT_REPLACEMENT_BUFFER_SIZE_BITS) { + const size_t first = filenum * files_found(); + const size_t last = first + sub_files_ - 1; + + uint8_t n = available_.popcount_subset(first, last); + if (!n) { + for (size_t bit = first; bit <= last; ++bit) { + available_.set(bit); + } + n = available_.popcount_subset(first, last); + } + if (n == sub_files_ && filenum == last_ && last_subid_ >= 0) n--; - uint8_t nth_ret = RANDOMIZE(n, -1); - for (uint8_t i = start; i <= end; ++i) { - if (available_[i] != available_mark_ || (last_ == filenum && last_subid_ == i % sub_files_)) continue; - if (!nth_ret) { - available_[i] = !available_mark_; - last_ = i / sub_files_; - last_subid_ = i % sub_files_; - return last_subid_; + size_t ret = available_.nth_subset(RANDOMIZE(n, -1), first, last); + if (ret == last_ * sub_files_ + last_subid_) { + ret = available_.popcount_subset(ret, last) > 1 ? available_.next(ret) : available_.prev(ret); } - nth_ret--; + + available_.clear(ret); + last_ = ret / sub_files_; + last_subid_ = ret % sub_files_; + return last_subid_; } - } +#endif #endif int ret = RANDOMIZE(sub_files_, last_ == filenum ? last_subid_ : -1); #ifdef NO_REPEAT_RANDOM @@ -474,33 +485,26 @@ class Effect { n = std::min(SaberBase::sound_number, num_files - 1); } else { #ifdef NO_REPEAT_RANDOM - size_t total_files = files_found() * number_of_subfiles(); - if (total_files > 2 && total_files <= NO_REPEAT_RANDOM_BUFFER_SIZE_BITS) { - uint8_t n = 0; - for (uint8_t i = 0; i < total_files; ++i) { - const int16_t file = sub_files_ ? i / sub_files_ : i; - const int16_t subfile = sub_files_ ? i % sub_files_ : 0; - n += available_[i] == available_mark_ && (last_ != file || (sub_files_ && last_subid_ != subfile)); - } +#ifdef RANDOM_SAMPLE_WITHOUT_REPLACEMENT + const size_t total_files = files_found() * number_of_subfiles(); + if (total_files > 2 && total_files <= SAMPLE_WITHOUT_REPLACEMENT_BUFFER_SIZE_BITS) { + uint8_t n = available_.popcount(); if (!n) { - available_mark_ = !available_mark_; - n = total_files; - } - - uint8_t nth_ret = RANDOMIZE(n, -1); - for (uint8_t i = 0; i < total_files; ++i) { - const int16_t file = sub_files_ ? i / sub_files_ : i; - const int16_t subfile = sub_files_ ? i % sub_files_ : 0; - if (available_[i] != available_mark_ || (last_ == file && (!sub_files_ || last_subid_ == subfile))) continue; - if (!nth_ret) { - available_[i] = !available_mark_; - last_ = file; - if (sub_files_) last_subid_ = subfile; - return FileID(this, last_, sub_files_ ? last_subid_ : 0); - } - nth_ret--; + available_.fill(total_files); + n = available_.popcount(); } + if (n == total_files && (last_ >= 0 || last_subid_ >= 0)) n--; + + size_t ret = available_.nth(RANDOMIZE(n, -1)); + const int16_t last = sub_files_ ? last_ * sub_files_ + last_subid_ : last_; + if (ret == last) ret = available_.next(ret); + + available_.clear(ret); + last_ = sub_files_ ? ret / sub_files_ : ret; + if (sub_files_) last_subid_ = ret % sub_files_; + return FileID(this, last_, sub_files_ ? last_subid_ : 0); } +#endif #endif n = RANDOMIZE(num_files, last_); } From 3c1970f18d42702e03cc5ba7ef2aeebec1f61582 Mon Sep 17 00:00:00 2001 From: Parker Levin Date: Sat, 11 Oct 2025 01:41:33 -0700 Subject: [PATCH 3/8] Add Bitwise Operands to BitSet --- common/arg_parser.h | 75 +++++++++++++++++++++++++++++++++++++++------ sound/effect.h | 10 +++--- 2 files changed, 70 insertions(+), 15 deletions(-) diff --git a/common/arg_parser.h b/common/arg_parser.h index 73a7e676e..569cc83a3 100644 --- a/common/arg_parser.h +++ b/common/arg_parser.h @@ -135,17 +135,22 @@ class BitSet { bool operator[](size_t bit) const { return !!(bits_[bit >> 5] & (1UL << (bit & 31))); } bool get(size_t bit) const { return !!(bits_[bit >> 5] & (1UL << (bit & 31))); } void set(size_t bit) { bits_[bit >> 5] |= (1UL << (bit & 31)); } + void set_subset(size_t first, size_t last) { *this |= ~(BitSet::fill() << last + 1) & (BitSet::fill() << first); } void clear(size_t bit) { bits_[bit >> 5] &=~ (1UL << (bit & 31)); } + void clear_subset(size_t first, size_t last) { *this &= (BitSet::fill() << last + 1) | ~(BitSet::fill() << first); } void clear() { for (size_t i = 0; i < NELEM(bits_); i++) { bits_[i] = 0; } } - void fill(size_t bit = SIZE) { - for (size_t i = 0; i < NELEM(bits_); i++) { - bits_[i] = ~uint32_t(0); - if (i == (bit >> 5) && !!(bit & 31)) bits_[i] >>= 32 - (bit & 31); + // Create a BitSet with a given number of initially set bits + static BitSet fill(size_t n = SIZE) { + BitSet ret; + for (size_t i = 0; i <= n >> 5; i++) { + ret.bits_[i] = ~uint32_t(0); } + if (!!(n & 31)) ret.bits_[n >> 5] >>= 32 - (n & 31); + return ret; } size_t popcount() const { size_t ret = 0; @@ -155,11 +160,8 @@ class BitSet { return ret; } size_t popcount_subset(size_t first, size_t last) const { - size_t ret = 0; - for (size_t i = first; i <= last; i++) { - ret += get(i); - } - return ret; + BitSet subset = ~(BitSet::fill() << last + 1) & (BitSet::fill() << first); + return (subset & *this).popcount(); } size_t next(size_t bit) const { for (size_t i = 1; i <= SIZE; i++) { @@ -205,6 +207,61 @@ class BitSet { } } } + BitSet operator>>(int bits) const { + BitSet ret = *this; + ret >>= bits; + return ret; + } + void operator<<=(int bits) { + if (!bits) return; + for (int i = SIZE - 1; i >= 0; i--) { + if (i - bits >= 0 && get(i - bits)) { + set(i); + } else { + clear(i); + } + } + } + BitSet operator<<(int bits) const { + BitSet ret = *this; + ret <<= bits; + return ret; + } + BitSet operator~() const { + BitSet ret = *this; + for (size_t i = 0; i < NELEM(bits_); i++) { + ret.bits_[i] = ~ret.bits_[i]; + } + if (!!(SIZE & 31)) ret.bits_[SIZE >> 5] &= ~uint32_t(0) >> 32 - (SIZE & 31); + return ret; + } + void operator&=(const BitSet& other) { + for (size_t i = 0; i < NELEM(bits_); i++) { + bits_[i] &= other.bits_[i]; + } + } + BitSet operator&(const BitSet& other) const { + BitSet ret = *this; + ret &= other; + return ret; + } + void operator|=(const BitSet& other) { + for (size_t i = 0; i < NELEM(bits_); i++) { + bits_[i] |= other.bits_[i]; + } + } + BitSet operator|(const BitSet& other) const { + BitSet ret = *this; + ret |= other; + return ret; + } + void print() const { + STDOUT << "BitSet<" << SIZE << ">: "; + for (size_t i = 0; i < SIZE; ++i) { + STDOUT << get(SIZE - 1 - i); + } + STDOUT << "\n"; + } private: uint32_t bits_[(SIZE+31)/32]; diff --git a/sound/effect.h b/sound/effect.h index 941a81d49..c553eb941 100644 --- a/sound/effect.h +++ b/sound/effect.h @@ -441,10 +441,8 @@ class Effect { uint8_t n = available_.popcount_subset(first, last); if (!n) { - for (size_t bit = first; bit <= last; ++bit) { - available_.set(bit); - } - n = available_.popcount_subset(first, last); + available_.set_subset(first, last); + n = sub_files_; } if (n == sub_files_ && filenum == last_ && last_subid_ >= 0) n--; @@ -490,8 +488,8 @@ class Effect { if (total_files > 2 && total_files <= SAMPLE_WITHOUT_REPLACEMENT_BUFFER_SIZE_BITS) { uint8_t n = available_.popcount(); if (!n) { - available_.fill(total_files); - n = available_.popcount(); + available_ = BitSet::fill(total_files); + n = total_files; } if (n == total_files && (last_ >= 0 || last_subid_ >= 0)) n--; From d4cae8d2ccec849df71d640d21ae59f7d176a2c7 Mon Sep 17 00:00:00 2001 From: Parker Levin Date: Thu, 16 Oct 2025 05:57:44 -0700 Subject: [PATCH 4/8] Optimize Bitshift Operands (untested) --- common/arg_parser.h | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/common/arg_parser.h b/common/arg_parser.h index 569cc83a3..5cef434a6 100644 --- a/common/arg_parser.h +++ b/common/arg_parser.h @@ -152,6 +152,16 @@ class BitSet { if (!!(n & 31)) ret.bits_[n >> 5] >>= 32 - (n & 31); return ret; } + uint32_t get_word(int word) const { + if (word < 0 || word >= (int)NELEM(bits_)) return 0; + return bits_[word]; + } + uint32_t get32(int pos) const { + uint64_t tmp = get_word(1 + (pos >> 5)); + tmp <<= 32; + tmp |= get_word(pos >> 5); + return tmp >> (pos & 31); + } size_t popcount() const { size_t ret = 0; for (size_t i = 0; i < NELEM(bits_); i++) { @@ -199,32 +209,20 @@ class BitSet { } void operator>>=(int bits) { if (!bits) return; - for (int i = 0; i < (int)SIZE; i++) { - if (i + bits < (int)SIZE && get(i + bits)) { - set(i); - } else { - clear(i); - } - } + for (int i = 0; i < SIZE; i++) bits_[i] = get32(i * 32 + bits); } BitSet operator>>(int bits) const { - BitSet ret = *this; - ret >>= bits; + BitSet ret; + for (size_t i = 0; i < NELEM(bits_); i++) ret.bits_[i] = get32(i * 32 + bits); return ret; } void operator<<=(int bits) { if (!bits) return; - for (int i = SIZE - 1; i >= 0; i--) { - if (i - bits >= 0 && get(i - bits)) { - set(i); - } else { - clear(i); - } - } + for (size_t i = NELEM(bits_) - 1; i >= 0; i--) bits_[i] = get32(i * 32 - bits); } BitSet operator<<(int bits) const { - BitSet ret = *this; - ret <<= bits; + BitSet ret; + for (size_t i = NELEM(bits_) - 1; i >= 0; i--) ret.bits_[i] = get32(i * 32 - bits); return ret; } BitSet operator~() const { From 4e3598252831e0adbe1ebeedd6ccfcbd36feaced Mon Sep 17 00:00:00 2001 From: Parker Levin Date: Sat, 25 Oct 2025 05:35:49 -0700 Subject: [PATCH 5/8] Fix Loop in operator>>= --- common/arg_parser.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/arg_parser.h b/common/arg_parser.h index 5cef434a6..2ee64288c 100644 --- a/common/arg_parser.h +++ b/common/arg_parser.h @@ -209,7 +209,7 @@ class BitSet { } void operator>>=(int bits) { if (!bits) return; - for (int i = 0; i < SIZE; i++) bits_[i] = get32(i * 32 + bits); + for (size_t i = 0; i < NELEM(bits_); i++) bits_[i] = get32(i * 32 + bits); } BitSet operator>>(int bits) const { BitSet ret; From 1966c6630e2a3140248ba4f6bcc092eaa6a4d24b Mon Sep 17 00:00:00 2001 From: Parker Levin Date: Sat, 8 Nov 2025 03:33:41 -0800 Subject: [PATCH 6/8] Fix Bounds Errors in BitSet, Fix Subset Range in random_subid() --- common/arg_parser.h | 14 +++++++++++--- sound/effect.h | 4 ++-- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/common/arg_parser.h b/common/arg_parser.h index 2ee64288c..695705d26 100644 --- a/common/arg_parser.h +++ b/common/arg_parser.h @@ -146,7 +146,7 @@ class BitSet { // Create a BitSet with a given number of initially set bits static BitSet fill(size_t n = SIZE) { BitSet ret; - for (size_t i = 0; i <= n >> 5; i++) { + for (size_t i = 0; i < NELEM(ret.bits_); i++) { ret.bits_[i] = ~uint32_t(0); } if (!!(n & 31)) ret.bits_[n >> 5] >>= 32 - (n & 31); @@ -218,11 +218,19 @@ class BitSet { } void operator<<=(int bits) { if (!bits) return; - for (size_t i = NELEM(bits_) - 1; i >= 0; i--) bits_[i] = get32(i * 32 - bits); + const size_t n = NELEM(bits_); + for (size_t i = 0; i < n; i++) { + const size_t curr = n - 1 - i; + bits_[curr] = get32(curr * 32 - bits); + } } BitSet operator<<(int bits) const { BitSet ret; - for (size_t i = NELEM(bits_) - 1; i >= 0; i--) ret.bits_[i] = get32(i * 32 - bits); + const size_t n = NELEM(bits_); + for (size_t i = 0; i < n; i++) { + const size_t curr = n - 1 - i; + ret.bits_[curr] = get32(curr * 32 - bits); + } return ret; } BitSet operator~() const { diff --git a/sound/effect.h b/sound/effect.h index c553eb941..e2b6c0ae1 100644 --- a/sound/effect.h +++ b/sound/effect.h @@ -436,8 +436,8 @@ class Effect { #ifdef RANDOM_SAMPLE_WITHOUT_REPLACEMENT const size_t total_files = files_found() * number_of_subfiles(); if (total_files > 2 && total_files <= SAMPLE_WITHOUT_REPLACEMENT_BUFFER_SIZE_BITS) { - const size_t first = filenum * files_found(); - const size_t last = first + sub_files_ - 1; + const size_t first = filenum * sub_files_; + const size_t last = first + files_found(); uint8_t n = available_.popcount_subset(first, last); if (!n) { From ba51d032079ffca4d81589cf0d3a57a7ee0b1ea3 Mon Sep 17 00:00:00 2001 From: Parker Levin Date: Sat, 8 Nov 2025 15:09:56 -0800 Subject: [PATCH 7/8] Simply Reverse Loop in BitSet --- common/arg_parser.h | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/common/arg_parser.h b/common/arg_parser.h index 695705d26..926296a5f 100644 --- a/common/arg_parser.h +++ b/common/arg_parser.h @@ -218,19 +218,11 @@ class BitSet { } void operator<<=(int bits) { if (!bits) return; - const size_t n = NELEM(bits_); - for (size_t i = 0; i < n; i++) { - const size_t curr = n - 1 - i; - bits_[curr] = get32(curr * 32 - bits); - } + for (int i = NELEM(bits_) - 1; i >= 0; i--) bits_[i] = get32(i * 32 - bits); } BitSet operator<<(int bits) const { BitSet ret; - const size_t n = NELEM(bits_); - for (size_t i = 0; i < n; i++) { - const size_t curr = n - 1 - i; - ret.bits_[curr] = get32(curr * 32 - bits); - } + for (int i = NELEM(bits_) - 1; i >= 0; i--) ret.bits_[i] = get32(i * 32 - bits); return ret; } BitSet operator~() const { From 5ad0dd81b5f40d75b54eec088148a931f1c2eb89 Mon Sep 17 00:00:00 2001 From: Parker Levin Date: Sat, 8 Nov 2025 16:31:10 -0800 Subject: [PATCH 8/8] Account for 0-Indexing in fill() --- common/arg_parser.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/arg_parser.h b/common/arg_parser.h index 926296a5f..3bbba1689 100644 --- a/common/arg_parser.h +++ b/common/arg_parser.h @@ -146,10 +146,10 @@ class BitSet { // Create a BitSet with a given number of initially set bits static BitSet fill(size_t n = SIZE) { BitSet ret; - for (size_t i = 0; i < NELEM(ret.bits_); i++) { + for (size_t i = 0; i <= (n - 1) >> 5; i++) { ret.bits_[i] = ~uint32_t(0); } - if (!!(n & 31)) ret.bits_[n >> 5] >>= 32 - (n & 31); + if (!!(n & 31)) ret.bits_[(n - 1) >> 5] >>= 32 - (n & 31); return ret; } uint32_t get_word(int word) const {