Skip to content

Conversation

@marc-mabe
Copy link
Owner

Based on #108

  • implements EnumSet as immutable
  • attach(): void -> withEnumerator(): self
  • detach(): void -> withoutEnumerator(): self
  • setBit(): void -> withBit(): self
  • setBinaryBitset[Le|Be](): void -> withBinaryBitset[Le|Be](): self

PS 1: I still want to make some benchmarks for comparison
PS 2: This make sense only if we make EnumMap immutable too

@prolic ping

@marc-mabe marc-mabe added this to the 4.0.0 milestone Feb 6, 2019
@marc-mabe marc-mabe changed the base branch from master to 4.x February 6, 2019 20:31
Copy link
Collaborator

@prolic prolic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me.
Maybe it's also not too unreasonable to have EnumSet/Map and EnumSet/Map-Immutable classes, similar to DateTime and DateTimeImmutable, so users have the choice to use what they prefer. I'd say immutable is always to prefer because it doesn't come with side-effects which can lead to tricky bugs, but no one listens to me anyway :)

@marc-mabe
Copy link
Owner Author

I'm not entirely sure about this. It would make sense only if both classes implement the same Interface. This means the interface would not make sure to handle immutable and mutable objects - in with DateTime and DateTimeImmutable.

Let's fist see what are the performance differences

@marc-mabe
Copy link
Owner Author

Here is the full benchmark: master -> 4.x -> 4.x (+ IteratorAggregate) -> 4.x (+IteratorAggregate + Immutable EnumSet)

+----------------+------------------------------+-----------------+--------------+--------------------------------+------------------------------------------+
| benchmark      | subject                      | tag:master:mean | tag:4.x:mean | tag:4.x_IteratorAggregate:mean | tag:4.x_IteratorAggregate_immutable:mean |
+----------------+------------------------------+-----------------+--------------+--------------------------------+------------------------------------------+
| EnumSet66Bench | benchAttachEnumeratorOnEmpty | 29.287μs        | 31.747μs     | 31.912μs                       | 41.938μs                                 |
| EnumSet66Bench | benchAttachValueOnEmpty      | 58.118μs        | 58.716μs     | 58.838μs                       | 74.214μs                                 |
| EnumSet66Bench | benchAttachEnumeratorOnFull  | 29.245μs        | 31.112μs     | 31.922μs                       | 41.867μs                                 |
| EnumSet66Bench | benchAttachValueOnFull       | 58.395μs        | 58.506μs     | 59.010μs                       | 73.980μs                                 |
| EnumSet66Bench | benchDetachEnumeratorOnEmpty | 30.443μs        | 30.084μs     | 30.228μs                       | 42.689μs                                 |
| EnumSet66Bench | benchDetachValueOnEmpty      | 59.323μs        | 59.440μs     | 59.819μs                       | 76.255μs                                 |
| EnumSet66Bench | benchDetachEnumeratorOnFull  | 30.418μs        | 30.235μs     | 30.526μs                       | 42.723μs                                 |
| EnumSet66Bench | benchDetachValueOnFull       | 59.539μs        | 59.155μs     | 59.367μs                       | 76.757μs                                 |
| EnumSet66Bench | benchContainsEnumeratorTrue  | 26.574μs        | 31.840μs     | 32.317μs                       | 31.927μs                                 |
| EnumSet66Bench | benchContainsValueTrue       | 55.635μs        | 58.691μs     | 58.582μs                       | 58.467μs                                 |
| EnumSet66Bench | benchContainsEnumeratorFalse | 26.448μs        | 31.883μs     | 31.790μs                       | 31.744μs                                 |
| EnumSet66Bench | benchContainsValueFalse      | 55.874μs        | 58.790μs     | 58.554μs                       | 58.662μs                                 |
| EnumSet66Bench | benchIterateFull             | 82.415μs        | 87.251μs     | 108.648μs                      | 108.792μs                                |
| EnumSet66Bench | benchIterateEmpty            | 0.554μs         | 0.574μs      | 19.426μs                       | 19.201μs                                 |
| EnumSet66Bench | benchCountFull               | 1.445μs         | 1.493μs      | 1.495μs                        | 1.504μs                                  |
| EnumSet66Bench | benchCountEmpty              | 0.366μs         | 0.397μs      | 0.397μs                        | 0.393μs                                  |
| EnumSet66Bench | benchIsEqual                 | 0.127μs         | 0.132μs      | 0.132μs                        | 0.132μs                                  |
| EnumSet66Bench | benchIsSubset                | 0.127μs         | 0.132μs      | 0.132μs                        | 0.132μs                                  |
| EnumSet66Bench | benchIsSuperset              | 0.167μs         | 0.178μs      | 0.177μs                        | 0.179μs                                  |
| EnumSet66Bench | benchUnion                   | 0.265μs         | 0.277μs      | 0.266μs                        | 0.267μs                                  |
| EnumSet66Bench | benchIntersect               | 0.261μs         | 0.274μs      | 0.263μs                        | 0.262μs                                  |
| EnumSet66Bench | benchDiff                    | 0.291μs         | 0.300μs      | 0.288μs                        | 0.292μs                                  |
| EnumSet66Bench | benchSymDiff                 | 0.263μs         | 0.272μs      | 0.262μs                        | 0.263μs                                  |
| EnumSet66Bench | benchGetOrdinalsFull         | 3.474μs         | 3.544μs      | 3.573μs                        | 3.529μs                                  |
| EnumSet66Bench | benchGetOrdinalsEmpty        | 0.377μs         | 0.405μs      | 0.402μs                        | 0.402μs                                  |
| EnumSet66Bench | benchGetValues               | 33.699μs        | 34.179μs     | 34.183μs                       | 34.057μs                                 |
| EnumSet66Bench | benchGetNames                | 37.440μs        | 38.139μs     | 38.276μs                       | 38.297μs                                 |
| EnumSet66Bench | benchGetEnumerators          | 31.761μs        | 32.128μs     | 32.283μs                       | 32.001μs                                 |
| EnumBench      | benchGetName                 | 6.588μs         | 5.782μs      |                                |                                          |
| EnumBench      | benchGetValue                | 2.656μs         | 2.666μs      |                                |                                          |
| EnumBench      | benchGetOrdinal              | 3.392μs         | 3.845μs      |                                |                                          |
| EnumBench      | benchIsByEnumerator          | 3.646μs         | 4.017μs      |                                |                                          |
| EnumBench      | benchIsByValue               | 6.419μs         | 6.724μs      |                                |                                          |
| EnumBench      | benchDetectConstants         | 86.766μs        | 85.821μs     |                                |                                          |
| EnumBench      | benchGetValues               | 0.380μs         | 0.399μs      |                                |                                          |
| EnumBench      | benchGetNames                | 0.125μs         | 0.131μs      |                                |                                          |
| EnumBench      | benchGetOrdinals             | 0.395μs         | 0.413μs      |                                |                                          |
| EnumBench      | benchGetEnumerators          | 11.989μs        | 11.760μs     |                                |                                          |
| EnumBench      | benchByValue                 | 28.830μs        | 29.518μs     |                                |                                          |
| EnumBench      | benchByValueAndInitialize    | 5,806.739μs     | 5,737.836μs  |                                |                                          |
| EnumBench      | benchByValueAndInstantiate   | 45.060μs        | 47.239μs     |                                |                                          |
| EnumBench      | benchByName                  | 9.749μs         | 10.237μs     |                                |                                          |
| EnumBench      | benchByNameAndInitialize     | 73.459μs        | 73.974μs     |                                |                                          |
| EnumBench      | benchByNameAndInstantiate    | 45.595μs        | 47.311μs     |                                |                                          |
| EnumBench      | benchByOrdinal               | 20.823μs        | 21.465μs     |                                |                                          |
| EnumBench      | benchByOrdinalAndInitialize  | 5,823.510μs     | 5,730.373μs  |                                |                                          |
| EnumBench      | benchByOrdinalAndInstantiate | 32.234μs        | 35.153μs     |                                |                                          |
| EnumBench      | benchGetByValues             | 31.191μs        | 32.522μs     |                                |                                          |
| EnumBench      | benchGetByEnumerator         | 4.712μs         | 5.468μs      |                                |                                          |
| EnumBench      | benchGetByCallStatic         | 18.200μs        | 20.783μs     |                                |                                          |
| EnumBench      | benchHasByEnumerator         | 4.599μs         | 5.191μs      |                                |                                          |
| EnumBench      | benchHasByValue              | 21.604μs        | 26.806μs     |                                |                                          |
| EnumSet32Bench | benchAttachEnumerator        | 10.562μs        | 11.244μs     | 11.198μs                       | 14.889μs                                 |
| EnumSet32Bench | benchAttachValue             | 21.685μs        | 22.114μs     | 22.232μs                       | 27.641μs                                 |
| EnumSet32Bench | benchDetachEnumerator        | 10.788μs        | 11.335μs     | 11.529μs                       | 14.994μs                                 |
| EnumSet32Bench | benchDetachValue             | 21.999μs        | 22.602μs     | 22.463μs                       | 28.013μs                                 |
| EnumSet32Bench | benchContainsEnumeratorTrue  | 10.575μs        | 11.804μs     | 11.756μs                       | 11.773μs                                 |
| EnumSet32Bench | benchContainsEnumeratorFalse | 10.544μs        | 11.802μs     | 11.773μs                       | 11.782μs                                 |
| EnumSet32Bench | benchContainsValueTrue       | 21.563μs        | 23.346μs     | 23.199μs                       | 23.186μs                                 |
| EnumSet32Bench | benchContainsValueFalse      | 21.615μs        | 23.257μs     | 23.307μs                       | 23.158μs                                 |
| EnumSet32Bench | benchIterateFull             | 33.523μs        | 35.523μs     | 46.422μs                       | 46.495μs                                 |
| EnumSet32Bench | benchIterateEmpty            | 0.401μs         | 0.416μs      | 7.837μs                        | 7.834μs                                  |
| EnumSet32Bench | benchCountFull               | 0.663μs         | 0.717μs      | 0.717μs                        | 0.720μs                                  |
| EnumSet32Bench | benchCountEmpty              | 0.193μs         | 0.207μs      | 0.208μs                        | 0.208μs                                  |
| EnumSet32Bench | benchIsEqual                 | 0.159μs         | 0.165μs      | 0.164μs                        | 0.164μs                                  |
| EnumSet32Bench | benchIsSubset                | 0.159μs         | 0.165μs      | 0.164μs                        | 0.164μs                                  |
| EnumSet32Bench | benchIsSuperset              | 0.144μs         | 0.159μs      | 0.159μs                        | 0.160μs                                  |
| EnumSet32Bench | benchUnion                   | 0.260μs         | 0.263μs      | 0.253μs                        | 0.253μs                                  |
| EnumSet32Bench | benchIntersect               | 0.257μs         | 0.264μs      | 0.253μs                        | 0.257μs                                  |
| EnumSet32Bench | benchDiff                    | 0.256μs         | 0.264μs      | 0.255μs                        | 0.257μs                                  |
| EnumSet32Bench | benchSymDiff                 | 0.254μs         | 0.266μs      | 0.254μs                        | 0.254μs                                  |
| EnumSet32Bench | benchGetOrdinalsFull         | 1.181μs         | 1.240μs      | 1.228μs                        | 1.237μs                                  |
| EnumSet32Bench | benchGetOrdinalsEmpty        | 0.707μs         | 0.723μs      | 0.722μs                        | 0.719μs                                  |
| EnumSet32Bench | benchGetValues               | 15.968μs        | 16.170μs     | 16.176μs                       | 16.176μs                                 |
| EnumSet32Bench | benchGetNames                | 17.735μs        | 18.261μs     | 18.228μs                       | 18.257μs                                 |
| EnumSet32Bench | benchGetEnumerators          | 14.946μs        | 15.354μs     | 15.308μs                       | 15.315μs                                 |
| EnumMapBench   | benchGetKeysEmpty            | 0.395μs         | 0.400μs      |                                |                                          |
| EnumMapBench   | benchGetKeysFull             | 23.008μs        | 22.944μs     |                                |                                          |
| EnumMapBench   | benchGetValuesEmpty          | 0.081μs         | 0.088μs      |                                |                                          |
| EnumMapBench   | benchGetValuesFull           | 0.082μs         | 0.089μs      |                                |                                          |
| EnumMapBench   | benchSearchTypeJuggling      | 1.418μs         | 1.458μs      |                                |                                          |
| EnumMapBench   | benchSearchStrict            | 0.671μs         | 0.718μs      |                                |                                          |
| EnumMapBench   | benchOffsetSetEnumerator     | 21.533μs        | 24.604μs     |                                |                                          |
| EnumMapBench   | benchOffsetSetValue          | 47.017μs        | 49.960μs     |                                |                                          |
| EnumMapBench   | benchOffsetUnsetEnumerator   | 18.890μs        | 19.882μs     |                                |                                          |
| EnumMapBench   | benchOffsetUnsetValue        | 45.957μs        | 47.261μs     |                                |                                          |
| EnumMapBench   | benchOffsetExistsEnumerator  | 17.477μs        | 18.851μs     |                                |                                          |
| EnumMapBench   | benchOffsetExistsValue       | 44.923μs        | 47.916μs     |                                |                                          |
| EnumMapBench   | benchContainsEnumerator      | 19.162μs        | 22.397μs     |                                |                                          |
| EnumMapBench   | benchContainsValue           | 45.832μs        | 47.982μs     |                                |                                          |
| EnumMapBench   | benchIterateFull             | 56.906μs        | 58.628μs     |                                |                                          |
| EnumMapBench   | benchIterateEmpty            | 0.219μs         | 0.224μs      |                                |                                          |
| EnumMapBench   | benchCountFull               | 0.086μs         | 0.090μs      |                                |                                          |
| EnumMapBench   | benchCountEmpty              | 0.086μs         | 0.090μs      |                                |                                          |
+----------------+------------------------------+-----------------+--------------+--------------------------------+------------------------------------------+

