Chromium Code Reviews| Index: pkg/compiler/lib/src/util/enumset.dart |
| diff --git a/pkg/compiler/lib/src/util/enumset.dart b/pkg/compiler/lib/src/util/enumset.dart |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..1f2facf8615e6cb116354504b82b6b76cecddd59 |
| --- /dev/null |
| +++ b/pkg/compiler/lib/src/util/enumset.dart |
| @@ -0,0 +1,199 @@ |
| +// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file |
| +// for details. All rights reserved. Use of this source code is governed by a |
| +// BSD-style license that can be found in the LICENSE file. |
| + |
| +library dart2js.util.enumset; |
| + |
| +import 'dart:collection'; |
| + |
| +/// A set of enum values based on a bit mask of the shifted enum indices. |
| +abstract class EnumSet<E> { |
| + /// Creates an empty mutable set. |
| + factory EnumSet() = _EnumSet<E>; |
| + |
| + /// Creates a mutable set from the bit mask [value]. |
| + factory EnumSet.fromValue(int value) = _EnumSet<E>.fromValue; |
| + |
| + /// Creates an immutable set from the bit mask [value]. |
| + const factory EnumSet.fixed(int value) = _ConstEnumSet<E>; |
| + |
| + /// Create a set containing the [values]. If [fixed] is `true` the set is |
| + /// immutable. |
| + factory EnumSet.fromValues(Iterable<E> values, {bool fixed: false}) { |
| + if (fixed) { |
| + return new _ConstEnumSet<E>.fromValues(values); |
| + } else { |
| + return new _EnumSet<E>.fromValues(values); |
| + } |
| + } |
| + |
| + const EnumSet._(); |
| + |
| + /// The bit mask of the shifted indices for the enum values in this set. |
| + int get value; |
| + |
| + /// Adds [enumValue] to this set. |
| + void add(E enumValue); |
| + |
| + /// Removes [enumValue] from this set. |
| + void remove(E enumValue); |
| + |
| + /// Clears this set. |
| + void clear(); |
| + |
| + /// Returns `true` if [enumValue] is in this set. |
| + bool contains(E enumValue) { |
| + return (value & (1 << (enumValue as dynamic).index)) != 0; |
| + } |
| + |
| + /// Returns an [Iterable] of the values is in this set using [values] to |
| + /// convert the stored indices to enum values. |
| + /// |
| + /// The method is typically called with the `values` property of the enum |
| + /// class as argument: |
| + /// |
| + /// EnumSet<EnumClass> set = ... |
| + /// Iterable<EnumClass> iterable = set.iterable(EnumClass.values); |
| + /// |
| + Iterable<E> iterable(List<E> values) { |
| + return new _EnumSetIterable(this, values); |
| + } |
| + |
| + /// Returns `true` if this and [other] have any elements in common. |
| + bool intersects(EnumSet<E> other) { |
| + return (value & other.value) != 0; |
| + } |
| + |
| + /// Returns `true` if this set is empty. |
| + bool get isEmpty => value == 0; |
| + |
| + int get hashCode => value.hashCode * 19; |
| + |
| + bool operator ==(other) { |
| + if (identical(this, other)) return true; |
| + if (other is! EnumSet) return false; |
|
sigurdm
2016/01/11 08:48:55
Ideally this should be
```
if (other is! EnumSet<E
Johnni Winther
2016/01/22 11:54:13
Updated. Should be OK as the VM canonicalizes the
|
| + return value == other.value; |
| + } |
| + |
| + String toString() { |
| + if (value == 0) return '0'; |
| + int index = value.bitLength - 1; |
| + StringBuffer sb = new StringBuffer(); |
| + int mask = 1 << index; |
| + while (index >= 0) { |
| + sb.write((value & mask) != 0 ? '1' : '0'); |
| + index--; |
| + mask >>= 1; |
| + } |
| + return sb.toString(); |
| + } |
| +} |
| + |
| +/// Mutable implementation of [EnumSet]. |
| +class _EnumSet<E> extends EnumSet<E> { |
| + int _value; |
| + |
| + _EnumSet() : this.fromValue(0); |
| + |
| + _EnumSet.fromValue(this._value) : super._(); |
| + |
| + _EnumSet.fromValues(Iterable<E> values) |
| + : this._value = 0, |
| + super._() { |
| + values.forEach(add); |
| + } |
| + |
| + int get value => _value; |
| + |
| + void add(E enumValue) { |
| + _value |= 1 << (enumValue as dynamic).index; |
| + } |
| + |
| + void remove(E enumValue) { |
| + _value &= ~(1 << (enumValue as dynamic).index); |
| + } |
| + |
| + void clear() { |
| + _value = 0; |
| + } |
| +} |
| + |
| +/// Immutable implementation of [EnumSet]. |
| +class _ConstEnumSet<E> extends EnumSet<E> { |
| + final int value; |
| + |
| + const _ConstEnumSet(this.value) : super._(); |
| + |
| + factory _ConstEnumSet.fromValues(Iterable<E> values) { |
| + int value = 0; |
| + void add(E enumValue) { |
| + if (enumValue != null) { |
| + value |= 1 << (enumValue as dynamic).index; |
| + } |
| + } |
| + values.forEach(add); |
| + return new _ConstEnumSet(value); |
| + } |
| + |
| + @override |
| + void add(E enumValue) { |
| + throw new UnsupportedError('EnumSet.add'); |
| + } |
| + |
| + @override |
| + void clear() { |
| + throw new UnsupportedError('EnumSet.clear'); |
| + } |
| + |
| + @override |
| + void remove(E enumValue) { |
| + throw new UnsupportedError('EnumSet.remove'); |
| + } |
| +} |
| + |
| +class _EnumSetIterable<E> extends IterableBase<E> { |
| + final EnumSet<E> _enumSet; |
| + final List<E> _values; |
| + |
| + _EnumSetIterable(this._enumSet, this._values); |
| + |
| + @override |
| + Iterator<E> get iterator => new _EnumSetIterator(_enumSet.value, _values); |
| +} |
| + |
| +class _EnumSetIterator<E> implements Iterator<E> { |
| + int _value; |
| + int _index; |
| + int _mask; |
| + final List<E> _values; |
| + E _current; |
| + |
| + _EnumSetIterator(this._value, this._values); |
| + |
| + @override |
| + E get current => _current; |
| + |
| + @override |
| + bool moveNext() { |
| + if (_value == 0) { |
| + return false; |
| + } else { |
| + if (_mask == null) { |
| + _index = _value.bitLength - 1; |
| + _mask = 1 << _index; |
| + } |
| + _current = null; |
| + while (_index >= 0) { |
| + if (_mask & _value != 0) { |
| + _current = _values[_index]; |
| + } |
| + _mask >>= 1; |
| + _index--; |
| + if (_current != null) { |
| + break; |
| + } |
| + } |
| + return _current != null; |
| + } |
| + } |
| +} |