2025-01-10 11:33:35 +01:00
|
|
|
// Copyright 2010-2025 Google LLC
|
2010-09-15 12:42:33 +00:00
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
|
//
|
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
//
|
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
|
// limitations under the License.
|
|
|
|
|
|
|
|
|
|
// Various utility functions on bitsets.
|
|
|
|
|
|
2025-11-05 10:13:48 +01:00
|
|
|
#ifndef ORTOOLS_UTIL_BITSET_H_
|
|
|
|
|
#define ORTOOLS_UTIL_BITSET_H_
|
2010-09-15 12:42:33 +00:00
|
|
|
|
2013-12-16 10:24:42 +00:00
|
|
|
#include <string.h>
|
2019-04-08 19:00:46 +02:00
|
|
|
|
2013-12-16 10:24:42 +00:00
|
|
|
#include <algorithm>
|
2024-01-31 14:44:02 +01:00
|
|
|
#include <cstddef>
|
2024-01-23 14:15:18 +01:00
|
|
|
#include <cstdint>
|
2024-01-31 14:44:02 +01:00
|
|
|
#include <iterator>
|
2022-03-29 17:58:33 +02:00
|
|
|
#include <string>
|
2024-01-31 14:44:02 +01:00
|
|
|
#include <tuple>
|
2010-09-15 12:42:33 +00:00
|
|
|
#include <vector>
|
|
|
|
|
|
2024-01-31 14:44:02 +01:00
|
|
|
#include "absl/log/check.h"
|
2010-09-15 12:42:33 +00:00
|
|
|
|
|
|
|
|
namespace operations_research {
|
|
|
|
|
|
|
|
|
|
// Basic bit operations
|
|
|
|
|
|
|
|
|
|
// Useful constants: word and double word will all bits set.
|
2021-04-01 12:13:35 +02:00
|
|
|
static const uint64_t kAllBits64 = uint64_t{0xFFFFFFFFFFFFFFFF};
|
|
|
|
|
static const uint64_t kAllBitsButLsb64 = uint64_t{0xFFFFFFFFFFFFFFFE};
|
2021-04-05 13:48:47 +02:00
|
|
|
static const uint32_t kAllBits32 = 0xFFFFFFFFU;
|
2010-09-15 12:42:33 +00:00
|
|
|
|
|
|
|
|
// Returns a word with only bit pos set.
|
2021-04-01 12:13:35 +02:00
|
|
|
inline uint64_t OneBit64(int pos) { return uint64_t{1} << pos; }
|
2021-04-05 13:48:47 +02:00
|
|
|
inline uint32_t OneBit32(int pos) { return 1U << pos; }
|
2010-09-15 12:42:33 +00:00
|
|
|
|
|
|
|
|
// Returns the number of bits set in n.
|
2021-04-01 12:13:35 +02:00
|
|
|
inline uint64_t BitCount64(uint64_t n) {
|
|
|
|
|
const uint64_t m1 = uint64_t{0x5555555555555555};
|
|
|
|
|
const uint64_t m2 = uint64_t{0x3333333333333333};
|
|
|
|
|
const uint64_t m4 = uint64_t{0x0F0F0F0F0F0F0F0F};
|
|
|
|
|
const uint64_t h01 = uint64_t{0x0101010101010101};
|
2010-09-15 12:42:33 +00:00
|
|
|
n -= (n >> 1) & m1;
|
|
|
|
|
n = (n & m2) + ((n >> 2) & m2);
|
|
|
|
|
n = (n + (n >> 4)) & m4;
|
|
|
|
|
n = (n * h01) >> 56;
|
|
|
|
|
return n;
|
|
|
|
|
}
|
2021-04-05 13:48:47 +02:00
|
|
|
inline uint32_t BitCount32(uint32_t n) {
|
2010-09-15 12:42:33 +00:00
|
|
|
n -= (n >> 1) & 0x55555555UL;
|
|
|
|
|
n = (n & 0x33333333) + ((n >> 2) & 0x33333333UL);
|
|
|
|
|
n = (n + (n >> 4)) & 0x0F0F0F0FUL;
|
|
|
|
|
n = n + (n >> 8);
|
|
|
|
|
n = n + (n >> 16);
|
|
|
|
|
return n & 0x0000003FUL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Returns a word with only the least significant bit of n set.
|
2021-04-01 12:13:35 +02:00
|
|
|
inline uint64_t LeastSignificantBitWord64(uint64_t n) { return n & ~(n - 1); }
|
2021-04-05 13:48:47 +02:00
|
|
|
inline uint32_t LeastSignificantBitWord32(uint32_t n) { return n & ~(n - 1); }
|
2010-09-15 12:42:33 +00:00
|
|
|
|
|
|
|
|
// Returns the least significant bit position in n.
|
2015-06-15 11:46:24 +02:00
|
|
|
// Discussion around lsb computation:
|
|
|
|
|
// De Bruijn is almost as fast as the bsr/bsf-instruction-based intrinsics.
|
|
|
|
|
// Both are always much faster than the Default algorithm.
|
2020-10-22 23:36:58 +02:00
|
|
|
#define USE_DEBRUIJN true // if true, use de Bruijn bit forward scanner.
|
2015-06-15 11:46:24 +02:00
|
|
|
#if defined(__GNUC__) || defined(__llvm__)
|
2020-10-22 23:36:58 +02:00
|
|
|
#define USE_FAST_LEAST_SIGNIFICANT_BIT true // if true, use fast lsb.
|
2010-09-15 12:42:33 +00:00
|
|
|
#endif
|
|
|
|
|
|
2015-06-15 11:46:24 +02:00
|
|
|
#if defined(USE_FAST_LEAST_SIGNIFICANT_BIT)
|
2021-04-01 12:13:35 +02:00
|
|
|
inline int LeastSignificantBitPosition64Fast(uint64_t n) {
|
2022-11-22 17:44:54 +01:00
|
|
|
return __builtin_ctzll(n);
|
2014-04-16 09:57:29 +00:00
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2021-04-01 12:13:35 +02:00
|
|
|
inline int LeastSignificantBitPosition64DeBruijn(uint64_t n) {
|
|
|
|
|
static const uint64_t kSeq = uint64_t{0x0218a392dd5fb34f};
|
2010-09-15 12:42:33 +00:00
|
|
|
static const int kTab[64] = {
|
2020-10-22 23:36:58 +02:00
|
|
|
// initialized by 'kTab[(kSeq << i) >> 58] = i
|
|
|
|
|
0, 1, 2, 7, 3, 13, 8, 19, 4, 25, 14, 28, 9, 52, 20, 58,
|
|
|
|
|
5, 17, 26, 56, 15, 38, 29, 40, 10, 49, 53, 31, 21, 34, 59, 42,
|
|
|
|
|
63, 6, 12, 18, 24, 27, 51, 57, 16, 55, 37, 39, 48, 30, 33, 41,
|
|
|
|
|
62, 11, 23, 50, 54, 36, 47, 32, 61, 22, 35, 46, 60, 45, 44, 43,
|
2018-06-08 16:40:43 +02:00
|
|
|
};
|
2015-10-13 17:03:37 +02:00
|
|
|
return kTab[((n & (~n + 1)) * kSeq) >> 58];
|
2014-04-16 09:57:29 +00:00
|
|
|
}
|
|
|
|
|
|
2021-04-01 12:13:35 +02:00
|
|
|
inline int LeastSignificantBitPosition64Default(uint64_t n) {
|
2022-11-22 17:44:54 +01:00
|
|
|
DCHECK_NE(n, 0);
|
2010-09-15 12:42:33 +00:00
|
|
|
int pos = 63;
|
|
|
|
|
if (n & 0x00000000FFFFFFFFLL) {
|
|
|
|
|
pos -= 32;
|
|
|
|
|
} else {
|
|
|
|
|
n >>= 32;
|
|
|
|
|
}
|
|
|
|
|
if (n & 0x000000000000FFFFLL) {
|
|
|
|
|
pos -= 16;
|
|
|
|
|
} else {
|
|
|
|
|
n >>= 16;
|
|
|
|
|
}
|
|
|
|
|
if (n & 0x00000000000000FFLL) {
|
2014-01-08 12:01:58 +00:00
|
|
|
pos -= 8;
|
2010-09-15 12:42:33 +00:00
|
|
|
} else {
|
2014-01-08 12:01:58 +00:00
|
|
|
n >>= 8;
|
2010-09-15 12:42:33 +00:00
|
|
|
}
|
|
|
|
|
if (n & 0x000000000000000FLL) {
|
2014-01-08 12:01:58 +00:00
|
|
|
pos -= 4;
|
2010-09-15 12:42:33 +00:00
|
|
|
} else {
|
2014-01-08 12:01:58 +00:00
|
|
|
n >>= 4;
|
2010-09-15 12:42:33 +00:00
|
|
|
}
|
|
|
|
|
if (n & 0x0000000000000003LL) {
|
2014-01-08 12:01:58 +00:00
|
|
|
pos -= 2;
|
2010-09-15 12:42:33 +00:00
|
|
|
} else {
|
2014-01-08 12:01:58 +00:00
|
|
|
n >>= 2;
|
2010-09-15 12:42:33 +00:00
|
|
|
}
|
|
|
|
|
if (n & 0x0000000000000001LL) {
|
2014-01-08 12:01:58 +00:00
|
|
|
pos -= 1;
|
2010-09-15 12:42:33 +00:00
|
|
|
}
|
|
|
|
|
return pos;
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-01 12:13:35 +02:00
|
|
|
inline int LeastSignificantBitPosition64(uint64_t n) {
|
2014-04-16 09:57:29 +00:00
|
|
|
DCHECK_NE(n, 0);
|
2015-06-15 11:46:24 +02:00
|
|
|
#ifdef USE_FAST_LEAST_SIGNIFICANT_BIT
|
|
|
|
|
return LeastSignificantBitPosition64Fast(n);
|
2014-04-16 09:57:29 +00:00
|
|
|
#elif defined(USE_DEBRUIJN)
|
|
|
|
|
return LeastSignificantBitPosition64DeBruijn(n);
|
|
|
|
|
#else
|
|
|
|
|
return LeastSignificantBitPosition64Default(n);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-15 11:46:24 +02:00
|
|
|
#if defined(USE_FAST_LEAST_SIGNIFICANT_BIT)
|
2021-04-05 13:48:47 +02:00
|
|
|
inline int LeastSignificantBitPosition32Fast(uint32_t n) {
|
2022-11-22 17:44:54 +01:00
|
|
|
return __builtin_ctzl(n);
|
2014-04-16 09:57:29 +00:00
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2021-04-05 13:48:47 +02:00
|
|
|
inline int LeastSignificantBitPosition32DeBruijn(uint32_t n) {
|
|
|
|
|
static const uint32_t kSeq = 0x077CB531U; // de Bruijn sequence
|
2020-10-22 23:36:58 +02:00
|
|
|
static const int kTab[32] = {// initialized by 'kTab[(kSeq << i) >> 27] = i
|
|
|
|
|
0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20,
|
|
|
|
|
15, 25, 17, 4, 8, 31, 27, 13, 23, 21, 19,
|
|
|
|
|
16, 7, 26, 12, 18, 6, 11, 5, 10, 9};
|
2015-10-13 17:03:37 +02:00
|
|
|
return kTab[((n & (~n + 1)) * kSeq) >> 27];
|
2014-04-16 09:57:29 +00:00
|
|
|
}
|
|
|
|
|
|
2021-04-05 13:48:47 +02:00
|
|
|
inline int LeastSignificantBitPosition32Default(uint32_t n) {
|
2022-11-22 17:44:54 +01:00
|
|
|
DCHECK_NE(n, 0);
|
2010-09-15 12:42:33 +00:00
|
|
|
int pos = 31;
|
|
|
|
|
if (n & 0x0000FFFFL) {
|
|
|
|
|
pos -= 16;
|
|
|
|
|
} else {
|
|
|
|
|
n >>= 16;
|
|
|
|
|
}
|
|
|
|
|
if (n & 0x000000FFL) {
|
2014-01-08 12:01:58 +00:00
|
|
|
pos -= 8;
|
2010-09-15 12:42:33 +00:00
|
|
|
} else {
|
2014-01-08 12:01:58 +00:00
|
|
|
n >>= 8;
|
2010-09-15 12:42:33 +00:00
|
|
|
}
|
|
|
|
|
if (n & 0x0000000FL) {
|
2014-01-08 12:01:58 +00:00
|
|
|
pos -= 4;
|
2010-09-15 12:42:33 +00:00
|
|
|
} else {
|
2014-01-08 12:01:58 +00:00
|
|
|
n >>= 4;
|
2010-09-15 12:42:33 +00:00
|
|
|
}
|
|
|
|
|
if (n & 0x00000003L) {
|
2014-01-08 12:01:58 +00:00
|
|
|
pos -= 2;
|
2010-09-15 12:42:33 +00:00
|
|
|
} else {
|
2014-01-08 12:01:58 +00:00
|
|
|
n >>= 2;
|
2010-09-15 12:42:33 +00:00
|
|
|
}
|
|
|
|
|
if (n & 0x00000001L) {
|
2014-01-08 12:01:58 +00:00
|
|
|
pos -= 1;
|
2010-09-15 12:42:33 +00:00
|
|
|
}
|
|
|
|
|
return pos;
|
2014-04-16 09:57:29 +00:00
|
|
|
}
|
|
|
|
|
|
2021-04-05 13:48:47 +02:00
|
|
|
inline int LeastSignificantBitPosition32(uint32_t n) {
|
2014-04-16 09:57:29 +00:00
|
|
|
DCHECK_NE(n, 0);
|
2015-06-15 11:46:24 +02:00
|
|
|
#ifdef USE_FAST_LEAST_SIGNIFICANT_BIT
|
|
|
|
|
return LeastSignificantBitPosition32Fast(n);
|
2014-04-16 09:57:29 +00:00
|
|
|
#elif defined(USE_DEBRUIJN)
|
|
|
|
|
return LeastSignificantBitPosition32DeBruijn(n);
|
|
|
|
|
#else
|
|
|
|
|
return LeastSignificantBitPosition32Default(n);
|
2010-09-15 12:42:33 +00:00
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Returns the most significant bit position in n.
|
2015-06-15 11:46:24 +02:00
|
|
|
#if USE_FAST_LEAST_SIGNIFICANT_BIT
|
2021-04-01 12:13:35 +02:00
|
|
|
inline int MostSignificantBitPosition64Fast(uint64_t n) {
|
2015-06-15 11:46:24 +02:00
|
|
|
// __builtin_clzll(1) should always return 63. There is no penalty in
|
2021-04-05 13:48:47 +02:00
|
|
|
// using offset, and the code looks more like its uint32_t counterpart.
|
2015-06-15 11:46:24 +02:00
|
|
|
const int offset = __builtin_clzll(1);
|
2018-01-10 13:21:06 +01:00
|
|
|
return n == 0 ? 0 : (offset - __builtin_clzll(n));
|
2015-06-15 11:46:24 +02:00
|
|
|
}
|
2010-09-15 12:42:33 +00:00
|
|
|
#endif
|
2015-06-15 11:46:24 +02:00
|
|
|
|
2021-04-01 12:13:35 +02:00
|
|
|
inline int MostSignificantBitPosition64Default(uint64_t n) {
|
2010-09-15 12:42:33 +00:00
|
|
|
int b = 0;
|
|
|
|
|
if (0 != (n & (kAllBits64 << (1 << 5)))) {
|
|
|
|
|
b |= (1 << 5);
|
|
|
|
|
n >>= (1 << 5);
|
|
|
|
|
}
|
|
|
|
|
if (0 != (n & (kAllBits64 << (1 << 4)))) {
|
|
|
|
|
b |= (1 << 4);
|
|
|
|
|
n >>= (1 << 4);
|
|
|
|
|
}
|
|
|
|
|
if (0 != (n & (kAllBits64 << (1 << 3)))) {
|
|
|
|
|
b |= (1 << 3);
|
|
|
|
|
n >>= (1 << 3);
|
|
|
|
|
}
|
|
|
|
|
if (0 != (n & (kAllBits64 << (1 << 2)))) {
|
|
|
|
|
b |= (1 << 2);
|
|
|
|
|
n >>= (1 << 2);
|
|
|
|
|
}
|
|
|
|
|
if (0 != (n & (kAllBits64 << (1 << 1)))) {
|
|
|
|
|
b |= (1 << 1);
|
|
|
|
|
n >>= (1 << 1);
|
|
|
|
|
}
|
|
|
|
|
if (0 != (n & (kAllBits64 << (1 << 0)))) {
|
|
|
|
|
b |= (1 << 0);
|
|
|
|
|
}
|
|
|
|
|
return b;
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-01 12:13:35 +02:00
|
|
|
inline int MostSignificantBitPosition64(uint64_t n) {
|
2015-06-15 11:46:24 +02:00
|
|
|
#ifdef USE_FAST_LEAST_SIGNIFICANT_BIT
|
|
|
|
|
return MostSignificantBitPosition64Fast(n);
|
2010-09-15 12:42:33 +00:00
|
|
|
#else
|
2015-06-15 11:46:24 +02:00
|
|
|
return MostSignificantBitPosition64Default(n);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if USE_FAST_LEAST_SIGNIFICANT_BIT
|
2021-04-05 13:48:47 +02:00
|
|
|
inline int MostSignificantBitPosition32Fast(uint32_t n) {
|
2015-06-15 11:46:24 +02:00
|
|
|
// The constant here depends on whether we are on a 32-bit or 64-bit machine.
|
|
|
|
|
// __builtin_clzl(1) returns 63 on a 64-bit machine and 31 on a 32-bit
|
|
|
|
|
// machine.
|
|
|
|
|
const int offset = __builtin_clzl(1);
|
2018-01-10 13:21:06 +01:00
|
|
|
return n == 0 ? 0 : (offset - __builtin_clzl(n));
|
2015-06-15 11:46:24 +02:00
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2021-04-05 13:48:47 +02:00
|
|
|
inline int MostSignificantBitPosition32Default(uint32_t n) {
|
2010-09-15 12:42:33 +00:00
|
|
|
int b = 0;
|
|
|
|
|
if (0 != (n & (kAllBits32 << (1 << 4)))) {
|
|
|
|
|
b |= (1 << 4);
|
|
|
|
|
n >>= (1 << 4);
|
|
|
|
|
}
|
|
|
|
|
if (0 != (n & (kAllBits32 << (1 << 3)))) {
|
|
|
|
|
b |= (1 << 3);
|
|
|
|
|
n >>= (1 << 3);
|
|
|
|
|
}
|
|
|
|
|
if (0 != (n & (kAllBits32 << (1 << 2)))) {
|
|
|
|
|
b |= (1 << 2);
|
|
|
|
|
n >>= (1 << 2);
|
|
|
|
|
}
|
|
|
|
|
if (0 != (n & (kAllBits32 << (1 << 1)))) {
|
|
|
|
|
b |= (1 << 1);
|
|
|
|
|
n >>= (1 << 1);
|
|
|
|
|
}
|
|
|
|
|
if (0 != (n & (kAllBits32 << (1 << 0)))) {
|
|
|
|
|
b |= (1 << 0);
|
|
|
|
|
}
|
|
|
|
|
return b;
|
2015-06-15 11:46:24 +02:00
|
|
|
}
|
|
|
|
|
|
2021-04-05 13:48:47 +02:00
|
|
|
inline int MostSignificantBitPosition32(uint32_t n) {
|
2015-06-15 11:46:24 +02:00
|
|
|
#ifdef USE_FAST_LEAST_SIGNIFICANT_BIT
|
|
|
|
|
return MostSignificantBitPosition32Fast(n);
|
|
|
|
|
#else
|
|
|
|
|
return MostSignificantBitPosition32Default(n);
|
2010-09-15 12:42:33 +00:00
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#undef USE_DEBRUIJN
|
2015-06-15 11:46:24 +02:00
|
|
|
#undef USE_FAST_LEAST_SIGNIFICANT_BIT
|
2010-09-15 12:42:33 +00:00
|
|
|
|
|
|
|
|
// Returns a word with bits from s to e set.
|
2021-04-01 12:13:35 +02:00
|
|
|
inline uint64_t OneRange64(uint64_t s, uint64_t e) {
|
2010-09-15 12:42:33 +00:00
|
|
|
DCHECK_LE(s, 63);
|
|
|
|
|
DCHECK_LE(e, 63);
|
|
|
|
|
DCHECK_LE(s, e);
|
|
|
|
|
return (kAllBits64 << s) ^ ((kAllBits64 - 1) << e);
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-05 13:48:47 +02:00
|
|
|
inline uint32_t OneRange32(uint32_t s, uint32_t e) {
|
2010-09-15 12:42:33 +00:00
|
|
|
DCHECK_LE(s, 31);
|
|
|
|
|
DCHECK_LE(e, 31);
|
|
|
|
|
DCHECK_LE(s, e);
|
|
|
|
|
return (kAllBits32 << s) ^ ((kAllBits32 - 1) << e);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Returns a word with s least significant bits unset.
|
2021-04-01 12:13:35 +02:00
|
|
|
inline uint64_t IntervalUp64(uint64_t s) {
|
2010-09-15 12:42:33 +00:00
|
|
|
DCHECK_LE(s, 63);
|
|
|
|
|
return kAllBits64 << s;
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-05 13:48:47 +02:00
|
|
|
inline uint32_t IntervalUp32(uint32_t s) {
|
2010-09-15 12:42:33 +00:00
|
|
|
DCHECK_LE(s, 31);
|
|
|
|
|
return kAllBits32 << s;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Returns a word with the s most significant bits unset.
|
2021-04-01 12:13:35 +02:00
|
|
|
inline uint64_t IntervalDown64(uint64_t s) {
|
2010-09-15 12:42:33 +00:00
|
|
|
DCHECK_LE(s, 63);
|
|
|
|
|
return kAllBits64 >> (63 - s);
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-05 13:48:47 +02:00
|
|
|
inline uint32_t IntervalDown32(uint32_t s) {
|
2010-09-15 12:42:33 +00:00
|
|
|
DCHECK_LE(s, 31);
|
|
|
|
|
return kAllBits32 >> (31 - s);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ----- Bitset operators -----
|
2024-03-15 16:38:25 +01:00
|
|
|
// Bitset: array of uint32_t/uint64_t words
|
2010-09-15 12:42:33 +00:00
|
|
|
|
|
|
|
|
// Bit operators used to manipulates bitsets.
|
|
|
|
|
|
|
|
|
|
// Returns the bit number in the word computed by BitOffsetXX,
|
|
|
|
|
// corresponding to the bit at position pos in the bitset.
|
|
|
|
|
// Note: '& 63' is faster than '% 64'
|
|
|
|
|
// TODO(user): rename BitPos and BitOffset to something more understandable.
|
2021-04-05 13:48:47 +02:00
|
|
|
inline uint32_t BitPos64(uint64_t pos) { return (pos & 63); }
|
|
|
|
|
inline uint32_t BitPos32(uint32_t pos) { return (pos & 31); }
|
2010-09-15 12:42:33 +00:00
|
|
|
|
|
|
|
|
// Returns the word number corresponding to bit number pos.
|
2021-04-01 12:13:35 +02:00
|
|
|
inline uint64_t BitOffset64(uint64_t pos) { return (pos >> 6); }
|
2021-04-05 13:48:47 +02:00
|
|
|
inline uint32_t BitOffset32(uint32_t pos) { return (pos >> 5); }
|
2010-09-15 12:42:33 +00:00
|
|
|
|
|
|
|
|
// Returns the number of words needed to store size bits.
|
2021-04-01 12:13:35 +02:00
|
|
|
inline uint64_t BitLength64(uint64_t size) { return ((size + 63) >> 6); }
|
2021-04-05 13:48:47 +02:00
|
|
|
inline uint32_t BitLength32(uint32_t size) { return ((size + 31) >> 5); }
|
2010-09-15 12:42:33 +00:00
|
|
|
|
|
|
|
|
// Returns the bit number in the bitset of the first bit of word number v.
|
2021-04-01 12:13:35 +02:00
|
|
|
inline uint64_t BitShift64(uint64_t v) { return v << 6; }
|
2021-04-05 13:48:47 +02:00
|
|
|
inline uint32_t BitShift32(uint32_t v) { return v << 5; }
|
2010-09-15 12:42:33 +00:00
|
|
|
|
|
|
|
|
// Returns true if the bit pos is set in bitset.
|
2021-04-01 12:13:35 +02:00
|
|
|
inline bool IsBitSet64(const uint64_t* const bitset, uint64_t pos) {
|
2010-09-15 12:42:33 +00:00
|
|
|
return (bitset[BitOffset64(pos)] & OneBit64(BitPos64(pos)));
|
|
|
|
|
}
|
2021-04-05 13:48:47 +02:00
|
|
|
inline bool IsBitSet32(const uint32_t* const bitset, uint32_t pos) {
|
2010-09-15 12:42:33 +00:00
|
|
|
return (bitset[BitOffset32(pos)] & OneBit32(BitPos32(pos)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Sets the bit pos to true in bitset.
|
2021-04-01 12:13:35 +02:00
|
|
|
inline void SetBit64(uint64_t* const bitset, uint64_t pos) {
|
2010-09-15 12:42:33 +00:00
|
|
|
bitset[BitOffset64(pos)] |= OneBit64(BitPos64(pos));
|
|
|
|
|
}
|
2021-04-05 13:48:47 +02:00
|
|
|
inline void SetBit32(uint32_t* const bitset, uint32_t pos) {
|
2010-09-15 12:42:33 +00:00
|
|
|
bitset[BitOffset32(pos)] |= OneBit32(BitPos32(pos));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Sets the bit pos to false in bitset.
|
2021-04-01 12:13:35 +02:00
|
|
|
inline void ClearBit64(uint64_t* const bitset, uint64_t pos) {
|
2010-09-15 12:42:33 +00:00
|
|
|
bitset[BitOffset64(pos)] &= ~OneBit64(BitPos64(pos));
|
|
|
|
|
}
|
2021-04-05 13:48:47 +02:00
|
|
|
inline void ClearBit32(uint32_t* const bitset, uint32_t pos) {
|
2010-09-15 12:42:33 +00:00
|
|
|
bitset[BitOffset32(pos)] &= ~OneBit32(BitPos32(pos));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Returns the number of bits set in bitset between positions start and end.
|
2023-05-24 15:34:42 +02:00
|
|
|
uint64_t BitCountRange64(const uint64_t* bitset, uint64_t start, uint64_t end);
|
|
|
|
|
uint32_t BitCountRange32(const uint32_t* bitset, uint32_t start, uint32_t end);
|
2010-09-15 12:42:33 +00:00
|
|
|
|
|
|
|
|
// Returns true if no bits are set in bitset between start and end.
|
2023-05-24 15:34:42 +02:00
|
|
|
bool IsEmptyRange64(const uint64_t* bitset, uint64_t start, uint64_t end);
|
|
|
|
|
bool IsEmptyRange32(const uint32_t* bitset, uint32_t start, uint32_t end);
|
2010-09-15 12:42:33 +00:00
|
|
|
|
|
|
|
|
// Returns the first bit set in bitset between start and max_bit.
|
2023-05-24 15:34:42 +02:00
|
|
|
int64_t LeastSignificantBitPosition64(const uint64_t* bitset, uint64_t start,
|
|
|
|
|
uint64_t end);
|
|
|
|
|
int LeastSignificantBitPosition32(const uint32_t* bitset, uint32_t start,
|
2021-04-05 13:48:47 +02:00
|
|
|
uint32_t end);
|
2010-09-15 12:42:33 +00:00
|
|
|
|
|
|
|
|
// Returns the last bit set in bitset between min_bit and start.
|
2023-05-24 15:34:42 +02:00
|
|
|
int64_t MostSignificantBitPosition64(const uint64_t* bitset, uint64_t start,
|
|
|
|
|
uint64_t end);
|
|
|
|
|
int MostSignificantBitPosition32(const uint32_t* bitset, uint32_t start,
|
2021-04-05 13:48:47 +02:00
|
|
|
uint32_t end);
|
2010-09-15 12:42:33 +00:00
|
|
|
|
|
|
|
|
// Unsafe versions of the functions above where respectively end and start
|
|
|
|
|
// are supposed to be set.
|
2023-05-24 15:34:42 +02:00
|
|
|
int64_t UnsafeLeastSignificantBitPosition64(const uint64_t* bitset,
|
2021-04-08 18:26:38 +02:00
|
|
|
uint64_t start, uint64_t end);
|
2023-05-24 15:34:42 +02:00
|
|
|
int32_t UnsafeLeastSignificantBitPosition32(const uint32_t* bitset,
|
2021-04-08 18:26:38 +02:00
|
|
|
uint32_t start, uint32_t end);
|
2010-09-15 12:42:33 +00:00
|
|
|
|
2023-05-24 15:34:42 +02:00
|
|
|
int64_t UnsafeMostSignificantBitPosition64(const uint64_t* bitset,
|
2021-04-08 18:26:38 +02:00
|
|
|
uint64_t start, uint64_t end);
|
2023-05-24 15:34:42 +02:00
|
|
|
int32_t UnsafeMostSignificantBitPosition32(const uint32_t* bitset,
|
2021-04-08 18:26:38 +02:00
|
|
|
uint32_t start, uint32_t end);
|
2010-09-15 12:42:33 +00:00
|
|
|
|
2013-12-05 09:23:39 +00:00
|
|
|
// Returns a mask with the bits pos % 64 and (pos ^ 1) % 64 sets.
|
2021-04-08 18:26:38 +02:00
|
|
|
inline uint64_t TwoBitsFromPos64(uint64_t pos) {
|
|
|
|
|
return uint64_t{3} << (pos & 62);
|
|
|
|
|
}
|
2013-12-05 09:23:39 +00:00
|
|
|
|
2013-01-10 17:01:34 +00:00
|
|
|
// This class is like an ITIVector<IndexType, bool> except that it provides a
|
|
|
|
|
// more efficient way to iterate over the positions set to true. It achieves
|
2021-04-01 12:13:35 +02:00
|
|
|
// this by caching the current uint64_t bucket in the Iterator and using
|
2013-01-10 17:01:34 +00:00
|
|
|
// LeastSignificantBitPosition64() to iterate over the positions at 1 in this
|
|
|
|
|
// bucket.
|
2021-04-01 12:13:35 +02:00
|
|
|
template <typename IndexType = int64_t>
|
2020-10-22 23:36:58 +02:00
|
|
|
class Bitset64 {
|
|
|
|
|
public:
|
2024-01-31 14:44:02 +01:00
|
|
|
using value_type = IndexType;
|
|
|
|
|
|
2024-04-17 14:13:41 +02:00
|
|
|
// When speed matter, caching the base pointer helps.
|
2022-11-22 17:44:54 +01:00
|
|
|
class ConstView {
|
|
|
|
|
public:
|
|
|
|
|
explicit ConstView(const Bitset64* bitset) : data_(bitset->data_.data()) {}
|
|
|
|
|
|
|
|
|
|
bool operator[](IndexType i) const {
|
|
|
|
|
return data_[BitOffset64(Value(i))] & OneBit64(BitPos64(Value(i)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const uint64_t* data() const { return data_; }
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
const uint64_t* const data_;
|
|
|
|
|
};
|
|
|
|
|
|
2024-04-17 14:13:41 +02:00
|
|
|
class View {
|
|
|
|
|
public:
|
|
|
|
|
explicit View(Bitset64* bitset) : data_(bitset->data_.data()) {}
|
|
|
|
|
|
|
|
|
|
bool operator[](IndexType i) const {
|
|
|
|
|
return data_[BitOffset64(Value(i))] & OneBit64(BitPos64(Value(i)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Clear(IndexType i) {
|
|
|
|
|
data_[BitOffset64(Value(i))] &= ~OneBit64(BitPos64(Value(i)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Set(IndexType i) {
|
|
|
|
|
data_[BitOffset64(Value(i))] |= OneBit64(BitPos64(Value(i)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
uint64_t* const data_;
|
|
|
|
|
};
|
|
|
|
|
|
2022-11-22 17:44:54 +01:00
|
|
|
Bitset64() : size_(), data_() {}
|
2013-01-10 17:01:34 +00:00
|
|
|
explicit Bitset64(IndexType size)
|
2014-03-21 18:01:18 +00:00
|
|
|
: size_(Value(size) > 0 ? size : IndexType(0)),
|
2022-11-22 17:44:54 +01:00
|
|
|
data_(BitLength64(Value(size_))) {}
|
|
|
|
|
|
|
|
|
|
ConstView const_view() const { return ConstView(this); }
|
2024-04-17 14:13:41 +02:00
|
|
|
View view() { return View(this); }
|
2013-01-10 17:01:34 +00:00
|
|
|
|
|
|
|
|
// Returns how many bits this Bitset64 can hold.
|
|
|
|
|
IndexType size() const { return size_; }
|
|
|
|
|
|
2013-06-11 14:53:20 +00:00
|
|
|
// Appends value at the end of the bitset.
|
|
|
|
|
void PushBack(bool value) {
|
|
|
|
|
++size_;
|
2014-03-21 18:01:18 +00:00
|
|
|
data_.resize(BitLength64(Value(size_)), 0);
|
2013-06-11 14:53:20 +00:00
|
|
|
Set(size_ - 1, value);
|
|
|
|
|
}
|
|
|
|
|
|
2014-03-21 18:01:18 +00:00
|
|
|
// Resizes the Bitset64 to the given number of bits. New bits are sets to 0.
|
2023-02-06 17:19:44 +01:00
|
|
|
void resize(int size) { Resize(IndexType(size)); }
|
2014-01-27 15:05:30 +00:00
|
|
|
void Resize(IndexType size) {
|
2014-03-21 18:01:18 +00:00
|
|
|
DCHECK_GE(Value(size), 0);
|
2024-01-23 14:15:18 +01:00
|
|
|
IndexType new_size = Value(size) > 0 ? size : IndexType(0);
|
|
|
|
|
if (new_size < size_ && Value(new_size) > 0) {
|
|
|
|
|
const int64_t new_data_size = BitLength64(Value(new_size));
|
|
|
|
|
const uint64_t bitmask = kAllBitsButLsb64
|
|
|
|
|
<< BitPos64(Value(new_size) - 1);
|
|
|
|
|
data_[new_data_size - 1] &= ~bitmask;
|
|
|
|
|
}
|
|
|
|
|
size_ = new_size;
|
2014-03-21 18:01:18 +00:00
|
|
|
data_.resize(BitLength64(Value(size_)), 0);
|
2014-01-27 15:05:30 +00:00
|
|
|
}
|
|
|
|
|
|
2013-01-10 17:01:34 +00:00
|
|
|
// Changes the number of bits the Bitset64 can hold and set all of them to 0.
|
|
|
|
|
void ClearAndResize(IndexType size) {
|
2014-03-21 18:01:18 +00:00
|
|
|
DCHECK_GE(Value(size), 0);
|
|
|
|
|
size_ = Value(size) > 0 ? size : IndexType(0);
|
|
|
|
|
|
|
|
|
|
// Memset is 4x faster than data_.assign() as of 19/03/2014.
|
|
|
|
|
// TODO(user): Ideally if a realloc happens, we don't need to copy the old
|
|
|
|
|
// data...
|
|
|
|
|
const size_t bit_length = static_cast<size_t>(BitLength64(Value(size_)));
|
|
|
|
|
const size_t to_clear = std::min(data_.size(), bit_length);
|
|
|
|
|
data_.resize(bit_length, 0);
|
2021-04-01 12:13:35 +02:00
|
|
|
memset(data_.data(), 0, to_clear * sizeof(int64_t));
|
2013-01-10 17:01:34 +00:00
|
|
|
}
|
|
|
|
|
|
2014-04-04 09:13:02 +00:00
|
|
|
// Sets all bits to 0.
|
2021-04-01 12:13:35 +02:00
|
|
|
void ClearAll() { memset(data_.data(), 0, data_.size() * sizeof(int64_t)); }
|
2014-04-04 09:13:02 +00:00
|
|
|
|
2013-01-10 17:01:34 +00:00
|
|
|
// Sets the bit at position i to 0.
|
|
|
|
|
void Clear(IndexType i) {
|
2014-03-21 18:01:18 +00:00
|
|
|
DCHECK_GE(Value(i), 0);
|
2017-04-19 16:20:56 +02:00
|
|
|
DCHECK_LT(Value(i), Value(size_));
|
2025-01-30 14:25:55 +01:00
|
|
|
data_.data()[BitOffset64(Value(i))] &= ~OneBit64(BitPos64(Value(i)));
|
2013-01-10 17:01:34 +00:00
|
|
|
}
|
|
|
|
|
|
2014-04-04 09:13:02 +00:00
|
|
|
// Sets bucket containing bit i to 0.
|
|
|
|
|
void ClearBucket(IndexType i) {
|
|
|
|
|
DCHECK_GE(Value(i), 0);
|
2017-04-19 16:20:56 +02:00
|
|
|
DCHECK_LT(Value(i), Value(size_));
|
2024-11-15 15:27:50 +01:00
|
|
|
data_.data()[BitOffset64(Value(i))] = 0;
|
2014-04-04 09:13:02 +00:00
|
|
|
}
|
|
|
|
|
|
2014-05-21 12:54:10 +00:00
|
|
|
// Clears the bits at position i and i ^ 1.
|
|
|
|
|
void ClearTwoBits(IndexType i) {
|
2014-03-21 18:01:18 +00:00
|
|
|
DCHECK_GE(Value(i), 0);
|
2017-04-19 16:20:56 +02:00
|
|
|
DCHECK_LT(Value(i), Value(size_));
|
2014-05-21 12:54:10 +00:00
|
|
|
data_[BitOffset64(Value(i))] &= ~TwoBitsFromPos64(Value(i));
|
2013-12-05 09:23:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Returns true if the bit at position i or the one at position i ^ 1 is set.
|
|
|
|
|
bool AreOneOfTwoBitsSet(IndexType i) const {
|
2014-03-21 18:01:18 +00:00
|
|
|
DCHECK_GE(Value(i), 0);
|
2017-04-19 16:20:56 +02:00
|
|
|
DCHECK_LT(Value(i), Value(size_));
|
2025-01-30 14:25:55 +01:00
|
|
|
return data_.data()[BitOffset64(Value(i))] & TwoBitsFromPos64(Value(i));
|
2013-12-05 09:23:39 +00:00
|
|
|
}
|
|
|
|
|
|
2013-01-10 17:01:34 +00:00
|
|
|
// Returns true if the bit at position i is set.
|
|
|
|
|
bool IsSet(IndexType i) const {
|
2014-03-21 18:01:18 +00:00
|
|
|
DCHECK_GE(Value(i), 0);
|
2017-04-19 16:20:56 +02:00
|
|
|
DCHECK_LT(Value(i), Value(size_));
|
2025-01-30 14:25:55 +01:00
|
|
|
return data_.data()[BitOffset64(Value(i))] & OneBit64(BitPos64(Value(i)));
|
2013-01-10 17:01:34 +00:00
|
|
|
}
|
|
|
|
|
|
2014-03-21 18:01:18 +00:00
|
|
|
// Same as IsSet().
|
|
|
|
|
bool operator[](IndexType i) const { return IsSet(i); }
|
|
|
|
|
|
2013-01-10 17:01:34 +00:00
|
|
|
// Sets the bit at position i to 1.
|
|
|
|
|
void Set(IndexType i) {
|
2014-03-21 18:01:18 +00:00
|
|
|
DCHECK_GE(Value(i), 0);
|
|
|
|
|
DCHECK_LT(Value(i), size_);
|
2024-09-27 11:10:42 +02:00
|
|
|
// The c++ hardening is costly here, so we disable it.
|
2025-01-30 14:25:55 +01:00
|
|
|
data_.data()[BitOffset64(Value(i))] |= OneBit64(BitPos64(Value(i)));
|
2013-01-10 17:01:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If value is true, sets the bit at position i to 1, sets it to 0 otherwise.
|
|
|
|
|
void Set(IndexType i, bool value) {
|
|
|
|
|
if (value) {
|
|
|
|
|
Set(i);
|
|
|
|
|
} else {
|
|
|
|
|
Clear(i);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-04 09:13:02 +00:00
|
|
|
// Copies bucket containing bit i from "other" to "this".
|
2020-10-29 14:25:39 +01:00
|
|
|
void CopyBucket(const Bitset64<IndexType>& other, IndexType i) {
|
2021-04-01 12:13:35 +02:00
|
|
|
const uint64_t offset = BitOffset64(Value(i));
|
2014-04-04 09:13:02 +00:00
|
|
|
data_[offset] = other.data_[offset];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Copies "other" to "this". The bitsets do not have to be of the same size.
|
|
|
|
|
// If "other" is smaller, high order bits are not changed. If "other" is
|
|
|
|
|
// larger, its high order bits are ignored. In any case "this" is not resized.
|
2017-04-19 16:20:56 +02:00
|
|
|
template <typename OtherIndexType>
|
2020-10-29 14:25:39 +01:00
|
|
|
void SetContentFromBitset(const Bitset64<OtherIndexType>& other) {
|
2021-04-01 12:13:35 +02:00
|
|
|
const int64_t min_size = std::min(data_.size(), other.data_.size());
|
2020-10-22 23:36:58 +02:00
|
|
|
if (min_size == 0) return;
|
2021-04-01 12:13:35 +02:00
|
|
|
const uint64_t last_common_bucket = data_[min_size - 1];
|
|
|
|
|
memcpy(data_.data(), other.data_.data(), min_size * sizeof(uint64_t));
|
2014-04-04 09:13:02 +00:00
|
|
|
if (data_.size() >= other.data_.size()) {
|
2021-04-01 12:13:35 +02:00
|
|
|
const uint64_t bitmask = kAllBitsButLsb64
|
2021-04-08 18:26:38 +02:00
|
|
|
<< BitPos64(other.Value(other.size() - 1));
|
2014-04-04 09:13:02 +00:00
|
|
|
data_[min_size - 1] &= ~bitmask;
|
|
|
|
|
data_[min_size - 1] |= (bitmask & last_common_bucket);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Same as SetContentFromBitset where "this" and "other" have the same size.
|
2017-04-19 16:20:56 +02:00
|
|
|
template <typename OtherIndexType>
|
2020-10-29 14:25:39 +01:00
|
|
|
void SetContentFromBitsetOfSameSize(const Bitset64<OtherIndexType>& other) {
|
2017-04-19 16:20:56 +02:00
|
|
|
DCHECK_EQ(Value(size()), other.Value(other.size()));
|
2021-04-01 12:13:35 +02:00
|
|
|
memcpy(data_.data(), other.data_.data(), data_.size() * sizeof(uint64_t));
|
2014-04-04 09:13:02 +00:00
|
|
|
}
|
|
|
|
|
|
2013-01-10 17:01:34 +00:00
|
|
|
// Sets "this" to be the intersection of "this" and "other". The
|
|
|
|
|
// bitsets do not have to be the same size. If other is smaller, all
|
|
|
|
|
// the higher order bits are assumed to be 0.
|
2020-10-29 14:25:39 +01:00
|
|
|
void Intersection(const Bitset64<IndexType>& other) {
|
2013-01-10 17:01:34 +00:00
|
|
|
const int min_size = std::min(data_.size(), other.data_.size());
|
2025-02-05 18:11:16 +01:00
|
|
|
uint64_t* const d = data_.data();
|
|
|
|
|
const uint64_t* const o = other.data_.data();
|
2013-01-10 17:01:34 +00:00
|
|
|
for (int i = 0; i < min_size; ++i) {
|
2025-02-05 18:11:16 +01:00
|
|
|
d[i] &= o[i];
|
2013-01-10 17:01:34 +00:00
|
|
|
}
|
|
|
|
|
for (int i = min_size; i < data_.size(); ++i) {
|
2025-02-05 18:11:16 +01:00
|
|
|
d[i] = 0;
|
2013-01-10 17:01:34 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-27 11:10:42 +02:00
|
|
|
// This one assume both given bitset to be of the same size.
|
|
|
|
|
void SetToIntersectionOf(const Bitset64<IndexType>& a,
|
|
|
|
|
const Bitset64<IndexType>& b) {
|
|
|
|
|
DCHECK_EQ(a.size(), b.size());
|
|
|
|
|
Resize(a.size());
|
|
|
|
|
|
|
|
|
|
// Copy buckets.
|
|
|
|
|
const int num_buckets = a.data_.size();
|
|
|
|
|
for (int i = 0; i < num_buckets; ++i) {
|
|
|
|
|
data_[i] = a.data_[i] & b.data_[i];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-06 16:11:43 +01:00
|
|
|
// Sets "this" to be the union of "this" and "other". The
|
|
|
|
|
// bitsets do not have to be the same size. If other is smaller, all
|
|
|
|
|
// the higher order bits are assumed to be 0.
|
2020-10-29 14:25:39 +01:00
|
|
|
void Union(const Bitset64<IndexType>& other) {
|
2017-02-06 16:11:43 +01:00
|
|
|
const int min_size = std::min(data_.size(), other.data_.size());
|
|
|
|
|
for (int i = 0; i < min_size; ++i) {
|
|
|
|
|
data_[i] |= other.data_[i];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-01-10 17:01:34 +00:00
|
|
|
// Class to iterate over the bit positions at 1 of a Bitset64.
|
2014-03-21 18:01:18 +00:00
|
|
|
//
|
2021-04-01 12:13:35 +02:00
|
|
|
// IMPORTANT: Because the iterator "caches" the current uint64_t bucket, this
|
2014-03-21 18:01:18 +00:00
|
|
|
// will probably not do what you want if Bitset64 is modified while iterating.
|
2013-01-10 17:01:34 +00:00
|
|
|
class Iterator {
|
2020-10-22 23:36:58 +02:00
|
|
|
public:
|
2024-01-31 14:44:02 +01:00
|
|
|
// Make this iterator a std::forward_iterator, so it works with std::sample,
|
|
|
|
|
// std::max_element, etc.
|
|
|
|
|
Iterator() : data_(nullptr), size_(0) {}
|
|
|
|
|
Iterator(Iterator&& other) = default;
|
|
|
|
|
Iterator(const Iterator& other) = default;
|
|
|
|
|
Iterator& operator=(const Iterator& other) = default;
|
|
|
|
|
using difference_type = std::ptrdiff_t;
|
|
|
|
|
using iterator_category = std::forward_iterator_tag;
|
|
|
|
|
using value_type = IndexType;
|
|
|
|
|
using size_type = std::size_t;
|
|
|
|
|
using reference = value_type&;
|
|
|
|
|
using pointer = value_type*;
|
|
|
|
|
|
2022-11-22 17:44:54 +01:00
|
|
|
explicit Iterator(const Bitset64& bitset)
|
|
|
|
|
: data_(bitset.data_.data()), size_(bitset.data_.size()) {
|
|
|
|
|
if (!bitset.data_.empty()) {
|
|
|
|
|
current_ = data_[0];
|
|
|
|
|
this->operator++();
|
2013-01-10 17:01:34 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-31 14:44:02 +01:00
|
|
|
static Iterator EndIterator(const Bitset64& bitset) {
|
|
|
|
|
return Iterator(bitset.data_.data());
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-31 16:19:50 +01:00
|
|
|
bool operator==(const Iterator& other) const { return !(*this != other); }
|
2024-01-31 14:44:02 +01:00
|
|
|
bool operator!=(const Iterator& other) const {
|
|
|
|
|
if (other.size_ == 0) {
|
|
|
|
|
return size_ != 0;
|
|
|
|
|
}
|
|
|
|
|
return std::tie(index_, current_) !=
|
|
|
|
|
std::tie(other.index_, other.current_);
|
|
|
|
|
}
|
2013-01-10 17:01:34 +00:00
|
|
|
|
2022-11-22 17:44:54 +01:00
|
|
|
IndexType operator*() const { return IndexType(index_); }
|
2013-01-10 17:01:34 +00:00
|
|
|
|
2024-01-31 14:44:02 +01:00
|
|
|
Iterator operator++(int) {
|
|
|
|
|
Iterator other = *this;
|
2024-01-31 16:19:50 +01:00
|
|
|
++(*this);
|
2024-01-31 14:44:02 +01:00
|
|
|
return other;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Iterator& operator++() {
|
2022-11-22 17:44:54 +01:00
|
|
|
int bucket = BitOffset64(index_);
|
|
|
|
|
while (current_ == 0) {
|
|
|
|
|
bucket++;
|
|
|
|
|
if (bucket == size_) {
|
|
|
|
|
size_ = 0;
|
2024-01-31 14:44:02 +01:00
|
|
|
return *this;
|
2013-01-10 17:01:34 +00:00
|
|
|
}
|
2022-11-22 17:44:54 +01:00
|
|
|
current_ = data_[bucket];
|
2013-01-10 17:01:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Computes the index and clear the least significant bit of current_.
|
2022-11-22 17:44:54 +01:00
|
|
|
index_ = BitShift64(bucket) | LeastSignificantBitPosition64(current_);
|
2013-01-10 17:01:34 +00:00
|
|
|
current_ &= current_ - 1;
|
2024-01-31 14:44:02 +01:00
|
|
|
return *this;
|
2013-01-10 17:01:34 +00:00
|
|
|
}
|
|
|
|
|
|
2020-10-22 23:36:58 +02:00
|
|
|
private:
|
2024-01-31 14:44:02 +01:00
|
|
|
explicit Iterator(const uint64_t* data) : data_(data), size_(0) {}
|
|
|
|
|
|
|
|
|
|
const uint64_t* data_;
|
2022-11-22 17:44:54 +01:00
|
|
|
int size_;
|
|
|
|
|
int index_ = 0;
|
|
|
|
|
uint64_t current_ = 0;
|
2013-01-10 17:01:34 +00:00
|
|
|
};
|
|
|
|
|
|
2013-06-11 14:53:20 +00:00
|
|
|
// Allows range-based "for" loop on the non-zero positions:
|
|
|
|
|
// for (const IndexType index : bitset) {}
|
|
|
|
|
Iterator begin() const { return Iterator(*this); }
|
2024-01-31 14:44:02 +01:00
|
|
|
Iterator end() const { return Iterator::EndIterator(*this); }
|
2013-06-11 14:53:20 +00:00
|
|
|
|
2021-04-14 14:33:47 +02:00
|
|
|
// Cryptic function! This is just an optimized version of a given piece of
|
|
|
|
|
// code and has probably little general use.
|
|
|
|
|
static uint64_t ConditionalXorOfTwoBits(IndexType i, uint64_t use1,
|
2023-10-15 18:08:33 +02:00
|
|
|
Bitset64<IndexType>::ConstView set1,
|
2021-04-14 14:33:47 +02:00
|
|
|
uint64_t use2,
|
2023-10-15 18:08:33 +02:00
|
|
|
Bitset64<IndexType>::ConstView set2) {
|
2013-01-10 17:01:34 +00:00
|
|
|
DCHECK(use1 == 0 || use1 == 1);
|
|
|
|
|
DCHECK(use2 == 0 || use2 == 1);
|
2014-03-21 18:01:18 +00:00
|
|
|
const int bucket = BitOffset64(Value(i));
|
|
|
|
|
const int pos = BitPos64(Value(i));
|
2023-10-15 18:08:33 +02:00
|
|
|
return ((use1 << pos) & set1.data()[bucket]) ^
|
|
|
|
|
((use2 << pos) & set2.data()[bucket]);
|
2013-01-10 17:01:34 +00:00
|
|
|
}
|
|
|
|
|
|
2019-11-20 14:28:11 -08:00
|
|
|
// Returns a 0/1 string representing the bitset.
|
2014-04-04 09:13:02 +00:00
|
|
|
std::string DebugString() const {
|
|
|
|
|
std::string output;
|
|
|
|
|
for (IndexType i(0); i < size(); ++i) {
|
|
|
|
|
output += IsSet(i) ? "1" : "0";
|
|
|
|
|
}
|
|
|
|
|
return output;
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-05 18:11:16 +01:00
|
|
|
bool IsAllFalse() const {
|
|
|
|
|
return std::all_of(data_.begin(), data_.end(),
|
|
|
|
|
[](uint64_t v) { return v == 0; });
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-22 23:36:58 +02:00
|
|
|
private:
|
2014-03-21 18:01:18 +00:00
|
|
|
// Returns the value of the index type.
|
2021-04-01 12:13:35 +02:00
|
|
|
// This function is specialized below to work with IntType and int64_t.
|
2022-02-22 18:33:45 +01:00
|
|
|
static int Value(IndexType input);
|
2014-03-21 18:01:18 +00:00
|
|
|
|
2013-01-10 17:01:34 +00:00
|
|
|
IndexType size_;
|
2021-04-01 12:13:35 +02:00
|
|
|
std::vector<uint64_t> data_;
|
2013-01-10 17:01:34 +00:00
|
|
|
|
2020-10-22 23:36:58 +02:00
|
|
|
template <class OtherIndexType>
|
|
|
|
|
friend class Bitset64;
|
2013-01-10 17:01:34 +00:00
|
|
|
};
|
|
|
|
|
|
2016-06-02 13:19:10 +02:00
|
|
|
// Specialized version of Bitset64 that allows to query the last bit set more
|
|
|
|
|
// efficiently.
|
|
|
|
|
class BitQueue64 {
|
2020-10-22 23:36:58 +02:00
|
|
|
public:
|
2016-06-02 13:19:10 +02:00
|
|
|
BitQueue64() : size_(), top_(-1), data_() {}
|
|
|
|
|
explicit BitQueue64(int size)
|
|
|
|
|
: size_(size), top_(-1), data_(BitLength64(size), 0) {}
|
|
|
|
|
|
2023-08-30 10:04:47 -04:00
|
|
|
// This type is neither copyable nor movable.
|
|
|
|
|
BitQueue64(const BitQueue64&) = delete;
|
|
|
|
|
BitQueue64& operator=(const BitQueue64&) = delete;
|
|
|
|
|
|
2016-06-02 13:19:10 +02:00
|
|
|
void IncreaseSize(int size) {
|
|
|
|
|
CHECK_GE(size, size_);
|
|
|
|
|
size_ = size;
|
|
|
|
|
data_.resize(BitLength64(size), 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ClearAndResize(int size) {
|
|
|
|
|
top_ = -1;
|
|
|
|
|
size_ = size;
|
|
|
|
|
data_.assign(BitLength64(size), 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Set(int i) {
|
|
|
|
|
DCHECK_GE(i, 0);
|
|
|
|
|
DCHECK_LT(i, size_);
|
|
|
|
|
top_ = std::max(top_, i);
|
|
|
|
|
data_[BitOffset64(i)] |= OneBit64(BitPos64(i));
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-24 11:07:21 +01:00
|
|
|
// Sets all the bits from 0 up to i-1 to 1.
|
|
|
|
|
void SetAllBefore(int i) {
|
|
|
|
|
DCHECK_GE(i, 0);
|
|
|
|
|
DCHECK_LT(i, size_);
|
|
|
|
|
top_ = std::max(top_, i - 1);
|
2018-02-12 11:39:56 +01:00
|
|
|
int bucket_index = static_cast<int>(BitOffset64(i));
|
2017-11-24 11:07:21 +01:00
|
|
|
data_[bucket_index] |= OneBit64(BitPos64(i)) - 1;
|
|
|
|
|
for (--bucket_index; bucket_index >= 0; --bucket_index) {
|
|
|
|
|
data_[bucket_index] = kAllBits64;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-02 13:19:10 +02:00
|
|
|
// Returns the position of the highest bit set in O(1) or -1 if no bit is set.
|
|
|
|
|
int Top() const { return top_; }
|
|
|
|
|
|
|
|
|
|
// Clears the Top() bit and recomputes the position of the next Top().
|
|
|
|
|
void ClearTop() {
|
|
|
|
|
DCHECK_NE(top_, -1);
|
2018-02-12 11:39:56 +01:00
|
|
|
int bucket_index = static_cast<int>(BitOffset64(top_));
|
2021-04-01 12:13:35 +02:00
|
|
|
uint64_t bucket = data_[bucket_index] &= ~OneBit64(BitPos64(top_));
|
2016-06-02 13:19:10 +02:00
|
|
|
while (!bucket) {
|
|
|
|
|
if (bucket_index == 0) {
|
|
|
|
|
top_ = -1;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
bucket = data_[--bucket_index];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Note(user): I experimented with reversing the bit order in a bucket to
|
|
|
|
|
// use LeastSignificantBitPosition64() and it is only slightly faster at the
|
2021-08-15 23:11:16 +07:00
|
|
|
// cost of a lower Set() speed. So I preferred this version.
|
2018-02-12 11:39:56 +01:00
|
|
|
top_ = static_cast<int>(BitShift64(bucket_index) +
|
|
|
|
|
MostSignificantBitPosition64(bucket));
|
2016-06-02 13:19:10 +02:00
|
|
|
}
|
|
|
|
|
|
2020-10-22 23:36:58 +02:00
|
|
|
private:
|
2016-06-02 13:19:10 +02:00
|
|
|
int size_;
|
|
|
|
|
int top_;
|
2021-04-01 12:13:35 +02:00
|
|
|
std::vector<uint64_t> data_;
|
2016-06-02 13:19:10 +02:00
|
|
|
};
|
|
|
|
|
|
2021-04-01 12:13:35 +02:00
|
|
|
// The specialization of Value() for IntType and int64_t.
|
2014-03-21 18:01:18 +00:00
|
|
|
template <typename IntType>
|
2022-02-22 18:33:45 +01:00
|
|
|
inline int Bitset64<IntType>::Value(IntType input) {
|
2014-03-21 18:01:18 +00:00
|
|
|
DCHECK_GE(input.value(), 0);
|
|
|
|
|
return input.value();
|
|
|
|
|
}
|
2020-10-22 23:36:58 +02:00
|
|
|
template <>
|
2022-02-22 18:33:45 +01:00
|
|
|
inline int Bitset64<int>::Value(int input) {
|
|
|
|
|
DCHECK_GE(input, 0);
|
|
|
|
|
return input;
|
|
|
|
|
}
|
|
|
|
|
template <>
|
|
|
|
|
inline int Bitset64<int64_t>::Value(int64_t input) {
|
2014-03-21 18:01:18 +00:00
|
|
|
DCHECK_GE(input, 0);
|
|
|
|
|
return input;
|
|
|
|
|
}
|
2024-09-23 16:04:53 +02:00
|
|
|
template <>
|
|
|
|
|
inline int Bitset64<size_t>::Value(size_t input) {
|
|
|
|
|
return input;
|
|
|
|
|
}
|
2014-03-21 18:01:18 +00:00
|
|
|
|
2013-12-05 09:23:39 +00:00
|
|
|
// A simple utility class to set/unset integer in a range [0, size).
|
|
|
|
|
// This is optimized for sparsity.
|
2021-04-01 12:13:35 +02:00
|
|
|
template <typename IntegerType = int64_t>
|
2020-10-22 23:36:58 +02:00
|
|
|
class SparseBitset {
|
|
|
|
|
public:
|
2013-12-05 09:23:39 +00:00
|
|
|
SparseBitset() {}
|
2014-03-21 18:01:18 +00:00
|
|
|
explicit SparseBitset(IntegerType size) : bitset_(size) {}
|
2023-08-30 10:04:47 -04:00
|
|
|
|
|
|
|
|
// This type is neither copyable nor movable.
|
|
|
|
|
SparseBitset(const SparseBitset&) = delete;
|
|
|
|
|
SparseBitset& operator=(const SparseBitset&) = delete;
|
2014-03-21 18:01:18 +00:00
|
|
|
IntegerType size() const { return bitset_.size(); }
|
2025-03-05 14:03:49 +01:00
|
|
|
void ResetAllToFalse() { ClearAndResize(size()); }
|
2013-12-05 09:23:39 +00:00
|
|
|
void ClearAndResize(IntegerType size) {
|
2014-03-21 18:01:18 +00:00
|
|
|
// As of 19/03/2014, experiments show that this is a reasonable threshold.
|
|
|
|
|
const int kSparseThreshold = 300;
|
|
|
|
|
if (to_clear_.size() * kSparseThreshold < size) {
|
2025-03-05 14:03:49 +01:00
|
|
|
for (const IntegerType i : to_clear_) bitset_.ClearBucket(i);
|
|
|
|
|
to_clear_.clear();
|
2014-03-21 18:01:18 +00:00
|
|
|
bitset_.Resize(size);
|
|
|
|
|
} else {
|
|
|
|
|
bitset_.ClearAndResize(size);
|
2014-04-04 09:13:02 +00:00
|
|
|
to_clear_.clear();
|
2013-12-05 09:23:39 +00:00
|
|
|
}
|
|
|
|
|
}
|
2014-07-29 00:58:38 +00:00
|
|
|
void Resize(IntegerType size) {
|
|
|
|
|
if (size < bitset_.size()) {
|
|
|
|
|
int new_index = 0;
|
|
|
|
|
for (IntegerType index : to_clear_) {
|
|
|
|
|
if (index < size) {
|
|
|
|
|
to_clear_[new_index] = index;
|
|
|
|
|
++new_index;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
to_clear_.resize(new_index);
|
|
|
|
|
}
|
|
|
|
|
bitset_.Resize(size);
|
|
|
|
|
}
|
2014-03-21 18:01:18 +00:00
|
|
|
bool operator[](IntegerType index) const { return bitset_[index]; }
|
2013-12-05 09:23:39 +00:00
|
|
|
void Set(IntegerType index) {
|
2014-03-21 18:01:18 +00:00
|
|
|
if (!bitset_[index]) {
|
|
|
|
|
bitset_.Set(index);
|
2013-12-10 15:58:07 +00:00
|
|
|
to_clear_.push_back(index);
|
2013-12-05 09:23:39 +00:00
|
|
|
}
|
|
|
|
|
}
|
2024-09-27 11:10:42 +02:00
|
|
|
|
2025-10-16 13:29:59 +02:00
|
|
|
void CopyFrom(const SparseBitset& other) {
|
|
|
|
|
bitset_.ClearAndResize(other.size());
|
|
|
|
|
bitset_.SetContentFromBitsetOfSameSize(other.bitset_);
|
|
|
|
|
to_clear_.assign(other.to_clear_.begin(), other.to_clear_.end());
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-27 11:10:42 +02:00
|
|
|
// A bit hacky for really hot loop.
|
|
|
|
|
typename Bitset64<IntegerType>::View BitsetView() { return bitset_.view(); }
|
2025-06-17 12:48:24 +02:00
|
|
|
typename Bitset64<IntegerType>::ConstView BitsetConstView() {
|
|
|
|
|
return bitset_.const_view();
|
|
|
|
|
}
|
2024-09-27 11:10:42 +02:00
|
|
|
void SetUnsafe(typename Bitset64<IntegerType>::View view, IntegerType index) {
|
|
|
|
|
view.Set(index);
|
2023-02-06 19:02:44 +01:00
|
|
|
to_clear_.push_back(index);
|
|
|
|
|
}
|
2024-09-27 11:10:42 +02:00
|
|
|
|
2014-03-21 18:01:18 +00:00
|
|
|
void Clear(IntegerType index) { bitset_.Clear(index); }
|
2013-12-05 09:23:39 +00:00
|
|
|
int NumberOfSetCallsWithDifferentArguments() const {
|
|
|
|
|
return to_clear_.size();
|
|
|
|
|
}
|
2020-10-29 14:25:39 +01:00
|
|
|
const std::vector<IntegerType>& PositionsSetAtLeastOnce() const {
|
2013-12-10 15:58:07 +00:00
|
|
|
return to_clear_;
|
|
|
|
|
}
|
2013-12-05 09:23:39 +00:00
|
|
|
|
2014-07-29 00:58:38 +00:00
|
|
|
// Tells the class that all its bits are cleared, so it can reset to_clear_
|
|
|
|
|
// to the empty vector. Note that this call is "unsafe" since the fact that
|
|
|
|
|
// the class is actually all cleared is only checked in debug mode.
|
|
|
|
|
//
|
|
|
|
|
// This is useful to iterate on the "set" positions while clearing them for
|
|
|
|
|
// instance. This way, after the loop, a client can call this for efficiency.
|
|
|
|
|
void NotifyAllClear() {
|
2025-02-24 22:59:21 +01:00
|
|
|
#if !defined(NDEBUG)
|
|
|
|
|
for (IntegerType index : to_clear_) CHECK(!bitset_[index]);
|
|
|
|
|
#endif
|
2014-07-29 00:58:38 +00:00
|
|
|
to_clear_.clear();
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-06 19:02:44 +01:00
|
|
|
typename Bitset64<IntegerType>::ConstView const_view() const {
|
|
|
|
|
return bitset_.const_view();
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-22 23:36:58 +02:00
|
|
|
private:
|
2014-03-21 18:01:18 +00:00
|
|
|
Bitset64<IntegerType> bitset_;
|
2013-12-10 15:58:07 +00:00
|
|
|
std::vector<IntegerType> to_clear_;
|
2013-12-05 09:23:39 +00:00
|
|
|
};
|
|
|
|
|
|
2020-10-22 23:36:58 +02:00
|
|
|
} // namespace operations_research
|
2010-09-15 12:42:33 +00:00
|
|
|
|
2025-11-05 10:13:48 +01:00
|
|
|
#endif // ORTOOLS_UTIL_BITSET_H_
|