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