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: 3.1.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 java.util.ArrayList;

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
    public T reduceLeft(@NotNull F2 f) {
        return this.tail.foldLeft(f, this.head);
    }

    @NotNull
    public T reduceRight(@NotNull F2 f) {
        return this.init().foldRight(f, this.last());
    }

    @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) {
        @SuppressWarnings("unchecked")
        T[] result = (T[]) new Object[length];
        ImmutableList list = this;
        int j = 0;
        for (int i = 0; i < length; i++) {
            T el = ((NonEmptyImmutableList) list).head;
            if (f.apply(el)) {
                result[j] = el;
                j++;
            }
            list = ((NonEmptyImmutableList) list).tail;
        }
        return fromBounded(result, 0, j);
    }

    @NotNull
    @Override
    public  NonEmptyImmutableList map(@NotNull F f) {
        @SuppressWarnings("unchecked")
        B[] result = (B[]) new Object[length];
        ImmutableList list = this;
        for (int i = 0; i < length; i++) {
            result[i] = f.apply(((NonEmptyImmutableList) list).head);
            list = ((NonEmptyImmutableList) list).tail;
        }
        return (NonEmptyImmutableList) from(result);
    }

    @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();
        }
        return (NonEmptyImmutableList) from(result);
    }

    @NotNull
    @Override
    public ImmutableList take(int n) {
        if (n <= 0) {
            return nil();
        }
        @SuppressWarnings("unchecked")
        T[] result = (T[]) new Object[n];
        ImmutableList list = this;
        for (int i = 0; i < n; i++) {
            result[i] = ((NonEmptyImmutableList) list).head;
            list = ((NonEmptyImmutableList) list).tail;
        }
        return from(result);
    }

    @NotNull
    @Override
    public ImmutableList drop(int n) {
        if (n <= 0) {
            return this;
        }
        ImmutableList list = this;
        while (n > 0) {
            if (list instanceof NonEmptyImmutableList) {
                list = ((NonEmptyImmutableList) list).tail;
                n--;
            }
        }
        return list;
    }

    @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) {
        ImmutableList list1 = this;
        ImmutableList list2 = list;
        int n = Math.min(list1.length, list2.length);
        @SuppressWarnings("unchecked")
        C[] result = (C[]) new Object[n];
        for (int i = 0; i < n; i++) {
            result[i] = f.apply(((NonEmptyImmutableList) list1).head, ((NonEmptyImmutableList) list2).head);
            list1 = ((NonEmptyImmutableList) list1).tail;
            list2 = ((NonEmptyImmutableList) list2).tail;
        }
        return from(result);
    }

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

    @NotNull
    @Override
    public  ImmutableList append(@NotNull ImmutableList list) {
        if (list.length == 0) {
            return this;
        }
        @SuppressWarnings("unchecked")
        T[] copy = toArray((T[]) new Object[length]);
        @SuppressWarnings("unchecked")
        ImmutableList listT = (ImmutableList) list;
        for (int i = copy.length - 1; i >= 0; i--) {
            listT = cons(copy[i], listT);
        }
        return listT;
    }

    @Override
    public boolean exists(@NotNull F f) {
        NonEmptyImmutableList list = this;
        while (true) {
            if (f.apply(list.head)) {
                return true;
            }
            if (list.tail instanceof Nil) {
                return false;
            }
            list = ((NonEmptyImmutableList) list.tail);
        }
    }

    @Override
    public boolean contains(@NotNull T a) {
        NonEmptyImmutableList list = this;
        while (true) {
            if (list.head == a) {
                return true;
            }
            if (list.tail instanceof Nil) {
                return false;
            }
            list = ((NonEmptyImmutableList) list.tail);
        }
    }

    @NotNull
    @Override
    public Pair, ImmutableList> span(@NotNull F f) {
        @SuppressWarnings("unchecked")
        T[] result = (T[]) new Object[length];
        ImmutableList list = this;
        int j = 0;
        for (int i = 0; i < length; i++) {
            T el = ((NonEmptyImmutableList) list).head;
            if (f.apply(el)) {
                result[j] = el;
                j++;
            } else {
                break;
            }
            list = ((NonEmptyImmutableList) list).tail;
        }
        return Pair.make(fromBounded(result, 0, j), list);
    }

    @NotNull
    @Override
    public  ImmutableList flatMap(@NotNull F> f) {
        ArrayList result = new ArrayList<>();
        ImmutableList list = this;
        while (list instanceof NonEmptyImmutableList) {
            ImmutableList bucket = f.apply(((NonEmptyImmutableList) list).head);
            while (bucket instanceof NonEmptyImmutableList) {
                result.add(((NonEmptyImmutableList) bucket).head);
                bucket = ((NonEmptyImmutableList) bucket).tail;
            }
            list = ((NonEmptyImmutableList) list).tail;
        }
        return from(result);
    }

    @NotNull
    @Override
    public ImmutableList removeAll(@NotNull F f) {
        return filter(x -> !f.apply(x));
    }

    @NotNull
    @Override
    public NonEmptyImmutableList reverse() {
        @SuppressWarnings("unchecked")
        T[] result = (T[]) new Object[length];
        ImmutableList list = this;
        for (int i = 0; i < length; i++) {
            result[length - i - 1] = ((NonEmptyImmutableList) list).head;
            list = ((NonEmptyImmutableList) list).tail;
        }
        return (NonEmptyImmutableList) from(result);
    }

    @NotNull
    @Override
    public  Pair> mapAccumL(@NotNull F2> f, @NotNull B acc) {
        @SuppressWarnings("unchecked")
        C[] result = (C[]) new Object[length];
        ImmutableList list = this;
        for (int i = 0; i < length; i++) {
            Pair pair = f.apply(acc, ((NonEmptyImmutableList) list).head);
            acc = pair.a;
            result[i] = pair.b;
            list = ((NonEmptyImmutableList) list).tail;
        }
        return new Pair<>(acc, from(result));
    }

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