diff --git a/libraries/shared/src/PropertyFlags.h b/libraries/shared/src/PropertyFlags.h index d8131d0c75..4c4dc6b386 100644 --- a/libraries/shared/src/PropertyFlags.h +++ b/libraries/shared/src/PropertyFlags.h @@ -11,9 +11,7 @@ // // TODO: // * implement decode -// * more operators, operator==, operator!=, operator!, operator~ // * iterator to enumerate the set values? -// * operator<<(enum) to work similar to set #ifndef hifi_PropertyFlags_h #define hifi_PropertyFlags_h @@ -29,14 +27,18 @@ templateclass PropertyFlags { public: typedef Enum enum_type; - inline PropertyFlags() : _maxFlag(INT_MIN), _minFlag(INT_MAX) { }; - inline PropertyFlags(const PropertyFlags& other) : _flags(other._flags), _maxFlag(other._maxFlag) {} - inline PropertyFlags(Enum flag) : _maxFlag(INT_MIN), _minFlag(INT_MAX) { setHasProperty(flag); } + inline PropertyFlags() : + _maxFlag(INT_MIN), _minFlag(INT_MAX), _trailingFlipped(false) { }; + inline PropertyFlags(const PropertyFlags& other) : + _flags(other._flags), _maxFlag(other._maxFlag), _minFlag(other._minFlag), + _trailingFlipped(other._trailingFlipped) {} + inline PropertyFlags(Enum flag) : + _maxFlag(INT_MIN), _minFlag(INT_MAX), _trailingFlipped(false) { setHasProperty(flag); } - void clear() { _flags.clear(); _maxFlag = INT_MIN; _minFlag = INT_MAX; } + void clear() { _flags.clear(); _maxFlag = INT_MIN; _minFlag = INT_MAX; _trailingFlipped = false; } - Enum firstFlag() const { return _minFlag; } - Enum lastFlag() const { return _maxFlag; } + Enum firstFlag() const { return (Enum)_minFlag; } + Enum lastFlag() const { return (Enum)_maxFlag; } void setHasProperty(Enum flag, bool value = true); bool getHasProperty(Enum flag); @@ -44,7 +46,12 @@ public: void decode(const QByteArray& fromEncoded); - PropertyFlags& operator=(const PropertyFlags &other); + bool operator==(const PropertyFlags& other) const { return _flags == other._flags; } + bool operator!=(const PropertyFlags& other) const { return _flags != other._flags; } + bool operator!() const { return _flags.size() == 0; } + + + PropertyFlags& operator=(const PropertyFlags& other); PropertyFlags& operator|=(PropertyFlags other); PropertyFlags& operator|=(Enum flag); @@ -55,9 +62,15 @@ public: PropertyFlags& operator^=(PropertyFlags other); PropertyFlags& operator^=(Enum flag); + PropertyFlags& operator+=(PropertyFlags other); + PropertyFlags& operator+=(Enum flag); + PropertyFlags& operator-=(PropertyFlags other); PropertyFlags& operator-=(Enum flag); + PropertyFlags& operator<<=(PropertyFlags other); + PropertyFlags& operator<<=(Enum flag); + PropertyFlags operator|(PropertyFlags other) const; PropertyFlags operator|(Enum flag) const; @@ -67,25 +80,38 @@ public: PropertyFlags operator^(PropertyFlags other) const; PropertyFlags operator^(Enum flag) const; + PropertyFlags operator+(PropertyFlags other) const; + PropertyFlags operator+(Enum flag) const; + PropertyFlags operator-(PropertyFlags other) const; PropertyFlags operator-(Enum flag) const; + PropertyFlags operator<<(PropertyFlags other) const; + PropertyFlags operator<<(Enum flag) const; - /* - inline PropertyFlags operator~() const { return PropertyFlags(Enum(~i)); } - inline bool operator!() const { return !i; } - */ + + PropertyFlags operator~() const; + + void debugDumpBits(); private: void shinkIfNeeded(); - void debugDumpBits(); QBitArray _flags; int _maxFlag; int _minFlag; + bool _trailingFlipped; /// are the trailing properties flipping in their state (e.g. assumed true, instead of false) }; +template PropertyFlags& operator<<(PropertyFlags& out, const PropertyFlags& other) { + return out <<= other; +} + +template PropertyFlags& operator<<(PropertyFlags& out, Enum flag) { + return out <<= flag; +} + template inline void PropertyFlags::setHasProperty(Enum flag, bool value) { // keep track of our min flag @@ -111,7 +137,7 @@ template inline void PropertyFlags::setHasProperty(Enum fla template inline bool PropertyFlags::getHasProperty(Enum flag) { if (flag > _maxFlag) { - return false; + return _trailingFlipped; // usually false } return _flags.testBit(flag); } @@ -121,6 +147,11 @@ const int BITS_PER_BYTE = 8; template inline QByteArray PropertyFlags::encode() { const bool debug = false; QByteArray output; + + if (_maxFlag < _minFlag) { + output.fill(0, 1); + return output; // no flags... nothing to encode + } outputBufferBits((const unsigned char*)output.constData(), output.size()); @@ -200,21 +231,26 @@ template inline void PropertyFlags::decode(const QByteArray } template inline void PropertyFlags::debugDumpBits() { + qDebug() << "_minFlag=" << _minFlag; + qDebug() << "_maxFlag=" << _maxFlag; + qDebug() << "_trailingFlipped=" << _trailingFlipped; for(int i = 0; i < _flags.size(); i++) { qDebug() << "bit[" << i << "]=" << _flags.at(i); } } -template inline PropertyFlags& PropertyFlags::operator=(const PropertyFlags &other) { +template inline PropertyFlags& PropertyFlags::operator=(const PropertyFlags& other) { _flags = other._flags; _maxFlag = other._maxFlag; + _minFlag = other._minFlag; return *this; } template inline PropertyFlags& PropertyFlags::operator|=(PropertyFlags other) { _flags |= other._flags; _maxFlag = std::max(_maxFlag, other._maxFlag); + _minFlag = std::min(_minFlag, other._minFlag); return *this; } @@ -222,6 +258,7 @@ template inline PropertyFlags& PropertyFlags::operato PropertyFlags other(flag); _flags |= other._flags; _maxFlag = std::max(_maxFlag, other._maxFlag); + _minFlag = std::min(_minFlag, other._minFlag); return *this; } @@ -251,31 +288,45 @@ template inline PropertyFlags& PropertyFlags::operato return *this; } -template inline PropertyFlags& PropertyFlags::operator-=(PropertyFlags other) { - for(int flag = other.firstFlag(); flag <= other.lastFlag(); flag++) { - //qDebug() << "checking other.getHasProperty(flag) flag=" << flag; - if (other.getHasProperty(flag)) { - //qDebug() << "setting setHasProperty(flag) flag=" << flag; - setHasProperty(flag, false); +template inline PropertyFlags& PropertyFlags::operator+=(PropertyFlags other) { + for(int flag = (int)other.firstFlag(); flag <= (int)other.lastFlag(); flag++) { + if (other.getHasProperty((Enum)flag)) { + setHasProperty((Enum)flag, true); } } - return *this; } +template inline PropertyFlags& PropertyFlags::operator+=(Enum flag) { + setHasProperty(flag, true); + return *this; +} + +template inline PropertyFlags& PropertyFlags::operator-=(PropertyFlags other) { + for(int flag = (int)other.firstFlag(); flag <= (int)other.lastFlag(); flag++) { + if (other.getHasProperty((Enum)flag)) { + setHasProperty((Enum)flag, false); + } + } + return *this; +} + template inline PropertyFlags& PropertyFlags::operator-=(Enum flag) { - bool debug = false; - if (debug) { - qDebug() << "operator-=(Enum flag) flag=" << flag << "before..."; - debugDumpBits(); - } setHasProperty(flag, false); + return *this; +} - if (debug) { - qDebug() << "after..."; - debugDumpBits(); +template inline PropertyFlags& PropertyFlags::operator<<=(PropertyFlags other) { + for(int flag = (int)other.firstFlag(); flag <= (int)other.lastFlag(); flag++) { + if (other.getHasProperty((Enum)flag)) { + setHasProperty((Enum)flag, true); + } } + return *this; +} +template inline PropertyFlags& PropertyFlags::operator<<=(Enum flag) { + setHasProperty(flag, true); return *this; } @@ -318,6 +369,18 @@ template inline PropertyFlags PropertyFlags::operator return result; } +template inline PropertyFlags PropertyFlags::operator+(PropertyFlags other) const { + PropertyFlags result(*this); + result += other; + return result; +} + +template inline PropertyFlags PropertyFlags::operator+(Enum flag) const { + PropertyFlags result(*this); + result.setHasProperty(flag, true); + return result; +} + template inline PropertyFlags PropertyFlags::operator-(PropertyFlags other) const { PropertyFlags result(*this); result -= other; @@ -330,6 +393,25 @@ template inline PropertyFlags PropertyFlags::operator return result; } +template inline PropertyFlags PropertyFlags::operator<<(PropertyFlags other) const { + PropertyFlags result(*this); + result <<= other; + return result; +} + +template inline PropertyFlags PropertyFlags::operator<<(Enum flag) const { + PropertyFlags result(*this); + result.setHasProperty(flag, true); + return result; +} + +template inline PropertyFlags PropertyFlags::operator~() const { + PropertyFlags result(*this); + result._flags = ~_flags; + result._trailingFlipped = !_trailingFlipped; + return result; +} + template inline void PropertyFlags::shinkIfNeeded() { bool maxFlagWas = _maxFlag; while (_maxFlag >= 0) { @@ -343,8 +425,6 @@ template inline void PropertyFlags::shinkIfNeeded() { } } - - /*** BitArr.resize(8*byteArr.count()); diff --git a/tests/octree/src/OctreeTests.cpp b/tests/octree/src/OctreeTests.cpp index 1a66a0b2ae..7143e6ca7a 100644 --- a/tests/octree/src/OctreeTests.cpp +++ b/tests/octree/src/OctreeTests.cpp @@ -66,7 +66,7 @@ void OctreeTests::propertyFlagsTests() { qDebug() << "OctreeTests::propertyFlagsTests()"; { - qDebug() << "Test 1: ModelProperties: PROP_VISIBLE, PROP_POSITION, PROP_RADIUS, PROP_MODEL_URL, PROP_ROTATION"; + qDebug() << "Test 1: ModelProperties: using setHasProperty()"; ModelPropertyFlags props; props.setHasProperty(PROP_VISIBLE); props.setHasProperty(PROP_POSITION); @@ -81,8 +81,7 @@ void OctreeTests::propertyFlagsTests() { } { - qDebug() << "Test 2: ParticlePropertyFlags: PROP_VISIBLE, PARTICLE_PROP_ANIMATION_URL, PARTICLE_PROP_ANIMATION_FPS, " - "PARTICLE_PROP_ANIMATION_FRAME_INDEX, PARTICLE_PROP_ANIMATION_PLAYING, PARTICLE_PROP_PAUSE_SIMULATION"; + qDebug() << "Test 2: ParticlePropertyFlags: using setHasProperty()"; ParticlePropertyFlags props2; props2.setHasProperty(PARTICLE_PROP_VISIBLE); props2.setHasProperty(PARTICLE_PROP_ANIMATION_URL); @@ -130,11 +129,245 @@ void OctreeTests::propertyFlagsTests() { qDebug() << "encoded="; outputBufferBits((const unsigned char*)encoded.constData(), encoded.size()); + } + + { + qDebug() << "Test 3c: ParticlePropertyFlags: using |= operator"; + ParticlePropertyFlags props; + + props |= PARTICLE_PROP_VISIBLE; + props |= PARTICLE_PROP_ANIMATION_URL; + props |= PARTICLE_PROP_ANIMATION_FPS; + props |= PARTICLE_PROP_ANIMATION_FRAME_INDEX; + props |= PARTICLE_PROP_ANIMATION_PLAYING; + props |= PARTICLE_PROP_PAUSE_SIMULATION; + + QByteArray encoded = props.encode(); + + qDebug() << "encoded="; + outputBufferBits((const unsigned char*)encoded.constData(), encoded.size()); + } + + { + qDebug() << "Test 4: ParticlePropertyFlags: using + operator"; + ParticlePropertyFlags props; + + props = ParticlePropertyFlags(PARTICLE_PROP_VISIBLE) + + ParticlePropertyFlags(PARTICLE_PROP_ANIMATION_URL) + + ParticlePropertyFlags(PARTICLE_PROP_ANIMATION_FPS) + + ParticlePropertyFlags(PARTICLE_PROP_ANIMATION_FRAME_INDEX) + + ParticlePropertyFlags(PARTICLE_PROP_ANIMATION_PLAYING) + + ParticlePropertyFlags(PARTICLE_PROP_PAUSE_SIMULATION); + + QByteArray encoded = props.encode(); + + qDebug() << "encoded="; + outputBufferBits((const unsigned char*)encoded.constData(), encoded.size()); + } + + { + qDebug() << "Test 4b: ParticlePropertyFlags: using += operator"; + ParticlePropertyFlags props; + + props += PARTICLE_PROP_VISIBLE; + props += PARTICLE_PROP_ANIMATION_URL; + props += PARTICLE_PROP_ANIMATION_FPS; + props += PARTICLE_PROP_ANIMATION_FRAME_INDEX; + props += PARTICLE_PROP_ANIMATION_PLAYING; + props += PARTICLE_PROP_PAUSE_SIMULATION; + + QByteArray encoded = props.encode(); + + qDebug() << "encoded="; + outputBufferBits((const unsigned char*)encoded.constData(), encoded.size()); + } + + { + qDebug() << "Test 5: ParticlePropertyFlags: using = ... << operator"; + ParticlePropertyFlags props; + + props = ParticlePropertyFlags(PARTICLE_PROP_VISIBLE) + << ParticlePropertyFlags(PARTICLE_PROP_ANIMATION_URL) + << ParticlePropertyFlags(PARTICLE_PROP_ANIMATION_FPS) + << ParticlePropertyFlags(PARTICLE_PROP_ANIMATION_FRAME_INDEX) + << ParticlePropertyFlags(PARTICLE_PROP_ANIMATION_PLAYING) + << ParticlePropertyFlags(PARTICLE_PROP_PAUSE_SIMULATION); + + QByteArray encoded = props.encode(); + + qDebug() << "encoded="; + outputBufferBits((const unsigned char*)encoded.constData(), encoded.size()); + } + + { + qDebug() << "Test 5b: ParticlePropertyFlags: using <<= operator"; + ParticlePropertyFlags props; + + props <<= PARTICLE_PROP_VISIBLE; + props <<= PARTICLE_PROP_ANIMATION_URL; + props <<= PARTICLE_PROP_ANIMATION_FPS; + props <<= PARTICLE_PROP_ANIMATION_FRAME_INDEX; + props <<= PARTICLE_PROP_ANIMATION_PLAYING; + props <<= PARTICLE_PROP_PAUSE_SIMULATION; + + QByteArray encoded = props.encode(); + + qDebug() << "encoded="; + outputBufferBits((const unsigned char*)encoded.constData(), encoded.size()); + } + + { + qDebug() << "Test 5c: ParticlePropertyFlags: using << enum operator"; + ParticlePropertyFlags props; + + props << PARTICLE_PROP_VISIBLE; + props << PARTICLE_PROP_ANIMATION_URL; + props << PARTICLE_PROP_ANIMATION_FPS; + props << PARTICLE_PROP_ANIMATION_FRAME_INDEX; + props << PARTICLE_PROP_ANIMATION_PLAYING; + props << PARTICLE_PROP_PAUSE_SIMULATION; + + QByteArray encoded = props.encode(); + + qDebug() << "encoded="; + outputBufferBits((const unsigned char*)encoded.constData(), encoded.size()); + } + + { + qDebug() << "Test 5d: ParticlePropertyFlags: using << flags operator "; + ParticlePropertyFlags props; + ParticlePropertyFlags props2; + + props << PARTICLE_PROP_VISIBLE; + props << PARTICLE_PROP_ANIMATION_URL; + props << PARTICLE_PROP_ANIMATION_FPS; + + props2 << PARTICLE_PROP_ANIMATION_FRAME_INDEX; + props2 << PARTICLE_PROP_ANIMATION_PLAYING; + props2 << PARTICLE_PROP_PAUSE_SIMULATION; + + props << props2; + + QByteArray encoded = props.encode(); + + qDebug() << "encoded="; + outputBufferBits((const unsigned char*)encoded.constData(), encoded.size()); + } + + { + qDebug() << "Test 6: ParticlePropertyFlags comparison"; + ParticlePropertyFlags propsA; + + qDebug() << "!propsA:" << (!propsA) << "{ expect true }"; + + propsA << PARTICLE_PROP_VISIBLE; + propsA << PARTICLE_PROP_ANIMATION_URL; + propsA << PARTICLE_PROP_ANIMATION_FPS; + propsA << PARTICLE_PROP_ANIMATION_FRAME_INDEX; + propsA << PARTICLE_PROP_ANIMATION_PLAYING; + propsA << PARTICLE_PROP_PAUSE_SIMULATION; + + qDebug() << "!propsA:" << (!propsA) << "{ expect false }"; + + ParticlePropertyFlags propsB; + qDebug() << "!propsB:" << (!propsB) << "{ expect true }"; + + + propsB << PARTICLE_PROP_VISIBLE; + propsB << PARTICLE_PROP_ANIMATION_URL; + propsB << PARTICLE_PROP_ANIMATION_FPS; + propsB << PARTICLE_PROP_ANIMATION_FRAME_INDEX; + propsB << PARTICLE_PROP_ANIMATION_PLAYING; + propsB << PARTICLE_PROP_PAUSE_SIMULATION; + + qDebug() << "!propsB:" << (!propsB) << "{ expect false }"; + + qDebug() << "propsA == propsB:" << (propsA == propsB) << "{ expect true }"; + qDebug() << "propsA != propsB:" << (propsA != propsB) << "{ expect false }"; + + + qDebug() << "AFTER propsB -= PARTICLE_PROP_PAUSE_SIMULATION..."; + propsB -= PARTICLE_PROP_PAUSE_SIMULATION; + + qDebug() << "propsA == propsB:" << (propsA == propsB) << "{ expect false }"; + qDebug() << "propsA != propsB:" << (propsA != propsB) << "{ expect true }"; + + qDebug() << "AFTER propsB = propsA..."; + propsB = propsA; + + qDebug() << "propsA == propsB:" << (propsA == propsB) << "{ expect true }"; + qDebug() << "propsA != propsB:" << (propsA != propsB) << "{ expect false }"; } + { + qDebug() << "Test 7: ParticlePropertyFlags testing individual properties"; + ParticlePropertyFlags props; + + qDebug() << "ParticlePropertyFlags props;"; + QByteArray encoded = props.encode(); + qDebug() << "props... encoded="; + outputBufferBits((const unsigned char*)encoded.constData(), encoded.size()); + + qDebug() << "props.getHasProperty(PARTICLE_PROP_VISIBLE)" << (props.getHasProperty(PARTICLE_PROP_VISIBLE)) + << "{ expect false }"; + + qDebug() << "props << PARTICLE_PROP_VISIBLE;"; + props << PARTICLE_PROP_VISIBLE; + + encoded = props.encode(); + qDebug() << "props... encoded="; + outputBufferBits((const unsigned char*)encoded.constData(), encoded.size()); + qDebug() << "props.getHasProperty(PARTICLE_PROP_VISIBLE)" << (props.getHasProperty(PARTICLE_PROP_VISIBLE)) + << "{ expect true }"; + + qDebug() << "props << PARTICLE_PROP_ANIMATION_URL;"; + props << PARTICLE_PROP_ANIMATION_URL; + + encoded = props.encode(); + qDebug() << "props... encoded="; + outputBufferBits((const unsigned char*)encoded.constData(), encoded.size()); + qDebug() << "props.getHasProperty(PARTICLE_PROP_VISIBLE)" << (props.getHasProperty(PARTICLE_PROP_VISIBLE)) + << "{ expect true }"; + + qDebug() << "props << ... more ..."; + props << PARTICLE_PROP_ANIMATION_FPS; + props << PARTICLE_PROP_ANIMATION_FRAME_INDEX; + props << PARTICLE_PROP_ANIMATION_PLAYING; + props << PARTICLE_PROP_PAUSE_SIMULATION; + + encoded = props.encode(); + qDebug() << "props... encoded="; + outputBufferBits((const unsigned char*)encoded.constData(), encoded.size()); + qDebug() << "props.getHasProperty(PARTICLE_PROP_VISIBLE)" << (props.getHasProperty(PARTICLE_PROP_VISIBLE)) + << "{ expect true }"; + + qDebug() << "ParticlePropertyFlags propsB = props & PARTICLE_PROP_VISIBLE;"; + ParticlePropertyFlags propsB = props & PARTICLE_PROP_VISIBLE; + + qDebug() << "propsB.getHasProperty(PARTICLE_PROP_VISIBLE)" << (propsB.getHasProperty(PARTICLE_PROP_VISIBLE)) + << "{ expect true }"; + + encoded = propsB.encode(); + qDebug() << "propsB... encoded="; + outputBufferBits((const unsigned char*)encoded.constData(), encoded.size()); + + qDebug() << "propsB..."; + propsB.debugDumpBits(); + + qDebug() << "ParticlePropertyFlags propsC = ~propsB;"; + ParticlePropertyFlags propsC = ~propsB; + qDebug() << "propsC..."; + propsC.debugDumpBits(); + + qDebug() << "propsC.getHasProperty(PARTICLE_PROP_VISIBLE)" << (propsC.getHasProperty(PARTICLE_PROP_VISIBLE)) + << "{ expect false }"; + + encoded = propsC.encode(); + qDebug() << "propsC... encoded="; + outputBufferBits((const unsigned char*)encoded.constData(), encoded.size()); + } - qDebug() << "******************************************************************************************"; }