diff --git a/src/FlagSetTrait.php b/src/FlagSetTrait.php index 2865008..097bd34 100644 --- a/src/FlagSetTrait.php +++ b/src/FlagSetTrait.php @@ -143,6 +143,8 @@ public function __get($name) /** * Get a string representation of the flag set. + * + * @return string The string representation. */ public function __toString() { @@ -172,6 +174,89 @@ public function __set($name, $value) throw new LogicException('Flag-sets are immutable.'); } + /** + * Compute the difference of flag-sets. + * + * @param self $other The other flag set to compare to. + * + * @return self A flag-set of the flags in $this and not in $other. + */ + public function diff(self $other) + { + $result = new self(); + foreach (self::$__flags as $flag) { + $result->{$flag} = $this->{$flag} && !$other->{$flag}; + } + + return $result; + } + + /** + * Compute the symmetric difference of flag-sets. + * + * @param self $other The other flag set to compare to. + * + * @return self A flag-set of the flags in $this and not in $other, and vice versa. + */ + public function symmetricDiff(self $other) + { + $result = new self(); + foreach (self::$__flags as $flag) { + $result->{$flag} = $this->{$flag} !== $other->{$flag}; + } + + return $result; + } + + /** + * Compute the intersection of flag-sets. + * + * @param self $other The other flag set to intersect with. + * + * @return self A flag-set of the flags in $this and $other. + */ + public function intersect(self $other) + { + $result = new self(); + foreach (self::$__flags as $flag) { + $result->{$flag} = $this->{$flag} && $other->{$flag}; + } + + return $result; + } + + /** + * Compute the union of flag-sets. + * + * @param self $other The other flag set to union with. + * + * @return self A flag-set of the flags in $this or $other. + */ + public function union(self $other) + { + $result = new self(); + foreach (self::$__flags as $flag) { + $result->{$flag} = $this->{$flag} || $other->{$flag}; + } + + return $result; + } + + /** + * Compute the inverse of this flag set. + * + * @return self The inverse of the flags in this flag-set. + */ + public function inverse() + { + $result = new self(); + foreach (self::$__flags as $flag) { + $result->{$flag} = !$this->{$flag}; + } + + return $result; + } + private function __construct() { if (null === self::$__flags) { diff --git a/test/suite/FlagSetTraitTest.php b/test/suite/FlagSetTraitTest.php index 0bb728c..c7d1e3a 100644 --- a/test/suite/FlagSetTraitTest.php +++ b/test/suite/FlagSetTraitTest.php @@ -140,4 +140,142 @@ public function testToString() strval(TestFlags::defaults()) ); } + + public function testDiff() + { + $defaults = TestFlags::defaults(); + + // diff to same + $flags = $defaults->diff( + $defaults + ); + $this->assertFalse($flags->foo); + $this->assertFalse($flags->bar); + $this->assertFalse($flags->baz); + $this->assertFalse($flags->qux); + + // diff to all + $flags = $defaults->diff( + TestFlags::all() + ); + $this->assertFalse($flags->foo); + $this->assertFalse($flags->bar); + $this->assertFalse($flags->baz); + $this->assertFalse($flags->qux); + + // diff to none + $flags = $defaults->diff( + TestFlags::none() + ); + $this->assertTrue($flags->foo); + $this->assertFalse($flags->bar); + $this->assertTrue($flags->baz); + $this->assertFalse($flags->qux); + } + + public function testSymmetricDiff() + { + $defaults = TestFlags::defaults(); + + // symmetric diff to same + $flags = $defaults->symmetricDiff( + $defaults + ); + $this->assertFalse($flags->foo); + $this->assertFalse($flags->bar); + $this->assertFalse($flags->baz); + $this->assertFalse($flags->qux); + + // symmetric diff to all + $flags = $defaults->symmetricDiff( + TestFlags::all() + ); + $this->assertFalse($flags->foo); + $this->assertTrue($flags->bar); + $this->assertFalse($flags->baz); + $this->assertTrue($flags->qux); + + // symmetric diff to none + $flags = $defaults->symmetricDiff( + TestFlags::none() + ); + $this->assertTrue($flags->foo); + $this->assertFalse($flags->bar); + $this->assertTrue($flags->baz); + $this->assertFalse($flags->qux); + } + + public function testIntersect() + { + $defaults = TestFlags::defaults(); + + // intersect to same + $flags = $defaults->intersect( + $defaults + ); + $this->assertTrue($flags->foo); + $this->assertFalse($flags->bar); + $this->assertTrue($flags->baz); + $this->assertFalse($flags->qux); + + // intersect to all + $flags = $defaults->intersect( + TestFlags::all() + ); + $this->assertTrue($flags->foo); + $this->assertFalse($flags->bar); + $this->assertTrue($flags->baz); + $this->assertFalse($flags->qux); + + // intersect to none + $flags = $defaults->intersect( + TestFlags::none() + ); + $this->assertFalse($flags->foo); + $this->assertFalse($flags->bar); + $this->assertFalse($flags->baz); + $this->assertFalse($flags->qux); + } + + public function testUnion() + { + $defaults = TestFlags::defaults(); + + // union to same + $flags = $defaults->union( + $defaults + ); + $this->assertTrue($flags->foo); + $this->assertFalse($flags->bar); + $this->assertTrue($flags->baz); + $this->assertFalse($flags->qux); + + // union to all + $flags = $defaults->union( + TestFlags::all() + ); + $this->assertTrue($flags->foo); + $this->assertTrue($flags->bar); + $this->assertTrue($flags->baz); + $this->assertTrue($flags->qux); + + // union to none + $flags = $defaults->union( + TestFlags::none() + ); + $this->assertTrue($flags->foo); + $this->assertFalse($flags->bar); + $this->assertTrue($flags->baz); + $this->assertFalse($flags->qux); + } + + public function testInverse() + { + $flags = TestFlags::defaults()->inverse(); + + $this->assertFalse($flags->foo); + $this->assertTrue($flags->bar); + $this->assertFalse($flags->baz); + $this->assertTrue($flags->qux); + } }