Beispiel #1
1
 @Override
 public Vector<T> retainAll(java.lang.Iterable<? extends T> elements) {
   Objects.requireNonNull(elements, "elements is null");
   final Vector<T> keeped = Vector.ofAll(elements).distinct();
   HashArrayMappedTrie<Integer, T> result = HashArrayMappedTrie.empty();
   for (T element : this) {
     if (keeped.contains(element)) {
       result = result.put(result.size(), element);
     }
   }
   return result.isEmpty() ? empty() : new Vector<>(result);
 }
Beispiel #2
1
 @Override
 public Vector<T> slice(int beginIndex, int endIndex) {
   if (beginIndex < 0 || beginIndex > endIndex || endIndex > length()) {
     throw new IndexOutOfBoundsException(
         String.format("slice(%s, %s) on List of length %s", beginIndex, endIndex, length()));
   }
   if (beginIndex == endIndex) {
     return Vector.empty();
   }
   HashArrayMappedTrie<Integer, T> trie = HashArrayMappedTrie.empty();
   for (int i = beginIndex; i < endIndex; i++) {
     trie = trie.put(trie.size(), get(i));
   }
   return trie.isEmpty() ? empty() : new Vector<>(trie);
 }
Beispiel #3
0
 @Override
 public <T1, T2> Tuple2<Vector<T1>, Vector<T2>> unzip(
     Function<? super T, Tuple2<? extends T1, ? extends T2>> unzipper) {
   Objects.requireNonNull(unzipper, "unzipper is null");
   HashArrayMappedTrie<Integer, T1> xs = HashArrayMappedTrie.empty();
   HashArrayMappedTrie<Integer, T2> ys = HashArrayMappedTrie.empty();
   for (T element : this) {
     final Tuple2<? extends T1, ? extends T2> t = unzipper.apply(element);
     xs = xs.put(xs.size(), t._1);
     ys = ys.put(ys.size(), t._2);
   }
   return Tuple.of(
       xs.isEmpty() ? empty() : new Vector<>(xs), ys.isEmpty() ? empty() : new Vector<>(ys));
 }
Beispiel #4
0
 @Override
 public Vector<Tuple2<T, Integer>> zipWithIndex() {
   HashArrayMappedTrie<Integer, Tuple2<T, Integer>> trie = HashArrayMappedTrie.empty();
   for (int i = 0; i < length(); i++) {
     trie = trie.put(i, Tuple.of(get(i), i));
   }
   return trie.isEmpty() ? empty() : new Vector<>(trie);
 }
Beispiel #5
0
 @Override
 public Vector<T> reverse() {
   HashArrayMappedTrie<Integer, T> trie = HashArrayMappedTrie.empty();
   for (int i = 0; i < length(); i++) {
     trie = trie.put(i, get(length() - 1 - i));
   }
   return trie.isEmpty() ? empty() : new Vector<>(trie);
 }
Beispiel #6
0
 /**
  * Creates a Vector of the given elements.
  *
  * @param <T> Component type of the Vector.
  * @param elements Zero or more elements.
  * @return A vector containing the given elements in the same order.
  * @throws NullPointerException if {@code elements} is null
  */
 @SafeVarargs
 public static <T> Vector<T> of(T... elements) {
   Objects.requireNonNull(elements, "elements is null");
   HashArrayMappedTrie<Integer, T> result = HashArrayMappedTrie.empty();
   for (T element : elements) {
     result = result.put(result.size(), element);
   }
   return elements.length == 0 ? empty() : new Vector<>(result);
 }
Beispiel #7
0
 @Override
 public Vector<T> replaceAll(UnaryOperator<T> operator) {
   Objects.requireNonNull(operator, "operator is null");
   HashArrayMappedTrie<Integer, T> trie = HashArrayMappedTrie.empty();
   for (int i = 0; i < length(); i++) {
     trie = trie.put(trie.size(), operator.apply(get(i)));
   }
   return trie.isEmpty() ? empty() : new Vector<>(trie);
 }
Beispiel #8
0
 @Override
 public <U> Vector<U> map(Function<? super T, ? extends U> mapper) {
   Objects.requireNonNull(mapper, "mapper is null");
   HashArrayMappedTrie<Integer, U> trie = HashArrayMappedTrie.empty();
   for (int i = 0; i < length(); i++) {
     trie = trie.put(i, mapper.apply(get(i)));
   }
   return trie.isEmpty() ? empty() : new Vector<>(trie);
 }
Beispiel #9
0
 @Override
 public Vector<T> removeAll(java.lang.Iterable<? extends T> elements) {
   Objects.requireNonNull(elements, "elements is null");
   HashArrayMappedTrie<T, T> removed = HashArrayMappedTrie.empty();
   for (T element : elements) {
     removed = removed.put(element, element);
   }
   HashArrayMappedTrie<Integer, T> result = HashArrayMappedTrie.empty();
   boolean found = false;
   for (int i = 0; i < length(); i++) {
     T element = get(i);
     if (removed.get(element).isDefined()) {
       found = true;
     } else {
       result = result.put(result.size(), element);
     }
   }
   return found ? (result.isEmpty() ? empty() : new Vector<>(result)) : this;
 }
Beispiel #10
0
 @Override
 public <U> Vector<Tuple2<T, U>> zip(java.lang.Iterable<U> that) {
   Objects.requireNonNull(that, "that is null");
   HashArrayMappedTrie<Integer, Tuple2<T, U>> result = HashArrayMappedTrie.empty();
   Iterator<T> list1 = iterator();
   java.util.Iterator<U> list2 = that.iterator();
   while (list1.hasNext() && list2.hasNext()) {
     result = result.put(result.size(), Tuple.of(list1.next(), list2.next()));
   }
   return result.isEmpty() ? empty() : new Vector<>(result);
 }
Beispiel #11
0
 @Override
 public Option<Vector<T>> tailOption() {
   if (isEmpty()) {
     return None.instance();
   }
   HashArrayMappedTrie<Integer, T> trie = HashArrayMappedTrie.empty();
   for (int i = 1; i < length(); i++) {
     trie = trie.put(i - 1, get(i));
   }
   return new Some<>(trie.isEmpty() ? empty() : new Vector<>(trie));
 }
Beispiel #12
0
 @Override
 public Vector<T> intersperse(T element) {
   HashArrayMappedTrie<Integer, T> trie = HashArrayMappedTrie.empty();
   for (int i = 0; i < length(); i++) {
     if (i > 0) {
       trie = trie.put(trie.size(), element);
     }
     trie = trie.put(trie.size(), get(i));
   }
   return trie.isEmpty() ? empty() : new Vector<>(trie);
 }
Beispiel #13
0
 @Override
 public Vector<T> tail() {
   if (isEmpty()) {
     throw new UnsupportedOperationException("tail of empty vector");
   }
   HashArrayMappedTrie<Integer, T> trie = HashArrayMappedTrie.empty();
   for (int i = 1; i < length(); i++) {
     trie = trie.put(i - 1, get(i));
   }
   return trie.isEmpty() ? empty() : new Vector<>(trie);
 }
Beispiel #14
0
 @Override
 public Vector<T> removeLast(Predicate<T> predicate) {
   Objects.requireNonNull(predicate, "predicate is null");
   HashArrayMappedTrie<Integer, T> trie = HashArrayMappedTrie.empty();
   for (int i = length() - 1; i >= 0; i--) {
     if (predicate.test(get(i))) {
       return removeAt(i);
     }
   }
   return this;
 }
Beispiel #15
0
 @Override
 public Vector<T> removeAll(T element) {
   HashArrayMappedTrie<Integer, T> result = HashArrayMappedTrie.empty();
   for (int i = 0; i < length(); i++) {
     final T value = get(i);
     if (!element.equals(value)) {
       result = result.put(result.size(), value);
     }
   }
   return result.size() == length() ? this : (result.isEmpty() ? empty() : new Vector<>(result));
 }
Beispiel #16
0
 @Override
 public <U> Vector<Tuple2<T, U>> zipAll(java.lang.Iterable<U> that, T thisElem, U thatElem) {
   Objects.requireNonNull(that, "that is null");
   HashArrayMappedTrie<Integer, Tuple2<T, U>> result = HashArrayMappedTrie.empty();
   Iterator<T> list1 = iterator();
   java.util.Iterator<U> list2 = that.iterator();
   while (list1.hasNext() || list2.hasNext()) {
     final T elem1 = list1.hasNext() ? list1.next() : thisElem;
     final U elem2 = list2.hasNext() ? list2.next() : thatElem;
     result = result.put(result.size(), Tuple.of(elem1, elem2));
   }
   return result.isEmpty() ? empty() : new Vector<>(result);
 }
Beispiel #17
0
 @Override
 public Vector<T> takeWhile(Predicate<? super T> predicate) {
   Objects.requireNonNull(predicate, "predicate is null");
   HashArrayMappedTrie<Integer, T> trie = HashArrayMappedTrie.empty();
   for (int i = 0; i < length(); i++) {
     T value = get(i);
     if (!predicate.test(value)) {
       break;
     }
     trie = trie.put(i, get(i));
   }
   return trie.size() == length() ? this : trie.isEmpty() ? empty() : new Vector<>(trie);
 }
Beispiel #18
0
 /**
  * Creates a Vector of the given elements.
  *
  * <p>The resulting vector has the same iteration order as the given iterable of elements if the
  * iteration order of the elements is stable.
  *
  * @param <T> Component type of the Vector.
  * @param elements An java.lang.Iterable of elements.
  * @return A vector containing the given elements in the same order.
  * @throws NullPointerException if {@code elements} is null
  */
 @SuppressWarnings("unchecked")
 public static <T> Vector<T> ofAll(java.lang.Iterable<? extends T> elements) {
   Objects.requireNonNull(elements, "elements is null");
   if (elements instanceof Vector) {
     return (Vector<T>) elements;
   } else {
     HashArrayMappedTrie<Integer, T> trie = HashArrayMappedTrie.empty();
     for (T element : elements) {
       trie = trie.put(trie.size(), element);
     }
     return new Vector<>(trie);
   }
 }
Beispiel #19
0
 @Override
 public Vector<T> drop(int n) {
   if (n <= 0) {
     return this;
   }
   if (n >= length()) {
     return empty();
   }
   HashArrayMappedTrie<Integer, T> trie = HashArrayMappedTrie.empty();
   for (int i = n; i < length(); i++) {
     trie = trie.put(i - n, get(i));
   }
   return trie.isEmpty() ? empty() : new Vector<>(trie);
 }
Beispiel #20
0
 @Override
 public Vector<T> dropRight(int n) {
   if (n <= 0) {
     return this;
   }
   if (n >= length()) {
     return empty();
   }
   HashArrayMappedTrie<Integer, T> trie = HashArrayMappedTrie.empty();
   for (int i = 0; i < length() - n; i++) {
     trie = trie.put(trie.size(), get(i));
   }
   return new Vector<>(trie);
 }
Beispiel #21
0
 @Override
 public Vector<T> replaceAll(T currentElement, T newElement) {
   HashArrayMappedTrie<Integer, T> trie = HashArrayMappedTrie.empty();
   boolean changed = false;
   for (int i = 0; i < length(); i++) {
     final T value = get(i);
     if (currentElement.equals(value)) {
       trie = trie.put(trie.size(), newElement);
       changed = true;
     } else {
       trie = trie.put(trie.size(), value);
     }
   }
   return changed ? (trie.isEmpty() ? empty() : new Vector<>(trie)) : this;
 }
Beispiel #22
0
 @Override
 public Vector<T> filter(Predicate<? super T> predicate) {
   Objects.requireNonNull(predicate, "predicate is null");
   HashArrayMappedTrie<Integer, T> trie = HashArrayMappedTrie.empty();
   for (T t : this) {
     if (predicate.test(t)) {
       trie = trie.put(trie.size(), t);
     }
   }
   if (trie.size() == length()) {
     return this;
   } else {
     return trie.isEmpty() ? empty() : new Vector<>(trie);
   }
 }
Beispiel #23
0
 @Override
 public <U> Vector<U> flatMap(
     Function<? super T, ? extends java.lang.Iterable<? extends U>> mapper) {
   Objects.requireNonNull(mapper, "mapper is null");
   if (isEmpty()) {
     return empty();
   } else {
     HashArrayMappedTrie<Integer, U> trie = HashArrayMappedTrie.empty();
     for (int i = 0; i < length(); i++) {
       for (U u : mapper.apply(get(i))) {
         trie = trie.put(trie.size(), u);
       }
     }
     return trie.isEmpty() ? empty() : new Vector<>(trie);
   }
 }
Beispiel #24
0
 @Override
 public Tuple2<Vector<T>, Vector<T>> splitAtInclusive(Predicate<? super T> predicate) {
   Objects.requireNonNull(predicate, "predicate is null");
   HashArrayMappedTrie<Integer, T> init = HashArrayMappedTrie.empty();
   for (T t : this) {
     init = init.put(init.size(), t);
     if (predicate.test(t)) {
       if (init.size() == length()) {
         Tuple.of(this, empty());
       } else {
         return Tuple.of(new Vector<>(init), drop(init.size()));
       }
     }
   }
   return Tuple.of(this, empty());
 }
Beispiel #25
0
 @Override
 public Vector<T> removeAt(int indx) {
   if (indx < 0) {
     throw new IndexOutOfBoundsException("removeAt(" + indx + ")");
   }
   if (indx >= length()) {
     throw new IndexOutOfBoundsException("removeAt(" + indx + ")");
   }
   HashArrayMappedTrie<Integer, T> trie = HashArrayMappedTrie.empty();
   for (int i = 0; i < length(); i++) {
     if (i != indx) {
       trie = trie.put(trie.size(), get(i));
     }
   }
   return trie.isEmpty() ? empty() : new Vector<>(trie);
 }
Beispiel #26
0
 @Override
 public Vector<T> remove(T element) {
   HashArrayMappedTrie<Integer, T> trie = HashArrayMappedTrie.empty();
   boolean found = false;
   for (int i = 0; i < length(); i++) {
     final T value = get(i);
     if (found) {
       trie = trie.put(trie.size(), value);
     } else {
       if (element.equals(value)) {
         found = true;
       } else {
         trie = trie.put(trie.size(), value);
       }
     }
   }
   return trie.size() == length() ? this : trie.isEmpty() ? empty() : new Vector<>(trie);
 }
Beispiel #27
0
 @Override
 public Vector<T> removeFirst(Predicate<T> predicate) {
   Objects.requireNonNull(predicate, "predicate is null");
   HashArrayMappedTrie<Integer, T> trie = HashArrayMappedTrie.empty();
   boolean found = false;
   for (int i = 0; i < length(); i++) {
     final T value = get(i);
     if (found) {
       trie = trie.put(trie.size(), value);
     } else {
       if (predicate.test(value)) {
         found = true;
       } else {
         trie = trie.put(trie.size(), value);
       }
     }
   }
   return trie.size() == length() ? this : trie.isEmpty() ? empty() : new Vector<>(trie);
 }
Beispiel #28
0
 @Override
 public Vector<T> insert(int index, T element) {
   if (index < 0) {
     throw new IndexOutOfBoundsException("insert(" + index + ", e)");
   }
   if (index > length()) {
     throw new IndexOutOfBoundsException(
         "insert(" + index + ", e) on Vector of length " + length());
   }
   HashArrayMappedTrie<Integer, T> trie = HashArrayMappedTrie.empty();
   for (int i = 0; i <= length(); i++) {
     if (i == index) {
       trie = trie.put(trie.size(), element);
     }
     if (i < length()) {
       trie = trie.put(trie.size(), get(i));
     }
   }
   return new Vector<>(trie);
 }
Beispiel #29
0
 /**
  * Returns a singleton {@code Vector}, i.e. a {@code Vector} of one element.
  *
  * @param element An element.
  * @param <T> The component type
  * @return A new Vector instance containing the given element
  */
 public static <T> Vector<T> of(T element) {
   return new Vector<>(HashArrayMappedTrie.<Integer, T>empty().put(0, element));
 }
Beispiel #30
0
/**
 * TODO javadoc
 *
 * @param <T> Component type of the Vector.
 */
public final class Vector<T> implements IndexedSeq<T>, Serializable {

  private static final long serialVersionUID = 1L;

  private static final Vector<?> EMPTY = new Vector<>(HashArrayMappedTrie.empty());

  private final HashArrayMappedTrie<Integer, T> trie;
  private final transient Lazy<Integer> hashCode = Lazy.of(() -> Traversable.hash(this));

  private Vector(HashArrayMappedTrie<Integer, T> trie) {
    this.trie = trie;
  }

  /**
   * Returns the empty Vector.
   *
   * @param <T> Component type.
   * @return The empty Vector.
   */
  @SuppressWarnings("unchecked")
  public static <T> Vector<T> empty() {
    return (Vector<T>) EMPTY;
  }

  /**
   * Returns a {@link java.util.stream.Collector} which may be used in conjunction with {@link
   * java.util.stream.Stream#collect(java.util.stream.Collector)} to obtain a {@link
   * javaslang.collection.Vector}s.
   *
   * @param <T> Component type of the Vector.
   * @return A javaslang.collection.List Collector.
   */
  public static <T> Collector<T, ArrayList<T>, Vector<T>> collector() {
    final Supplier<ArrayList<T>> supplier = ArrayList::new;
    final BiConsumer<ArrayList<T>, T> accumulator = ArrayList::add;
    final BinaryOperator<ArrayList<T>> combiner =
        (left, right) -> {
          left.addAll(right);
          return left;
        };
    final Function<ArrayList<T>, Vector<T>> finisher = Vector::ofAll;
    return Collector.of(supplier, accumulator, combiner, finisher);
  }

  /**
   * Returns a singleton {@code Vector}, i.e. a {@code Vector} of one element.
   *
   * @param element An element.
   * @param <T> The component type
   * @return A new Vector instance containing the given element
   */
  public static <T> Vector<T> of(T element) {
    return new Vector<>(HashArrayMappedTrie.<Integer, T>empty().put(0, element));
  }

  /**
   * Creates a Vector of the given elements.
   *
   * @param <T> Component type of the Vector.
   * @param elements Zero or more elements.
   * @return A vector containing the given elements in the same order.
   * @throws NullPointerException if {@code elements} is null
   */
  @SafeVarargs
  public static <T> Vector<T> of(T... elements) {
    Objects.requireNonNull(elements, "elements is null");
    HashArrayMappedTrie<Integer, T> result = HashArrayMappedTrie.empty();
    for (T element : elements) {
      result = result.put(result.size(), element);
    }
    return elements.length == 0 ? empty() : new Vector<>(result);
  }

  /**
   * Creates a Vector of the given elements.
   *
   * <p>The resulting vector has the same iteration order as the given iterable of elements if the
   * iteration order of the elements is stable.
   *
   * @param <T> Component type of the Vector.
   * @param elements An java.lang.Iterable of elements.
   * @return A vector containing the given elements in the same order.
   * @throws NullPointerException if {@code elements} is null
   */
  @SuppressWarnings("unchecked")
  public static <T> Vector<T> ofAll(java.lang.Iterable<? extends T> elements) {
    Objects.requireNonNull(elements, "elements is null");
    if (elements instanceof Vector) {
      return (Vector<T>) elements;
    } else {
      HashArrayMappedTrie<Integer, T> trie = HashArrayMappedTrie.empty();
      for (T element : elements) {
        trie = trie.put(trie.size(), element);
      }
      return new Vector<>(trie);
    }
  }

  /**
   * Creates a Vector based on the elements of a boolean array.
   *
   * @param array a boolean array
   * @return A new Vector of Boolean values
   */
  public static Vector<Boolean> ofAll(boolean[] array) {
    Objects.requireNonNull(array, "array is null");
    return Vector.ofAll(Iterator.ofAll(array));
  }

  /**
   * Creates a Vector based on the elements of a byte array.
   *
   * @param array a byte array
   * @return A new Vector of Byte values
   */
  public static Vector<Byte> ofAll(byte[] array) {
    Objects.requireNonNull(array, "array is null");
    return Vector.ofAll(Iterator.ofAll(array));
  }

  /**
   * Creates a Vector based on the elements of a char array.
   *
   * @param array a char array
   * @return A new Vector of Character values
   */
  public static Vector<Character> ofAll(char[] array) {
    Objects.requireNonNull(array, "array is null");
    return Vector.ofAll(Iterator.ofAll(array));
  }

  /**
   * Creates a Vector based on the elements of a double array.
   *
   * @param array a double array
   * @return A new Vector of Double values
   */
  public static Vector<Double> ofAll(double[] array) {
    Objects.requireNonNull(array, "array is null");
    return Vector.ofAll(Iterator.ofAll(array));
  }

  /**
   * Creates a Vector based on the elements of a float array.
   *
   * @param array a float array
   * @return A new Vector of Float values
   */
  public static Vector<Float> ofAll(float[] array) {
    Objects.requireNonNull(array, "array is null");
    return Vector.ofAll(Iterator.ofAll(array));
  }

  /**
   * Creates a Vector based on the elements of an int array.
   *
   * @param array an int array
   * @return A new Vector of Integer values
   */
  public static Vector<Integer> ofAll(int[] array) {
    Objects.requireNonNull(array, "array is null");
    return Vector.ofAll(Iterator.ofAll(array));
  }

  /**
   * Creates a Vector based on the elements of a long array.
   *
   * @param array a long array
   * @return A new Vector of Long values
   */
  public static Vector<Long> ofAll(long[] array) {
    Objects.requireNonNull(array, "array is null");
    return Vector.ofAll(Iterator.ofAll(array));
  }

  /**
   * Creates a Vector based on the elements of a short array.
   *
   * @param array a short array
   * @return A new Vector of Short values
   */
  public static Vector<Short> ofAll(short[] array) {
    Objects.requireNonNull(array, "array is null");
    return Vector.ofAll(Iterator.ofAll(array));
  }

  /**
   * Creates a Vector of int numbers starting from {@code from}, extending to {@code toExclusive -
   * 1}.
   *
   * <p>Examples:
   *
   * <pre>
   * <code>
   * Vector.range(0, 0)  // = Vector()
   * Vector.range(2, 0)  // = Vector()
   * Vector.range(-2, 2) // = Vector(-2, -1, 0, 1)
   * </code>
   * </pre>
   *
   * @param from the first number
   * @param toExclusive the last number + 1
   * @return a range of int values as specified or the empty range if {@code from >= toExclusive}
   */
  public static Vector<Integer> range(int from, int toExclusive) {
    return Vector.ofAll(Iterator.range(from, toExclusive));
  }

  /**
   * Creates a Vector of int numbers starting from {@code from}, extending to {@code toExclusive -
   * 1}, with {@code step}.
   *
   * <p>Examples:
   *
   * <pre>
   * <code>
   * Vector.rangeBy(1, 3, 1)  // = Vector(1, 2)
   * Vector.rangeBy(1, 4, 2)  // = Vector(1, 3)
   * Vector.rangeBy(4, 1, -2) // = Vector(4, 2)
   * Vector.rangeBy(4, 1, 2)  // = Vector()
   * </code>
   * </pre>
   *
   * @param from the first number
   * @param toExclusive the last number + 1
   * @param step the step
   * @return a range of long values as specified or the empty range if<br>
   *     {@code from >= toInclusive} and {@code step > 0} or<br>
   *     {@code from <= toInclusive} and {@code step < 0}
   * @throws IllegalArgumentException if {@code step} is zero
   */
  public static Vector<Integer> rangeBy(int from, int toExclusive, int step) {
    return Vector.ofAll(Iterator.rangeBy(from, toExclusive, step));
  }

  /**
   * Creates a Vector of long numbers starting from {@code from}, extending to {@code toExclusive -
   * 1}.
   *
   * <p>Examples:
   *
   * <pre>
   * <code>
   * Vector.range(0L, 0L)  // = Vector()
   * Vector.range(2L, 0L)  // = Vector()
   * Vector.range(-2L, 2L) // = Vector(-2L, -1L, 0L, 1L)
   * </code>
   * </pre>
   *
   * @param from the first number
   * @param toExclusive the last number + 1
   * @return a range of long values as specified or the empty range if {@code from >= toExclusive}
   */
  public static Vector<Long> range(long from, long toExclusive) {
    return Vector.ofAll(Iterator.range(from, toExclusive));
  }

  /**
   * Creates a Vector of long numbers starting from {@code from}, extending to {@code toExclusive -
   * 1}, with {@code step}.
   *
   * <p>Examples:
   *
   * <pre>
   * <code>
   * Vector.rangeBy(1L, 3L, 1L)  // = Vector(1L, 2L)
   * Vector.rangeBy(1L, 4L, 2L)  // = Vector(1L, 3L)
   * Vector.rangeBy(4L, 1L, -2L) // = Vector(4L, 2L)
   * Vector.rangeBy(4L, 1L, 2L)  // = Vector()
   * </code>
   * </pre>
   *
   * @param from the first number
   * @param toExclusive the last number + 1
   * @param step the step
   * @return a range of long values as specified or the empty range if<br>
   *     {@code from >= toInclusive} and {@code step > 0} or<br>
   *     {@code from <= toInclusive} and {@code step < 0}
   * @throws IllegalArgumentException if {@code step} is zero
   */
  public static Vector<Long> rangeBy(long from, long toExclusive, long step) {
    return Vector.ofAll(Iterator.rangeBy(from, toExclusive, step));
  }

  /**
   * Creates a Vector of int numbers starting from {@code from}, extending to {@code toInclusive}.
   *
   * <p>Examples:
   *
   * <pre>
   * <code>
   * Vector.rangeClosed(0, 0)  // = Vector(0)
   * Vector.rangeClosed(2, 0)  // = Vector()
   * Vector.rangeClosed(-2, 2) // = Vector(-2, -1, 0, 1, 2)
   * </code>
   * </pre>
   *
   * @param from the first number
   * @param toInclusive the last number
   * @return a range of int values as specified or the empty range if {@code from > toInclusive}
   */
  public static Vector<Integer> rangeClosed(int from, int toInclusive) {
    return Vector.ofAll(Iterator.rangeClosed(from, toInclusive));
  }

  /**
   * Creates a Vector of int numbers starting from {@code from}, extending to {@code toInclusive},
   * with {@code step}.
   *
   * <p>Examples:
   *
   * <pre>
   * <code>
   * Vector.rangeClosedBy(1, 3, 1)  // = Vector(1, 2, 3)
   * Vector.rangeClosedBy(1, 4, 2)  // = Vector(1, 3)
   * Vector.rangeClosedBy(4, 1, -2) // = Vector(4, 2)
   * Vector.rangeClosedBy(4, 1, 2)  // = Vector()
   * </code>
   * </pre>
   *
   * @param from the first number
   * @param toInclusive the last number
   * @param step the step
   * @return a range of int values as specified or the empty range if<br>
   *     {@code from > toInclusive} and {@code step > 0} or<br>
   *     {@code from < toInclusive} and {@code step < 0}
   * @throws IllegalArgumentException if {@code step} is zero
   */
  public static Vector<Integer> rangeClosedBy(int from, int toInclusive, int step) {
    return Vector.ofAll(Iterator.rangeClosedBy(from, toInclusive, step));
  }

