/*
* Written by Gil Tene and Martin Thompson, and released to the public domain,
* as explained at http://creativecommons.org/publicdomain/zero/1.0/
*/
package org.ObjectLayout;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Constructor;
/**
* Supports the construction of a {@link StructuredArray}'s individual elements using a
* copy constructor, copying a source array's individual elements.
* <p>
* Expects the source {@link StructuredArray} to be provided as an opaque (Object) cookie
* in the {@link ConstructionContext} parameter passed to the
* {@link org.ObjectLayout.CopyCtorAndArgsProvider#getForContext(ConstructionContext)} method.
* <p>
* If the source element being copied is itself an instance of {@link StructuredArray}, the
* source element will be passed through as a contextCookie in the outgoing {@link org.ObjectLayout.CtorAndArgs},
* and will become the source array (the context cookie) in the next {@link StructuredArray}
* nesting level and it's calls to {@link CopyCtorAndArgsProvider#getForContext(ConstructionContext)}.
* <p>
* {@link CopyCtorAndArgsProvider} will attempt to efficiently recycle {@link org.ObjectLayout.CtorAndArgs}
* instances and to avoid per-element allocation of new {@link org.ObjectLayout.CtorAndArgs} instances by caching
* and recycling discarded instances.
*
* @param <T> type of the element occupying each array slot
*/
class CopyCtorAndArgsProvider<T> implements CtorAndArgsProvider<T> {
private static final MethodHandles.Lookup noLookup = null;
private final long sourceOffset;
private final Constructor<T> copyConstructor;
private final CtorAndArgs<T> ctorAndArgs;
/**
* Used to apply a copy constructor to a target array's elements, copying corresponding elements from a
* source array
*/
public CopyCtorAndArgsProvider(
final Class<T> elementClass) throws NoSuchMethodException {
this(noLookup, elementClass);
}
/**
* Used to apply a copy constructor to a target array's elements, copying corresponding elements from a
* source array
*/
public CopyCtorAndArgsProvider(
MethodHandles.Lookup lookup,
final Class<T> elementClass) {
this(lookup, elementClass, 0);
}
/**
* Used to apply a copy constructor to a target array's elements, copying corresponding elements from a
* source array, starting at a given offset
*
* @param sourceOffset The beginning index in the source from which to start copying
*/
public CopyCtorAndArgsProvider(
final Class<T> elementClass,
final long sourceOffset) {
this(noLookup, elementClass, sourceOffset);
}
/**
* Used to apply a copy constructor to a target array's elements, copying corresponding elements from a
* source array, starting at a given offset
*
* @param lookup The lookup object to use when resolving constructors
* @param elementClass The element class to which the copy constructor belongs
* @param sourceOffset The beginning index in the source from which to start copying
*/
public CopyCtorAndArgsProvider(
MethodHandles.Lookup lookup,
final Class<T> elementClass,
final long sourceOffset) {
this.sourceOffset = sourceOffset;
this.ctorAndArgs = new CtorAndArgs<>(lookup, elementClass, new Class[] {elementClass}, new Object[1]);
this.copyConstructor = ctorAndArgs.getConstructor(); // Remember it so we can overwrite back each time.
}
/**
* Get a {@link CtorAndArgs} instance to be used in copy-constructing a given element index in
* a {@link StructuredArray}. .
*
* @param context The construction context (index, containing array, etc.) of the element to be constructed.
* @return {@link CtorAndArgs} instance to used in element construction
*/
@Override
public CtorAndArgs<T> getForContext(final ConstructionContext context) {
// Find source array for this context:
@SuppressWarnings("unchecked")
StructuredArray<T> sourceArray = (StructuredArray<T>) context.getContextCookie();
long index = context.getIndex() + sourceOffset;
T sourceElement = sourceArray.get(index);
ctorAndArgs.setConstructor(copyConstructor);
// Set the source object for the copy constructor:
ctorAndArgs.getArgs()[0] = sourceElement;
// Set the cookie object to the source element. Will be passed on as the cookie object in the
// next context level if the sourceElement is a StructuredArray.
ctorAndArgs.setContextCookie(sourceElement);
return ctorAndArgs;
}
}