private async ValueTask <LTrieNodeExternalLinkStruct> GetRemainingExternalLink(LTrieNodeStruct gn, byte value) { IMemoryOwner <byte>?owner = null; var restLength = gn.GetRestLength(); var secondLinkPointer = gn.GetSecondExternalLinkOwnPointer(); if (!Storage.TryDirectRead(secondLinkPointer, restLength, out var memory)) { owner = MemoryPool.Rent(restLength); var outputMemory = owner.Memory.Slice(0, restLength); await Storage.Read(secondLinkPointer, outputMemory); memory = outputMemory; } for (int linkIndex = 0; linkIndex < gn.ExternalLinkSlotCount - 1; linkIndex++) { var linkOwnPointer = secondLinkPointer + linkIndex * Sizes.ExternalLinkLength; var l = new LTrieNodeExternalLinkStruct(linkOwnPointer, memory.Span.Slice(linkIndex * Sizes.ExternalLinkLength, Sizes.ExternalLinkLength)); if (l.Pointer != 0 && l.Value == value) { owner?.Dispose(); return(l); } } owner?.Dispose(); return(default);
public LTrieNodeStruct(long ownPointer, ReadOnlySpan <byte> data) { var lineLen = data.ReadUInt16BigEndian(); OwnPointer = ownPointer; ExternalLinkSlotCount = (lineLen - Sizes.DefaultPointerLen) / Sizes.ExternalLinkLength; InternalLinkPointer = (long)data.Slice(2).BigEndianToLongDynamic(); FirstExternalLink = new LTrieNodeExternalLinkStruct(OwnPointer + 2 + Sizes.DefaultPointerLen, data.Slice(2 + Sizes.DefaultPointerLen)); }
internal async ValueTask <MatchResult> FindBestMatch(ReadOnlyMemory <byte> key) { LTrieNodeStruct gn = await ReadNodeStruct(); LTrieNodeStruct prev = default; if (key.Length == 0) { return(await CreateMatchResult(0, gn.GetInternalLinkObject(), gn, prev)); } for (int i = 0; i < key.Length; i++) { LTrieNodeExternalLinkStruct externalLink = default; if (key.Span[i] == gn.FirstExternalLink.Value) { externalLink = gn.FirstExternalLink; } else if (gn.ExternalLinkSlotCount > 1) { externalLink = await GetRemainingExternalLink(gn, key.Span[i]); } if (externalLink.Pointer == 0) { var result = await CreateMatchResult(i, null, gn, prev); result.MissingValue = key.Span[i]; result.KeyIndex = i; return(result); } if (!externalLink.LinkToNode) { var result = await CreateMatchResult(i, externalLink.ToLinkObject(), gn, prev); result.KeyIndex = i; return(result); } prev = gn; gn = await ReadNodeStruct(externalLink.Pointer); } return(await CreateMatchResult(key.Length, gn.GetInternalLinkObject(), gn, prev)); }
internal async IAsyncEnumerable <LTrieValue> EnumerateStartsWith(ReadOnlyMemory <byte> startWithKey, EnumerationOrder order) { AssertNotEnumerating(); try { enumerating = true; var res = await FindBestMatch(startWithKey); // In this case, we don't have an exact match, and no children either if (res.ValueLink is null && res.MissingValue is byte) { yield break; } if (res.ValueLink is Link l && l.Label is null) { var record = await GetValueIfStartWith(startWithKey, res.ValueLink.Pointer); if (record is LTrieValue) { yield return(record); } } var nextNodes = new Stack <(int Depth, LTrieNodeStruct Node, int NextLinkIndex)>(); (int Depth, LTrieNodeStruct Node, int NextLinkIndex)current = (res.BestNode.MinKeyLength, await ReadNodeStruct(res.BestNode.OwnPointer), 0); while (current.Depth > -1 || nextNodes.TryPop(out current)) { LTrieNodeExternalLinkStruct link = default; if (current.NextLinkIndex == 0 && current.Node.ExternalLinkSlotCount == 1) { link = current.Node.FirstExternalLink; } else { link = await GetOrderedExternalLink(current.Node, current.NextLinkIndex, order); } if (link.Pointer == 0) { current.Depth = -1; continue; } if (!link.LinkToNode) { var record = await GetValueIfStartWith(startWithKey, link.Pointer); if (record is LTrieValue) { yield return(record); } current.NextLinkIndex++; if (current.NextLinkIndex >= current.Node.ExternalLinkSlotCount) { current.Depth = -1; } } else { var childNode = await ReadNodeStruct(link.Pointer); if (childNode.InternalLinkPointer != 0) { var record = await GetValueIfStartWith(startWithKey, childNode.InternalLinkPointer); if (record is LTrieValue) { yield return(record); } } current.NextLinkIndex++; if (current.NextLinkIndex < current.Node.ExternalLinkSlotCount) { nextNodes.Push((current.Depth, current.Node, current.NextLinkIndex)); } current = (current.Depth + 1, childNode, 0); if (current.NextLinkIndex >= childNode.ExternalLinkSlotCount) { current.Depth = -1; } } } } finally { enumerating = false; } }