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

org.jenetics.internal.collection.Array Maven / Gradle / Ivy

There is a newer version: 3.6.0
Show newest version
/*
 * Java Genetic Algorithm Library (jenetics-3.4.0).
 * Copyright (c) 2007-2016 Franz Wilhelmstötter
 *
 * 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.
 *
 * Author:
 *    Franz Wilhelmstötter ([email protected])
 */
package org.jenetics.internal.collection;

import static java.lang.String.format;
import static java.util.Objects.requireNonNull;

import java.io.Serializable;
import java.util.Collection;
import java.util.Iterator;

/**
 * Array implementation class. This class manages the actual array (store) and
 * the start index and the length.
 *
 * @param  the array element type
 * @author Franz Wilhelmstötter
 * @version 3.4
 * @since 3.4
 */
public final class Array implements Serializable {
	private static final long serialVersionUID = 1L;

	private final Store.Ref _store;
	private final int _start;
	private final int _length;

	/**
	 * Private primary constructor.
	 *
	 * @param store the store used by this array
	 * @param from the start index of the array
	 * @param until the end index of the array
	 */
	private Array(final Store.Ref store, final int from, final int until) {
		_store = requireNonNull(store);
		_start = from;
		_length = until - from;
	}

	/**
	 * Create a new array from the given store
	 *
	 * @param store the store used by this array
	 */
	private Array(final Store store) {
		this(Store.Ref.of(store), 0, store.length());
	}

	/**
	 * Return the underlying array store.
	 *
	 * @return the underlying array store
	 */
	public Store store() {
		return _store._value;
	}

	public void copyIfSealed() {
		_store.copyIfSealed();
	}

	/**
	 * Return a new sealed array instance. The underlying store is sealed
	 * as well, but not copied.
	 *
	 * @return a new sealed array
	 */
	public final Array seal() {
		return new Array<>(_store.seal(), _start, _length + _start);
	}

	/**
	 * Return the seal state of the array.
	 *
	 * @return {@code true} is the array is sealed, {@code false} otherwise
	 */
	public boolean isSealed() {
		return _store.isSealed();
	}

	/**
	 * Set the {@code value} at the given {@code index}. The array index is not
	 * checked.
	 *
	 * @param index the array index
	 * @param value the value to set
	 */
	public void set(final int index, final T value) {
		_store.set(index + _start, value);
	}

	/**
	 * Get the array value at the given {@code index}. The array index is not
	 * checked.
	 *
	 * @param index the array index
	 * @return the value at the given index
	 */
	public T get(final int index) {
		return _store.get(index + _start);
	}

	/**
	 * Return a new {@code Array} object with the given values appended.
	 *
	 * @since 3.4
	 *
	 * @param array the values to append
	 * @return a new {@code Array} object with the elements of
	 *         {@code this} array and the given {@code array} appended.
	 * @throws NullPointerException if the given {@code array} is {@code null}
	 */
	public Array append(final Array array) {
		final Array appended = newInstance(length() + array.length());
		for (int i = 0; i < _length; ++i) {
			appended.set(i, get(i));
		}
		for (int i = 0; i < array._length; ++i) {
			appended.set(i + _length, array.get(i));
		}

		return appended;
	}

	private Array newInstance(final int length) {
		return of(_store._value.newInstance(length));
	}

	/**
	 * Return a new {@code Array} with the given {@code values} appended.
	 *
	 * @since 3.4
	 *
	 * @param values the values to append
	 * @return a new {@code Array} with the elements of {@code this}
	 *        array and the given {@code values} appended.
	 * @throws NullPointerException if the given {@code values} iterable is
	 *         {@code null}
	 */
	public Array append(final Iterable values) {
		final int size = size(values);
		final Array array = newInstance(_length + size);

		for (int i = 0; i < _length; ++i) {
			array.set(i, get(i));
		}

		final Iterator it = values.iterator();
		for (int i = 0; i < size; ++i) {
			array.set(_length + i, it.next());
		}

		return array;
	}

	/**
	 * Return a new {@code Array} with the given {@code values} prepended.
	 *
	 * @since 3.4
	 *
	 * @param values the values to prepend
	 * @return a new {@code Array} with the elements of {@code this}
	 *        array and the given {@code values} appended.
	 * @throws NullPointerException if the given {@code values} iterable is
	 *         {@code null}
	 */
	public Array prepend(final Iterable values) {
		final int size = size(values);
		final Array array = newInstance(_length + size);

		final Iterator it = values.iterator();
		for (int i = 0; i < size; ++i) {
			array.set(i, it.next());
		}

		for (int i = 0; i < _length; ++i) {
			array.set(size + i, get(i));
		}

		return array;
	}

	private static int size(final Iterable values) {
		int size = 0;
		if (values instanceof Collection) {
			size = ((Collection)values).size();
		} else {
			final Iterator it = values.iterator();
			while (it.hasNext()) {
				++size;
				it.next();
			}
		}

		return size;
	}

	/**
	 * Return the array length.
	 *
	 * @return the array length
	 */
	public int length() {
		return _length;
	}

	/**
	 * Return a copy of this array.
	 *
	 * @return a copy of this array
	 */
	public Array copy() {
		return new Array<>(_store.copy(_start, _length + _start));
	}