For me it tells me I should check where all the performance degrations comes from.

  • For master -> 4.x it could be based on type-hints - I'll check if I can remove at least some of them - they are documented anyway and this lib does extensible testing.
  • For IteratorAggregate it seams clear that this approach is much slower then a direct Iterator. It was clear from the beginning but the difference is a lot. I'll do some tests with generators now
  • For immutable EnumSet - this was expected and does not seem too bad. I'll also add a methods to add/remove enumerators based on a given iterable and also think of accepting this as constructor argument as then the with[out]Enumerator methods should be needed in much rare cases.

@marc-mabe marc-mabe force-pushed the immutable-set branch 7 times, most recently from ad8f316 to 209f028 Compare February 24, 2019 11:20
@marc-mabe
Copy link
Owner Author

@prolic It's ready now :)

I decided to have both mutable and immutable interfaces but with consistent naming:

  • Added second constructor argument to initialize an EnumSet with an iterable list of enumerators
  • renamed [attach|detach] -> [attach|detach]Enumerator
  • added [attach|detach]Enumerators
  • added withEnumerator & withEnumerators
  • added withoutEnumerator & withoutEnumerators
  • added withBinaryBitset[Le|Be]
  • added withBit
  • rename union -> withUnion
  • added setUnion
  • rename intersect -> withIntersect
  • added setIntersect
  • rename diff -> withDiff
  • added setDiff
  • rename symDiff -> withSymDiff
  • added setSymDiff

Copy link
Collaborator

@prolic prolic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sorry for being late on this one, was moving around the globe. just one small remark.

@marc-mabe marc-mabe changed the title [WIP] Immutable EnumSet Immutable EnumSet Mar 10, 2019
@marc-mabe marc-mabe merged commit ac334b1 into 4.x Mar 10, 2019
@marc-mabe marc-mabe deleted the immutable-set branch March 10, 2019 20:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants