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.util.Objects;
  31 
  32 /**
  33  * A {@code VectorMask} represents an ordered immutable sequence of {@code boolean}
  34  * values.  A VectorMask can be used with a mask accepting vector operation to
  35  * control the selection and operation of lane elements of input vectors.
  36  * <p>
  37  * The number of values in the sequence is referred to as the VectorMask
  38  * {@link #length() length}. The length also corresponds to the number of
  39  * VectorMask lanes.  The lane element at lane index {@code N} (from {@code 0},
  40  * inclusive, to length, exclusive) corresponds to the {@code N + 1}'th
  41  * value in the sequence.
  42  * A VectorMask and Vector of the same element type and shape have the same number
  43  * of lanes.
  44  * <p>
  45  * A lane is said to be <em>set</em> if the lane element is {@code true},
  46  * otherwise a lane is said to be <em>unset</em> if the lane element is
  47  * {@code false}.
  48  * <p>
  49  * VectorMask declares a limited set of unary, binary and reductive mask
  50  * operations.
  51  * <ul>
  52  * <li>
  53  * A mask unary operation (1-ary) operates on one input mask to produce a
  54  * result mask.
  55  * For each lane of the input mask the
  56  * lane element is operated on using the specified scalar unary operation and
  57  * the boolean result is placed into the mask result at the same lane.
  58  * The following pseudocode expresses the behaviour of this operation category:
  59  *
  60  * <pre>{@code
  61  * VectorMask<E> a = ...;
  62  * boolean[] ar = new boolean[a.length()];
  63  * for (int i = 0; i < a.length(); i++) {
  64  *     ar[i] = boolean_unary_op(a.isSet(i));
  65  * }
  66  * VectorMask<E> r = VectorMask.fromArray(ar, 0);
  67  * }</pre>
  68  *
  69  * <li>
  70  * A mask binary operation (2-ary) operates on two input
  71  * masks to produce a result mask.
  72  * For each lane of the two input masks,
  73  * a and b say, the corresponding lane elements from a and b are operated on
  74  * using the specified scalar binary operation and the boolean result is placed
  75  * into the mask result at the same lane.
  76  * The following pseudocode expresses the behaviour of this operation category:
  77  *
  78  * <pre>{@code
  79  * VectorMask<E> a = ...;
  80  * VectorMask<E> b = ...;
  81  * boolean[] ar = new boolean[a.length()];
  82  * for (int i = 0; i < a.length(); i++) {
  83  *     ar[i] = scalar_binary_op(a.isSet(i), b.isSet(i));
  84  * }
  85  * VectorMask<E> r = VectorMask.fromArray(ar, 0);
  86  * }</pre>
  87  *
  88  * </ul>
  89  * @param <E> the boxed element type of this mask
  90  */
  91 public abstract class VectorMask<E> {
  92     VectorMask() {}
  93 
  94     /**
  95      * Returns the species of this mask.
  96      *
  97      * @return the species of this mask
  98      */
  99     public abstract VectorSpecies<E> species();
 100 
 101     /**
 102      * Returns the number of mask lanes (the length).
 103      *
 104      * @return the number of mask lanes
 105      */
 106     public int length() { return species().length(); }
 107 
 108     /**
 109      * Returns a mask where each lane is set or unset according to given
 110      * {@code boolean} values
 111      * <p>
 112      * For each mask lane, where {@code N} is the mask lane index,
 113      * if the given {@code boolean} value at index {@code N} is {@code true}
 114      * then the mask lane at index {@code N} is set, otherwise it is unset.
 115      *
 116      * @param species mask species
 117      * @param bits the given {@code boolean} values
 118      * @return a mask where each lane is set or unset according to the given {@code boolean} value
 119      * @throws IndexOutOfBoundsException if {@code bits.length < species.length()}
 120      */
 121     @ForceInline
 122     public static <E> VectorMask<E> fromValues(VectorSpecies<E> species, boolean... bits) {
 123         return fromArray(species, bits, 0);
 124     }
 125 
 126     /**
 127      * Loads a mask from a {@code boolean} array starting at an offset.
 128      * <p>
 129      * For each mask lane, where {@code N} is the mask lane index,
 130      * if the array element at index {@code ix + N} is {@code true} then the
 131      * mask lane at index {@code N} is set, otherwise it is unset.
 132      *
 133      * @param species mask species
 134      * @param bits the {@code boolean} array
 135      * @param ix the offset into the array
 136      * @return the mask loaded from a {@code boolean} array
 137      * @throws IndexOutOfBoundsException if {@code ix < 0}, or
 138      * {@code ix > bits.length - species.length()}
 139      */
 140     @ForceInline
 141     @SuppressWarnings("unchecked")
 142     public static <E> VectorMask<E> fromArray(VectorSpecies<E> species, boolean[] bits, int ix) {
 143         Objects.requireNonNull(bits);
 144         ix = VectorIntrinsics.checkIndex(ix, bits.length, species.length());
 145         return VectorIntrinsics.load((Class<VectorMask<E>>) species.maskType(), species.elementType(), species.length(),
 146                 bits, (long) ix + Unsafe.ARRAY_BOOLEAN_BASE_OFFSET,
 147                 bits, ix, species,
 148                 (boolean[] c, int idx, VectorSpecies<E> s) -> ((AbstractSpecies<E>)s).opm(n -> c[idx + n]));
 149     }
 150 
 151     /**
 152      * Returns a mask where all lanes are set.
 153      *
 154      * @param species mask species
 155      * @return a mask where all lanes are set
 156      */
 157     @ForceInline
 158     @SuppressWarnings("unchecked")
 159     public static <E> VectorMask<E> maskAllTrue(VectorSpecies<E> species) {
 160         return VectorIntrinsics.broadcastCoerced((Class<VectorMask<E>>) species.maskType(), species.elementType(), species.length(),
 161                 -1,  species,
 162                 ((z, s) -> AbstractMask.trueMask(s)));
 163     }
 164 
 165     /**
 166      * Returns a mask where all lanes are unset.
 167      *
 168      * @param species mask species
 169      * @return a mask where all lanes are unset
 170      */
 171     @ForceInline
 172     @SuppressWarnings("unchecked")
 173     public static <E> VectorMask<E> maskAllFalse(VectorSpecies<E> species) {
 174         return VectorIntrinsics.broadcastCoerced((Class<VectorMask<E>>) species.maskType(), species.elementType(), species.length(),
 175                 0, species,
 176                 ((z, s) -> AbstractMask.falseMask(s)));
 177     }
 178 
 179     /**
 180      * Converts this mask to a mask of the given species shape of element type {@code F}.
 181      * <p>
 182      * For each mask lane, where {@code N} is the lane index, if the
 183      * mask lane at index {@code N} is set, then the mask lane at index
 184      * {@code N} of the resulting mask is set, otherwise that mask lane is
 185      * not set.
 186      *
 187      * @param s the species of the desired mask
 188      * @param <F> the boxed element type of the species
 189      * @return a mask converted by shape and element type
 190      * @throws IllegalArgumentException if this mask length and the species
 191      * length differ
 192      */
 193     public abstract <F> VectorMask<F> cast(VectorSpecies<F> s);
 194 
 195     /**
 196      * Returns the lane elements of this mask packed into a {@code long}
 197      * value for at most the first 64 lane elements.
 198      * <p>
 199      * The lane elements are packed in the order of least significant bit
 200      * to most significant bit.
 201      * For each mask lane where {@code N} is the mask lane index, if the
 202      * mask lane is set then the {@code N}'th bit is set to one in the
 203      * resulting {@code long} value, otherwise the {@code N}'th bit is set
 204      * to zero.
 205      *
 206      * @return the lane elements of this mask packed into a {@code long}
 207      * value.
 208      */
 209     public abstract long toLong();
 210 
 211     /**
 212      * Returns an {@code boolean} array containing the lane elements of this
 213      * mask.
 214      * <p>
 215      * This method behaves as if it {@link #intoArray(boolean[], int)} stores}
 216      * this mask into an allocated array and returns that array as
 217      * follows:
 218      * <pre>{@code
 219      * boolean[] a = new boolean[this.length()];
 220      * this.intoArray(a, 0);
 221      * return a;
 222      * }</pre>
 223      *
 224      * @return an array containing the the lane elements of this vector
 225      */
 226     public abstract boolean[] toArray();
 227 
 228     /**
 229      * Stores this mask into a {@code boolean} array starting at offset.
 230      * <p>
 231      * For each mask lane, where {@code N} is the mask lane index,
 232      * the lane element at index {@code N} is stored into the array at index
 233      * {@code i + N}.
 234      *
 235      * @param a the array
 236      * @param i the offset into the array
 237      * @throws IndexOutOfBoundsException if {@code i < 0}, or
 238      * {@code i > a.length - this.length()}
 239      */
 240     public abstract void intoArray(boolean[] a, int i);
 241 
 242     /**
 243      * Returns {@code true} if any of the mask lanes are set.
 244      *
 245      * @return {@code true} if any of the mask lanes are set, otherwise
 246      * {@code false}.
 247      */
 248     public abstract boolean anyTrue();
 249 
 250     /**
 251      * Returns {@code true} if all of the mask lanes are set.
 252      *
 253      * @return {@code true} if all of the mask lanes are set, otherwise
 254      * {@code false}.
 255      */
 256     public abstract boolean allTrue();
 257 
 258     /**
 259      * Returns the number of mask lanes that are set.
 260      *
 261      * @return the number of mask lanes that are set.
 262      */
 263     public abstract int trueCount();
 264 
 265     /**
 266      * Logically ands this mask with an input mask.
 267      * <p>
 268      * This is a mask binary operation where the logical and operation
 269      * ({@code &&} is applied to lane elements.
 270      *
 271      * @param o the input mask
 272      * @return the result of logically and'ing this mask with an input mask
 273      */
 274     public abstract VectorMask<E> and(VectorMask<E> o);
 275 
 276     /**
 277      * Logically ors this mask with an input mask.
 278      * <p>
 279      * This is a mask binary operation where the logical or operation
 280      * ({@code ||} is applied to lane elements.
 281      *
 282      * @param o the input mask
 283      * @return the result of logically or'ing this mask with an input mask
 284      */
 285     public abstract VectorMask<E> or(VectorMask<E> o);
 286 
 287     /**
 288      * Logically negates this mask.
 289      * <p>
 290      * This is a mask unary operation where the logical not operation
 291      * ({@code !} is applied to lane elements.
 292      *
 293      * @return the result of logically negating this mask.
 294      */
 295     public abstract VectorMask<E> not();
 296 
 297     /**
 298      * Returns a vector representation of this mask.
 299      * <p>
 300      * For each mask lane, where {@code N} is the mask lane index,
 301      * if the mask lane is set then an element value whose most significant
 302      * bit is set is placed into the resulting vector at lane index
 303      * {@code N}, otherwise the default element value is placed into the
 304      * resulting vector at lane index {@code N}.
 305      *
 306      * @return a vector representation of this mask.
 307      */
 308     public abstract Vector<E> toVector();
 309 
 310     /**
 311      * Tests if the lane at index {@code i} is set
 312      * @param i the lane index
 313      *
 314      * @return true if the lane at index {@code i} is set, otherwise false
 315      */
 316     public abstract boolean getElement(int i);
 317 
 318     /**
 319      * Tests if the lane at index {@code i} is set
 320      * @param i the lane index
 321      * @return true if the lane at index {@code i} is set, otherwise false
 322      * @see #getElement
 323      */
 324     public boolean isSet(int i) {
 325         return getElement(i);
 326     }
 327 }