| OLD | NEW |
| (Empty) | |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. |
| 4 |
| 5 library dart2js.util.setlet; |
| 6 |
| 7 class Setlet<E> { |
| 8 static const _MARKER = const _SetletMarker(); |
| 9 static const CAPACITY = 8; |
| 10 |
| 11 // The setlet can be in one of four states: |
| 12 // |
| 13 // * Empty (extra: null, contents: marker) |
| 14 // * Single element (extra: null, contents: element) |
| 15 // * List-backed (extra: length, contents: list) |
| 16 // * Set-backed (extra: marker, contents: set) |
| 17 // |
| 18 // When the setlet is list-backed, the list in the contents field |
| 19 // may have empty slots filled with the marker value. |
| 20 var _contents = _MARKER; |
| 21 var _extra; |
| 22 |
| 23 Iterator<E> get iterator { |
| 24 if (_extra == null) { |
| 25 return new _SetletSingleIterator<E>(_contents); |
| 26 } else if (_MARKER == _extra) { |
| 27 return _contents.iterator; |
| 28 } else { |
| 29 return new _SetletListIterator<E>(_contents, _extra); |
| 30 } |
| 31 } |
| 32 |
| 33 int get length { |
| 34 if (_extra == null) { |
| 35 return (_MARKER == _contents) ? 0 : 1; |
| 36 } else if (_MARKER == _extra) { |
| 37 return _contents.length; |
| 38 } else { |
| 39 return _extra; |
| 40 } |
| 41 } |
| 42 |
| 43 bool get isEmpty { |
| 44 if (_extra == null) { |
| 45 return _MARKER == _contents; |
| 46 } else if (_MARKER == _extra) { |
| 47 return _contents.isEmpty; |
| 48 } else { |
| 49 return _extra == 0; |
| 50 } |
| 51 } |
| 52 |
| 53 bool contains(E element) { |
| 54 if (_extra == null) { |
| 55 return _contents == element; |
| 56 } else if (_MARKER == _extra) { |
| 57 return _contents.contains(element); |
| 58 } else { |
| 59 for (int remaining = _extra, i = 0; remaining > 0 && i < CAPACITY; i++) { |
| 60 var candidate = _contents[i]; |
| 61 if (_MARKER == candidate) continue; |
| 62 if (candidate == element) return true; |
| 63 remaining--; |
| 64 } |
| 65 return false; |
| 66 } |
| 67 } |
| 68 |
| 69 bool remove(E element) { |
| 70 if (_extra == null) { |
| 71 if (_contents == element) { |
| 72 _contents = _MARKER; |
| 73 return true; |
| 74 } else { |
| 75 return false; |
| 76 } |
| 77 } else if (_MARKER == _extra) { |
| 78 return _contents.remove(element); |
| 79 } else { |
| 80 for (int remaining = _extra, i = 0; remaining > 0 && i < CAPACITY; i++) { |
| 81 var candidate = _contents[i]; |
| 82 if (_MARKER == candidate) continue; |
| 83 if (candidate == element) { |
| 84 _contents[i] = _MARKER; |
| 85 _extra--; |
| 86 return true; |
| 87 } |
| 88 remaining--; |
| 89 } |
| 90 return false; |
| 91 } |
| 92 } |
| 93 |
| 94 void add(E element) { |
| 95 if (_extra == null) { |
| 96 if (_MARKER == _contents) { |
| 97 _contents = element; |
| 98 } else if (_contents == element) { |
| 99 // Do nothing. |
| 100 } else { |
| 101 List list = new List(CAPACITY); |
| 102 list[0] = _contents; |
| 103 list[1] = element; |
| 104 _contents = list; |
| 105 _extra = 2; // Two elements. |
| 106 } |
| 107 } else if (_MARKER == _extra) { |
| 108 _contents.add(element); |
| 109 } else { |
| 110 int remaining = _extra; |
| 111 int index = 0; |
| 112 int copyTo, copyFrom; |
| 113 while (remaining > 0 && index < CAPACITY) { |
| 114 var candidate = _contents[index++]; |
| 115 if (_MARKER == candidate) { |
| 116 // Keep track of the last range of empty slots in the |
| 117 // list. When we're done we'll move all the elements |
| 118 // after those empty slots down, so that adding an element |
| 119 // after that will preserve the insertion order. |
| 120 if (copyFrom == index - 1) { |
| 121 copyFrom++; |
| 122 } else { |
| 123 copyTo = index - 1; |
| 124 copyFrom = index; |
| 125 } |
| 126 continue; |
| 127 } else if (candidate == element) { |
| 128 return; |
| 129 } |
| 130 remaining--; |
| 131 } |
| 132 if (index < CAPACITY) { |
| 133 _contents[index] = element; |
| 134 _extra++; |
| 135 } else if (_extra < CAPACITY) { |
| 136 // Move the last elements down into the last empty slots |
| 137 // so that we have empty slots after the last element. |
| 138 while (copyFrom < CAPACITY) { |
| 139 _contents[copyTo++] = _contents[copyFrom++]; |
| 140 } |
| 141 // Insert the new element as the last element. |
| 142 _contents[copyTo++] = element; |
| 143 _extra++; |
| 144 // Clear all elements after the new last elements to |
| 145 // make sure we don't keep extra stuff alive. |
| 146 while (copyTo < CAPACITY) _contents[copyTo++] = null; |
| 147 } else { |
| 148 _contents = new Set<E>()..addAll(_contents)..add(element); |
| 149 _extra = _MARKER; |
| 150 } |
| 151 } |
| 152 } |
| 153 |
| 154 void forEach(void action(E element)) { |
| 155 if (_extra == null) { |
| 156 if (_MARKER != _contents) action(_contents); |
| 157 } else if (_MARKER == _extra) { |
| 158 _contents.forEach(action); |
| 159 } else { |
| 160 for (int remaining = _extra, i = 0; remaining > 0 && i < CAPACITY; i++) { |
| 161 var element = _contents[i]; |
| 162 if (_MARKER == element) continue; |
| 163 action(element); |
| 164 remaining--; |
| 165 } |
| 166 } |
| 167 } |
| 168 } |
| 169 |
| 170 class _SetletMarker { |
| 171 const _SetletMarker(); |
| 172 toString() => "-"; |
| 173 } |
| 174 |
| 175 class _SetletSingleIterator<E> implements Iterator<E> { |
| 176 var _element; |
| 177 E _current; |
| 178 _SetletSingleIterator(this._element); |
| 179 |
| 180 E get current => _current; |
| 181 |
| 182 bool moveNext() { |
| 183 if (Setlet._MARKER == _element) { |
| 184 _current = null; |
| 185 return false; |
| 186 } |
| 187 _current = _element; |
| 188 _element = Setlet._MARKER; |
| 189 return true; |
| 190 } |
| 191 } |
| 192 |
| 193 class _SetletListIterator<E> implements Iterator<E> { |
| 194 final List _list; |
| 195 int _remaining; |
| 196 int _index = 0; |
| 197 E _current; |
| 198 _SetletListIterator(this._list, this._remaining); |
| 199 |
| 200 E get current => _current; |
| 201 |
| 202 bool moveNext() { |
| 203 while (_remaining > 0) { |
| 204 var candidate = _list[_index++]; |
| 205 if (Setlet._MARKER != candidate) { |
| 206 _current = candidate; |
| 207 _remaining--; |
| 208 return true; |
| 209 } |
| 210 } |
| 211 _current = null; |
| 212 return false; |
| 213 } |
| 214 } |
| OLD | NEW |