private uint TakeBlocks(int blocksNeeded) { lock (_sync) { bool rescan = false; bool resized = false; int startingFrom = _prevFreeBlock; int endingBefore = int.MaxValue; while (true) { int found = 0; int last = int.MinValue; int first = int.MaxValue; foreach (int free in _freeBlocks.EnumerateRange(startingFrom, endingBefore)) { if (_reservedBlocks.Contains(free)) { continue; } if (found == 0) { _prevFreeBlock = free; if (!resized && rescan) { _firstFreeBlock = free; } } first = Math.Min(first, free); found = (last + 1 != free) ? 1 : found + 1; last = free; if (found == blocksNeeded) { int start = free - (blocksNeeded - 1); for (int i = start; i <= free; i++) { _freeBlocks.Remove(i); } uint blockId = (uint)start; blockId |= ((uint)Math.Min(16, blocksNeeded) - 1 << 28) & 0xF0000000u; return(blockId); } } if (resized) { throw new ArgumentOutOfRangeException("length"); } if (!rescan && _firstFreeBlock < startingFrom) { rescan = true; endingBefore = startingFrom + blocksNeeded - 1; startingFrom = _firstFreeBlock; } else { resized = true; startingFrom = AddSection(); endingBefore = int.MaxValue; } } } }