com.jongsoft.lang.collection.impl.TailedList Maven / Gradle / Ivy
/*
* The MIT License
*
* Copyright 2016-2018 Jong Soft.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.jongsoft.lang.collection.impl;
import static java.lang.String.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collector;
import com.jongsoft.lang.collection.Iterator;
import com.jongsoft.lang.collection.Map;
import com.jongsoft.lang.collection.Sequence;
import com.jongsoft.lang.collection.support.AbstractIterator;
import com.jongsoft.lang.collection.support.Collections;
/**
* A {@link TailedList} is an {@link Sequence} implementation where each entry in the list points to the next
* entry in the list.
*
* @param the type of elements contained within the {@link TailedList}
* @see Linked list documentation
* @since 0.0.1
*/
public class TailedList implements Sequence {
private static final TailedList> EMPTY = new TailedList<>(null, null);
private final Object element;
private final TailedList tail;
private TailedList(T element, TailedList tail) {
this.element = element;
this.tail = tail;
}
@Override
public Sequence append(T value) {
return new TailedList<>(value, (TailedList) reverse()).reverse();
}
@Override
public Sequence union(final Iterable iterable) {
Sequence reversed = reverse();
for (T value : iterable) {
reversed = new TailedList<>(value, (TailedList) reversed);
}
return reversed.reverse();
}
@Override
public Sequence insert(int index, T value) {
validateIndexOutOfBounds(index);
TailedList result = this;
for (int i = 0; i < index; i++) {
result = result.tail;
}
result = new TailedList<>(value, result);
for (int i = index - 1; i >= 0; i--) {
result = new TailedList<>(get(i), result);
}
return result;
}
@Override
public int firstIndexWhere(final Predicate predicate) {
int index = 0;
for (TailedList list = this; !list.isEmpty(); list = list.tail, index++) {
if (predicate.test(list.get())) {
return index;
}
}
return -1;
}
@Override
@SuppressWarnings("unchecked")
public T get(int index) {
validateIndexOutOfBounds(index);
int loopIdx = 0;
TailedList computed;
for (computed = this; loopIdx < index; computed = computed.tail, loopIdx++);
return (T) computed.element;
}
@Override
public Sequence tail() {
return tail;
}
@Override
public Sequence remove(int index) {
validateIndexOutOfBounds(index);
Sequence reversed = empty();
for (TailedList newTail = this; !newTail.isEmpty(); newTail = newTail.tail, index--) {
if (index != 0) {
reversed = reversed.append(newTail.get());
}
}
return reversed;
}
@Override
public Sequence filter(Predicate predicate) {
Objects.requireNonNull(predicate, "The predicate may not be null");
Sequence filtered = empty();
for (T value : reverse()) {
if (predicate.test(value)) {
filtered = new TailedList<>(value, (TailedList) filtered);
}
}
return filtered;
}
@Override
public Sequence distinct() {
return null;
}
@Override
public Sequence map(final Function mapper) {
Sequence mappedTail = empty();
for (TailedList processing = this; !processing.isEmpty(); processing = processing.tail) {
mappedTail = new TailedList<>(mapper.apply(processing.get()), (TailedList) mappedTail);
}
return mappedTail.reverse();
}
@Override
public Map> groupBy(final Function super T, ? extends K> keyGenerator) {
return Collections.groupBy(TailedList::empty, this, keyGenerator);
}
@Override
public int size() {
int size = 0;
for (TailedList list = this; !list.isEmpty(); list = list.tail, size++);
return size;
}
@Override
public boolean isEmpty() {
return EMPTY.equals(this);
}
@Override
public Iterator iterator() {
return new IteratorImpl<>(this);
}
@Override
public List toJava() {
java.util.List result = new java.util.ArrayList<>(size());
forEach(result::add);
return result;
}
public static Collector, Sequence> collector() {
return Collections.collector(TailedList::ofAll);
}
private void validateIndexOutOfBounds(int index) {
if (index >= size()) {
throw new IndexOutOfBoundsException(format("%s is not in the bounds of 0 and %s", index, size()));
}
}
@Override
public Sequence reverse() {
Sequence corrected = empty();
for (int i = 0; i < size(); i++) {
corrected = new TailedList<>(get(i), (TailedList) corrected);
}
return corrected;
}
class IteratorImpl extends AbstractIterator {
private TailedList start;
private TailedList position;
private IteratorImpl(TailedList position) {
this.start = position;
this.position = position;
}
@Override
public void reset() {
position = start;
}
@Override
public boolean hasNext() {
return !position.isEmpty();
}
@Override
public T getNext() {
T value = position.get();
position = position.tail;
return value;
}
}
//------------------------------------------------------------------
//-- Static supporting methods
/**
* Creates a new empty TailedList.
*
* @param the type of the list
* @return the created list
*/
@SuppressWarnings("unchecked")
public static Sequence empty() {
return (TailedList) EMPTY;
}
/**
* Create a new {@link TailedList} containing exactly one entry being the provided element.
*
* @param element the element to wrap in a {@link TailedList}
* @param the type of the element
* @return the {@link TailedList} containing the provided element
*/
public static Sequence of(T element) {
return TailedList.of((T[]) new Object[]{element});
}
/**
* Create a new {@link TailedList} containing all the elements provided in the order they were provided.
*
* @param elements the elements to wrap in a {@link TailedList}
* @param the type of the elements
* @return the {@link TailedList} containing the provided elements
*/
@SafeVarargs
public static Sequence of(T...elements) {
return ofAll(Iterator.of(elements));
}
/**
* Create a new {@link TailedList} containing all the elements provided in the order they were provided.
*
* @param iterable the elements to wrap in a {@link TailedList}
* @param the type of the elements
* @return the {@link TailedList} containing the provided elements
*/
public static Sequence ofAll(Iterable extends T> iterable) {
TailedList reversed = (TailedList) TailedList.EMPTY;
for (T element : iterable) {
reversed = new TailedList<>(element, reversed);
}
return reversed.reverse();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy