Beispiel #1
0
        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);
Beispiel #2
0
        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));
        }
Beispiel #3
0
        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));
        }
Beispiel #4
0
        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;
            }
        }