blob: aa8a3ba6fdf4f8180d557d6569ccaf01ed8b82a3 [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef LIB_FIDL_CPP_INTERNAL_BITSET_H_
#define LIB_FIDL_CPP_INTERNAL_BITSET_H_
#include <cstddef>
#include <cstdint>
namespace fidl {
namespace internal {
// BitSet used to track field presence in HLCPP tables.
template <size_t N>
class BitSet final {
static const size_t RoundUpN = (N + 63ull) & ~63ull;
static const size_t StorageSize = RoundUpN / 64ull;
static inline size_t StorageIndex(size_t index) { return index / 64ull; }
static inline uint64_t BitMask(size_t index) { return 1ull << (index % 64ull); }
// Return the index of the most significant bit set or -1 if none are set.
static inline int64_t MaxBitSet(uint64_t input) {
// __builtin_clzll is undefined for an input of 0.
if (input == 0) {
return -1;
}
return 63ll - __builtin_clzll(input);
}
public:
BitSet() noexcept = default;
BitSet(const BitSet& other) noexcept = default;
BitSet& operator=(const BitSet& other) noexcept = default;
template <size_t Index>
inline bool IsSet() const noexcept {
static_assert(Index < N, "index exceeds BitSet size");
return (storage_[StorageIndex(Index)] & BitMask(Index)) != 0;
}
template <size_t Index>
inline void Set() noexcept {
static_assert(Index < N, "index exceeds BitSet size");
storage_[StorageIndex(Index)] |= BitMask(Index);
}
template <size_t Index>
inline void Clear() noexcept {
static_assert(Index < N, "index exceeds BitSet size");
storage_[StorageIndex(Index)] &= ~BitMask(Index);
}
bool IsEmpty() const noexcept {
uint64_t cum_union = 0ull;
for (size_t i = 0; i < StorageSize; i++) {
cum_union |= storage_[i];
}
return cum_union == 0ull;
}
int64_t MaxSetIndex() const noexcept {
static_assert(StorageSize >= 1, "storage size expected to be at least 1");
for (int64_t i = StorageSize - 1; i >= 1; i--) {
uint64_t val = storage_[i];
if (val != 0) {
return 64ll * i + MaxBitSet(val);
}
}
return MaxBitSet(storage_[0]);
}
private:
uint64_t storage_[StorageSize] = {};
};
// Specialization to avoid compile errors due to 0-sized array.
template <>
class BitSet<0> {
public:
BitSet() noexcept = default;
BitSet(const BitSet& other) noexcept = default;
BitSet& operator=(const BitSet& other) noexcept = default;
bool IsEmpty() const noexcept { return true; }
int64_t MaxSetIndex() const noexcept { return -1; }
};
} // namespace internal
} // namespace fidl
#endif // LIB_FIDL_CPP_INTERNAL_BITSET_H_