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

io.jenetics.util.Buffer Maven / Gradle / Ivy

There is a newer version: 8.1.0
Show newest version
/*
 * Java Genetic Algorithm Library (jenetics-7.1.2).
 * Copyright (c) 2007-2023 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 io.jenetics.util;

import static java.lang.Math.min;
import static java.lang.System.arraycopy;

import java.util.Collection;
import java.util.Iterator;
import java.util.function.IntFunction;

import io.jenetics.internal.collection.Array;
import io.jenetics.internal.collection.ArrayMSeq;
import io.jenetics.internal.collection.ObjectStore;

/**
 * This class is a bounded buffer, which can store only a given amount of
 * elements. If the buffer is full, it starts overwriting previously
 * inserted elements at the beginning of the buffer. A full buffer
 * neither blocks the insertion of new elements, nor does it throw an exception.
 * 

* If you want to access the elements of the buffer, you have to take a * snapshot of the current content. This can be done with the * {@link #toArray()}, {@link #toArray(IntFunction)} and {@link #toSeq()} methods. * * @implNote * This class is not thread-safe. If two threads accesses the buffer * concurrently it must be synchronized externally. * * @author Franz Wilhelmstötter * @version 5.1 * @since 5.0 */ final class Buffer implements Iterable { private final Object[] _buffer; private int _index; private int _size; /** * Create a new ring buffer with the given {@code capacity}. * * @param capacity the buffer capacity * @throws NegativeArraySizeException if the given {@code capacity} is * negative */ private Buffer(final int capacity) { _buffer = new Object[capacity]; } /** * Return the capacity of {@code this} buffer. This is the number of elements * the buffer is able to store. * * @return the capacity of {@code this} buffer */ public int capacity() { return _buffer.length; } /** * Return the current number of elements {@code this} buffer holds. * * @return the current buffer size */ public int size() { return _size; } /** * Returns {@code true} if this buffer contains no elements. * * @return {@code true} if this buffer contains no elements */ public boolean isEmpty() { return _size == 0; } /** * Add a new element to the buffer. * * @param value the value to add */ public void add(final T value) { _buffer[_index] = value; if (++_index == _buffer.length) { _index = 0; } if (_size < _buffer.length) { ++_size; } } /** * Add the given {@code values} to the buffer. * * @param values the values to add * @throws NullPointerException if the given parameter is {@code null} */ @SafeVarargs public final void addAll(final T... values) { addAll(values, 0, values.length); } /** * Add the given values to the ring buffer. * * @param values the values being added to the ring buffer * @throws NullPointerException if the given parameter is {@code null} */ public void addAll(final Iterable values) { if (values instanceof Buffer buff) { final Object[] array = buff.toArray(); addAll(array, 0, array.length); } else if (values instanceof Collection coll) { final Object[] array = coll.toArray(); addAll(array, 0, array.length); } else { for (T value : values) { add(value); } } } /** * Add the {@code values} of the given array to {@code this} buffer. The * values are added at the given {@code start} index and the given * {@code length}. * * @param values the array which contains the values to add * @param start the start index of the source array * @param length the number of elements to copy * @throws IndexOutOfBoundsException if copying would cause access of data * outside array bounds * @throws ArrayStoreException if an element in the {@code value} array * could not be stored into the dest array because of a type mismatch */ private void addAll(final Object[] values, final int start, final int length) { if (length >= _buffer.length) { arraycopy( values, values.length - _buffer.length + start, _buffer, 0, _buffer.length ); _size = _buffer.length; _index = 0; } else { final int remaining = _buffer.length - _index; _size = min(_size + length, _buffer.length); if (length <= remaining) { arraycopy(values, start, _buffer, _index, length); _index += length; } else { arraycopy(values, start, _buffer, _index, remaining); arraycopy( values, remaining + start, _buffer, 0, length - remaining ); _index = length - remaining; } } } /** * Return an iterator from an element snapshot, taken with the {@link #toSeq()} * method. * * @return a new iterator from a snapshot of the current elements */ @Override public Iterator iterator() { return toSeq().iterator(); } /** * Return a snapshot of the current buffer content. * * @return the buffer snapshot */ public Object[] toArray() { return toArray(Object[]::new); } /** * Return a snapshot of the current buffer content. * * @param generator a function which produces a new array of the desired * type and the provided length * @param the element type of the resulting array * @return the buffer snapshot * @throws ArrayStoreException if an element in the {@code value} array * could not be stored into the dest array because of a type mismatch * @throws NullPointerException if the given {@code generator} is {@code null} */ public A[] toArray(final IntFunction generator) { final A[] result = generator.apply(_size); copyTo(result); return result; } private void copyTo(final A[] array) { assert array.length >= _size; if (_size < _buffer.length || _index == 0) { arraycopy(_buffer, 0, array, 0, _size); } else { arraycopy(_buffer, _index, array, 0, _buffer.length - _index); arraycopy(_buffer, 0, array, _buffer.length - _index, _index); } } /** * Return a snapshot of the current buffer content. * * @return the buffer snapshot */ public ISeq toSeq() { return isEmpty() ? ISeq.empty() : new ArrayMSeq(Array.of(ObjectStore.of(toArray()))).toISeq(); } @Override public String toString() { return toSeq().toString(); } /** * Create a new ring buffer with the given {@code capacity}. * * @param the element type * @param capacity the buffer capacity * @return a new ring buffer with the given capacity * @throws NegativeArraySizeException if the given {@code capacity} is * negative */ public static Buffer ofCapacity(final int capacity) { return new Buffer<>(capacity); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy