19 #ifndef hifi_PropertyFlags_h
20 #define hifi_PropertyFlags_h
28 #include "ByteCountCoding.h"
29 #include "SharedLogging.h"
31 template<
typename Enum>
class PropertyFlags {
33 typedef Enum enum_type;
34 inline PropertyFlags() :
35 _maxFlag(INT_MIN), _minFlag(INT_MAX), _trailingFlipped(false), _encodedLength(0) { };
37 inline PropertyFlags(
const PropertyFlags& other) :
38 _flags(other._flags), _maxFlag(other._maxFlag), _minFlag(other._minFlag),
39 _trailingFlipped(other._trailingFlipped), _encodedLength(0) {}
41 inline PropertyFlags(Enum flag) :
42 _maxFlag(INT_MIN), _minFlag(INT_MAX), _trailingFlipped(false), _encodedLength(0) { setHasProperty(flag); }
44 inline PropertyFlags(
const QByteArray& fromEncoded) :
45 _maxFlag(INT_MIN), _minFlag(INT_MAX), _trailingFlipped(false), _encodedLength(0) { decode(fromEncoded); }
47 void clear() { _flags.clear(); _maxFlag = INT_MIN; _minFlag = INT_MAX; _trailingFlipped =
false; _encodedLength = 0; }
48 bool isEmpty()
const {
return _maxFlag == INT_MIN && _minFlag == INT_MAX && _trailingFlipped ==
false && _encodedLength == 0; }
50 Enum firstFlag()
const {
return (Enum)_minFlag; }
51 Enum lastFlag()
const {
return (Enum)_maxFlag; }
53 void setHasProperty(Enum flag,
bool value =
true);
54 bool getHasProperty(Enum flag)
const;
56 size_t decode(
const uint8_t* data,
size_t length);
57 size_t decode(
const QByteArray& fromEncoded);
59 operator QByteArray() {
return encode(); };
61 bool operator==(
const PropertyFlags& other)
const {
return _flags == other._flags; }
62 bool operator!=(
const PropertyFlags& other)
const {
return _flags != other._flags; }
63 bool operator!()
const {
return _flags.size() == 0; }
65 PropertyFlags& operator=(
const PropertyFlags& other);
67 PropertyFlags& operator|=(
const PropertyFlags& other);
68 PropertyFlags& operator|=(Enum flag);
70 PropertyFlags& operator&=(
const PropertyFlags& other);
71 PropertyFlags& operator&=(Enum flag);
73 PropertyFlags& operator+=(
const PropertyFlags& other);
74 PropertyFlags& operator+=(Enum flag);
76 PropertyFlags& operator-=(
const PropertyFlags& other);
77 PropertyFlags& operator-=(Enum flag);
79 PropertyFlags& operator<<=(
const PropertyFlags& other);
80 PropertyFlags& operator<<=(Enum flag);
82 PropertyFlags operator|(
const PropertyFlags& other)
const;
83 PropertyFlags operator|(Enum flag)
const;
85 PropertyFlags operator&(
const PropertyFlags& other)
const;
86 PropertyFlags operator&(Enum flag)
const;
88 PropertyFlags operator+(
const PropertyFlags& other)
const;
89 PropertyFlags operator+(Enum flag)
const;
91 PropertyFlags operator-(
const PropertyFlags& other)
const;
92 PropertyFlags operator-(Enum flag)
const;
94 PropertyFlags operator<<(
const PropertyFlags& other)
const;
95 PropertyFlags operator<<(Enum flag)
const;
100 PropertyFlags& operator^=(
const PropertyFlags& other);
101 PropertyFlags& operator^=(Enum flag);
102 PropertyFlags operator^(
const PropertyFlags& other)
const;
103 PropertyFlags operator^(Enum flag)
const;
104 PropertyFlags operator~()
const;
106 void debugDumpBits();
108 int getEncodedLength()
const {
return _encodedLength; }
112 void shrinkIfNeeded();
117 bool _trailingFlipped;
121 template<
typename Enum> PropertyFlags<Enum>& operator<<(PropertyFlags<Enum>& out,
const PropertyFlags<Enum>& other) {
122 return out <<= other;
125 template<
typename Enum> PropertyFlags<Enum>& operator<<(PropertyFlags<Enum>& out, Enum flag) {
130 template<
typename Enum>
inline void PropertyFlags<Enum>::setHasProperty(Enum flag,
bool value) {
132 if (flag < _minFlag) {
137 if (flag > _maxFlag) {
140 _flags.resize(_maxFlag + 1);
145 _flags.setBit(flag, value);
147 if (flag == _maxFlag && !value) {
152 template<
typename Enum>
inline bool PropertyFlags<Enum>::getHasProperty(Enum flag)
const {
153 if (flag > _maxFlag) {
154 return _trailingFlipped;
156 return _flags.testBit(flag);
159 const int BITS_PER_BYTE = 8;
161 template<
typename Enum>
inline QByteArray PropertyFlags<Enum>::encode() {
164 if (_maxFlag < _minFlag) {
170 int lengthInBytes = (_maxFlag / (BITS_PER_BYTE - 1)) + 1;
172 output.fill(0, lengthInBytes);
175 for(
int i = 0; i < lengthInBytes; i++) {
177 int bitValue = (i < (lengthInBytes - 1) ? 1 : 0);
178 char original = output.at(outputIndex / BITS_PER_BYTE);
179 int shiftBy = BITS_PER_BYTE - ((outputIndex % BITS_PER_BYTE) + 1);
180 char thisBit = ( bitValue << shiftBy);
181 output[i / BITS_PER_BYTE] = (original | thisBit);
185 for(
int i = lengthInBytes; i < (lengthInBytes + _maxFlag + 1); i++) {
186 int flagIndex = i - lengthInBytes;
188 int bitValue = ( _flags[flagIndex] ? 1 : 0);
189 char original = output.at(outputIndex / BITS_PER_BYTE);
190 int shiftBy = BITS_PER_BYTE - ((outputIndex % BITS_PER_BYTE) + 1);
191 char thisBit = ( bitValue << shiftBy);
192 output[i / BITS_PER_BYTE] = (original | thisBit);
195 _encodedLength = lengthInBytes;
199 template<
typename Enum>
200 inline size_t PropertyFlags<Enum>::decode(
const uint8_t* data,
size_t size) {
203 size_t bytesConsumed = 0;
204 int bitCount = BITS_IN_BYTE * (int)size;
206 int encodedByteCount = 1;
208 bool inLeadBits =
true;
210 int expectedBitCount;
211 int lastValueBit = 0;
212 for (
unsigned int byte = 0;
byte < size;
byte++) {
213 char originalByte = data[byte];
215 unsigned char maskBit = 0x80;
216 for (
int bit = 0; bit < BITS_IN_BYTE; bit++) {
217 bool bitIsSet = originalByte & maskBit;
225 expectedBitCount = (encodedByteCount * BITS_IN_BYTE) - leadBits;
226 lastValueBit = expectedBitCount + bitAt;
229 if (expectedBitCount > (bitCount - leadBits)) {
234 if (bitAt > lastValueBit) {
239 setHasProperty(
static_cast<Enum
>(bitAt - leadBits),
true);
245 if (!inLeadBits && bitAt > lastValueBit) {
249 _encodedLength = (int)bytesConsumed;
250 return bytesConsumed;
253 template<
typename Enum>
inline size_t PropertyFlags<Enum>::decode(
const QByteArray& fromEncodedBytes) {
254 return decode(
reinterpret_cast<const uint8_t*
>(fromEncodedBytes.data()), fromEncodedBytes.size());
257 template<
typename Enum>
inline void PropertyFlags<Enum>::debugDumpBits() {
258 qCDebug(shared) <<
"_minFlag=" << _minFlag;
259 qCDebug(shared) <<
"_maxFlag=" << _maxFlag;
260 qCDebug(shared) <<
"_trailingFlipped=" << _trailingFlipped;
262 for(
int i = 0; i < _flags.size(); i++) {
263 bits += (_flags.at(i) ?
"1" :
"0");
265 qCDebug(shared) <<
"bits:" << bits;
269 template<
typename Enum>
inline PropertyFlags<Enum>& PropertyFlags<Enum>::operator=(
const PropertyFlags& other) {
270 _flags = other._flags;
271 _maxFlag = other._maxFlag;
272 _minFlag = other._minFlag;
276 template<
typename Enum>
inline PropertyFlags<Enum>& PropertyFlags<Enum>::operator|=(
const PropertyFlags& other) {
277 _flags |= other._flags;
278 _maxFlag = std::max(_maxFlag, other._maxFlag);
279 _minFlag = std::min(_minFlag, other._minFlag);
283 template<
typename Enum>
inline PropertyFlags<Enum>& PropertyFlags<Enum>::operator|=(Enum flag) {
284 PropertyFlags other(flag);
285 _flags |= other._flags;
286 _maxFlag = std::max(_maxFlag, other._maxFlag);
287 _minFlag = std::min(_minFlag, other._minFlag);
291 template<
typename Enum>
inline PropertyFlags<Enum>& PropertyFlags<Enum>::operator&=(
const PropertyFlags& other) {
292 _flags &= other._flags;
297 template<
typename Enum>
inline PropertyFlags<Enum>& PropertyFlags<Enum>::operator&=(Enum flag) {
298 PropertyFlags other(flag);
299 _flags &= other._flags;
304 template<
typename Enum>
inline PropertyFlags<Enum>& PropertyFlags<Enum>::operator^=(
const PropertyFlags& other) {
305 _flags ^= other._flags;
310 template<
typename Enum>
inline PropertyFlags<Enum>& PropertyFlags<Enum>::operator^=(Enum flag) {
311 PropertyFlags other(flag);
312 _flags ^= other._flags;
317 template<
typename Enum>
inline PropertyFlags<Enum>& PropertyFlags<Enum>::operator+=(
const PropertyFlags& other) {
318 for(
int flag = (
int)other.firstFlag(); flag <= (
int)other.lastFlag(); flag++) {
319 if (other.getHasProperty((Enum)flag)) {
320 setHasProperty((Enum)flag,
true);
326 template<
typename Enum>
inline PropertyFlags<Enum>& PropertyFlags<Enum>::operator+=(Enum flag) {
327 setHasProperty(flag,
true);
331 template<
typename Enum>
inline PropertyFlags<Enum>& PropertyFlags<Enum>::operator-=(
const PropertyFlags& other) {
332 for(
int flag = (
int)other.firstFlag(); flag <= (
int)other.lastFlag(); flag++) {
333 if (other.getHasProperty((Enum)flag)) {
334 setHasProperty((Enum)flag,
false);
340 template<
typename Enum>
inline PropertyFlags<Enum>& PropertyFlags<Enum>::operator-=(Enum flag) {
341 setHasProperty(flag,
false);
345 template<
typename Enum>
inline PropertyFlags<Enum>& PropertyFlags<Enum>::operator<<=(
const PropertyFlags& other) {
346 for(
int flag = (
int)other.firstFlag(); flag <= (
int)other.lastFlag(); flag++) {
347 if (other.getHasProperty((Enum)flag)) {
348 setHasProperty((Enum)flag,
true);
354 template<
typename Enum>
inline PropertyFlags<Enum>& PropertyFlags<Enum>::operator<<=(Enum flag) {
355 setHasProperty(flag,
true);
359 template<
typename Enum>
inline PropertyFlags<Enum> PropertyFlags<Enum>::operator|(
const PropertyFlags& other)
const {
360 PropertyFlags result(*
this);
365 template<
typename Enum>
inline PropertyFlags<Enum> PropertyFlags<Enum>::operator|(Enum flag)
const {
366 PropertyFlags result(*
this);
367 PropertyFlags other(flag);
372 template<
typename Enum>
inline PropertyFlags<Enum> PropertyFlags<Enum>::operator&(
const PropertyFlags& other)
const {
373 PropertyFlags result(*
this);
378 template<
typename Enum>
inline PropertyFlags<Enum> PropertyFlags<Enum>::operator&(Enum flag)
const {
379 PropertyFlags result(*
this);
380 PropertyFlags other(flag);
385 template<
typename Enum>
inline PropertyFlags<Enum> PropertyFlags<Enum>::operator^(
const PropertyFlags& other)
const {
386 PropertyFlags result(*
this);
391 template<
typename Enum>
inline PropertyFlags<Enum> PropertyFlags<Enum>::operator^(Enum flag)
const {
392 PropertyFlags result(*
this);
393 PropertyFlags other(flag);
398 template<
typename Enum>
inline PropertyFlags<Enum> PropertyFlags<Enum>::operator+(
const PropertyFlags& other)
const {
399 PropertyFlags result(*
this);
404 template<
typename Enum>
inline PropertyFlags<Enum> PropertyFlags<Enum>::operator+(Enum flag)
const {
405 PropertyFlags result(*
this);
406 result.setHasProperty(flag,
true);
410 template<
typename Enum>
inline PropertyFlags<Enum> PropertyFlags<Enum>::operator-(
const PropertyFlags& other)
const {
411 PropertyFlags result(*
this);
416 template<
typename Enum>
inline PropertyFlags<Enum> PropertyFlags<Enum>::operator-(Enum flag)
const {
417 PropertyFlags result(*
this);
418 result.setHasProperty(flag,
false);
422 template<
typename Enum>
inline PropertyFlags<Enum> PropertyFlags<Enum>::operator<<(
const PropertyFlags& other)
const {
423 PropertyFlags result(*
this);
428 template<
typename Enum>
inline PropertyFlags<Enum> PropertyFlags<Enum>::operator<<(Enum flag)
const {
429 PropertyFlags result(*
this);
430 result.setHasProperty(flag,
true);
434 template<
typename Enum>
inline PropertyFlags<Enum> PropertyFlags<Enum>::operator~()
const {
435 PropertyFlags result(*
this);
436 result._flags = ~_flags;
437 result._trailingFlipped = !_trailingFlipped;
441 template<
typename Enum>
inline void PropertyFlags<Enum>::shrinkIfNeeded() {
442 int maxFlagWas = _maxFlag;
443 while (_maxFlag >= 0) {
444 if (_flags.testBit(_maxFlag)) {
449 if (maxFlagWas != _maxFlag) {
450 _flags.resize(_maxFlag + 1);
454 template<
typename Enum>
inline QByteArray& operator<<(QByteArray& out, PropertyFlags<Enum>& value) {
458 template<
typename Enum>
inline QByteArray& operator>>(QByteArray& in, PropertyFlags<Enum>& value) {