/* ============================================================================== This file is part of the JUCE library - "Jules' Utility Class Extensions" Copyright 2004-9 by Raw Material Software Ltd. ------------------------------------------------------------------------------ JUCE can be redistributed and/or modified under the terms of the GNU General Public License (Version 2), as published by the Free Software Foundation. A copy of the license is included in the JUCE distribution, or can be found online at www.gnu.org/licenses. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. ------------------------------------------------------------------------------ To release a closed-source product which uses JUCE, commercial licenses are available: visit www.rawmaterialsoftware.com/juce for more information. ============================================================================== */ #include "../core/juce_StandardHeader.h" BEGIN_JUCE_NAMESPACE #include "juce_BitArray.h" #include "juce_MemoryBlock.h" #include "../core/juce_Random.h" //============================================================================== BitArray::BitArray() throw() : numValues (4), highestBit (-1), negative (false) { values.calloc (numValues + 1); } BitArray::BitArray (const int value) throw() : numValues (4), highestBit (31), negative (value < 0) { values.calloc (numValues + 1); values[0] = abs (value); highestBit = getHighestBit(); } BitArray::BitArray (int64 value) throw() : numValues (4), highestBit (63), negative (value < 0) { values.calloc (numValues + 1); if (value < 0) value = -value; values[0] = (unsigned int) value; values[1] = (unsigned int) (value >> 32); highestBit = getHighestBit(); } BitArray::BitArray (const unsigned int value) throw() : numValues (4), highestBit (31), negative (false) { values.calloc (numValues + 1); values[0] = value; highestBit = getHighestBit(); } BitArray::BitArray (const BitArray& other) throw() : numValues (jmax (4, (other.highestBit >> 5) + 1)), highestBit (other.getHighestBit()), negative (other.negative) { values.malloc (numValues + 1); memcpy (values, other.values, sizeof (unsigned int) * (numValues + 1)); } BitArray::~BitArray() throw() { } BitArray& BitArray::operator= (const BitArray& other) throw() { if (this != &other) { highestBit = other.getHighestBit(); numValues = jmax (4, (highestBit >> 5) + 1); negative = other.negative; values.malloc (numValues + 1); memcpy (values, other.values, sizeof (unsigned int) * (numValues + 1)); } return *this; } // result == 0 = the same // result < 0 = this number is smaller // result > 0 = this number is bigger int BitArray::compare (const BitArray& other) const throw() { if (isNegative() == other.isNegative()) { const int absComp = compareAbsolute (other); return isNegative() ? -absComp : absComp; } else { return isNegative() ? -1 : 1; } } int BitArray::compareAbsolute (const BitArray& other) const throw() { const int h1 = getHighestBit(); const int h2 = other.getHighestBit(); if (h1 > h2) return 1; else if (h1 < h2) return -1; for (int i = (h1 >> 5) + 1; --i >= 0;) if (values[i] != other.values[i]) return (values[i] > other.values[i]) ? 1 : -1; return 0; } bool BitArray::operator== (const BitArray& other) const throw() { return compare (other) == 0; } bool BitArray::operator!= (const BitArray& other) const throw() { return compare (other) != 0; } bool BitArray::operator[] (const int bit) const throw() { return bit >= 0 && bit <= highestBit && ((values [bit >> 5] & (1 << (bit & 31))) != 0); } bool BitArray::isEmpty() const throw() { return getHighestBit() < 0; } void BitArray::clear() throw() { if (numValues > 16) { numValues = 4; values.calloc (numValues + 1); } else { zeromem (values, sizeof (unsigned int) * (numValues + 1)); } highestBit = -1; negative = false; } void BitArray::setBit (const int bit) throw() { if (bit >= 0) { if (bit > highestBit) { ensureSize (bit >> 5); highestBit = bit; } values [bit >> 5] |= (1 << (bit & 31)); } } void BitArray::setBit (const int bit, const bool shouldBeSet) throw() { if (shouldBeSet) setBit (bit); else clearBit (bit); } void BitArray::clearBit (const int bit) throw() { if (bit >= 0 && bit <= highestBit) values [bit >> 5] &= ~(1 << (bit & 31)); } void BitArray::setRange (int startBit, int numBits, const bool shouldBeSet) throw() { while (--numBits >= 0) setBit (startBit++, shouldBeSet); } void BitArray::insertBit (const int bit, const bool shouldBeSet) throw() { if (bit >= 0) shiftBits (1, bit); setBit (bit, shouldBeSet); } //============================================================================== void BitArray::andWith (const BitArray& other) throw() { // this operation will only work with the absolute values jassert (isNegative() == other.isNegative()); int n = numValues; while (n > other.numValues) values[--n] = 0; while (--n >= 0) values[n] &= other.values[n]; if (other.highestBit < highestBit) highestBit = other.highestBit; highestBit = getHighestBit(); } void BitArray::orWith (const BitArray& other) throw() { if (other.highestBit < 0) return; // this operation will only work with the absolute values jassert (isNegative() == other.isNegative()); ensureSize (other.highestBit >> 5); int n = (other.highestBit >> 5) + 1; while (--n >= 0) values[n] |= other.values[n]; if (other.highestBit > highestBit) highestBit = other.highestBit; highestBit = getHighestBit(); } void BitArray::xorWith (const BitArray& other) throw() { if (other.highestBit < 0) return; // this operation will only work with the absolute values jassert (isNegative() == other.isNegative()); ensureSize (other.highestBit >> 5); int n = (other.highestBit >> 5) + 1; while (--n >= 0) values[n] ^= other.values[n]; if (other.highestBit > highestBit) highestBit = other.highestBit; highestBit = getHighestBit(); } //============================================================================== void BitArray::add (const BitArray& other) throw() { if (other.isNegative()) { BitArray o (other); o.negate(); subtract (o); return; } if (isNegative()) { if (compareAbsolute (other) < 0) { BitArray temp (*this); temp.negate(); *this = other; subtract (temp); } else { negate(); subtract (other); negate(); } return; } if (other.highestBit > highestBit) highestBit = other.highestBit; ++highestBit; const int numInts = (highestBit >> 5) + 1; ensureSize (numInts); int64 remainder = 0; for (int i = 0; i <= numInts; ++i) { if (i < numValues) remainder += values[i]; if (i < other.numValues) remainder += other.values[i]; values[i] = (unsigned int) remainder; remainder >>= 32; } jassert (remainder == 0); highestBit = getHighestBit(); } void BitArray::subtract (const BitArray& other) throw() { if (other.isNegative()) { BitArray o (other); o.negate(); add (o); return; } if (! isNegative()) { if (compareAbsolute (other) < 0) { BitArray temp (*this); *this = other; subtract (temp); negate(); return; } } else { negate(); add (other); negate(); return; } const int numInts = (highestBit >> 5) + 1; const int maxOtherInts = (other.highestBit >> 5) + 1; int64 amountToSubtract = 0; for (int i = 0; i <= numInts; ++i) { if (i <= maxOtherInts) amountToSubtract += (int64)other.values[i]; if (values[i] >= amountToSubtract) { values[i] = (unsigned int) (values[i] - amountToSubtract); amountToSubtract = 0; } else { const int64 n = ((int64) values[i] + (((int64) 1) << 32)) - amountToSubtract; values[i] = (unsigned int) n; amountToSubtract = 1; } } } void BitArray::multiplyBy (const BitArray& other) throw() { BitArray total; highestBit = getHighestBit(); const bool wasNegative = isNegative(); setNegative (false); for (int i = 0; i <= highestBit; ++i) { if (operator[](i)) { BitArray n (other); n.setNegative (false); n.shiftBits (i); total.add (n); } } *this = total; negative = wasNegative ^ other.isNegative(); } void BitArray::divideBy (const BitArray& divisor, BitArray& remainder) throw() { jassert (this != &remainder); // (can't handle passing itself in to get the remainder) const int divHB = divisor.getHighestBit(); const int ourHB = getHighestBit(); if (divHB < 0 || ourHB < 0) { // division by zero remainder.clear(); clear(); } else { remainder = *this; remainder.setNegative (false); const bool wasNegative = isNegative(); clear(); BitArray temp (divisor); temp.setNegative (false); int leftShift = ourHB - divHB; temp.shiftBits (leftShift); while (leftShift >= 0) { if (remainder.compareAbsolute (temp) >= 0) { remainder.subtract (temp); setBit (leftShift); } if (--leftShift >= 0) temp.shiftBits (-1); } negative = wasNegative ^ divisor.isNegative(); remainder.setNegative (wasNegative); } } void BitArray::modulo (const BitArray& divisor) throw() { BitArray remainder; divideBy (divisor, remainder); *this = remainder; } static const BitArray simpleGCD (BitArray* m, BitArray* n) throw() { while (! m->isEmpty()) { if (n->compareAbsolute (*m) > 0) swapVariables (m, n); m->subtract (*n); } return *n; } const BitArray BitArray::findGreatestCommonDivisor (BitArray n) const throw() { BitArray m (*this); while (! n.isEmpty()) { if (abs (m.getHighestBit() - n.getHighestBit()) <= 16) return simpleGCD (&m, &n); BitArray temp1 (m), temp2; temp1.divideBy (n, temp2); m = n; n = temp2; } return m; } void BitArray::exponentModulo (const BitArray& exponent, const BitArray& modulus) throw() { BitArray exp (exponent); exp.modulo (modulus); BitArray value (*this); value.modulo (modulus); clear(); setBit (0); while (! exp.isEmpty()) { if (exp [0]) { multiplyBy (value); this->modulo (modulus); } value.multiplyBy (value); value.modulo (modulus); exp.shiftBits (-1); } } void BitArray::inverseModulo (const BitArray& modulus) throw() { const BitArray one (1); if (modulus == one || modulus.isNegative()) { clear(); return; } if (isNegative() || compareAbsolute (modulus) >= 0) this->modulo (modulus); if (*this == one) return; if (! (*this)[0]) { // not invertible clear(); return; } BitArray a1 (modulus); BitArray a2 (*this); BitArray b1 (modulus); BitArray b2 (1); while (a2 != one) { BitArray temp1, temp2, multiplier (a1); multiplier.divideBy (a2, temp1); temp1 = a2; temp1.multiplyBy (multiplier); temp2 = a1; temp2.subtract (temp1); a1 = a2; a2 = temp2; temp1 = b2; temp1.multiplyBy (multiplier); temp2 = b1; temp2.subtract (temp1); b1 = b2; b2 = temp2; } while (b2.isNegative()) b2.add (modulus); b2.modulo (modulus); *this = b2; } //============================================================================== void BitArray::shiftBits (int bits, const int startBit) throw() { if (highestBit < 0) return; if (startBit > 0) { if (bits < 0) { // right shift for (int i = startBit; i <= highestBit; ++i) setBit (i, operator[] (i - bits)); highestBit = getHighestBit(); } else if (bits > 0) { // left shift for (int i = highestBit + 1; --i >= startBit;) setBit (i + bits, operator[] (i)); while (--bits >= 0) clearBit (bits + startBit); } } else { if (bits < 0) { // right shift bits = -bits; if (bits > highestBit) { clear(); } else { const int wordsToMove = bits >> 5; int top = 1 + (highestBit >> 5) - wordsToMove; highestBit -= bits; if (wordsToMove > 0) { int i; for (i = 0; i < top; ++i) values [i] = values [i + wordsToMove]; for (i = 0; i < wordsToMove; ++i) values [top + i] = 0; bits &= 31; } if (bits != 0) { const int invBits = 32 - bits; --top; for (int i = 0; i < top; ++i) values[i] = (values[i] >> bits) | (values [i + 1] << invBits); values[top] = (values[top] >> bits); } highestBit = getHighestBit(); } } else if (bits > 0) { // left shift ensureSize (((highestBit + bits) >> 5) + 1); const int wordsToMove = bits >> 5; int top = 1 + (highestBit >> 5); highestBit += bits; if (wordsToMove > 0) { int i; for (i = top; --i >= 0;) values [i + wordsToMove] = values [i]; for (i = 0; i < wordsToMove; ++i) values [i] = 0; bits &= 31; } if (bits != 0) { const int invBits = 32 - bits; for (int i = top + 1 + wordsToMove; --i > wordsToMove;) values[i] = (values[i] << bits) | (values [i - 1] >> invBits); values [wordsToMove] = values [wordsToMove] << bits; } highestBit = getHighestBit(); } } } const BitArray BitArray::getBitRange (int startBit, int numBits) const throw() { BitArray r; numBits = jmin (numBits, getHighestBit() + 1 - startBit); r.ensureSize (numBits >> 5); r.highestBit = numBits; int i = 0; while (numBits > 0) { r.values[i++] = getBitRangeAsInt (startBit, jmin (32, numBits)); numBits -= 32; startBit += 32; } r.highestBit = r.getHighestBit(); return r; } int BitArray::getBitRangeAsInt (const int startBit, int numBits) const throw() { if (numBits > 32) { jassertfalse // use getBitRange() if you need more than 32 bits.. numBits = 32; } numBits = jmin (numBits, highestBit + 1 - startBit); if (numBits <= 0) return 0; const int pos = startBit >> 5; const int offset = startBit & 31; const int endSpace = 32 - numBits; uint32 n = ((uint32) values [pos]) >> offset; if (offset > endSpace) n |= ((uint32) values [pos + 1]) << (32 - offset); return (int) (n & (((uint32) 0xffffffff) >> endSpace)); } void BitArray::setBitRangeAsInt (const int startBit, int numBits, unsigned int valueToSet) throw() { if (numBits > 32) { jassertfalse numBits = 32; } for (int i = 0; i < numBits; ++i) { setBit (startBit + i, (valueToSet & 1) != 0); valueToSet >>= 1; } } //============================================================================== bool BitArray::isNegative() const throw() { return negative && ! isEmpty(); } void BitArray::setNegative (const bool neg) throw() { negative = neg; } void BitArray::negate() throw() { negative = (! negative) && ! isEmpty(); } int BitArray::countNumberOfSetBits() const throw() { int total = 0; for (int i = (highestBit >> 5) + 1; --i >= 0;) { unsigned int n = values[i]; if (n == 0xffffffff) { total += 32; } else { while (n != 0) { total += (n & 1); n >>= 1; } } } return total; } int BitArray::getHighestBit() const throw() { for (int i = highestBit + 1; --i >= 0;) if ((values [i >> 5] & (1 << (i & 31))) != 0) return i; return -1; } int BitArray::findNextSetBit (int i) const throw() { for (; i <= highestBit; ++i) if ((values [i >> 5] & (1 << (i & 31))) != 0) return i; return -1; } int BitArray::findNextClearBit (int i) const throw() { for (; i <= highestBit; ++i) if ((values [i >> 5] & (1 << (i & 31))) == 0) break; return i; } void BitArray::ensureSize (const int numVals) throw() { if (numVals + 2 >= numValues) { int oldSize = numValues; numValues = ((numVals + 2) * 3) / 2; values.realloc (numValues + 1); while (oldSize < numValues) values [oldSize++] = 0; } } //============================================================================== const String BitArray::toString (const int base, const int minimumNumCharacters) const throw() { String s; BitArray v (*this); if (base == 2 || base == 8 || base == 16) { const int bits = (base == 2) ? 1 : (base == 8 ? 3 : 4); static const tchar* const hexDigits = T("0123456789abcdef"); for (;;) { const int remainder = v.getBitRangeAsInt (0, bits); v.shiftBits (-bits); if (remainder == 0 && v.isEmpty()) break; s = String::charToString (hexDigits [remainder]) + s; } } else if (base == 10) { const BitArray ten (10); BitArray remainder; for (;;) { v.divideBy (ten, remainder); if (remainder.isEmpty() && v.isEmpty()) break; s = String (remainder.getBitRangeAsInt (0, 8)) + s; } } else { jassertfalse // can't do the specified base return String::empty; } const int length = s.length(); if (length < minimumNumCharacters) s = String::repeatedString (T("0"), minimumNumCharacters - length) + s; return isNegative() ? T("-") + s : s; } void BitArray::parseString (const String& text, const int base) throw() { clear(); const tchar* t = (const tchar*) text; if (base == 2 || base == 8 || base == 16) { const int bits = (base == 2) ? 1 : (base == 8 ? 3 : 4); for (;;) { const tchar c = *t++; const int digit = CharacterFunctions::getHexDigitValue (c); if (((unsigned int) digit) < (unsigned int) base) { shiftBits (bits); add (digit); } else if (c == 0) { break; } } } else if (base == 10) { const BitArray ten ((unsigned int) 10); for (;;) { const tchar c = *t++; if (c >= T('0') && c <= T('9')) { multiplyBy (ten); add ((int) (c - T('0'))); } else if (c == 0) { break; } } } setNegative (text.trimStart().startsWithChar (T('-'))); } const MemoryBlock BitArray::toMemoryBlock() const throw() { const int numBytes = (getHighestBit() + 8) >> 3; MemoryBlock mb ((size_t) numBytes); for (int i = 0; i < numBytes; ++i) mb[i] = (uint8) getBitRangeAsInt (i << 3, 8); return mb; } void BitArray::loadFromMemoryBlock (const MemoryBlock& data) throw() { clear(); for (size_t i = data.getSize(); --i >= 0;) this->setBitRangeAsInt ((int) (i << 3), 8, data [i]); } END_JUCE_NAMESPACE