using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; namespace Ryujinx.Common.Collections { /// /// Dictionary that provides the ability for O(logN) Lookups for keys that exist in the Dictionary, and O(logN) lookups for keys immediately greater than or less than a specified key. /// /// Key /// Value public class TreeDictionary : IntrusiveRedBlackTreeImpl>, IDictionary where K : IComparable { #region Public Methods /// /// Returns the value of the node whose key is , or the default value if no such node exists. /// /// Key of the node value to get /// Value associated w/ /// is null public V Get(K key) { ArgumentNullException.ThrowIfNull(key); Node node = GetNode(key); if (node == null) { return default; } return node.Value; } /// /// Adds a new node into the tree whose key is key and value is . ///

/// Note: Adding the same key multiple times will cause the value for that key to be overwritten. ///
/// Key of the node to add /// Value of the node to add /// or are null public void Add(K key, V value) { ArgumentNullException.ThrowIfNull(key); ArgumentNullException.ThrowIfNull(value); Insert(key, value); } /// /// Removes the node whose key is from the tree. /// /// Key of the node to remove /// is null public void Remove(K key) { ArgumentNullException.ThrowIfNull(key); if (Delete(key) != null) { Count--; } } /// /// Returns the value whose key is equal to or immediately less than . /// /// Key for which to find the floor value of /// Key of node immediately less than /// is null public K Floor(K key) { Node node = FloorNode(key); if (node != null) { return node.Key; } return default; } /// /// Returns the node whose key is equal to or immediately greater than . /// /// Key for which to find the ceiling node of /// Key of node immediately greater than /// is null public K Ceiling(K key) { Node node = CeilingNode(key); if (node != null) { return node.Key; } return default; } /// /// Finds the value whose key is immediately greater than . /// /// Key to find the successor of /// Value public K SuccessorOf(K key) { Node node = GetNode(key); if (node != null) { Node successor = SuccessorOf(node); return successor != null ? successor.Key : default; } return default; } /// /// Finds the value whose key is immediately less than . /// /// Key to find the predecessor of /// Value public K PredecessorOf(K key) { Node node = GetNode(key); if (node != null) { Node predecessor = PredecessorOf(node); return predecessor != null ? predecessor.Key : default; } return default; } /// /// Adds all the nodes in the dictionary as key/value pairs into . ///

/// The key/value pairs will be added in Level Order. ///
/// List to add the tree pairs into public List> AsLevelOrderList() { List> list = new List>(); Queue> nodes = new Queue>(); if (this.Root != null) { nodes.Enqueue(this.Root); } while (nodes.TryDequeue(out Node node)) { list.Add(new KeyValuePair(node.Key, node.Value)); if (node.Left != null) { nodes.Enqueue(node.Left); } if (node.Right != null) { nodes.Enqueue(node.Right); } } return list; } /// /// Adds all the nodes in the dictionary into . /// /// A list of all KeyValuePairs sorted by Key Order public List> AsList() { List> list = new List>(); AddToList(Root, list); return list; } #endregion #region Private Methods (BST) /// /// Adds all nodes that are children of or contained within into , in Key Order. /// /// The node to search for nodes within /// The list to add node to private void AddToList(Node node, List> list) { if (node == null) { return; } AddToList(node.Left, list); list.Add(new KeyValuePair(node.Key, node.Value)); AddToList(node.Right, list); } /// /// Retrieve the node reference whose key is , or null if no such node exists. /// /// Key of the node to get /// Node reference in the tree /// is null private Node GetNode(K key) { ArgumentNullException.ThrowIfNull(key); Node node = Root; while (node != null) { int cmp = key.CompareTo(node.Key); if (cmp < 0) { node = node.Left; } else if (cmp > 0) { node = node.Right; } else { return node; } } return null; } /// /// Inserts a new node into the tree whose key is and value is . ///

/// Adding the same key multiple times will overwrite the previous value. ///
/// Key of the node to insert /// Value of the node to insert private void Insert(K key, V value) { Node newNode = BSTInsert(key, value); RestoreBalanceAfterInsertion(newNode); } /// /// Insertion Mechanism for a Binary Search Tree (BST). ///

/// Iterates the tree starting from the root and inserts a new node where all children in the left subtree are less than , and all children in the right subtree are greater than . ///

/// Note: If a node whose key is already exists, it's value will be overwritten. ///
/// Key of the node to insert /// Value of the node to insert /// The inserted Node private Node BSTInsert(K key, V value) { Node parent = null; Node node = Root; while (node != null) { parent = node; int cmp = key.CompareTo(node.Key); if (cmp < 0) { node = node.Left; } else if (cmp > 0) { node = node.Right; } else { node.Value = value; return node; } } Node newNode = new Node(key, value, parent); if (newNode.Parent == null) { Root = newNode; } else if (key.CompareTo(parent.Key) < 0) { parent.Left = newNode; } else { parent.Right = newNode; } Count++; return newNode; } /// /// Removes from the dictionary, if it exists. /// /// Key of the node to delete /// The deleted Node private Node Delete(K key) { // O(1) Retrieval Node nodeToDelete = GetNode(key); if (nodeToDelete == null) return null; Node replacementNode; if (LeftOf(nodeToDelete) == null || RightOf(nodeToDelete) == null) { replacementNode = nodeToDelete; } else { replacementNode = PredecessorOf(nodeToDelete); } Node tmp = LeftOf(replacementNode) ?? RightOf(replacementNode); if (tmp != null) { tmp.Parent = ParentOf(replacementNode); } if (ParentOf(replacementNode) == null) { Root = tmp; } else if (replacementNode == LeftOf(ParentOf(replacementNode))) { ParentOf(replacementNode).Left = tmp; } else { ParentOf(replacementNode).Right = tmp; } if (replacementNode != nodeToDelete) { nodeToDelete.Key = replacementNode.Key; nodeToDelete.Value = replacementNode.Value; } if (tmp != null && ColorOf(replacementNode) == Black) { RestoreBalanceAfterRemoval(tmp); } return replacementNode; } /// /// Returns the node whose key immediately less than or equal to . /// /// Key for which to find the floor node of /// Node whose key is immediately less than or equal to , or null if no such node is found. /// is null private Node FloorNode(K key) { ArgumentNullException.ThrowIfNull(key); Node tmp = Root; while (tmp != null) { int cmp = key.CompareTo(tmp.Key); if (cmp > 0) { if (tmp.Right != null) { tmp = tmp.Right; } else { return tmp; } } else if (cmp < 0) { if (tmp.Left != null) { tmp = tmp.Left; } else { Node parent = tmp.Parent; Node ptr = tmp; while (parent != null && ptr == parent.Left) { ptr = parent; parent = parent.Parent; } return parent; } } else { return tmp; } } return null; } /// /// Returns the node whose key is immediately greater than or equal to than . /// /// Key for which to find the ceiling node of /// Node whose key is immediately greater than or equal to , or null if no such node is found. /// is null private Node CeilingNode(K key) { ArgumentNullException.ThrowIfNull(key); Node tmp = Root; while (tmp != null) { int cmp = key.CompareTo(tmp.Key); if (cmp < 0) { if (tmp.Left != null) { tmp = tmp.Left; } else { return tmp; } } else if (cmp > 0) { if (tmp.Right != null) { tmp = tmp.Right; } else { Node parent = tmp.Parent; Node ptr = tmp; while (parent != null && ptr == parent.Right) { ptr = parent; parent = parent.Parent; } return parent; } } else { return tmp; } } return null; } #endregion #region Interface Implementations // Method descriptions are not provided as they are already included as part of the interface. public bool ContainsKey(K key) { ArgumentNullException.ThrowIfNull(key); return GetNode(key) != null; } bool IDictionary.Remove(K key) { int count = Count; Remove(key); return count > Count; } public bool TryGetValue(K key, [MaybeNullWhen(false)] out V value) { ArgumentNullException.ThrowIfNull(key); Node node = GetNode(key); value = node != null ? node.Value : default; return node != null; } public void Add(KeyValuePair item) { ArgumentNullException.ThrowIfNull(item.Key); Add(item.Key, item.Value); } public bool Contains(KeyValuePair item) { if (item.Key == null) { return false; } Node node = GetNode(item.Key); if (node != null) { return node.Key.Equals(item.Key) && node.Value.Equals(item.Value); } return false; } public void CopyTo(KeyValuePair[] array, int arrayIndex) { if (arrayIndex < 0 || array.Length - arrayIndex < this.Count) { throw new ArgumentOutOfRangeException(nameof(arrayIndex)); } SortedList list = GetKeyValues(); int offset = 0; for (int i = arrayIndex; i < array.Length && offset < list.Count; i++) { array[i] = new KeyValuePair(list.Keys[i], list.Values[i]); offset++; } } public bool Remove(KeyValuePair item) { Node node = GetNode(item.Key); if (node == null) { return false; } if (node.Value.Equals(item.Value)) { int count = Count; Remove(item.Key); return count > Count; } return false; } public IEnumerator> GetEnumerator() { return GetKeyValues().GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetKeyValues().GetEnumerator(); } public ICollection Keys => GetKeyValues().Keys; public ICollection Values => GetKeyValues().Values; public bool IsReadOnly => false; public V this[K key] { get => Get(key); set => Add(key, value); } #endregion #region Private Interface Helper Methods /// /// Returns a sorted list of all the node keys / values in the tree. /// /// List of node keys private SortedList GetKeyValues() { SortedList set = new SortedList(); Queue> queue = new Queue>(); if (Root != null) { queue.Enqueue(Root); } while (queue.TryDequeue(out Node node)) { set.Add(node.Key, node.Value); if (null != node.Left) { queue.Enqueue(node.Left); } if (null != node.Right) { queue.Enqueue(node.Right); } } return set; } #endregion } /// /// Represents a node in the TreeDictionary which contains a key and value of generic type K and V, respectively. /// /// Key of the node /// Value of the node public class Node : IntrusiveRedBlackTreeNode> where K : IComparable { internal K Key; internal V Value; internal Node(K key, V value, Node parent) { Key = key; Value = value; Parent = parent; } } }