  /**
   * Creates a Vector of long numbers starting from {@code from}, extending to {@code toInclusive}.
   *
   * <p>Examples:
   *
   * <pre>
   * <code>
   * Vector.rangeClosed(0L, 0L)  // = Vector(0L)
   * Vector.rangeClosed(2L, 0L)  // = Vector()
   * Vector.rangeClosed(-2L, 2L) // = Vector(-2L, -1L, 0L, 1L, 2L)
   * </code>
   * </pre>
   *
   * @param from the first number
   * @param toInclusive the last number
   * @return a range of long values as specified or the empty range if {@code from > toInclusive}
   */
  public static Vector<Long> rangeClosed(long from, long toInclusive) {
    return Vector.ofAll(Iterator.rangeClosed(from, toInclusive));
  }

  /**
   * Creates a Vector of long numbers starting from {@code from}, extending to {@code toInclusive},
   * with {@code step}.
   *
   * <p>Examples:
   *
   * <pre>
   * <code>
   * Vector.rangeClosedBy(1L, 3L, 1L)  // = Vector(1L, 2L, 3L)
   * Vector.rangeClosedBy(1L, 4L, 2L)  // = Vector(1L, 3L)
   * Vector.rangeClosedBy(4L, 1L, -2L) // = Vector(4L, 2L)
   * Vector.rangeClosedBy(4L, 1L, 2L)  // = Vector()
   * </code>
   * </pre>
   *
   * @param from the first number
   * @param toInclusive the last number
   * @param step the step
   * @return a range of int values as specified or the empty range if<br>
   *     {@code from > toInclusive} and {@code step > 0} or<br>
   *     {@code from < toInclusive} and {@code step < 0}
   * @throws IllegalArgumentException if {@code step} is zero
   */
  public static Vector<Long> rangeClosedBy(long from, long toInclusive, long step) {
    return Vector.ofAll(Iterator.rangeClosedBy(from, toInclusive, step));
  }

  @Override
  public Vector<T> append(T element) {
    return new Vector<>(trie.put(trie.size(), element));
  }

  @Override
  public Vector<T> appendAll(java.lang.Iterable<? extends T> elements) {
    HashArrayMappedTrie<Integer, T> result = trie;
    for (T element : elements) {
      result = result.put(result.size(), element);
    }
    return new Vector<>(result);
  }

  @Override
  public Vector<T> clear() {
    return Vector.empty();
  }

  @Override
  public Vector<Tuple2<T, T>> crossProduct() {
    return crossProduct(this);
  }

  @Override
  public <U> Vector<Tuple2<T, U>> crossProduct(java.lang.Iterable<? extends U> that) {
    Objects.requireNonNull(that, "that is null");
    final Vector<? extends U> other = Vector.ofAll(that);
    return flatMap(a -> other.map(b -> Tuple.of(a, b)));
  }

  @Override
  public Vector<Vector<T>> combinations() {
    return Vector.rangeClosed(0, length()).map(this::combinations).flatMap(Function.identity());
  }

  @Override
  public Vector<Vector<T>> combinations(int k) {
    class Recursion {
      Vector<Vector<T>> combinations(Vector<T> elements, int k) {
        return (k == 0)
            ? Vector.of(Vector.empty())
            : elements
                .zipWithIndex()
                .flatMap(
                    t ->
                        combinations(elements.drop(t._2 + 1), (k - 1))
                            .map((Vector<T> c) -> c.prepend(t._1)));
      }
    }
    return new Recursion().combinations(this, Math.max(k, 0));
  }

  @Override
  public Vector<T> distinct() {
    return distinctBy(Function.identity());
  }

  @Override
  public Vector<T> distinctBy(Comparator<? super T> comparator) {
    Objects.requireNonNull(comparator, "comparator is null");
    final java.util.Set<T> seen = new java.util.TreeSet<>(comparator);
    return filter(seen::add);
  }

  @Override
  public <U> Vector<T> distinctBy(Function<? super T, ? extends U> keyExtractor) {
    Objects.requireNonNull(keyExtractor, "keyExtractor is null");
    final java.util.Set<U> seen = new java.util.HashSet<>();
    return filter(t -> seen.add(keyExtractor.apply(t)));
  }

  @Override
  public Vector<T> drop(int n) {
    if (n <= 0) {
      return this;
    }
    if (n >= length()) {
      return empty();
    }
    HashArrayMappedTrie<Integer, T> trie = HashArrayMappedTrie.empty();
    for (int i = n; i < length(); i++) {
      trie = trie.put(i - n, get(i));
    }
    return trie.isEmpty() ? empty() : new Vector<>(trie);
  }

  @Override
  public Vector<T> dropRight(int n) {
    if (n <= 0) {
      return this;
    }
    if (n >= length()) {
      return empty();
    }
    HashArrayMappedTrie<Integer, T> trie = HashArrayMappedTrie.empty();
    for (int i = 0; i < length() - n; i++) {
      trie = trie.put(trie.size(), get(i));
    }
    return new Vector<>(trie);
  }

  @Override
  public Vector<T> dropWhile(Predicate<? super T> predicate) {
    Objects.requireNonNull(predicate, "predicate is null");
    for (int i = 0; i < length(); i++) {
      if (!predicate.test(get(i))) {
        return drop(i);
      }
    }
    return empty();
  }

  @Override
  public Vector<T> filter(Predicate<? super T> predicate) {
    Objects.requireNonNull(predicate, "predicate is null");
    HashArrayMappedTrie<Integer, T> trie = HashArrayMappedTrie.empty();
    for (T t : this) {
      if (predicate.test(t)) {
        trie = trie.put(trie.size(), t);
      }
    }
    if (trie.size() == length()) {
      return this;
    } else {
      return trie.isEmpty() ? empty() : new Vector<>(trie);
    }
  }

  @Override
  public <U> Vector<U> flatMap(
      Function<? super T, ? extends java.lang.Iterable<? extends U>> mapper) {
    Objects.requireNonNull(mapper, "mapper is null");
    if (isEmpty()) {
      return empty();
    } else {
      HashArrayMappedTrie<Integer, U> trie = HashArrayMappedTrie.empty();
      for (int i = 0; i < length(); i++) {
        for (U u : mapper.apply(get(i))) {
          trie = trie.put(trie.size(), u);
        }
      }
      return trie.isEmpty() ? empty() : new Vector<>(trie);
    }
  }

  @Override
  public Vector<Object> flatten() {
    return flatMap(
        t ->
            (t instanceof java.lang.Iterable)
                ? Vector.ofAll((java.lang.Iterable<?>) t).flatten()
                : Vector.of(t));
  }

  @Override
  public T get(int index) {
    if (index < 0 || index >= length()) {
      throw new IndexOutOfBoundsException("get(" + index + ")");
    }
    return trie.get(index).get();
  }

