1*bb722a7dSDimitry Andric //===-- A self contained equivalent of std::bitset --------------*- C++ -*-===// 2*bb722a7dSDimitry Andric // 3*bb722a7dSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*bb722a7dSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*bb722a7dSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*bb722a7dSDimitry Andric // 7*bb722a7dSDimitry Andric //===----------------------------------------------------------------------===// 8*bb722a7dSDimitry Andric 9*bb722a7dSDimitry Andric #ifndef LLVM_LIBC_SRC___SUPPORT_CPP_BITSET_H 10*bb722a7dSDimitry Andric #define LLVM_LIBC_SRC___SUPPORT_CPP_BITSET_H 11*bb722a7dSDimitry Andric 12*bb722a7dSDimitry Andric #include "src/__support/macros/attributes.h" 13*bb722a7dSDimitry Andric #include "src/__support/macros/config.h" 14*bb722a7dSDimitry Andric #include <stddef.h> // For size_t. 15*bb722a7dSDimitry Andric 16*bb722a7dSDimitry Andric namespace LIBC_NAMESPACE_DECL { 17*bb722a7dSDimitry Andric namespace cpp { 18*bb722a7dSDimitry Andric 19*bb722a7dSDimitry Andric template <size_t NumberOfBits> struct bitset { 20*bb722a7dSDimitry Andric static_assert(NumberOfBits != 0, 21*bb722a7dSDimitry Andric "Cannot create a LIBC_NAMESPACE::cpp::bitset of size 0."); 22*bb722a7dSDimitry Andric setbitset23*bb722a7dSDimitry Andric LIBC_INLINE constexpr void set(size_t Index) { 24*bb722a7dSDimitry Andric Data[Index / BITS_PER_UNIT] |= mask(Index); 25*bb722a7dSDimitry Andric } 26*bb722a7dSDimitry Andric resetbitset27*bb722a7dSDimitry Andric LIBC_INLINE constexpr void reset() { 28*bb722a7dSDimitry Andric for (size_t i = 0; i < NUMBER_OF_UNITS; ++i) 29*bb722a7dSDimitry Andric Data[i] = 0; 30*bb722a7dSDimitry Andric } 31*bb722a7dSDimitry Andric testbitset32*bb722a7dSDimitry Andric LIBC_INLINE constexpr bool test(size_t Index) const { 33*bb722a7dSDimitry Andric return Data[Index / BITS_PER_UNIT] & mask(Index); 34*bb722a7dSDimitry Andric } 35*bb722a7dSDimitry Andric flipbitset36*bb722a7dSDimitry Andric LIBC_INLINE constexpr void flip() { 37*bb722a7dSDimitry Andric for (size_t i = 0; i < NUMBER_OF_UNITS; ++i) 38*bb722a7dSDimitry Andric Data[i] = ~Data[i]; 39*bb722a7dSDimitry Andric } 40*bb722a7dSDimitry Andric 41*bb722a7dSDimitry Andric // This function sets all bits in the range from Start to End (inclusive) to 42*bb722a7dSDimitry Andric // true. It assumes that Start <= End. set_rangebitset43*bb722a7dSDimitry Andric LIBC_INLINE constexpr void set_range(size_t Start, size_t End) { 44*bb722a7dSDimitry Andric size_t start_index = Start / BITS_PER_UNIT; 45*bb722a7dSDimitry Andric size_t end_index = End / BITS_PER_UNIT; 46*bb722a7dSDimitry Andric 47*bb722a7dSDimitry Andric if (start_index == end_index) { 48*bb722a7dSDimitry Andric // The reason the left shift is split into two parts (instead of just left 49*bb722a7dSDimitry Andric // shifting by End - Start + 1) is because when a number is shifted left 50*bb722a7dSDimitry Andric // by 64 then it wraps around to doing nothing, but shifting by 63 and the 51*bb722a7dSDimitry Andric // shifting by 1 correctly shifts away all of the bits. 52*bb722a7dSDimitry Andric size_t bit_mask = (((size_t(1) << (End - Start)) << 1) - 1) 53*bb722a7dSDimitry Andric << (Start - (start_index * BITS_PER_UNIT)); 54*bb722a7dSDimitry Andric Data[start_index] |= bit_mask; 55*bb722a7dSDimitry Andric } else { 56*bb722a7dSDimitry Andric size_t low_bit_mask = 57*bb722a7dSDimitry Andric ~((size_t(1) << (Start - (start_index * BITS_PER_UNIT))) - 1); 58*bb722a7dSDimitry Andric Data[start_index] |= low_bit_mask; 59*bb722a7dSDimitry Andric 60*bb722a7dSDimitry Andric for (size_t i = start_index + 1; i < end_index; ++i) 61*bb722a7dSDimitry Andric Data[i] = ~size_t(0); 62*bb722a7dSDimitry Andric 63*bb722a7dSDimitry Andric // Same as above, by splitting the shift the behavior is more consistent. 64*bb722a7dSDimitry Andric size_t high_bit_mask = 65*bb722a7dSDimitry Andric ((size_t(1) << (End - (end_index * BITS_PER_UNIT))) << 1) - 1; 66*bb722a7dSDimitry Andric Data[end_index] |= high_bit_mask; 67*bb722a7dSDimitry Andric } 68*bb722a7dSDimitry Andric } 69*bb722a7dSDimitry Andric 70*bb722a7dSDimitry Andric LIBC_INLINE constexpr bool 71*bb722a7dSDimitry Andric operator==(const bitset<NumberOfBits> &other) const { 72*bb722a7dSDimitry Andric for (size_t i = 0; i < NUMBER_OF_UNITS; ++i) { 73*bb722a7dSDimitry Andric if (Data[i] != other.Data[i]) 74*bb722a7dSDimitry Andric return false; 75*bb722a7dSDimitry Andric } 76*bb722a7dSDimitry Andric return true; 77*bb722a7dSDimitry Andric } 78*bb722a7dSDimitry Andric 79*bb722a7dSDimitry Andric private: 80*bb722a7dSDimitry Andric static constexpr size_t BITS_PER_BYTE = 8; 81*bb722a7dSDimitry Andric static constexpr size_t BITS_PER_UNIT = BITS_PER_BYTE * sizeof(size_t); 82*bb722a7dSDimitry Andric static constexpr size_t NUMBER_OF_UNITS = 83*bb722a7dSDimitry Andric (NumberOfBits + BITS_PER_UNIT - 1) / BITS_PER_UNIT; 84*bb722a7dSDimitry Andric maskbitset85*bb722a7dSDimitry Andric LIBC_INLINE static constexpr size_t mask(size_t Index) { 86*bb722a7dSDimitry Andric return size_t{1} << (Index % BITS_PER_UNIT); 87*bb722a7dSDimitry Andric } 88*bb722a7dSDimitry Andric size_t Data[NUMBER_OF_UNITS] = {0}; 89*bb722a7dSDimitry Andric }; 90*bb722a7dSDimitry Andric 91*bb722a7dSDimitry Andric } // namespace cpp 92*bb722a7dSDimitry Andric } // namespace LIBC_NAMESPACE_DECL 93*bb722a7dSDimitry Andric 94*bb722a7dSDimitry Andric #endif // LLVM_LIBC_SRC___SUPPORT_CPP_BITSET_H 95