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

com.shapesecurity.functional.data.ConcatList 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 com.shapesecurity.functional.Effect;
import com.shapesecurity.functional.F;
import com.shapesecurity.functional.F2;

import org.jetbrains.annotations.NotNull;

import java.util.Iterator;

public abstract class ConcatList implements Iterable {
    private static final Empty EMPTY = new Empty<>();
    private static BinaryTreeMonoid MONOID = new BinaryTreeMonoid<>();
    public final int length;

    protected ConcatList(int length) {
        this.length = length;
    }

    @SuppressWarnings("unchecked")
    @NotNull
    public static  ConcatList empty() {
        return (ConcatList) EMPTY;
    }

    @SuppressWarnings("unchecked")
    @NotNull
    public static  ConcatList nil() {
        return (ConcatList) EMPTY;
    }

    @NotNull
    public static  ConcatList single(@NotNull T scope) {
        return new Leaf<>(scope);
    }

    @SuppressWarnings("unchecked")
    public static  Monoid> monoid() {
        return (BinaryTreeMonoid) MONOID;
    }

    @NotNull
    public final ImmutableList toList() {
        return this.toList(ImmutableList.nil());
    }

    protected abstract ImmutableList toList(@NotNull ImmutableList acc);

    @NotNull
    public abstract  B foldLeft(@NotNull F2 f, @NotNull B init);

    @NotNull
    public abstract  B foldRight(@NotNull F2 f, @NotNull B init);

    public abstract void foreach(@NotNull Effect f);

    public abstract boolean isEmpty();

    @NotNull
    public abstract ConcatList append(@NotNull ConcatList rhs);

    @NotNull
    public final ConcatList append1(@NotNull T element) {
        return this.append(ConcatList.single(element));
    }

    public abstract boolean exists(@NotNull F f);

    @NotNull
    public abstract Maybe find(@NotNull F f);

    @NotNull
    public abstract ConcatList reverse();

    @NotNull
    public abstract Maybe index(int index);

    @NotNull
    public abstract Maybe> update(int index, @NotNull T element);

    public final static class Empty extends ConcatList {
        private Empty() {
            super(0);
        }

        @NotNull
        @Override
        protected ImmutableList toList(@NotNull ImmutableList acc) {
            return acc;
        }

        @NotNull
        @Override
        public  B foldLeft(@NotNull F2 f, @NotNull B init) {
            return init;
        }

        @NotNull
        @Override
        public  B foldRight(@NotNull F2 f, @NotNull B init) {
            return init;
        }

        @Override
        public void foreach(@NotNull Effect f) {
        }

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

        @SuppressWarnings("unchecked")
        @NotNull
        @Override
        public ConcatList append(@NotNull ConcatList rhs) {
            return (ConcatList) rhs;
        }

        @Override
        public boolean exists(@NotNull F f) {
            return false;
        }

        @NotNull
        @Override
        public Maybe find(@NotNull F f) {
            return Maybe.nothing();
        }

        @NotNull
        @Override
        public ConcatList reverse() {
            return this;
        }

        @NotNull
        @Override
        public Maybe index(int index) {
            return Maybe.nothing();
        }

        @NotNull
        @Override
        public Maybe> update(int index, @NotNull T element) {
            return Maybe.nothing();
        }

        @Override
        public Iterator iterator() {
            return new Iterator() {
                @Override
                public boolean hasNext() {
                    return false;
                }

                @Override
                public T next() {
                    return null;
                }
            };
        }
    }

    public final static class Leaf extends ConcatList {
        @NotNull
        public final T data;

        private Leaf(@NotNull T data) {
            super(1);
            this.data = data;
        }

        @NotNull
        @Override
        protected ImmutableList toList(@NotNull ImmutableList acc) {
            return acc.cons(this.data);
        }

        @NotNull
        @Override
        public  B foldLeft(@NotNull F2 f, @NotNull B init) {
            return f.apply(init, this.data);
        }

        @NotNull
        @Override
        public  B foldRight(@NotNull F2 f, @NotNull B init) {
            return f.apply(this.data, init);
        }

        @Override
        public void foreach(@NotNull Effect f) {
            f.apply(this.data);
        }

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

