/* * Copyright 2015 McDowell * * 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 uk.kludje.experimental.collect.array; import uk.kludje.experimental.array.EmptyArrays; import java.util.*; abstract class AbstractArrayCollection<E> implements Collection<E> { protected Object[] elements = EmptyArrays.EMPTY_OBJECT_ARRAY; protected int start; protected int end; protected int version; @Override public Iterator<E> iterator() { return new MutableStoreIterator<>(this); } protected E at(int index) { int getAt = index + start; assertIndexInBounds(getAt); return (E) elements[getAt]; } protected void assertIndexInBounds(int offset) { Assert.that(offset >= start, "offset >= start", IndexOutOfBoundsException::new); Assert.that(offset < end, "offset < end", IndexOutOfBoundsException::new); } protected int getVersion() { return version; } protected int growSizeBy(int requiredCapacity) { assert requiredCapacity >= 0 : "requiredCapacity >= 0"; int size = size(); int standardIncrease = (size == 0) ? 8 : size; if (requiredCapacity > standardIncrease) { return requiredCapacity; } else { return standardIncrease; } } protected int indexOf(Object o) { for (int i = start; i < end; i++) { Object element = elements[i]; if (Objects.equals(element, o)) { return i - start; } } return -1; } protected Object removeIndex(int index) { int removeFrom = index + start; assertIndexInBounds(removeFrom); version++; Object removed = elements[removeFrom]; if (removeFrom == start) { elements[removeFrom] = null; start++; } else if (removeFrom == (end - 1)) { elements[removeFrom] = null; end--; } else { System.arraycopy(elements, removeFrom + 1, elements, removeFrom, end - removeFrom); end--; elements[end] = null; } return removed; } protected void clearElements() { Arrays.fill(elements, null); start = 0; end = 0; } @Override public boolean contains(Object o) { return indexOf(o) >= 0; } @Override public int size() { return end - start; } @Override public boolean isEmpty() { return end == start; } @Override public boolean remove(Object o) { int index = indexOf(o); if (index == -1) { return false; } return removeIndex(index) != null; } public boolean containsAll(Collection<?> c) { for (Object o : c) { if (contains(o)) { return true; } } return false; } public boolean removeAll(Collection<?> c) { boolean removed = false; for (Object o : c) { removed |= remove(o); } return removed; } public boolean retainAll(Collection<?> c) { boolean changed = false; for (Object o : c) { int idx = indexOf(o); if (idx >= 0) { changed = true; removeIndex(idx); } } return changed; } @Override public boolean addAll(Collection<? extends E> c) { boolean changed = false; for (E e : c) { changed |= add(e); } return changed; } public Object[] toArray() { return toArray(new Object[size()]); } public <T> T[] toArray(T[] a) { //noinspection SuspiciousSystemArraycopy System.arraycopy(elements, start, a, 0, end - start); return a; } @Override public String toString() { StringJoiner joiner = new StringJoiner(", ", "[", "]"); for (int i = start; i < end; i++) { joiner.add(Objects.toString(elements[i])); } return joiner.toString(); } }