All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.d2ab.collection.doubles.ArrayDoubleList Maven / Gradle / Ivy

/*
 * Copyright 2016 Daniel Skogquist Åborg
 *
 * 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 org.d2ab.collection.doubles;

import org.d2ab.collection.Arrayz;
import org.d2ab.iterator.doubles.DoubleIterator;

import java.util.*;
import java.util.function.DoubleConsumer;
import java.util.function.DoublePredicate;
import java.util.function.DoubleUnaryOperator;

import static org.d2ab.util.Doubles.eq;

/**
 * A {@link DoubleList} backed by a double-array, supporting all {@link DoubleList}-methods by modifying and/or
 * replacing the underlying array.
 */
public class ArrayDoubleList extends DoubleList.Base implements RandomAccess {
	private double[] contents;
	private int size;

	private int modCount;

	/**
	 * Create a new empty mutable {@code ArrayDoubleList}. When possible, it's preferred to use
	 * {@link DoubleList#create()} instead.
	 *
	 * @return a new empty mutable {@code ArrayDoubleList}.
	 *
	 * @see DoubleList#create()
	 * @see #withCapacity(int)
	 * @since 2.1
	 */
	public static ArrayDoubleList create() {
		return new ArrayDoubleList();
	}

	/**
	 * Create a new mutable {@code ArrayDoubleList} initialized with a copy of the given contents. When possible, it's
	 * preferred to use {@link DoubleList#create(double...)} instead.
	 *
	 * @return a new mutable {@code ArrayDoubleList} initialized with a copy of the given contents.
	 *
	 * @see DoubleList#create(double...)
	 * @see #ArrayDoubleList(DoubleCollection)
	 * @since 2.1
	 */
	public static ArrayDoubleList create(double... xs) {
		return new ArrayDoubleList(xs);
	}

	/**
	 * @return a new mutable {@code ArrayDoubleList} with the given initial capacity.
	 *
	 * @since 2.1
	 */
	public static ArrayDoubleList withCapacity(int capacity) {
		return new ArrayDoubleList(capacity);
	}

	/**
	 * Create a new mutable {@code ArrayDoubleList}.
	 *
	 * @since 2.0
	 */
	private ArrayDoubleList() {
		this(10);
	}

	/**
	 * Create a new mutable {@code ArrayDoubleList} with the given initial capacity.
	 *
	 * @since 2.0
	 */
	private ArrayDoubleList(int capacity) {
		this.contents = new double[capacity];
	}

	public ArrayDoubleList(DoubleCollection xs) {
		this();
		addAllDoubles(xs);
	}

	public ArrayDoubleList(double[] xs) {
		this.contents = Arrays.copyOf(xs, xs.length);
		this.size = xs.length;
	}

	@Override
	public int size() {
		return size;
	}

	@Override
	public boolean isEmpty() {
		return size == 0;
	}

	@Override
	public void clear() {
		size = 0;
	}

	@Override
	public double[] toDoubleArray() {
		return Arrays.copyOfRange(contents, 0, size);
	}

	@Override
	public DoubleIterator iterator() {
		return listIterator();
	}

	@Override
	public DoubleListIterator listIterator(int index) {
		rangeCheckForAdd(index);
		return new ListIter(index);
	}

	@Override
	public void sortDoubles() {
		Arrays.sort(contents, 0, size);
	}

	@Override
	public int binarySearchExactly(double x) {
		return Arrays.binarySearch(contents, 0, size, x);
	}

	@Override
	public DoubleList subList(int from, int to) {
		return new SubList(from, to);
	}

	@Override
	public void replaceAllDoubles(DoubleUnaryOperator operator) {
		for (int i = 0; i < size; i++)
			contents[i] = operator.applyAsDouble(contents[i]);

		modCount++;
	}

	@Override
	public double getDouble(int index) {
		rangeCheck(index);
		return contents[index];
	}

	@Override
	public double setDouble(int index, double x) {
		rangeCheck(index);
		double previous = contents[index];
		contents[index] = x;

		modCount++;
		return previous;
	}

	@Override
	public void addDoubleAt(int index, double x) {
		rangeCheckForAdd(index);
		uncheckedAdd(index, x);

		modCount++;
	}

	@Override
	public double removeDoubleAt(int index) {
		rangeCheck(index);
		double previous = contents[index];
		uncheckedRemove(index);

		modCount++;
		return previous;
	}

	@Override
	public int lastIndexOfDoubleExactly(double x) {
		for (int i = size - 1; i >= 0; i--)
			if (contents[i] == x)
				return i;

		return -1;
	}

