package com.github.marschall.memoryfilesystem;
import java.util.AbstractList;
import java.util.Collections;
import java.util.List;
import java.util.RandomAccess;
/**
* A list made of two other lists.
*
* <p>An example usage for this is path relativization. Consider you have
* a list <code>["..", ".."]</code> and a list <code>["a", "b"]</code>
* and you want to create a new list <code>["..", "..", "a", "b"]</code>
* without having to allocate a full array.</p>
*
* <p>This list tries to automatically "defragment" itself. When a sublist
* is created in an index range that falls into only one list then a
* sublist of only that list and not the whole composite list is
* returned.</p>
*
* @param <E> the element type
*/
final class CompositeList<E> extends AbstractList<E> implements RandomAccess {
private final List<E> first;
private final List<E> second;
private CompositeList(List<E> first, List<E> second) {
this.first = first;
this.second = second;
}
@Override
public E get(int index) {
int firstSize = this.first.size();
if (index < firstSize) {
return this.first.get(index);
} else {
return this.second.get(index - firstSize);
}
}
@Override
public int size() {
return this.first.size() + this.second.size();
}
@Override
public List<E> subList(int fromIndex, int toIndex) {
int firstSize = this.first.size();
int size = this.size();
if (fromIndex == 0 && toIndex == size) {
return this;
}
if (toIndex == fromIndex) {
return Collections.emptyList();
}
if (toIndex - fromIndex == 1) {
return Collections.singletonList(this.get(fromIndex));
}
if (toIndex <= firstSize) {
if (fromIndex == 0 && toIndex == firstSize) {
return this.first;
} else {
return this.first.subList(fromIndex, toIndex);
}
} else if (fromIndex >= firstSize) {
if (fromIndex == firstSize && toIndex == size) {
return this.second;
} else {
return this.second.subList(fromIndex - firstSize, toIndex - firstSize);
}
} else {
return super.subList(fromIndex, toIndex);
}
}
static <E> List<E> create(List<E> first, List<E> second) {
if (first.isEmpty()) {
return second;
} else if (second.isEmpty()) {
return first;
} else {
return new CompositeList<>(first, second);
}
}
}