net.algart.arrays.AbstractObjectArray Maven / Gradle / Ivy
Show all versions of algart Show documentation
/*
* The MIT License (MIT)
*
* Copyright (c) 2007-2024 Daniel Alievsky, AlgART Laboratory (http://algart.net)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package net.algart.arrays;
import java.util.Objects;
/**
* Implementation of almost all basic functions of {@link ObjectArray} interface.
* The only {@link ObjectArray#get(long)} method is not defined in this class;
* all other methods are implemented via calls of {@link ObjectArray#get(long)}.
*
* @param the generic type of array elements.
* @author Daniel Alievsky
*/
public abstract class AbstractObjectArray extends AbstractArray implements ObjectArray {
final boolean underlyingArraysAreParallel;
final Class elementType;
/**
* Creates an array with the given initial capacity and length.
*
* The underlyingArraysAreParallel
informs whether the passed underlying arrays (if they exist)
* are "parallel" to this one and to each other.
* Intuitively, it means that every element #k
of this array is connected (for example, depends on)
* the elements #k
(of, maybe, #k±i
, where i
is little) of the
* underlying arrays.
* Precisely, this argument affects the following in this implementation:
*
*
* - If it is
true
, then all passed underlying arrays
* if underlyingArrays.length>1
)
* must have identical length — in other case, this constructor throws {@link SizeMismatchException}.
*
*
* - If it is
true
, then
* - {@link #loadResources(ArrayContext context, long fromIndex, long toIndex)},
* - {@link #flushResources(ArrayContext context, long fromIndex, long toIndex, boolean forcePhysicalWriting)}
* and
* - {@link #freeResources(ArrayContext context, long fromIndex, long toIndex, boolean forcePhysicalWriting)}
*
*
methods call
* {@link #loadResources(ArrayContext context)},
* {@link #flushResources(ArrayContext context, boolean forcePhysicalWriting)} and
* {@link #freeResources(ArrayContext context, boolean forcePhysicalWriting)}
* methods for the corresponding {@link #subArray subarrays} of all underlying
* arrays. If this argument is false
, then
* - {@link #loadResources(ArrayContext context, long fromIndex, long toIndex)} does nothing,
* - {@link #flushResources(ArrayContext context, long fromIndex, long toIndex, boolean forcePhysicalWriting)}
* and {@link #freeResources(ArrayContext context, long fromIndex, long toIndex, boolean forcePhysicalWriting)}
* methods ignore their
fromIndex
/ toIndex
arguments and call
* {@link #loadResources(ArrayContext context)},
* {@link #flushResources(ArrayContext context, boolean forcePhysicalWriting)} and
* {@link #freeResources(ArrayContext context, boolean forcePhysicalWriting)}
* methods for original underlying arrays (not their subarrays).
*
Of course, if you specify underlyingArraysAreParallel=false
, you can override
* {@link #loadResources(ArrayContext context, long fromIndex, long toIndex)},
* {@link #flushResources(ArrayContext context, long fromIndex, long toIndex, boolean forcePhysicalWriting)}
* and {@link #freeResources(ArrayContext context, long fromIndex, long toIndex, boolean forcePhysicalWriting)}
* methods and offer better implementations for subarrays,
* for example, that will work with suitable regions of the underlying arrays.
*
*
*
* This array is not {@link #isNew() new} by default.
* This is correct usually, because this class is often used
* for creating a view of another data. However, if the instance
* of this class does not depend on any other data sources,
* you may call {@link #setNewStatus(boolean) setNewStatus(true)} in
* the constructor of your subclass.
*
*
The created array never has new-read-only-view status:
* {@link Array#isNewReadOnlyView()} method always returns false
in this class and its inheritors.
*
* @param elementType the {@link #elementType() element type} of this array.
* @param initialCapacity initial capacity of the array.
* @param initialLength initial length of the array.
* @param underlyingArraysAreParallel whether the underlying arrays are "parallel" to this.
* @param underlyingArrays see the same argument of
* {@link AbstractArray#AbstractArray(long, long, Array...)}.
* @throws NullPointerException if underlyingArrays
argument or some
* of underlyingArrays[k]
* elements is {@code null}.
* @throws IllegalArgumentException if the initialCapacity
or initialLength
arguments
* are illegal (negative, or capacity < length).
* @throws SizeMismatchException if underlyingArraysAreParallel=true
,
* underlyingArrays.length>1
and some of passed arrays
* have different lengths.
*/
protected AbstractObjectArray(
Class elementType, long initialCapacity, long initialLength,
boolean underlyingArraysAreParallel, Array... underlyingArrays) {
super(initialCapacity, initialLength, underlyingArrays);
Objects.requireNonNull(elementType, "Null elementType argument");
if (initialLength < 0) {
throw new IllegalArgumentException("Negative initialLength argument");
}
if (initialCapacity < 0) {
throw new IllegalArgumentException("Negative initialCapacity argument");
}
if (initialLength > initialCapacity) {
throw new IllegalArgumentException("initialCapacity argument must not be less than initialLength");
}
Objects.requireNonNull(underlyingArrays, "Null underlyingArrays argument");
this.underlyingArraysAreParallel = underlyingArraysAreParallel;
long len = -1;
for (int k = 0; k < underlyingArrays.length; k++) {
Objects.requireNonNull(underlyingArrays[k], "Null underlyingArrays[" + k + "] argument");
if (underlyingArraysAreParallel) {
if (k == 0) {
len = underlyingArrays[k].length();
} else if (underlyingArrays[k].length() != len) {
throw new SizeMismatchException("underlyingArrays[" + k
+ "].length() and underlyingArrays[0].length() mismatch");
}
}
}
this.elementType = elementType;
}
/**
* Equivalent to the constructor {@link #AbstractObjectArray(Class, long, long, boolean, Array...)},
* where both initialCapacity
and initialLength
arguments are equal to
* initialCapacityAndLength
.
*
* @param elementType the {@link #elementType() element type} of this array.
* @param initialCapacityAndLength initial capacity and length of the array.
* @param underlyingArraysAreParallel see {@link
* #AbstractObjectArray(Class, long, long, boolean, Array...)}.
* @param underlyingArrays see {@link
* #AbstractObjectArray(Class, long, long, boolean, Array...)}.
* @throws NullPointerException if underlyingArrays
argument or some
* of underlyingArrays[k]
* elements is {@code null}.
* @throws IllegalArgumentException if initialCapacityAndLength
argument is negative.
* @throws SizeMismatchException if underlyingArraysAreParallel=true
,
* underlyingArrays.length>1
and some of passed arrays
* have different lengths.
*/
protected AbstractObjectArray(
Class elementType, long initialCapacityAndLength,
boolean underlyingArraysAreParallel, Array... underlyingArrays) {
this(elementType, initialCapacityAndLength, initialCapacityAndLength,
underlyingArraysAreParallel, underlyingArrays);
}
@Override
public Class elementType() {
return elementType;
}
@Override
public Class extends ObjectArray> type() {
return InternalUtils.cast(ObjectArray.class);
}
@Override
public Class extends UpdatableObjectArray> updatableType() {
return InternalUtils.cast(UpdatableObjectArray.class);
}
@Override
public Class extends MutableObjectArray> mutableType() {
return InternalUtils.cast(MutableObjectArray.class);
}
/**
* This implementation is based on a loop of calls of {@link #get(long)} method.
* Please override this method if it's possible to perform the same task more efficiently
* than such a loop.
*
* @param arrayPos starting position in this AlgART array.
* @param destArray the target Java array.
* @param destArrayOffset starting position in the target Java array.
* @param count the number of elements to be copied.
* @throws NullPointerException if destArray
argument is {@code null}.
* @throws IllegalArgumentException if destArray
argument is not an array.
* @throws IndexOutOfBoundsException if copying would cause access of data outside this array or target array.
* @throws ArrayStoreException if destArray
element type mismatches with this array
* {@link #elementType()}.
* @throws ClassCastException if destArray
element type mismatches with this array
* {@link #elementType()}
* (both this and ArrayStoreException
are possible,
* depending on implementation).
*/
@Override
public void getData(long arrayPos, Object destArray, int destArrayOffset, int count) {
Objects.requireNonNull(destArray, "Null destArray argument");
Object[] a = (Object[]) destArray;
if (count < 0) {
throw new IllegalArgumentException("Negative number of loaded elements (" + count + ")");
}
if (arrayPos < 0) {
throw rangeException(arrayPos);
}
if (arrayPos > length - count) {
throw rangeException(arrayPos + count - 1);
}
for (long arrayPosMax = arrayPos + count; arrayPos < arrayPosMax; arrayPos++, destArrayOffset++) {
a[destArrayOffset] = get(arrayPos);
}
}
/**
* This implementation calls {@link #getData(long, Object, int, int)}
* with corresponding arguments.
*
* @param arrayPos starting position in this AlgART array.
* @param destArray the target Java array.
* @throws NullPointerException if destArray
argument is {@code null}.
* @throws IllegalArgumentException if destArray
argument is not an array.
* @throws IndexOutOfBoundsException if arrayPos
is out of range 0..length()-1
.
* @throws ArrayStoreException if destArray
element type mismatches with this array
* {@link #elementType()}.
* @throws ClassCastException if destArray
element type mismatches with this array
* {@link #elementType()}
* (both this and ArrayStoreException
are possible,
* depending on implementation).
*/
@Override
public void getData(long arrayPos, Object destArray) {
Objects.requireNonNull(destArray, "Null destArray argument");
if (arrayPos < 0 || arrayPos > length) {
throw rangeException(arrayPos);
}
int count = ((Object[]) destArray).length;
if (count > length - arrayPos) {
count = (int) (length - arrayPos);
}
getData(arrayPos, destArray, 0, count);
}
/**
* This implementation returns get(index)
.
*
* @param index index of element to get.
* @return the element at the specified position in this array.
* @throws IndexOutOfBoundsException if index
is out of range 0..length()-1
.
*/
@Override
public Object getElement(long index) {
return get(index);
}
public ObjectArray cast(Class elementType) {
Class> desiredType = InternalUtils.cast(elementType);
if (!desiredType.isAssignableFrom(this.elementType)) {
throw new ClassCastException("Illegal desired element type " + elementType + " for " + this);
}
return InternalUtils.cast(this);
}
/**
* This implementation returns new instance of {@link AbstractObjectArray} with the same memory model
* and underlying arrays, that were passed to the constructor of this instance,
* and with overridden methods {@link #get(long)} and
* {@link #getData(long arrayPos, Object destArray, int destArrayOffset, int count)},
* calling the same methods of this instance with corresponding corrections of the arguments.
*
* The returned instance also have overridden methods {@link #loadResources(ArrayContext, long, long)},
* {@link #flushResources(ArrayContext, long, long, boolean)} and
* {@link #freeResources(ArrayContext, long, long, boolean)},
* that also call the same methods of this instance with corresponding correction of their fromIndex
* argument.
*
*
The returned instance also have overridden method {@link #isLazy()},
* that just calls the same methods of this instance with the same arguments.
*
* @param fromIndex low endpoint (inclusive) of the subarray.
* @param toIndex high endpoint (exclusive) of the subarray.
* @return a view of the specified range within this array.
* @throws IndexOutOfBoundsException for illegal fromIndex and toIndex
* (fromIndex < 0 || toIndex > length() || fromIndex > toIndex).
*/
@Override
public Array subArray(long fromIndex, long toIndex) {
checkSubArrayArguments(fromIndex, toIndex);
final AbstractObjectArray parent = this;
final long offset = fromIndex;
return new AbstractObjectArray<>(elementType, toIndex - fromIndex,
underlyingArraysAreParallel, underlyingArrays) {
@Override
public E get(long index) {
if (index < 0 || index >= length) {
throw rangeException(index);
}
return parent.get(offset + index);
}
@Override
public long indexOf(long lowIndex, long highIndex, E value) {
if (lowIndex < 0) {
lowIndex = 0;
}
if (highIndex > length) {
highIndex = length;
}
if (highIndex <= lowIndex) {
// this check guarantees that overflow is impossible below:
// offset + lowIndex <= offset + highIndex <= offset + length = toIndex <= Long.MAX_VALUE
return -1;
}
long result = parent.indexOf(offset + lowIndex, offset + highIndex, value);
return result == -1 ? -1 : result - offset;
}
@Override
public long lastIndexOf(long lowIndex, long highIndex, E value) {
if (lowIndex < 0) {
lowIndex = 0;
}
if (highIndex > length) {
highIndex = length;
}
if (highIndex <= lowIndex) {
// this check guarantees that overflow is impossible below:
// offset + lowIndex <= offset + highIndex <= offset + length = toIndex <= Long.MAX_VALUE
return -1;
}
long result = parent.lastIndexOf(offset + lowIndex, offset + highIndex, value);
return result == -1 ? -1 : result - offset;
}
@Override
public void getData(long arrayPos, Object destArray, int destArrayOffset, int count) {
if (count < 0) {
throw new IllegalArgumentException("Negative number of loaded elements (" + count + ")");
}
if (arrayPos < 0) {
throw rangeException(arrayPos);
}
if (arrayPos > length - count) {
throw rangeException(arrayPos + count - 1);
}
parent.getData(offset + arrayPos, destArray, destArrayOffset, count);
}
@Override
public boolean isLazy() {
return parent.isLazy();
}
@Override
protected void loadResources(ArrayContext context, long fromIndex, long toIndex) {
parent.loadResources(context, offset + fromIndex, offset + toIndex);
}
@Override
protected void flushResources(
ArrayContext context, long fromIndex, long toIndex,
boolean forcePhysicalWriting) {
parent.flushResources(context, offset + fromIndex, offset + toIndex, forcePhysicalWriting);
}
@Override
protected void freeResources(
ArrayContext context, long fromIndex, long toIndex,
boolean forcePhysicalWriting) {
parent.freeResources(context, offset + fromIndex, offset + toIndex, forcePhysicalWriting);
}
};
}
@Override
public DataObjectBuffer buffer(DataBuffer.AccessMode mode, long capacity) {
return InternalUtils.cast(super.buffer(mode, capacity));
}
@Override
public DataObjectBuffer buffer(DataBuffer.AccessMode mode) {
return InternalUtils.cast(super.buffer(mode));
}
@Override
public DataObjectBuffer buffer(long capacity) {
return InternalUtils.cast(super.buffer(capacity));
}
@Override
public DataObjectBuffer buffer() {
return InternalUtils.cast(super.buffer());
}
public abstract E get(long index);
/**
* This implementation is based on a loop of calls of {@link #get(long)} method
* from index max(lowIndex,0)
until index min({@link #length()},highIndex)-1
.
* Please override this method if it's possible to perform the same task more efficiently
* than such a loop.
*
* @param lowIndex the low index in the array for search (inclusive).
* @param highIndex the high index in the array for search (exclusive).
* @param value the value to be found.
* @return the index of the first occurrence of this value in this array
* in range lowIndex<=index<highIndex
,
* or -1
if this value does not occur in this range.
*/
public long indexOf(long lowIndex, long highIndex, E value) {
long k = Math.max(lowIndex, 0);
long n = Math.min(length(), highIndex);
if (value == null) {
for (; k < n; k++) {
if (get(k) == null) {
return k;
}
}
} else {
for (; k < n; k++) {
if (value.equals(get(k))) {
return k;
}
}
}
return -1;
}
/**
* This implementation is based on a loop of calls of {@link #get(long)} method
* from index min({@link #length()},highIndex)-1
back until index max(lowIndex,0)
.
* Please override this method if it's possible to perform the same task more efficiently
* than such a loop.
*
* @param lowIndex the low index in the array for search (inclusive).
* @param highIndex the high index in the array for search (exclusive).
* @param value the value to be found.
* @return the index of the last occurrence of this value in this array
* in range lowIndex<=index<highIndex
,
* or -1
if this value does not occur in this range.
*/
public long lastIndexOf(long lowIndex, long highIndex, E value) {
long k = Math.min(length(), highIndex);
// warning: highIndex-1 can be invalid value Long.MAX_VALUE
long low = Math.max(lowIndex, 0);
if (value == null) {
for (; k > low; ) {
if (get(--k) == null) {
return k;
}
}
} else {
for (; k > low; ) {
if (value.equals(get(--k))) {
return k;
}
}
}
return -1;
}
/**
* This implementation returns true
.
* Should be overridden if the inheritor is mutable.
*
* @return true
if this instance is immutable.
*/
@Override
public boolean isImmutable() {
return true;
}
/**
* This implementation returns true
.
* Should be overridden if the inheritor is resizable
*
* @return true
if this instance is unresizable.
*/
@Override
public boolean isUnresizable() {
return true;
}
/**
* This implementation does nothing.
*
* @throws UnallowedMutationError never in this implementation.
*/
@Override
public void checkUnallowedMutation() throws UnallowedMutationError {
}
/**
* This implementation calls {@link #asImmutable()} and returns its result.
*
* @return a trusted immutable view of this array (or a reference to this array if it is already
* trusted immutable).
*/
@Override
public ObjectArray asTrustedImmutable() {
return asImmutable();
}
/**
* This implementation returns this object.
* Should be overridden if the inheritor is mutable.
*
* @return a copy-on-next-write view of this array (or a reference to this array if it is
* immutable or already copy-on-next-write).
*/
@Override
public Array asCopyOnNextWrite() {
return this;
}
/**
* This implementation returns false
.
* Should be overridden if the inheritor is mutable.
*
* @return true
if this array is in copy-on-next-write mode
*/
@Override
public boolean isCopyOnNextWrite() {
return false;
}
/**
* This implementation returns this object.
* Should be overridden if the inheritor is mutable.
*
* @return an immutable view of this array (or a reference to this array if it is immutable).
*/
@Override
public ObjectArray asImmutable() {
return this;
}
@Override
public MutableObjectArray mutableClone(MemoryModel memoryModel) {
return InternalUtils.cast(super.mutableClone(memoryModel));
}
@Override
public UpdatableObjectArray updatableClone(MemoryModel memoryModel) {
return InternalUtils.cast(super.updatableClone(memoryModel));
}
@SuppressWarnings("unchecked")
public E[] ja() {
return (E[]) super.ja();
}
/**
* This implementation calls
* {@link #loadResources(ArrayContext, long, long) loadResources(context, 0, length())}.
*
* @param context the context of execution; can be {@code null}, then it will be ignored.
*/
@Override
public void loadResources(ArrayContext context) {
loadResources(context, 0, length());
}
/**
* This implementation calls
* {@link #flushResources(ArrayContext, long, long, boolean)
* flushResources(context, 0, length(), forcePhysicalWriting)}.
*
* @param context the context of execution; can be {@code null}, then it will be ignored.
* @param forcePhysicalWriting is it necessary to try forcing physical writing all associated resources
* to the external device.
*/
@Override
public void flushResources(ArrayContext context, boolean forcePhysicalWriting) {
flushResources(context, 0, length(), forcePhysicalWriting);
}
/**
* This implementation calls
* {@link #freeResources(ArrayContext, long, long, boolean)
* freeResources(context, 0, length()), forcePhysicalWriting)}.
*
* @param context the context of execution; can be {@code null}, then it will be ignored.
* @param forcePhysicalWriting is it necessary to try forcing physical writing all associated resources
* to the external device.
*/
@Override
public void freeResources(ArrayContext context, boolean forcePhysicalWriting) {
freeResources(context, 0, length(), forcePhysicalWriting);
}
/**
* This method implements all actions that should be performed by
* {@link #subArray subArray}(fromIndex, toIndex).{@link #loadResources(ArrayContext)
* loadResources}(context)
call.
* This default implementation calls {@link #loadResources(ArrayContext) loadResources(c)}
* (where c
is a necessary {@link ArrayContext#part(long, long, long) part} of the passed context)
* for the corresponding subarray
* of all underlying arrays, passed via the last argument of the constructor,
* if the underlyingArraysAreParallel
constructor argument was true
,
* or does nothing in other case.
*
* @param context the context of execution; can be {@code null}, then it will be ignored.
* @param fromIndex low endpoint (inclusive) of the subarray that should be loaded.
* @param toIndex high endpoint (exclusive) of the subarray that should be loaded.
* @throws IndexOutOfBoundsException for illegal fromIndex and toIndex
* (fromIndex < 0 || toIndex > length() || fromIndex > toIndex).
*/
protected void loadResources(ArrayContext context, long fromIndex, long toIndex) {
checkSubArrayArguments(fromIndex, toIndex);
if (underlyingArraysAreParallel) {
for (int k = 0; k < underlyingArrays.length; k++) {
underlyingArrays[k].subArray(fromIndex, toIndex).loadResources(
context == null ? null : context.part(k, k + 1, underlyingArrays.length));
}
}
}
/**
* This method implements all actions that should be performed by
* {@link #subArray subArray}(fromIndex, toIndex).{@link #flushResources(ArrayContext, boolean)
* flushResources(context, forcePhysicalWriting)}
call.
* This default implementation calls {@link #flushResources(ArrayContext, boolean)
* flushResources(c, forcePhysicalWriting)}
* (where c
is a necessary {@link ArrayContext#part(long, long, long) part} of the passed context)
* for the corresponding subarray of all underlying arrays, passed via the last argument of the constructor,
* if the underlyingArraysAreParallel
constructor argument was true
,
* or for original underlying arrays in other case
* (alike {@link AbstractArray#flushResources(ArrayContext, boolean)}).
*
* @param context the context of execution; can be {@code null}, then it will be ignored.
* @param fromIndex low endpoint (inclusive) of the subarray that should be flushed.
* @param toIndex high endpoint (exclusive) of the subarray that should be flushed.
* @param forcePhysicalWriting is it necessary to try forcing physical writing all associated resources
* to the external device.
* @throws IndexOutOfBoundsException for illegal fromIndex and toIndex
* (fromIndex < 0 || toIndex > length() || fromIndex > toIndex).
*/
protected void flushResources(ArrayContext context, long fromIndex, long toIndex, boolean forcePhysicalWriting) {
checkSubArrayArguments(fromIndex, toIndex);
if (underlyingArraysAreParallel) {
for (int k = 0; k < underlyingArrays.length; k++) {
underlyingArrays[k].subArray(fromIndex, toIndex).flushResources(
context == null ? null : context.part(k, k + 1, underlyingArrays.length),
forcePhysicalWriting);
}
} else {
super.flushResources(context, forcePhysicalWriting);
}
}
/**
* This method implements all actions that should be performed by
* {@link #subArray subArray}(fromIndex, toIndex).{@link #freeResources(ArrayContext, boolean)
* freeResources(context, forcePhysicalWriting)}
call.
* This default implementation calls {@link #freeResources(ArrayContext, boolean)
* freeResources(c, forcePhysicalWriting)}
* (where c
is a necessary {@link ArrayContext#part(long, long, long) part} of the passed context)
* for the corresponding subarray of all underlying arrays, passed via the last argument of the constructor,
* if the underlyingArraysAreParallel
constructor argument was true
,
* or for original underlying arrays in other case
* (alike {@link AbstractArray#freeResources(ArrayContext, boolean)}).
*
* @param context the context of execution; can be {@code null}, then it will be ignored.
* @param fromIndex low endpoint (inclusive) of the subarray that should be freed.
* @param toIndex high endpoint (exclusive) of the subarray that should be freed.
* @param forcePhysicalWriting is it necessary to try forcing physical writing all associated resources
* to the external device.
* @throws IndexOutOfBoundsException for illegal fromIndex and toIndex
* (fromIndex < 0 || toIndex > length() || fromIndex > toIndex).
*/
protected void freeResources(ArrayContext context, long fromIndex, long toIndex, boolean forcePhysicalWriting) {
checkSubArrayArguments(fromIndex, toIndex);
if (underlyingArraysAreParallel) {
for (int k = 0; k < underlyingArrays.length; k++) {
underlyingArrays[k].subArray(fromIndex, toIndex).freeResources(
context == null ? null : context.part(k, k + 1, underlyingArrays.length),
forcePhysicalWriting);
}
} else {
super.freeResources(context, forcePhysicalWriting);
}
}
@Override
public String toString() {
return "immutable AlgART array " + elementType.getName() + "[" + length + "]" + (underlyingArrays.length == 0 ? "" :
" based on " + underlyingArrays.length + " underlying array" + (underlyingArrays.length > 1 ? "s" : ""));
}
Object javaArrayInternal() {
return null;
}
int javaArrayOffsetInternal() {
return 0;
}
}