1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
|
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_ACCESSIBILITY_AX_BITSET_H_
#define UI_ACCESSIBILITY_AX_BITSET_H_
#include <stdint.h>
#include <bit>
#include <optional>
#include "base/functional/function_ref.h"
namespace ui {
// A helper class to store AX-related boolean enums.
// IMPORTANT: This AXBitset implementation uses single uint32_t bitmasks and is
// therefore limited to managing enums whose underlying integer values are
// strictly less than 32 (i.e., in the range [0, 31]). Enum values outside
// this range will lead to incorrect behavior or will be ignored.
template <typename T>
class AXBitset {
public:
AXBitset() = default;
AXBitset(uint32_t initial_set_bits, uint32_t initial_values)
: set_bits_(initial_set_bits), values_(initial_values) {}
~AXBitset() = default;
uint32_t GetSetBits() const { return set_bits_; }
uint32_t GetValues() const { return values_; }
// Returns whether enum T at |value| is set to true, false or unset.
std::optional<bool> Get(T enum_value) const {
uint32_t index = static_cast<uint32_t>(enum_value);
uint32_t mask = 1ULL << index;
// Check if the value is set.
if (set_bits_ & mask) {
return values_ & mask;
}
return std::nullopt;
}
// Sets the enum T at |enum_value| to true or false.
void Set(T enum_value, bool bool_value) {
uint32_t index = static_cast<uint32_t>(enum_value);
uint32_t mask = 1ULL << index;
// Mark as set.
set_bits_ |= mask;
if (bool_value) {
// Set the value bit to 1 for true.
values_ |= mask;
} else {
// Clear the value bit to 0 for false.
values_ &= ~mask;
}
}
void Unset(T enum_value) {
uint32_t index = static_cast<uint32_t>(enum_value);
uint32_t mask = 1ULL << index;
// Mark as not set.
set_bits_ &= ~mask;
}
// Iterates over each attribute that is currently "set" (i.e., has been
// explicitly set to true or false and not subsequently unset) and invokes
// the provided 'function' with the attribute and its boolean value.
// The order of iteration is from the least significant bit (lowest enum
// value) to the most significant bit (highest enum value) among the set
// attributes.
void ForEach(
base::FunctionRef<void(T attribute, bool value)> function) const {
uint32_t remainder = set_bits_;
while (remainder) {
// Find the index (0-31) of the least significant bit that is set to 1
// in 'remainder'. This corresponds to the enum's integer value.
// std::countr_zero counts trailing zeros; e.g., for 0b...1000, it
// returns 3.
int index = std::countr_zero(remainder);
T attribute = static_cast<T>(index);
uint32_t mask = 1ULL << index;
bool attribute_value = static_cast<bool>(values_ & mask);
function(attribute, attribute_value);
// Clear the least significant set bit in 'remainder' to prepare for the
// next iteration. This ensures that each set bit is processed exactly
// once.
remainder &= remainder - 1;
}
}
// Merges the set attributes from another AXBitset into this one.
void Append(const AXBitset<T>& other) {
// Clear positions in 'this->values_' that will be overridden by 'other'.
// These are positions where 'other.set_bits_' has a '1'.
// `~other.set_bits_` has '0's at these positions, so ANDing clears them in
// `this->values_`.
values_ &= ~other.set_bits_;
// OR in the relevant values from 'other'.
// `(other.values_ & other.set_bits_)` isolates T/F values only for
// attributes actually set in 'other'.
values_ |= (other.values_ & other.set_bits_);
// Ensure attributes set in 'other' are now also marked as set in 'this'.
set_bits_ |= other.set_bits_;
}
// Returns the number of attributes that are currently explicitly set
// (i.e., have been Set to true or false and not subsequently Unset).
size_t Size() const { return std::popcount(set_bits_); }
template <typename U>
friend bool operator==(const AXBitset<U>& lhs, const AXBitset<U>& rhs);
private:
uint32_t set_bits_ = 0;
uint32_t values_ = 0;
};
template <typename T>
bool operator==(const AXBitset<T>& lhs, const AXBitset<T>& rhs) {
// Check if the set of active attributes is the same.
if (lhs.set_bits_ != rhs.set_bits_) {
return false;
}
// If the set_bits_ are identical, then compare the values for the bits that
// are actually set.
return (lhs.values_ & lhs.set_bits_) == (rhs.values_ & lhs.set_bits_);
}
} // namespace ui
#endif // UI_ACCESSIBILITY_AX_BITSET_H_
|