175 lines
5.0 KiB
C++
175 lines
5.0 KiB
C++
|
/**********
|
||
|
This library is free software; you can redistribute it and/or modify it under
|
||
|
the terms of the GNU Lesser General Public License as published by the
|
||
|
Free Software Foundation; either version 2.1 of the License, or (at your
|
||
|
option) any later version. (See <http://www.gnu.org/copyleft/lesser.html>.)
|
||
|
|
||
|
This library 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 Lesser General Public License for
|
||
|
more details.
|
||
|
|
||
|
You should have received a copy of the GNU Lesser General Public License
|
||
|
along with this library; if not, write to the Free Software Foundation, Inc.,
|
||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||
|
**********/
|
||
|
// "liveMedia"
|
||
|
// Copyright (c) 1996-2016 Live Networks, Inc. All rights reserved.
|
||
|
// Bit Vector data structure
|
||
|
// Implementation
|
||
|
|
||
|
#include "BitVector.hh"
|
||
|
|
||
|
BitVector::BitVector(unsigned char* baseBytePtr,
|
||
|
unsigned baseBitOffset,
|
||
|
unsigned totNumBits) {
|
||
|
setup(baseBytePtr, baseBitOffset, totNumBits);
|
||
|
}
|
||
|
|
||
|
void BitVector::setup(unsigned char* baseBytePtr,
|
||
|
unsigned baseBitOffset,
|
||
|
unsigned totNumBits) {
|
||
|
fBaseBytePtr = baseBytePtr;
|
||
|
fBaseBitOffset = baseBitOffset;
|
||
|
fTotNumBits = totNumBits;
|
||
|
fCurBitIndex = 0;
|
||
|
}
|
||
|
|
||
|
static unsigned char const singleBitMask[8]
|
||
|
= {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
|
||
|
|
||
|
#define MAX_LENGTH 32
|
||
|
|
||
|
void BitVector::putBits(unsigned from, unsigned numBits) {
|
||
|
if (numBits == 0) return;
|
||
|
|
||
|
unsigned char tmpBuf[4];
|
||
|
unsigned overflowingBits = 0;
|
||
|
|
||
|
if (numBits > MAX_LENGTH) {
|
||
|
numBits = MAX_LENGTH;
|
||
|
}
|
||
|
|
||
|
if (numBits > fTotNumBits - fCurBitIndex) {
|
||
|
overflowingBits = numBits - (fTotNumBits - fCurBitIndex);
|
||
|
}
|
||
|
|
||
|
tmpBuf[0] = (unsigned char)(from>>24);
|
||
|
tmpBuf[1] = (unsigned char)(from>>16);
|
||
|
tmpBuf[2] = (unsigned char)(from>>8);
|
||
|
tmpBuf[3] = (unsigned char)from;
|
||
|
|
||
|
shiftBits(fBaseBytePtr, fBaseBitOffset + fCurBitIndex, /* to */
|
||
|
tmpBuf, MAX_LENGTH - numBits, /* from */
|
||
|
numBits - overflowingBits /* num bits */);
|
||
|
fCurBitIndex += numBits - overflowingBits;
|
||
|
}
|
||
|
|
||
|
void BitVector::put1Bit(unsigned bit) {
|
||
|
// The following is equivalent to "putBits(..., 1)", except faster:
|
||
|
if (fCurBitIndex >= fTotNumBits) { /* overflow */
|
||
|
return;
|
||
|
} else {
|
||
|
unsigned totBitOffset = fBaseBitOffset + fCurBitIndex++;
|
||
|
unsigned char mask = singleBitMask[totBitOffset%8];
|
||
|
if (bit) {
|
||
|
fBaseBytePtr[totBitOffset/8] |= mask;
|
||
|
} else {
|
||
|
fBaseBytePtr[totBitOffset/8] &=~ mask;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
unsigned BitVector::getBits(unsigned numBits) {
|
||
|
if (numBits == 0) return 0;
|
||
|
|
||
|
unsigned char tmpBuf[4];
|
||
|
unsigned overflowingBits = 0;
|
||
|
|
||
|
if (numBits > MAX_LENGTH) {
|
||
|
numBits = MAX_LENGTH;
|
||
|
}
|
||
|
|
||
|
if (numBits > fTotNumBits - fCurBitIndex) {
|
||
|
overflowingBits = numBits - (fTotNumBits - fCurBitIndex);
|
||
|
}
|
||
|
|
||
|
shiftBits(tmpBuf, 0, /* to */
|
||
|
fBaseBytePtr, fBaseBitOffset + fCurBitIndex, /* from */
|
||
|
numBits - overflowingBits /* num bits */);
|
||
|
fCurBitIndex += numBits - overflowingBits;
|
||
|
|
||
|
unsigned result
|
||
|
= (tmpBuf[0]<<24) | (tmpBuf[1]<<16) | (tmpBuf[2]<<8) | tmpBuf[3];
|
||
|
result >>= (MAX_LENGTH - numBits); // move into low-order part of word
|
||
|
result &= (0xFFFFFFFF << overflowingBits); // so any overflow bits are 0
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
unsigned BitVector::get1Bit() {
|
||
|
// The following is equivalent to "getBits(1)", except faster:
|
||
|
|
||
|
if (fCurBitIndex >= fTotNumBits) { /* overflow */
|
||
|
return 0;
|
||
|
} else {
|
||
|
unsigned totBitOffset = fBaseBitOffset + fCurBitIndex++;
|
||
|
unsigned char curFromByte = fBaseBytePtr[totBitOffset/8];
|
||
|
unsigned result = (curFromByte >> (7-(totBitOffset%8))) & 0x01;
|
||
|
return result;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void BitVector::skipBits(unsigned numBits) {
|
||
|
if (numBits > fTotNumBits - fCurBitIndex) { /* overflow */
|
||
|
fCurBitIndex = fTotNumBits;
|
||
|
} else {
|
||
|
fCurBitIndex += numBits;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
unsigned BitVector::get_expGolomb() {
|
||
|
unsigned numLeadingZeroBits = 0;
|
||
|
unsigned codeStart = 1;
|
||
|
|
||
|
while (get1Bit() == 0 && fCurBitIndex < fTotNumBits) {
|
||
|
++numLeadingZeroBits;
|
||
|
codeStart *= 2;
|
||
|
}
|
||
|
|
||
|
return codeStart - 1 + getBits(numLeadingZeroBits);
|
||
|
}
|
||
|
|
||
|
|
||
|
void shiftBits(unsigned char* toBasePtr, unsigned toBitOffset,
|
||
|
unsigned char const* fromBasePtr, unsigned fromBitOffset,
|
||
|
unsigned numBits) {
|
||
|
if (numBits == 0) return;
|
||
|
|
||
|
/* Note that from and to may overlap, if from>to */
|
||
|
unsigned char const* fromBytePtr = fromBasePtr + fromBitOffset/8;
|
||
|
unsigned fromBitRem = fromBitOffset%8;
|
||
|
unsigned char* toBytePtr = toBasePtr + toBitOffset/8;
|
||
|
unsigned toBitRem = toBitOffset%8;
|
||
|
|
||
|
while (numBits-- > 0) {
|
||
|
unsigned char fromBitMask = singleBitMask[fromBitRem];
|
||
|
unsigned char fromBit = (*fromBytePtr)&fromBitMask;
|
||
|
unsigned char toBitMask = singleBitMask[toBitRem];
|
||
|
|
||
|
if (fromBit != 0) {
|
||
|
*toBytePtr |= toBitMask;
|
||
|
} else {
|
||
|
*toBytePtr &=~ toBitMask;
|
||
|
}
|
||
|
|
||
|
if (++fromBitRem == 8) {
|
||
|
++fromBytePtr;
|
||
|
fromBitRem = 0;
|
||
|
}
|
||
|
if (++toBitRem == 8) {
|
||
|
++toBytePtr;
|
||
|
toBitRem = 0;
|
||
|
}
|
||
|
}
|
||
|
}
|