Class ArrayForest
Forest class.
ArrayForest is a data structure that implements Forest.
Any modifications to the ArrayForest are only applied to that instance in memory.
Under-After Coordinates
When a specific position in the forest needs to be defined for mutating operations such as move or insert, under-after
coordinates are used. (If operation addresses a specific row, the row ID is used instead.)
Under-after coordinates contain under value, which identifies the parent row of the
specified position (the depth and the subtree). If under is 0, the position is at the
top (root row).
The other parameter, after coordinate, defines the location of the inserted row amongst siblings -
the rows at the same depth under the same parent. If after is 0, it means that the position
should be the first under the specified parent.
Note: moving a row after itself, i.e. when the under coordinate is equal to the row's parent row
and the after coordinate is equal to the row itself, is allowed and does not change the position of the row.
Methods from this class don't not modify the forest stored in the database for a structure.
To make modifications of the structure's forest, apply forest changes with ForestSource.apply(ForestAction).
This class in not thread-safe.
- Author:
- Igor Sereda
- See Also:
-
Field Summary
-
Constructor Summary
ConstructorsConstructorDescriptionArrayForest(long row) Creates a singular tree.ArrayForest(LongList rows, IntList depths) ArrayForest(WritableLongList rows, WritableIntList depths, boolean reuseLists) Constructs a forest based on the given rows and depths.ArrayForest(Forest copyFrom) -
Method Summary
Modifier and TypeMethodDescriptionvoidvoidaddForestMutuallyExclusive(Forest forest, long under, long after) Adds a forest to this forest.booleanaddRow(long row, long under, long after) Adds a single row at the specified position.voidvoidclear()clone()booleancontainsRow(long row) Can be used to check if the forest contains a specific row.copy()Creates an exact copy of this forest.copySubforest(long row) copySubforestAtIndex(int k) static ForestensureImmutability(Forest forest) booleanFilters this forest by hiding rows that do not pass thefiltercondition.filterHardest(La<Long, ?> filter) Filters this forest by excluding rows that do not pass thefiltercondition.filterSoft(La<Long, ?> filter) Filters this forest by excluding rows that do not pass thefiltercondition.<T,C> C foldUpwards(ForestParentChildrenClosure<T, C> closure) This is a more generic version ofForest.visitParentChildrenUpwards(com.almworks.jira.structure.api.forest.raw.ForestParentChildrenVisitor)that allows you to effectively process the forest bottom-up, probably saving on memory allocation and search speed.LongArraygetChildren(long row) Creates an array with all direct sub-rows of the specified row.LongArraygetChildrenAtIndex(int index) Creates an array with all direct sub-rows of the row at the specified index.IntIteratorgetChildrenIndicesIterator(int index) Returns an iterator over indices of all direct sub-rows of the row at the specified index.intgetDepth(int index) Gets the depth of the row at the specified position in the forest.IntListReturns a non-modifiable list of depths, in the order the rows appear in the forest.static StringChecks whether RowTree invariants hold.longgetLastChild(long parent) Gets the last direct sub-row of the specified parent row.longgetLastChildByIndex(int parentIndex) Gets the last direct sub-row of the specified parent row.longgetNextSibling(long row) Gets the row that immediately follows the specified row in the list of children of the specified row's parent.longgetNextSiblingForIndex(int index) Gets the row that immediately follows the one with the given index in the list of children of its parent.intgetNextSiblingIndex(int index) Gets the index of the row that immediately follows the row at the given index in the list of children of its parent.longgetParent(long row) Gets the parent row of the specified row.intgetParentIndex(int index) Searches the forest for the index of a "parent row".LongArraygetParentPathForIndex(int index) Returns the path to the specified row without the row itself.LongArraygetPath(long row) Returns the path to the specified row - a sequence of rows that starts with a root row, ends with the specified row, and whereelement[i]is the parent row ofelement[i+1].LongArraygetPathForIndex(int idx) Similar toForest.getPath(long), returns the path to the row specified by index.intgetPathIndexAtDepth(int index, int depth) Given row at the specified index, traverses its "path" upwards - that is, looks for all parent rows up to the topmost root parent, and returns an index of the parent that has the specified depth.longgetPrecedingSibling(long row) Gets the row that immediately precedes the specified row in the list of children of the specified row's parent.longgetPrecedingSiblingForIndex(int index) Gets the row that immediately precedes the one with the given index in the list of children of its parent.intgetPrecedingSiblingIndex(int index) Gets the index of the row that immediately precedes the row at the given index in the list of children of its parent.LongArraygetPrecedingSiblings(long row) Returns the array of all rows that come before the given row in the list of children of its parent, in the same order as they appear in the forest.LongArraygetPrecedingSiblingsForIndex(int index) Returns the array of all rows that come before the given row in the list of children of its parent, in the same order as they appear in the forest.LongArraygetRoots()Returns an array of all root rows in the forest (those that have depth of0).longgetRow(int index) Gets the ID of the row at the specified position in the forest.LongListgetRows()Returns a non-modifiable list of rows, in the order they appear in the forest.intgetSubtreeEnd(int index) The method looks for the end of a subtree rooted at the specified index.inthashCode()intindexOf(long row) Searches for the position of a specific row in the forest.booleanisEmpty()Used to check if the forest does not contain any rows.booleanReturns true if the forest is immutable.LongIntIteratoriterator()Makes this instance non-modifiablevoidmergeForest(Forest forest, long under, long after) Convenience method to callmergeForest(Forest, long, long, ForestChangeEventHandler)without event handler.voidmergeForest(Forest forest, long under, long after, ForestChangeEventHandler eventHandler) Merges another forest into this forest.booleanmoveSubtree(long row, long under, long after) Convenience method to callmoveSubtree(long, long, long, ForestChangeEventHandler)without event handler.booleanmoveSubtree(long row, long under, long after, ForestChangeEventHandler eventHandler) Moves sub-tree rooted at the specified row to a position specified by(under, after)coordinates.intmoveSubtreeAtIndex(int index, long under, long after, ForestChangeEventHandler eventHandler) Moves sub-tree rooted at the specified index to a position specified by(under, after)coordinates.removeSubtree(long row) Convenience method to callremoveSubtree(long, ForestChangeEventHandler)without event handler.removeSubtree(long row, ForestChangeEventHandler eventHandler) Removes a subtree from this forest.removeSubtreeAtIndex(int index, ForestChangeEventHandler eventHandler) Removes a sub-tree with rooted at the specified index from this forest.voidreorder(long parent, LongList children) voidreplaceSubtrees(long rowId, Forest forest) Removes everything from under given row and inserts forest as sub-forest of rowId.voidreplaceSubtreesMutuallyExclusive(long rowId, Forest forest) voidreplaceSubtreesMutuallyExclusiveAtIndex(int index, Forest forest) Removes everything from under row with given index and inserts forest as sub-forest of the same rowvoidscanDownwards(ForestScanner scanner) Iterates through each row from top to the bottom.set(LongList rows, IntList depths) Replaces the contents of this forest with the values passed in the parameters.final Forestset(WritableLongList rows, WritableIntList depths, boolean reuseLists) Replaces the contents of this forest with the values passed in the parameters.intsize()Gets the number of rows in this tree.subtree(long row) Creates a forest that contains the specified row and all its sub-rows from this forest.subtreeAtIndex(int index) Creates a forest that contains the specified row and all its sub-rows from this forest.Utility method for debugging - returns full string representation of the forest, that contains all the information, unliketoString()method, which may be truncated to some character number limit.toString()voidThis method is used to efficiently traverse all pairs (parent, children) from the end of the forest upwards.Methods inherited from interface Iterable
forEach, spliterator
-
Constructor Details
-
ArrayForest
public ArrayForest() -
ArrayForest
public ArrayForest(long row) Creates a singular tree. Singular tree cannot be stored (the row is a standalone row), but can be used between operations on other trees.- Parameters:
row- row ID of the root
-
ArrayForest
public ArrayForest(WritableLongList rows, WritableIntList depths, boolean reuseLists) Constructs a forest based on the given rows and depths. Row list and depth list must conform to the RowTree invariants. If invariants are violated, then either an error is thrown (if assertions are on), or further behavior is undefined.- Parameters:
rows- list of row IDsdepths- list of corresponding depthsreuseLists- if true, passed instances of List can be used by this RowTree (otherwise a copy is made)
-
ArrayForest
public ArrayForest(LongList rows, IntList depths) -
ArrayForest
-
-
Method Details
-
set
Replaces the contents of this forest with the values passed in the parameters.
The passed lists must satisfy the invariant conditions listed in
Forest, otherwise the results are undefined.- Parameters:
rows- new row listdepths- new depths listreuseLists- if true, the passed arrays may be used by the forest without copying the data. In that case, the calling code must not use these lists after this method call.- Returns:
- this forest
-
set
Replaces the contents of this forest with the values passed in the parameters.
The passed lists must satisfy the invariant conditions listed in
Forest, otherwise the results are undefined.- Parameters:
rows- new row listdepths- new depths list- Returns:
- this forest
-
getDiagnostics
-
getDiagnostics
Checks whether RowTree invariants hold.- Returns:
- null if all invariants are true, otherwise return a message with description of the problem
-
containsRow
public boolean containsRow(long row) Description copied from interface:ForestCan be used to check if the forest contains a specific row.
Execution of this method may take
O(size())time.- Specified by:
containsRowin interfaceForest- Parameters:
row- the row ID to search for- Returns:
- true if the forest contains the specified row
-
mergeForest
Convenience method to callmergeForest(Forest, long, long, ForestChangeEventHandler)without event handler.- Parameters:
forest- the merged forestunder- the parent of the merged forest, or 0 if the forest rows should be placed at the root levelafter- the preceding sibling of the merged forest, or 0 to place forest as the first child- Throws:
StructureException- if the operation cannot be completed because it requires an invalid move
-
addForest
-
clear
public void clear() -
mergeForest
public void mergeForest(Forest forest, long under, long after, @Nullable ForestChangeEventHandler eventHandler) throws StructureException Merges another forest into this forest. After the method has executed, this forest will contain all rows from
forestin the same topology under the specified positions: the root rows fromforestwill be positioned as defined byunder-aftercoordinates (seeForestfor the explanation of under-after coordinates), and non-root rows fromforestwill have the same parent rows as inforest.This forest and the merged
forestmay have the same rows. In that case the rows are moved within this forest and placed at the position required by this operation.When
StructureExceptionis thrown from this method, the state of this forest is unknown - due to the fact that merge splits into several atomic updates and the exception may be thrown after some of the updates have taken place.- Parameters:
forest- the merged forestunder- the parent of the merged forest, or 0 if the forest rows should be placed at the root levelafter- the preceding sibling of the merged forest, or 0 to place forest as the first childeventHandler- an optional event handler to get notifications about changes being applied - may be called several times because merge could be split into series of moves and additions.- Throws:
StructureException- if the operation cannot be completed because it requires an invalid move
-
addRow
Adds a single row at the specified position.
If the row is already in the structure, this method moves it to the specified position.
- Parameters:
row- row to be addedunder- the parent of the row, or 0 if the row should be placed at the forest root levelafter- the preceding sibling of the row, or 0 to place row as the first child- Returns:
- true if the forest has been changed
- Throws:
StructureException- ifunderis not in the forest or if a similar problem happens
-
addForestMutuallyExclusive
public void addForestMutuallyExclusive(Forest forest, long under, long after) throws StructureException Adds a forest to this forest. Works faster thanaddForest(long, long, Forest)andmergeForest(Forest, long, long)when the added forest is guaranteed to be mutually exclusive with this forest, i.e. when it contains only row IDs not present in this forest. If this is not the case, the result of the operation is undefined.- Parameters:
forest- the forest to addunder- the parent of the added forest, or 0 if the forest rows should be placed at the root levelafter- the preceding sibling of the added forest, or 0 to place forest as the first child- Throws:
StructureException- ifunderis not in the forest or if a similar problem happens
-
removeSubtree
Removes a subtree from this forest. This method will create a new RowTree with row at its root and all sub-rows, properly outdented.- Parameters:
row- row ID of the root of the subtree to be removed- Returns:
- null if this tree does not contain row, otherwise an RowTree with the row as the root
-
removeSubtreeAtIndex
@NotNull public Forest removeSubtreeAtIndex(int index, @Nullable ForestChangeEventHandler eventHandler) Removes a sub-tree with rooted at the specified index from this forest.
- Parameters:
index- the index of the root of the sub-tree to be removedeventHandler- optional handler of the forest events- Returns:
- forest with the removed rows, or empty forest if
indexis negative
-
subtree
Description copied from interface:ForestCreates a forest that contains the specified row and all its sub-rows from this forest. -
subtreeAtIndex
Description copied from interface:ForestCreates a forest that contains the specified row and all its sub-rows from this forest.- Specified by:
subtreeAtIndexin interfaceForest- Parameters:
index- index of the root of the sub-tree- Returns:
- a new forest that contains a copy of the sub-tree rooted at row at
index, or an empty forest if the index is negative
-
getSubtreeEnd
public int getSubtreeEnd(int index) Description copied from interface:ForestThe method looks for the end of a subtree rooted at the specified index.
A subtree rooted at index
kis a sub-sequence in the forest starting at positionkand containing all following elements that have depthd > depth[k].The result of this method is the next index after the last element of this subsequence. More specifically, the result is the first element after
[k]that has depthd <= depth[k].When the subtree ends with the whole forest, the return value is equal to
Forest.size().If
indexis a negative number, the returned value is0. Ifindexis greater or equal thansize(), the returned value is equal tosize().- Specified by:
getSubtreeEndin interfaceForest- Parameters:
index- the index of the root row of the subtree- Returns:
- the index of the row that follows the last row of the subtree, or the size of the forest in case the subtree is at the end of it
-
copySubforest
- Specified by:
copySubforestin interfaceForest
-
copySubforestAtIndex
- Specified by:
copySubforestAtIndexin interfaceForest
-
getRows
@NotNull public LongList getRows()Description copied from interface:ForestReturns a non-modifiable list of rows, in the order they appear in the forest. The size of the list is equal to the value returned byForest.size(). -
getDepths
@NotNull public IntList getDepths()Description copied from interface:ForestReturns a non-modifiable list of depths, in the order the rows appear in the forest. The size of the list is equal to the value returned byForest.size()and thei-th element of this list corresponds to the row ID at thei-th position in the list returned byForest.getRows(). -
getRow
public long getRow(int index) Description copied from interface:ForestGets the ID of the row at the specified position in the forest. -
getDepth
public int getDepth(int index) Description copied from interface:ForestGets the depth of the row at the specified position in the forest. -
getParent
public long getParent(long row) Description copied from interface:ForestGets the parent row of the specified row. -
getParentIndex
public int getParentIndex(int index) Description copied from interface:ForestSearches the forest for the index of a "parent row". If the row at the specified index is a root row (has depth of
0), returns -1.If
indexis negative, returns -1.- Specified by:
getParentIndexin interfaceForest- Parameters:
index- index of a child row- Returns:
- -1 if the row at
indexis a root row, or indexkof the parent row, such as thatk = MAX(k in [0, index-1] that has depth[k] == depth[index] - 1)
-
getPathIndexAtDepth
public int getPathIndexAtDepth(int index, int depth) Description copied from interface:ForestGiven row at the specified index, traverses its "path" upwards - that is, looks for all parent rows up to the topmost root parent, and returns an index of the parent that has the specified depth.
If the required depth is equal to the depth of the row at the specified index, returns
index.If
indexis a negative value, returns -1. If row at the specified index has less depth than the required value, returns-1.- Specified by:
getPathIndexAtDepthin interfaceForest- Parameters:
index- index of the rowdepth- required depth of the [grand-] parent row- Returns:
- the index of the [grand-] parent row on the "path" to the specified row that has the specified depth, or
-1if not found
-
getPrecedingSiblingIndex
public int getPrecedingSiblingIndex(int index) Description copied from interface:ForestGets the index of the row that immediately precedes the row at the given index in the list of children of its parent.- Specified by:
getPrecedingSiblingIndexin interfaceForest- Parameters:
index- row index- Returns:
- index of immediately preceding sibling, or -1 if row at
indexis not found in the forest or is the first root or the first child of its parent row
-
getPrecedingSiblingForIndex
public long getPrecedingSiblingForIndex(int index) Description copied from interface:ForestGets the row that immediately precedes the one with the given index in the list of children of its parent.- Specified by:
getPrecedingSiblingForIndexin interfaceForest- Parameters:
index- row index- Returns:
- immediately preceding sibling, or 0 if there is none
-
getPrecedingSibling
public long getPrecedingSibling(long row) Description copied from interface:ForestGets the row that immediately precedes the specified row in the list of children of the specified row's parent.- Specified by:
getPrecedingSiblingin interfaceForest- Parameters:
row- a row- Returns:
- immediately preceding sibling (row that has the same parent and same depth),
or 0 if
rowis not found in the forest or is the first root or the first child of its parent row
-
getPrecedingSiblings
@NotNull public LongArray getPrecedingSiblings(long row) Description copied from interface:ForestReturns the array of all rows that come before the given row in the list of children of its parent, in the same order as they appear in the forest.- Specified by:
getPrecedingSiblingsin interfaceForest- Parameters:
row- a row- Returns:
- array of all preceding siblings, empty if
rowhas none or is not in the forest
-
getPrecedingSiblingsForIndex
@NotNull public LongArray getPrecedingSiblingsForIndex(int index) Description copied from interface:ForestReturns the array of all rows that come before the given row in the list of children of its parent, in the same order as they appear in the forest.- Specified by:
getPrecedingSiblingsForIndexin interfaceForest- Parameters:
index- row index- Returns:
- array of all preceding siblings, empty if row at
indexhas none orindexis negative
-
getNextSiblingIndex
public int getNextSiblingIndex(int index) Description copied from interface:ForestGets the index of the row that immediately follows the row at the given index in the list of children of its parent.- Specified by:
getNextSiblingIndexin interfaceForest- Parameters:
index- row index- Returns:
- index of immediately following sibling, or -1 if row at
indexis not found in the forest or is the last root or the last child of its parent row
-
getNextSiblingForIndex
public long getNextSiblingForIndex(int index) Description copied from interface:ForestGets the row that immediately follows the one with the given index in the list of children of its parent.- Specified by:
getNextSiblingForIndexin interfaceForest- Parameters:
index- row index- Returns:
- immediately following sibling, or 0 if there is none
-
getNextSibling
public long getNextSibling(long row) Description copied from interface:ForestGets the row that immediately follows the specified row in the list of children of the specified row's parent.- Specified by:
getNextSiblingin interfaceForest- Parameters:
row- a row- Returns:
- immediately following sibling (row that has the same parent and same depth),
or 0 if
rowis not found in the forest or is the last root or the last child of its parent row
-
getChildren
@NotNull public LongArray getChildren(long row) Description copied from interface:ForestCreates an array with all direct sub-rows of the specified row.
The returned array is writable and owned by the calling code.
If row is not in the forest or does not have children, empty array is returned.
- Specified by:
getChildrenin interfaceForest- Parameters:
row- the parent row, you can pass 0 to get the roots.- Returns:
- array of all sub-rows of the specified row that have depth equal to the parent depth + 1
-
getChildrenAtIndex
@NotNull public LongArray getChildrenAtIndex(int index) Description copied from interface:ForestCreates an array with all direct sub-rows of the row at the specified index.
The returned array is writable and owned by the calling code.
If the specified row does not have children, or if the index is negative, empty array is returned.
- Specified by:
getChildrenAtIndexin interfaceForest- Parameters:
index- the index of the parent row- Returns:
- array of all sub-rows of the specified row that have depth equal to the parent depth + 1
-
getChildrenIndicesIterator
@NotNull public IntIterator getChildrenIndicesIterator(int index) Description copied from interface:ForestReturns an iterator over indices of all direct sub-rows of the row at the specified index.
This method is a lazy variant of
Forest.getChildrenAtIndex(int): the underlying data structure is scanned as you advance the returned iterator. This allows to save on an extra scan, and on copying to the result array.Another difference is that this method returns indices, not the rows themselves.
- Specified by:
getChildrenIndicesIteratorin interfaceForest- Parameters:
index- the index of the parent row, in the interval [-1; forest.size()); if -1, will iterate over roots- Returns:
- iterator over indices of all sub-rows of the specified row that have depth equal to the parent depth + 1, or over indices of roots if index is -1
-
getRoots
@NotNull public LongArray getRoots()Description copied from interface:ForestReturns an array of all root rows in the forest (those that have depth of0). -
filter
Description copied from interface:ForestFilters this forest by hiding rows that do not pass the
filtercondition. The resulting forest contains only the rows that pass the condition (all of them).The topology of the resulting forest may differ from the original forest - that is, a row may have a different parent in the resulting forest. This happens when a row that has sub-rows is filtered out - in that case, its sub-tree is substituted instead of the parent row. This is different from
Forest.filterSoft(com.almworks.jira.structure.api.util.La<java.lang.Long, ?>)method, which preserves the topology.This forest is not modified by this method. If all rows pass the condition, then this forest is returned as the result. If filtering has taken place, a new forest is returned.
The filter method is called once for every row in the forest, and a truthy result (as defined in
La.accepts(T)) indicates that the row passes the filter.- Specified by:
filterin interfaceForest- Parameters:
filter- filter that returns a truthy value if the row with given ID is allowed to be present in the resulting forest. Null means "no filtering" - this forest is returned- Returns:
- a filtered forest (or this forest if all rows satisfy the filter)
- See Also:
-
filterSoft
Description copied from interface:ForestFilters this forest by excluding rows that do not pass the
filtercondition. All rows that contain sub-rows that have passed the filter are also preserved. The resulting forest contains sub-sequence of the original forest with rows having the same parents and depths.Unlike
Forest.filter(com.almworks.jira.structure.api.util.La<java.lang.Long, ?>)method, this method preserves the topology of the original forest - all rows in the resulting forest have the same root path as they do in the original forest.This forest is not modified by this method. If all rows pass the condition, then this forest is returned as the result. If filtering has taken place, a new forest is returned.
The filter method is called once for every row in the forest, and a truthy result (as defined in
La.accepts(T)) indicates that the row passes the filter.Note: if you need to filter by hierarchy-based or JQL constraints, see
StructureQuery.- Specified by:
filterSoftin interfaceForest- Parameters:
filter- filter that returns a truthy value if a row with given ID should be present in the resulting forest Null means "no filtering" - this forest is returned- Returns:
- a filtered forest (or this forest if all rows satisfy the filter)
-
filterHardest
Description copied from interface:ForestFilters this forest by excluding rows that do not pass the
filtercondition. All sub-rows of rows that have not passed the filter are also removed. The resulting forest contains only rows that pass the condition, but possibly not all of them.Unlike
Forest.filter(com.almworks.jira.structure.api.util.La<java.lang.Long, ?>)method, this method preserves the topology of the original forest - all rows in the resulting forest have the same root path as they do in the original forest. However, unlikeForest.filterSoft(com.almworks.jira.structure.api.util.La<java.lang.Long, ?>)it achieves that by not including those matching rows that would change the hierarchy.This forest is not modified by this method. If all rows pass the condition, then this forest is returned as the result. If filtering has taken place, a new forest is returned.
The filter method is called once for every row in the forest, and a truthy result (as defined in
La.accepts(T)) indicates that the row passes the filter.- Specified by:
filterHardestin interfaceForest- Parameters:
filter- filter that returns a truthy value if a row with given ID should be present in the resulting forest Null means "no filtering" - this forest is returned- Returns:
- a filtered forest (or this forest if all rows satisfy the filter)
-
makeImmutable
Makes this instance non-modifiable- Returns:
- row tree with the same data (backed by different collections), which cannot be modified
-
isImmutable
public boolean isImmutable()Description copied from interface:ForestReturns true if the forest is immutable.- Specified by:
isImmutablein interfaceForest- See Also:
-
ensureImmutability
-
size
public int size()Gets the number of rows in this tree.- Specified by:
sizein interfaceForest- Returns:
- the number of rows, also the size of lists returned by
getRows()andgetDepths()
-
copy
Description copied from interface:ForestCreates an exact copy of this forest. -
moveSubtree
Convenience method to callmoveSubtree(long, long, long, ForestChangeEventHandler)without event handler.- Parameters:
row- the root row of the sub-tree being movedunder- the new parent of the sub-tree, or 0 if the sub-tree should be placed at the forest root levelafter- the preceding sibling of the new location for the sub-tree, or 0 to place sub-tree as the first child- Returns:
- true if the sub-tree has been moved, false if not (for example, if the row is not in the forest)
- Throws:
StructureException- if the move is not possible - for example,underis not in the forest or if you attempt to move a sub-tree under itself
-
moveSubtree
public boolean moveSubtree(long row, long under, long after, @Nullable ForestChangeEventHandler eventHandler) throws StructureException Moves sub-tree rooted at the specified row to a position specified by
(under, after)coordinates.This method modifies the forest by removing the sub-tree with the specified row as the root and adding it at the position specified by
under-aftercoordinates. SeeForestfor the explanation of under-after coordinates.- Parameters:
row- the root row of the sub-tree being movedunder- the new parent of the sub-tree, or 0 if the sub-tree should be placed at the forest root levelafter- the preceding sibling of the new location for the sub-tree, or 0 to place sub-tree as the first childeventHandler- optional handler of the move events- Returns:
- true if the sub-tree has been moved, false if not (for example, if the row is not in the forest)
- Throws:
StructureException- if the move is not possible - for example,underis not in the forest or if you attempt to move a sub-tree under itself
-
moveSubtreeAtIndex
public int moveSubtreeAtIndex(int index, long under, long after, @Nullable ForestChangeEventHandler eventHandler) throws StructureException Moves sub-tree rooted at the specified index to a position specified by
(under, after)coordinates.This method modifies the forest by removing the sub-tree with the specified row as the root and adding it at the position specified by
under-aftercoordinates. SeeForestfor the explanation of under-after coordinates.- Parameters:
index- the index of the root row of the sub-tree being movedunder- the new parent of the sub-tree, or 0 if the sub-tree should be placed at the forest root levelafter- the preceding sibling of the new location for the sub-tree, or 0 to place sub-tree as the first childeventHandler- optional handler of the move events- Returns:
- new index of the sub-tree if it has been moved, -1 if not (for example, if the given row index is negative or the subtree is already there)
- Throws:
StructureException- if the move is not possible - for example,underis not in the forest or if you attempt to move a sub-tree under itself
-
indexOf
public int indexOf(long row) Description copied from interface:ForestSearches for the position of a specific row in the forest.
Execution of this method may take
O(size())time, however it may be optimized if the implementation maintains an index. It's better to use this method rather than usingforest.getRows().indexOf(row)because of the possible optimizations. -
isEmpty
public boolean isEmpty()Description copied from interface:ForestUsed to check if the forest does not contain any rows. -
equals
-
hashCode
public int hashCode() -
toString
-
toFullString
Description copied from interface:ForestUtility method for debugging - returns full string representation of the forest, that contains all the information, unliketoString()method, which may be truncated to some character number limit.- Specified by:
toFullStringin interfaceForest- Returns:
- a full string containing all information about this forest
-
clone
-
getLastChild
public long getLastChild(long parent) Description copied from interface:ForestGets the last direct sub-row of the specified parent row.
Special case: when
parentis0, returns the last root row in the forest.If the parent row is not in the forest, or if it does not have child rows, the return value is
0.- Specified by:
getLastChildin interfaceForest- Parameters:
parent- parent row- Returns:
- the last row among the parent row's children, or 0 if the parent row does not have children
-
getLastChildByIndex
public long getLastChildByIndex(int parentIndex) Description copied from interface:ForestGets the last direct sub-row of the specified parent row.
Special case: when
parentIndexis less than zero, returns the last root row in the forest.If the parent row does not have child rows, the return value is
0.- Specified by:
getLastChildByIndexin interfaceForest- Parameters:
parentIndex- the index of the parent row- Returns:
- the last row among the parent row's children, or 0 if the parent row does not have children
-
foldUpwards
Description copied from interface:ForestThis is a more generic version of
Forest.visitParentChildrenUpwards(com.almworks.jira.structure.api.forest.raw.ForestParentChildrenVisitor)that allows you to effectively process the forest bottom-up, probably saving on memory allocation and search speed.The method goes over the forest in the backwards direction and calls
closuremethods for each row:ForestParentChildrenClosure.visitRow(com.almworks.jira.structure.api.forest.raw.ForestIterationControl, long, com.almworks.integers.LongList, C)is called for every row (in the same wayForest.visitParentChildrenUpwards(com.almworks.jira.structure.api.forest.raw.ForestParentChildrenVisitor)) works;visitRow()can return a result of the processing;ForestParentChildrenClosure.combine(com.almworks.jira.structure.api.forest.raw.ForestIterationControl, T, C)is called after each call tovisitRow()to aggregate the results of children under the same parent.
- Specified by:
foldUpwardsin interfaceForest- Type Parameters:
T- the type of the result of processing one rowC- the type of the result of processing a number of sub-rows under the same parent- Parameters:
closure- the closure- Returns:
- the result of processing top-level rows in the forest
- See Also:
-
scanDownwards
Description copied from interface:ForestIterates through each row from top to the bottom.ForestScannerreceivesForestScanControl, which can be used to cancel the scan, access parents, or skip subtrees.- Specified by:
scanDownwardsin interfaceForest- Parameters:
scanner- the iteratee
-
visitParentChildrenUpwards
Description copied from interface:ForestThis method is used to efficiently traverse all pairs (parent, children) from the end of the forest upwards.
This method goes over the forest in the backwards direction and reports to the visitor pairs of (parent, direct children).
Invariants:
- The number of calls to the visitor is equal to the forest size: every row is reported as a parent once.
- A child row is reported (as the parent of its own sub-rows) before parent is reported: the iteration goes upwards.
- A leaf row is reported as a parent with no children (empty children list).
If the forest is modified during iteration, the results are undefined.
- Specified by:
visitParentChildrenUpwardsin interfaceForest- Parameters:
visitor- the visitor to receive pairs of (parent, children)
-
getPath
@NotNull public LongArray getPath(long row) Description copied from interface:ForestReturns the path to the specified row - a sequence of rows that starts with a root row, ends with the specified row, and where
element[i]is the parent row ofelement[i+1].If
rowis not in the forest, returns empty array.The array is modifiable and owned by the calling code.
-
getPathForIndex
@NotNull public LongArray getPathForIndex(int idx) Description copied from interface:ForestSimilar toForest.getPath(long), returns the path to the row specified by index.- Specified by:
getPathForIndexin interfaceForest- Parameters:
idx- the index of the row to get the path to- Returns:
- path to the specified row, or empty array if the index is negative
-
getParentPathForIndex
@NotNull public LongArray getParentPathForIndex(int index) Description copied from interface:ForestReturns the path to the specified row without the row itself. In other words, this is the path to the parent of the specified row, if there is one.
- Specified by:
getParentPathForIndexin interfaceForest- Parameters:
index- row index- Returns:
- path to the specified row's parent; empty array if the row is top-level or not in the forest
- See Also:
-
removeSubtree
Convenience method to callremoveSubtree(long, ForestChangeEventHandler)without event handler.- Parameters:
row- the root of the sub-tree to be removed- Returns:
- forest with the removed rows, or empty forest if
rowis not in this forest.
-
reorder
public void reorder(long parent, LongList children) -
append
-
iterator
@NotNull public LongIntIterator iterator() -
replaceSubtrees
Removes everything from under given row and inserts forest as sub-forest of rowId.- Parameters:
rowId- parent rowId, or 0 if the whole forest should be replacedforest- the content to insert in place of the removed sub-forest under rowId
-
replaceSubtreesMutuallyExclusive
-
replaceSubtreesMutuallyExclusiveAtIndex
Removes everything from under row with given index and inserts forest as sub-forest of the same row- Parameters:
index- parent row index, should be in [-1, forest.size()) range, -1 means replace the whole forestforest- the content to insert in place of the removed sub-forest under
-