private static int IndexOfNull <TValue>( byte[] buffer, int index, int count, ref BsonTrieNode <TValue> bsonTrieNode) { for (; count > 0; index++, count--) { // bsonTrieNode might be null on entry or it might become null while navigating the trie if (bsonTrieNode == null) { return(Array.IndexOf <byte>(buffer, 0, index, count)); } var keyByte = buffer[index]; if (keyByte == 0) { return(index); } bsonTrieNode = bsonTrieNode.GetChild(keyByte); // might return null } return(-1); }
/// <summary> /// Gets the node associated with the specified element name. /// </summary> /// <param name="utf8">The element name.</param> /// <param name="node"> /// When this method returns, contains the node associated with the specified element name, if the key is found; /// otherwise, null. This parameter is passed unitialized. /// </param> /// <returns>True if the node was found; otherwise, false.</returns> public bool TryGetNode(ArraySegment <byte> utf8, out BsonTrieNode <TValue> node) { node = _root; for (var i = 0; node != null && i < utf8.Count; i++) { var keyByte = utf8.Array[utf8.Offset + i]; node = node.GetChild(keyByte); } return(node != null); }
/// <summary> /// Tries to get the node associated with a name read from a stream. /// </summary> /// <param name="stream">The stream.</param> /// <param name="node">The node.</param> /// <returns> /// True if the node was found. /// If the node was found the stream is advanced over the name, otherwise /// the stream is repositioned to the beginning of the name. /// </returns> public bool TryGetNode(BsonStream stream, out BsonTrieNode <TValue> node) { var position = stream.Position; var utf8 = stream.ReadCStringBytes(); if (TryGetNode(utf8, out node)) { return(true); } stream.Position = position; return(false); }
// public methods /// <summary> /// Adds the specified elementName (after encoding as a UTF8 byte sequence) and value to the trie. /// </summary> /// <param name="elementName">The element name to add.</param> /// <param name="value">The value to add. The value can be null for reference types.</param> public void Add(string elementName, TValue value) { var keyBytes = __utf8Encoding.GetBytes(elementName); var node = _root; foreach (var keyByte in keyBytes) { var child = node.GetChild(keyByte); if (child == null) { child = new BsonTrieNode<TValue>(keyByte); node.AddChild(child); } node = child; } node.SetValue(elementName, value); }
// public methods /// <summary> /// Adds the specified elementName (after encoding as a UTF8 byte sequence) and value to the trie. /// </summary> /// <param name="elementName">The element name to add.</param> /// <param name="value">The value to add. The value can be null for reference types.</param> public void Add(string elementName, TValue value) { using var rentedSegment = Utf8Encodings.Strict.GetBytesUsingThreadStaticBuffer(elementName); var node = _root; foreach (var keyByte in rentedSegment.Segment) { var child = node.GetChild(keyByte); if (child == null) { child = new BsonTrieNode <TValue>(keyByte); node.AddChild(child); } node = child; } node.SetValue(elementName, value); }
// constructors /// <summary> /// Initializes a new instance of the BsonTrie class. /// </summary> public BsonTrie() { _root = new BsonTrieNode <TValue>(0); }
// internal methods internal void AddChild(BsonTrieNode <TValue> child) { if (GetChild(child._keyByte) != null) { throw new ArgumentException("BsonTrieNode already contains a child with the same keyByte."); } if (_children != null) { // add a new child to the existing _children var children = new BsonTrieNode <TValue> [_children.Length + 1]; Array.Copy(_children, children, _children.Length); children[children.Length - 1] = child; var childrenIndexes = _childrenIndexes; var minChildKeyByte = _minChildKeyByte; var maxChildKeyByte = _minChildKeyByte + _childrenIndexes.Length - 1; // if new keyByte doesn't fall within existing min/max range expand the range if (child._keyByte < minChildKeyByte) { // grow the indexes on the min side minChildKeyByte = child._keyByte; childrenIndexes = new byte[maxChildKeyByte - minChildKeyByte + 1]; var sizeDelta = childrenIndexes.Length - _childrenIndexes.Length; for (var i = 0; i < sizeDelta; i++) { childrenIndexes[i] = 255; } Array.Copy(_childrenIndexes, 0, childrenIndexes, sizeDelta, _childrenIndexes.Length); } else if (child._keyByte > maxChildKeyByte) { // grow the indexes on the max side maxChildKeyByte = child._keyByte; childrenIndexes = new byte[maxChildKeyByte - minChildKeyByte + 1]; Array.Copy(_childrenIndexes, 0, childrenIndexes, 0, _childrenIndexes.Length); for (var i = _childrenIndexes.Length; i < childrenIndexes.Length; i++) { childrenIndexes[i] = 255; } } childrenIndexes[child._keyByte - minChildKeyByte] = (byte)(children.Length - 1); _children = children; _childrenIndexes = childrenIndexes; _minChildKeyByte = minChildKeyByte; } else if (_onlyChild != null) { // switch from having an _onlyChild to having two _children var children = new BsonTrieNode <TValue> [2]; children[0] = _onlyChild; children[1] = child; var minChildKeyByte = _onlyChild._keyByte; var maxChildKeyByte = child._keyByte; if (minChildKeyByte > maxChildKeyByte) { minChildKeyByte = child._keyByte; maxChildKeyByte = _onlyChild._keyByte; } var childrenIndexes = new byte[maxChildKeyByte - minChildKeyByte + 1]; for (var i = 0; i < childrenIndexes.Length; i++) { childrenIndexes[i] = 255; } childrenIndexes[_onlyChild._keyByte - minChildKeyByte] = 0; childrenIndexes[child._keyByte - minChildKeyByte] = 1; _onlyChild = null; _children = children; _childrenIndexes = childrenIndexes; _minChildKeyByte = minChildKeyByte; } else { _onlyChild = child; } }