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: 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 org.jetbrains.annotations.NotNull;

public abstract class ConcatList {
  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;
  }

  @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 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 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();
    }
  }

  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 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();
    }
  }

  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 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));
    }
  }

  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);
    }
  }
}