inet.ipaddr.format.util.AddressTrieOps Maven / Gradle / Ivy
Show all versions of ipaddress Show documentation
/*
* Copyright 2020 Sean C Foley
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
* or at
* https://github.com/seancfoley/IPAddress/blob/master/LICENSE
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package inet.ipaddr.format.util;
import java.util.Iterator;
import java.util.Spliterator;
import java.util.function.Function;
import java.util.function.Supplier;
import inet.ipaddr.Address;
import inet.ipaddr.format.util.AddressTrie.TrieNode;
import inet.ipaddr.format.util.AssociativeAddressTrie.AssociativeTrieNode;
import inet.ipaddr.format.util.BinaryTreeNode.CachingIterator;
/**
* Provides an interface to the trie operations.
* Operations which take an address as an argument require that the address is an individual address or prefix block.
*
* @author scfoley
*
* @param
*/
public interface AddressTrieOps extends TreeOps {
/**
* Gets the node corresponding to the given address, returns null if not such element exists.
*
* If added is true, returns only nodes representing added elements, otherwise returns any node,
* including a prefix block that was not added.
*
* If the given address is not a single address nor prefix block, then this method throws IllegalArgumentException.
*
* If not a single address nor prefix block, the {@link Partition} class can be used to convert the address before calling this method.
* See {@link AddressTrieAddOps#add(Address)} for more details.
*
* @see #contains(Address)
* @param addr
* @return
*/
TrieNode getNode(E addr);
/**
* Gets trie nodes representing added elements.
*
* Use {@link #contains(Address)} to check for the existence of a given address in the trie,
* as well as {@link #getNode(Address)} to search for all nodes including those not-added but also auto-generated nodes for subnet blocks.
*
* @param addr
* @return
*/
default TrieNode getAddedNode(E addr) {
TrieNode ret = getNode(addr);
return (ret == null || ret.isAdded()) ? ret : null;
}
/**
* Checks if a prefix block subnet or address in the trie contains the given subnet or address.
*
* If the given address is not a single address nor prefix block, then this method throws IllegalArgumentException.
*
* If not a single address nor prefix block, the {@link Partition} class can be used to convert the address before calling this method.
* See {@link AddressTrieAddOps#add(Address)} for more details.
*
* Returns true if the subnet or address is contained by a trie element, false otherwise.
*
* To get all the containing addresses, use {@link #elementsContaining(Address)}.
*
* @param addr
* @return
*/
boolean elementContains(E addr);
/**
* Returns whether the given address or prefix block subnet is in the trie (as an added element).
*
* If the given address is not a single address nor prefix block, then this method throws IllegalArgumentException.
*
* If not a single address nor prefix block, the {@link Partition} class can be used to convert the address before calling this method.
* See {@link AddressTrieAddOps#add(Address)} for more details.
*
* Returns true if the prefix block or address address exists already in the trie, false otherwise.
*
* Use {@link #getAddedNode(Address)} to get the node for the address rather than just checking for its existence.
*
* @param addr
* @return
*/
boolean contains(E addr);
/**
* Removes the given single address or prefix block subnet from the trie.
*
* Removing an element will not remove contained elements (nodes for contained blocks and addresses).
*
* If the given address is not a single address nor prefix block, then this method throws IllegalArgumentException.
*
* If not a single address nor prefix block, the {@link Partition} class can be used to convert the address before calling this method.
* See {@link AddressTrieAddOps#add(Address)} for more details.
*
* Returns true if the prefix block or address was removed, false if not already in the trie.
*
* You can also remove by calling {@link #getAddedNode(Address)} to get the node and then calling {@link BinaryTreeNode#remove()} on the node.
*
* When an address is removed, the corresponding node may remain in the trie if it remains a subnet block for two sub-nodes.
* If the corresponding node can be removed from the trie, it will be.
*
* @see #removeElementsContainedBy(Address)
* @param addr
* @return
*/
boolean remove(E addr);
/**
* Removes any single address or prefix block subnet from the trie that is contained in the given individual address or prefix block subnet.
*
* Goes further than {@link #remove(Address)}, not requiring a match to an inserted node, and also removing all the sub-nodes of any removed node or sub-node.
*
* For example, after inserting 1.2.3.0 and 1.2.3.1, passing 1.2.3.0/31 to {@link #removeElementsContainedBy(Address)} will remove them both,
* while {@link #remove(Address)} will remove nothing.
* After inserting 1.2.3.0/31, then #remove(Address) will remove 1.2.3.0/31, but will leave 1.2.3.0 and 1.2.3.1 in the trie.
*
* It cannot partially delete a node, such as deleting a single address from a prefix block represented by a node.
* It can only delete the whole node if the whole address or block represented by that node is contained in the given address or block.
*
* If the given address is not a single address nor prefix block, then this method throws IllegalArgumentException.
*
* If not a single address nor prefix block, the {@link Partition} class can be used to convert the address before calling this method.
* See {@link AddressTrieAddOps#add(Address)} for more details.
*
* Returns the root node of the subtrie that was removed from the trie, or null if nothing was removed.
*
* @param addr
* @return
*/
TrieNode removeElementsContainedBy(E addr);
/**
* Checks if a part of this trie is contained by the given prefix block subnet or individual address.
*
* If the given address is not a single address nor prefix block, then this method throws IllegalArgumentException.
*
* If not a single address nor prefix block, the {@link Partition} class can be used to convert the address before calling this method.
* See {@link AddressTrieAddOps#add(Address)} for more details.
*
* Returns the root node of the contained subtrie, or null if no subtrie is contained.
* The node returned need not be an "added" node, see {@link TrieNode#isAdded()} for more details on added nodes.
* The returned subtrie is backed by this trie, so changes in this trie are reflected in those nodes and vice-versa.
*
* @param addr
* @return
*/
TrieNode elementsContainedBy(E addr);
/**
* Finds the added subnets and/or addresses in the trie that contain the given individual address or prefix block subnet.
*
* If the given address is not a single address nor prefix block, then this method throws IllegalArgumentException.
*
* If not a single address nor prefix block, the {@link Partition} class can be used to convert the address before calling this method.
* See {@link AddressTrieAddOps#add(Address)} for more details.
*
* Returns a list of the nodes for prefix block subnets and addresses from the trie that contain the address or block.
* The list consists only of added nodes, see {@link TrieNode#isAdded()} for more details on added nodes.
* The list is constructed as a trie in which each parent node has only one sub-node.
*
* Use {@link #elementContains(Address)} to check for the existence of a containing address.
*
* @param addr
* @return
*/
TrieNode elementsContaining(E addr);
/**
* Finds the containing subnet or address in the trie with the smallest subnet size,
* which is equivalent to finding the subnet or address with the longest matching prefix.
* Returns the node corresponding to that subnet.
*
* If the given address is not a single address nor prefix block, then this method throws IllegalArgumentException.
*
* If not a single address nor prefix block, the {@link Partition} class can be used to convert the address before calling this method.
* See {@link AddressTrieAddOps#add(Address)} for more details.
*
* Returns null if no added subnet or address contains the given argument.
*
* Use {@link #elementContains(Address)} to check for the existence of a containing address.
* To get all the containing addresses, use {@link #elementsContaining(Address)}.
* Use {@link #longestPrefixMatch(Address)} to get the address corresponding to the result of this method.
*
* @param addr
* @return
*/
TrieNode longestPrefixMatchNode(E addr);
/**
* Of all the added subnets or address whose prefix matches the given address, returns the one with the longest prefix.
* This is equivalent to finding the containing subnet or address with the smallest subnet size.
*
* If the given address is not a single address nor prefix block, then this method throws IllegalArgumentException.
*
* If not a single address nor prefix block, the {@link Partition} class can be used to convert the address before calling this method.
* See {@link AddressTrieAddOps#add(Address)} for more details.
*
* Returns null if no added subnet or address contains the given argument.
*
* Use {@link #elementContains(Address)} to check for the existence of a containing address.
* To get all the containing addresses (subnets with matching prefix), use {@link #elementsContaining(Address)}.
* To get the node corresponding to the result of this method, use {@link #longestPrefixMatchNode(Address)}
*
* @param addr
* @return
*/
E longestPrefixMatch(E addr);
@Override
Iterator extends TrieNode> nodeIterator(boolean forward);
@Override
Iterator extends TrieNode> allNodeIterator(boolean forward);
@Override
CachingIterator extends TrieNode, E, C> containingFirstIterator(boolean forwardSubNodeOrder);
@Override
CachingIterator extends TrieNode, E, C> containingFirstAllNodeIterator(boolean forwardSubNodeOrder);
@Override
Iterator extends TrieNode> containedFirstIterator(boolean forwardSubNodeOrder);
@Override
Iterator extends TrieNode> containedFirstAllNodeIterator(boolean forwardSubNodeOrder);
@Override
Spliterator extends TrieNode> nodeSpliterator(boolean forward);
@Override
Spliterator extends TrieNode> allNodeSpliterator(boolean forward);
/**
* Returns the node with the first (lowest valued) key, whether the node is added or not
*
* @return
*/
TrieNode firstNode();
/**
* Returns the node with the last (highest valued) key, whether the node is added or not
*
* @return
*/
TrieNode lastNode();
/**
* Returns the added node with the first (lowest valued) key,
* or null if there are no added entries in this trie or subtrie
* @return
*/
TrieNode firstAddedNode();
/**
* Returns the added node with the last (highest valued) key,
* or null if there are no added elements in this trie or subtrie
* @return
*/
TrieNode lastAddedNode();
/**
* Returns the added node whose address is the highest address less than or equal to the given address.
* @param addr
* @return
*/
TrieNode floorAddedNode(E addr);
/**
* Returns the added node whose address is the highest address strictly less than the given address.
* @param addr
* @return
*/
TrieNode lowerAddedNode(E addr);
/**
* Returns the added node whose address is the lowest address greater than or equal to the given address.
* @param addr
* @return
*/
TrieNode ceilingAddedNode(E addr);
/**
* Returns the added node whose address is the lowest address strictly greater than the given address.
* @param addr
* @return
*/
TrieNode higherAddedNode(E addr);
/**
* Provides an interface to the trie add operations.
* Operations which take an address as an argument require that the address is an individual address or prefix block.
*
*
* @author scfoley
*
* @param
*/
public static interface AddressTrieAddOps extends AddressTrieOps {
/**
* Adds the given single address or prefix block subnet to the trie.
*
* If the given address is not a single address nor prefix block, then this method throws IllegalArgumentException.
*
* If not a single address nor prefix block, the {@link Partition} class can be used to convert the address before calling this method.
* Given a subnet s of type E and a trie of type AddressTrie<E>, such as {@link inet.ipaddr.ipv4.IPv4Address} and {@link inet.ipaddr.ipv4.IPv4AddressTrie},
* you can convert and add the spanning prefix blocks with Partition.partitionWithSpanningBlocks(s).predicateForEach(trie::add)
,
* or you can convert and add using a single max block size with Partition.partitionWithSingleBlockSize(s).predicateForEach(trie::add)
.
*
* Returns true if the prefix block or address was inserted, false if already in the trie.
*
* @param addr
* @return
*/
boolean add(E addr);
/**
* Adds the given single address or prefix block subnet to the trie, if not already there.
*
* If the given address is not a single address nor prefix block, then this method throws IllegalArgumentException.
*
* If not a single address nor prefix block, the {@link Partition} class can be used to convert the address before calling this method.
* See {@link #add(Address)} for more details.
*
* Returns the node for the added address, whether it was already in the trie or not.
*
* If you wish to know whether the node was already there when adding, use {@link #add(Address)}, or before adding you can use {@link #getAddedNode(Address)}
*
* @param addr
* @return
*/
TrieNode addNode(E addr);
/**
* Adds nodes matching the given sub-root node and all of its sub-nodes to the trie, if not already there.
*
* For each added in the given node that does not exist in the trie, a copy of each node will be made that matches the trie type (associative or not),
* and the copy will be inserted into the trie.
*
* The node type need not match the node type of the trie, although the address type/version E must match.
* You can add associative nodes to tries with this method but associated values will all be null.
* If you want to preserve the values, use {@link AssociativeAddressTriePutOps#putTrie(AssociativeTrieNode)} instead.
*
* When adding one trie to another, this method is more efficient than adding each node of the first trie individually.
* When using this method, searching for the location to add sub-nodes starts from the inserted parent node.
*
* Returns the node corresponding to the given sub-root node, whether it was already in the trie or not.
*
*
* @param trie
* @return
*/
TrieNode addTrie(TrieNode trie);
}
/**
* Provides an interface to the associative trie operations.
* Operations which take an address as an argument require that the address is an individual address or prefix block.
*
*
* @author scfoley
*
* @param
* @param
*/
public static interface AssociativeAddressTrieOps extends AddressTrieOps {
/**
* Gets the specified value for the specified key in this mapped trie or subtrie.
*
* If the given address is not a single address nor prefix block, then this method throws IllegalArgumentException.
*
* If not a single address nor prefix block, the {@link Partition} class can be used to convert the address before calling this method.
* See {@link AddressTrieAddOps#add(Address)} for more details.
*
* Returns the value for the given key.
* Returns null if the contains no mapping for that key or if the mapped value is null.
*
* @param addr
* @return
*/
V get(K addr);
}
/**
* Provides an interface to the associative trie put operations.
* Operations which take an address as an argument require that the address is an individual address or prefix block.
*
*
* @author scfoley
*
* @param
* @param
*/
public static interface AssociativeAddressTriePutOps extends AssociativeAddressTrieOps {
/**
* Associates the specified value with the specified key in this map.
*
* Unlike {@link #putNew(Address, Object)}, {@link #put(Address, Object)} can provide the value to which to key was previously mapped.
*
* If the given address is not a single address nor prefix block, then this method throws IllegalArgumentException.
*
* If not a single address nor prefix block, the {@link Partition} class can be used to convert the address before calling this method.
* See {@link AddressTrieAddOps#add(Address)} for more details.
*
* If this map previously contained a mapping for a key,
* the old value is replaced by the specified value, and the old value is returned.
* If this map did not previously contain a mapping for the key, null is returned.
*
* @param addr
* @return
*/
V put(K addr, V value);
/**
* Associates the specified value with the specified key in this map.
*
* Unlike {@link #put(Address, Object)}, {@link #put(Address, Object)} can distinguish between
* cases where the call results in a new entry, and cases where the call matched a previous entry that was mapped to null.
*
* If the given address is not a single address nor prefix block, then this method throws IllegalArgumentException.
*
* If not a single address nor prefix block, the {@link Partition} class can be used to convert the address before calling this method.
* See {@link AddressTrieAddOps#add(Address)} for more details.
*
* If this map previously contained a mapping for a key,
* the old value is replaced by the specified value, and false is returned.
* If this map did not previously contain a mapping for the key, true is returned.
*
* @param addr
* @return
*/
boolean putNew(K addr, V value);
/**
* Associates the specified value with the specified key in this map.
*
* Unlike {@link #put(Address, Object)}, {@link #put(Address, Object)} can distinguish between
* cases where the call results in a new entry, and cases where the call matched a previous entry that was mapped to null.
*
* If the given address is not a single address nor prefix block, then this method throws IllegalArgumentException.
*
* If not a single address nor prefix block, the {@link Partition} class can be used to convert the address before calling this method.
* See {@link AddressTrieAddOps#add(Address)} for more details.
*
* Returns the node for the added address, whether it was already in the tree or not.
*
* If you wish to know whether the node was already there when adding, use {@link #putNew(Address, Object)}, or before adding you can use {@link #getAddedNode(Address)}
*
* @param addr
* @return
*/
AssociativeTrieNode putNode(K addr, V value);
/**
* Remaps node values in the trie.
*
* This will lookup the node corresponding to the given key.
* It will call the remapping function with the key as the first argument, regardless of whether the node is found or not.
*
* If the node is not found, the value argument will be null.
* If the node is found, the value argument will be the node's value, which can also be null.
*
* If the remapping function returns null, then the matched node will be removed, if any.
* If it returns a non-null value, then it will either set the existing node to have that value,
* or if there was no matched node, it will create a new node with that value.
*
* The method will return the node involved, which is either the matched node, or the newly created node,
* or null if there was no matched node nor newly created node.
*
* If the remapping function modifies the trie during its computation,
* and the returned value specifies changes to be made,
* then the trie will not be changed and ConcurrentModificationException will be thrown instead.
*
* If the given address is not a single address nor prefix block, then this method throws IllegalArgumentException.
*
* If not a single address nor prefix block, the {@link Partition} class can be used to convert the address before calling this method.
* See {@link AddressTrieAddOps#add(Address)} for more details.
*
* @param addr
* @param remapper
* @return
*/
AssociativeTrieNode remap(K addr, Function super V, ? extends V> remapper);
/**
* Remaps node values in the trie, but only for nodes that do not exist or are mapped to null.
*
* This will look up the node corresponding to the given key.
* If the node is not found or mapped to null, this will call the remapping function.
*
* If the remapping function returns a non-null value, then it will either set the existing node to have that value,
* or if there was no matched node, it will create a new node with that value.
* If the remapping function returns null, then it will do the same if insertNull is true, otherwise it will do nothing.
*
* The method will return the node involved, which is either the matched node, or the newly created node,
* or null if there was no matched node nor newly created node.
*
* If the remapping function modifies the trie during its computation,
* and the returned value specifies changes to be made,
* then the trie will not be changed and ConcurrentModificationException will be thrown instead.
*
* If the given address is not a single address nor prefix block, then this method throws IllegalArgumentException.
*
* If not a single address nor prefix block, the {@link Partition} class can be used to convert the address before calling this method.
* See {@link AddressTrieAddOps#add(Address)} for more details.
*
* @param addr
* @param remapper
* @param insertNull whether null values returned from remapper should be inserted into the map, or whether null values indicate no remapping
* @return
*/
AssociativeTrieNode remapIfAbsent(K addr, Supplier extends V> remapper, boolean insertNull);
/**
* Adds nodes matching the given sub-root node and all of its sub-nodes to the trie, if not already there.
*
* For each added in the given node that does not exist in the trie, a copy of each node will be made that matches the trie type (associative or not),
* the copy including the associated value, and the copy will be inserted into the trie.
*
* The node type need not match the node type of the trie, although the address type/version E must match.
* So this means you can add non-associative nodes with this method,
* in which case, the new nodes will be associative but will be mapped to null.
*
* When adding one trie to another, this method is more efficient than adding each node of the first trie individually.
* When using this method, searching for the location to add sub-nodes starts from the inserted parent node.
*
* Returns the node corresponding to the given sub-root node, whether it was already in the trie or not.
*
*
* @param trie
* @return
*/
AssociativeTrieNode putTrie(AssociativeTrieNode trie);
}
}