Interface IPosition<T,​P extends IPosition<T,​P>>

  • Type Parameters:
    T - type of element held in the list
    All Superinterfaces:
    IPositionHolder<T,​P>, IPositionListener
    All Known Implementing Classes:
    IPositionBase, Position

    public interface IPosition<T,​P extends IPosition<T,​P>>
    extends IPositionHolder<T,​P>
    Represents a position in the list at the given index and with a span of 0 or 1 elements.

    Add/remove operations affect the index and span of this position depending on the anchor type of the position.

    Once the span becomes 0, no modifications to the list can change it to span 1 element.

    PositionAnchor.CURRENT - tracks a specific element at index when the position is instantiated. Adding elements before the position will shift the range down in the list. Removing elements before the position will shift the range up in the list. Removing elements which include the position's index will set its span to 0. The position is always available for adding/removing next/previous elements. The current element is only available when span is 1.

    PositionAnchor.PREVIOUS - tracks the previous element to the position from which it was instantiated. The span will be 0 if no previous element existed when it was instantiated (ie. at position 0) or was removed later.

    The index of this position reflects the position in the list previous to the position from which it was instantiated and the index is valid if span is 1 or index is >0. Relative offset <0 will be increased by 1 if span is 0 to reflect removal of previous element.

    This anchor position type is used for iterating positions in reverse since it ignores insertions into the list immediately before the current position.

    PositionAnchor.NEXT - tracks the next element to the position from which it was instantiated. The span will be 0 if no next element existed when it was instantiated (ie. at end of the list) or was removed later.

    The index of this position reflects the position in the list next to the position from which it was instantiated and the index is valid if span is 1 or index is <list.size(). Relative offset >0 will be reduced by 1 if span is 0 to reflect removal of next element.

    This anchor position type is used for iterating positions since it ignores insertions into the list immediately after the current position.

    All offset based operations on this position are operations on the list at index relative to this position's index and span, so offsets may be -ve or +ve as long as absolute index is >=0 and <list.size()

    NOTE: Offsets are affected by span being 0 or 1 and type of anchor for the position: Offset of 0 refers to the element of this position and is only available if this position span is 1.

    Offset <0 refer to the elements preceding the element at this position. For PositionAnchor.PREVIOUS If span is 0 then the offset is increased by 1 to reflect that there is no current element at this position.

    Offset >0 refer to the elements following the element at this position. If span is 0 then offset is reduced by 1 to reflect that there is no current element.

    PositionList iterator will iterate over list elements while elements are added or removed from the list without affecting count of the iteration as long as elements are only added immediately before or after the current position.

    This is not limited to adding 1 element. Each added element before or after the current position moves the previous/next element position in the list. The first addition is limited to relative offset of -1, 0 or 1 from current index if the addition is not to affect iteration.

    The following operations can insert anywhere in the previously inserted range.

    Deletions have no limitations. They can never cause new elements to be inserted after the next element position of the iterator so cannot cause iteration to continue on a newly added element.

    All this makes list manipulation while traversing it easier to write, debug and understand because all operations are relative to current position instead of a numeric index. In the code you see -1, 0, +1, for previous, current and next element references taking removal and addition of elements into account.

    PositionList adjusts all outstanding positions into its instance. Allowing getting multiple positions in the list before making modification, in order to track index of elements at those positions. If after modifications the position has 0 span, as reflected by its IPositionHolder.isValidElement() being false, then the element at that position was removed. Otherwise, getIndex() will return the current index of that element in the list. If there is no valid element will return the index of the position, which will be the next available element in the list.

    Index computations can be a real bug generator, throw inserting, deleting and traversing a list at the same time and you have a beast to debug and maintenance nightmare to look forward to. PositionList and Position instances make all that go away. That's why I wrote these classes so I don't have to write and debug the same error prone code for manipulating lists.

    • Method Detail

      • getIndex

        int getIndex​(int offset)
        Parameters:
        offset - offset to current position

        FIX: allow getIndex(offset) to return -1

        Returns:
        absolute index in list, even if this position is not valid, it will always be [-1, list.size()]
      • getPosition

        P getPosition​(int offset)
        Parameters:
        offset - index relative to current position, <0 previous elements, 0 means current, >0 following elements
        Returns:
        Position representing the index relative to current position, throws IllegalStateException if current position is not valid and given index == 0 throws IndexOutOfBoundsException if requested index results in absolute index <0 or >size() of the list

        NOTE: to avoid exceptions test if position has a valid index with isValidIndex()

      • invalidate

        void invalidate()
        Mark position as not valid may be useful for something. Invalidates current element with all side-effects of this state
      • isValidIndex

        boolean isValidIndex()
        Returns:
        true if index of this position is between 0 and size() of the list
      • get

        T get()
        Returns:
        get element at this position, throws IllegalStateException if current position is not valid or after last element of list
      • get

        T get​(int offset)
        Insert element at index
        Parameters:
        offset - relative to this position, absolute index [0, size()], if absolute index == size() then element is added at the end of the list. The latter is also considered an insert at size() index.
        Returns:
        element
      • getOrNull

        T getOrNull()
        Returns:
        get element at this position or null if no such thing
      • getOrNull

        @Nullable
        T getOrNull​(int offset)
        Insert element at index
        Parameters:
        offset - relative to this position, absolute index [0, size()], if absolute index == size() then element is added at the end of the list. The latter is also considered an insert at size() index.
        Returns:
        element or null if for some reason the index or position are not valid
      • getOrNull

        @Nullable
        <S extends T> S getOrNull​(java.lang.Class<S> elementClass)
        Get the requested class or null if element at position cannot be cast to this class
        Type Parameters:
        S - type of element
        Parameters:
        elementClass - class of element desired
        Returns:
        element of type or null
      • getOrNull

        @Nullable
        <S extends T> S getOrNull​(int offset,
                                  java.lang.Class<S> elementClass)
        Get the requested class or null if element at position cannot be cast to this class
        Type Parameters:
        S - type of element
        Parameters:
        offset - relative to this position, absolute index [0, size()], if absolute index == size() then element is added at the end of the list. The latter is also considered an insert at size() index.
        elementClass - class of element desired
        Returns:
        element of type or null
      • set

        void set​(T element)
        Parameters:
        element - to which to set the current element in the list throws IllegalStateException if current index is not valid

        If the current index is after the last element this will add the value to the end of the list treating as an insert, with corresponding updates to any positions that this would affect.

      • set

        T set​(int offset,
              T element)
        Set element at given index
        Parameters:
        offset - relative to this position, absolute index [0, size()], if absolute index == size() then element is added at the end of the list. The latter is considered an insert at the index.
        element - value to set at offset
        Returns:
        element value at that position before. If adding at end of list then null is always returned.
      • add

        boolean add​(T element)
        Parameters:
        element - to insert after the current position in the list, not at the end of the list as a regular List does. throws IllegalStateException if current index is not valid
        Returns:
        true
      • add

        boolean add​(int offset,
                    T element)
        Add element at position given by relative offset to current position.

        NOTE: The position of insert is changed, depending on what has happened to the elements around the current position since it was instantiated: if element at position was deleted then offset 0 and 1 have the same effect, insert element before next.

        0 will always insert before the current position, so add(0, item1) will insert before current position, which advances the position to keep up with the current element. Next add(0, item2) will insert item2 after item1.

        Parameters:
        offset - offset, can be negative. 0 means insert before current, 1 means after current, -1 means before previous
        element - to insert
        Returns:
        true
      • addAll

        boolean addAll​(@NotNull
                       java.util.Collection<T> elements)
      • addAll

        boolean addAll​(int offset,
                       @NotNull
                       java.util.Collection<T> elements)
      • remove

        T remove()
        Specified by:
        remove in interface IPositionHolder<T,​P extends IPosition<T,​P>>
        Returns:
        removed current element, throws IllegalStateException if current index is not valid or after last element of list
      • remove

        T remove​(int offset)
      • remove

        void remove​(int startOffset,
                    int endOffset)
      • maxOffset

        int maxOffset()
        Returns:
        max offset from current position
      • minOffset

        int minOffset()
        Returns:
        min offset from current position to 0
      • size

        int size()
      • isEmpty

        boolean isEmpty()
      • append

        boolean append​(T element)
      • indexOf

        P indexOf​(T o)
      • indexOf

        P indexOf​(int offset,
                  T o)
      • indexOf

        P indexOf​(@NotNull
                  java.util.function.Predicate<P> predicate)
      • indexOf

        P indexOf​(int offset,
                  @NotNull
                  java.util.function.Predicate<P> predicate)
      • lastIndexOf

        P lastIndexOf​(T o)
      • lastIndexOf

        P lastIndexOf​(@NotNull
                      java.util.function.Predicate<P> predicate)
      • lastIndexOf

        P lastIndexOf​(int offset,
                      T o)
      • lastIndexOf

        P lastIndexOf​(int offset,
                      @NotNull
                      java.util.function.Predicate<P> predicate)