示例#1
0
        /// <summary>
        /// Ensure that the given range of placeholders is granular.
        /// </summary>
        /// <param name="id">Start of the range, measured in granular placeholders</param>
        /// <param name="size">Size of the range, measured in granular placeholders</param>
        /// <param name="splitPlaceholderCallback">Callback function to run when splitting placeholders, calls with (start, middle)</param>
        public void EnsurePlaceholders(ulong id, ulong size, Action <ulong, ulong> splitPlaceholderCallback)
        {
            // Search 1 before and after the placeholders, as we may need to expand/join granular regions surrounding the requested area.

            ulong endId         = id + size;
            ulong searchStartId = id == 0 ? 0 : (id - 1);
            int   blockCount    = _placeholders.FindOverlapsNonOverlapping(searchStartId, (endId - searchStartId) + 1, ref _foundBlocks);

            PlaceholderBlock first        = _foundBlocks[0];
            PlaceholderBlock last         = _foundBlocks[blockCount - 1];
            bool             overlapStart = first.EndAddress >= id && id != 0;
            bool             overlapEnd   = last.Address <= endId;

            for (int i = 0; i < blockCount; i++)
            {
                // Go through all non-granular blocks in the range and create placeholders.
                PlaceholderBlock block = _foundBlocks[i];

                if (block.Address <= id && block.EndAddress >= endId && block.IsGranular)
                {
                    return; // The region we're searching for is already granular.
                }

                if (!block.IsGranular)
                {
                    ulong placeholderStart = Math.Max(block.Address, id);
                    ulong placeholderEnd   = Math.Min(block.EndAddress - 1, endId);

                    if (placeholderStart != block.Address && placeholderStart != block.EndAddress)
                    {
                        splitPlaceholderCallback(block.Address, placeholderStart - block.Address);
                    }

                    for (ulong j = placeholderStart; j < placeholderEnd; j++)
                    {
                        splitPlaceholderCallback(j, 1);
                    }
                }

                if (!((block == first && overlapStart) || (block == last && overlapEnd)))
                {
                    // Remove blocks that will be replaced
                    _placeholders.Remove(block);
                }
            }

            if (overlapEnd)
            {
                if (!(first == last && overlapStart))
                {
                    _placeholders.Remove(last);
                }

                if (last.IsGranular)
                {
                    endId = last.EndAddress;
                }
                else if (last.EndAddress != endId)
                {
                    _placeholders.Add(new PlaceholderBlock(endId, last.EndAddress - endId, false));
                }
            }

            if (overlapStart && first.IsGranular)
            {
                first.ExtendTo(endId);
            }
            else
            {
                if (overlapStart)
                {
                    first.ExtendTo(id);
                }

                _placeholders.Add(new PlaceholderBlock(id, endId - id, true));
            }

            ValidateList();
        }
示例#2
0
        /// <summary>
        /// Coalesces placeholders in a given region, as they are not being used.
        /// This assumes that the region only contains placeholders - all views and allocations must have been replaced with placeholders.
        /// </summary>
        /// <param name="id">Start of the range, measured in granular placeholders</param>
        /// <param name="size">Size of the range, measured in granular placeholders</param>
        /// <param name="coalescePlaceholderCallback">Callback function to run when coalescing two placeholders, calls with (start, end)</param>
        public void RemovePlaceholders(ulong id, ulong size, Action <ulong, ulong> coalescePlaceholderCallback)
        {
            ulong endId      = id + size;
            int   blockCount = _placeholders.FindOverlapsNonOverlapping(id, size, ref _foundBlocks);

            PlaceholderBlock first = _foundBlocks[0];
            PlaceholderBlock last  = _foundBlocks[blockCount - 1];

            // All granular blocks must have non-granular blocks surrounding them, unless they start at 0.
            // We must extend the non-granular blocks into the granular ones. This does mean that we need to search twice.

            if (first.IsGranular || last.IsGranular)
            {
                ulong surroundStart = Math.Max(0, (first.IsGranular && first.Address != 0) ? first.Address - 1 : id);
                blockCount = _placeholders.FindOverlapsNonOverlapping(
                    surroundStart,
                    (last.IsGranular ? last.EndAddress + 1 : endId) - surroundStart,
                    ref _foundBlocks);

                first = _foundBlocks[0];
                last  = _foundBlocks[blockCount - 1];
            }

            if (first == last)
            {
                return; // Already coalesced.
            }

            PlaceholderBlock extendBlock = id == 0 ? null : first;
            bool             newBlock    = false;

            for (int i = extendBlock == null ? 0 : 1; i < blockCount; i++)
            {
                // Go through all granular blocks in the range and extend placeholders.
                PlaceholderBlock block = _foundBlocks[i];

                ulong blockEnd = block.EndAddress;
                ulong extendFrom;
                ulong extent = Math.Min(blockEnd, endId);

                if (block.Address < id && blockEnd > id)
                {
                    block.ExtendTo(id);
                    extendBlock = null;
                }
                else
                {
                    _placeholders.Remove(block);
                }

                if (extendBlock == null)
                {
                    extendFrom  = id;
                    extendBlock = new PlaceholderBlock(id, extent - id, false);
                    _placeholders.Add(extendBlock);

                    if (blockEnd > extent)
                    {
                        _placeholders.Add(new PlaceholderBlock(extent, blockEnd - extent, true));

                        // Skip the next non-granular block, and extend from that into the granular block afterwards.
                        // (assuming that one is still in the requested range)

                        if (i + 1 < blockCount)
                        {
                            extendBlock = _foundBlocks[i + 1];
                        }

                        i++;
                    }

                    newBlock = true;
                }
                else
                {
                    extendFrom = extendBlock.Address;
                    extendBlock.ExtendTo(block.IsGranular ? extent : block.EndAddress);
                }

                if (block.IsGranular)
                {
                    ulong placeholderStart = Math.Max(block.Address, id);
                    ulong placeholderEnd   = extent;

                    if (newBlock)
                    {
                        placeholderStart++;
                        newBlock = false;
                    }

                    for (ulong j = placeholderStart; j < placeholderEnd; j++)
                    {
                        coalescePlaceholderCallback(extendFrom, (j + 1) - extendFrom);
                    }

                    if (extent < block.EndAddress)
                    {
                        _placeholders.Add(new PlaceholderBlock(placeholderEnd, block.EndAddress - placeholderEnd, true));
                        ValidateList();
                        return;
                    }
                }
                else
                {
                    coalescePlaceholderCallback(extendFrom, block.EndAddress - extendFrom);
                }
            }

            ValidateList();
        }