Example #1
0
 public unsafe void ResizeToAtLeast(ref RawBuffer buffer, int targetSize, int copyCount)
 {
     Debug.Assert(copyCount <= buffer.Length, "Can't copy more than the capacity of the buffer.");
     Debug.Assert(copyCount <= targetSize, "Can't copy more than the target size.");
     //Only do anything if the new size is actually different from the current size.
     targetSize = 1 << (SpanHelper.GetContainingPowerOf2(targetSize));
     if (buffer.Allocated)
     {
         DecomposeId(buffer.Id, out var powerIndex, out var slotIndex);
         var currentSize = 1 << powerIndex;
         if (currentSize != targetSize || pools[powerIndex].GetStartPointerForSlot(slotIndex) != buffer.Memory)
         {
             TakeAtLeast(targetSize, out var newBuffer);
             Buffer.MemoryCopy(buffer.Memory, newBuffer.Memory, buffer.Length, copyCount);
             pools[powerIndex].Return(slotIndex);
             buffer = newBuffer;
         }
         else
         {
             //While the allocation size is equal to the target size, the buffer might not be.
             //Fortunately, if the allocation stays the same size and the buffer start is at its original location, we can skip doing any work.
             //(With more work, you could expand *backwards*, we just didn't bother since this is exceptionally rare anyway.
             //The typed codepath doesn't bother doing this at all, and that's fine.)
             buffer.Length = targetSize;
         }
     }
     else
     {
         //Nothing to return or copy.
         TakeAtLeast(targetSize, out buffer);
     }
 }
Example #2
0
 public static int GetCapacityForCount <T>(int count)
 {
     if (count == 0)
     {
         count = 1;
     }
     return((1 << SpanHelper.GetContainingPowerOf2(count * Unsafe.SizeOf <T>())) / Unsafe.SizeOf <T>());
 }
Example #3
0
            public PowerPool(int power, int minimumBlockSize, int expectedPooledCount)
            {
                Power                       = power;
                SuballocationSize           = 1 << power;
                BlockSize                   = Math.Max(SuballocationSize, minimumBlockSize);
                Slots                       = new ManagedIdPool(expectedPooledCount);
                SuballocationsPerBlock      = BlockSize / SuballocationSize;
                SuballocationsPerBlockShift = SpanHelper.GetContainingPowerOf2(SuballocationsPerBlock);
                SuballocationsPerBlockMask  = (1 << SuballocationsPerBlockShift) - 1;
                Blocks                      = new Block[1];
                BlockCount                  = 0;

#if DEBUG
                outstandingIds = new HashSet <int>();
#if LEAKDEBUG
                outstandingAllocators = new Dictionary <string, HashSet <int> >();
#endif
#endif
            }
Example #4
0
            public unsafe void Take(out RawBuffer buffer)
            {
                var slot       = Slots.Take();
                var blockIndex = slot >> SuballocationsPerBlockShift;

                if (blockIndex >= Blocks.Length)
                {
                    Array.Resize(ref Blocks, 1 << SpanHelper.GetContainingPowerOf2(blockIndex + 1));
                }
                if (blockIndex >= BlockCount)
                {
#if DEBUG
                    for (int i = 0; i < blockIndex; ++i)
                    {
                        Debug.Assert(Blocks[i].Allocated, "If a block index is found to exceed the current block count, then every block preceding the index should be allocated.");
                    }
#endif
                    BlockCount = blockIndex + 1;
                    Debug.Assert(!Blocks[blockIndex].Allocated);
                    Blocks[blockIndex] = new Block(BlockSize);
                }

                var indexInBlock = slot & SuballocationsPerBlockMask;
                buffer = new RawBuffer(Blocks[blockIndex].Allocate(indexInBlock, SuballocationSize), SuballocationSize, (Power << IdPowerShift) | slot);
                Debug.Assert(buffer.Id >= 0 && Power >= 0 && Power < 32, "Slot/power should be safely encoded in a 32 bit integer.");
#if DEBUG
                const int maximumOutstandingCount = 1 << 20;
                Debug.Assert(outstandingIds.Count <= maximumOutstandingCount,
                             $"Do you actually truly really need to have {maximumOutstandingCount} allocations taken from this power pool, or is this a memory leak?");
                Debug.Assert(outstandingIds.Add(slot), "Should not be able to request the same slot twice.");
#if LEAKDEBUG
                var allocator = new StackTrace().ToString();
                if (!outstandingAllocators.TryGetValue(allocator, out var idsForAllocator))
                {
                    idsForAllocator = new HashSet <int>();
                    outstandingAllocators.Add(allocator, idsForAllocator);
                }
                Debug.Assert(idsForAllocator.Count < (1 << 25), "Do you actually have that many allocations for this one allocator?");
                idsForAllocator.Add(slot);
#endif
#endif
            }
Example #5
0
 public void TakeAtLeast(int count, out RawBuffer buffer)
 {
     TakeForPower(SpanHelper.GetContainingPowerOf2(count), out buffer);
 }
Example #6
0
 /// <summary>
 /// Gets the capacity allocated for a power.
 /// </summary>
 /// <param name="power">Power to check.</param>
 /// <returns>Allocated capacity for the given power.</returns>
 public int GetCapacityForPower(int power)
 {
     SpanHelper.ValidatePower(power);
     return(pools[power].BlockCount * pools[power].BlockSize);
 }
Example #7
0
 /// <summary>
 /// Ensures that the pool associated with a given power has at least a certain amount of capacity, measured in bytes.
 /// </summary>
 /// <param name="byteCount">Minimum number of bytes to require for the power pool.</param>
 /// <param name="power">Power associated with the pool to check.</param>
 public void EnsureCapacityForPower(int byteCount, int power)
 {
     SpanHelper.ValidatePower(power);
     ValidatePinnedState(true);
     pools[power].EnsureCapacity(byteCount);
 }