1 /* 2 * Copyright (C) 2011 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #ifndef BitVector_h 27 #define BitVector_h 28 29 #include "wtf/Assertions.h" 30 #include "wtf/StdLibExtras.h" 31 #include "wtf/WTFExport.h" 32 33 namespace WTF { 34 35 class PrintStream; 36 37 // This is a space-efficient, resizeable bitvector class. In the common case it 38 // occupies one word, but if necessary, it will inflate this one word to point 39 // to a single chunk of out-of-line allocated storage to store an arbitrary number 40 // of bits. 41 // 42 // - The bitvector remembers the bound of how many bits can be stored, but this 43 // may be slightly greater (by as much as some platform-specific constant) 44 // than the last argument passed to ensureSize(). 45 // 46 // - The bitvector can resize itself automatically (set, clear, get) or can be used 47 // in a manual mode, which is faster (quickSet, quickClear, quickGet, ensureSize). 48 // 49 // - Accesses ASSERT that you are within bounds. 50 // 51 // - Bits are automatically initialized to zero. 52 // 53 // On the other hand, this BitVector class may not be the fastest around, since 54 // it does conditionals on every get/set/clear. But it is great if you need to 55 // juggle a lot of variable-length BitVectors and you're worried about wasting 56 // space. 57 58 class WTF_EXPORT BitVector { 59 public: BitVector()60 BitVector() 61 : m_bitsOrPointer(makeInlineBits(0)) 62 { 63 } 64 BitVector(size_t numBits)65 explicit BitVector(size_t numBits) 66 : m_bitsOrPointer(makeInlineBits(0)) 67 { 68 ensureSize(numBits); 69 } 70 BitVector(const BitVector & other)71 BitVector(const BitVector& other) 72 : m_bitsOrPointer(makeInlineBits(0)) 73 { 74 (*this) = other; 75 } 76 77 ~BitVector()78 ~BitVector() 79 { 80 if (isInline()) 81 return; 82 OutOfLineBits::destroy(outOfLineBits()); 83 } 84 85 BitVector& operator=(const BitVector& other) 86 { 87 if (isInline() && other.isInline()) 88 m_bitsOrPointer = other.m_bitsOrPointer; 89 else 90 setSlow(other); 91 return *this; 92 } 93 size()94 size_t size() const 95 { 96 if (isInline()) 97 return maxInlineBits(); 98 return outOfLineBits()->numBits(); 99 } 100 ensureSize(size_t numBits)101 void ensureSize(size_t numBits) 102 { 103 if (numBits <= size()) 104 return; 105 resizeOutOfLine(numBits); 106 } 107 108 // Like ensureSize(), but supports reducing the size of the bitvector. 109 void resize(size_t numBits); 110 111 void clearAll(); 112 quickGet(size_t bit)113 bool quickGet(size_t bit) const 114 { 115 ASSERT_WITH_SECURITY_IMPLICATION(bit < size()); 116 return !!(bits()[bit / bitsInPointer()] & (static_cast<uintptr_t>(1) << (bit & (bitsInPointer() - 1)))); 117 } 118 quickSet(size_t bit)119 void quickSet(size_t bit) 120 { 121 ASSERT_WITH_SECURITY_IMPLICATION(bit < size()); 122 bits()[bit / bitsInPointer()] |= (static_cast<uintptr_t>(1) << (bit & (bitsInPointer() - 1))); 123 } 124 quickClear(size_t bit)125 void quickClear(size_t bit) 126 { 127 ASSERT_WITH_SECURITY_IMPLICATION(bit < size()); 128 bits()[bit / bitsInPointer()] &= ~(static_cast<uintptr_t>(1) << (bit & (bitsInPointer() - 1))); 129 } 130 quickSet(size_t bit,bool value)131 void quickSet(size_t bit, bool value) 132 { 133 if (value) 134 quickSet(bit); 135 else 136 quickClear(bit); 137 } 138 get(size_t bit)139 bool get(size_t bit) const 140 { 141 if (bit >= size()) 142 return false; 143 return quickGet(bit); 144 } 145 set(size_t bit)146 void set(size_t bit) 147 { 148 ensureSize(bit + 1); 149 quickSet(bit); 150 } 151 ensureSizeAndSet(size_t bit,size_t size)152 void ensureSizeAndSet(size_t bit, size_t size) 153 { 154 ensureSize(size); 155 quickSet(bit); 156 } 157 clear(size_t bit)158 void clear(size_t bit) 159 { 160 if (bit >= size()) 161 return; 162 quickClear(bit); 163 } 164 set(size_t bit,bool value)165 void set(size_t bit, bool value) 166 { 167 if (value) 168 set(bit); 169 else 170 clear(bit); 171 } 172 173 void dump(PrintStream& out); 174 175 private: bitsInPointer()176 static unsigned bitsInPointer() 177 { 178 return sizeof(void*) << 3; 179 } 180 maxInlineBits()181 static unsigned maxInlineBits() 182 { 183 return bitsInPointer() - 1; 184 } 185 byteCount(size_t bitCount)186 static size_t byteCount(size_t bitCount) 187 { 188 return (bitCount + 7) >> 3; 189 } 190 makeInlineBits(uintptr_t bits)191 static uintptr_t makeInlineBits(uintptr_t bits) 192 { 193 ASSERT(!(bits & (static_cast<uintptr_t>(1) << maxInlineBits()))); 194 return bits | (static_cast<uintptr_t>(1) << maxInlineBits()); 195 } 196 197 class OutOfLineBits { 198 public: numBits()199 size_t numBits() const { return m_numBits; } numWords()200 size_t numWords() const { return (m_numBits + bitsInPointer() - 1) / bitsInPointer(); } bits()201 uintptr_t* bits() { return bitwise_cast<uintptr_t*>(this + 1); } bits()202 const uintptr_t* bits() const { return bitwise_cast<const uintptr_t*>(this + 1); } 203 204 static OutOfLineBits* create(size_t numBits); 205 206 static void destroy(OutOfLineBits*); 207 208 private: OutOfLineBits(size_t numBits)209 OutOfLineBits(size_t numBits) 210 : m_numBits(numBits) 211 { 212 } 213 214 size_t m_numBits; 215 }; 216 isInline()217 bool isInline() const { return m_bitsOrPointer >> maxInlineBits(); } 218 outOfLineBits()219 const OutOfLineBits* outOfLineBits() const { return bitwise_cast<const OutOfLineBits*>(m_bitsOrPointer << 1); } outOfLineBits()220 OutOfLineBits* outOfLineBits() { return bitwise_cast<OutOfLineBits*>(m_bitsOrPointer << 1); } 221 222 void resizeOutOfLine(size_t numBits); 223 void setSlow(const BitVector& other); 224 bits()225 uintptr_t* bits() 226 { 227 if (isInline()) 228 return &m_bitsOrPointer; 229 return outOfLineBits()->bits(); 230 } 231 bits()232 const uintptr_t* bits() const 233 { 234 if (isInline()) 235 return &m_bitsOrPointer; 236 return outOfLineBits()->bits(); 237 } 238 239 uintptr_t m_bitsOrPointer; 240 }; 241 242 } // namespace WTF 243 244 using WTF::BitVector; 245 246 #endif // BitVector_h 247