mirror of
https://github.com/AleziaKurdis/overte.git
synced 2025-04-14 09:06:51 +02:00
first cut at ByteCountCoding template, additional features in PropertyFlags template
This commit is contained in:
parent
b74676de0d
commit
2a73a91775
2 changed files with 184 additions and 2 deletions
168
libraries/shared/src/ByteCountCoding.h
Normal file
168
libraries/shared/src/ByteCountCoding.h
Normal file
|
@ -0,0 +1,168 @@
|
|||
//
|
||||
// ByteCountCoding.h
|
||||
// libraries/shared/src
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 6/3/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
//
|
||||
// TODO:
|
||||
// * handle signed types better, check for - numeric_limits<type>::is_signed
|
||||
// * test extra long buffer with garbage data at end...
|
||||
|
||||
#ifndef hifi_ByteCountCoding_h
|
||||
#define hifi_ByteCountCoding_h
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <climits>
|
||||
#include <limits>
|
||||
|
||||
#include <QBitArray>
|
||||
#include <QByteArray>
|
||||
|
||||
#include "SharedUtil.h"
|
||||
|
||||
template<typename T> class ByteCountCoded {
|
||||
public:
|
||||
T data;
|
||||
ByteCountCoded(T input = 0) : data(input) {
|
||||
assert(!std::numeric_limits<T>::is_signed); // we don't yet support signed types
|
||||
};
|
||||
|
||||
ByteCountCoded(const QByteArray& fromEncoded) : data(0) { decode(fromEncoded); }
|
||||
|
||||
QByteArray encode() const;
|
||||
void decode(const QByteArray& fromEncoded);
|
||||
|
||||
bool operator==(const ByteCountCoded& other) const { return data == other.data; }
|
||||
bool operator!=(const ByteCountCoded& other) const { return data != other.data; }
|
||||
bool operator!() const { return data == 0; }
|
||||
|
||||
operator QByteArray() const { return encode(); };
|
||||
operator T() const { return data; };
|
||||
};
|
||||
|
||||
template<typename T> inline QByteArray& operator<<(QByteArray& out, const ByteCountCoded<T>& value) {
|
||||
return out = value;
|
||||
}
|
||||
|
||||
template<typename T> inline QByteArray& operator>>(QByteArray& in, ByteCountCoded<T>& value) {
|
||||
value.decode(in);
|
||||
return in;
|
||||
}
|
||||
|
||||
template<typename T> inline QByteArray ByteCountCoded<T>::encode() const {
|
||||
QByteArray output;
|
||||
|
||||
//qDebug() << "data=";
|
||||
//outputBufferBits((const unsigned char*)&data, sizeof(data));
|
||||
|
||||
T totalBits = sizeof(data) * BITS_IN_BYTE;
|
||||
//qDebug() << "totalBits=" << totalBits;
|
||||
T valueBits = totalBits;
|
||||
bool firstValueFound = false;
|
||||
T temp = data;
|
||||
T lastBitMask = (T)(1) << (totalBits - 1);
|
||||
|
||||
//qDebug() << "lastBitMask=";
|
||||
//outputBufferBits((const unsigned char*)&lastBitMask, sizeof(lastBitMask));
|
||||
|
||||
// determine the number of bits that the value takes
|
||||
for (int bitAt = 0; bitAt < totalBits; bitAt++) {
|
||||
T bitValue = (temp & lastBitMask) == lastBitMask;
|
||||
//qDebug() << "bitValue[" << bitAt <<"]=" << bitValue;
|
||||
if (!firstValueFound) {
|
||||
if (bitValue == 0) {
|
||||
valueBits--;
|
||||
} else {
|
||||
firstValueFound = true;
|
||||
}
|
||||
}
|
||||
temp = temp << 1;
|
||||
}
|
||||
qDebug() << "valueBits=" << valueBits;
|
||||
|
||||
// calculate the number of total bytes, including our header
|
||||
// BITS_IN_BYTE-1 because we need to code the number of bytes in the header
|
||||
// + 1 because we always take at least 1 byte, even if number of bits is less than a bytes worth
|
||||
int numberOfBytes = (valueBits / (BITS_IN_BYTE - 1)) + 1;
|
||||
//qDebug() << "numberOfBytes=" << numberOfBytes;
|
||||
|
||||
//int numberOfBits = numberOfBytes + valueBits;
|
||||
//qDebug() << "numberOfBits=" << numberOfBits;
|
||||
|
||||
output.fill(0, numberOfBytes);
|
||||
|
||||
// next pack the number of header bits in, the first N-1 to be set to 1, the last to be set to 0
|
||||
for(int i = 0; i < numberOfBytes; i++) {
|
||||
int outputIndex = i;
|
||||
T bitValue = (i < (numberOfBytes - 1) ? 1 : 0);
|
||||
char original = output.at(outputIndex / BITS_IN_BYTE);
|
||||
int shiftBy = BITS_IN_BYTE - ((outputIndex % BITS_IN_BYTE) + 1);
|
||||
char thisBit = ( bitValue << shiftBy);
|
||||
output[i / BITS_IN_BYTE] = (original | thisBit);
|
||||
}
|
||||
|
||||
// finally pack the the actual bits from the bit array
|
||||
temp = data;
|
||||
for(int i = numberOfBytes; i < (numberOfBytes + valueBits); i++) {
|
||||
int outputIndex = i;
|
||||
T bitValue = (temp & 1);
|
||||
char original = output.at(outputIndex / BITS_IN_BYTE);
|
||||
int shiftBy = BITS_IN_BYTE - ((outputIndex % BITS_IN_BYTE) + 1);
|
||||
char thisBit = ( bitValue << shiftBy);
|
||||
output[i / BITS_IN_BYTE] = (original | thisBit);
|
||||
|
||||
temp = temp >> 1;
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
template<typename T> inline void ByteCountCoded<T>::decode(const QByteArray& fromEncodedBytes) {
|
||||
|
||||
// first convert the ByteArray into a BitArray...
|
||||
QBitArray encodedBits;
|
||||
int bitCount = BITS_IN_BYTE * fromEncodedBytes.count();
|
||||
encodedBits.resize(bitCount);
|
||||
|
||||
for(int byte = 0; byte < fromEncodedBytes.count(); byte++) {
|
||||
char originalByte = fromEncodedBytes.at(byte);
|
||||
for(int bit = 0; bit < BITS_IN_BYTE; bit++) {
|
||||
int shiftBy = BITS_IN_BYTE - (bit + 1);
|
||||
char maskBit = ( 1 << shiftBy);
|
||||
bool bitValue = originalByte & maskBit;
|
||||
encodedBits.setBit(byte * BITS_IN_BYTE + bit, bitValue);
|
||||
}
|
||||
}
|
||||
|
||||
// next, read the leading bits to determine the correct number of bytes to decode (may not match the QByteArray)
|
||||
int encodedByteCount = 0;
|
||||
int bitAt;
|
||||
for (bitAt = 0; bitAt < bitCount; bitAt++) {
|
||||
if (encodedBits.at(bitAt)) {
|
||||
encodedByteCount++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
encodedByteCount++; // always at least one byte
|
||||
int expectedBitCount = encodedByteCount * BITS_IN_BYTE;
|
||||
|
||||
// Now, keep reading...
|
||||
int valueStartsAt = bitAt + 1;
|
||||
T value = 0;
|
||||
T bitValue = 1;
|
||||
for (bitAt = valueStartsAt; bitAt < expectedBitCount; bitAt++) {
|
||||
if(encodedBits.at(bitAt)) {
|
||||
value += bitValue;
|
||||
}
|
||||
bitValue *= 2;
|
||||
}
|
||||
data = value;
|
||||
}
|
||||
#endif // hifi_ByteCountCoding_h
|
||||
|
|
@ -11,6 +11,7 @@
|
|||
//
|
||||
// TODO:
|
||||
// * consider adding iterator to enumerate the properties that have been set?
|
||||
// * operator QSet<Enum> - this would be easiest way to handle enumeration
|
||||
|
||||
#ifndef hifi_PropertyFlags_h
|
||||
#define hifi_PropertyFlags_h
|
||||
|
@ -33,6 +34,8 @@ public:
|
|||
_trailingFlipped(other._trailingFlipped) {}
|
||||
inline PropertyFlags(Enum flag) :
|
||||
_maxFlag(INT_MIN), _minFlag(INT_MAX), _trailingFlipped(false) { setHasProperty(flag); }
|
||||
inline PropertyFlags(const QByteArray& fromEncoded) :
|
||||
_maxFlag(INT_MIN), _minFlag(INT_MAX), _trailingFlipped(false) { decode(fromEncoded); }
|
||||
|
||||
void clear() { _flags.clear(); _maxFlag = INT_MIN; _minFlag = INT_MAX; _trailingFlipped = false; }
|
||||
|
||||
|
@ -41,9 +44,11 @@ public:
|
|||
|
||||
void setHasProperty(Enum flag, bool value = true);
|
||||
bool getHasProperty(Enum flag);
|
||||
QByteArray encode();
|
||||
QByteArray encode() const;
|
||||
void decode(const QByteArray& fromEncoded);
|
||||
|
||||
operator QByteArray() const { return encode(); };
|
||||
|
||||
|
||||
bool operator==(const PropertyFlags& other) const { return _flags == other._flags; }
|
||||
bool operator!=(const PropertyFlags& other) const { return _flags != other._flags; }
|
||||
|
@ -142,7 +147,7 @@ template<typename Enum> inline bool PropertyFlags<Enum>::getHasProperty(Enum fla
|
|||
|
||||
const int BITS_PER_BYTE = 8;
|
||||
|
||||
template<typename Enum> inline QByteArray PropertyFlags<Enum>::encode() {
|
||||
template<typename Enum> inline QByteArray PropertyFlags<Enum>::encode() const {
|
||||
QByteArray output;
|
||||
|
||||
if (_maxFlag < _minFlag) {
|
||||
|
@ -414,5 +419,14 @@ template<typename Enum> inline void PropertyFlags<Enum>::shinkIfNeeded() {
|
|||
}
|
||||
}
|
||||
|
||||
template<typename Enum> inline QByteArray& operator<<(QByteArray& out, const PropertyFlags<Enum>& value) {
|
||||
return out = value;
|
||||
}
|
||||
|
||||
template<typename Enum> inline QByteArray& operator>>(QByteArray& in, PropertyFlags<Enum>& value) {
|
||||
value.decode(in);
|
||||
return in;
|
||||
}
|
||||
|
||||
#endif // hifi_PropertyFlags_h
|
||||
|
||||
|
|
Loading…
Reference in a new issue