/// <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)); }
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); }
private void RegisterAreaSize(FreeArea area) { int index = ListSearching.BinarySearch(_freeAreasBySize, area.Size, a => a.Size); if (index < 0) { index = ~index; } _freeAreasBySize.Insert(index, area); }
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))); }
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); }