  @Override
  public T head() {
    if (isEmpty()) {
      throw new NoSuchElementException("head of empty vector");
    } else {
      return get(0);
    }
  }

  @Override
  public Option<T> headOption() {
    if (isEmpty()) {
      return None.instance();
    } else {
      return new Some<>(get(0));
    }
  }

  @Override
  public <C> Map<C, Vector<T>> groupBy(Function<? super T, ? extends C> classifier) {
    Objects.requireNonNull(classifier, "classifier is null");
    return iterator().groupBy(classifier).map((c, it) -> Map.Entry.of(c, Vector.ofAll(it)));
  }

  @Override
  public boolean hasDefiniteSize() {
    return true;
  }

  @Override
  public int indexOf(T element, int from) {
    for (int i = from; i < length(); i++) {
      if (Objects.equals(get(i), element)) {
        return i;
      }
    }
    return -1;
  }

  @Override
  public Vector<T> init() {
    if (isEmpty()) {
      throw new UnsupportedOperationException("init of empty vector");
    }
    return new Vector<>(trie.remove(length() - 1));
  }

  @Override
  public Option<? extends Vector<T>> initOption() {
    if (isEmpty()) {
      return None.instance();
    } else {
      return new Some<>(init());
    }
  }

  @Override
  public Vector<T> insert(int index, T element) {
    if (index < 0) {
      throw new IndexOutOfBoundsException("insert(" + index + ", e)");
    }
    if (index > length()) {
      throw new IndexOutOfBoundsException(
          "insert(" + index + ", e) on Vector of length " + length());
    }
    HashArrayMappedTrie<Integer, T> trie = HashArrayMappedTrie.empty();
    for (int i = 0; i <= length(); i++) {
      if (i == index) {
        trie = trie.put(trie.size(), element);
      }
      if (i < length()) {
        trie = trie.put(trie.size(), get(i));
      }
    }
    return new Vector<>(trie);
  }

  @Override
  public Vector<T> insertAll(int index, java.lang.Iterable<? extends T> elements) {
    if (index < 0) {
      throw new IndexOutOfBoundsException("insert(" + index + ", e)");
    }
    if (index > length()) {
      throw new IndexOutOfBoundsException(
          "insert(" + index + ", e) on Vector of length " + length());
    }
    HashArrayMappedTrie<Integer, T> trie = HashArrayMappedTrie.empty();
    for (int i = 0; i <= length(); i++) {
      if (i == index) {
        for (T element : elements) {
          trie = trie.put(trie.size(), element);
        }
      }
      if (i < length()) {
        trie = trie.put(trie.size(), get(i));
      }
    }
    return new Vector<>(trie);
  }

  @Override
  public Vector<T> intersperse(T element) {
    HashArrayMappedTrie<Integer, T> trie = HashArrayMappedTrie.empty();
    for (int i = 0; i < length(); i++) {
      if (i > 0) {
        trie = trie.put(trie.size(), element);
      }
      trie = trie.put(trie.size(), get(i));
    }
    return trie.isEmpty() ? empty() : new Vector<>(trie);
  }

  @Override
  public boolean isEmpty() {
    return trie.isEmpty();
  }

  @Override
  public boolean isTraversableAgain() {
    return true;
  }

  @Override
  public Iterator<T> iterator() {
    return new Iterator<T>() {
      private int index = 0;

      @Override
      public boolean hasNext() {
        return index < trie.size();
      }

      @Override
      public T next() {
        return trie.get(index++).get();
      }
    };
  }

  @Override
  public int lastIndexOf(T element, int end) {
    for (int i = Math.min(end, length() - 1); i >= 0; i--) {
      if (Objects.equals(get(i), element)) {
        return i;
      }
    }
    return -1;
  }

  @Override
  public int length() {
    return trie.size();
  }

  @Override
  public <U> Vector<U> map(Function<? super T, ? extends U> mapper) {
    Objects.requireNonNull(mapper, "mapper is null");
    HashArrayMappedTrie<Integer, U> trie = HashArrayMappedTrie.empty();
    for (int i = 0; i < length(); i++) {
      trie = trie.put(i, mapper.apply(get(i)));
    }
    return trie.isEmpty() ? empty() : new Vector<>(trie);
  }

  @Override
  public Vector<T> padTo(int length, T element) {
    if (length <= length()) {
      return this;
    } else {
      return appendAll(Iterator.constant(element).take(length - length()));
    }
  }

  @Override
  public Vector<T> patch(int from, java.lang.Iterable<? extends T> that, int replaced) {
    from = from < 0 ? 0 : from;
    replaced = replaced < 0 ? 0 : replaced;
    Vector<T> result = take(from).appendAll(that);
    from += replaced;
    result = result.appendAll(drop(from));
    return result;
  }

  @Override
  public Tuple2<Vector<T>, Vector<T>> partition(Predicate<? super T> predicate) {
    Objects.requireNonNull(predicate, "predicate is null");
    final java.util.List<T> left = new ArrayList<>(), right = new ArrayList<>();
    for (int i = 0; i < length(); i++) {
      T t = get(i);
      (predicate.test(t) ? left : right).add(t);
    }
    return Tuple.of(Vector.ofAll(left), Vector.ofAll(right));
  }

  @Override
  public Vector<T> peek(Consumer<? super T> action) {
    Objects.requireNonNull(action, "action is null");
    if (!isEmpty()) {
      action.accept(head());
    }
    return this;
  }

  @Override
  public Vector<Vector<T>> permutations() {
    if (isEmpty()) {
      return Vector.empty();
    } else {
      final Vector<T> tail = tail();
      if (tail.isEmpty()) {
        return Vector.of(this);
      } else {
        final Vector<Vector<T>> zero = empty();
        // TODO: IntelliJ IDEA 14.1.1 needs a redundant cast here, jdk 1.8.0_40 compiles fine
        return distinct()
            .foldLeft(
                zero,
                (xs, x) ->
                    xs.appendAll(
                        remove(x)
                            .permutations()
                            .map((Function<Vector<T>, Vector<T>>) l -> l.prepend(x))));
      }
    }
  }

  @Override
  public Vector<T> prepend(T element) {
    return insert(0, element);
  }

  @Override
  public Vector<T> prependAll(java.lang.Iterable<? extends T> elements) {
    return insertAll(0, elements);
  }

  @Override
  public Vector<T> remove(T element) {
    HashArrayMappedTrie<Integer, T> trie = HashArrayMappedTrie.empty();
    boolean found = false;
    for (int i = 0; i < length(); i++) {
      final T value = get(i);
      if (found) {
        trie = trie.put(trie.size(), value);
      } else {
        if (element.equals(value)) {
          found = true;
        } else {
          trie = trie.put(trie.size(), value);
        }
      }
    }
    return trie.size() == length() ? this : trie.isEmpty() ? empty() : new Vector<>(trie);
  }

  @Override
  public Vector<T> removeFirst(Predicate<T> predicate) {
    Objects.requireNonNull(predicate, "predicate is null");
    HashArrayMappedTrie<Integer, T> trie = HashArrayMappedTrie.empty();
    boolean found = false;
    for (int i = 0; i < length(); i++) {
      final T value = get(i);
      if (found) {
        trie = trie.put(trie.size(), value);
      } else {
        if (predicate.test(value)) {
          found = true;
        } else {
          trie = trie.put(trie.size(), value);
        }
      }
    }
    return trie.size() == length() ? this : trie.isEmpty() ? empty() : new Vector<>(trie);
  }

  @Override
  public Vector<T> removeLast(Predicate<T> predicate) {
    Objects.requireNonNull(predicate, "predicate is null");
    HashArrayMappedTrie<Integer, T> trie = HashArrayMappedTrie.empty();
    for (int i = length() - 1; i >= 0; i--) {
      if (predicate.test(get(i))) {
        return removeAt(i);
      }
    }
    return this;
  }

  @Override
  public Vector<T> removeAt(int indx) {
    if (indx < 0) {
      throw new IndexOutOfBoundsException("removeAt(" + indx + ")");
    }
    if (indx >= length()) {
      throw new IndexOutOfBoundsException("removeAt(" + indx + ")");
    }
    HashArrayMappedTrie<Integer, T> trie = HashArrayMappedTrie.empty();
    for (int i = 0; i < length(); i++) {
      if (i != indx) {
        trie = trie.put(trie.size(), get(i));
      }
    }
    return trie.isEmpty() ? empty() : new Vector<>(trie);
  }

  @Override
  public Vector<T> removeAll(T element) {
    HashArrayMappedTrie<Integer, T> result = HashArrayMappedTrie.empty();
    for (int i = 0; i < length(); i++) {
      final T value = get(i);
      if (!element.equals(value)) {
        result = result.put(result.size(), value);
      }
    }
    return result.size() == length() ? this : (result.isEmpty() ? empty() : new Vector<>(result));
  }

  @Override
  public Vector<T> removeAll(java.lang.Iterable<? extends T> elements) {
    Objects.requireNonNull(elements, "elements is null");
    HashArrayMappedTrie<T, T> removed = HashArrayMappedTrie.empty();
    for (T element : elements) {
      removed = removed.put(element, element);
    }
    HashArrayMappedTrie<Integer, T> result = HashArrayMappedTrie.empty();
    boolean found = false;
    for (int i = 0; i < length(); i++) {
      T element = get(i);
      if (removed.get(element).isDefined()) {
        found = true;
      } else {
        result = result.put(result.size(), element);
      }
    }
    return found ? (result.isEmpty() ? empty() : new Vector<>(result)) : this;
  }

  @Override
  public Vector<T> replace(T currentElement, T newElement) {
    HashArrayMappedTrie<Integer, T> trie = HashArrayMappedTrie.empty();
    boolean found = false;
    for (int i = 0; i < length(); i++) {
      final T value = get(i);
      if (found) {
        trie = trie.put(trie.size(), value);
      } else {
        if (currentElement.equals(value)) {
          trie = trie.put(trie.size(), newElement);
          found = true;
        } else {
          trie = trie.put(trie.size(), value);
        }
      }
    }
    return found ? new Vector<>(trie) : this;
  }

  @Override
  public Vector<T> replaceAll(T currentElement, T newElement) {
    HashArrayMappedTrie<Integer, T> trie = HashArrayMappedTrie.empty();
    boolean changed = false;
    for (int i = 0; i < length(); i++) {
      final T value = get(i);
      if (currentElement.equals(value)) {
        trie = trie.put(trie.size(), newElement);
        changed = true;
      } else {
        trie = trie.put(trie.size(), value);
      }
    }
    return changed ? (trie.isEmpty() ? empty() : new Vector<>(trie)) : this;
  }

  @Override
  public Vector<T> replaceAll(UnaryOperator<T> operator) {
    Objects.requireNonNull(operator, "operator is null");
    HashArrayMappedTrie<Integer, T> trie = HashArrayMappedTrie.empty();
    for (int i = 0; i < length(); i++) {
      trie = trie.put(trie.size(), operator.apply(get(i)));
    }
    return trie.isEmpty() ? empty() : new Vector<>(trie);
  }

  @Override
  public Vector<T> retainAll(java.lang.Iterable<? extends T> elements) {
    Objects.requireNonNull(elements, "elements is null");
    final Vector<T> keeped = Vector.ofAll(elements).distinct();
    HashArrayMappedTrie<Integer, T> result = HashArrayMappedTrie.empty();
    for (T element : this) {
      if (keeped.contains(element)) {
        result = result.put(result.size(), element);
      }
    }
    return result.isEmpty() ? empty() : new Vector<>(result);
  }

  @Override
  public Vector<T> reverse() {
    HashArrayMappedTrie<Integer, T> trie = HashArrayMappedTrie.empty();
    for (int i = 0; i < length(); i++) {
      trie = trie.put(i, get(length() - 1 - i));
    }
    return trie.isEmpty() ? empty() : new Vector<>(trie);
  }

  @Override
  public Vector<T> slice(int beginIndex) {
    if (beginIndex < 0) {
      throw new IndexOutOfBoundsException("slice(" + beginIndex + ")");
    }
    if (beginIndex > length()) {
      throw new IndexOutOfBoundsException("slice(" + beginIndex + ")");
    }
    return drop(beginIndex);
  }

  @Override
  public Vector<T> slice(int beginIndex, int endIndex) {
    if (beginIndex < 0 || beginIndex > endIndex || endIndex > length()) {
      throw new IndexOutOfBoundsException(
          String.format("slice(%s, %s) on List of length %s", beginIndex, endIndex, length()));
    }
    if (beginIndex == endIndex) {
      return Vector.empty();
    }
    HashArrayMappedTrie<Integer, T> trie = HashArrayMappedTrie.empty();
    for (int i = beginIndex; i < endIndex; i++) {
      trie = trie.put(trie.size(), get(i));
    }
    return trie.isEmpty() ? empty() : new Vector<>(trie);
  }

  @Override
  public Vector<T> sort() {
    return isEmpty() ? this : toJavaStream().sorted().collect(Vector.collector());
  }

  @Override
  public Vector<T> sort(Comparator<? super T> comparator) {
    Objects.requireNonNull(comparator, "comparator is null");
    return isEmpty() ? this : toJavaStream().sorted(comparator).collect(Vector.collector());
  }

  @Override
  public Tuple2<Vector<T>, Vector<T>> span(Predicate<? super T> predicate) {
    Objects.requireNonNull(predicate, "predicate is null");
    return Tuple.of(takeWhile(predicate), dropWhile(predicate));
  }

  @Override
  public Tuple2<Vector<T>, Vector<T>> splitAt(int n) {
    return Tuple.of(take(n), drop(n));
  }

