001/* 002 * Copyright (c) 1994, 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; 028import Torello.Java.ReadOnly.ROVectorBuilder; 029 030import java.io.IOException; 031import java.io.ObjectInputStream; 032import java.io.StreamCorruptedException; 033 034import java.util.*; 035 036import java.util.stream.Collector; 037 038import java.util.function.Consumer; 039import java.util.function.Function; 040import java.util.function.Supplier; 041import java.util.function.Predicate; 042 043/** 044 * Immutable Wrapper for <CODE>java.util.Vector</CODE>, found in the "Java Collections 045 * Framework". 046 * 047 * <EMBED CLASS=globalDefs DATA-JDK=Vector> 048 * <EMBED CLASS='external-html' DATA-FILE-ID=MUCHOS_CONSTRUCTORS> 049 * <EMBED CLASS='external-html' DATA-FILE-ID=DATA_CLASS> 050 * <EMBED CLASS='external-html' DATA-FILE-ID=RO_SYNCHRONIZED> 051 * 052 * @param <E> Type of component elements 053 */ 054@Torello.JavaDoc.JDHeaderBackgroundImg(EmbedTagFileID="JDHBI_MAIN") 055@SuppressWarnings("unchecked") 056public class ReadOnlyVector<E> 057 // extends AbstractReadOnlyList<E> 058 implements ReadOnlyList<E>, RandomAccess, java.io.Serializable 059{ 060 // ******************************************************************************************** 061 // ******************************************************************************************** 062 // Protected & Private Fields, Methods, Statics 063 // ******************************************************************************************** 064 // ******************************************************************************************** 065 066 067 /** <EMBED CLASS='external-html' DATA-FILE-ID=SVUID> */ 068 protected static final long serialVersionUID = 1; 069 070 // Minor Optimization where new Vector's that have no contents always re-use this static 071 // instance. Since this instance is completely empty, the Raw-Types things is irrelevant. 072 073 @SuppressWarnings("rawtypes") 074 private static final Vector EMPTY_VECTOR = new Vector(0); 075 076 // Singleton & Empty ReadOnlyVector, Uses the "Supplier Constructor" 077 @SuppressWarnings("rawtypes") 078 private static final ReadOnlyVector EMPTY_READONLY_VECTOR = 079 new ReadOnlyVector(0, () -> null); 080 081 // The actual Vector used by this instance. 082 private final Vector<E> vector; 083 084 // TRUE => This was built using the class ROVectorBuilder 085 // FALSE => This was built using the clone() of a standard java.util.Vector constructor 086 087 private final boolean fromBuilderOrVector; 088 089 // Mimics the C++ Keyword/Concept of "Friend Class". Is "Friends With" ROVectorBuilder 090 static class AccessBadge { private AccessBadge() { } } 091 private static final AccessBadge friendClassBadge = new AccessBadge(); 092 093 public static <T> ReadOnlyVector<T> emptyROV() 094 { return (ReadOnlyVector<T>) EMPTY_READONLY_VECTOR; } 095 096 097 // ******************************************************************************************** 098 // ******************************************************************************************** 099 // Basic Constructors 100 // ******************************************************************************************** 101 // ******************************************************************************************** 102 103 104 // To all the readers out there following along: The "AccessBadge" thing is just a slightly 105 // wimpier substitute for the C++ keyword / concept 'friend' or "Friend Class". It means this 106 // constructor is (for all intents and purposes) a private-constructor, except for the class 107 // ROVectorBuilder 108 // 109 // This is the Constructor used by the Builder. It has a "Zero-Size" Optimization 110 111 ReadOnlyVector(ROVectorBuilder<E> rovb, ROVectorBuilder.AccessBadge badge) 112 { 113 Objects.requireNonNull(badge, "Access Badge is null. Requires Friend-Class Badge"); 114 115 this.fromBuilderOrVector = true; 116 this.vector = rovb; 117 } 118 119 /** 120 * Copies parameter {@code 'c'} (and saves it) in order to guarantee that {@code 'this'} 121 * instance is Read-Only, and shielded from outside modification. 122 * 123 * @param c The {@code Collection} to be copied and saved into this instance internal 124 * and private {@code 'vector'} field. 125 */ 126 public ReadOnlyVector(Collection<E> c) 127 { 128 this.fromBuilderOrVector = false; 129 130 // Empty Optimization (throw away, completely, the reference, use static-constant) 131 this.vector = (c.size() == 0) ? ((Vector<E>) EMPTY_VECTOR) : new Vector<>(c); 132 } 133 134 /** 135 * Use a {@code Supplier<E>} to provide an arbitrary number of elements of type {@code 'E'} 136 * directly to this constructor. This constructor will request elements from the 137 * {@code Supplier} provided to parameter {@code 's'} until {@code 's'} returns null. 138 * 139 * @param quantityIfKnown If the number of elements to be supplied is known, that number may be 140 * provided so that the internal {@code Vector} is adequately initialized at the beginning 141 * of the constructor, without any need for resizing during construction. 142 * 143 * <BR /><BR />If this parameter is passed null, it will be ignored. When this happens, the 144 * initialization of the internal {@code Vector} will be done by Java's default (Zero 145 * Argument) {@code Vector}-Constructor. 146 * 147 * <BR /><BR />It is not mandatory that the value provided be accurate, as ought be seen in the 148 * code below, this value is solely used for the {@code 'initialCapacity'} parameter to the 149 * {@code Vector} constructor. 150 * 151 * @param s Any Java {@code Supplier<E>} 152 * 153 * @throws IllegalArgumentException if the specified quantity / capacity is negative 154 */ 155 public ReadOnlyVector(Integer quantityIfKnown, Supplier<E> s) 156 { 157 fromBuilderOrVector = false; 158 159 Vector<E>vector = (quantityIfKnown != null) 160 ? new Vector<>(quantityIfKnown) 161 : new Vector<>(); 162 163 E e; 164 while ((e = s.get()) != null) vector.add(e); 165 166 // Empty Optimization (throw away, completely, the reference, use static-constant) 167 this.vector = (vector.size() == 0) ? ((Vector<E>) EMPTY_VECTOR) : vector; 168 } 169 170 171 // ******************************************************************************************** 172 // ******************************************************************************************** 173 // Iterable & Array Based Constructors - **NO FILTER** 174 // ******************************************************************************************** 175 // ******************************************************************************************** 176 177 178 /** 179 * If only a small amount of processing needs to be done on the contents of some Java 180 * Data-Type, and using an entire Builder-Class seems disproportionately complex - <I>this 181 * constructor can convert any Java {@code Iterable} into a {@code ReadOnlyVector}, using 182 * a simple {@code 'mapper'}</I>. 183 * 184 * <EMBED CLASS=defs DATA-SOURCE=Iterable> 185 * 186 * @param <T> <EMBED CLASS='external-html' DATA-FILE-ID=ITERABLE_TYPE_PARAM> 187 * @param i Any Java {@code Iterable<T>} 188 * @param mapper <EMBED CLASS='external-html' DATA-FILE-ID=ITERABLE_MAPPER> 189 * @param sizeIfKnown <EMBED CLASS='external-html' DATA-FILE-ID=VECAL_INIT_CAPACITY> 190 * 191 * @throws NullPointerException If either {@code 'i'} or {@code 'mapper'} are passed null. 192 */ 193 public <T> ReadOnlyVector( 194 Iterable<T> i, 195 Function<? super T, ? extends E> mapper, 196 Integer sizeIfKnown 197 ) 198 { 199 Objects.requireNonNull(mapper, ROHelpers.NULL_MSG + "'mapper'"); 200 201 fromBuilderOrVector = false; 202 203 Vector<E> vector = (sizeIfKnown != null) 204 ? new Vector<>(sizeIfKnown) 205 : new Vector<>(); 206 207 for (T t : i) vector.add(mapper.apply(t)); 208 209 // Empty Optimization (throw away, completely, the reference, use static-constant) 210 this.vector = (vector.size() == 0) ? ((Vector<E>) EMPTY_VECTOR) : vector; 211 } 212 213 /** 214 * If a Standard Java {@code Iterable} can be directly mapped into a {@code Vector} 215 * (and, ergo, an entire Builder-Instance would be a bit excessive) - <I>this constructor will 216 * seamlessly convert any Java {@code Iterable<E>} directly into a {@code ReadOnlyVector<E>} 217 * with just this single invocation</I>. 218 * 219 * <EMBED CLASS=defs DATA-SOURCE=Iterable> 220 * 221 * @param i Any Java {@code Iteratable<E>} 222 * @param sizeIfKnown <EMBED CLASS='external-html' DATA-FILE-ID=VECAL_INIT_CAPACITY> 223 * 224 * @throws IllegalArgumentException if the specified initial capacity is negative 225 */ 226 public ReadOnlyVector(Iterable<E> i, Integer sizeIfKnown) 227 { 228 fromBuilderOrVector = false; 229 230 Vector<E> vector = (sizeIfKnown != null) 231 ? new Vector<>(sizeIfKnown) 232 : new Vector<>(); 233 234 for (E element : i) vector.add(element); 235 236 // Empty Optimization (throw away, completely, the reference, use static-constant) 237 this.vector = (vector.size() == 0) ? ((Vector<E>) EMPTY_VECTOR) : vector; 238 } 239 240 /** 241 * Builds {@code ReadOnlyVector<E>} instance having Generic-Type {@code 'E'}, and contents 242 * {@code 'elements'}. 243 * 244 * @param elementsType <EMBED CLASS='external-html' DATA-FILE-ID=ELEMENTS_TYPE> 245 * @param elements <EMBED CLASS='external-html' DATA-FILE-ID=ELEMENTS_VAR_ARGS> 246 * 247 * @throws ClassCastException <EMBED CLASS='external-html' DATA-FILE-ID=CCEX> 248 * @throws NullPointerException If {@code 'elementsType'} is passed null. 249 */ 250 public ReadOnlyVector(Class<E> elementsType, Object... elements) 251 { 252 Objects.requireNonNull(elementsType, ROHelpers.NULL_MSG + "'elementsType'"); 253 254 fromBuilderOrVector = false; 255 256 if (elements.length == 0) 257 this.vector = (Vector<E>) EMPTY_VECTOR; 258 259 else 260 { 261 this.vector = new Vector<>(elements.length); 262 for (Object element : elements) this.vector.add(elementsType.cast(element)); 263 } 264 } 265 266 /** 267 * Builds {@code ReadOnlyVector<E>} instance having Generic-Type {@code 'E'}, and contents 268 * {@code 'elements'}. 269 * 270 * @param mapper <EMBED CLASS='external-html' DATA-FILE-ID=OBJ_E_MAPPER> 271 * @param elements <EMBED CLASS='external-html' DATA-FILE-ID=ELEMENTS_VAR_ARGS> 272 * 273 * @throws ClassCastException <EMBED CLASS='external-html' DATA-FILE-ID=CCEX> 274 * @throws NullPointerException If {@code 'mapper'} is passed null. 275 */ 276 public ReadOnlyVector(Function<Object, ? extends E> mapper, Object... elements) 277 { 278 Objects.requireNonNull(mapper, ROHelpers.NULL_MSG + "'mapper'"); 279 280 fromBuilderOrVector = false; 281 282 if (elements.length == 0) 283 this.vector = (Vector<E>) EMPTY_VECTOR; 284 285 else 286 { 287 this.vector = new Vector<>(elements.length); 288 for (Object element : elements) this.vector.add(mapper.apply(element)); 289 } 290 } 291 292 293 // ******************************************************************************************** 294 // ******************************************************************************************** 295 // Iterable & Array Based Constructors - **INCLUDES ELEMENT FILTER** 296 // ******************************************************************************************** 297 // ******************************************************************************************** 298 299 300 /** 301 * If only a small amount of processing needs to be done on the contents of some Java 302 * Data-Type, and using an entire Builder-Class seems disproportionately complex - <I>this 303 * constructor can convert any Java {@code Iterable} into a {@code ReadOnlyVector}, using 304 * a simple {@code 'mapper'}</I>. 305 * 306 * <EMBED CLASS=defs DATA-SOURCE=Iterable> 307 * 308 * @param <T> <EMBED CLASS='external-html' DATA-FILE-ID=ITERABLE_TYPE_PARAM> 309 * @param i Any Java {@code Iterable<T>} 310 * @param mapper <EMBED CLASS='external-html' DATA-FILE-ID=ITERABLE_MAPPER> 311 * @param filter <EMBED CLASS='external-html' DATA-FTP=T DATA-FILE-ID=PREDICATE_FILTER> 312 * @param sizeIfKnown <EMBED CLASS='external-html' DATA-FILE-ID=VECAL_INIT_CAPACITY> 313 * 314 * @throws NullPointerException If any of {@code 'i'}, {@code 'mapper'} or {@code 'filter'} are 315 * passed null. 316 */ 317 public <T> ReadOnlyVector( 318 Iterable<T> i, 319 Function<? super T, ? extends E> mapper, 320 Predicate<? super T> filter, 321 Integer sizeIfKnown 322 ) 323 { 324 Objects.requireNonNull(mapper, ROHelpers.NULL_MSG + "'mapper'"); 325 Objects.requireNonNull(filter, ROHelpers.NULL_MSG + "'filter'"); 326 327 fromBuilderOrVector = false; 328 329 Vector<E> vector = (sizeIfKnown != null) 330 ? new Vector<>(sizeIfKnown) 331 : new Vector<>(); 332 333 for (T t : i) if (filter.test(t)) vector.add(mapper.apply(t)); 334 335 // Empty Optimization (throw away, completely, the reference, use static-constant) 336 this.vector = (vector.size() == 0) ? ((Vector<E>) EMPTY_VECTOR) : vector; 337 } 338 339 /** 340 * If a Standard Java {@code Iterable} can be directly mapped into an {@code Vector} 341 * (and, ergo, an entire Builder-Instance would be a bit excessive) - <I>this constructor will 342 * seamlessly convert any Java {@code Iterable<E>} directly into a {@code ReadOnlyVector<E>} 343 * with just this single invocation</I>. 344 * 345 * <EMBED CLASS=defs DATA-SOURCE=Iterable> 346 * 347 * @param i Any Java {@code Iteratable<E>} 348 * @param filter <EMBED CLASS='external-html' DATA-FTP=E DATA-FILE-ID=PREDICATE_FILTER> 349 * @param sizeIfKnown <EMBED CLASS='external-html' DATA-FILE-ID=VECAL_INIT_CAPACITY> 350 * 351 * @throws IllegalArgumentException if the specified initial capacity is negative 352 * @throws NullPointerException If either {@code 'i'} or {@code 'filter'} are passed null. 353 */ 354 public ReadOnlyVector(Iterable<E> i, Predicate<? super E> filter, Integer sizeIfKnown) 355 { 356 Objects.requireNonNull(filter, ROHelpers.NULL_MSG + "'filter'"); 357 358 fromBuilderOrVector = false; 359 360 Vector<E> vector = (sizeIfKnown != null) 361 ? new Vector<>(sizeIfKnown) 362 : new Vector<>(); 363 364 for (E element : i) if (filter.test(element)) vector.add(element); 365 366 // Empty Optimization (throw away, completely, the reference, use static-constant) 367 this.vector = (vector.size() == 0) ? ((Vector<E>) EMPTY_VECTOR) : vector; 368 } 369 370 /** 371 * Builds {@code ReadOnlyVector<E>} instance having Generic-Type {@code 'E'}, and contents 372 * {@code 'elements'}. 373 * 374 * @param elementsType <EMBED CLASS='external-html' DATA-FILE-ID=ELEMENTS_TYPE> 375 * @param filter <EMBED CLASS='external-html' DATA-FTP=E DATA-FILE-ID=PREDICATE_FILTER> 376 * @param elements <EMBED CLASS='external-html' DATA-FILE-ID=ELEMENTS_VAR_ARGS> 377 * 378 * @throws ClassCastException <EMBED CLASS='external-html' DATA-FILE-ID=CCEX> 379 * 380 * @throws NullPointerException If either {@code 'elementsType'} or {@code 'filter'} are passed 381 * null. 382 */ 383 public ReadOnlyVector 384 (Class<E> elementsType, Predicate<? super E> filter, Object... elements) 385 { 386 Objects.requireNonNull(elementsType, ROHelpers.NULL_MSG + "'elementsType'"); 387 Objects.requireNonNull(filter, ROHelpers.NULL_MSG + "'filter'"); 388 389 fromBuilderOrVector = false; 390 391 Vector<E> vector = new Vector<>(elements.length); 392 393 E e; 394 for (Object element : elements) 395 if (filter.test(e = elementsType.cast(element))) 396 vector.add(e); 397 398 // Empty Optimization (throw away, completely, the reference, use static-constant) 399 this.vector = (vector.size() == 0) ? ((Vector<E>) EMPTY_VECTOR) : vector; 400 } 401 402 /** 403 * Builds {@code ReadOnlyVector<E>} instance having Generic-Type {@code 'E'}, and contents 404 * {@code 'elements'}. 405 * 406 * @param mapper <EMBED CLASS='external-html' DATA-FILE-ID=OBJ_E_MAPPER> 407 * @param filter <EMBED CLASS='external-html' DATA-FTP=Object DATA-FILE-ID=PREDICATE_FILTER> 408 * @param elements <EMBED CLASS='external-html' DATA-FILE-ID=ELEMENTS_VAR_ARGS> 409 * 410 * @throws NullPointerException If either {@code 'mapper'} or {@code 'filter'} are passed null 411 */ 412 public ReadOnlyVector( 413 Function<Object, ? extends E> mapper, 414 Predicate<Object> filter, 415 Object... elements 416 ) 417 { 418 Objects.requireNonNull(mapper, ROHelpers.NULL_MSG + "'mapper'"); 419 Objects.requireNonNull(filter, ROHelpers.NULL_MSG + "'filter'"); 420 421 fromBuilderOrVector = false; 422 423 Vector<E> vector = new Vector<>(elements.length); 424 425 for (Object element : elements) 426 if (filter.test(element)) 427 vector.add(mapper.apply(element)); 428 429 // Empty Optimization (throw away, completely, the reference, use static-constant) 430 this.vector = (vector.size() == 0) ? ((Vector<E>) EMPTY_VECTOR) : vector; 431 } 432 433 434 // ******************************************************************************************** 435 // ******************************************************************************************** 436 // @SafeVarargs / Variable-Arity / VarArgs: with Parameterized / Generic Type's 437 // ******************************************************************************************** 438 // ******************************************************************************************** 439 440 441 /** 442 * Builds {@code ReadOnlyVector<E>} instance having Generic-Type {@code 'E'}, and contents 443 * {@code 'elements'}. 444 * 445 * @param elements <EMBED CLASS='external-html' DATA-FILE-ID=ELEMENTS_VAR_ARGS> 446 */ 447 @SafeVarargs 448 public ReadOnlyVector(E... elements) 449 { 450 fromBuilderOrVector = false; 451 452 if (elements.length == 0) 453 this.vector = (Vector<E>) EMPTY_VECTOR; 454 455 else 456 { 457 this.vector = new Vector<>(elements.length); 458 for (E e : elements) this.vector.add(e); 459 } 460 } 461 462 /** 463 * Builds {@code ReadOnlyVector<E>} instance having Generic-Type {@code 'E'}, and contents 464 * {@code 'elements'}. 465 * 466 * @param <T> <EMBED CLASS='external-html' DATA-FILE-ID=VARARGS_TYPE_PARAM> 467 * @param dummy <EMBED CLASS='external-html' DATA-FILE-ID=DUMMY_INT> 468 * @param mapper <EMBED CLASS='external-html' DATA-FILE-ID=T_ARR_E_MAPPER> 469 * @param elements <EMBED CLASS='external-html' DATA-FILE-ID=ELEMENTS_VAR_ARGS> 470 * 471 * @throws NullPointerException If {@code 'mapper'} is null. 472 */ 473 @SafeVarargs 474 public <T> ReadOnlyVector 475 (int dummy, Function<? super T, ? extends E> mapper, T... elements) 476 { 477 Objects.requireNonNull(mapper, ROHelpers.NULL_MSG + "'mapper'"); 478 479 fromBuilderOrVector = false; 480 481 if (elements.length == 0) 482 this.vector = (Vector<E>) EMPTY_VECTOR; 483 484 else 485 { 486 this.vector = new Vector<>(elements.length); 487 for (T t : elements) this.vector.add(mapper.apply(t)); 488 } 489 } 490 491 /** 492 * Builds {@code ReadOnlyVector<E>} instance having Generic-Type {@code 'E'}, and contents 493 * {@code 'elements'}. 494 * 495 * @param filter <EMBED CLASS='external-html' DATA-FTP=E DATA-FILE-ID=PREDICATE_FILTER> 496 * @param elements <EMBED CLASS='external-html' DATA-FILE-ID=ELEMENTS_VAR_ARGS> 497 * 498 * @throws NullPointerException If {@code 'elementsType'} is null. 499 */ 500 @SafeVarargs 501 public ReadOnlyVector(Predicate<? super E> filter, E... elements) 502 { 503 Objects.requireNonNull(filter, ROHelpers.NULL_MSG + "'filter'"); 504 505 fromBuilderOrVector = false; 506 507 Vector<E> vector = new Vector<>(elements.length); 508 for (E e : elements) if (filter.test(e)) vector.add(e); 509 510 // Empty Optimization (throw away, completely, the reference, use static-constant) 511 this.vector = (vector.size() == 0) ? ((Vector<E>) EMPTY_VECTOR) : vector; 512 } 513 514 /** 515 * Builds {@code ReadOnlyVector<E>} instance having Generic-Type {@code 'E'}, and contents 516 * {@code 'elements'}. 517 * 518 * @param <T> <EMBED CLASS='external-html' DATA-FILE-ID=VARARGS_TYPE_PARAM> 519 * @param filter <EMBED CLASS='external-html' DATA-FTP=T DATA-FILE-ID=PREDICATE_FILTER> 520 * @param mapper <EMBED CLASS='external-html' DATA-FILE-ID=T_ARR_E_MAPPER> 521 * @param elements <EMBED CLASS='external-html' DATA-FILE-ID=ELEMENTS_VAR_ARGS> 522 * 523 * @throws NullPointerException If {@code 'mapper'} or {@code 'filter'} is null. 524 */ 525 @SafeVarargs 526 public <T> ReadOnlyVector( 527 Predicate<? super T> filter, 528 Function<? super T, ? extends E> mapper, 529 T... elements 530 ) 531 { 532 Objects.requireNonNull(mapper, ROHelpers.NULL_MSG + "'mapper'"); 533 Objects.requireNonNull(filter, ROHelpers.NULL_MSG + "'filter'"); 534 535 fromBuilderOrVector = false; 536 537 Vector<E> vector = new Vector<>(elements.length); 538 for (T t : elements) if (filter.test(t)) vector.add(mapper.apply(t)); 539 540 // Empty Optimization (throw away, completely, the reference, use static-constant) 541 this.vector = (vector.size() == 0) ? ((Vector<E>) EMPTY_VECTOR) : vector; 542 } 543 544 545 // ******************************************************************************************** 546 // ******************************************************************************************** 547 // PRIMITIVE-ARRAY INPUT 548 // ******************************************************************************************** 549 // ******************************************************************************************** 550 551 552 /** 553 * Converts a Java Primitive-Array to a {@code ReadOnlyVector<E>}, where {@code 'E'} is the 554 * Java Boxed-Type which corresponds to the Primitive-Array's Type. 555 * 556 * <EMBED CLASS='external-html' DATA-FILE-ID=PRIM_ARR_CTOR_DESC> 557 * @param primitiveArray <EMBED CLASS='external-html' DATA-FILE-ID=PRIMITIVE_ARRAY> 558 * @throws ClassCastException <EMBED CLASS='external-html' DATA-FILE-ID=PRIM_ARR_CCEX> 559 * @throws NullPointerException If {@code 'primitiveArray'} is passed null; 560 */ 561 public ReadOnlyVector(Object primitiveArray) 562 { 563 fromBuilderOrVector = false; 564 565 Vector<E> v = ROHelpers.buildROListOrSet( 566 primitiveArray, 567 (int arrayLen) -> new Vector<E>(arrayLen), 568 null 569 ); 570 571 // Empty Optimization (throw away, completely, the reference, use static-constant) 572 this.vector = (v.size() == 0) ? ((Vector<E>) EMPTY_VECTOR) : v; 573 } 574 575 /** 576 * Converts a Java Primitive-Array to a {@code ReadOnlyVector<E>}, where {@code 'E'} is the 577 * Java Boxed-Type which corresponds to the Primitive-Array's Type - <I>but also accepts a 578 * {@code 'filter'} that can remove any array-entries that need to be removed</I>. 579 * 580 * 581 * <EMBED CLASS='external-html' DATA-FILE-ID=PRIM_ARR_CTOR_DESC> 582 * @param primitiveArray <EMBED CLASS='external-html' DATA-FILE-ID=PRIMITIVE_ARRAY> 583 * @param filter <EMBED CLASS='external-html' DATA-FILE-ID=PRED_FILT_PRIM> 584 * @throws ClassCastException <EMBED CLASS='external-html' DATA-FILE-ID=PRIM_ARR_CCEX> 585 * @throws NullPointerException If {@code 'primitiveArray'} is passed null; 586 */ 587 public ReadOnlyVector( 588 Object primitiveArray, 589 Predicate<?> filter 590 ) 591 { 592 Objects.requireNonNull(filter, ROHelpers.NULL_MSG + "'filter'"); 593 594 fromBuilderOrVector = false; 595 596 Vector<E> v = ROHelpers.buildROListOrSet( 597 primitiveArray, 598 (int arrayLen) -> new Vector<E>(arrayLen), 599 filter 600 ); 601 602 // Empty Optimization (throw away, completely, the reference, use static-constant) 603 this.vector = (v.size() == 0) ? ((Vector<E>) EMPTY_VECTOR) : v; 604 } 605 606 607 // ******************************************************************************************** 608 // ******************************************************************************************** 609 // java.util.stream.Stream HELPER 610 // ******************************************************************************************** 611 // ******************************************************************************************** 612 613 614 /** 615 * For use with a the Java Stream method {@code 'collect(Collector c)'}. 616 * 617 * <EMBED CLASS='external-html' DATA-ABBREV=v DATA-FILE-ID=STREAM_COLLECTOR> 618 * 619 * @param <T> This is the Generic-Type of the Input-Stream. It will also be the Generic-Type 620 * of the {@code ReadOnlyVector} that's returned from the stream's {@code collect} method. 621 * 622 * @param characteristics Optional Characteristics List. See Java Stream-API Documentation on 623 * {@code Collector.Characteristics} inner-class for more details. 624 * 625 * @return This returns a collector that may be piped into a stream's {@code 'collect'} method, 626 * as in the example, above. 627 */ 628 public static <T> java.util.stream.Collector 629 <T, ROVectorBuilder<T>, ReadOnlyVector<T>> 630 streamCollector(Collector.Characteristics... characteristics) 631 { 632 return Collector.of( 633 ROVectorBuilder<T>::new, // The "Supplier" (builds a new ROVectorBuilder) 634 ROVectorBuilder<T>::add, // The "Accumulator" (adds elements to the builder) 635 636 // Oracle Making Life Difficult - It should be the line below, but, alas, it is not! 637 // ROVectorBuilder<T>::addAll, // The "Combiner" (combines multiple ROVectorBuilders) 638 // 639 // In Stream.collect(), the 3rd parameter - the "combiner" - is a "BiConsumer<R, R>" 640 // NOTE: A "BiConsumer" is a FunctionalInterface that does not return anything - it is 641 // (obviously) a "void" return method! 642 // 643 // **BUT** 644 // 645 // In Collector.of, the 3rd parameter - the "combiner" - is a "BinaryOperation<R>" 646 647 (ROVectorBuilder<T> rovb1, ROVectorBuilder<T> rovb2) -> 648 { 649 rovb1.addAll(rovb2); 650 return rovb1; 651 }, 652 653 ROVectorBuilder<T>::build, // The "Finisher" (Converts Builder to ReadOnlyVector) 654 characteristics 655 ); 656 } 657 658 659 // ******************************************************************************************** 660 // ******************************************************************************************** 661 // Convert to java.util Types 662 // ******************************************************************************************** 663 // ******************************************************************************************** 664 665 666 /** 667 * Clone's {@code 'this'} instance internal {@code Vector<E>} field, and returns it. 668 * <EMBED CLASS='external-html' DATA-TYPE=Vector DATA-FILE-ID=CLONE_TO> 669 * 670 * @return An independent, mutable copy of {@code 'this'} instance' internal {@code Vector<E>} 671 * data-structure. 672 */ 673 public Vector<E> cloneToVector() 674 { 675 return fromBuilderOrVector 676 ? new Vector<E>(this.vector) 677 : (Vector<E>) this.vector.clone(); 678 } 679 680 /** 681 * Invokes {@code java.util.Collections.unmodifiableList} on the internal {@code Vector}. 682 * <EMBED CLASS='external-html' DATA-RET_TYPE=List DATA-FILE-ID=WRAP_TO_IMMUTABLE> 683 * 684 * @return A {@code List} which adheres to the JDK interface {@code java.util.List}, but throws 685 * an {@code UnsupportedOperationException} if a user attempts to invoke a Mutator-Method on 686 * the returned instance. 687 */ 688 public List<E> wrapToImmutableList() 689 { return Collections.unmodifiableList(this.vector); } 690 691 692 // ******************************************************************************************** 693 // ******************************************************************************************** 694 // Original JDK Methods, java.util.Vectpr 695 // ******************************************************************************************** 696 // ******************************************************************************************** 697 698 699 /** 700 * Copies the components of this {@code Vector} into the specified array. The item at 701 * index{@code k} in this {@code Vector} is copied into component {@code k} of {@code anArray}. 702 * 703 * @param anArray the array into which the components get copied 704 * 705 * @throws NullPointerException if the given array is null 706 * 707 * @throws IndexOutOfBoundsException if the specified array is not large enough to hold all the 708 * components of this {@code Vector} 709 * 710 * @throws ArrayStoreException if a component of this {@code Vector} is not of a runtime type 711 * that can be stored in the specified array 712 * 713 * @see #toArray(Object[]) 714 */ 715 public void copyInto(Object[] anArray) 716 { this.vector.copyInto(anArray); } 717 718 /** 719 * Returns the current capacity of this {@code Vector}. 720 * 721 * @return the current capacity (the length of its internal data array, kept in the field 722 * {@code elementData} of this {@code Vector}) 723 */ 724 public int capacity() 725 { return this.vector.capacity(); } 726 727 /** 728 * Returns the number of components in this {@code Vector}. 729 * 730 * @return the number of components in this {@code Vector} 731 */ 732 public int size() 733 { return this.vector.size(); } 734 735 /** 736 * Tests if this {@code Vector} has no components. 737 * 738 * @return {@code TRUE} if and only if this {@code Vector} has no components, that is, its 739 * size is zero; {@code FALSE} otherwise. 740 */ 741 public boolean isEmpty() 742 { return this.vector.isEmpty(); } 743 744 /** 745 * Returns an enumeration of the components of this {@code Vector}. The returned 746 * {@code Enumeration} object will generate all items in this {@code Vector}. The first item 747 * generated is the item at index {@code 0}, then the item at index {@code 1}, and so on. If 748 * the {@code Vector} is structurally modified while enumerating over the elements then the 749 * results of enumerating are undefined. 750 * 751 * @return an enumeration of the components of this {@code Vector} 752 */ 753 public Enumeration<E> elements() 754 { return this.vector.elements(); } 755 756 /** 757 * Returns {@code TRUE} if this {@code Vector} contains the specified element. More formally, 758 * returns {@code TRUE} if and only if this {@code Vector} contains at least one element 759 * {@code e} such that {@code Objects.equals(o, e)}. 760 * 761 * @param o element whose presence in this {@code Vector} is to be tested 762 * 763 * @return {@code TRUE} if this {@code Vector} contains the specified element 764 */ 765 public boolean contains(Object o) 766 { return this.vector.contains(o); } 767 768 /** 769 * Returns the index of the first occurrence of the specified element in this {@code Vector}, 770 * or {@code -1} if this {@code Vector} does not contain the element. More formally, returns 771 * the lowest index {@code i} such that {@code Objects.equals(o, get(i))}, or {@code -1} if 772 * there is no such index. 773 * 774 * @param o element to search for 775 * 776 * @return the index of the first occurrence of the specified element in this {@code Vector}, 777 * or {@code -1} if this {@code Vector} does not contain the element 778 */ 779 public int indexOf(Object o) 780 { return this.vector.indexOf(o); } 781 782 /** 783 * Returns the index of the first occurrence of the specified element in this {@code Vector}, 784 * searching forwards from {@code index}, or returns {@code -1} if the element is not found. 785 * More formally, returns the lowest index {@code i} such that 786 * {@code (i >= index && Objects.equals(o, get(i)))}, or {@code -1} if there is no such index. 787 * 788 * @param o element to search for 789 * 790 * @param index index to start searching from 791 * 792 * @return the index of the first occurrence of the element in this {@code Vector} at position 793 * {@code index} or later in the {@code Vector}; {@code -1} if the element is not found. 794 * 795 * @throws IndexOutOfBoundsException if the specified index is negative 796 */ 797 public int indexOf(Object o, int index) 798 { return this.vector.indexOf(o, index); } 799 800 /** 801 * Returns the index of the last occurrence of the specified element in this {@code Vector}, or 802 * {@code -1} if this {@code Vector} does not contain the element. More formally, returns the 803 * highest index {@code i} such that {@code Objects.equals(o, get(i))}, or {@code -1} if there 804 * is no such index. 805 * 806 * @param o element to search for 807 * 808 * @return the index of the last occurrence of the specified element in this {@code Vector}, or 809 * {@code -1} if this {@code Vector} does not contain the element 810 */ 811 public int lastIndexOf(Object o) 812 { return this.vector.lastIndexOf(o); } 813 814 /** 815 * Returns the index of the last occurrence of the specified element in this {@code Vector}, 816 * searching backwards from {@code index}, or returns {@code -1} if the element is not found. 817 * More formally, returns the highest index {@code i} such that 818 * {@code (i <= index && Objects.equals(o, get(i)))}, or {@code -1} if there is no such index. 819 * 820 * @param o element to search for 821 * 822 * @param index index to start searching backwards from 823 * 824 * @return the index of the last occurrence of the element at position less than or equal to 825 * {@code index} in this {@code Vector}; {@code -1} if the element is not found. 826 * 827 * @throws IndexOutOfBoundsException if the specified index is greater than or equal to the 828 * current size of this {@code Vector} 829 */ 830 public int lastIndexOf(Object o, int index) 831 { return this.vector.lastIndexOf(index); } 832 833 /** 834 * Returns the component at the specified index. 835 * 836 * <BR /><BR />This method is identical in functionality to the {@link #get(int)} 837 * method (which is part of the {@link ReadOnlyList} interface). 838 * 839 * @param index an index into this {@code Vector} 840 * 841 * @return the component at the specified index 842 * 843 * @throws ArrayIndexOutOfBoundsException if the index is out of range 844 * ({@code index < 0 || index >= size()}) 845 */ 846 public E elementAt(int index) 847 { return this.vector.elementAt(index); } 848 849 /** 850 * Returns the first component (the item at index {@code 0}) of this {@code Vector}. 851 * 852 * @return the first component of this {@code Vector} 853 * 854 * @throws NoSuchElementException if this {@code Vector} has no components 855 */ 856 public E firstElement() 857 { return this.vector.firstElement(); } 858 859 /** 860 * Returns the last component of the {@code Vector}. 861 * 862 * @return the last component of the {@code Vector}, i.e., the component at index 863 * {@code size() - 1} 864 * 865 * @throws NoSuchElementException if this {@code Vector} is empty 866 */ 867 public E lastElement() 868 { return this.vector.lastElement(); } 869 870 /** Returns an array containing all of the elements in this {@code Vector} in the correct order. */ 871 public Object[] toArray() 872 { return this.vector.toArray(); } 873 874 /** 875 * Returns an array containing all of the elements in this {@code Vector} in the correct order; 876 * the runtime type of the returned array is that of the specified array. If the 877 * {@code Vector} fits in the specified array, it is returned therein. Otherwise, a new array 878 * is allocated with the runtime type of the specified array and the size of this 879 * {@code Vector}. 880 * 881 * <BR /><BR />If the {@code Vector} fits in the specified array with room to spare (i.e., the 882 * array has more elements than the {@code Vector}), the element in the array immediately 883 * following the end of the {@code Vector} is set to null. (This is useful in determining the 884 * length of the {@code Vector} <em>only</em> if the caller knows that the {@code Vector} does 885 * not contain any null elements.) 886 * 887 * @param <T> type of array elements. The same type as {@code <E>} or a supertype of 888 * {@code <E>}. 889 * 890 * @param a the array into which the elements of the {@code Vector} are to be stored, if it is 891 * big enough; otherwise, a new array of the same runtime type is allocated for this purpose. 892 * 893 * @return an array containing the elements of the {@code Vector} 894 * 895 * @throws ArrayStoreException if the runtime type of a, {@code <T>}, is not a supertype of the 896 * runtime type, {@code <E>}, of every element in this {@code Vector} 897 * 898 * @throws NullPointerException if the given array is null 899 */ 900 public <T> T[] toArray(T[] a) 901 { return this.vector.toArray(a); } 902 903 /** 904 * Returns the element at the specified position in this {@code Vector}. 905 * 906 * @param index index of the element to return 907 * 908 * @return object at the specified index 909 * 910 * @throws ArrayIndexOutOfBoundsException if the index is out of range 911 * ({@code index < 0 || index >= size()}) 912 */ 913 public E get(int index) 914 { return this.vector.get(index); } 915 916 /** 917 * Returns {@code TRUE} if this {@code Vector} contains all of the elements in the specified 918 * Collection 919 * 920 * @param c a collection whose elements will be tested for containment in this {@code Vector} 921 * 922 * @return {@code TRUE} if this {@code Vector} contains all of the elements in the specified 923 * collection 924 * 925 * @throws NullPointerException if the specified collection is null 926 */ 927 public boolean containsAll(Collection<?> c) 928 { return this.vector.containsAll(c); } 929 930 /** 931 * Returns a view of the portion of this List between {@code 'fromIndex'}, inclusive, and 932 * {@code 'toIndex'}, exclusive. (If {@code 'fromIndex'} and {@code 'toIndex'} are equal, the 933 * returned List is empty.) The returned List supports all of the optional 934 * {@code ReadOnlyList} operations supported by this {@code ReadOnlyList}. 935 * 936 * <BR /><BR />This method eliminates the need for explicit range operations (of the sort that 937 * commonly exist for arrays). Any operation that expects a List can be used as a range 938 * operation by operating on a subList view instead of a whole List. Idioms may be constructed 939 * for indexOf and lastIndexOf, and all of the algorithms in the Collections class can be 940 * applied to a subList. 941 * 942 * @param fromIndex low endpoint (inclusive) of the subList 943 * @param toIndex high endpoint (exclusive) of the subList 944 * @return a view of the specified range within this List 945 * 946 * @throws IndexOutOfBoundsException if an endpoint index value is out of range 947 * {@code (fromIndex < 0 || toIndex > size)} 948 * 949 * @throws IllegalArgumentException if the endpoint indices are out of order 950 * {@code (fromIndex > toIndex)} 951 */ 952 public ReadOnlyList<E> subList(int fromIndex, int toIndex) 953 { 954 return InterfaceBuilder.toReadOnlyList( 955 fromBuilderOrVector 956 ? ((ROVectorBuilder<E>) this.vector)._subList(fromIndex, toIndex, friendClassBadge) 957 : this.vector.subList(fromIndex, toIndex) 958 ); 959 } 960 961 /** 962 * Returns a list iterator over the elements in this list (in proper sequence), starting at the 963 * specified position in the list. The specified index indicates the first element that would 964 * be returned by an initial call to {@link ReadOnlyListIterator#next next}. An initial call 965 * to {@link ReadOnlyListIterator#previous previous} would return the element with the 966 * specified index minus one. 967 * 968 * @throws IndexOutOfBoundsException if the index is out of range 969 * {@code (index < 0 || index > size())} 970 */ 971 public ReadOnlyListIterator<E> listIterator(int index) 972 { 973 return InterfaceBuilder.toReadOnlyListIterator( 974 fromBuilderOrVector 975 ? ((ROVectorBuilder<E>) this.vector)._listIterator(index, friendClassBadge) 976 : this.vector.listIterator(index) 977 ); 978 } 979 980 /** 981 * Returns a list iterator over the elements in this list (in proper sequence). 982 * @see #listIterator(int) 983 */ 984 public ReadOnlyListIterator<E> listIterator() 985 { 986 return InterfaceBuilder.toReadOnlyListIterator( 987 fromBuilderOrVector 988 ? ((ROVectorBuilder<E>) this.vector)._listIterator(friendClassBadge) 989 : this.vector.listIterator() 990 ); 991 } 992 993 /** 994 * Returns an iterator over the elements in this list in proper sequence. 995 * 996 * @return an iterator over the elements in this list in proper sequence 997 */ 998 public RemoveUnsupportedIterator<E> iterator() 999 { return new RemoveUnsupportedIterator<>(this.vector.iterator()); } 1000 1001 /** @throws NullPointerException {@inheritDoc} */ 1002 @Override 1003 public void forEach(Consumer<? super E> action) 1004 { this.vector.forEach(action); } 1005 1006 /** 1007 * Uses the private and internal {@code 'vector'} field to build a {@code 'Spliterator'} 1008 * @return a {@code Spliterator} over the elements in this list 1009 */ 1010 @Override 1011 public Spliterator<E> spliterator() 1012 { return this.vector.spliterator(); } 1013 1014 1015 // ******************************************************************************************** 1016 // ******************************************************************************************** 1017 // java.lang.Object 1018 // ******************************************************************************************** 1019 // ******************************************************************************************** 1020 1021 1022 /** 1023 * Returns a {@code String} representation of this {@code Vector}. The {@code String} 1024 * representation consists of a list of the collection's elements in the order they are 1025 * returned by its iterator, enclosed in square brackets ({@code "[]"}). Adjacent elements are 1026 * separated by the characters {@code ", "} (comma and space). Elements are converted to 1027 * {@code String's} as by {@code String.valueOf(Object)}. 1028 * 1029 * @return a {@code String} representation of this {@code Vector} 1030 */ 1031 public String toString() 1032 { return this.vector.toString(); } 1033 1034 /** 1035 * Compares the specified Object with this List for equality, as per the definition in the 1036 * class {@code java.util.Vector}. 1037 * 1038 * @param o object to be compared for equality with this {@code ReadOnlyVector}. 1039 * @return {@code TRUE} if the specified Object is equal to this list 1040 */ 1041 public boolean equals(Object o) 1042 { return ROHelpers.roListEq(this, o); } 1043 1044 /** 1045 * Returns the hash code value for this List as per the definition in the class 1046 * {@code java.util.Vector}. 1047 */ 1048 public int hashCode() 1049 { return this.vector.hashCode(); } 1050} 1051