Basics of JavaFX sequence implementation
This article introduces the core classes used for
the JavaFX sequence implementation.
Note that these are internal classes and interfaces,
not a supported API.
This is purely for your information and edification:
The goal is to help you get a mental model of what is under the hood
,
and the approximate cost of the various sequence operations.
The Sequence interface
A JavaFX sequence type T[] is implemented
using classes that implement the Sequence<T> interface:
public interface Sequence<T> {
/** Number of items in sequence. */
public int size();
public T get(int position);
/** Copy elements from sequence into an array. */
public void toArray(int sourceOffset, int length, Object[] array, int destOffset);
/** Get this[startPos..<endPos]. */
public Sequence<T> getSlice(int startPos, int endPos);
/** What to return when an index is out-of-range. */
T getDefaultValue();
... a few more ...;
}
All (existing) Sequence concrete classes extend
AbstractSequence, which implements various utility methods:
public class AbstractSequence<T> implements Sequence<T> {
... default implementations of some methods ...
}
(Idea to consider: We might want to merge Sequence and
AbstractSequence. That would save a little bit of static
footprint. It should also slightly improve performance, since
virtual method calls are usually more efficient than interface
method calls, especially on not-so-smart VMs.)
The default
sequence implementation
is ArraySequence, which (surprise!) uses a Java array.
The following is highly simplified;
we'll go into ArraySequence in more detail in a later note.
public class ArraySequence<T> extends AbstractSequence<T> {
T[] array;
// Warning - this is simplified!
public T get(int position) {
if (position < 0 || position >= array.length)
return getDefaultValue();
return array[position];
}
...
}
There are a few special Sequence classes.
SingletonSequence is an optimization for single-item
sequences. IntRangeSequence (and the similar
NumberRangeSequence) are used to implement
[start..<end] ranges:
public class IntRangeSequence extends AbstractSequence<Integer> {
int start, step, size;
...;
public Integer get(int position) {
if (position < 0 || position >= size)
return getDefaultValue();
else
return (start + position * step);
}
}
Finally, SubSequence is used for sequence slices:
public class SubSequence<Integer> extends AbstractSequence<Integer> {
public T get(int position) {
if (position < 0 || position >= size)
return getDefaultValue();
else
return sequence.get(startPos + step * position);
}
...
}
The JavaFX type T[] is actually mapped to the
Java type Sequence<? extends T>,
where the
specifies a wildcard.
This is to support
co-variance of sequence types. You see this below.
? extends T
What about sequences of primitive
types, such as Integer,
which corresponds to the Java int type?
That deserves a separate article.
A named mutable variable is represented by SequenceVariable.
It stores the current value
,
which is a sequence value, of type Sequence<? extends T>.
class SequenceVariable<T> {
protected Sequence<? extends T> $value;
public Sequence<? extends T> getAsSequence() { return $value; }
public Sequence<? extends T> setAsSequence (Sequence newValue) {
$value = newValue;
... handle triggers and dependencies ...
}
public void insertBefore(T value, int position) {
replaceSlice(position, position, value);
}
public void replaceSlice(int startPos, int endPos, T newValue) {
... interesting stuff ...
}
public void replaceSlice(int startPos, int endPos, Sequence newValue) {
... interesting stuff ...
}
...
}
All of the sequence insert/delete/replace operations map down to either
replaceSlice(int startPos, int endPos, T newValue)
or replaceSlice(int startPos, int endPos, Sequence<? extends T> newValues), where the former can be viewed as optimizations of the latter.
These operations for updating sequence variables are interesting and tricky enough that they deserve separate articles JavaFX-sequence-updating and JavaFX-sequence-triggers.