	/**
	 * Return a new array slice starting with the {@code from} index.
	 *
	 * @param from the start index
	 * @return a new array slice
	 * @throws ArrayIndexOutOfBoundsException if the index is out of bounds.
	 */
	public Array slice(final int from) {
		return slice(from, length());
	}

	/**
	 * Return a new array slice starting with the {@code from} index and
	 * {@code until} index.
	 *
	 * @param from the start index
	 * @param until the end index
	 * @return a new array slice
	 * @throws ArrayIndexOutOfBoundsException if the indexes are out of bounds.
	 */
	public Array slice(final int from, final int until) {
		checkIndex(from, until);
		return new Array<>(_store, from + _start, until + _start);
	}

	/**
	 * Check the given array {@code index}
	 *
	 * @param index the index to check
	 * @throws ArrayIndexOutOfBoundsException if the given index is not in the
	 *         valid range.
	 */
	public void checkIndex(final int index) {
		if (index < 0 || index >= length()) {
			throw new ArrayIndexOutOfBoundsException(format(
				"Index %s is out of bounds [0, %s)", index, length()
			));
		}
	}

	/**
	 * Check the given {@code from} and {@code until} indices.
	 *
	 * @param from the from index, inclusively.
	 * @param until the until index, exclusively.
	 * @throws ArrayIndexOutOfBoundsException if the given index is not in the
	 *         valid range.
	 */
	public final void checkIndex(final int from, final int until) {
		if (from > until) {
			throw new ArrayIndexOutOfBoundsException(format(
				"fromIndex(%d) > toIndex(%d)", from, until
			));
		}
		if (from < 0 || until > length()) {
			throw new ArrayIndexOutOfBoundsException(format(
				"Invalid index range: [%d, %s)", from, until
			));
		}
	}

	/**
	 * Create a new {@code Array} from the given object store.
	 *
	 * @param store the object store
	 * @param  the array type
	 * @return a new array with the given {@code store}
	 */
	public static  Array of(final Store store) {
		return new Array<>(store);
	}

	/**
	 * Create a new {@code Array} with the given length. The array is created
	 * with the default {@code ObjectStore} object.
	 *
	 * @param length the array length
	 * @param  the array type
	 * @return a new array with the given {@code length}
	 */
	public static  Array ofLength(final int length) {
		return new Array(ObjectStore.ofLength(length));
	}


	/**
	 * Minimal interface for accessing an underlying array structure.
	 *
	 * @param  the array element type
	 * @author Franz Wilhelmstötter
	 * @version 3.4
	 * @since 3.4
	 */
	public interface Store {

		/**
		 * Write the given {@code value} at the given {@code index} to the
		 * underlying array structure.
		 *
		 * @param index the array index
		 * @param value the value to set
		 */
		public void set(final int index, final T value);

		/**
		 * Return the value at the given array {@code index}.
		 *
		 * @param index the array index
		 * @return the value at the given index
		 */
		public T get(final int index);

		/**
		 * Return the length of the array {@code Store}.
		 *
		 * @return the array store length
		 */
		public int length();

		/**
		 * Return a new array {@code Store} with the copied portion of the
		 * underlying array.
		 *
		 * @param from the start index of the copied array
		 * @param until the end index of the copied array
		 * @return a new copy of the given range
		 */
		public Store copy(final int from, final int until);

		/**
		 * Return a new array {@code Store} with the copied portion of the
		 * underlying array.
		 *
		 * @param from the start index of the copied array
		 * @return a new copy of the given range
		 */
		public default Store copy(final int from) {
			return copy(from, length());
		}

		/**
		 * Return a new array {@code Store} copy.
		 *
		 * @return a new array {@code Store} copy
		 */
		public default Store copy() {
			return copy(0, length());
		}

		/**
		 * Return a new {@code Store} of the same type and the given length.
		 *
		 * @param length the length of the new store
		 * @return a new {@code Store} of the same type and the given length.
		 * @throws NegativeArraySizeException if the length is smaller than zero
		 */
		public Store newInstance(final int length);

		/**
		 * Mutable reference of an underlying array {@code Store}.
		 *
		 * @param  the array element type
		 * @author Franz Wilhelmstötter
		 * @version 3.4
		 * @since 3.4
		 */
		public static final class Ref implements Store, Serializable {
			private static final long serialVersionUID = 1L;

			private Store _value;
			private boolean _sealed;

			/**
			 * Private primary constructor.
			 *
			 * @param value the array store which is referenced
			 * @param sealed the sealed flag of the reference
			 */
			private Ref(final Store value, final boolean sealed) {
				_value = value;
				_sealed = sealed;
			}

			public Ref seal() {
				_sealed = true;
				return new Ref<>(_value, true);
			}

			public boolean isSealed() {
				return _sealed;
			}

			@Override
			public void set(final int index, final T value) {
				copyIfSealed();
				_value.set(index, value);
			}

			void copyIfSealed() {
				if (_sealed) {
					_value = copy();
					_sealed = false;
				}
			}

			@Override
			public T get(final int index) {
				return _value.get(index);
			}

			@Override
			public int length() {
				return _value.length();
			}

			@Override
			public Store copy(final int from, final int until) {
				return _value.copy(from, until);
			}

			@Override
			public Store newInstance(final int length) {
				return _value.newInstance(length);
			}

			public static  Ref of(final Store value) {
				return new Ref<>(requireNonNull(value), false);
			}
		}

	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy