Exemple #1
0
 private ushort GetHead(int arenaIndex)
 {
     return(_memory.Read <ushort>(_headsPtr + (arenaIndex * sizeof(ushort))));
 }
Exemple #2
0
        /// <summary>
        /// Find the chunk (with start index) that contains or is before the given index
        /// </summary>
        protected void FindNearestChunk(uint targetIndex, out bool found, out long chunkPtr, out uint chunkIndex)
        {
            unchecked
            {
                // 1. Calculate desired chunk index
                uint targetChunkIdx = (uint)(targetIndex / ElemsPerChunk);
                uint endChunkIdx    = (uint)((_elementCount - 1) / ElemsPerChunk);

                // 2. Optimise for start- and end- of chain (small lists & very likely for Push & Pop)
                if (targetChunkIdx == 0)
                { // start of chain
                    found      = true;
                    chunkPtr   = _baseChunkTable;
                    chunkIndex = targetChunkIdx;
                    return;
                }
                if (_elementCount == 0 || targetChunkIdx == endChunkIdx)
                { // lands in a chunk
                    found      = true;
                    chunkPtr   = _endChunkPtr;
                    chunkIndex = targetChunkIdx;
                    return;
                }
                if (targetIndex >= _elementCount)
                { // lands outside a chunk -- off the end
                    found      = false;
                    chunkPtr   = _endChunkPtr;
                    chunkIndex = targetChunkIdx;
                    return;
                }

                // All the simple optimal paths failed. Make sure the skip list is good...
                MaybeRebuildSkipTable();

                // 3. Use the skip table to find a chunk near the target
                //    By ensuring the skip table is fresh, we can calculate the correct location
                uint startChunkIdx = 0;
                var  chunkHeadPtr  = _baseChunkTable;

                if (_skipEntries > 1)
                {
                    // guess search bounds
                    var guess = (targetChunkIdx * _skipEntries) / endChunkIdx;
                    var upper = guess + 2;
                    var lower = guess - 2;
                    if (upper > _skipEntries)
                    {
                        upper = _skipEntries;
                    }
                    if (lower < 0)
                    {
                        lower = 0;
                    }

                    // binary search for the best chunk
                    while (lower < upper)
                    {
                        var mid = ((upper - lower) / 2) + lower;
                        if (mid == lower)
                        {
                            break;
                        }

                        var midChunkIdx = _mem.Read <uint>(_skipTable + (SKIP_ELEM_SIZE * mid));
                        if (midChunkIdx == targetChunkIdx)
                        {
                            break;
                        }

                        if (midChunkIdx < targetChunkIdx)
                        {
                            lower = mid;
                        }
                        else
                        {
                            upper = mid;
                        }
                    }

                    var baseAddr = _skipTable + (SKIP_ELEM_SIZE * lower); // pointer to skip table entry
                    startChunkIdx = _mem.Read <uint>(baseAddr);
                    chunkHeadPtr  = _mem.Read <long>(baseAddr + INDEX_SIZE);
                }

                var walk = targetChunkIdx - startChunkIdx;
                if (walk > 5 && _skipEntries < SKIP_TABLE_SIZE_LIMIT)
                {
                    _skipTableDirty = true; // if we are walking too far, try builing a better table
                }

                // 4. Walk the chain until we find the chunk we want
                for (; startChunkIdx < targetChunkIdx; startChunkIdx++)
                {
                    chunkHeadPtr = _mem.Read <long>(chunkHeadPtr);
                }

                found      = true;
                chunkPtr   = chunkHeadPtr;
                chunkIndex = targetChunkIdx;
            }
        }
Exemple #3
0
        public Result <long> AddChild(long parent, TElement element)
        {
            if (parent < 0)
            {
                return(Result.Fail <long>());
            }

            var head = _mem.Read <TreeNodeHead>(parent);

            if (head.FirstChildPtr >= 0) // There is a sibling chain. Switch function
            {
                return(AddSibling(head.FirstChildPtr, element));
            }

            // This is the first child of this parent
            var res = AllocateAndWriteNode(parent, element);

            if (!res.Success)
            {
                return(Result.Fail <long>());
            }
            var newChildPtr = res.Value;

            // Set ourself as the parent's first child
            head.FirstChildPtr = newChildPtr;
            _mem.Write(parent, head);
            return(Result.Ok(newChildPtr));
        }