001/* 002 * Copyright (c) 1998, 2018, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. Oracle designates this 008 * particular file as subject to the "Classpath" exception as provided 009 * by Oracle in the LICENSE file that accompanied this code. 010 * 011 * This code is distributed in the hope that it will be useful, but WITHOUT 012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 014 * version 2 for more details (a copy is included in the LICENSE file that 015 * accompanied this code). 016 * 017 * You should have received a copy of the GNU General Public License version 018 * 2 along with this work; if not, write to the Free Software Foundation, 019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 020 * 021 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 022 * or visit www.oracle.com if you need additional information or have any 023 * questions. 024 */ 025package Torello.Java.ReadOnly; 026 027import Torello.Java.Additional.RemoveUnsupportedIterator; 028 029import java.util.*; 030 031import java.io.Serializable; 032 033import java.util.stream.Collector; 034 035import java.util.function.Function; 036import java.util.function.Supplier; 037import java.util.function.Predicate; 038 039/** 040 * Immutable Wrapper for <CODE>java.util.TreeSet</CODE>, found in the "Java Collections 041 * Framework". 042 * 043 * <EMBED CLASS=globalDefs DATA-JDK=TreeSet> 044 * <EMBED CLASS='external-html' DATA-FILE-ID=MUCHOS_CONSTRUCTORS> 045 * <EMBED CLASS='external-html' DATA-FILE-ID=DATA_CLASS> 046 * 047 * @param <E> the type of elements maintained by this set 048 */ 049@Torello.JavaDoc.JDHeaderBackgroundImg(EmbedTagFileID="JDHBI_MAIN") 050@SuppressWarnings("unchecked") 051public class ReadOnlyTreeSet<E> 052 // extends AbstractReadOnlySet<E> 053 implements ReadOnlyNavigableSet<E>, Serializable 054{ 055 // ******************************************************************************************** 056 // ******************************************************************************************** 057 // Protected & Private Fields, Methods, Statics 058 // ******************************************************************************************** 059 // ******************************************************************************************** 060 061 062 /** <EMBED CLASS='external-html' DATA-FILE-ID=SVUID> */ 063 protected static final long serialVersionUID = 1; 064 065 // Minor Optimization where new TreeSet's that have no contents always re-use this static 066 // instance. Since this instance is completely empty, the Raw-Types things is irrelevant. 067 068 @SuppressWarnings("rawtypes") 069 private static final TreeSet EMPTY_TREE_SET = new TreeSet(); 070 071 // Singleton & Empty ReadOnlyTreeSet, Uses the "Supplier Constructor" 072 @SuppressWarnings("rawtypes") 073 private static final ReadOnlyTreeSet EMPTY_READONLY_TREE_SET = 074 new ReadOnlyTreeSet(null, () -> null); 075 076 // The actual TreeSet used by this instance. 077 private final TreeSet<E> treeSet; 078 079 // TRUE => This was built using the class ROTreeSetBuilder 080 // FALSE => This was built using the clone() of a standard java.util.TreeSet constructor 081 082 private final boolean fromBuilderOrTreeSet; 083 084 // Mimics the C++ Keyword/Concept of "Friend Class". Is "Friends With" ROTreeSetBuilder 085 static class AccessBadge { private AccessBadge() { } } 086 private static final AccessBadge friendClassBadge = new AccessBadge(); 087 088 public static <T> ReadOnlyTreeSet<T> emptyROTS() 089 { return (ReadOnlyTreeSet<T>) EMPTY_READONLY_TREE_SET; } 090 091 092 // ******************************************************************************************** 093 // ******************************************************************************************** 094 // Basic Constructors 095 // ******************************************************************************************** 096 // ******************************************************************************************** 097 098 099 // To all the readers out there following along: The "AccessBadge" thing is just a slightly 100 // wimpier substitute for the C++ keyword / concept 'friend' or "Friend Class". It means this 101 // constructor is (for all intents and purposes) a private-constructor, except for the class 102 // ROTreeSetBuilder 103 // 104 // This is the Constructor used by the Builder. It has a "Zero-Size" Optimization 105 106 ReadOnlyTreeSet(ROTreeSetBuilder<E> rotsb, ROTreeSetBuilder.AccessBadge badge) 107 { 108 Objects.requireNonNull(badge, "Access Badge is null. Requires Friend-Class Badge"); 109 110 fromBuilderOrTreeSet = true; 111 this.treeSet = rotsb; 112 } 113 114 /** 115 * Copies parameter {@code 'c'} (and saves it) in order to guarantee that {@code 'this'} 116 * instance is Read-Only, and shielded from outside modification. 117 * 118 * <EMBED CLASS='external-html' DATA-FILE-ID=TREESET_CMPR_WARN> 119 * 120 * @param c The {@code TreeSet} to be copied and saved into this instance internal 121 * and private {@code 'treeSet'} field. 122 */ 123 public ReadOnlyTreeSet(Collection<E> c) 124 { 125 fromBuilderOrTreeSet = false; 126 this.treeSet = (c.size() == 0) ? ((TreeSet<E>) EMPTY_TREE_SET) : new TreeSet<>(c); 127 } 128 129 /** 130 * Copies parameter {@code 's'} (and saves it) in order to guarantee that {@code 'this'} 131 * instance is Read-Only, and shielded from outside modification. 132 * 133 * @param s The {@code TreeSet} to be copied and saved into this instance internal 134 * and private {@code 'treeSet'} field. 135 */ 136 public ReadOnlyTreeSet(SortedSet<E> s) 137 { 138 fromBuilderOrTreeSet = false; 139 this.treeSet = (s.size() == 0) ? ((TreeSet<E>) EMPTY_TREE_SET) : new TreeSet<>(s); 140 } 141 142 /** 143 * Use a {@code Supplier<E>} to provide an arbitrary number of elements of type {@code 'E'} 144 * directly to this constructor. This constructor will request elements from the 145 * {@code Supplier} provided to parameter {@code 's'} until {@code 's'} returns null. 146 * 147 * <EMBED CLASS='external-html' DATA-FILE-ID=TREESET_CMPR_WARN> 148 * 149 * @param comparator <EMBED CLASS='external-html' DATA-FILE-ID=COMPARATOR> 150 * @param s Any Java {@code Supplier<E>} 151 */ 152 public ReadOnlyTreeSet(Comparator<? super E> comparator, Supplier<E> s) 153 { 154 fromBuilderOrTreeSet = false; 155 156 TreeSet<E> treeSet = (comparator != null) 157 ? new TreeSet<>(comparator) 158 : new TreeSet<>(); 159 160 E e; 161 while ((e = s.get()) != null) treeSet.add(e); 162 163 // Empty Optimization (throw away, completely, the reference, use static-constant) 164 this.treeSet = (treeSet.size() == 0) ? ((TreeSet<E>) EMPTY_TREE_SET) : treeSet; 165 } 166 167 168 // ******************************************************************************************** 169 // ******************************************************************************************** 170 // Iterable & Array Based Constructors - **NO FILTER** 171 // ******************************************************************************************** 172 // ******************************************************************************************** 173 174 175 /** 176 * If only a small amount of processing needs to be done on the contents of some Java 177 * Data-Type, and using an entire Builder-Class seems disproportionately complex - <I>this 178 * constructor can convert any Java {@code Iterable} into a {@code ReadOnlyTreeSet}, using 179 * a simple {@code 'mapper'}</I>. 180 * 181 * <EMBED CLASS='external-html' DATA-FILE-ID=TREESET_CMPR_WARN> 182 * 183 * @param <T> <EMBED CLASS='external-html' DATA-FILE-ID=ITERABLE_TYPE_PARAM> 184 * @param i Any Java {@code Iterable} 185 * @param mapper <EMBED CLASS='external-html' DATA-FILE-ID=ITERABLE_MAPPER> 186 * @param comparator <EMBED CLASS='external-html' DATA-FILE-ID=COMPARATOR> 187 * 188 * @throws NullPointerException if either {@code 'i'} or {@code 'mapper'} are passed null. 189 */ 190 public <T> ReadOnlyTreeSet( 191 Iterable<T> i, 192 Function<? super T, ? extends E> mapper, 193 Comparator<? super E> comparator 194 ) 195 { 196 Objects.requireNonNull(mapper, ROHelpers.NULL_MSG + "'mapper'"); 197 198 fromBuilderOrTreeSet = false; 199 200 TreeSet<E> treeSet = (comparator != null) 201 ? new TreeSet<>(comparator) 202 : new TreeSet<>(); 203 204 for (T t : i) treeSet.add(mapper.apply(t)); 205 206 // Empty Optimization (throw away, completely, the reference, use static-constant) 207 this.treeSet = (treeSet.size() == 0) ? ((TreeSet<E>) EMPTY_TREE_SET) : treeSet; 208 } 209 210 /** 211 * If a Standard Java {@code Iterable} can be directly mapped into a {@code TreeSet} 212 * (and, ergo, an entire Builder-Instance would be a bit excessive) - <I>this constructor will 213 * seamlessly convert any Java {@code Iterable<E>} directly into a {@code ReadOnlyTreeSet<E>} 214 * with just this single invocation</I>. 215 * 216 * <EMBED CLASS='external-html' DATA-FILE-ID=TREESET_CMPR_WARN> 217 * 218 * @param i Any Java {@code Iterable<E>} 219 * @param comparator <EMBED CLASS='external-html' DATA-FILE-ID=COMPARATOR> 220 */ 221 public ReadOnlyTreeSet(Iterable<E> i, Comparator<? super E> comparator) 222 { 223 fromBuilderOrTreeSet = false; 224 225 TreeSet<E> treeSet = (comparator != null) 226 ? new TreeSet<>(comparator) 227 : new TreeSet<>(); 228 229 for (E element : i) treeSet.add(element); 230 231 // Empty Optimization (throw away, completely, the reference, use static-constant) 232 this.treeSet = (treeSet.size() == 0) ? ((TreeSet<E>) EMPTY_TREE_SET) : treeSet; 233 } 234 235 /** 236 * Builds {@code ReadOnlyTreeSet<E>} instance having Generic-Type {@code 'E'}, and contents 237 * {@code 'elements'}. 238 * 239 * <EMBED CLASS='external-html' DATA-FILE-ID=TREESET_CMPR_WARN> 240 * 241 * @param elementsType <EMBED CLASS='external-html' DATA-FILE-ID=ELEMENTS_TYPE> 242 * @param comparator <EMBED CLASS='external-html' DATA-FILE-ID=COMPARATOR> 243 * @param elements <EMBED CLASS='external-html' DATA-FILE-ID=ELEMENTS_VAR_ARGS> 244 * 245 * @throws ClassCastException <EMBED CLASS='external-html' DATA-FILE-ID=CCEX> 246 * @throws NullPointerException If {@code 'elementsType'} is passed null. 247 */ 248 public ReadOnlyTreeSet 249 (Class<E> elementsType, Comparator<? super E> comparator, Object... elements) 250 { 251 Objects.requireNonNull(elementsType, ROHelpers.NULL_MSG + "'elementsType'"); 252 253 fromBuilderOrTreeSet = false; 254 255 if (elements.length == 0) 256 this.treeSet = (TreeSet<E>) EMPTY_TREE_SET; 257 258 else 259 { 260 this.treeSet = (comparator != null) 261 ? new TreeSet<>(comparator) 262 : new TreeSet<>(); 263 264 for (Object element : elements) this.treeSet.add(elementsType.cast(element)); 265 } 266 } 267 268 /** 269 * Builds {@code ReadOnlyTreeSet<E>} instance having Generic-Type {@code 'E'}, and contents 270 * {@code 'elements'}. 271 * 272 * <EMBED CLASS='external-html' DATA-FILE-ID=TREESET_CMPR_WARN> 273 * 274 * @param mapper <EMBED CLASS='external-html' DATA-FILE-ID=OBJ_E_MAPPER> 275 * @param comparator <EMBED CLASS='external-html' DATA-FILE-ID=COMPARATOR> 276 * @param elements <EMBED CLASS='external-html' DATA-FILE-ID=ELEMENTS_VAR_ARGS> 277 * 278 * @throws ClassCastException <EMBED CLASS='external-html' DATA-FILE-ID=CCEX> 279 * @throws NullPointerException If {@code 'mapper'} is passed null. 280 */ 281 public ReadOnlyTreeSet( 282 Function<Object, ? extends E> mapper, 283 Comparator<? super E> comparator, 284 Object... elements 285 ) 286 { 287 Objects.requireNonNull(mapper, ROHelpers.NULL_MSG + "'mapper'"); 288 289 fromBuilderOrTreeSet = false; 290 291 if (elements.length == 0) 292 this.treeSet = (TreeSet<E>) EMPTY_TREE_SET; 293 294 else 295 { 296 this.treeSet = (comparator != null) 297 ? new TreeSet<>(comparator) 298 : new TreeSet<>(); 299 300 for (Object element : elements) this.treeSet.add(mapper.apply(element)); 301 } 302 } 303 304 305 // ******************************************************************************************** 306 // ******************************************************************************************** 307 // Iterable & Array Based Constructors - **INCLUDES ELEMENT FILTER** 308 // ******************************************************************************************** 309 // ******************************************************************************************** 310 311 312 /** 313 * If only a small amount of processing needs to be done on the contents of some Java 314 * Data-Type, and using an entire Builder-Class seems disproportionately complex - <I>this 315 * constructor can convert any Java {@code Iterable} into a {@code ReadOnlyTreeSet}, using 316 * a simple {@code 'mapper'}</I>. 317 * 318 * <EMBED CLASS='external-html' DATA-FILE-ID=TREESET_CMPR_WARN> 319 * 320 * @param <T> <EMBED CLASS='external-html' DATA-FILE-ID=ITERABLE_TYPE_PARAM> 321 * @param i Any Java {@code Iterable<T>} 322 * @param mapper <EMBED CLASS='external-html' DATA-FILE-ID=ITERABLE_MAPPER> 323 * @param filter <EMBED CLASS='external-html' DATA-FTP=T DATA-FILE-ID=PREDICATE_FILTER> 324 * @param comparator <EMBED CLASS='external-html' DATA-FILE-ID=COMPARATOR> 325 * 326 * @throws NullPointerException if any of {@code 'i'}, {@code 'mapper'} or {@code 'filter'} are 327 * passed null 328 */ 329 public <T> ReadOnlyTreeSet( 330 Iterable<T> i, 331 Function<? super T, ? extends E> mapper, 332 Predicate<? super T> filter, 333 Comparator<? super E> comparator 334 ) 335 { 336 Objects.requireNonNull(mapper, ROHelpers.NULL_MSG + "'mapper'"); 337 Objects.requireNonNull(filter, ROHelpers.NULL_MSG + "'filter'"); 338 339 fromBuilderOrTreeSet = false; 340 341 TreeSet<E> treeSet = (comparator != null) 342 ? new TreeSet<>(comparator) 343 : new TreeSet<>(); 344 345 for (T t : i) if (filter.test(t)) treeSet.add(mapper.apply(t)); 346 347 // Empty Optimization (throw away, completely, the reference, use static-constant) 348 this.treeSet = (treeSet.size() == 0) ? ((TreeSet<E>) EMPTY_TREE_SET) : treeSet; 349 } 350 351 /** 352 * If a Standard Java {@code Iterable} can be directly mapped into a {@code TreeSet} 353 * (and, ergo, an entire Builder-Instance would be a bit excessive) - <I>this constructor will 354 * seamlessly convert any Java {@code Iterable<E>} directly into a {@code ReadOnlyTreeSet<E>} 355 * with just this single invocation</I>. 356 * 357 * <EMBED CLASS='external-html' DATA-FILE-ID=TREESET_CMPR_WARN> 358 * 359 * @param i Any Java {@code Iterabler<E>} 360 * @param filter <EMBED CLASS='external-html' DATA-FTP=E DATA-FILE-ID=PREDICATE_FILTER> 361 * @param comparator <EMBED CLASS='external-html' DATA-FILE-ID=COMPARATOR> 362 * 363 * @throws NullPointerException if either {@code 'i'} or {@code 'filter'} are passed null 364 */ 365 public ReadOnlyTreeSet 366 (Iterable<E> i, Predicate<? super E> filter, Comparator<? super E> comparator) 367 { 368 fromBuilderOrTreeSet = false; 369 370 TreeSet<E> treeSet = (comparator != null) 371 ? new TreeSet<>(comparator) 372 : new TreeSet<>(); 373 374 for (E element : i) if (filter.test(element)) treeSet.add(element); 375 376 // Empty Optimization (throw away, completely, the reference, use static-constant) 377 this.treeSet = (treeSet.size() == 0) ? ((TreeSet<E>) EMPTY_TREE_SET) : treeSet; 378 } 379 380 /** 381 * Builds {@code ReadOnlyTreeSet<E>} instance having Generic-Type {@code 'E'}, and contents 382 * {@code 'elements'}. 383 * 384 * <EMBED CLASS='external-html' DATA-FILE-ID=TREESET_CMPR_WARN> 385 * 386 * @param elementsType <EMBED CLASS='external-html' DATA-FILE-ID=ELEMENTS_TYPE> 387 * @param filter <EMBED CLASS='external-html' DATA-FTP=E DATA-FILE-ID=PREDICATE_FILTER> 388 * @param comparator <EMBED CLASS='external-html' DATA-FILE-ID=COMPARATOR> 389 * @param elements <EMBED CLASS='external-html' DATA-FILE-ID=ELEMENTS_VAR_ARGS> 390 * 391 * @throws ClassCastException <EMBED CLASS='external-html' DATA-FILE-ID=CCEX> 392 * 393 * @throws NullPointerException If either {@code 'elementsType'} or {@code 'filter'} are passed 394 * null. 395 */ 396 public ReadOnlyTreeSet( 397 Class<E> elementsType, 398 Predicate<? super E> filter, 399 Comparator<? super E> comparator, 400 Object... elements 401 ) 402 { 403 Objects.requireNonNull(elementsType, ROHelpers.NULL_MSG + "'elementsType'"); 404 Objects.requireNonNull(filter, ROHelpers.NULL_MSG + "'filter'"); 405 406 fromBuilderOrTreeSet = false; 407 408 TreeSet<E> treeSet = (comparator != null) 409 ? new TreeSet<>(comparator) 410 : new TreeSet<>(); 411 412 E e; 413 for (Object element : elements) 414 if (filter.test(e = elementsType.cast(element))) 415 treeSet.add(e); 416 417 // Empty Optimization (throw away, completely, the reference, use static-constant) 418 this.treeSet = (treeSet.size() == 0) ? ((TreeSet<E>) EMPTY_TREE_SET) : treeSet; 419 } 420 421 /** 422 * Builds {@code ReadOnlyTreeSet<E>} instance having Generic-Type {@code 'E'}, and contents 423 * {@code 'elements'}. 424 * 425 * <EMBED CLASS='external-html' DATA-FILE-ID=TREESET_CMPR_WARN> 426 * 427 * @param mapper <EMBED CLASS='external-html' DATA-FILE-ID=OBJ_E_MAPPER> 428 * @param filter <EMBED CLASS='external-html' DATA-FTP=Object DATA-FILE-ID=PREDICATE_FILTER> 429 * @param comparator <EMBED CLASS='external-html' DATA-FILE-ID=COMPARATOR> 430 * @param elements <EMBED CLASS='external-html' DATA-FILE-ID=ELEMENTS_VAR_ARGS> 431 * 432 * @throws ClassCastException <EMBED CLASS='external-html' DATA-FILE-ID=CCEX> 433 * @throws NullPointerException If either {@code 'mapper'} or {@code 'filter'} are passed null 434 */ 435 public ReadOnlyTreeSet( 436 Function<Object, ? extends E> mapper, 437 Predicate<Object> filter, 438 Comparator<? super E> comparator, 439 Object... elements 440 ) 441 { 442 Objects.requireNonNull(mapper, ROHelpers.NULL_MSG + "'mapper'"); 443 Objects.requireNonNull(filter, ROHelpers.NULL_MSG + "'filter'"); 444 445 fromBuilderOrTreeSet = false; 446 447 TreeSet<E> treeSet = (comparator != null) 448 ? new TreeSet<>(comparator) 449 : new TreeSet<>(); 450 451 for (Object element : elements) 452 if (filter.test(element)) 453 treeSet.add(mapper.apply(element)); 454 455 // Empty Optimization (throw away, completely, the reference, use static-constant) 456 this.treeSet = (treeSet.size() == 0) ? ((TreeSet<E>) EMPTY_TREE_SET) : treeSet; 457 } 458 459 460 // ******************************************************************************************** 461 // ******************************************************************************************** 462 // @SafeVarargs / Variable-Arity / VarArgs: with Parameterized / Generic Type's 463 // ******************************************************************************************** 464 // ******************************************************************************************** 465 466 467 /** 468 * Builds {@code ReadOnlyTreeSet<E>} instance having Generic-Type {@code 'E'}, and contents 469 * {@code 'elements'}. 470 * 471 * <EMBED CLASS='external-html' DATA-FILE-ID=TREESET_CMPR_WARN> 472 * 473 * @param comparator <EMBED CLASS='external-html' DATA-FILE-ID=COMPARATOR> 474 * @param elements <EMBED CLASS='external-html' DATA-FILE-ID=ELEMENTS_VAR_ARGS> 475 */ 476 @SafeVarargs 477 public ReadOnlyTreeSet(Comparator<? super E> comparator, E... elements) 478 { 479 fromBuilderOrTreeSet = false; 480 481 if (elements.length == 0) 482 this.treeSet = (TreeSet<E>) EMPTY_TREE_SET; 483 484 else 485 { 486 this.treeSet = (comparator != null) 487 ? new TreeSet<>(comparator) 488 : new TreeSet<>(); 489 490 for (E e : elements) this.treeSet.add(e); 491 } 492 } 493 494 /** 495 * Builds {@code ReadOnlyTreeSet<E>} instance having Generic-Type {@code 'E'}, and contents 496 * {@code 'elements'}. 497 * 498 * <EMBED CLASS='external-html' DATA-FILE-ID=TREESET_CMPR_WARN> 499 * 500 * @param <T> <EMBED CLASS='external-html' DATA-FILE-ID=VARARGS_TYPE_PARAM> 501 * @param comparator <EMBED CLASS='external-html' DATA-FILE-ID=COMPARATOR> 502 * @param mapper <EMBED CLASS='external-html' DATA-FILE-ID=T_ARR_E_MAPPER> 503 * @param elements <EMBED CLASS='external-html' DATA-FILE-ID=ELEMENTS_VAR_ARGS> 504 * 505 * @throws NullPointerException If {@code 'mapper'} is passed null. 506 */ 507 @SafeVarargs 508 public <T> ReadOnlyTreeSet( 509 Comparator<? super E> comparator, 510 Function<? super T, ? extends E> mapper, 511 T... elements 512 ) 513 { 514 Objects.requireNonNull(mapper, ROHelpers.NULL_MSG + "'mapper'"); 515 516 fromBuilderOrTreeSet = false; 517 518 if (elements.length == 0) 519 this.treeSet = (TreeSet<E>) EMPTY_TREE_SET; 520 521 else 522 { 523 this.treeSet = (comparator != null) 524 ? new TreeSet<>(comparator) 525 : new TreeSet<>(); 526 527 for (T t : elements) this.treeSet.add(mapper.apply(t)); 528 } 529 } 530 531 /** 532 * Builds {@code ReadOnlyTreeSet<E>} instance having Generic-Type {@code 'E'}, and contents 533 * {@code 'elements'}. 534 * 535 * <EMBED CLASS='external-html' DATA-FILE-ID=TREESET_CMPR_WARN> 536 * 537 * @param filter <EMBED CLASS='external-html' DATA-FTP=E DATA-FILE-ID=PREDICATE_FILTER> 538 * @param comparator <EMBED CLASS='external-html' DATA-FILE-ID=COMPARATOR> 539 * @param elements <EMBED CLASS='external-html' DATA-FILE-ID=ELEMENTS_VAR_ARGS> 540 * 541 * @throws NullPointerException If {@code 'filter'} is passed null. 542 */ 543 @SafeVarargs 544 public ReadOnlyTreeSet( 545 Predicate<? super E> filter, 546 Comparator<? super E> comparator, 547 E... elements 548 ) 549 { 550 Objects.requireNonNull(filter, ROHelpers.NULL_MSG + "'filter'"); 551 552 fromBuilderOrTreeSet = false; 553 554 TreeSet<E> treeSet = (comparator != null) 555 ? new TreeSet<>(comparator) 556 : new TreeSet<>(); 557 558 for (E e : elements) if (filter.test(e)) treeSet.add(e); 559 560 // Empty Optimization (throw away, completely, the reference, use static-constant) 561 this.treeSet = (treeSet.size() == 0) ? ((TreeSet<E>) EMPTY_TREE_SET) : treeSet; 562 } 563 564 /** 565 * Builds {@code ReadOnlyTreeSet<E>} instance having Generic-Type {@code 'E'}, and contents 566 * {@code 'elements'}. 567 * 568 * <EMBED CLASS='external-html' DATA-FILE-ID=TREESET_CMPR_WARN> 569 * 570 * @param <T> <EMBED CLASS='external-html' DATA-FILE-ID=VARARGS_TYPE_PARAM> 571 * @param filter <EMBED CLASS='external-html' DATA-FTP=T DATA-FILE-ID=PREDICATE_FILTER> 572 * @param mapper <EMBED CLASS='external-html' DATA-FILE-ID=T_ARR_E_MAPPER> 573 * @param comparator <EMBED CLASS='external-html' DATA-FILE-ID=COMPARATOR> 574 * @param elements <EMBED CLASS='external-html' DATA-FILE-ID=ELEMENTS_VAR_ARGS> 575 * 576 * @throws NullPointerException If either {@code 'mapper'} or {@code 'filter'} are passed null 577 */ 578 @SafeVarargs 579 public <T> ReadOnlyTreeSet( 580 Predicate<? super T> filter, 581 Function<? super T, ? extends E> mapper, 582 Comparator<? super E> comparator, 583 T... elements 584 ) 585 { 586 Objects.requireNonNull(mapper, ROHelpers.NULL_MSG + "'mapper'"); 587 Objects.requireNonNull(filter, ROHelpers.NULL_MSG + "'filter'"); 588 589 fromBuilderOrTreeSet = false; 590 591 TreeSet<E> treeSet = (comparator != null) 592 ? new TreeSet<>(comparator) 593 : new TreeSet<>(); 594 595 for (T t : elements) if (filter.test(t)) treeSet.add(mapper.apply(t)); 596 597 // Empty Optimization (throw away, completely, the reference, use static-constant) 598 this.treeSet = (treeSet.size() == 0) ? ((TreeSet<E>) EMPTY_TREE_SET) : treeSet; 599 } 600 601 602 // ******************************************************************************************** 603 // ******************************************************************************************** 604 // PRIMITIVE-ARRAY INPUT 605 // ******************************************************************************************** 606 // ******************************************************************************************** 607 608 609 /** 610 * Converts a Java Primitive-Array to a {@code ReadOnlyTreeSet<E>}, where {@code 'E'} is the 611 * Java Boxed-Type which corresponds to the Primitive-Array's Type. 612 * 613 * <EMBED CLASS='external-html' DATA-FILE-ID=PRIM_ARR_CTOR_DESC> 614 * @param primitiveArray <EMBED CLASS='external-html' DATA-FILE-ID=PRIMITIVE_ARRAY> 615 * @throws ClassCastException <EMBED CLASS='external-html' DATA-FILE-ID=PRIM_ARR_CCEX> 616 * @throws NullPointerException If {@code 'primitiveArray'} is passed null; 617 */ 618 public ReadOnlyTreeSet(Object primitiveArray, Comparator<? super E> comparator) 619 { 620 fromBuilderOrTreeSet = false; 621 622 TreeSet<E> ts = ROHelpers.buildROListOrSet( 623 primitiveArray, 624 (int arrayLen) -> (comparator != null) ? new TreeSet<E>(comparator) : new TreeSet<E>(), 625 null 626 ); 627 628 // Empty Optimization (throw away, completely, the reference, use static-constant) 629 this.treeSet = (ts.size() == 0) ? ((TreeSet<E>) EMPTY_TREE_SET) : ts; 630 } 631 632 /** 633 * Converts a Java Primitive-Array to a {@code ReadOnlyTreeSet<E>}, where {@code 'E'} is the 634 * Java Boxed-Type which corresponds to the Primitive-Array's Type - <I>but also accepts a 635 * {@code 'filter'} that can remove any array-entries that need to be removed</I>. 636 * 637 * <EMBED CLASS='external-html' DATA-FILE-ID=PRIM_ARR_CTOR_DESC> 638 * @param primitiveArray <EMBED CLASS='external-html' DATA-FILE-ID=PRIMITIVE_ARRAY> 639 * @param filter <EMBED CLASS='external-html' DATA-FILE-ID=PRED_FILT_PRIM> 640 * @throws ClassCastException <EMBED CLASS='external-html' DATA-FILE-ID=PRIM_ARR_CCEX> 641 * @throws NullPointerException If {@code 'primitiveArray'} is passed null; 642 */ 643 public ReadOnlyTreeSet( 644 Object primitiveArray, 645 Comparator<? super E> comparator, 646 Predicate<?> filter 647 ) 648 { 649 Objects.requireNonNull(filter, ROHelpers.NULL_MSG + "'filter'"); 650 651 fromBuilderOrTreeSet = false; 652 653 TreeSet<E> ts = ROHelpers.buildROListOrSet( 654 primitiveArray, 655 (int arrayLen) -> (comparator != null) ? new TreeSet<E>(comparator) : new TreeSet<E>(), 656 filter 657 ); 658 659 // Empty Optimization (throw away, completely, the reference, use static-constant) 660 this.treeSet = (ts.size() == 0) ? ((TreeSet<E>) EMPTY_TREE_SET) : ts; 661 } 662 663 664 // ******************************************************************************************** 665 // ******************************************************************************************** 666 // java.util.stream.Stream HELPER 667 // ******************************************************************************************** 668 // ******************************************************************************************** 669 670 671 /** 672 * For use with a the Java Stream method {@code 'collect(Collector c)'}. 673 * 674 * <EMBED CLASS='external-html' DATA-ABBREV=ts DATA-FILE-ID=STREAM_COLLECTOR> 675 * 676 * @param <T> This is the Generic-Type of the Input-Stream. It will also be the Generic-Type 677 * of the {@code ReadOnlyTreeSet} that's returned from the stream's {@code collect} method. 678 * 679 * @param characteristics Optional Characteristics List. See Java Stream-API Documentation on 680 * {@code Collector.Characteristics} inner-class for more details. 681 * 682 * @return This returns a collector that may be piped into a stream's {@code 'collect'} method, 683 * as in the example, above. 684 */ 685 public static <T> java.util.stream.Collector 686 <T, ROTreeSetBuilder<T>, ReadOnlyTreeSet<T>> 687 streamCollector(Collector.Characteristics... characteristics) 688 { 689 return Collector.of( 690 ROTreeSetBuilder<T>::new, // The "Supplier" (builds a new ROTreeSetBuilder) 691 ROTreeSetBuilder<T>::add, // The "Accumulator" (adds elements to the builder) 692 693 // Oracle Making Life Difficult - It should be the line below, but, alas, it is not! 694 // ROTreeSetBuilder<T>::addAll, // The "Combiner" (combines multiple ROTreeSetBuilders) 695 // 696 // In Stream.collect(), the 3rd parameter - the "combiner" - is a "BiConsumer<R, R>" 697 // NOTE: A "BiConsumer" is a FunctionalInterface that does not return anything - it is 698 // (obviously) a "void" return method! 699 // 700 // **BUT** 701 // 702 // In Collector.of, the 3rd parameter - the "combiner" - is a "BinaryOperation<R>" 703 704 (ROTreeSetBuilder<T> rotsb1, ROTreeSetBuilder<T> rotsb2) -> 705 { 706 rotsb1.addAll(rotsb2); 707 return rotsb1; 708 }, 709 710 ROTreeSetBuilder<T>::build, // The "Finisher" (Converts Builder to ReadOnlyTreeSet) 711 characteristics 712 ); 713 } 714 715 716 // ******************************************************************************************** 717 // ******************************************************************************************** 718 // Convert to java.util Types 719 // ******************************************************************************************** 720 // ******************************************************************************************** 721 722 723 /** 724 * Clone's {@code 'this'} instance internal {@code TreeSet<E>} field, and returns it. 725 * <EMBED CLASS='external-html' DATA-TYPE=TreeSet DATA-FILE-ID=CLONE_TO> 726 * 727 * @return An independent, mutable copy of {@code 'this'} instance' internal {@code TreeSet<E>} 728 * data-structure. 729 */ 730 public TreeSet<E> cloneToTreeSet() 731 { 732 return fromBuilderOrTreeSet 733 ? new TreeSet<E>(this.treeSet) 734 : (TreeSet<E>) this.treeSet.clone(); 735 } 736 737 /** 738 * Invokes {@code java.util.Collections.unmodifiableSet} on the internal {@code TreeSet}. 739 * <EMBED CLASS='external-html' DATA-RET_TYPE=Set DATA-FILE-ID=WRAP_TO_IMMUTABLE> 740 * 741 * @return A {@code Set} which adheres to the JDK interface {@code java.util.Set}, but throws 742 * an {@code UnsupportedOperationException} if a user attempts to invoke a Mutator-Method on 743 * the returned instance. 744 */ 745 public Set<E> wrapToImmutableSet() 746 { return Collections.unmodifiableSet(this.treeSet); } 747 748 749 // ******************************************************************************************** 750 // ******************************************************************************************** 751 // Original JDK Methods, java.util.TreeSet 752 // ******************************************************************************************** 753 // ******************************************************************************************** 754 755 756 /** 757 * Returns an iterator over the elements in this set in ascending order. 758 * @return an iterator over the elements in this set in ascending order 759 */ 760 public RemoveUnsupportedIterator<E> iterator() 761 { return new RemoveUnsupportedIterator<>(this.treeSet.iterator()); } 762 763 /** 764 * Returns an iterator over the elements in this set in descending order. 765 * @return an iterator over the elements in this set in descending order 766 */ 767 public RemoveUnsupportedIterator<E> descendingIterator() 768 { return new RemoveUnsupportedIterator<>(this.treeSet.descendingIterator()); } 769 770 public ReadOnlyNavigableSet<E> descendingSet() 771 { 772 return InterfaceBuilder.toReadOnlyNavigableSet( 773 fromBuilderOrTreeSet 774 ? ((ROTreeSetBuilder<E>) this.treeSet)._descendingSet(friendClassBadge) 775 : this.treeSet.descendingSet() 776 ); 777 } 778 779 /** 780 * Returns the number of elements in this set (its cardinality). 781 * @return the number of elements in this set (its cardinality) 782 */ 783 public int size() 784 { return this.treeSet.size(); } 785 786 /** 787 * Returns {@code TRUE} if this set contains no elements. 788 * @return {@code TRUE} if this set contains no elements 789 */ 790 public boolean isEmpty() 791 { return this.treeSet.isEmpty(); } 792 793 /** 794 * Returns {@code TRUE} if this set contains the specified element. More formally, returns 795 * {@code TRUE} if and only if this set contains an element {@code e} such that 796 * {@code Objects.equals(o, e)}. 797 * 798 * @param o object to be checked for containment in this set 799 * @return {@code TRUE} if this set contains the specified element 800 * 801 * @throws ClassCastException if the specified object cannot be compared with the elements 802 * currently in the set 803 * 804 * @throws NullPointerException if the specified element is null and this set uses natural 805 * ordering, or its comparator does not permit null elements 806 */ 807 public boolean contains(Object o) 808 { return this.treeSet.contains(o); } 809 810 /** 811 * @throws ClassCastException {@inheritDoc} 812 * 813 * @throws NullPointerException if {@code fromElement} or {@code toElement} is null and this 814 * set uses natural ordering, or its comparator does not permit null elements 815 * 816 * @throws IllegalArgumentException {@inheritDoc} 817 */ 818 public ReadOnlyNavigableSet<E> subSet( 819 E fromElement, boolean fromInclusive, 820 E toElement, boolean toInclusive 821 ) 822 { 823 return InterfaceBuilder.toReadOnlyNavigableSet( 824 fromBuilderOrTreeSet 825 ? ((ROTreeSetBuilder<E>) this.treeSet)._subSet 826 (fromElement, fromInclusive, toElement, toInclusive, friendClassBadge) 827 : this.treeSet.subSet(fromElement, fromInclusive, toElement, toInclusive) 828 ); 829 } 830 831 /** 832 * @throws ClassCastException {@inheritDoc} 833 * 834 * @throws NullPointerException if {@code toElement} is null and this set uses natural 835 * ordering, or its comparator does not permit null elements 836 * 837 * @throws IllegalArgumentException {@inheritDoc} 838 */ 839 public ReadOnlyNavigableSet<E> headSet(E toElement, boolean inclusive) 840 { 841 return InterfaceBuilder.toReadOnlyNavigableSet( 842 fromBuilderOrTreeSet 843 ? ((ROTreeSetBuilder<E>) this.treeSet)._headSet 844 (toElement, inclusive, friendClassBadge) 845 : this.treeSet.headSet(toElement, inclusive) 846 ); 847 } 848 849 /** 850 * @throws ClassCastException {@inheritDoc} 851 * 852 * @throws NullPointerException if {@code fromElement} is null and this set uses natural 853 * ordering, or its comparator does not permit null elements 854 * 855 * @throws IllegalArgumentException {@inheritDoc} 856 */ 857 public ReadOnlyNavigableSet<E> tailSet(E fromElement, boolean inclusive) 858 { 859 return InterfaceBuilder.toReadOnlyNavigableSet( 860 fromBuilderOrTreeSet 861 ? ((ROTreeSetBuilder<E>) this.treeSet)._tailSet 862 (fromElement, inclusive, friendClassBadge) 863 : this.treeSet.tailSet(fromElement, inclusive) 864 ); 865 } 866 867 /** 868 * @throws ClassCastException {@inheritDoc} 869 * 870 * @throws NullPointerException if {@code fromElement} or {@code toElement} is null and this 871 * set uses natural ordering, or its comparator does not permit null elements 872 * 873 * @throws IllegalArgumentException {@inheritDoc} 874 */ 875 public ReadOnlySortedSet<E> subSet(E fromElement, E toElement) 876 { 877 return InterfaceBuilder.toReadOnlySortedSet( 878 fromBuilderOrTreeSet 879 ? ((ROTreeSetBuilder<E>) this.treeSet)._subSet 880 (fromElement, toElement, friendClassBadge) 881 : this.treeSet.subSet(fromElement, toElement) 882 ); 883 } 884 885 /** 886 * @throws ClassCastException {@inheritDoc} 887 * 888 * @throws NullPointerException if {@code toElement} is null and this set uses natural 889 * ordering, or its comparator does not permit null elements 890 * 891 * @throws IllegalArgumentException {@inheritDoc} 892 */ 893 public ReadOnlySortedSet<E> headSet(E toElement) 894 { 895 return InterfaceBuilder.toReadOnlySortedSet( 896 fromBuilderOrTreeSet 897 ? ((ROTreeSetBuilder<E>) this.treeSet)._headSet(toElement, friendClassBadge) 898 : this.treeSet.headSet(toElement) 899 ); 900 } 901 902 /** 903 * @throws ClassCastException {@inheritDoc} 904 * 905 * @throws NullPointerException if {@code fromElement} is null and this set uses natural 906 * ordering, or its comparator does not permit null elements 907 * 908 * @throws IllegalArgumentException {@inheritDoc} 909 */ 910 public ReadOnlySortedSet<E> tailSet(E fromElement) 911 { 912 return InterfaceBuilder.toReadOnlySortedSet( 913 fromBuilderOrTreeSet 914 ? ((ROTreeSetBuilder<E>) this.treeSet)._tailSet(fromElement, friendClassBadge) 915 : this.treeSet.tailSet(fromElement) 916 ); 917 } 918 919 public Comparator<? super E> comparator() 920 { return this.treeSet.comparator(); } 921 922 /** @throws NoSuchElementException {@inheritDoc} */ 923 public E first() 924 { return this.treeSet.first(); } 925 926 /** @throws NoSuchElementException {@inheritDoc} */ 927 public E last() 928 { return this.treeSet.last(); } 929 930 /** 931 * @throws ClassCastException {@inheritDoc} 932 * 933 * @throws NullPointerException if the specified element is null and this set uses natural 934 * ordering, or its comparator does not permit null elements 935 */ 936 public E lower(E e) 937 { return this.treeSet.lower(e); } 938 939 /** 940 * @throws ClassCastException {@inheritDoc} 941 * 942 * @throws NullPointerException if the specified element is null and this set uses natural 943 * ordering, or its comparator does not permit null elements 944 */ 945 public E floor(E e) 946 { return this.treeSet.floor(e); } 947 948 /** 949 * @throws ClassCastException {@inheritDoc} 950 * 951 * @throws NullPointerException if the specified element is null and this set uses natural 952 * ordering, or its comparator does not permit null elements 953 */ 954 public E ceiling(E e) 955 { return this.treeSet.ceiling(e); } 956 957 /** 958 * @throws ClassCastException {@inheritDoc} 959 * 960 * @throws NullPointerException if the specified element is null and this set uses natural 961 * ordering, or its comparator does not permit null elements 962 */ 963 public E higher(E e) 964 { return this.treeSet.higher(e); } 965 966 /** 967 * Utilizes the private, internal {@code java.util.TreeSet} field to generate a 968 * {@code Spliterator}. 969 * 970 * @return a {@code Spliterator} over the elements in this set 971 */ 972 public Spliterator<E> spliterator() 973 { return this.treeSet.spliterator(); } 974 975 976 // ******************************************************************************************** 977 // ******************************************************************************************** 978 // Misc Stuff that is defined in a super-class - for java.util, but not for Java.ReadOnly 979 // ******************************************************************************************** 980 // ******************************************************************************************** 981 982 983 public boolean containsAll(Collection<?> c) 984 { return this.treeSet.containsAll(c); } 985 986 public <T> T[] toArray​(T[] a) 987 { return this.treeSet.toArray(a); } 988 989 public Object[] toArray() 990 { return this.treeSet.toArray(); } 991 992 993 // ******************************************************************************************** 994 // ******************************************************************************************** 995 // java.lang.Object 996 // ******************************************************************************************** 997 // ******************************************************************************************** 998 999 1000 /** 1001 * Returns a {@code String} representation of this {@code TreeSet}. The {@code String} 1002 * representation consists of a list of the collection's elements in the order they are 1003 * returned by its iterator, enclosed in square brackets ({@code "[]"}). Adjacent elements are 1004 * separated by the characters {@code ", "} (comma and space). Elements are converted to 1005 * {@code String's} as by {@code String.valueOf(Object)}. 1006 * 1007 * @return a {@code String} representation of this {@code TreeSet} 1008 */ 1009 public String toString() 1010 { return this.treeSet.toString(); } 1011 1012 /** 1013 * Compares the specified Object with this Set for equality, as per the definition in the 1014 * class {@code java.util.TreeSet}. 1015 * 1016 * @param o object to be compared for equality with this {@code ReadOnlyTreeSet}. 1017 * @return {@code TRUE} if the specified Object is equal to this set 1018 */ 1019 public boolean equals(Object o) 1020 { return ROHelpers.roSetEq(this, o); } 1021 1022 /** 1023 * Returns the hash code value for this Set as per the definition in the class 1024 * {@code java.util.TreeSet}. 1025 */ 1026 public int hashCode() 1027 { return this.treeSet.hashCode(); } 1028} 1029