Skip to content

Commit 4c41ffe

Browse files
committed
Immutable EnumSet
1 parent a1813f9 commit 4c41ffe

File tree

5 files changed

+153
-151
lines changed

5 files changed

+153
-151
lines changed

bench/EnumSet32Bench.php

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,35 +50,35 @@ public function init()
5050
$this->emptySet = new EnumSet(Enum32::class);
5151
$this->fullSet = new EnumSet(Enum32::class);
5252
foreach ($this->enumerators as $enumerator) {
53-
$this->fullSet->attach($enumerator);
53+
$this->fullSet = $this->fullSet->withEnumerator($enumerator);
5454
}
5555
}
5656

5757
public function benchAttachEnumerator()
5858
{
5959
foreach ($this->enumerators as $enumerator) {
60-
$this->emptySet->attach($enumerator);
60+
$this->emptySet->withEnumerator($enumerator);
6161
}
6262
}
6363

6464
public function benchAttachValue()
6565
{
6666
foreach ($this->values as $value) {
67-
$this->emptySet->attach($value);
67+
$this->emptySet->withEnumerator($value);
6868
}
6969
}
7070

7171
public function benchDetachEnumerator()
7272
{
7373
foreach ($this->enumerators as $enumerator) {
74-
$this->fullSet->detach($enumerator);
74+
$this->fullSet->withoutEnumerator($enumerator);
7575
}
7676
}
7777

7878
public function benchDetachValue()
7979
{
8080
foreach ($this->values as $value) {
81-
$this->fullSet->detach($value);
81+
$this->fullSet->withoutEnumerator($value);
8282
}
8383
}
8484

bench/EnumSet66Bench.php

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -50,63 +50,63 @@ public function init()
5050
$this->emptySet = new EnumSet(Enum66::class);
5151
$this->fullSet = new EnumSet(Enum66::class);
5252
foreach ($this->enumerators as $enumerator) {
53-
$this->fullSet->attach($enumerator);
53+
$this->fullSet = $this->fullSet->withEnumerator($enumerator);
5454
}
5555
}
5656

5757
public function benchAttachEnumeratorOnEmpty()
5858
{
5959
foreach ($this->enumerators as $enumerator) {
60-
$this->emptySet->attach($enumerator);
60+
$this->emptySet->withEnumerator($enumerator);
6161
}
6262
}
6363

6464
public function benchAttachValueOnEmpty()
6565
{
6666
foreach ($this->values as $value) {
67-
$this->emptySet->attach($value);
67+
$this->emptySet->withEnumerator($value);
6868
}
6969
}
7070

7171
public function benchAttachEnumeratorOnFull()
7272
{
7373
foreach ($this->enumerators as $enumerator) {
74-
$this->fullSet->attach($enumerator);
74+
$this->fullSet->withEnumerator($enumerator);
7575
}
7676
}
7777

7878
public function benchAttachValueOnFull()
7979
{
8080
foreach ($this->values as $value) {
81-
$this->fullSet->attach($value);
81+
$this->fullSet->withEnumerator($value);
8282
}
8383
}
8484

8585
public function benchDetachEnumeratorOnEmpty()
8686
{
8787
foreach ($this->enumerators as $enumerator) {
88-
$this->emptySet->detach($enumerator);
88+
$this->emptySet->withoutEnumerator($enumerator);
8989
}
9090
}
9191

9292
public function benchDetachValueOnEmpty()
9393
{
9494
foreach ($this->values as $value) {
95-
$this->emptySet->detach($value);
95+
$this->emptySet->withoutEnumerator($value);
9696
}
9797
}
9898

9999
public function benchDetachEnumeratorOnFull()
100100
{
101101
foreach ($this->enumerators as $enumerator) {
102-
$this->fullSet->detach($enumerator);
102+
$this->fullSet->withoutEnumerator($enumerator);
103103
}
104104
}
105105

106106
public function benchDetachValueOnFull()
107107
{
108108
foreach ($this->values as $value) {
109-
$this->fullSet->detach($value);
109+
$this->fullSet->withoutEnumerator($value);
110110
}
111111
}
112112

src/EnumSet.php

Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -103,29 +103,33 @@ public function getEnumeration(): string
103103
}
104104

105105
/**
106-
* Attach a new enumerator or overwrite an existing one
106+
* Adds the given enumerator
107107
* @param Enum|null|bool|int|float|string|array $enumerator
108-
* @return void
108+
* @return static
109109
* @throws InvalidArgumentException On an invalid given enumerator
110110
*/
111-
public function attach($enumerator): void
111+
public function withEnumerator($enumerator): self
112112
{
113-
$this->{$this->fnDoSetBit}(($this->enumeration)::get($enumerator)->getOrdinal());
113+
$clone = clone $this;
114+
$clone->{$this->fnDoSetBit}(($this->enumeration)::get($enumerator)->getOrdinal());
115+
return $clone;
114116
}
115117

116118
/**
117-
* Detach the given enumerator
119+
* Removed an enumerator
118120
* @param Enum|null|bool|int|float|string|array $enumerator
119-
* @return void
121+
* @return static
120122
* @throws InvalidArgumentException On an invalid given enumerator
121123
*/
122-
public function detach($enumerator): void
124+
public function withoutEnumerator($enumerator): self
123125
{
124-
$this->{$this->fnDoUnsetBit}(($this->enumeration)::get($enumerator)->getOrdinal());
126+
$clone = clone $this;
127+
$clone->{$this->fnDoUnsetBit}(($this->enumeration)::get($enumerator)->getOrdinal());
128+
return $clone;
125129
}
126130

127131
/**
128-
* Test if the given enumerator was attached
132+
* Test if the given enumerator exists
129133
* @param Enum|null|bool|int|float|string|array $enumerator
130134
* @return bool
131135
*/
@@ -554,24 +558,22 @@ private function doGetBinaryBitsetLeInt(): string
554558
/**
555559
* Set binary bitset in little-endian order
556560
*
557-
* NOTE: It resets the current position of the iterator
558-
*
559561
* @param string $bitset
560-
* @return void
562+
* @return static
561563
* @throws InvalidArgumentException On out-of-range bits given as input bitset
562564
* @uses doSetBinaryBitsetLeBin()
563565
* @uses doSetBinaryBitsetLeInt()
564566
*/
565-
public function setBinaryBitsetLe(string $bitset): void
567+
public function withBinaryBitsetLe(string $bitset): self
566568
{
567-
$this->{$this->fnDoSetBinaryBitsetLe}($bitset);
569+
$clone = clone $this;
570+
$clone->{$this->fnDoSetBinaryBitsetLe}($bitset);
571+
return $clone;
568572
}
569573

570574
/**
571575
* Set binary bitset in little-endian order
572576
*
573-
* NOTE: It resets the current position of the iterator
574-
*
575577
* @param string $bitset
576578
* @return void
577579
* @throws InvalidArgumentException On out-of-range bits given as input bitset
@@ -611,8 +613,6 @@ private function doSetBinaryBitsetLeBin(string $bitset): void
611613
/**
612614
* Set binary bitset in little-endian order
613615
*
614-
* NOTE: It resets the current position of the iterator
615-
*
616616
* @param string $bitset
617617
* @return void
618618
* @throws InvalidArgumentException On out-of-range bits given as input bitset
@@ -653,15 +653,13 @@ public function getBinaryBitsetBe(): string
653653
/**
654654
* Set binary bitset in big-endian order
655655
*
656-
* NOTE: It resets the current position of the iterator
657-
*
658656
* @param string $bitset
659-
* @return void
657+
* @return static
660658
* @throws InvalidArgumentException On out-of-range bits given as input bitset
661659
*/
662-
public function setBinaryBitsetBe(string $bitset): void
660+
public function withBinaryBitsetBe(string $bitset): self
663661
{
664-
$this->setBinaryBitsetLe(\strrev($bitset));
662+
return $this->withBinaryBitsetLe(\strrev($bitset));
665663
}
666664

667665
/**
@@ -717,24 +715,26 @@ private function doGetBitInt(int $ordinal): bool
717715
*
718716
* @param int $ordinal Ordinal number of bit to set
719717
* @param bool $bit The bit to set
720-
* @return void
718+
* @return static
721719
* @throws InvalidArgumentException If the given ordinal number is out-of-range
722720
* @uses doSetBitBin()
723721
* @uses doSetBitInt()
724722
* @uses doUnsetBitBin()
725723
* @uses doUnsetBitInt()
726724
*/
727-
public function setBit(int $ordinal, bool $bit): void
725+
public function withBit(int $ordinal, bool $bit): self
728726
{
729727
if ($ordinal < 0 || $ordinal > $this->enumerationCount) {
730728
throw new InvalidArgumentException("Ordinal number must be between 0 and {$this->enumerationCount}");
731729
}
732730

731+
$clone = clone $this;
733732
if ($bit) {
734-
$this->{$this->fnDoSetBit}($ordinal);
733+
$clone->{$this->fnDoSetBit}($ordinal);
735734
} else {
736-
$this->{$this->fnDoUnsetBit}($ordinal);
735+
$clone->{$this->fnDoUnsetBit}($ordinal);
737736
}
737+
return $clone;
738738
}
739739

740740
/**

tests/MabeEnumTest/EnumSetIteratorTest.php

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,9 @@ public function testIterateEmpty()
3434
public function testIterateOrdered()
3535
{
3636
$set = new EnumSet(EnumBasic::class);
37-
$set->attach(EnumBasic::FOUR);
38-
$set->attach(EnumBasic::TWO);
39-
$set->attach(EnumBasic::SEVEN);
37+
$set = $set->withEnumerator(EnumBasic::FOUR);
38+
$set = $set->withEnumerator(EnumBasic::TWO);
39+
$set = $set->withEnumerator(EnumBasic::SEVEN);
4040

4141
$this->assertSame([
4242
1 => EnumBasic::TWO(),
@@ -48,8 +48,8 @@ public function testIterateOrdered()
4848
public function testMultipleIterators()
4949
{
5050
$set = new EnumSet(EnumBasic::class);
51-
$set->attach(EnumBasic::ONE);
52-
$set->attach(EnumBasic::TWO);
51+
$set = $set->withEnumerator(EnumBasic::ONE);
52+
$set = $set->withEnumerator(EnumBasic::TWO);
5353

5454
$it1 = $set->getIterator();
5555
$it2 = $set->getIterator();
@@ -62,7 +62,7 @@ public function testMultipleIterators()
6262
public function testStartAtFirstValidPosition()
6363
{
6464
$set = new EnumSet(EnumBasic::class);
65-
$set->attach(EnumBasic::SEVEN);
65+
$set = $set->withEnumerator(EnumBasic::SEVEN);
6666

6767
$it = $set->getIterator();
6868
$this->assertSame(EnumBasic::SEVEN(), $it->current());
@@ -88,7 +88,7 @@ public function testNextCurrentOutOfRange(string $enumeration)
8888
$set = new EnumSet($enumeration);
8989
$count = count($enumeration::getConstants());
9090
$last = $enumeration::byOrdinal($count - 1);
91-
$set->attach($last);
91+
$set = $set->withEnumerator($last);
9292

9393
$it = $set->getIterator();
9494
$this->assertTrue($it->valid());

0 commit comments

Comments
 (0)