1*795d594fSAndroid Build Coastguard Worker /* 2*795d594fSAndroid Build Coastguard Worker * Copyright (C) 2017 The Android Open Source Project 3*795d594fSAndroid Build Coastguard Worker * 4*795d594fSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License"); 5*795d594fSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License. 6*795d594fSAndroid Build Coastguard Worker * You may obtain a copy of the License at 7*795d594fSAndroid Build Coastguard Worker * 8*795d594fSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0 9*795d594fSAndroid Build Coastguard Worker * 10*795d594fSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software 11*795d594fSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS, 12*795d594fSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*795d594fSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and 14*795d594fSAndroid Build Coastguard Worker * limitations under the License. 15*795d594fSAndroid Build Coastguard Worker */ 16*795d594fSAndroid Build Coastguard Worker 17*795d594fSAndroid Build Coastguard Worker #ifndef ART_LIBARTBASE_BASE_BIT_STRING_H_ 18*795d594fSAndroid Build Coastguard Worker #define ART_LIBARTBASE_BASE_BIT_STRING_H_ 19*795d594fSAndroid Build Coastguard Worker 20*795d594fSAndroid Build Coastguard Worker #include "bit_struct.h" 21*795d594fSAndroid Build Coastguard Worker #include "bit_utils.h" 22*795d594fSAndroid Build Coastguard Worker 23*795d594fSAndroid Build Coastguard Worker #include <ostream> 24*795d594fSAndroid Build Coastguard Worker 25*795d594fSAndroid Build Coastguard Worker namespace art { 26*795d594fSAndroid Build Coastguard Worker 27*795d594fSAndroid Build Coastguard Worker struct BitStringChar; 28*795d594fSAndroid Build Coastguard Worker inline std::ostream& operator<<(std::ostream& os, const BitStringChar& bc); 29*795d594fSAndroid Build Coastguard Worker 30*795d594fSAndroid Build Coastguard Worker /** 31*795d594fSAndroid Build Coastguard Worker * A BitStringChar is a light-weight wrapper to read/write a single character 32*795d594fSAndroid Build Coastguard Worker * into a BitString, while restricting the bitlength. 33*795d594fSAndroid Build Coastguard Worker * 34*795d594fSAndroid Build Coastguard Worker * This is only intended for reading/writing into temporaries, as the representation is 35*795d594fSAndroid Build Coastguard Worker * inefficient for memory (it uses a word for the character and another word for the bitlength). 36*795d594fSAndroid Build Coastguard Worker * 37*795d594fSAndroid Build Coastguard Worker * See also BitString below. 38*795d594fSAndroid Build Coastguard Worker */ 39*795d594fSAndroid Build Coastguard Worker struct BitStringChar { 40*795d594fSAndroid Build Coastguard Worker using StorageType = uint32_t; 41*795d594fSAndroid Build Coastguard Worker static_assert(std::is_unsigned_v<StorageType>, "BitStringChar::StorageType must be unsigned"); 42*795d594fSAndroid Build Coastguard Worker 43*795d594fSAndroid Build Coastguard Worker // BitStringChars are always zero-initialized by default. Equivalent to BitStringChar(0,0). BitStringCharBitStringChar44*795d594fSAndroid Build Coastguard Worker BitStringChar() : data_(0u), bitlength_(0u) { } 45*795d594fSAndroid Build Coastguard Worker 46*795d594fSAndroid Build Coastguard Worker // Create a new BitStringChar whose data bits can be at most bitlength. BitStringCharBitStringChar47*795d594fSAndroid Build Coastguard Worker BitStringChar(StorageType data, size_t bitlength) 48*795d594fSAndroid Build Coastguard Worker : data_(data), bitlength_(bitlength) { 49*795d594fSAndroid Build Coastguard Worker // All bits higher than bitlength must be set to 0. 50*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(0u, data & ~MaskLeastSignificant(bitlength_)) 51*795d594fSAndroid Build Coastguard Worker << "BitStringChar data out of range, data: " << data << ", bitlength: " << bitlength; 52*795d594fSAndroid Build Coastguard Worker } 53*795d594fSAndroid Build Coastguard Worker 54*795d594fSAndroid Build Coastguard Worker // What is the bitlength constraint for this character? 55*795d594fSAndroid Build Coastguard Worker // (Data could use less bits, but this is the maximum bit capacity at that BitString position). GetBitLengthBitStringChar56*795d594fSAndroid Build Coastguard Worker size_t GetBitLength() const { 57*795d594fSAndroid Build Coastguard Worker return bitlength_; 58*795d594fSAndroid Build Coastguard Worker } 59*795d594fSAndroid Build Coastguard Worker 60*795d594fSAndroid Build Coastguard Worker // Is there any capacity in this BitStringChar to store any data? IsEmptyBitStringChar61*795d594fSAndroid Build Coastguard Worker bool IsEmpty() const { 62*795d594fSAndroid Build Coastguard Worker return bitlength_ == 0; 63*795d594fSAndroid Build Coastguard Worker } 64*795d594fSAndroid Build Coastguard Worker StorageTypeBitStringChar65*795d594fSAndroid Build Coastguard Worker explicit operator StorageType() const { 66*795d594fSAndroid Build Coastguard Worker return data_; 67*795d594fSAndroid Build Coastguard Worker } 68*795d594fSAndroid Build Coastguard Worker 69*795d594fSAndroid Build Coastguard Worker bool operator==(StorageType storage) const { 70*795d594fSAndroid Build Coastguard Worker return data_ == storage; 71*795d594fSAndroid Build Coastguard Worker } 72*795d594fSAndroid Build Coastguard Worker 73*795d594fSAndroid Build Coastguard Worker bool operator!=(StorageType storage) const { 74*795d594fSAndroid Build Coastguard Worker return !(*this == storage); 75*795d594fSAndroid Build Coastguard Worker } 76*795d594fSAndroid Build Coastguard Worker 77*795d594fSAndroid Build Coastguard Worker // Compare equality against another BitStringChar. Note: bitlength is ignored. 78*795d594fSAndroid Build Coastguard Worker bool operator==(const BitStringChar& other) const { 79*795d594fSAndroid Build Coastguard Worker return data_ == other.data_; 80*795d594fSAndroid Build Coastguard Worker } 81*795d594fSAndroid Build Coastguard Worker 82*795d594fSAndroid Build Coastguard Worker // Compare non-equality against another BitStringChar. Note: bitlength is ignored. 83*795d594fSAndroid Build Coastguard Worker bool operator!=(const BitStringChar& other) const { 84*795d594fSAndroid Build Coastguard Worker return !(*this == other); 85*795d594fSAndroid Build Coastguard Worker } 86*795d594fSAndroid Build Coastguard Worker 87*795d594fSAndroid Build Coastguard Worker // Add a BitStringChar with an integer. The resulting BitStringChar's data must still fit within 88*795d594fSAndroid Build Coastguard Worker // this BitStringChar's bit length. 89*795d594fSAndroid Build Coastguard Worker BitStringChar operator+(StorageType storage) const { 90*795d594fSAndroid Build Coastguard Worker DCHECK_LE(storage, MaximumValue().data_ - data_) << "Addition would overflow " << *this; 91*795d594fSAndroid Build Coastguard Worker return BitStringChar(data_ + storage, bitlength_); 92*795d594fSAndroid Build Coastguard Worker } 93*795d594fSAndroid Build Coastguard Worker 94*795d594fSAndroid Build Coastguard Worker // Get the maximum representible value with the same bitlength. 95*795d594fSAndroid Build Coastguard Worker // (Useful to figure out the maximum value for this BitString position.) MaximumValueBitStringChar96*795d594fSAndroid Build Coastguard Worker BitStringChar MaximumValue() const { 97*795d594fSAndroid Build Coastguard Worker StorageType maximimum_data = MaxInt<StorageType>(bitlength_); 98*795d594fSAndroid Build Coastguard Worker return BitStringChar(maximimum_data, bitlength_); 99*795d594fSAndroid Build Coastguard Worker } 100*795d594fSAndroid Build Coastguard Worker 101*795d594fSAndroid Build Coastguard Worker private: 102*795d594fSAndroid Build Coastguard Worker StorageType data_; // Unused bits (outside of bitlength) are 0. 103*795d594fSAndroid Build Coastguard Worker size_t bitlength_; 104*795d594fSAndroid Build Coastguard Worker // Logically const. Physically non-const so operator= still works. 105*795d594fSAndroid Build Coastguard Worker }; 106*795d594fSAndroid Build Coastguard Worker 107*795d594fSAndroid Build Coastguard Worker // Print e.g. "BitStringChar<10>(123)" where 10=bitlength, 123=data. 108*795d594fSAndroid Build Coastguard Worker inline std::ostream& operator<<(std::ostream& os, const BitStringChar& bc) { 109*795d594fSAndroid Build Coastguard Worker os << "BitStringChar<" << bc.GetBitLength() << ">(" 110*795d594fSAndroid Build Coastguard Worker << static_cast<BitStringChar::StorageType>(bc) << ")"; 111*795d594fSAndroid Build Coastguard Worker return os; 112*795d594fSAndroid Build Coastguard Worker } 113*795d594fSAndroid Build Coastguard Worker 114*795d594fSAndroid Build Coastguard Worker /** 115*795d594fSAndroid Build Coastguard Worker * BitString 116*795d594fSAndroid Build Coastguard Worker * 117*795d594fSAndroid Build Coastguard Worker * MSB (most significant bit) LSB 118*795d594fSAndroid Build Coastguard Worker * +------------+-----+------------+------------+------------+ 119*795d594fSAndroid Build Coastguard Worker * | | | | | | 120*795d594fSAndroid Build Coastguard Worker * | CharN | ... | Char2 | Char1 | Char0 | 121*795d594fSAndroid Build Coastguard Worker * | | | | | | 122*795d594fSAndroid Build Coastguard Worker * +------------+-----+------------+------------+------------+ 123*795d594fSAndroid Build Coastguard Worker * <- len[N] -> ... <- len[2] -> <- len[1] -> <- len[0] -> 124*795d594fSAndroid Build Coastguard Worker * 125*795d594fSAndroid Build Coastguard Worker * Stores up to "N+1" characters in a subset of a machine word. Each character has a different 126*795d594fSAndroid Build Coastguard Worker * bitlength, as defined by len[pos]. This BitString can be nested inside of a BitStruct 127*795d594fSAndroid Build Coastguard Worker * (see e.g. SubtypeCheckBitsAndStatus). 128*795d594fSAndroid Build Coastguard Worker * 129*795d594fSAndroid Build Coastguard Worker * Definitions: 130*795d594fSAndroid Build Coastguard Worker * 131*795d594fSAndroid Build Coastguard Worker * "ABCDE...K" := [A,B,C,D,E, ... K] + [0]*(N-idx(K)) s.t. N >= K. 132*795d594fSAndroid Build Coastguard Worker * // Padded with trailing 0s to fit (N+1) bitstring chars. 133*795d594fSAndroid Build Coastguard Worker * MaxBitstringLen := N+1 134*795d594fSAndroid Build Coastguard Worker * StrLen(Bitstring) := I s.t. (I == 0 OR Char(I-1) != 0) 135*795d594fSAndroid Build Coastguard Worker * AND forall char in CharI..CharN : char == 0 136*795d594fSAndroid Build Coastguard Worker * // = Maximum length - the # of consecutive trailing zeroes. 137*795d594fSAndroid Build Coastguard Worker * Bitstring[N] := CharN 138*795d594fSAndroid Build Coastguard Worker * Bitstring[I..N) := [CharI, CharI+1, ... CharN-1] 139*795d594fSAndroid Build Coastguard Worker * 140*795d594fSAndroid Build Coastguard Worker * (These are used by the SubtypeCheckInfo definitions and invariants, see subtype_check_info.h) 141*795d594fSAndroid Build Coastguard Worker */ 142*795d594fSAndroid Build Coastguard Worker struct BitString { 143*795d594fSAndroid Build Coastguard Worker using StorageType = BitStringChar::StorageType; 144*795d594fSAndroid Build Coastguard Worker 145*795d594fSAndroid Build Coastguard Worker // As this is meant to be used only with "SubtypeCheckInfo", 146*795d594fSAndroid Build Coastguard Worker // the bitlengths and the maximum string length is tuned by maximizing the coverage of "Assigned" 147*795d594fSAndroid Build Coastguard Worker // bitstrings for instance-of and check-cast targets during Optimizing compilation. 148*795d594fSAndroid Build Coastguard Worker static constexpr size_t kBitSizeAtPosition[] = {12, 4, 11}; // len[] from header docs. 149*795d594fSAndroid Build Coastguard Worker static constexpr size_t kCapacity = arraysize(kBitSizeAtPosition); // MaxBitstringLen above. 150*795d594fSAndroid Build Coastguard Worker 151*795d594fSAndroid Build Coastguard Worker // How many bits are needed to represent BitString[0..position)? GetBitLengthTotalAtPositionBitString152*795d594fSAndroid Build Coastguard Worker static constexpr size_t GetBitLengthTotalAtPosition(size_t position) { 153*795d594fSAndroid Build Coastguard Worker size_t idx = 0; 154*795d594fSAndroid Build Coastguard Worker size_t sum = 0; 155*795d594fSAndroid Build Coastguard Worker while (idx < position && idx < kCapacity) { 156*795d594fSAndroid Build Coastguard Worker sum += kBitSizeAtPosition[idx]; 157*795d594fSAndroid Build Coastguard Worker ++idx; 158*795d594fSAndroid Build Coastguard Worker } 159*795d594fSAndroid Build Coastguard Worker // TODO: precompute with CreateArray helper. 160*795d594fSAndroid Build Coastguard Worker 161*795d594fSAndroid Build Coastguard Worker return sum; 162*795d594fSAndroid Build Coastguard Worker } 163*795d594fSAndroid Build Coastguard Worker 164*795d594fSAndroid Build Coastguard Worker // What is the least-significant-bit for a position? 165*795d594fSAndroid Build Coastguard Worker // (e.g. to use with BitField{Insert,Extract,Clear}.) GetLsbForPositionBitString166*795d594fSAndroid Build Coastguard Worker static constexpr size_t GetLsbForPosition(size_t position) { 167*795d594fSAndroid Build Coastguard Worker DCHECK_GE(kCapacity, position); 168*795d594fSAndroid Build Coastguard Worker return GetBitLengthTotalAtPosition(position); 169*795d594fSAndroid Build Coastguard Worker } 170*795d594fSAndroid Build Coastguard Worker 171*795d594fSAndroid Build Coastguard Worker // How many bits are needed for a BitStringChar at the position? 172*795d594fSAndroid Build Coastguard Worker // Returns 0 if the position is out of range. MaybeGetBitLengthAtPositionBitString173*795d594fSAndroid Build Coastguard Worker static constexpr size_t MaybeGetBitLengthAtPosition(size_t position) { 174*795d594fSAndroid Build Coastguard Worker if (position >= kCapacity) { 175*795d594fSAndroid Build Coastguard Worker return 0; 176*795d594fSAndroid Build Coastguard Worker } 177*795d594fSAndroid Build Coastguard Worker return kBitSizeAtPosition[position]; 178*795d594fSAndroid Build Coastguard Worker } 179*795d594fSAndroid Build Coastguard Worker 180*795d594fSAndroid Build Coastguard Worker // Read a bitchar at some index within the capacity. 181*795d594fSAndroid Build Coastguard Worker // See also "BitString[N]" in the doc header. 182*795d594fSAndroid Build Coastguard Worker BitStringChar operator[](size_t idx) const { 183*795d594fSAndroid Build Coastguard Worker DCHECK_LT(idx, kCapacity); 184*795d594fSAndroid Build Coastguard Worker 185*795d594fSAndroid Build Coastguard Worker StorageType data = BitFieldExtract(storage_, GetLsbForPosition(idx), kBitSizeAtPosition[idx]); 186*795d594fSAndroid Build Coastguard Worker 187*795d594fSAndroid Build Coastguard Worker return BitStringChar(data, kBitSizeAtPosition[idx]); 188*795d594fSAndroid Build Coastguard Worker } 189*795d594fSAndroid Build Coastguard Worker 190*795d594fSAndroid Build Coastguard Worker // Overwrite a bitchar at a position with a new one. 191*795d594fSAndroid Build Coastguard Worker // 192*795d594fSAndroid Build Coastguard Worker // The `bitchar` bitlength must be no more than the maximum bitlength for that position. SetAtBitString193*795d594fSAndroid Build Coastguard Worker void SetAt(size_t idx, BitStringChar bitchar) { 194*795d594fSAndroid Build Coastguard Worker DCHECK_LT(idx, kCapacity); 195*795d594fSAndroid Build Coastguard Worker DCHECK_LE(bitchar.GetBitLength(), kBitSizeAtPosition[idx]); 196*795d594fSAndroid Build Coastguard Worker 197*795d594fSAndroid Build Coastguard Worker // Read the bitchar: Bits > bitlength in bitchar are defined to be 0. 198*795d594fSAndroid Build Coastguard Worker storage_ = BitFieldInsert(storage_, 199*795d594fSAndroid Build Coastguard Worker static_cast<StorageType>(bitchar), 200*795d594fSAndroid Build Coastguard Worker GetLsbForPosition(idx), 201*795d594fSAndroid Build Coastguard Worker kBitSizeAtPosition[idx]); 202*795d594fSAndroid Build Coastguard Worker } 203*795d594fSAndroid Build Coastguard Worker 204*795d594fSAndroid Build Coastguard Worker // How many characters are there in this bitstring? 205*795d594fSAndroid Build Coastguard Worker // Trailing 0s are ignored, but 0s in-between are counted. 206*795d594fSAndroid Build Coastguard Worker // See also "StrLen(BitString)" in the doc header. LengthBitString207*795d594fSAndroid Build Coastguard Worker size_t Length() const { 208*795d594fSAndroid Build Coastguard Worker size_t num_trailing_zeros = 0; 209*795d594fSAndroid Build Coastguard Worker size_t i; 210*795d594fSAndroid Build Coastguard Worker for (i = kCapacity - 1u; ; --i) { 211*795d594fSAndroid Build Coastguard Worker BitStringChar bc = (*this)[i]; 212*795d594fSAndroid Build Coastguard Worker if (bc != 0u) { 213*795d594fSAndroid Build Coastguard Worker break; // Found first trailing non-zero. 214*795d594fSAndroid Build Coastguard Worker } 215*795d594fSAndroid Build Coastguard Worker 216*795d594fSAndroid Build Coastguard Worker ++num_trailing_zeros; 217*795d594fSAndroid Build Coastguard Worker if (i == 0u) { 218*795d594fSAndroid Build Coastguard Worker break; // No more bitchars remaining: don't underflow. 219*795d594fSAndroid Build Coastguard Worker } 220*795d594fSAndroid Build Coastguard Worker } 221*795d594fSAndroid Build Coastguard Worker 222*795d594fSAndroid Build Coastguard Worker return kCapacity - num_trailing_zeros; 223*795d594fSAndroid Build Coastguard Worker } 224*795d594fSAndroid Build Coastguard Worker 225*795d594fSAndroid Build Coastguard Worker // Cast to the underlying integral storage type. StorageTypeBitString226*795d594fSAndroid Build Coastguard Worker explicit operator StorageType() const { 227*795d594fSAndroid Build Coastguard Worker return storage_; 228*795d594fSAndroid Build Coastguard Worker } 229*795d594fSAndroid Build Coastguard Worker 230*795d594fSAndroid Build Coastguard Worker // Get the # of bits this would use if it was nested inside of a BitStruct. BitStructSizeOfBitString231*795d594fSAndroid Build Coastguard Worker static constexpr size_t BitStructSizeOf() { 232*795d594fSAndroid Build Coastguard Worker return GetBitLengthTotalAtPosition(kCapacity); 233*795d594fSAndroid Build Coastguard Worker } 234*795d594fSAndroid Build Coastguard Worker 235*795d594fSAndroid Build Coastguard Worker BitString() = default; 236*795d594fSAndroid Build Coastguard Worker 237*795d594fSAndroid Build Coastguard Worker // Efficient O(1) comparison: Equal if both bitstring words are the same. 238*795d594fSAndroid Build Coastguard Worker bool operator==(const BitString& other) const { 239*795d594fSAndroid Build Coastguard Worker return storage_ == other.storage_; 240*795d594fSAndroid Build Coastguard Worker } 241*795d594fSAndroid Build Coastguard Worker 242*795d594fSAndroid Build Coastguard Worker // Efficient O(1) negative comparison: Not-equal if both bitstring words are different. 243*795d594fSAndroid Build Coastguard Worker bool operator!=(const BitString& other) const { 244*795d594fSAndroid Build Coastguard Worker return !(*this == other); 245*795d594fSAndroid Build Coastguard Worker } 246*795d594fSAndroid Build Coastguard Worker 247*795d594fSAndroid Build Coastguard Worker // Does this bitstring contain exactly 0 characters? IsEmptyBitString248*795d594fSAndroid Build Coastguard Worker bool IsEmpty() const { 249*795d594fSAndroid Build Coastguard Worker return (*this) == BitString{}; 250*795d594fSAndroid Build Coastguard Worker } 251*795d594fSAndroid Build Coastguard Worker 252*795d594fSAndroid Build Coastguard Worker // Remove all BitStringChars starting at end. 253*795d594fSAndroid Build Coastguard Worker // Returns the BitString[0..end) substring as a copy. 254*795d594fSAndroid Build Coastguard Worker // See also "BitString[I..N)" in the doc header. TruncateBitString255*795d594fSAndroid Build Coastguard Worker BitString Truncate(size_t end) { 256*795d594fSAndroid Build Coastguard Worker DCHECK_GE(kCapacity, end); 257*795d594fSAndroid Build Coastguard Worker BitString copy = *this; 258*795d594fSAndroid Build Coastguard Worker 259*795d594fSAndroid Build Coastguard Worker if (end < kCapacity) { 260*795d594fSAndroid Build Coastguard Worker size_t lsb = GetLsbForPosition(end); 261*795d594fSAndroid Build Coastguard Worker size_t bit_size = GetLsbForPosition(kCapacity) - lsb; 262*795d594fSAndroid Build Coastguard Worker StorageType data = BitFieldClear(copy.storage_, lsb, bit_size); 263*795d594fSAndroid Build Coastguard Worker copy.storage_ = data; 264*795d594fSAndroid Build Coastguard Worker } 265*795d594fSAndroid Build Coastguard Worker 266*795d594fSAndroid Build Coastguard Worker return copy; 267*795d594fSAndroid Build Coastguard Worker } 268*795d594fSAndroid Build Coastguard Worker 269*795d594fSAndroid Build Coastguard Worker private: 270*795d594fSAndroid Build Coastguard Worker friend std::ostream& operator<<(std::ostream& os, const BitString& bit_string); 271*795d594fSAndroid Build Coastguard Worker 272*795d594fSAndroid Build Coastguard Worker // Data is stored with the first character in the least-significant-bit. 273*795d594fSAndroid Build Coastguard Worker // Unused bits are zero. 274*795d594fSAndroid Build Coastguard Worker StorageType storage_; 275*795d594fSAndroid Build Coastguard Worker }; 276*795d594fSAndroid Build Coastguard Worker 277*795d594fSAndroid Build Coastguard Worker static_assert(BitSizeOf<BitString::StorageType>() >= 278*795d594fSAndroid Build Coastguard Worker BitString::GetBitLengthTotalAtPosition(BitString::kCapacity), 279*795d594fSAndroid Build Coastguard Worker "Storage type is too small for the # of bits requested"); 280*795d594fSAndroid Build Coastguard Worker 281*795d594fSAndroid Build Coastguard Worker // Print e.g. "BitString[1,0,3]". Trailing 0s are dropped. 282*795d594fSAndroid Build Coastguard Worker inline std::ostream& operator<<(std::ostream& os, const BitString& bit_string) { 283*795d594fSAndroid Build Coastguard Worker const size_t length = bit_string.Length(); 284*795d594fSAndroid Build Coastguard Worker 285*795d594fSAndroid Build Coastguard Worker os << "BitString["; 286*795d594fSAndroid Build Coastguard Worker for (size_t i = 0; i < length; ++i) { 287*795d594fSAndroid Build Coastguard Worker BitStringChar bc = bit_string[i]; 288*795d594fSAndroid Build Coastguard Worker if (i != 0) { 289*795d594fSAndroid Build Coastguard Worker os << ","; 290*795d594fSAndroid Build Coastguard Worker } 291*795d594fSAndroid Build Coastguard Worker os << static_cast<BitString::StorageType>(bc); 292*795d594fSAndroid Build Coastguard Worker } 293*795d594fSAndroid Build Coastguard Worker os << "]"; 294*795d594fSAndroid Build Coastguard Worker return os; 295*795d594fSAndroid Build Coastguard Worker } 296*795d594fSAndroid Build Coastguard Worker 297*795d594fSAndroid Build Coastguard Worker } // namespace art 298*795d594fSAndroid Build Coastguard Worker 299*795d594fSAndroid Build Coastguard Worker #endif // ART_LIBARTBASE_BASE_BIT_STRING_H_ 300