  @Override
  public Tuple2<Vector<T>, Vector<T>> splitAt(Predicate<? super T> predicate) {
    Objects.requireNonNull(predicate, "predicate is null");
    final Vector<T> init = takeWhile(predicate.negate());
    return Tuple.of(init, drop(init.length()));
  }

  @Override
  public Tuple2<Vector<T>, Vector<T>> splitAtInclusive(Predicate<? super T> predicate) {
    Objects.requireNonNull(predicate, "predicate is null");
    HashArrayMappedTrie<Integer, T> init = HashArrayMappedTrie.empty();
    for (T t : this) {
      init = init.put(init.size(), t);
      if (predicate.test(t)) {
        if (init.size() == length()) {
          Tuple.of(this, empty());
        } else {
          return Tuple.of(new Vector<>(init), drop(init.size()));
        }
      }
    }
    return Tuple.of(this, empty());
  }

  @Override
  public Spliterator<T> spliterator() {
    return Spliterators.spliterator(
        iterator(), length(), Spliterator.ORDERED | Spliterator.IMMUTABLE);
  }

  @Override
  public Vector<T> tail() {
    if (isEmpty()) {
      throw new UnsupportedOperationException("tail of empty vector");
    }
    HashArrayMappedTrie<Integer, T> trie = HashArrayMappedTrie.empty();
    for (int i = 1; i < length(); i++) {
      trie = trie.put(i - 1, get(i));
    }
    return trie.isEmpty() ? empty() : new Vector<>(trie);
  }

  @Override
  public Option<Vector<T>> tailOption() {
    if (isEmpty()) {
      return None.instance();
    }
    HashArrayMappedTrie<Integer, T> trie = HashArrayMappedTrie.empty();
    for (int i = 1; i < length(); i++) {
      trie = trie.put(i - 1, get(i));
    }
    return new Some<>(trie.isEmpty() ? empty() : new Vector<>(trie));
  }

  @Override
  public Vector<T> take(int n) {
    if (n >= length()) {
      return this;
    }
    if (n <= 0) {
      return empty();
    }
    HashArrayMappedTrie<Integer, T> trie = HashArrayMappedTrie.empty();
    for (int i = 0; i < n; i++) {
      trie = trie.put(i, get(i));
    }
    return new Vector<>(trie);
  }

  @Override
  public Vector<T> takeRight(int n) {
    if (n >= length()) {
      return this;
    }
    if (n <= 0) {
      return empty();
    }
    HashArrayMappedTrie<Integer, T> trie = HashArrayMappedTrie.empty();
    for (int i = 0; i < n; i++) {
      trie = trie.put(i, get(length() - n + i));
    }
    return new Vector<>(trie);
  }

  @Override
  public Vector<T> takeWhile(Predicate<? super T> predicate) {
    Objects.requireNonNull(predicate, "predicate is null");
    HashArrayMappedTrie<Integer, T> trie = HashArrayMappedTrie.empty();
    for (int i = 0; i < length(); i++) {
      T value = get(i);
      if (!predicate.test(value)) {
        break;
      }
      trie = trie.put(i, get(i));
    }
    return trie.size() == length() ? this : trie.isEmpty() ? empty() : new Vector<>(trie);
  }

  @Override
  public <U> Vector<U> unit(java.lang.Iterable<? extends U> iterable) {
    return Vector.ofAll(iterable);
  }

  @Override
  public <T1, T2> Tuple2<Vector<T1>, Vector<T2>> unzip(
      Function<? super T, Tuple2<? extends T1, ? extends T2>> unzipper) {
    Objects.requireNonNull(unzipper, "unzipper is null");
    HashArrayMappedTrie<Integer, T1> xs = HashArrayMappedTrie.empty();
    HashArrayMappedTrie<Integer, T2> ys = HashArrayMappedTrie.empty();
    for (T element : this) {
      final Tuple2<? extends T1, ? extends T2> t = unzipper.apply(element);
      xs = xs.put(xs.size(), t._1);
      ys = ys.put(ys.size(), t._2);
    }
    return Tuple.of(
        xs.isEmpty() ? empty() : new Vector<>(xs), ys.isEmpty() ? empty() : new Vector<>(ys));
  }

  @Override
  public Vector<T> update(int index, T element) {
    if (index < 0) {
      throw new IndexOutOfBoundsException("update(" + index + ")");
    }
    if (index >= length()) {
      throw new IndexOutOfBoundsException("update(" + index + ")");
    }
    return new Vector<>(trie.put(index, element));
  }

  @Override
  public <U> Vector<Tuple2<T, U>> zip(java.lang.Iterable<U> that) {
    Objects.requireNonNull(that, "that is null");
    HashArrayMappedTrie<Integer, Tuple2<T, U>> result = HashArrayMappedTrie.empty();
    Iterator<T> list1 = iterator();
    java.util.Iterator<U> list2 = that.iterator();
    while (list1.hasNext() && list2.hasNext()) {
      result = result.put(result.size(), Tuple.of(list1.next(), list2.next()));
    }
    return result.isEmpty() ? empty() : new Vector<>(result);
  }

  @Override
  public <U> Vector<Tuple2<T, U>> zipAll(java.lang.Iterable<U> that, T thisElem, U thatElem) {
    Objects.requireNonNull(that, "that is null");
    HashArrayMappedTrie<Integer, Tuple2<T, U>> result = HashArrayMappedTrie.empty();
    Iterator<T> list1 = iterator();
    java.util.Iterator<U> list2 = that.iterator();
    while (list1.hasNext() || list2.hasNext()) {
      final T elem1 = list1.hasNext() ? list1.next() : thisElem;
      final U elem2 = list2.hasNext() ? list2.next() : thatElem;
      result = result.put(result.size(), Tuple.of(elem1, elem2));
    }
    return result.isEmpty() ? empty() : new Vector<>(result);
  }

  @Override
  public Vector<Tuple2<T, Integer>> zipWithIndex() {
    HashArrayMappedTrie<Integer, Tuple2<T, Integer>> trie = HashArrayMappedTrie.empty();
    for (int i = 0; i < length(); i++) {
      trie = trie.put(i, Tuple.of(get(i), i));
    }
    return trie.isEmpty() ? empty() : new Vector<>(trie);
  }

  private Object readResolve() {
    return isEmpty() ? EMPTY : this;
  }

  @Override
  public boolean equals(Object o) {
    if (o == this) {
      return true;
    } else if (o instanceof Vector) {
      Vector<?> vector1 = this;
      Vector<?> vector2 = (Vector<?>) o;
      while (!vector1.isEmpty() && !vector2.isEmpty()) {
        final boolean isEqual = Objects.equals(vector1.head(), vector2.head());
        if (!isEqual) {
          return false;
        }
        vector1 = vector1.tail();
        vector2 = vector2.tail();
      }
      return vector1.isEmpty() && vector2.isEmpty();
    } else {
      return false;
    }
  }

  @Override
  public int hashCode() {
    return hashCode.get();
  }

  @Override
  public String toString() {
    return mkString(", ", "Vector(", ")");
  }
}