1 /* 2 * Hunt - A refined core library for D programming language. 3 * 4 * Copyright (C) 2018-2019 HuntLabs 5 * 6 * Website: https://www.huntlabs.net/ 7 * 8 * Licensed under the Apache-2.0 License. 9 * 10 */ 11 12 module hunt.collection.TreeSet; 13 14 import hunt.collection.AbstractSet; 15 import hunt.collection.Collection; 16 import hunt.collection.Iterator; 17 import hunt.collection.Map; 18 import hunt.collection.NavigableSet; 19 import hunt.collection.NavigableMap; 20 import hunt.collection.Set; 21 import hunt.collection.SortedSet; 22 import hunt.collection.TreeMap; 23 24 import hunt.util.Comparator; 25 import hunt.Exceptions; 26 import hunt.Object; 27 28 import std.range; 29 30 /** 31 * A {@link NavigableSet} implementation based on a {@link TreeMap}. 32 * The elements are ordered using their {@linkplain Comparable natural 33 * ordering}, or by a {@link Comparator} provided at set creation 34 * time, depending on which constructor is used. 35 * 36 * <p>This implementation provides guaranteed log(n) time cost for the basic 37 * operations ({@code add}, {@code remove} and {@code contains}). 38 * 39 * <p>Note that the ordering maintained by a set (whether or not an explicit 40 * comparator is provided) must be <i>consistent with equals</i> if it is to 41 * correctly implement the {@code Set} interface. (See {@code Comparable} 42 * or {@code Comparator} for a precise definition of <i>consistent with 43 * equals</i>.) This is so because the {@code Set} interface is defined in 44 * terms of the {@code equals} operation, but a {@code TreeSet} instance 45 * performs all element comparisons using its {@code compareTo} (or 46 * {@code compare}) method, so two elements that are deemed equal by this method 47 * are, from the standpoint of the set, equal. The behavior of a set 48 * <i>is</i> well-defined even if its ordering is inconsistent with equals; it 49 * just fails to obey the general contract of the {@code Set} interface. 50 * 51 * <p><strong>Note that this implementation is not synchronized.</strong> 52 * If multiple threads access a tree set concurrently, and at least one 53 * of the threads modifies the set, it <i>must</i> be synchronized 54 * externally. This is typically accomplished by synchronizing on some 55 * object that naturally encapsulates the set. 56 * If no such object exists, the set should be "wrapped" using the 57 * {@link Collections#synchronizedSortedSet Collections.synchronizedSortedSet} 58 * method. This is best done at creation time, to prevent accidental 59 * unsynchronized access to the set: <pre> 60 * SortedSet s = Collections.synchronizedSortedSet(new TreeSet(...));</pre> 61 * 62 * <p>The iterators returned by this class's {@code iterator} method are 63 * <i>fail-fast</i>: if the set is modified at any time after the iterator is 64 * created, in any way except through the iterator's own {@code remove} 65 * method, the iterator will throw a {@link ConcurrentModificationException}. 66 * Thus, in the face of concurrent modification, the iterator fails quickly 67 * and cleanly, rather than risking arbitrary, non-deterministic behavior at 68 * an undetermined time in the future. 69 * 70 * <p>Note that the fail-fast behavior of an iterator cannot be guaranteed 71 * as it is, generally speaking, impossible to make any hard guarantees in the 72 * presence of unsynchronized concurrent modification. Fail-fast iterators 73 * throw {@code ConcurrentModificationException} on a best-effort basis. 74 * Therefore, it would be wrong to write a program that depended on this 75 * exception for its correctness: <i>the fail-fast behavior of iterators 76 * should be used only to detect bugs.</i> 77 * 78 * <p>This class is a member of the 79 * <a href="{@docRoot}/../technotes/guides/collections/index.html"> 80 * Java Collections Framework</a>. 81 * 82 * @param (E) the type of elements maintained by this set 83 * 84 * @author Josh Bloch 85 * @see Collection 86 * @see Set 87 * @see HashSet 88 * @see Comparable 89 * @see Comparator 90 * @see TreeMap 91 * @since 1.2 92 */ 93 94 class TreeSet(E) : AbstractSet!(E), NavigableSet!(E) //, Cloneable 95 { 96 /** 97 * The backing map. 98 */ 99 private NavigableMap!(E, Object) m; 100 101 // Dummy value to associate with an Object in the backing Map 102 private __gshared static Object PRESENT; 103 104 shared static this() 105 { 106 PRESENT = new Object(); 107 } 108 109 /** 110 * Constructs a set backed by the specified navigable map. 111 */ 112 this(NavigableMap!(E, Object) m) { 113 this.m = m; 114 } 115 116 /** 117 * Constructs a new, empty tree set, sorted according to the 118 * natural ordering of its elements. All elements inserted into 119 * the set must implement the {@link Comparable} interface. 120 * Furthermore, all such elements must be <i>mutually 121 * comparable</i>: {@code e1.compareTo(e2)} must not throw a 122 * {@code ClassCastException} for any elements {@code e1} and 123 * {@code e2} in the set. If the user attempts to add an element 124 * to the set that violates this constraint (for example, the user 125 * attempts to add a string element to a set whose elements are 126 * integers), the {@code add} call will throw a 127 * {@code ClassCastException}. 128 */ 129 this() { 130 this(new TreeMap!(E, Object)()); 131 } 132 133 /** 134 * Constructs a new, empty tree set, sorted according to the specified 135 * comparator. All elements inserted into the set must be <i>mutually 136 * comparable</i> by the specified comparator: {@code comparator.compare(e1, 137 * e2)} must not throw a {@code ClassCastException} for any elements 138 * {@code e1} and {@code e2} in the set. If the user attempts to add 139 * an element to the set that violates this constraint, the 140 * {@code add} call will throw a {@code ClassCastException}. 141 * 142 * @param comparator the comparator that will be used to order this set. 143 * If {@code null}, the {@linkplain Comparable natural 144 * ordering} of the elements will be used. 145 */ 146 this(Comparator!E comparator) { 147 this(new TreeMap!(E, Object)(comparator)); 148 } 149 150 /** 151 * Constructs a new tree set containing the elements in the specified 152 * collection, sorted according to the <i>natural ordering</i> of its 153 * elements. All elements inserted into the set must implement the 154 * {@link Comparable} interface. Furthermore, all such elements must be 155 * <i>mutually comparable</i>: {@code e1.compareTo(e2)} must not throw a 156 * {@code ClassCastException} for any elements {@code e1} and 157 * {@code e2} in the set. 158 * 159 * @param c collection whose elements will comprise the new set 160 * @throws ClassCastException if the elements in {@code c} are 161 * not {@link Comparable}, or are not mutually comparable 162 * @throws NullPointerException if the specified collection is null 163 */ 164 this(Collection!E c) { 165 this(); 166 addAll(c); 167 } 168 169 /** 170 * Constructs a new tree set containing the same elements and 171 * using the same ordering as the specified sorted set. 172 * 173 * @param s sorted set whose elements will comprise the new set 174 * @throws NullPointerException if the specified sorted set is null 175 */ 176 // this(SortedSet!(E) s) { 177 // this(s.comparator()); 178 // addAll(s); 179 // } 180 181 override int opApply(scope int delegate(ref E) dg) { 182 if(dg is null) 183 throw new NullPointerException(); 184 185 int result = 0; 186 int expectedModCount = m.size(); 187 foreach(E k; m.byKey) { 188 result = dg(k); 189 if(result != 0) return result; 190 } 191 192 if (expectedModCount !is m.size()) 193 throw new ConcurrentModificationException(); 194 return result; 195 } 196 197 /** 198 * Returns an iterator over the elements in this set in ascending order. 199 * 200 * @return an iterator over the elements in this set in ascending order 201 */ 202 override InputRange!(E) iterator() { 203 return m.byKey(); 204 // return m.navigableKeySet().iterator(); 205 } 206 207 /** 208 * Returns an iterator over the elements in this set in descending order. 209 * 210 * @return an iterator over the elements in this set in descending order 211 * @since 1.6 212 */ 213 // Iterator!(E) descendingIterator() { 214 // return m.descendingKeySet().iterator(); 215 // } 216 217 /** 218 * @since 1.6 219 */ 220 // NavigableSet!(E) descendingSet() { 221 // return new TreeSet!(E, Object)(m.descendingMap()); 222 // } 223 224 /** 225 * Returns the number of elements in this set (its cardinality). 226 * 227 * @return the number of elements in this set (its cardinality) 228 */ 229 override int size() { 230 return m.size(); 231 } 232 233 /** 234 * Returns {@code true} if this set contains no elements. 235 * 236 * @return {@code true} if this set contains no elements 237 */ 238 override bool isEmpty() { 239 return m.isEmpty(); 240 } 241 242 /** 243 * Returns {@code true} if this set contains the specified element. 244 * More formally, returns {@code true} if and only if this set 245 * contains an element {@code e} such that 246 * <tt>(o==null ? e==null : o.equals(e))</tt>. 247 * 248 * @param o object to be checked for containment in this set 249 * @return {@code true} if this set contains the specified element 250 * @throws ClassCastException if the specified object cannot be compared 251 * with the elements currently in the set 252 * @throws NullPointerException if the specified element is null 253 * and this set uses natural ordering, or its comparator 254 * does not permit null elements 255 */ 256 override bool contains(E o) { 257 return m.containsKey(o); 258 } 259 260 /** 261 * Adds the specified element to this set if it is not already present. 262 * More formally, adds the specified element {@code e} to this set if 263 * the set contains no element {@code e2} such that 264 * <tt>(e==null ? e2==null : e.equals(e2))</tt>. 265 * If this set already contains the element, the call leaves the set 266 * unchanged and returns {@code false}. 267 * 268 * @param e element to be added to this set 269 * @return {@code true} if this set did not already contain the specified 270 * element 271 * @throws ClassCastException if the specified object cannot be compared 272 * with the elements currently in this set 273 * @throws NullPointerException if the specified element is null 274 * and this set uses natural ordering, or its comparator 275 * does not permit null elements 276 */ 277 override bool add(E e) { 278 return m.put(e, PRESENT) is null; 279 } 280 281 /** 282 * Removes the specified element from this set if it is present. 283 * More formally, removes an element {@code e} such that 284 * <tt>(o==null ? e==null : o.equals(e))</tt>, 285 * if this set contains such an element. Returns {@code true} if 286 * this set contained the element (or equivalently, if this set 287 * changed as a result of the call). (This set will not contain the 288 * element once the call returns.) 289 * 290 * @param o object to be removed from this set, if present 291 * @return {@code true} if this set contained the specified element 292 * @throws ClassCastException if the specified object cannot be compared 293 * with the elements currently in this set 294 * @throws NullPointerException if the specified element is null 295 * and this set uses natural ordering, or its comparator 296 * does not permit null elements 297 */ 298 override bool remove(E o) { 299 return m.remove(o)==PRESENT; 300 } 301 302 /** 303 * Removes all of the elements from this set. 304 * The set will be empty after this call returns. 305 */ 306 override void clear() { 307 m.clear(); 308 } 309 310 /** 311 * Adds all of the elements in the specified collection to this set. 312 * 313 * @param c collection containing elements to be added to this set 314 * @return {@code true} if this set changed as a result of the call 315 * @throws ClassCastException if the elements provided cannot be compared 316 * with the elements currently in the set 317 * @throws NullPointerException if the specified collection is null or 318 * if any element is null and this set uses natural ordering, or 319 * its comparator does not permit null elements 320 */ 321 override bool addAll(Collection!(E) c) { 322 // Use linear-time version if applicable 323 // if (m.size()==0 && c.size() > 0 && 324 // c instanceof SortedSet && 325 // m instanceof TreeMap) { 326 // SortedSet!(E) set = (SortedSet!(E)) c; 327 // TreeMap!(E, Object) map = (TreeMap<E, Object>) m; 328 // Comparator<?> cc = set.comparator(); 329 // Comparator<E> mc = map.comparator(); 330 // if (cc==mc || (cc !is null && cc.equals(mc))) { 331 // map.addAllForTreeSet(set, PRESENT); 332 // return true; 333 // } 334 // } 335 return super.addAll(c); 336 } 337 338 /** 339 * @throws ClassCastException {@inheritDoc} 340 * @throws NullPointerException if {@code fromElement} or {@code toElement} 341 * is null and this set uses natural ordering, or its comparator 342 * does not permit null elements 343 * @throws IllegalArgumentException {@inheritDoc} 344 * @since 1.6 345 */ 346 NavigableSet!(E) subSet(E fromElement, bool fromInclusive, 347 E toElement, bool toInclusive) { 348 return new TreeSet!(E)(m.subMap(fromElement, fromInclusive, 349 toElement, toInclusive)); 350 } 351 352 /** 353 * @throws ClassCastException {@inheritDoc} 354 * @throws NullPointerException if {@code toElement} is null and 355 * this set uses natural ordering, or its comparator does 356 * not permit null elements 357 * @throws IllegalArgumentException {@inheritDoc} 358 * @since 1.6 359 */ 360 NavigableSet!(E) headSet(E toElement, bool inclusive) { 361 return new TreeSet!(E)(m.headMap(toElement, inclusive)); 362 } 363 364 /** 365 * @throws ClassCastException {@inheritDoc} 366 * @throws NullPointerException if {@code fromElement} is null and 367 * this set uses natural ordering, or its comparator does 368 * not permit null elements 369 * @throws IllegalArgumentException {@inheritDoc} 370 * @since 1.6 371 */ 372 NavigableSet!(E) tailSet(E fromElement, bool inclusive) { 373 return new TreeSet!(E)(m.tailMap(fromElement, inclusive)); 374 } 375 376 /** 377 * @throws ClassCastException {@inheritDoc} 378 * @throws NullPointerException if {@code fromElement} or 379 * {@code toElement} is null and this set uses natural ordering, 380 * or its comparator does not permit null elements 381 * @throws IllegalArgumentException {@inheritDoc} 382 */ 383 SortedSet!(E) subSet(E fromElement, E toElement) { 384 return subSet(fromElement, true, toElement, false); 385 } 386 387 /** 388 * @throws ClassCastException {@inheritDoc} 389 * @throws NullPointerException if {@code toElement} is null 390 * and this set uses natural ordering, or its comparator does 391 * not permit null elements 392 * @throws IllegalArgumentException {@inheritDoc} 393 */ 394 SortedSet!(E) headSet(E toElement) { 395 return headSet(toElement, false); 396 } 397 398 /** 399 * @throws ClassCastException {@inheritDoc} 400 * @throws NullPointerException if {@code fromElement} is null 401 * and this set uses natural ordering, or its comparator does 402 * not permit null elements 403 * @throws IllegalArgumentException {@inheritDoc} 404 */ 405 SortedSet!(E) tailSet(E fromElement) { 406 return tailSet(fromElement, true); 407 } 408 409 Comparator!(E) comparator() { 410 return m.comparator(); 411 } 412 413 /** 414 * @throws NoSuchElementException {@inheritDoc} 415 */ 416 E first() { 417 return m.firstKey(); 418 } 419 420 /** 421 * @throws NoSuchElementException {@inheritDoc} 422 */ 423 E last() { 424 return m.lastKey(); 425 } 426 427 // NavigableSet API methods 428 429 /** 430 * @throws ClassCastException {@inheritDoc} 431 * @throws NullPointerException if the specified element is null 432 * and this set uses natural ordering, or its comparator 433 * does not permit null elements 434 * @since 1.6 435 */ 436 E lower(E e) { 437 return m.lowerKey(e); 438 } 439 440 /** 441 * @throws ClassCastException {@inheritDoc} 442 * @throws NullPointerException if the specified element is null 443 * and this set uses natural ordering, or its comparator 444 * does not permit null elements 445 * @since 1.6 446 */ 447 E floor(E e) { 448 return m.floorKey(e); 449 } 450 451 /** 452 * @throws ClassCastException {@inheritDoc} 453 * @throws NullPointerException if the specified element is null 454 * and this set uses natural ordering, or its comparator 455 * does not permit null elements 456 * @since 1.6 457 */ 458 E ceiling(E e) { 459 return m.ceilingKey(e); 460 } 461 462 /** 463 * @throws ClassCastException {@inheritDoc} 464 * @throws NullPointerException if the specified element is null 465 * and this set uses natural ordering, or its comparator 466 * does not permit null elements 467 * @since 1.6 468 */ 469 E higher(E e) { 470 return m.higherKey(e); 471 } 472 473 /** 474 * @since 1.6 475 */ 476 E pollFirst() { 477 MapEntry!(E, Object) e = m.pollFirstEntry(); 478 static if(is(E == class) || is(E == interface)) { 479 return (e is null) ? null : e.getKey(); 480 } else 481 return e.getKey(); 482 } 483 484 /** 485 * @since 1.6 486 */ 487 E pollLast() { 488 MapEntry!(E, Object) e = m.pollLastEntry(); 489 static if(is(E == class) || is(E == interface)) { 490 return (e is null) ? null : e.getKey(); 491 } else 492 return e.getKey(); 493 } 494 495 /** 496 * Returns a shallow copy of this {@code TreeSet} instance. (The elements 497 * themselves are not cloned.) 498 * 499 * @return a shallow copy of this set 500 */ 501 // Object clone() { 502 // TreeSet!(E) clone; 503 // try { 504 // clone = (TreeSet!(E)) super.clone(); 505 // } catch (CloneNotSupportedException e) { 506 // throw new InternalError(e); 507 // } 508 509 // clone.m = new TreeMap<>(m); 510 // return clone; 511 // } 512 513 /** 514 * Creates a <em><a href="Spliterator.html#binding">late-binding</a></em> 515 * and <em>fail-fast</em> {@link Spliterator} over the elements in this 516 * set. 517 * 518 * <p>The {@code Spliterator} reports {@link Spliterator#SIZED}, 519 * {@link Spliterator#DISTINCT}, {@link Spliterator#SORTED}, and 520 * {@link Spliterator#ORDERED}. Overriding implementations should document 521 * the reporting of additional characteristic values. 522 * 523 * <p>The spliterator's comparator (see 524 * {@link java.util.Spliterator#getComparator()}) is {@code null} if 525 * the tree set's comparator (see {@link #comparator()}) is {@code null}. 526 * Otherwise, the spliterator's comparator is the same as or imposes the 527 * same total ordering as the tree set's comparator. 528 * 529 * @return a {@code Spliterator} over the elements in this set 530 * @since 1.8 531 */ 532 // Spliterator!(E) spliterator() { 533 // return TreeMap.keySpliteratorFor(m); 534 // } 535 536 override bool opEquals(IObject o) { 537 return opEquals(cast(Object) o); 538 } 539 540 override bool opEquals(Object o) { 541 return super.opEquals(o); 542 } 543 544 override size_t toHash() @trusted nothrow { 545 return super.toHash(); 546 } 547 548 override string toString() { 549 return super.toString(); 550 } 551 }