1 /*
   2  * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have
  23  * questions.
  24  */
  25 package jdk.incubator.vector;
  26 
  27 import jdk.internal.misc.Unsafe;
  28 import jdk.internal.vm.annotation.ForceInline;
  29 
  30 import java.nio.BufferUnderflowException;
  31 import java.nio.ByteBuffer;
  32 
  33 /**
  34  * A {@code Vector} is designed for use in computations that can be transformed
  35  * by a runtime compiler, on supported hardware, to Single Instruction Multiple
  36  * Data (SIMD) computations leveraging vector hardware registers and vector
  37  * hardware instructions.  Such SIMD computations exploit data parallelism to
  38  * perform the same operation on multiple data points simultaneously in a
  39  * faster time it would ordinarily take to perform the same operation
  40  * sequentially on each data point.
  41  * <p>
  42  * A Vector represents an ordered immutable sequence of values of the same
  43  * element type {@code e} that is one of the following primitive types
  44  * {@code byte}, {@code short}, {@code int}, {@code long}, {@code float}, or
  45  * {@code double}).  The type variable {@code E} corresponds to the boxed
  46  * element type, specifically the class that wraps a value of {@code e} in an
  47  * object (such the {@code Integer} class that wraps a value of {@code int}}.
  48  * A Vector has a {@link #shape() shape} {@code S}, extending type
  49  * {@link Shape}, that governs the total {@link #bitSize() size} in bits
  50  * of the sequence of values.
  51  * <p>
  52  * The number of values in the sequence is referred to as the Vector
  53  * {@link #length() length}.  The length also corresponds to the number of
  54  * Vector lanes.  The lane element at lane index {@code N} (from {@code 0},
  55  * inclusive, to length, exclusive) corresponds to the {@code N + 1}'th value in
  56  * the sequence.
  57  * Note: this arrangement
  58  * of Vector bit size, Vector length, element bit size, and lane element index
  59  * has no bearing on how a Vector instance and its sequence of elements may be
  60  * arranged in memory or represented as a value in a vector hardware register.
  61  * <p>
  62  * Vector declares a set of vector operations (methods) that are common to all
  63  * element types (such as addition).  Sub-classes of Vector with a concrete
  64  * boxed element type declare further operations that are specific to that
  65  * element type (such as access to element values in lanes, logical operations
  66  * on values of integral elements types, or transcendental operations on values
  67  * of floating point element types).
  68  * There are six sub-classes of Vector corresponding to the supported set
  69  * of element types, {@link ByteVector<S>}, {@link ShortVector<S>},
  70  * {@link IntVector<S>} {@link LongVector<S>}, {@link FloatVector<S>}, and
  71  * {@link DoubleVector<S>}.
  72  * <p>
  73  * Vector values, instances of Vector, are created from a special kind of
  74  * factory called a {@link Species}.  A Species has an
  75  * element type and shape and creates Vector values of the same element type
  76  * and shape.
  77  * A species can be {@link #speciesInstance obtained} given an element type and
  78  * shape, or a preferred species can be {@link #speciesInstance obtained} given
  79  * just an element type where the most optimal shape is selected for the current
  80  * platform.  It is recommended that Species instances be held in
  81  * {@code static final} fields for optimal creation and usage of Vector values
  82  * by the runtime compiler.
  83  * <p>
  84  * Vector operations can be grouped into various categories and their behaviour
  85  * generally specified as follows:
  86  * <ul>
  87  * <li>
  88  * A vector unary operation (1-ary) operates on one input vector to produce a
  89  * result vector.
  90  * For each lane of the input vector the
  91  * lane element is operated on using the specified scalar unary operation and
  92  * the element result is placed into the vector result at the same lane.
  93  * The following pseudocode expresses the behaviour of this operation category,
  94  * where {@code e} is the element type and {@code EVector} corresponds to the
  95  * primitive Vector type:
  96  *
  97  * <pre>{@code
  98  * EVector<S> a = ...;
  99  * e[] ar = new e[a.length()];
 100  * for (int i = 0; i < a.length(); i++) {
 101  *     ar[i] = scalar_unary_op(a.get(i));
 102  * }
 103  * EVector<S> r = a.species().fromArray(ar, 0);
 104  * }</pre>
 105  *
 106  * Unless otherwise specified the input and result vectors will have the same
 107  * element type and shape.
 108  *
 109  * <li>
 110  * A vector binary operation (2-ary) operates on two input
 111  * vectors to produce a result vector.
 112  * For each lane of the two input vectors,
 113  * a and b say, the corresponding lane elements from a and b are operated on
 114  * using the specified scalar binary operation and the element result is placed
 115  * into the vector result at the same lane.
 116  * The following pseudocode expresses the behaviour of this operation category:
 117  *
 118  * <pre>{@code
 119  * EVector<S> a = ...;
 120  * EVector<S> b = ...;
 121  * e[] ar = new e[a.length()];
 122  * for (int i = 0; i < a.length(); i++) {
 123  *     ar[i] = scalar_binary_op(a.get(i), b.get(i));
 124  * }
 125  * EVector<S> r = a.species().fromArray(ar, 0);
 126  * }</pre>
 127  *
 128  * Unless otherwise specified the two input and result vectors will have the
 129  * same element type and shape.
 130  *
 131  * <li>
 132  * Generalizing from unary (1-ary) and binary (2-ary) operations, a vector n-ary
 133  * operation operates in n input vectors to produce a
 134  * result vector.
 135  * N lane elements from each input vector are operated on
 136  * using the specified n-ary scalar operation and the element result is placed
 137  * into the vector result at the same lane.
 138  * Unless otherwise specified the n input and result vectors will have the same
 139  * element type and shape.
 140  *
 141  * <li>
 142  * A vector reduction operation operates on all the lane
 143  * elements of an input vector.
 144  * An accumulation function is applied to all the
 145  * lane elements to produce a scalar result.
 146  * If the reduction operation is associative then the result may be accumulated
 147  * by operating on the lane elements in any order using a specified associative
 148  * scalar binary operation and identity value.  Otherwise, the reduction
 149  * operation specifies the behaviour of the accumulation function.
 150  * The following pseudocode expresses the behaviour of this operation category
 151  * if it is associative:
 152  * <pre>{@code
 153  * EVector<S> a = ...;
 154  * e r = <identity value>;
 155  * for (int i = 0; i < a.length(); i++) {
 156  *     r = assoc_scalar_binary_op(r, a.get(i));
 157  * }
 158  * }</pre>
 159  *
 160  * Unless otherwise specified the scalar result type and element type will be
 161  * the same.
 162  *
 163  * <li>
 164  * A vector binary test operation operates on two input vectors to produce a
 165  * result mask.  For each lane of the two input vectors, a and b say, the
 166  * the corresponding lane elements from a and b are operated on using the
 167  * specified scalar binary test operation and the boolean result is placed
 168  * into the mask at the same lane.
 169  * The following pseudocode expresses the behaviour of this operation category:
 170  * <pre>{@code
 171  * EVector<S> a = ...;
 172  * EVector<S> b = ...;
 173  * boolean[] ar = new boolean[a.length()];
 174  * for (int i = 0; i < a.length(); i++) {
 175  *     ar[i] = scalar_binary_test_op(a.get(i), b.get(i));
 176  * }
 177  * Mask<E, S> r = a.species().maskFromArray(ar, 0);
 178  * }</pre>
 179  *
 180  * Unless otherwise specified the two input vectors and result mask will have
 181  * the same element type and shape.
 182  *
 183  * <li>
 184  * The prior categories of operation can be said to operate within the vector
 185  * lanes, where lane access is uniformly applied to all vectors, specifically
 186  * the scalar operation is applied to elements taken from input vectors at the
 187  * same lane, and if appropriate applied to the result vector at the same lane.
 188  * A further category of operation is a cross-lane vector operation where lane
 189  * access is defined by the arguments to the operation.  Cross-lane operations
 190  * generally rearrange lane elements, by permutation (commonly controlled by a
 191  * {@link Shuffle}) or by blending (commonly controlled by a {@link Mask}).
 192  * Such an operation explicitly specifies how it rearranges lane elements.
 193  * </ul>
 194  *
 195  * If a vector operation is represented as an instance method then first input
 196  * vector corresponds to {@code this} vector and subsequent input vectors are
 197  * arguments of the method.  Otherwise, if the an operation is represented as a
 198  * static method then all input vectors are arguments of the method.
 199  * <p>
 200  * If a vector operation does not belong to one of the above categories then
 201  * the operation explicitly specifies how it processes the lane elements of
 202  * input vectors, and where appropriate expresses the behaviour using
 203  * pseudocode.
 204  *
 205  * <p>
 206  * Many vector operations provide an additional {@link Mask mask} accepting
 207  * variant.
 208  * The mask controls which lanes are selected for application of the scalar
 209  * operation.  Masks are a key component for the support of control flow in
 210  * vector computations.
 211  * <p>
 212  * For certain operation categories the mask accepting variants can be specified
 213  * in generic terms.  If a lane of the mask is set then the scalar operation is
 214  * applied to corresponding lane elements, otherwise if a lane of a mask is not
 215  * set then a default scalar operation is applied and its result is placed into
 216  * the vector result at the same lane. The default operation is specified for
 217  * the following operation categories:
 218  * <ul>
 219  * <li>
 220  * For a vector n-ary operation the default operation is a function that returns
 221  * it's first argument, specifically a lane element of the first input vector.
 222  * <li>
 223  * For an associative vector reduction operation the default operation is a
 224  * function that returns the identity value.
 225  * <li>
 226  * For vector binary test operation the default operation is a function that
 227  * returns false.
 228  *</ul>
 229  * Otherwise, the mask accepting variant of the operation explicitly specifies
 230  * how it processes the lane elements of input vectors, and where appropriate
 231  * expresses the behaviour using pseudocode.
 232  *
 233  * <p>
 234  * For convenience many vector operations, of arity greater than one, provide
 235  * an additional scalar accepting variant.  This variant accepts compatible
 236  * scalar values instead of vectors for the second and subsequent input vectors,
 237  * if any.
 238  * Unless otherwise specified the scalar variant behaves as if each scalar value
 239  * is transformed to a vector using the vector Species
 240  * {@code broadcast} operation, and
 241  * then the vector accepting vector operation is applied using the transformed
 242  * values.
 243  *
 244  * <p>
 245  * This is a value-based
 246  * class; use of identity-sensitive operations (including reference equality
 247  * ({@code ==}), identity hash code, or synchronization) on instances of
 248  * {@code Vector} may have unpredictable results and should be avoided.
 249  *
 250  * @param <E> the boxed element type of elements in this vector
 251  * @param <S> the type of shape of this vector
 252  */
 253 public abstract class Vector<E, S extends Vector.Shape> {
 254 
 255     Vector() {}
 256 
 257     /**
 258      * Returns the species of this vector.
 259      *
 260      * @return the species of this vector
 261      */
 262     public abstract Species<E, S> species();
 263 
 264     // @@@
 265 
 266     /**
 267      * Returns the primitive element type of this vector.
 268      *
 269      * @return the primitive element type of this vector
 270      */
 271     public Class<E> elementType() { return species().elementType(); }
 272 
 273     /**
 274      * Returns the element size, in bits, of this vector.
 275      *
 276      * @return the element size, in bits
 277      */
 278     public int elementSize() { return species().elementSize(); }
 279 
 280     /**
 281      * Returns the shape of this vector.
 282      *
 283      * @return the shape of this vector
 284      */
 285     public S shape() { return species().shape(); }
 286 
 287     /**
 288      * Returns the number of vector lanes (the length).
 289      *
 290      * @return the number of vector lanes
 291      */
 292     public int length() { return species().length(); }
 293 
 294     /**
 295      * Returns the total vector size, in bits.
 296      *
 297      * @return the total vector size, in bits
 298      */
 299     public int bitSize() { return species().bitSize(); }
 300 
 301     //Arithmetic
 302 
 303     /**
 304      * Adds this vector to an input vector.
 305      * <p>
 306      * This is a vector binary operation where the primitive addition operation
 307      * ({@code +}) is applied to lane elements.
 308      *
 309      * @param b the input vector
 310      * @return the result of adding this vector to the input vector
 311      */
 312     public abstract Vector<E, S> add(Vector<E, S> b);
 313 
 314     /**
 315      * Adds this vector to an input vector, selecting lane elements
 316      * controlled by a mask.
 317      * <p>
 318      * This is a vector binary operation where the primitive addition operation
 319      * ({@code +}) is applied to lane elements.
 320      *
 321      * @param b the input vector
 322      * @param m the mask controlling lane selection
 323      * @return the result of adding this vector to the given vector
 324      */
 325     public abstract Vector<E, S> add(Vector<E, S> b, Mask<E, S> m);
 326 
 327     public abstract Vector<E, S> addSaturate(Vector<E, S> o);
 328 
 329     public abstract Vector<E, S> addSaturate(Vector<E, S> o, Mask<E, S> m);
 330 
 331     public abstract Vector<E, S> sub(Vector<E, S> o);
 332 
 333     public abstract Vector<E, S> sub(Vector<E, S> o, Mask<E, S> m);
 334 
 335     public abstract Vector<E, S> subSaturate(Vector<E, S> o);
 336 
 337     public abstract Vector<E, S> subSaturate(Vector<E, S> o, Mask<E, S> m);
 338 
 339     public abstract Vector<E, S> mul(Vector<E, S> o);
 340 
 341     public abstract Vector<E, S> mul(Vector<E, S> o, Mask<E, S> m);
 342 
 343     /**
 344      * Negates this vector.
 345      * <p>
 346      * This is a vector unary operation where the primitive negation operation
 347      * ({@code -})is applied to lane elements.
 348      *
 349      * @return the result of negating this vector
 350      */
 351     public abstract Vector<E, S> neg();
 352 
 353     public abstract Vector<E, S> neg(Mask<E, S> m);
 354 
 355     //Maths from java.math
 356     public abstract Vector<E, S> abs();
 357 
 358     public abstract Vector<E, S> abs(Mask<E, S> m);
 359 
 360     public abstract Vector<E, S> min(Vector<E, S> o);
 361 
 362     public abstract Vector<E, S> max(Vector<E, S> o);
 363 
 364     //TODO: Parity
 365 
 366     //Comparisons
 367 
 368     //TODO: N.B. Floating point NaN behaviors?
 369     //TODO: Check the JLS
 370 
 371     /**
 372      * Tests if this vector is equal to the given vector.
 373      * <p>
 374      * This is a vector binary test operation where the primitive equals
 375      * operation ({@code ==}) is applied to lane elements.
 376      *
 377      * @param b the given vector
 378      * @return the result mask of testing if this vector is equal to the given
 379      * vector
 380      */
 381     public abstract Mask<E, S> equal(Vector<E, S> b);
 382 
 383     public abstract Mask<E, S> notEqual(Vector<E, S> o);
 384 
 385     /**
 386      * Tests if this vector is less than the given vector.
 387      * <p>
 388      * This is a vector binary test operation where the primitive less than
 389      * operation ({@code <}) is applied to lane elements.
 390      *
 391      * @param b the given vector
 392      * @return the mask result of testing if this vector is less than the given
 393      * vector
 394      */
 395     public abstract Mask<E, S> lessThan(Vector<E, S> b);
 396 
 397     public abstract Mask<E, S> lessThanEq(Vector<E, S> o);
 398 
 399     public abstract Mask<E, S> greaterThan(Vector<E, S> o);
 400 
 401     public abstract Mask<E, S> greaterThanEq(Vector<E, S> o);
 402 
 403     //Elemental shifting
 404 
 405     /**
 406      * Rotates left the lane elements of this vector by the given number of
 407      * lanes, {@code i}, modulus the vector length.
 408      * <p>
 409      * This is a cross-lane operation that permutes the lane elements of this
 410      * vector.
 411      * For each lane of the input vector, at lane index {@code N}, the lane
 412      * element is assigned to the result vector at lane index
 413      * {@code (i + N) % this.length()}.
 414      *
 415      * @param i the number of lanes to rotate left
 416      * @return the result of rotating left lane elements of this vector by the
 417      * given number of lanes
 418      */
 419     public abstract Vector<E, S> rotateEL(int i); //Rotate elements left
 420 
 421     /**
 422      * Rotates right the lane elements of this vector by the given number of
 423      * lanes, {@code i}, modulus the vector length.
 424      * <p>
 425      * This is a cross-lane operation that permutes the lane elements of this
 426      * vector and behaves as if rotating left the lane elements by
 427      * {@code this.length() - (i % this.length())} lanes.
 428      *
 429      * @param i the number of lanes to rotate left
 430      * @return the result of rotating right lane elements of this vector by the
 431      * given number of lanes
 432      */
 433     public abstract Vector<E, S> rotateER(int i); //Rotate elements right
 434 
 435     public abstract Vector<E, S> shiftEL(int i); //shift elements left
 436 
 437     public abstract Vector<E, S> shiftER(int i); //shift elements right
 438 
 439     /**
 440      * Blends the lane elements of this vector with those of an input vector,
 441      * selecting lanes controlled by a mask.
 442      * <p>
 443      * For each lane of the mask, at lane index {@code N}, if the mask lane
 444      * is set then the lane element at {@code N} from the input vector is
 445      * selected and placed into the resulting vector at {@code N},
 446      * otherwise the the lane element at {@code N} from this input vector is
 447      * selected and placed into the resulting vector at {@code N}.
 448      *
 449      * @param b the input vector
 450      * @param m the mask controlling lane selection
 451      * @return the result of blending the lane elements of this vector with
 452      * those of an input vector
 453      */
 454     public abstract Vector<E, S> blend(Vector<E, S> b, Mask<E, S> m);
 455 
 456     /**
 457      * Shuffles the lane elements of this vector and those of an input vector,
 458      * selecting lane indexes controlled by a shuffle.
 459      * <p>
 460      * This is a cross-lane operation that permutes the lane elements of this
 461      * vector and tine input vector.
 462      * For each lane of the shuffle, at lane index {@code N}, if the shuffle
 463      * lane element, {@code I}, is less than the length of this vector then the
 464      * lane element at {@code I} from this vector is selected and placed into
 465      * the resulting vector at {@code N}, otherwise the lane element at
 466      * {@code I - this.length()} from the input vector is selected and placed
 467      * into the resulting vector at {@code N}.
 468      *
 469      * @param b the input vector
 470      * @param s the shuffle controlling lane index selection
 471      * @return the result of shuffling the lane elements of this vector and
 472      * those of an input vector
 473      * @throws IndexOutOfBoundsException if any lane element is {@code < 0} or
 474      * {@code >= 2 * this.length())
 475      */
 476     public abstract Vector<E, S> shuffle(Vector<E, S> b, Shuffle<E, S> s);
 477 
 478     /**
 479      * Shuffles the lane elements of this vector selecting lane indexes
 480      * controlled by a shuffle.
 481      * <p>
 482      * This is a cross-lane operation that permutes the lane elements of this
 483      * vector.
 484      * For each lane of the shuffle, at lane index {@code N} with lane
 485      * element {@code I}, the lane element at {@code I} from this vector is
 486      * selected and placed into the resulting vector at {@code N}.
 487      *
 488      * @param s the shuffle controlling lane index selection
 489      * @return the result of shuffling the lane elements of this vector
 490      * @throws IndexOutOfBoundsException if any lane element is {@code < 0} or
 491      * {@code >= this.length())
 492      */
 493     public abstract Vector<E, S> swizzle(Shuffle<E, S> s);
 494 
 495 
 496     // Conversions
 497 
 498     // Bitwise preserving
 499 
 500     /**
 501      * Transforms this vector to a vector of the given species shape {@code T}
 502      * and element type {@code F}.
 503      * <p>
 504      * This method behaves as if it returns the result of calling
 505      * {@link Species#reshape(Vector) reshape} on the given species with this
 506      * vector:
 507      * <pre>{@code
 508      * return species.reshape(this);
 509      * }</pre>
 510      *
 511      * @param species the species
 512      * @param <F> the boxed element type of the species
 513      * @param <T> the type of shape of the species
 514      * @return a vector transformed by shape and element type
 515      * @see Species#reshape(Vector)
 516      */
 517     @ForceInline
 518     public <F, T extends Shape> Vector<F, T> reshape(Species<F, T> species) {
 519         return species.reshape(this);
 520     }
 521 
 522     /**
 523      * Transforms this vector to a vector of the given species element type
 524      * {@code F}, where this vector's shape {@code S} is preserved.
 525      * <p>
 526      * This method behaves as if it returns the result of calling
 527      * {@link Species#rebracket(Vector) rebracket} on the given species with this
 528      * vector:
 529      * <pre>{@code
 530      * return species.rebracket(this);
 531      * }</pre>
 532      *
 533      * @param species the species
 534      * @param <F> the boxed element type of the species
 535      * @return a vector transformed element type
 536      * @see Species#rebracket(Vector)
 537      */
 538     @ForceInline
 539     public <F> Vector<F, S> rebracket(Species<F, S> species) {
 540         return species.reshape(this);
 541     }
 542 
 543     /**
 544      * Transforms this vector to a vector of the given species shape {@code T},
 545      * where this vector's element type {@code E} is preserved.
 546      * <p>
 547      * This method behaves as if it returns the result of calling
 548      * {@link Species#resize(Vector) resize} on the given species with this vector:
 549      * <pre>{@code
 550      * return species.resize(this);
 551      * }</pre>
 552      *
 553      * @param species the species
 554      * @param <T> the type of shape of the species
 555      * @return a vector transformed by shape
 556      * @see Species#resize(Vector)
 557      */
 558     public abstract <T extends Shape> Vector<E, T> resize(Species<E, T> species);
 559 
 560     // Cast
 561 
 562     /**
 563      * Converts this vector to a vector of the given species shape {@code T} and
 564      * element type {@code F}.
 565      * <p>
 566      * This method behaves as if it returns the result of calling
 567      * {@link Species#cast(Vector) cast} on the given species with this vector:
 568      * <pre>{@code
 569      * return species.cast(this);
 570      * }</pre>
 571      *
 572      * @param species the species
 573      * @param <F> the boxed element type of the species
 574      * @param <T> the type of shape of the species
 575      * @return a vector converted by shape and element type
 576      * @see Species#cast(Vector)
 577      */
 578     @ForceInline
 579     public <F, T extends Shape> Vector<F, T> cast(Species<F, T> species) {
 580         return species.cast(this);
 581     }
 582 
 583     //Array stores
 584 
 585     /**
 586      * Stores this vector into a byte array starting at an offset.
 587      * <p>
 588      * Bytes are extracted from primitive lane elements according to the
 589      * native byte order of the underlying platform.
 590      * <p>
 591      * This method behaves as it calls the
 592      * byte buffer, offset, and mask accepting
 593      * {@link #intoByteBuffer(ByteBuffer, int, Mask) method} as follows:
 594      * <pre>{@code
 595      * return this.intoByteBuffer(ByteBuffer.wrap(a), i, this.maskAllTrue());
 596      * }</pre>
 597      *
 598      * @param a the byte array
 599      * @param i the offset into the array
 600      * @return a vector loaded from a byte array
 601      * @throws IndexOutOfBoundsException if {@code i < 0} or
 602      * {@code i > a.length - (this.length() * this.elementSize() / Byte.SIZE)}
 603      */
 604     public abstract void intoByteArray(byte[] a, int i);
 605 
 606     /**
 607      * Stores this vector into a byte array starting at an offset and using a mask.
 608      * <p>
 609      * Bytes are extracted from primitive lane elements according to the
 610      * native byte order of the underlying platform.
 611      * <p>
 612      * This method behaves as it calls the
 613      * byte buffer, offset, and mask accepting
 614      * {@link #intoByteBuffer(ByteBuffer, int, Mask) method} as follows:
 615      * <pre>{@code
 616      * return this.intoByteBuffer(ByteBuffer.wrap(a), i, m);
 617      * }</pre>
 618      *
 619      * @param a the byte array
 620      * @param i the offset into the array
 621      * @throws IndexOutOfBoundsException if the offset is {@code < 0},
 622      * or {@code > a.length},
 623      * for any vector lane index {@code N} where the mask at lane {@code N}
 624      * is set
 625      * {@code i >= a.length - (N * this.elementSize() / Byte.SIZE)}
 626      */
 627     public abstract void intoByteArray(byte[] a, int i, Mask<E, S> m);
 628 
 629     /**
 630      * Stores this vector into a {@link ByteBuffer byte buffer} starting at the
 631      * buffer's position.
 632      * <p>
 633      * Bytes are extracted from primitive lane elements according to the
 634      * native byte order of the underlying platform.
 635      * <p>
 636      * This method behaves as if it calls the byte buffer, offset, and mask
 637      * accepting
 638      * {@link #intoByteBuffer(ByteBuffer, int, Mask)} method} as follows:
 639      * <pre>{@code
 640      *   this.intoByteBuffer(b, b.position(), this.maskAllTrue())
 641      * }</pre>
 642      *
 643      * @param b the byte buffer
 644      * @throws IndexOutOfBoundsException if there are fewer than
 645      * {@code this.length() * this.elementSize() / Byte.SIZE} bytes
 646      * remaining in the byte buffer
 647      */
 648     public abstract void intoByteBuffer(ByteBuffer b);
 649 
 650     /**
 651      * Stores this vector into a {@link ByteBuffer byte buffer} starting at the
 652      * buffer's position and using a mask.
 653      * <p>
 654      * Bytes are extracted from primitive lane elements according to the
 655      * native byte order of the underlying platform.
 656      * <p>
 657      * This method behaves as if it calls the byte buffer, offset, and mask
 658      * accepting
 659      * {@link #intoByteBuffer(ByteBuffer, int, Mask)} method} as follows:
 660      * <pre>{@code
 661      *   this.intoByteBuffer(b, b.position(), m)
 662      * }</pre>
 663      *
 664      * @param b the byte buffer
 665      * @param m the mask
 666      * @throws IndexOutOfBoundsException if for any vector lane index
 667      * {@code N} where the mask at lane {@code N} is set
 668      * {@code b.position() >= b.limit() - (N * this.elementSize() / Byte.SIZE)}
 669      */
 670     public abstract void intoByteBuffer(ByteBuffer b, Mask<E, S> m);
 671 
 672     /**
 673      * Stores this vector into a {@link ByteBuffer byte buffer} starting at an
 674      * offset into the byte buffer.
 675      * <p>
 676      * Bytes are extracted from primitive lane elements according to the
 677      * native byte order of the underlying platform.
 678      * <p>
 679      * This method behaves as if it calls the byte buffer, offset, and mask
 680      * accepting
 681      * {@link #intoByteBuffer(ByteBuffer, int, Mask)} method} as follows:
 682      * <pre>{@code
 683      *   this.intoByteBuffer(b, i, this.maskAllTrue())
 684      * }</pre>
 685      *
 686      * @param b the byte buffer
 687      * @param i the offset into the byte buffer
 688      * @throws IndexOutOfBoundsException if the offset is {@code < 0},
 689      * or {@code > b.limit()},
 690      * or if there are fewer than
 691      * {@code this.length() * this.elementSize() / Byte.SIZE} bytes
 692      * remaining in the byte buffer from the given offset
 693      */
 694     public abstract void intoByteBuffer(ByteBuffer b, int i);
 695 
 696     /**
 697      * Stores this vector into a {@link ByteBuffer byte buffer} starting at an
 698      * offset into the byte buffer and using a mask.
 699      * <p>
 700      * This method behaves as if the byte buffer is viewed as a primitive
 701      * {@link java.nio.Buffer buffer} for the primitive element type,
 702      * according to the native byte order of the underlying platform, and
 703      * the lane elements of this vector are put into the buffer if the
 704      * corresponding mask lane is set.
 705      * The following pseudocode expresses the behaviour, where
 706      * {@coce EBuffer} is the primitive buffer type, {@code e} is the
 707      * primitive element type, and {@code EVector<S>} is the primitive
 708      * vector type for this vector:
 709      * <pre>{@code
 710      * EBuffer eb = b.duplicate().
 711      *     order(ByteOrder.nativeOrder()).position(i).
 712      *     asEBuffer();
 713      * e[] es = ((EVector<S>)this).toArray();
 714      * for (int n = 0; n < t.length && m.isSet(n); n++) {
 715      *     eb.put(n, es[n]);
 716      * }
 717      * }</pre>
 718      *
 719      * @param b the byte buffer
 720      * @param i the offset into the byte buffer
 721      * @param m the mask
 722      * @throws IndexOutOfBoundsException if the offset is {@code < 0},
 723      * or {@code > b.limit()},
 724      * for any vector lane index {@code N} where the mask at lane {@code N}
 725      * is set
 726      * {@code i >= b.limit() - (N * this.elementSize() / Byte.SIZE)} bytes
 727      */
 728     public abstract void intoByteBuffer(ByteBuffer b, int i, Mask<E, S> m);
 729 
 730 
 731     /**
 732      * A factory for creating {@link Vector}, {@link Mask} and {@link Shuffle}
 733      * values of the same element type and shape.
 734      *
 735      * @param <E> the boxed element type of this species
 736      * @param <S> the type of shape of this species
 737      */
 738     public static abstract class Species<E, S extends Shape> {
 739         Species() {}
 740 
 741         /**
 742          * Returns the primitive element type of vectors produced by this
 743          * species.
 744          *
 745          * @return the primitive element type
 746          */
 747         public abstract Class<E> elementType();
 748 
 749         /**
 750          * Returns the element size, in bits, of vectors produced by this
 751          * species.
 752          *
 753          * @return the element size, in bits
 754          */
 755         public abstract int elementSize();
 756 
 757         /**
 758          * Returns the shape of masks, shuffles, and vectors produced by this
 759          * species.
 760          *
 761          * @return the primitive element type
 762          */
 763         public abstract S shape();
 764 
 765         /**
 766          * Returns the mask, shuffe, or vector lanes produced by this species.
 767          *
 768          * @return the the number of lanes
 769          */
 770         public int length() { return shape().length(this); }
 771 
 772         /**
 773          * Returns the total vector size, in bits, of vectors produced by this
 774          * species.
 775          *
 776          * @return the total vector size, in bits
 777          */
 778         public int bitSize() { return shape().bitSize(); }
 779 
 780         // Factory
 781 
 782         /**
 783          * Returns a vector where all lane elements are set to the default
 784          * primitive value.
 785          *
 786          * @return a zero vector
 787          */
 788         public abstract Vector<E, S> zero();
 789 
 790         /**
 791          * Loads a vector from a byte array starting at an offset.
 792          * <p>
 793          * Bytes are composed into primitive lane elements according to the
 794          * native byte order of the underlying platform
 795          * <p>
 796          * This method behaves as if it returns the result of calling the
 797          * byte buffer, offset, and mask accepting
 798          * {@link #fromByteBuffer(ByteBuffer, int, Mask) method} as follows:
 799          * <pre>{@code
 800          * return this.fromByteBuffer(ByteBuffer.wrap(a), i, this.maskAllTrue());
 801          * }</pre>
 802          *
 803          * @param a the byte array
 804          * @param i the offset into the array
 805          * @return a vector loaded from a byte array
 806          * @throws IndexOutOfBoundsException if {@code i < 0} or
 807          * {@code i > a.length - (this.length() * this.elementSize() / Byte.SIZE)}
 808          */
 809         public abstract Vector<E, S> fromByteArray(byte[] a, int i);
 810 
 811         /**
 812          * Loads a vector from a byte array starting at an offset and using a
 813          * mask.
 814          * <p>
 815          * Bytes are composed into primitive lane elements according to the
 816          * native byte order of the underlying platform.
 817          * <p>
 818          * This method behaves as if it returns the result of calling the
 819          * byte buffer, offset, and mask accepting
 820          * {@link #fromByteBuffer(ByteBuffer, int, Mask) method} as follows:
 821          * <pre>{@code
 822          * return this.fromByteBuffer(ByteBuffer.wrap(a), i, m);
 823          * }</pre>
 824          *
 825          * @param a the byte array
 826          * @param i the offset into the array
 827          * @param m the mask
 828          * @return a vector loaded from a byte array
 829          * @throws IndexOutOfBoundsException if {@code i < 0} or
 830          * {@code i > a.length - (this.length() * this.elementSize() / Byte.SIZE)}
 831          * @throws IndexOutOfBoundsException if the offset is {@code < 0},
 832          * or {@code > a.length},
 833          * for any vector lane index {@code N} where the mask at lane {@code N}
 834          * is set
 835          * {@code i >= a.length - (N * this.elementSize() / Byte.SIZE)}
 836          */
 837         public abstract Vector<E, S> fromByteArray(byte[] a, int i, Mask<E, S> m);
 838 
 839         /**
 840          * Loads a vector from a {@link ByteBuffer byte buffer} starting at the
 841          * buffer's position.
 842          * <p>
 843          * Bytes are composed into primitive lane elements according to the
 844          * native byte order of the underlying platform.
 845          * <p>
 846          * This method behaves as if it returns the result of calling the
 847          * byte buffer, offset, and mask accepting
 848          * {@link #fromByteBuffer(ByteBuffer, int, Mask) method} as follows:
 849          * <pre>{@code
 850          *   return this.fromByteBuffer(b, b.position(), this.maskAllTrue())
 851          * }</pre>
 852          *
 853          * @param b the byte buffer
 854          * @return a vector loaded from a byte buffer
 855          * @throws IndexOutOfBoundsException if there are fewer than
 856          * {@code this.length() * this.elementSize() / Byte.SIZE} bytes
 857          * remaining in the byte buffer
 858          */
 859         public abstract Vector<E, S> fromByteBuffer(ByteBuffer b);
 860 
 861         /**
 862          * Loads a vector from a {@link ByteBuffer byte buffer} starting at the
 863          * buffer's position and using a mask.
 864          * <p>
 865          * Bytes are composed into primitive lane elements according to the
 866          * native byte order of the underlying platform.
 867          * <p>
 868          * This method behaves as if it returns the result of calling the
 869          * byte buffer, offset, and mask accepting
 870          * {@link #fromByteBuffer(ByteBuffer, int, Mask)} method} as follows:
 871          * <pre>{@code
 872          *   return this.fromByteBuffer(b, b.position(), m)
 873          * }</pre>
 874          *
 875          * @param b the byte buffer
 876          * @param m the mask
 877          * @return a vector loaded from a byte buffer
 878          * @throws IndexOutOfBoundsException if for any vector lane index
 879          * {@code N} where the mask at lane {@code N} is set
 880          * {@code b.position() >= b.limit() - (N * this.elementSize() / Byte.SIZE)}
 881          */
 882         public abstract Vector<E, S> fromByteBuffer(ByteBuffer b, Mask<E, S> m);
 883 
 884         /**
 885          * Loads a vector from a {@link ByteBuffer byte buffer} starting at an
 886          * offset into the byte buffer.
 887          * <p>
 888          * Bytes are composed into primitive lane elements according to the
 889          * native byte order of the underlying platform.
 890          * <p>
 891          * This method behaves as if it returns the result of calling the
 892          * byte buffer, offset, and mask accepting
 893          * {@link #fromByteBuffer(ByteBuffer, int, Mask)} method} as follows:
 894          * <pre>{@code
 895          *   return this.fromByteBuffer(b, i, this.maskAllTrue())
 896          * }</pre>
 897          *
 898          * @param b the byte buffer
 899          * @param i the offset into the byte buffer
 900          * @return a vector loaded from a byte buffer
 901          * @throws IndexOutOfBoundsException if the offset is {@code < 0},
 902          * or {@code > b.limit()},
 903          * or if there are fewer than
 904          * {@code this.length() * this.elementSize() / Byte.SIZE} bytes
 905          * remaining in the byte buffer from the given offset
 906          */
 907         public abstract Vector<E, S> fromByteBuffer(ByteBuffer b, int i);
 908 
 909         /**
 910          * Loads a vector from a {@link ByteBuffer byte buffer} starting at an
 911          * offset into the byte buffer and using a mask.
 912          * <p>
 913          * This method behaves as if the byte buffer is viewed as a primitive
 914          * {@link java.nio.Buffer buffer} for the primitive element type,
 915          * according to the native byte order of the underlying platform, and
 916          * the returned vector is loaded with a mask from a primitive array
 917          * obtained from the primitive buffer.
 918          * The following pseudocode expresses the behaviour, where
 919          * {@coce EBuffer} is the primitive buffer type, {@code e} is the
 920          * primitive element type, and {@code ESpecies<S>} is the primitive
 921          * species for {@code e}:
 922          * <pre>{@code
 923          * EBuffer eb = b.duplicate().
 924          *     order(ByteOrder.nativeOrder()).position(i).
 925          *     asEBuffer();
 926          * e[] es = new e[this.length()];
 927          * for (int n = 0; n < t.length && m.isSet(n); n++) {
 928          *     es[n] = eb.get(n);
 929          * }
 930          * Vector<E, S> r = ((ESpecies<S>)this).fromArray(es, 0, m);
 931          * }</pre>
 932          *
 933          * @param b the byte buffer
 934          * @param i the offset into the byte buffer
 935          * @return a vector loaded from a byte buffer
 936          * @throws IndexOutOfBoundsException if the offset is {@code < 0},
 937          * or {@code > b.limit()},
 938          * for any vector lane index {@code N} where the mask at lane {@code N}
 939          * is set
 940          * {@code i >= b.limit() - (N * this.elementSize() / Byte.SIZE)}
 941          */
 942         public abstract Vector<E, S> fromByteBuffer(ByteBuffer b, int i, Mask<E, S> m);
 943 
 944         //Mask and shuffle constructions
 945 
 946         /**
 947          * Returns a mask where each lane is set or unset according to a given
 948          * {@code boolean} value.
 949          * <p>
 950          * For each mask lane, where {@code N} is the mask lane index,
 951          * if the given {@code boolean} value at index {@code N} is {@code true}
 952          * then the mask lane at index {@code N} is set, otherwise it is unset.
 953          *
 954          * @@@ What should happen if bits.length < this.length() ? use the
 955          * default value or throw IndexOutOfBoundsException
 956          *
 957          * @param bits the given {@code boolean} values
 958          * @return a mask where each lane is set or unset according to a given
 959          * {@code boolean} value
 960          */
 961         public abstract Mask<E, S> maskFromValues(boolean... bits);
 962 
 963         /**
 964          * Loads a mask from a {@code boolean} array starting at an offset.
 965          * <p>
 966          * For each mask lane, where {@code N} is the mask lane index,
 967          * if the array element at index {@code i + N} is {@code true} then the
 968          * mask lane at index {@code N} is set, otherwise it is unset.
 969          *
 970          * @param a the {@code boolean} array
 971          * @param i the offset into the array
 972          * @return the mask loaded from a {@code boolean} array
 973          * @throws IndexOutOfBoundsException if {@code i < 0}, or
 974          * {@code i > a.length - this.length()}
 975          */
 976         public abstract Mask<E, S> maskFromArray(boolean[] a, int i);
 977 
 978         /**
 979          * Returns a mask where all lanes are a set.
 980          *
 981          * @return a mask where all lanes are a set
 982          */
 983         public abstract Mask<E, S> maskAllTrue();
 984 
 985         /**
 986          * Returns a mask where all lanes are unset.
 987          *
 988          * @return a mask where all lanes are unset
 989          */
 990         public abstract Mask<E, S> maskAllFalse();
 991 
 992         /**
 993          * Returns a shuffle where each lane element to a given {@code int}
 994          * value.
 995          * <p>
 996          * For each shuffle lane, where {@code N} is the shuffle lane index, the
 997          * the {@code int} value at index {@code N} is placed into the resulting
 998          * shuffle at lane index {@code N}.
 999          *
1000          * @@@ What should happen if indexes.length < this.length() ? use the
1001          * default value or throw IndexOutOfBoundsException
1002          *
1003          * @param indexes the given {@code int} values
1004          * @return a shufle where each lane element is set to a given
1005          * {@code int} value
1006          */
1007         public abstract Shuffle<E, S> shuffleFromValues(int... indexes);
1008 
1009         /**
1010          * Loads a shuffle from an {@code int} array starting at offset.
1011          * <p>
1012          * For each shuffle lane, where {@code N} is the shuffle lane index, the
1013          * array element at index {@code i + N} is placed into the
1014          * resulting shuffle at lane index {@code N}.
1015          *
1016          * @param a the {@code int} array
1017          * @param i the offset into the array
1018          * @return the shuffle loaded from an {@code int} array
1019          * @throws IndexOutOfBoundsException if {@code i < 0}, or
1020          * {@code i > a.length - this.length()}
1021          */
1022         public abstract Shuffle<E, S> shuffleFromArray(int[] a, int i);
1023 
1024         /**
1025          * Returns a shuffle containing lane elements of an {@code int}
1026          * vector.
1027          * <p>
1028          * For each vector lane, where {@code N} is the vector lane index, the
1029          * lane element at index {@code N} is placed into the resulting shuffle
1030          * at lane index {@code N}.
1031          *
1032          * @param v the {@code int} vector
1033          * @return a shuffle containing lane elements of an {@code int} vector
1034          */
1035         public abstract Shuffle<E, S> shuffleFromVector(Vector<Integer, S> v);
1036 
1037         // Shuffle iota, 0...N
1038 
1039         // Vector type/shape transformations
1040 
1041         /**
1042          * Transforms an input vector of shape {@code T} and element type
1043          * {@code F} to a vector of this species shape {@code S} and element
1044          * type {@code E}.
1045          * <p>
1046          * The underlying bits of the input vector are copied to the resulting
1047          * vector without modification, but those bits, before copying, may be
1048          * truncated if the vector bit size is greater than this species bit
1049          * size, or appended to with zero bits if the vector bit size is less
1050          * than this species bit size.
1051          * <p>
1052          * The method behaves as if the input vector is stored into a byte buffer
1053          * and then the returned vector is loaded from the byte buffer using
1054          * native byte ordering. The implication is that ByteBuffer reads bytes
1055          * and then composes them based on the byte ordering so the result
1056          * depends on this composition.
1057          * <p>
1058          * For example, on a system with ByteOrder.LITTLE_ENDIAN, loading from
1059          * byte array with values {0,1,2,3} and reshaping to int, leads to bytes
1060          * being composed in order 0x3 0x2 0x1 0x0 which is decimal value 50462976.
1061          * On a system with ByteOrder.BIG_ENDIAN, the value is instead 66051 because
1062          * bytes are composed in order 0x0 0x1 0x2 0x3.
1063          * <p>
1064          * The following pseudocode expresses the behaviour:
1065          * <pre>{@code
1066          * int blen = Math.max(v.bitSize(), bitSize()) / Byte.SIZE;
1067          * ByteBuffer bb = ByteBuffer.allocate(blen).order(ByteOrder.nativeOrder());
1068          * v.intoByteBuffer(bb, 0);
1069          * return fromByteBuffer(bb, 0);
1070          * }</pre>
1071          *
1072          * @param v the input vector
1073          * @param <F> the boxed element type of the vector
1074          * @param <T> the type of shape of the vector
1075          * @return a vector transformed, by shape and element type, from an
1076          * input vector
1077          */
1078         public abstract <F, T extends Shape> Vector<E, S> reshape(Vector<F, T> v);
1079 
1080         /**
1081          * Transforms an input vector of element type {@code F} to a vector of
1082          * this species element type {@code E}, where the this species shape
1083          * {@code S} is preserved.
1084          * <p>
1085          * The underlying bits of the input vector are copied without
1086          * modification to the resulting vector.
1087          * <p>
1088          * The method behaves as if the input vector is stored into a byte buffer
1089          * and then the returned vector is loaded from the byte buffer using
1090          * native byte ordering. The implication is that ByteBuffer reads bytes
1091          * and then composes them based on the byte ordering so the result
1092          * depends on this composition.
1093          * <p>
1094          * For example, on a system with ByteOrder.LITTLE_ENDIAN, loading from
1095          * byte array with values {0,1,2,3} and rebracketing to int, leads to bytes
1096          * being composed in order 0x3 0x2 0x1 0x0 which is decimal value 50462976.
1097          * On a system with ByteOrder.BIG_ENDIAN, the value is instead 66051 because
1098          * bytes are composed in order 0x0 0x1 0x2 0x3.
1099          * <p>
1100          * The following pseudocode expresses the behaviour:
1101          * <pre>{@code
1102          * ByteBuffer bb = ByteBuffer.allocate(v.bitSize()).order(ByteOrder.nativeOrder());
1103          * v.intoByteBuffer(bb, 0);
1104          * return fromByteBuffer(bb, 0);
1105          * }</pre>
1106          *
1107          * @param v the input vector
1108          * @param <F> the boxed element type of the vector
1109          * @return a vector transformed, by element type, from an input vector
1110          */
1111         public abstract <F> Vector<E, S> rebracket(Vector<F, S> v);
1112 
1113         /**
1114          * Transforms an input vector of shape {@code T} to a vector of this
1115          * species shape {@code S}, where the this species element type
1116          * {@code E} is preserved.
1117          * <p>
1118          * The lane elements of the input vector are copied without
1119          * modification to the resulting vector, but those lane elements, before
1120          * copying, may be truncated if the vector length is greater than this
1121          * species length, or appended to with default element values if the
1122          * vector length is less than this species length.
1123          * <p>
1124          * The method behaves as if the input vector is stored into a byte array
1125          * and then the returned vector is loaded from the byte array.
1126          * The following pseudocode expresses the behaviour:
1127          * <pre>{@code
1128          * int alen = Math.max(v.bitSize(), this.bitSize()) / Byte.SIZE;
1129          * byte[] a = new byte[alen];
1130          * v.intoByteArray(a, 0);
1131          * return fromByteArray(a, 0);
1132          * }</pre>
1133          *
1134          * @param v the input vector
1135          * @param <T> the type of shape of the vector
1136          * @return a vector transformed, by shape, from an input vector
1137          */
1138         public abstract <T extends Shape> Vector<E, S> resize(Vector<E, T> v);
1139 
1140         /**
1141          * Converts an input vector of shape {@code T} and element type
1142          * {@code F} to a vector of this species shape {@code S} and element
1143          * type {@code E}.
1144          * <p>
1145          * For each input vector lane up to the length of the input vector or
1146          * this species, which ever is the minimum, and where {@code N} is the
1147          * vector lane index, the element at index {@code N} of primitive type
1148          * {@code F} is converted, according to primitive conversion rules
1149          * specified by the Java Language Specification, to a value of primitive
1150          * type {@code E} and placed into the resulting vector at lane index
1151          * {@code N}.  If this species length is greater than the input
1152          * vector length then the default primitive value is placed into
1153          * subsequent lanes of the resulting vector.
1154          *
1155          * @param v the input vector
1156          * @param <F> the boxed element type of the vector
1157          * @param <T> the type of shape of the vector
1158          * @return a vector, converted by shape and element type, from an input
1159          * vector.
1160          */
1161         public abstract <F, T extends Shape> Vector<E, S> cast(Vector<F, T> v);
1162 
1163 
1164         // Mask type/shape transformations
1165 
1166         /**
1167          * Transforms an input mask of shape {@code T} and element type
1168          * {@code F} to a vector of this species shape {@code S} and element
1169          * type {@code E}.
1170          * <p>
1171          * The lane elements of the input mask are copied to the resulting
1172          * mask without modification, but those lane elements, before copying,
1173          * may be truncated if the mask length is greater than this species
1174          * length, or appended to with false values if the mask length less than
1175          * this species length.
1176          * <p>
1177          * The method behaves as if the input mask is stored into a boolean
1178          * array and then the returned mask is loaded from the boolean array.
1179          * The following pseudocode expresses the behaviour:
1180          * <pre>{@code
1181          * int alen = Math.max(m.length(), this.length());
1182          * boolean[] a = new boolean[alen];
1183          * m.intoArray(a, 0);
1184          * return this.maskFromArray(a, 0);
1185          * }</pre>
1186          *
1187          * @param m the input mask
1188          * @param <F> the boxed element type of the mask
1189          * @param <T> the type of shape of the mask
1190          * @return a mask transformed, by shape and element type, from an
1191          * input mask
1192          */
1193         public <F, T extends Shape> Mask<E, S> reshape(Mask<F, T> m) {
1194             return maskFromValues(m.toArray());
1195         }
1196 
1197         /**
1198          * Transforms an input mask of element type {@code F} to a mask of
1199          * this species element type {@code E}, where the this species shape
1200          * {@code S} is preserved.
1201          * <p>
1202          * The lane elements of the input mask are copied without
1203          * modification to the resulting mask.
1204          * <p>
1205          * The method behaves as if the input mask is stored into a boolean
1206          * array and then the returned mask is loaded from the boolean array.
1207          * The following pseudocode expresses the behaviour:
1208          * <pre>{@code
1209          * boolean[] a = new byte[m.length()];
1210          * m.intoArray(a, 0);
1211          * return this.maskFromArray(a, 0);
1212          * }</pre>
1213          *
1214          * @param m the input mask
1215          * @param <F> the boxed element type of the mask
1216          * @return a mask transformed, by element type, from an input mask
1217          */
1218         @ForceInline
1219         public <F> Mask<E, S> rebracket(Mask<F, S> m) {
1220             return reshape(m);
1221         }
1222 
1223         /**
1224          * Transforms an input mask of shape {@code T} to a mask of this
1225          * species shape {@code S}, where the this species element type
1226          * {@code E} is preserved.
1227          * <p>
1228          * The lane elements of the input mask are copied to the resulting
1229          * mask without modification, but those lane elements, before copying,
1230          * may be truncated if the mask length is greater than this species
1231          * length, or appended to with false values if the mask length less than
1232          * this species length.
1233          * <p>
1234          * The method behaves as if the input mask is stored into a boolean
1235          * array and then the returned mask is loaded from the boolean array.
1236          * The following pseudocode expresses the behaviour:
1237          * <pre>{@code
1238          * int alen = Math.max(m.length(), this.length());
1239          * boolean[] a = new boolean[alen];
1240          * m.intoArray(a, 0);
1241          * return this.maskFromArray(a, 0);
1242          * }</pre>
1243          *
1244          * @param m the input mask
1245          * @param <T> the type of shape of the mask
1246          * @return a mask transformed, by shape, from an input mask
1247          */
1248         @ForceInline
1249         public <T extends Shape> Mask<E, S> resize(Mask<E, T> m) {
1250             return reshape(m);
1251         }
1252 
1253 
1254         // Shuffle type/shape transformations
1255 
1256         /**
1257          * Transforms an input shuffle of shape {@code T} and element type
1258          * {@code F} to a shuffle of this species shape {@code S} and element
1259          * type {@code E}.
1260          * <p>
1261          * The lane elements of the input shuffle are copied to the resulting
1262          * shuffle without modification, but those lane elements, before copying,
1263          * may be truncated if the shuffle length is greater than this species
1264          * length, or appended to with zero values if the shuffle length less than
1265          * this species length.
1266          * <p>
1267          * The method behaves as if the input shuffle is stored into a int
1268          * array and then the returned shuffle is loaded from the int array.
1269          * The following pseudocode expresses the behaviour:
1270          * <pre>{@code
1271          * int alen = Math.max(s.length(), this.length());
1272          * int[] a = new int[blen];
1273          * s.intoArray(a, 0);
1274          * return this.shuffleFromArray(a, 0);
1275          * }</pre>
1276          *
1277          * @param s the input shuffle
1278          * @param <F> the boxed element type of the shuffle
1279          * @param <T> the type of shape of the shuffle
1280          * @return a shuffle transformed, by shape and element type, from an
1281          * input shuffle
1282          */
1283         public <F, T extends Shape> Shuffle<E, S> reshape(Shuffle<F, T> s) {
1284             return shuffleFromValues(s.toArray());
1285         }
1286 
1287         /**
1288          * Transforms an input shuffle of element type {@code F} to a shuffle of
1289          * this species element type {@code E}, where the this species shape
1290          * {@code S} is preserved.
1291          * <p>
1292          * The lane elements of the input shuffle are copied without
1293          * modification to the resulting shuffle.
1294          * <p>
1295          * The method behaves as if the input shuffle is stored into a int
1296          * array and then the returned shuffle is loaded from the int array.
1297          * The following pseudocode expresses the behaviour:
1298          * <pre>{@code
1299          * int[] a = new byte[s.length()];
1300          * s.intoArray(a, 0);
1301          * return this.shuffleFromArray(a, 0);
1302          * }</pre>
1303          *
1304          * @param s the input shuffle
1305          * @param <F> the boxed element type of the shuffle
1306          * @return a shuffle transformed, by element type, from an input shuffle
1307          */
1308         @ForceInline
1309         public <F> Shuffle<E, S> rebracket(Shuffle<F, S> s) {
1310             return reshape(s);
1311         }
1312 
1313         /**
1314          * Transforms an input shuffle of shape {@code T} to a shuffle of this
1315          * species shape {@code S}, where the this species element type
1316          * {@code E} is preserved.
1317          * <p>
1318          * The lane elements of the input shuffle are copied to the resulting
1319          * shuffle without modification, but those lane elements, before copying,
1320          * may be truncated if the shuffle length is greater than this species
1321          * length, or appended to with zero values if the shuffle length less than
1322          * this species length.
1323          * <p>
1324          * The method behaves as if the input shuffle is stored into a int
1325          * array and then the returned shuffle is loaded from the int array.
1326          * The following pseudocode expresses the behaviour:
1327          * <pre>{@code
1328          * int alen = Math.max(m.length(), this.length());
1329          * boolean[] a = new boolean[alen];
1330          * m.intoArray(a, 0);
1331          * return this.maskFromArray(a, 0);
1332          * }</pre>
1333          *
1334          * @param s the input shuffle
1335          * @param <T> the type of shape of the shuffle
1336          * @return a shuffle transformed, by shape, from an input shuffle
1337          */
1338         @ForceInline
1339         public <T extends Shape> Shuffle<E, S> resize(Shuffle<E, T> s) {
1340             return reshape(s);
1341         }
1342 
1343 
1344         // Species/species transformations
1345 
1346         // Returns a species for a given element type and the length of this
1347         // species.
1348         // The length of the returned species will be equal to the length of
1349         // this species.
1350         //
1351         // Throws IAE if no shape exists for the element type and this species length,
1352 //        public <F> Species<F, ?> toSpeciesWithSameNumberOfLanes(Class<F> c) {
1353 //            // @@@ TODO implement and find better name
1354 //            throw new UnsupportedOperationException();
1355 //        }
1356 
1357     }
1358 
1359     /**
1360      * A {@code Shape} governs the total size, in bits, of a
1361      * {@link Vector}, {@link Mask}, or {@code Shuffle}.  The shape in
1362      * combination with the element type together govern the number of lanes.
1363      */
1364     public static abstract class Shape {
1365         Shape() {}
1366 
1367         /**
1368          * Returns the size, in bits, of this shape.
1369          *
1370          * @return the size, in bits, of this shape.
1371          */
1372         public abstract int bitSize();
1373 
1374         // @@@ remove this method
1375         public int length(Species<?, ?> s) { return bitSize() / s.elementSize(); }
1376     }
1377 
1378     /**
1379      * A {@code Mask} represents an ordered immutable sequence of {@code boolean}
1380      * values.  A Mask can be used with a mask accepting vector operation to
1381      * control the selection and operation of lane elements of input vectors.
1382      * <p>
1383      * The number of values in the sequence is referred to as the Mask
1384      * {@link #length() length}.  The length also corresponds to the number of
1385      * Mask lanes.  The lane element at lane index {@code N} (from {@code 0},
1386      * inclusive, to length, exclusive) corresponds to the {@code N + 1}'th
1387      * value in the sequence.
1388      * A Mask and Vector of the same element type and shape have the same number
1389      * of lanes.
1390      * <p>
1391      * A lane is said to be <em>set</em> if the lane element is {@code true},
1392      * otherwise a lane is said to be <em>unset</em> if the lane element is
1393      * {@code false}.
1394      * <p>
1395      * Mask declares a limited set of unary, binary and reductive mask
1396      * operations.
1397      * <ul>
1398      * <li>
1399      * A mask unary operation (1-ary) operates on one input mask to produce a
1400      * result mask.
1401      * For each lane of the input mask the
1402      * lane element is operated on using the specified scalar unary operation and
1403      * the boolean result is placed into the mask result at the same lane.
1404      * The following pseudocode expresses the behaviour of this operation category:
1405      *
1406      * <pre>{@code
1407      * Mask<E, S> a = ...;
1408      * boolean[] ar = new boolean[a.length()];
1409      * for (int i = 0; i < a.length(); i++) {
1410      *     ar[i] = boolean_unary_op(a.isSet(i));
1411      * }
1412      * Mask<E, S> r = a.species().maskFromArray(ar, 0);
1413      * }</pre>
1414      *
1415      * <li>
1416      * A mask binary operation (2-ary) operates on two input
1417      * masks to produce a result mask.
1418      * For each lane of the two input masks,
1419      * a and b say, the corresponding lane elements from a and b are operated on
1420      * using the specified scalar binary operation and the boolean result is placed
1421      * into the mask result at the same lane.
1422      * The following pseudocode expresses the behaviour of this operation category:
1423      *
1424      * <pre>{@code
1425      * Mask<E, S> a = ...;
1426      * Mask<E, S> b = ...;
1427      * boolean[] ar = new boolean[a.length()];
1428      * for (int i = 0; i < a.length(); i++) {
1429      *     ar[i] = scalar_binary_op(a.isSet(i), b.isSet(i));
1430      * }
1431      * Mask<E, S> r = a.species().maskFromArray(ar, 0);
1432      * }</pre>
1433      *
1434      * @param <E> the boxed element type of this mask
1435      * @param <S> the type of shape of this mask
1436      */
1437     public static abstract class Mask<E, S extends Shape> {
1438         Mask() {}
1439 
1440         /**
1441          * Returns the species of this mask.
1442          *
1443          * @return the species of this mask
1444          */
1445         public abstract Species<E, S> species();
1446 
1447         /**
1448          * Returns the number of mask lanes (the length).
1449          *
1450          * @return the number of mask lanes
1451          */
1452         public int length() { return species().length(); }
1453 
1454         /**
1455          * Returns the lane elements of this mask packed into a {@code long}
1456          * value for at most the first 64 lane elements.
1457          * <p>
1458          * The lane elements are packed in the order of least significant bit
1459          * to most significant bit.
1460          * For each mask lane where {@code N} is the mask lane index, if the
1461          * mask lane is set then the {@code N}'th bit is set to one in the
1462          * resulting {@code long} value, otherwise the {@code N}'th bit is set
1463          * to zero.
1464          *
1465          * @return the lane elements of this mask packed into a {@code long}
1466          * value.
1467          */
1468         public abstract long toLong();
1469 
1470         /**
1471          * Returns an {@code boolean} array containing the lane elements of this
1472          * mask.
1473          * <p>
1474          * This method behaves as if it {@link #intoArray(boolean[], int)} stores}
1475          * this mask into an allocated array and returns that array as
1476          * follows:
1477          * <pre>{@code
1478          * boolean[] a = new boolean[this.length()];
1479          * this.intoArray(a, 0);
1480          * return a;
1481          * }</pre>
1482          *
1483          * @return an array containing the the lane elements of this vector
1484          */
1485         public abstract boolean[] toArray();
1486 
1487         /**
1488          * Stores this mask into a {@code boolean} array starting at offset.
1489          * <p>
1490          * For each mask lane, where {@code N} is the mask lane index,
1491          * the lane element at index {@code N} is stored into the array at index
1492          * {@code i + N}.
1493          *
1494          * @param a the array
1495          * @param i the offset into the array
1496          * @throws IndexOutOfBoundsException if {@code i < 0}, or
1497          * {@code i > a.length - this.length()}
1498          */
1499         public abstract void intoArray(boolean[] a, int i);
1500 
1501         /**
1502          * Returns {@code true} if any of the mask lanes are set.
1503          *
1504          * @return {@code true} if any of the mask lanes are set, otherwise
1505          * {@code false}.
1506          */
1507         public abstract boolean anyTrue();
1508 
1509         /**
1510          * Returns {@code true} if all of the mask lanes are set.
1511          *
1512          * @return {@code true} if all of the mask lanes are set, otherwise
1513          * {@code false}.
1514          */
1515         public abstract boolean allTrue();
1516 
1517         /**
1518          * Returns the number of mask lanes that are set.
1519          *
1520          * @return the number of mask lanes that are set.
1521          */
1522         public abstract int trueCount();
1523 
1524         // TODO: LZ count/numberOfLeadingZeros
1525         // TODO: xor, shiftl, shiftr
1526 
1527         /**
1528          * Logically ands this mask with an input mask.
1529          * <p>
1530          * This is a mask binary operation where the logical and operation
1531          * ({@code &&} is applied to lane elements.
1532          *
1533          * @param o the input mask
1534          * @return the result of logically and'ing this mask with an input mask
1535          */
1536         public abstract Mask<E, S> and(Mask<E, S> o);
1537 
1538         /**
1539          * Logically ors this mask with an input mask.
1540          * <p>
1541          * This is a mask binary operation where the logical or operation
1542          * ({@code ||} is applied to lane elements.
1543          *
1544          * @param o the input mask
1545          * @return the result of logically or'ing this mask with an input mask
1546          */
1547         public abstract Mask<E, S> or(Mask<E, S> o);
1548 
1549         /**
1550          * Logically negates this mask.
1551          * <p>
1552          * This is a mask unary operation where the logical not operation
1553          * ({@code !} is applied to lane elements.
1554          *
1555          * @return the result of logically negating this mask.
1556          */
1557         public abstract Mask<E, S> not();
1558 
1559         /**
1560          * Returns a vector representation of this mask.
1561          * <p>
1562          * For each mask lane, where {@code N} is the mask lane index,
1563          * if the mask lane is set then an element value whose most significant
1564          * bit is set is placed into the resulting vector at lane index
1565          * {@code N}, otherwise the default element value is placed into the
1566          * resulting vector at lane index {@code N}.
1567          *
1568          * @return a vector representation of this mask.
1569          */
1570         public abstract Vector<E, S> toVector();
1571 
1572         /**
1573          * Tests if the lane at index {@code i} is set
1574          * @param i the lane index
1575          *
1576          * @return true if the lane at index {@code i} is set, otherwise false
1577          */
1578         // @@@ Rename to isSet
1579         public abstract boolean getElement(int i);
1580 
1581         /**
1582          * Transforms this mask to a mask of the given species shape {@code T}
1583          * and element type {@code F}.
1584          * <p>
1585          * This method behaves as if it returns the result of calling
1586          * {@link Species#reshape(Mask) reshape} on the given species with this
1587          * mask:
1588          * <pre>{@code
1589          * return species.reshape(this);
1590          * }</pre>
1591          *
1592          * @param species the species
1593          * @param <F> the boxed element type of the species
1594          * @param <T> the type of shape of the species
1595          * @return a mask transformed by shape and element type
1596          * @see Species#reshape(Mask)
1597          */
1598         @ForceInline
1599         public <F, T extends Shape> Mask<F, T> reshape(Species<F, T> species) {
1600             return species.reshape(this);
1601         }
1602 
1603         /**
1604          * Transforms this mask to a mask of the given species element type
1605          * {@code F}, where this mask's shape {@code S} is preserved.
1606          * <p>
1607          * This method behaves as if it returns the result of calling
1608          * {@link Species#rebracket(Mask) rebracket} on the given species with
1609          * this mask:
1610          * <pre>{@code
1611          * return species.rebracket(this);
1612          * }</pre>
1613          *
1614          * @param species the species
1615          * @param <F> the boxed element type of the species
1616          * @return a mask transformed element type
1617          * @see Species#rebracket(Mask)
1618          */
1619         @ForceInline
1620         public <F> Mask<F, S> rebracket(Species<F, S> species) {
1621             return species.reshape(this);
1622         }
1623 
1624         /**
1625          * Transforms this mask to a mask of the given species shape {@code T},
1626          * where this mask's element type {@code E} is preserved.
1627          * <p>
1628          * This method behaves as if it returns the result of calling
1629          * {@link Species#resize(Mask) resize} on the given species with this
1630          * mask:
1631          * <pre>{@code
1632          * return species.resize(this);
1633          * }</pre>
1634          *
1635          * @param species the species
1636          * @param <T> the type of shape of the species
1637          * @return a mask transformed by shape
1638          * @see Species#resize(Mask)
1639          */
1640         @ForceInline
1641         public <T extends Shape> Mask<E, T> resize(Species<E, T> species) {
1642             return species.reshape(this);
1643         }
1644     }
1645 
1646     /**
1647      * A {@code Shuffle} represents an ordered immutable sequence of
1648      * {@code int} values.  A Shuffle can be used with a shuffle accepting
1649      * vector operation to control the rearrangement of lane elements of input
1650      * vectors
1651      * <p>
1652      * The number of values in the sequence is referred to as the Shuffle
1653      * {@link #length() length}.  The length also corresponds to the number of
1654      * Shuffle lanes.  The lane element at lane index {@code N} (from {@code 0},
1655      * inclusive, to length, exclusive) corresponds to the {@code N + 1}'th
1656      * value in the sequence.
1657      * A Shuffle and Vector of the same element type and shape have the same
1658      * number of lanes.
1659      * <p>
1660      * A {@code Shuffle<E, S>} is a specialized and limited form of an
1661      * {@code IntVector<S>} where the Shuffle's lane elements correspond to
1662      * lane index values.
1663      * A Shuffle describes how a lane element of a vector may cross lanes from
1664      * its lane index, {@code i} say, to another lane index whose value is the
1665      * Shuffle's lane element at lane index {@code i}.
1666      *
1667      * @param <E> the boxed element type of this mask
1668      * @param <S> the type of shape of this mask
1669      */
1670     public static abstract class Shuffle<E, S extends Shape> {
1671         Shuffle() {}
1672 
1673         /**
1674          * Returns the species of this shuffle.
1675          *
1676          * @return the species of this shuffle
1677          */
1678         public abstract Species<E, S> species();
1679 
1680         /**
1681          * Returns the specialized {@code int} species of this shuffle.
1682          *
1683          * @return the specialized {@code int} species of this shuffle
1684          * @see #toVector
1685          */
1686         public abstract IntVector.IntSpecies<S> intSpecies();
1687 
1688         /**
1689          * Returns the number of shuffle lanes (the length).
1690          *
1691          * @return the number of shuffle lanes
1692          */
1693         public int length() { return species().length(); }
1694 
1695         /**
1696          * Returns an {@code int} array containing the lane elements of this
1697          * shuffle.
1698          * <p>
1699          * This method behaves as if it {@link #intoArray(int[], int)} stores}
1700          * this shuffle into an allocated array and returns that array as
1701          * follows:
1702          * <pre>{@code
1703          *   int[] a = new int[this.length()];
1704          *   this.intoArray(a, 0);
1705          *   return a;
1706          * }</pre>
1707          *
1708          * @return an array containing the the lane elements of this vector
1709          */
1710         public abstract int[] toArray();
1711 
1712         /**
1713          * Stores this shuffle into an {@code int} array starting at offset.
1714          * <p>
1715          * For each shuffle lane, where {@code N} is the shuffle lane index,
1716          * the lane element at index {@code N} is stored into the array at index
1717          * {@code i + N}.
1718          *
1719          * @param a the array
1720          * @param i the offset into the array
1721          * @throws IndexOutOfBoundsException if {@code i < 0}, or
1722          * {@code i > a.length - this.length()}
1723          */
1724         public abstract void intoArray(int[] a, int i);
1725 
1726         // @@@ rotate/shift/EL/ER
1727 
1728         /**
1729          * Returns an {@link IntVector}, of the same shape as this shuffle,
1730          * containing the lane elements of this shuffle.
1731          * <p>
1732          * This method behaves as if it returns the result of creating an
1733          * {@link IntVector} given this shuffle's {@code int} species and an
1734          * {@code int} array obtained from this shuffle's lane elements, as
1735          * follows:
1736          * <pre>{@code
1737          *   int[] a = this.toArray();
1738          *   return this.intSpecies().fromArray(a, 0);
1739          * }</pre>
1740          *
1741          * @return an {@link IntVector}, of the same shape as this shuffle,
1742          * containing the lane elements of this shuffle
1743          */
1744         public abstract IntVector<S> toVector();
1745 
1746         /**
1747          * Gets the {@code int} lane element at lane index {@code i}
1748          *
1749          * @param i the lane index
1750          * @return the {@code int} lane element at lane index {@code i}
1751          */
1752         public int getElement(int i) { return toArray()[i]; }
1753 
1754         /**
1755          * Transforms this shuffle to a shuffle of the given species shape {@code T}
1756          * and element type {@code F}.
1757          * <p>
1758          * This method behaves as if it returns the result of calling
1759          * {@link Species#reshape(Shuffle) reshape} on the given species with this
1760          * shuffle:
1761          * <pre>{@code
1762          * return species.reshape(this);
1763          * }</pre>
1764          *
1765          * @param species the species
1766          * @param <F> the boxed element type of the species
1767          * @param <T> the type of shape of the species
1768          * @return a shuffle transformed by shape and element type
1769          * @see Species#reshape(Shuffle)
1770          */
1771         @ForceInline
1772         public <F, T extends Shape> Shuffle<F, T> reshape(Species<F, T> species) {
1773             return species.reshape(this);
1774         }
1775 
1776         /**
1777          * Transforms this shuffle to a shuffle of the given species element type
1778          * {@code F}, where this shuffle's shape {@code S} is preserved.
1779          * <p>
1780          * This method behaves as if it returns the result of calling
1781          * {@link Species#rebracket(Shuffle) rebracket} on the given species with this
1782          * shuffle:
1783          * <pre>{@code
1784          * return species.rebracket(this);
1785          * }</pre>
1786          *
1787          * @param species the species
1788          * @param <F> the boxed element type of the species
1789          * @return a shuffle transformed element type
1790          * @see Species#rebracket(Shuffle)
1791          */
1792         @ForceInline
1793         public <F> Shuffle<F, S> rebracket(Species<F, S> species) {
1794             return species.reshape(this);
1795         }
1796 
1797         /**
1798          * Transforms this shuffle to a shuffle of the given species shape {@code T},
1799          * where this shuffle's element type {@code E} is preserved.
1800          * <p>
1801          * This method behaves as if it returns the result of calling
1802          * {@link Species#resize(Shuffle) resize} on the given species with this shuffle:
1803          * <pre>{@code
1804          * return species.resize(this);
1805          * }</pre>
1806          *
1807          * @param species the species
1808          * @param <T> the type of shape of the species
1809          * @return a shuffle transformed by shape
1810          * @see Species#resize(Shuffle)
1811          */
1812         @ForceInline
1813         public <T extends Shape> Shuffle<E, T> resize(Species<E, T> species) {
1814             return species.reshape(this);
1815         }
1816     }
1817 
1818     /**
1819      * Finds a preferred species for an element type.
1820      * <p>
1821      * A preferred species is a species chosen by the platform that has a
1822      * shape of maximal bit size.  A preferred species for different element
1823      * types will have the same shape, and therefore vectors created from
1824      * such species will be shape compatible.
1825      *
1826      * @param c the element type
1827      * @param <E> the boxed element type
1828      * @return a preferred species for an element type
1829      * @throws IllegalArgumentException if no such species exists for the
1830      * element type
1831      */
1832     @SuppressWarnings("unchecked")
1833     public static <E> Vector.Species<E, ?> preferredSpeciesInstance(Class<E> c) {
1834         Unsafe u = Unsafe.getUnsafe();
1835 
1836         int vectorLength = u.getMaxVectorSize(c);
1837         int vectorBitSize = bitSizeForVectorLength(c, vectorLength);
1838         Shape s = shapeForVectorBitSize(vectorBitSize);
1839         return speciesInstance(c, s);
1840     }
1841 
1842     // @@@ public static method on Species?
1843     private static int bitSizeForVectorLength(Class<?> c, int elementSize) {
1844         if (c == float.class) {
1845             return Float.SIZE * elementSize;
1846         }
1847         else if (c == double.class) {
1848             return Double.SIZE * elementSize;
1849         }
1850         else if (c == byte.class) {
1851             return Byte.SIZE * elementSize;
1852         }
1853         else if (c == short.class) {
1854             return Short.SIZE * elementSize;
1855         }
1856         else if (c == int.class) {
1857             return Integer.SIZE * elementSize;
1858         }
1859         else if (c == long.class) {
1860             return Long.SIZE * elementSize;
1861         }
1862         else {
1863             throw new IllegalArgumentException("Bad vector type: " + c.getName());
1864         }
1865     }
1866 
1867     // @@@ public static method on Shape?
1868     private static Shape shapeForVectorBitSize(int bitSize) {
1869         switch (bitSize) {
1870             case 64:
1871                 return Shapes.S_64_BIT;
1872             case 128:
1873                 return Shapes.S_128_BIT;
1874             case 256:
1875                 return Shapes.S_256_BIT;
1876             case 512:
1877                 return Shapes.S_512_BIT;
1878             default:
1879                 throw new IllegalArgumentException("Bad vector bit size: " + bitSize);
1880         }
1881     }
1882 
1883     /**
1884      * Finds a species for an element type and shape.
1885      *
1886      * @param c the element type
1887      * @param s the shape
1888      * @param <E> the boxed element type
1889      * @param <S> the type of shape
1890      * @return a species for an element type and shape
1891      * @throws IllegalArgumentException if no such species exists for the
1892      * element type and/or shape
1893      */
1894     @SuppressWarnings("unchecked")
1895     public static <E, S extends Shape> Vector.Species<E, S> speciesInstance(Class<E> c, S s) {
1896         if (c == float.class) {
1897             return (Vector.Species<E, S>) FloatVector.speciesInstance(s);
1898         }
1899         else if (c == double.class) {
1900             return (Vector.Species<E, S>) DoubleVector.speciesInstance(s);
1901         }
1902         else if (c == byte.class) {
1903             return (Vector.Species<E, S>) ByteVector.speciesInstance(s);
1904         }
1905         else if (c == short.class) {
1906             return (Vector.Species<E, S>) ShortVector.speciesInstance(s);
1907         }
1908         else if (c == int.class) {
1909             return (Vector.Species<E, S>) IntVector.speciesInstance(s);
1910         }
1911         else if (c == long.class) {
1912             return (Vector.Species<E, S>) LongVector.speciesInstance(s);
1913         }
1914         else {
1915             throw new IllegalArgumentException("Bad vector element type: " + c.getName());
1916         }
1917     }
1918 }