	@Override
	public int indexOfDoubleExactly(double x) {
		for (int i = 0; i < size; i++)
			if (contents[i] == x)
				return i;

		return -1;
	}

	@Override
	public Spliterator.OfDouble spliterator() {
		return Arrays.spliterator(contents, 0, size);
	}

	@Override
	public boolean addDoubleExactly(double x) {
		growIfNecessaryBy(1);
		contents[size++] = x;

		modCount++;
		return true;
	}

	@Override
	public boolean addDouble(double x, double precision) {
		return addDoubleExactly(x);
	}

	@Override
	public boolean addAllDoubles(double... xs) {
		if (xs.length == 0)
			return false;

		growIfNecessaryBy(xs.length);
		System.arraycopy(xs, 0, contents, size, xs.length);
		size += xs.length;

		modCount++;
		return true;
	}

	@Override
	public boolean addAllDoubles(DoubleCollection xs) {
		int xsSize = xs.size();
		if (xsSize == 0)
			return false;

		growIfNecessaryBy(xsSize);
		uncheckedAdd(size, xs, xsSize);
		size += xsSize;

		modCount++;
		return true;
	}

	@Override
	public boolean addAllDoublesAt(int index, double... xs) {
		if (xs.length == 0)
			return false;

		rangeCheckForAdd(index);
		growIfNecessaryBy(xs.length);
		System.arraycopy(contents, index, contents, index + xs.length, size - index);
		System.arraycopy(xs, 0, contents, index, xs.length);
		size += xs.length;

		modCount++;
		return true;
	}

	@Override
	public boolean addAllDoublesAt(int index, DoubleCollection xs) {
		int xsSize = xs.size();
		if (xsSize == 0)
			return false;

		rangeCheckForAdd(index);
		growIfNecessaryBy(xsSize);
		System.arraycopy(contents, index, contents, index + xsSize, size - index);
		uncheckedAdd(index, xs, xsSize);
		size += xsSize;

		modCount++;
		return true;
	}

	@Override
	public boolean removeDouble(double x, double precision) {
		for (int i = 0; i < size; i++)
			if (eq(contents[i], x, precision)) {
				uncheckedRemove(i);
				modCount++;
				return true;
			}

		return false;
	}

	@Override
	public boolean removeDoubleExactly(double x) {
		for (int i = 0; i < size; i++)
			if (contents[i] == x) {
				uncheckedRemove(i);
				modCount++;
				return true;
			}

		return false;
	}

	@Override
	public boolean containsDoubleExactly(double x) {
		for (int i = 0; i < size; i++)
			if (contents[i] == x)
				return true;

		return false;
	}

	@Override
	public boolean removeAllDoubles(double[] xs, double precision) {
		boolean modified = false;
		for (int i = 0; i < size; i++)
			if (Arrayz.contains(xs, contents[i], precision)) {
				uncheckedRemove(i--);
				modified = true;
			}

		if (modified)
			modCount++;
		return modified;
	}

	@Override
	public boolean removeAllDoublesExactly(double... xs) {
		boolean modified = false;
		for (int i = 0; i < size; i++)
			if (Arrayz.containsExactly(xs, contents[i])) {
				uncheckedRemove(i--);
				modified = true;
			}

		if (modified)
			modCount++;
		return modified;
	}

	@Override
	public boolean retainAllDoubles(double[] xs, double precision) {
		boolean modified = false;
		for (int i = 0; i < size; i++)
			if (!Arrayz.contains(xs, contents[i], precision)) {
				uncheckedRemove(i--);
				modified = true;
			}

		if (modified)
			modCount++;
		return modified;
	}

	@Override
	public boolean retainAllDoublesExactly(double... xs) {
		boolean modified = false;
		for (int i = 0; i < size; i++)
			if (!Arrayz.containsExactly(xs, contents[i])) {
				uncheckedRemove(i--);
				modified = true;
			}

		if (modified)
			modCount++;
		return modified;
	}

	@Override
	public boolean removeDoublesIf(DoublePredicate filter) {
		boolean modified = false;
		for (int i = 0; i < size; i++)
			if (filter.test(contents[i])) {
				uncheckedRemove(i--);
				modified = true;
			}

		if (modified)
			modCount++;
		return modified;
	}

	@Override
	public void forEachDouble(DoubleConsumer consumer) {
		for (int i = 0; i < size; i++)
			consumer.accept(contents[i]);
	}

