/// <summary>
        ///     Translates a stringID into an index into the global debug strings array.
        /// </summary>
        /// <param name="id">The StringID to translate.</param>
        /// <returns>The index of the string in the global debug strings array.</returns>
        public int StringIDToIndex(StringID id)
        {
            // Find the index of the first set which is less than the set in the ID
            int closestSetIndex = ListSearching.BinarySearch(_setsByID.Keys, id.GetSet(IDLayout));

            if (closestSetIndex < 0)
            {
                // BinarySearch returns the bitwise complement of the index of the next highest value if not found
                // So, use the set that comes before it...
                closestSetIndex = ~closestSetIndex - 1;
                if (closestSetIndex < 0)
                {
                    return((int)id.Value);                     // No previous set defined - just return the handle
                }
            }

            // If the index falls outside the set's min value, then put it into the previous set
            if (id.GetIndex(IDLayout) < _setsByID.Values[closestSetIndex].MinIndex)
            {
                closestSetIndex--;
                if (closestSetIndex < 0)
                {
                    return((int)id.Value);
                }
            }

            // Calculate the array index by subtracting the value of the first ID in the set
            // and then adding the index in the global array of the set's first string
            StringIDSet set     = _setsByID.Values[closestSetIndex];
            var         firstId = new StringID(set.ID, set.MinIndex, IDLayout);

            return((int)(id.Value - firstId.Value + set.GlobalIndex));
        }
예제 #2
0
        private FreeArea FindSmallestBlock(int minSize, uint align)
        {
            if (minSize <= 0)
            {
                throw new ArgumentException("Invalid block size");
            }

            int index = ListSearching.BinarySearch(_freeAreasBySize, minSize, a => a.Size);

            if (index < 0)
            {
                index = ~index;                 // Get the index of the next largest block
            }
            // Search until a block is found where the data can be aligned in
            while (index < _freeAreasBySize.Count)
            {
                FreeArea area           = _freeAreasBySize[index];
                long     alignedAddress = (area.Address + align - 1) & ~((long)align - 1);
                if (alignedAddress + minSize <= area.Address + area.Size)
                {
                    return(area);
                }

                index++;
            }
            return(null);
        }
예제 #3
0
        private void RegisterAreaSize(FreeArea area)
        {
            int index = ListSearching.BinarySearch(_freeAreasBySize, area.Size, a => a.Size);

            if (index < 0)
            {
                index = ~index;
            }
            _freeAreasBySize.Insert(index, area);
        }
예제 #4
0
        public void Add(ITag tag)
        {
            // Insert the tag in order by datum index
            // NOTE: Casting the datum index to a signed value is necessary because that's what the XEX does
            var index = ListSearching.BinarySearch(_table, (int)tag.Index.Value, (t) => (int)t.Index.Value);

            if (index >= 0)
            {
                return;
            }
            index = ~index;
            _table.Insert(index, tag);
            _changed = true;
        }
        /// <summary>
        ///     Translates a string index into a stringID which can be written to the file.
        /// </summary>
        /// <param name="index">The index of the string in the global strings array.</param>
        /// <returns>The stringID associated with the index.</returns>
        public StringID IndexToStringID(int index)
        {
            // Determine which set the index belongs to by finding the set with the closest global index that comes before it
            int closestSetIndex = ListSearching.BinarySearch(_setsByGlobalIndex.Keys, index);

            if (closestSetIndex < 0)
            {
                // BinarySearch returns the bitwise complement of the index of the next highest value if not found
                // So negate it and subtract 1 to get the closest global index that comes before it
                closestSetIndex = ~closestSetIndex - 1;
                if (closestSetIndex < 0)
                {
                    return(new StringID((uint)index));                     // No previous set defined - just return the index
                }
            }

            // Calculate the StringID by subtracting the set's global array index
            // and then adding the value of the first stringID in the set
            StringIDSet set     = _setsByGlobalIndex.Values[closestSetIndex];
            var         firstId = new StringID(set.ID, set.MinIndex, IDLayout);

            return(new StringID((uint)(index - set.GlobalIndex + firstId.Value)));
        }
예제 #6
0
        private FreeArea FreeBlock(long address, int size)
        {
            if (size <= 0)
            {
                throw new ArgumentException("Invalid block size");
            }

            int index = ListSearching.BinarySearch(_freeAreasByAddr.Keys, address);

            if (index >= 0)
            {
                // Address is already free, but if the size doesn't overlap anything, then allow it
                FreeArea freedArea = _freeAreasByAddr.Values[index];
                if (freedArea.Address + freedArea.Size < address + size)
                {
                    throw new InvalidOperationException("Part of the block is already free");
                }
                return(freedArea);
            }

            // Get pointers to the previous and next free blocks
            index = ~index;             // Get index of first largest area
            FreeArea next = null, previous = null;

            if (index > 0)
            {
                previous = _freeAreasByAddr.Values[index - 1];
                if (previous.Address + previous.Size >= address + size)
                {
                    return(previous);
                }
                if (previous.Address + previous.Size > address && previous.Address + previous.Size < address + size)
                {
                    throw new InvalidOperationException("Part of the block is already free");
                }
            }
            if (index < _freeAreasByAddr.Count)
            {
                next = _freeAreasByAddr.Values[index];
                if (address + size > next.Address)
                {
                    throw new InvalidOperationException("Part of the block is already free");
                }
            }

            // Four possible cases here:
            // 1. We're filling in a hole between two blocks, in which case we delete the second and expand the first
            // 2. The block being freed is immediately after another block, in which case we expand the previous block
            // 3. The block being freed is immediately before another block, in which case we change the next block's start address and size
            // 4. The block being freed has no neighbors, in which case it's just added to the list
            if (next != null && previous != null)
            {
                // Check if we're filling in a hole between two free areas
                // If we are, then merge the three areas together
                if (previous.Address + previous.Size == address && address + size == next.Address)
                {
                    RemoveArea(next);
                    ResizeArea(previous, previous.Size + size + next.Size);
                    return(previous);
                }
            }
            if (previous != null)
            {
                // Check if the previous block extends up to the address that's being freed
                // If it does, resize it to help prevent heap fragmentation
                if (previous.Address + previous.Size == address)
                {
                    // Just resize the block before it
                    ResizeArea(previous, previous.Size + size);
                    return(previous);
                }
            }
            if (next != null)
            {
                // Check if the next block starts at the end of the block that's being freed
                // If it does, resize it to help prevent heap fragmentation
                if (address + size == next.Address)
                {
                    // Change the start address of the block after it
                    ChangeStartAddress(next, address);
                    return(next);
                }
            }

            // Just create a new free area for the block, we're done
            var area = new FreeArea {
                Address = address, Size = size
            };

            AddArea(area);
            return(area);
        }