        @SuppressWarnings("unchecked")
        @NotNull
        @Override
        public ConcatList append(@NotNull ConcatList rhs) {
            return new Fork<>(this, (ConcatList) rhs);
        }

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

        @NotNull
        @Override
        public Maybe find(@NotNull F f) {
            if (f.apply(this.data)) {
                return Maybe.just(this.data);
            }
            return Maybe.nothing();
        }

        @NotNull
        @Override
        public ConcatList reverse() {
            return this;
        }

        @NotNull
        @Override
        public Maybe index(int index) {
            return Maybe.iff(index == 0, this.data);
        }

        @NotNull
        @Override
        public Maybe> update(int index, @NotNull T element) {
            return index == 0 ? Maybe.just(single(element)) : Maybe.nothing();
        }

        @Override
        public Iterator iterator() {
            return new Iterator() {
                private boolean used = false;

                @Override
                public boolean hasNext() {
                    return !this.used;
                }

                @Override
                public T next() {
                    if (!this.used) {
                        this.used = true;
                        return data;
                    }
                    return null;
                }
            };
        }
    }

    public final static class Fork extends ConcatList {
        @NotNull
        public final ConcatList left, right;

        private Fork(@NotNull ConcatList left, @NotNull ConcatList right) {
            super(left.length + right.length);
            this.left = left;
            this.right = right;
        }

        @NotNull
        @Override
        protected ImmutableList toList(@NotNull ImmutableList acc) {
            return this.left.toList(this.right.toList(acc));
        }

        @NotNull
        @Override
        public  B foldLeft(@NotNull F2 f, @NotNull B init) {
            return this.right.foldLeft(f, this.left.foldLeft(f, init));
        }

        @NotNull
        @Override
        public  B foldRight(@NotNull F2 f, @NotNull B init) {
            return this.left.foldRight(f, this.right.foldRight(f, init));
        }

        @Override
        public void foreach(@NotNull Effect f) {
            this.left.foreach(f);
            this.right.foreach(f);
        }


        @Override
        public boolean isEmpty() {
            return this.left.isEmpty() || this.right.isEmpty();
        }

        @SuppressWarnings("unchecked")
        @NotNull
        @Override
        public ConcatList append(@NotNull ConcatList rhs) {
            return new Fork<>(this, (ConcatList) rhs);
        }

        @Override
        public boolean exists(@NotNull F f) {
            return this.left.exists(f) || this.right.exists(f);
        }

        @NotNull
        @Override
        public Maybe find(@NotNull F f) {
            Maybe foundLeft = this.left.find(f);
            if (foundLeft.isNothing()) {
                return this.right.find(f);
            }
            return foundLeft;
        }

        @NotNull
        @Override
        public Fork reverse() {
            return new Fork<>(this.right.reverse(), this.left.reverse());
        }

        @NotNull
        @Override
        public Maybe index(int index) {
            if (index >= this.length) {
                return Maybe.nothing();
            }
            return index < this.left.length ? this.left.index(index) : this.right.index(index - this.left.length);
        }

        @NotNull
        @Override
        public Maybe> update(int index, @NotNull T element) {
            if (index >= this.length) {
                return Maybe.nothing();
            }
            ConcatList left = this.left;
            ConcatList right = this.right;

            if (index < this.left.length) {
                left = left.update(index, element).just();
            } else {
                right = right.update(index - this.left.length, element).just();
            }
            return Maybe.just(left.append(right));
        }

        @Override
        public Iterator iterator() {
            return new Iterator() {
                private boolean isLeft = true;
                private Iterator branchIterator = left.iterator();

                private void ensureCorrectBranch() {
                    if (this.isLeft && !this.branchIterator.hasNext()) {
                        this.isLeft = false;
                        this.branchIterator = right.iterator();
                    }
                }

                @Override
                public boolean hasNext() {
                    this.ensureCorrectBranch();
                    return this.branchIterator.hasNext();
                }

                @Override
                public T next() {
                    this.ensureCorrectBranch();
                    return this.branchIterator.next();
                }
            };
        }
    }

    private static class BinaryTreeMonoid implements Monoid> {
        @NotNull
        @Override
        public ConcatList identity() {
            return new Empty<>();
        }

        @NotNull
        @Override
        public ConcatList append(ConcatList a, ConcatList b) {
            return a.append(b);
        }
    }
}