in src/Proton/Buffer/ProtonCompositeBuffer.cs [473:557]
private IProtonBuffer DoEnsureWritable(long amount, bool allowCompaction = true, long minimumGrowth = 1)
{
if (amount < 0)
{
throw new ArgumentOutOfRangeException(nameof(amount), "Growth amount must be greater than zero");
}
if (WritableBytes >= amount)
{
return this;
}
if (minimumGrowth < 0)
{
throw new ArgumentOutOfRangeException(nameof(minimumGrowth), "The minimum growth cannot be negative: " + minimumGrowth + '.');
}
if (allowCompaction && amount <= readOffset)
{
int compactableBuffers = 0;
foreach (IProtonBuffer candidate in buffers)
{
if (candidate.Capacity != candidate.ReadOffset)
{
break;
}
compactableBuffers++;
}
if (compactableBuffers > 0)
{
IProtonBuffer[] compactable;
if (compactableBuffers < buffers.Length)
{
compactable = new IProtonBuffer[compactableBuffers];
Array.ConstrainedCopy(buffers, 0, compactable, 0, compactable.Length);
Array.ConstrainedCopy(buffers, compactable.Length, buffers, 0, buffers.Length - compactable.Length);
Array.ConstrainedCopy(compactable, 0, buffers, buffers.Length - compactable.Length, compactable.Length);
}
else
{
compactable = buffers;
}
foreach (IProtonBuffer target in compactable)
{
target.Reset();
}
ComputeOffsetsAndIndexes();
if (WritableBytes >= amount)
{
return this;
}
}
else if (buffers.Length == 1)
{
// If we only have a single component buffer, then we can safely compact that in-place.
buffers[0].Compact();
ComputeOffsetsAndIndexes();
if (WritableBytes >= amount)
{
return this;
}
}
}
long growth = Math.Max(amount - WritableBytes, minimumGrowth);
if (growth < 0)
{
throw new ArgumentOutOfRangeException("Buffer size must not be negative, but was " + growth + '.');
}
if ((ulong)(growth + Capacity) > (ulong)maxCapacity)
{
throw new ArgumentOutOfRangeException(
"Buffer size cannot be made greater than " + maxCapacity +
", but was requested to grow to" + (ulong)(growth + Capacity) + '.');
}
IProtonBuffer extension = allocator.Allocate(growth);
AppendValidatedBuffer(extension);
return this;
}