All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.shapesecurity.functional.data.NonEmptyImmutableList Maven / Gradle / Ivy

There is a newer version: 2.2.0
Show newest version
/*
 * Copyright 2014 Shape Security, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.shapesecurity.functional.data;

import com.shapesecurity.functional.F;
import com.shapesecurity.functional.F2;
import com.shapesecurity.functional.Pair;
import org.jetbrains.annotations.NotNull;

public final class NonEmptyImmutableList extends ImmutableList {
  @NotNull
  public final T head;

  @NotNull
  public final ImmutableList tail;

  protected NonEmptyImmutableList(@NotNull T head, @NotNull final ImmutableList tail) {
    super(tail.length + 1);
    this.head = head;
    this.tail = tail;
  }

  @NotNull
  public ImmutableList tail() {
    return tail;
  }

  @SuppressWarnings("unchecked")
  @Override
  public boolean equals(Object o) {
    if (this == o) {
      return true;
    }
    if (!(o instanceof NonEmptyImmutableList)) {
      return false;
    }

    NonEmptyImmutableList list = (NonEmptyImmutableList) o;
    return this.head.equals(list.head) && this.tail().equals(list.tail());
  }

  @NotNull
  @Override
  public  A foldLeft(@NotNull F2 f, @NotNull A init) {
    ImmutableList list = this;
    while (list instanceof NonEmptyImmutableList) {
      init = f.apply(init, ((NonEmptyImmutableList) list).head);
      list = ((NonEmptyImmutableList) list).tail();
    }
    return init;
  }

  @NotNull
  @Override
  public  A foldRight(@NotNull F2 f, @NotNull A init) {
    return f.apply(this.head, this.tail().foldRight(f, init));
  }

  @NotNull
  @Override
  public Maybe maybeHead() {
    return Maybe.just(this.head);
  }

  @NotNull
  @Override
  public Maybe maybeLast() {
    if (this.tail().isEmpty()) {
      return Maybe.just(this.head);
    }
    return this.tail().maybeLast();
  }

  @NotNull
  @Override
  public Maybe> maybeTail() {
    return Maybe.just(this.tail());
  }

  @NotNull
  @Override
  public Maybe> maybeInit() {
    if (this.tail().isEmpty()) {
      return Maybe.just(nil());
    }
    return this.tail().maybeInit().map(t -> t.cons(this.head));
  }

  @NotNull
  public final T last() {
    NonEmptyImmutableList nel = this;
    while (true) {
      if (nel.tail().isEmpty()) {
        return nel.head;
      }
      nel = (NonEmptyImmutableList) nel.tail();
    }
  }

  @NotNull
  public final ImmutableList init() {
    if (this.tail().isEmpty()) {
      return nil();
    }
    return cons(this.head, ((NonEmptyImmutableList) this.tail()).init());
  }

  @NotNull
  @Override
  public ImmutableList filter(@NotNull F f) {
    return f.apply(this.head) ? cons(this.head, this.tail().filter(f)) : this.tail().filter(f);
  }

  @NotNull
  @Override
  public  NonEmptyImmutableList map(@NotNull F f) {
    return ImmutableList.cons(f.apply(this.head), this.tail().map(f));
  }

  @Override
  @NotNull
  public final  NonEmptyImmutableList mapWithIndex(@NotNull F2 f) {
    int length = this.length;
    @SuppressWarnings("unchecked")
    B[] result = (B[]) new Object[length];
    ImmutableList list = this;
    for (int i = 0; i < length; i++) {
      result[i] = f.apply(i, ((NonEmptyImmutableList) list).head);
      list = ((NonEmptyImmutableList) list).tail();
    }
    ImmutableList nList = nil();
    for (int i = length - 1; i >= 0; i--) {
      nList = nList.cons(result[i]);
    }
    return (NonEmptyImmutableList) nList;
  }

  @NotNull
  @Override
  public ImmutableList take(int n) {
    if (n <= 0) {
      return nil();
    }
    return cons(this.head, this.tail().take(n - 1));
  }

  @NotNull
  @Override
  public ImmutableList drop(int n) {
    if (n <= 0) {
      return this;
    }
    return this.tail().drop(n - 1);
  }

  @NotNull
  @Override
  public Maybe> toNonEmptyList() {
    return Maybe.just(this);
  }

  @NotNull
  @Override
  public  Maybe decons(@NotNull F2, B> f) {
    return Maybe.just(f.apply(this.head, this.tail()));
  }

  @NotNull
  @Override
  public  ImmutableList zipWith(@NotNull F2 f, @NotNull ImmutableList list) {
    if (list instanceof NonEmptyImmutableList) {
      NonEmptyImmutableList nonEmptyList = (NonEmptyImmutableList) list;
      return ImmutableList.cons(f.apply(this.head, nonEmptyList.head), this.tail().zipWith(f, nonEmptyList.tail()));
    }
    return nil();
  }

  @Override
  public boolean isEmpty() {
    return false;
  }

  @NotNull
  @Override
  public  ImmutableList append(@NotNull ImmutableList defaultClause) {
    return cons(this.head, this.tail().append(defaultClause));
  }

  @Override
  public boolean exists(@NotNull F f) {
    return f.apply(this.head) || this.tail().exists(f);
  }

  @NotNull
  @Override
  public Pair, ImmutableList> span(@NotNull F f) {
    if (!f.apply(this.head)) {
      return new Pair<>(nil(), this);
    }
    Pair, ImmutableList> s = this.tail().span(f);
    return new Pair<>(s.a.cons(this.head), s.b);
  }

  @NotNull
  @Override
  public  ImmutableList flatMap(@NotNull F> f) {
    return f.apply(this.head).append(this.tail().flatMap(f));
  }

  @NotNull
  @Override
  public ImmutableList removeAll(@NotNull F f) {
    if (f.apply(this.head)) {
      return this.tail().removeAll(f);
    }
    return cons(this.head, this.tail().removeAll(f));
  }

  @NotNull
  @Override
  public NonEmptyImmutableList reverse() {
    return this.reverse(nil());
  }

  @NotNull
  @Override
  public  Pair> mapAccumL(@NotNull F2> f, @NotNull B acc) {
    Pair pair = f.apply(acc, this.head);
    Pair> bListPair = this.tail().mapAccumL(f, pair.a);
    return new Pair<>(bListPair.a, ImmutableList.cons(pair.b, bListPair.b));
  }

  @NotNull
  private NonEmptyImmutableList reverse(@NotNull ImmutableList acc) {
    if (this.tail().isEmpty()) {
      return acc.cons(this.head);
    }
    return ((NonEmptyImmutableList) this.tail()).reverse(cons(this.head, acc));
  }

  @Override
  protected int calcHashCode() {
    int start = HashCodeBuilder.init();
    start = HashCodeBuilder.put(start, "List");
    start = HashCodeBuilder.put(start, head);
    return HashCodeBuilder.put(start, tail);
  }
}