Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.shapesecurity.functional.data.ConcatList Maven / Gradle / Ivy
/*
* 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 com.shapesecurity.functional.Pair;
import javax.annotation.CheckReturnValue;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Deque;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Spliterator;
import java.util.Stack;
import java.util.function.Consumer;
@CheckReturnValue
public abstract class ConcatList implements Iterable {
@SuppressWarnings("StaticInitializerReferencesSubClass")
private static final Empty EMPTY = new Empty<>();
private static BinaryTreeMonoid MONOID = new BinaryTreeMonoid<>();
public final int length;
final boolean isBalanced;
protected ConcatList(int length, boolean isBalanced) {
this.length = length;
this.isBalanced = isBalanced;
}
@SuppressWarnings("unchecked")
@Nonnull
public static ConcatList empty() {
return (ConcatList) EMPTY;
}
@SuppressWarnings("unchecked")
@Nonnull
@Deprecated
public static ConcatList nil() {
return ConcatList.empty();
}
@SafeVarargs
public static ConcatList of(T... elements) {
if (elements.length == 0) {
return empty();
}
return ofInternal(elements, 0, elements.length);
}
public abstract boolean isEmpty();
@Nonnull
public static ConcatList fromList(@Nonnull List list) {
return fromListInternal(list.iterator(), 0, list.size());
}
@Nonnull
private static ConcatList ofInternal(@Nonnull T[] elements, int start, int end) {
if (start == end) {
return empty();
} else if (start + 1 == end) {
return single(elements[start]);
} else {
int mid = (start + end) / 2; // start < mid && mid < end
return ofInternal(elements, start, mid).append(ofInternal(elements, mid, end));
}
}
@Nonnull
private static ConcatList fromListInternal(@Nonnull Iterator elements, int start, int end) {
if (start == end) {
return empty();
} else if (start + 1 == end) {
return single(elements.next());
} else {
int mid = (start + end) / 2; // start < mid && mid < end
return fromListInternal(elements, start, mid).append(fromListInternal(elements, mid, end));
}
}
public abstract ConcatList balanced();
@Nonnull
public final Maybe, ConcatList>> split(int index) {
if (index < 0 || index > this.length) {
return Maybe.empty();
}
if (index == 0) {
return Maybe.of(Pair.of(empty(), this));
}
if (index == this.length) {
return Maybe.of(Pair.of(this, empty()));
}
return Maybe.of(this.splitInternal(index));
}
abstract Pair, ConcatList> splitInternal(int index);
@Nonnull
public static ConcatList single(@Nonnull T scope) {
return new Leaf<>(scope);
}
@SuppressWarnings("unchecked")
public static Monoid> monoid() {
return (BinaryTreeMonoid) MONOID;
}
@Nonnull
public abstract ImmutableList toList();
@Nonnull
public final B foldLeft(@Nonnull F2 f, @Nonnull B init) {
if (this.isEmpty()) {
return init;
}
@SuppressWarnings("unchecked")
B[] result = (B[]) new Object[]{init};
this.forEach(n -> result[0] = f.apply(result[0], n));
return result[0];
}
@Nonnull
public final B foldRight(@Nonnull F2 super T, B, B> f, @Nonnull B init) {
// Manually expanded recursion
Deque> stack = new ArrayDeque<>(this.length);
stack.add(this);
while (!stack.isEmpty()) {
ConcatList curr = stack.pop();
if (curr instanceof Fork) {
Fork fork = (Fork) curr;
stack.push(fork.left);
stack.push(fork.right);
} else if (curr instanceof Leaf) {
init = f.apply(((Leaf) curr).data, init);
}
}
return init;
}
/**
* @deprecated Use {@link #forEach(Consumer)} instead
*/
@Deprecated
public final void foreach(@Nonnull Effect f) {
this.forEach(f::e);
}
@Override
public final void forEach(@Nonnull Consumer super T> action) {
// Manually expanded recursion
@SuppressWarnings("unchecked")
ConcatList[] stack = new ConcatList[this.length];
int i = 0;
stack[i++] = this;
while (i > 0) {
ConcatList curr = stack[--i];
if (curr instanceof Fork) {
Fork fork = (Fork) curr;
stack[i++] = fork.right;
stack[i++] = fork.left;
} else if (curr instanceof Leaf) {
action.accept(((Leaf) curr).data);
}
}
}
@Nonnull
public abstract ConcatList append(@Nonnull ConcatList extends T> rhs);
@Nonnull
public final ConcatList append1(@Nonnull T element) {
return this.append(ConcatList.single(element));
}
public final boolean exists(@Nonnull F f) {
return this.find(f).isJust();
}
@Nonnull
public final Maybe find(@Nonnull F f) {
// Manually expanded recursion
Deque> stack = new ArrayDeque<>(this.length);
stack.add(this);
while (!stack.isEmpty()) {
ConcatList curr = stack.pop();
if (curr instanceof Fork) {
Fork fork = (Fork) curr;
stack.push(fork.right);
stack.push(fork.left);
} else if (curr instanceof Leaf) {
if (f.apply(((Leaf) curr).data)) {
return Maybe.of(((Leaf) curr).data);
}
}
}
return Maybe.empty();
}
@Nonnull
public final ConcatList reverse() {
if (this instanceof Empty) {
return this;
}
ArrayList list = new ArrayList<>(this.length);
Deque> stack = new ArrayDeque<>(this.length);
stack.add(this);
while (!stack.isEmpty()) {
ConcatList curr = stack.pop();
if (curr instanceof Fork) {
Fork fork = (Fork) curr;
// reversed
stack.push(fork.left);
stack.push(fork.right);
} else if (curr instanceof Leaf) {
list.add(((Leaf) curr).data);
}
}
return ConcatList.fromList(list);
}
@Nonnull
public final Maybe index(int index) {
ConcatList list = this;
if (index >= this.length) {
return Maybe.empty();
}
// list is not an Empty
while (list instanceof Fork) {
ConcatList left = ((Fork) list).left;
if (index < left.length) {
list = left;
} else {
index -= left.length;
list = ((Fork) list).right;
}
}
return Maybe.of(((Leaf) list).data);
}
@Nullable
abstract ConcatList updateInternal(int index, @Nonnull T element);
@Nonnull
public final Maybe> update(int index, @Nonnull T element) {
return Maybe.fromNullable(this.updateInternal(index, element));
}
private final static class Empty extends ConcatList {
private Empty() {
super(0, true);
}
@Nonnull
@Override
public ImmutableList toList() {
return ImmutableList.empty();
}
@Override
public boolean isEmpty() {
return true;
}
@Override
public ConcatList balanced() {
return this;
}
@Override
Pair, ConcatList> splitInternal(int index) {
return Pair.of(this, this);
}
@SuppressWarnings("unchecked")
@Nonnull
@Override
public ConcatList append(@Nonnull ConcatList extends T> rhs) {
return (ConcatList) rhs;
}
@Nullable
@Override
public ConcatList updateInternal(int index, @Nonnull T element) {
return null;
}
@Override
public Iterator iterator() {
return new Iterator() {
@Override
public boolean hasNext() {
return false;
}
@Override
public T next() {
return null;
}
};
}
}
private final static class Leaf extends ConcatList {
@Nonnull
public final T data;
private Leaf(@Nonnull T data) {
super(1, true);
this.data = data;
}
@Nonnull
@Override
public ImmutableList toList() {
return ImmutableList.of(this.data);
}
@Override
public boolean isEmpty() {
return false;
}
@Override
public ConcatList balanced() {
return this;
}
@Override
Pair, ConcatList> splitInternal(int index) {
if (index == 0) {
return Pair.of(ConcatList.empty(), this);
} else {
return Pair.of(this, ConcatList.empty());
}
}
@SuppressWarnings("unchecked")
@Nonnull
@Override
public ConcatList append(@Nonnull ConcatList extends T> rhs) {
if (rhs instanceof Empty) {
return this;
}
return new Fork<>(this, (ConcatList) rhs);
}
@Nullable
@Override
ConcatList updateInternal(int index, @Nonnull T element) {
return index == 0 ? single(element) : null;
}
@Override
public Iterator iterator() {
return Collections.singleton(this.data).iterator();
}
}
private final static class Fork extends ConcatList {
@Nonnull
public final ConcatList left, right;
private Fork(@Nonnull ConcatList left, @Nonnull ConcatList right) {
super(left.length + right.length, left.isBalanced && right.isBalanced && (left.length + right.length < 16 || left.length > right.length / 2 && left.length < right.length * 2));
this.left = left;
this.right = right;
}
@Nonnull
@Override
public ImmutableList toList() {
ImmutableList out = ImmutableList.empty();
final Stack> stack = new Stack<>();
stack.push(this.left);
ConcatList next = this.right;
while (true) {
if (next instanceof Fork) {
stack.push(((Fork) next).left);
next = ((Fork) next).right;
} else if (next instanceof Leaf) {
out = out.cons(((Leaf) next).data);
if (stack.empty()) break;
next = stack.pop();
} else { // Empty
if (stack.empty()) break;
next = stack.pop();
}
}
return out;
}
@Override
public boolean isEmpty() {
return false;
}
@Override
public ConcatList balanced() {
if (this.isBalanced) {
return this;
}
return ConcatList.fromListInternal(this.iterator(), 0, this.length);
}
@Override
@Nonnull
Pair, ConcatList> splitInternal(int index) {
// Manually expanded zipper access
Stack> zippers1 = new Stack<>();
Stack zippers2 = new Stack<>();
ConcatList list = this;
while (list instanceof Fork) {
ConcatList left = ((Fork) list).left;
if (index < left.length) {
zippers1.push(((Fork) list).right);
zippers2.push(false);
list = left;
} else {
index -= left.length;
zippers1.push(left);
zippers2.push(true);
list = ((Fork) list).right;
}
}
// list is the first of the right hand side
Pair, ConcatList> result = Pair.of(empty(), list);
while (!zippers1.isEmpty()) {
if (zippers2.pop()) {
result = Pair.of(
zippers1.pop().append(result.left()),
result.right());
} else {
result = Pair.of(
result.left(),
result.right().append(zippers1.pop()));
}
}
return result;
}
@SuppressWarnings("unchecked")
@Nonnull
@Override
public ConcatList append(@Nonnull ConcatList extends T> rhs) {
if (rhs instanceof Empty) {
return this;
}
return new Fork<>(this, (ConcatList) rhs);
}
@Nullable
@Override
ConcatList updateInternal(int index, @Nonnull T element) {
// Manually expanded zipper access
if (index >= this.length) {
return null;
}
Stack> zippers1 = new Stack<>();
Stack zippers2 = new Stack<>();
ConcatList list = this;
while (list instanceof Fork) {
ConcatList left = ((Fork) list).left;
if (index < left.length) {
zippers1.push(((Fork) list).right);
zippers2.push(false);
list = left;
} else {
index -= left.length;
zippers1.push(left);
zippers2.push(true);
list = ((Fork) list).right;
}
}
ConcatList l = ConcatList.single(element);
while (!zippers1.isEmpty()) {
l = zippers2.pop() ? zippers1.pop().append(l) : l.append(zippers1.pop());
}
return l;
}
@Override
public Iterator iterator() {
return new Iterator() {
@SuppressWarnings("unchecked")
private final ConcatList[] stack = new ConcatList[Fork.this.length];
int i = 0;
{
this.stack[this.i++] = Fork.this;
}
@Override
public boolean hasNext() {
return this.i > 0;
}
@Override
public T next() {
while (this.i > 0) {
ConcatList curr = this.stack[--this.i];
if (curr instanceof Fork) {
Fork fork = (Fork) curr;
this.stack[this.i++] = fork.right;
this.stack[this.i++] = fork.left;
} else if (curr instanceof Leaf) {
return ((Leaf) curr).data;
}
}
throw new NoSuchElementException();
}
};
}
}
private final static class ConcatListSplitIterator implements Spliterator {
@Nonnull
private final Deque> stack;
private int size;
private ConcatListSplitIterator(@Nonnull Deque> stack, int size) {
this.stack = stack;
this.size = size;
}
private ConcatListSplitIterator(@Nonnull ConcatList list) {
// Manually expanded recursion
this.stack = new ArrayDeque<>(list.length);
this.stack.add(list);
this.size = list.length;
}
@Override
public boolean tryAdvance(Consumer super T> action) {
while (!this.stack.isEmpty()) {
ConcatList curr = this.stack.pop();
if (curr instanceof Fork) {
Fork fork = (Fork) curr;
this.stack.push(fork.right);
this.stack.push(fork.left);
} else if (curr instanceof Leaf) {
this.size--;
action.accept(((Leaf) curr).data);
return true;
}
}
return false;
}
@Override
public Spliterator trySplit() {
Deque> newDequeue = new ArrayDeque<>();
newDequeue.addAll(this.stack);
return new ConcatListSplitIterator<>(newDequeue, this.size);
}
@Override
public long estimateSize() {
return this.size;
}
@Override
public int characteristics() {
return IMMUTABLE | ORDERED | SUBSIZED | SIZED;
}
@Override
public void forEachRemaining(Consumer super T> action) {
while (!this.stack.isEmpty()) {
ConcatList curr = this.stack.pop();
if (curr instanceof Fork) {
Fork fork = (Fork) curr;
this.stack.push(fork.right);
this.stack.push(fork.left);
} else if (curr instanceof Leaf) {
this.size--;
action.accept(((Leaf) curr).data);
}
}
}
}
@Override
public Spliterator spliterator() {
return new ConcatListSplitIterator<>(this);
}
private static class BinaryTreeMonoid implements Monoid> {
@Nonnull
@Override
public ConcatList identity() {
return new Empty<>();
}
@Nonnull
@Override
public ConcatList append(ConcatList a, ConcatList b) {
return a.append(b);
}
}
}