	private void growIfNecessaryBy(int grow) {
		int newSize = size + grow;
		if (newSize > contents.length) {
			int newCapacity = newSize + (newSize >> 1);
			double[] copy = new double[newCapacity];
			System.arraycopy(contents, 0, copy, 0, size);
			contents = copy;
		}
	}

	private void uncheckedAdd(int index, double x) {
		growIfNecessaryBy(1);
		System.arraycopy(contents, index, contents, index + 1, size++ - index);
		contents[index] = x;
	}

	protected void uncheckedAdd(int index, DoubleIterable xs, int xsSize) {
		if (xs instanceof ArrayDoubleList) {
			System.arraycopy(((ArrayDoubleList) xs).contents, 0, contents, index, xsSize);
		} else {
			DoubleIterator iterator = xs.iterator();
			for (int i = 0; i < xsSize; i++)
				contents[i + index] = iterator.nextDouble();
		}
	}

	private void uncheckedRemove(int index) {
		System.arraycopy(contents, index + 1, contents, index, size-- - index - 1);
	}

	private void rangeCheck(int index) {
		if (index < 0 || index >= size)
			throw new IndexOutOfBoundsException("index: " + index + " size: " + size);
	}

	private void rangeCheckForAdd(int index) {
		if (index < 0 || index > size)
			throw new IndexOutOfBoundsException("index: " + index + " size: " + size);
	}

	private class ListIter implements DoubleListIterator {
		private int nextIndex;
		private int currentIndex;
		private final int from;
		private int to;
		private boolean addOrRemove;
		private boolean nextOrPrevious;

		private int expectedModCount = modCount;

		private ListIter(int index) {
			this(index, 0, size);
		}

		private ListIter(int index, int from, int to) {
			this.nextIndex = index;
			this.currentIndex = index - 1;
			this.from = from;
			this.to = to;
		}

		@Override
		public boolean hasNext() {
			return nextIndex < to - from;
		}

		@Override
		public double nextDouble() {
			checkForCoModification();
			if (!hasNext())
				throw new NoSuchElementException();
			addOrRemove = false;
			nextOrPrevious = true;
			return contents[(currentIndex = nextIndex++) + from];
		}

		@Override
		public boolean hasPrevious() {
			return nextIndex > 0;
		}

		@Override
		public double previousDouble() {
			checkForCoModification();
			if (!hasPrevious())
				throw new NoSuchElementException();
			addOrRemove = false;
			nextOrPrevious = true;
			return contents[(currentIndex = --nextIndex) + from];
		}

		@Override
		public int nextIndex() {
			return nextIndex;
		}

		@Override
		public int previousIndex() {
			return nextIndex - 1;
		}

		@Override
		public void remove() {
			checkForCoModification();
			if (addOrRemove)
				throw new IllegalStateException("add() or remove() called");
			if (!nextOrPrevious)
				throw new IllegalStateException("nextDouble() or previousDouble() not called");

			uncheckedRemove((nextIndex = currentIndex--) + from);

			addOrRemove = true;
			to--;
			modCount++;
			expectedModCount++;
		}

		@Override
		public void set(double x) {
			checkForCoModification();
			if (addOrRemove)
				throw new IllegalStateException("add() or remove() called");
			if (!nextOrPrevious)
				throw new IllegalStateException("nextDouble() or previousDouble() not called");

			contents[currentIndex + from] = x;

			modCount++;
			expectedModCount++;
		}

		@Override
		public void add(double x) {
			checkForCoModification();
			uncheckedAdd((currentIndex = nextIndex++) + from, x);

			addOrRemove = true;
			to++;
			modCount++;
			expectedModCount++;
		}

		private void checkForCoModification() {
			if (modCount != expectedModCount)
				throw new ConcurrentModificationException();
		}
	}

	private class SubList implements DoubleList {
		private int from;
		private int to;

		private SubList(int from, int to) {
			if (from < 0)
				throw new ArrayIndexOutOfBoundsException(from);
			if (to > size)
				throw new ArrayIndexOutOfBoundsException(to);
			this.from = from;
			this.to = to;
		}

		@Override
		public DoubleIterator iterator() {
			return listIterator();
		}

		@Override
		public DoubleListIterator listIterator(int index) {
			return new ArrayDoubleList.ListIter(index, from, to) {
				@Override
				public void add(double x) {
					super.add(x);
					ArrayDoubleList.SubList.this.to++;
				}

				@Override
				public void remove() {
					super.remove();
					ArrayDoubleList.SubList.this.to--;
				}
			};
		}

		public int size() {
			return to - from;
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy