1 //===-- include/flang/Common/constexpr-bitset.h -----------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #ifndef FORTRAN_COMMON_CONSTEXPR_BITSET_H_
10 #define FORTRAN_COMMON_CONSTEXPR_BITSET_H_
11 
12 // Implements a replacement for std::bitset<> that is suitable for use
13 // in constexpr expressions.  Limited to elements in [0..63].
14 
15 #include "bit-population-count.h"
16 #include <cstddef>
17 #include <cstdint>
18 #include <initializer_list>
19 #include <optional>
20 #include <type_traits>
21 
22 namespace Fortran::common {
23 
24 template <int BITS> class BitSet {
25   static_assert(BITS > 0 && BITS <= 64);
26   static constexpr bool partialWord{BITS != 32 && BITS != 64};
27   using Word = std::conditional_t<(BITS > 32), std::uint64_t, std::uint32_t>;
28   static constexpr Word allBits{
29       partialWord ? (static_cast<Word>(1) << BITS) - 1 : ~static_cast<Word>(0)};
30 
BitSet(Word b)31   constexpr BitSet(Word b) : bits_{b} {}
32 
33 public:
BitSet()34   constexpr BitSet() {}
BitSet(const std::initializer_list<int> & xs)35   constexpr BitSet(const std::initializer_list<int> &xs) {
36     for (auto x : xs) {
37       set(x);
38     }
39   }
40   constexpr BitSet(const BitSet &) = default;
41   constexpr BitSet(BitSet &&) = default;
42   constexpr BitSet &operator=(const BitSet &) = default;
43   constexpr BitSet &operator=(BitSet &&) = default;
44 
45   constexpr BitSet &operator&=(const BitSet &that) {
46     bits_ &= that.bits_;
47     return *this;
48   }
49   constexpr BitSet &operator&=(BitSet &&that) {
50     bits_ &= that.bits_;
51     return *this;
52   }
53   constexpr BitSet &operator^=(const BitSet &that) {
54     bits_ ^= that.bits_;
55     return *this;
56   }
57   constexpr BitSet &operator^=(BitSet &&that) {
58     bits_ ^= that.bits_;
59     return *this;
60   }
61   constexpr BitSet &operator|=(const BitSet &that) {
62     bits_ |= that.bits_;
63     return *this;
64   }
65   constexpr BitSet &operator|=(BitSet &&that) {
66     bits_ |= that.bits_;
67     return *this;
68   }
69 
70   constexpr BitSet operator~() const { return ~bits_; }
71   constexpr BitSet operator&(const BitSet &that) const {
72     return bits_ & that.bits_;
73   }
74   constexpr BitSet operator&(BitSet &&that) const { return bits_ & that.bits_; }
75   constexpr BitSet operator^(const BitSet &that) const {
76     return bits_ ^ that.bits_;
77   }
78   constexpr BitSet operator^(BitSet &&that) const { return bits_ & that.bits_; }
79   constexpr BitSet operator|(const BitSet &that) const {
80     return bits_ | that.bits_;
81   }
82   constexpr BitSet operator|(BitSet &&that) const { return bits_ | that.bits_; }
83 
84   constexpr bool operator==(const BitSet &that) const {
85     return bits_ == that.bits_;
86   }
87   constexpr bool operator==(BitSet &&that) const { return bits_ == that.bits_; }
88   constexpr bool operator!=(const BitSet &that) const {
89     return bits_ != that.bits_;
90   }
91   constexpr bool operator!=(BitSet &&that) const { return bits_ != that.bits_; }
92 
size()93   static constexpr std::size_t size() { return BITS; }
test(std::size_t x)94   constexpr bool test(std::size_t x) const {
95     return x < BITS && ((bits_ >> x) & 1) != 0;
96   }
97 
all()98   constexpr bool all() const { return bits_ == allBits; }
any()99   constexpr bool any() const { return bits_ != 0; }
none()100   constexpr bool none() const { return bits_ == 0; }
101 
count()102   constexpr std::size_t count() const { return BitPopulationCount(bits_); }
103 
set()104   constexpr BitSet &set() {
105     bits_ = allBits;
106     return *this;
107   }
108   constexpr BitSet set(std::size_t x, bool value = true) {
109     if (!value) {
110       return reset(x);
111     } else {
112       bits_ |= static_cast<Word>(1) << x;
113       return *this;
114     }
115   }
reset()116   constexpr BitSet &reset() {
117     bits_ = 0;
118     return *this;
119   }
reset(std::size_t x)120   constexpr BitSet &reset(std::size_t x) {
121     bits_ &= ~(static_cast<Word>(1) << x);
122     return *this;
123   }
flip()124   constexpr BitSet &flip() {
125     bits_ ^= allBits;
126     return *this;
127   }
flip(std::size_t x)128   constexpr BitSet &flip(std::size_t x) {
129     bits_ ^= static_cast<Word>(1) << x;
130     return *this;
131   }
132 
LeastElement()133   constexpr std::optional<std::size_t> LeastElement() const {
134     if (bits_ == 0) {
135       return std::nullopt;
136     } else {
137       return {TrailingZeroBitCount(bits_)};
138     }
139   }
140 
bits()141   Word bits() const { return bits_; }
142 
143 private:
144   Word bits_{0};
145 };
146 } // namespace Fortran::common
147 #endif // FORTRAN_COMMON_CONSTEXPR_BITSET_H_
148