blob: 6091ed79e9362ed1fe08d1f663cf840ebec074c6 [file] [log] [blame]
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/ukm/bitset.h"
#include <cstring>
#include "base/check_op.h"
#include "base/containers/span.h"
namespace ukm {
BitSet::BitSet(size_t set_size) : set_size_(set_size) {
CHECK_GT(set_size_, 0U);
bitset_.resize(1 + (set_size_ - 1) / 8);
}
BitSet::BitSet(size_t set_size, std::string_view data) : BitSet(set_size) {
// Copy the passed `data` to the end of the internal `bitset_`. For example,
// if `data` is {0xAA, 0xBB}, and set_size is 32 (so `bitset_` is a vector of
// 4 uint8_t's), then the final `bitset_` should be {0x00, 0x00, 0xAA, 0xBB}.
base::span(bitset_).last(data.size()).copy_from(base::as_byte_span((data)));
}
BitSet::~BitSet() = default;
void BitSet::Add(size_t index) {
CHECK_LT(index, set_size_);
size_t internal_index = ToInternalIndex(index);
uint8_t bitmask = ToBitmask(index);
bitset_[internal_index] |= bitmask;
}
bool BitSet::Contains(size_t index) const {
CHECK_LT(index, set_size_);
size_t internal_index = ToInternalIndex(index);
uint8_t bitmask = ToBitmask(index);
return (bitset_[internal_index] & bitmask) != 0;
}
std::string BitSet::Serialize() const {
// Since the bitset is stored from right to left, as an optimization, omit all
// the leftmost 0's.
size_t offset;
for (offset = 0; offset < bitset_.size(); ++offset) {
if (bitset_[offset] != 0) {
break;
}
}
base::span<const char> s =
base::as_chars(base::span(bitset_).subspan(offset));
return std::string(s.begin(), s.end());
}
size_t BitSet::ToInternalIndex(size_t index) const {
// Note: internally, the bitset is stored from right to left. For example,
// index 0 maps to the least significant bit of the last element of `bitset_`.
return bitset_.size() - 1 - index / 8;
}
uint8_t BitSet::ToBitmask(size_t index) const {
return 1 << (index % 8);
}
} // namespace ukm