public void TestBasics() { OrdinalList list = new OrdinalList(); Assert.IsFalse(list.IsReadOnly); list.Ceiling = 0; for (int i = 512; i >= 0; i--) list.Add(i); int offset = 0; foreach (int item in list) Assert.AreEqual(offset++, item); Assert.AreEqual(513, offset); Assert.AreEqual(513, list.Count); Assert.AreEqual(519, list.Ceiling); list.Clear(); list.AddRange(new int[] { 5, 10, 20 }); list.AddRange(new int[] { }); Assert.AreEqual(3, list.Count); Assert.AreEqual(23, list.Ceiling); Assert.IsTrue(list.Contains(20)); Assert.IsTrue(list.Remove(20)); Assert.IsFalse(list.Contains(20)); Assert.IsFalse(list.Remove(20)); Assert.AreEqual(2, list.Count); int[] items = new int[2]; list.CopyTo(items, 0); Assert.AreEqual(5, items[0]); Assert.AreEqual(10, items[1]); items = list.ToArray(); Assert.AreEqual(5, items[0]); Assert.AreEqual(10, items[1]); byte[] bits = list.ToByteArray(); Assert.AreEqual(3, bits.Length); Assert.AreEqual(2, new OrdinalList(bits).Count); List<int> tmp = new List<int>(); foreach (int i in list) tmp.Add(i); Assert.AreEqual(2, tmp.Count); Assert.AreEqual(5, tmp[0]); Assert.AreEqual(10, tmp[1]); }
/// <summary> /// Allocates a handle for data, you MUST call Write to commit the handle, otherwise the handle /// may be reallocated after closing and re-opening this file. If you do not intend to commit /// the handle by writing to it, you should still call Delete() so that it may be reused. /// </summary> public uint Create() { uint handle = 0; lock (_sync) { while (handle == 0) { foreach (int i in _freeHandles.EnumerateFrom(_prevFreeHandle)) { _freeHandles.Remove(i); _prevFreeHandle = i + 1; handle = (uint)i; break; } if (handle == 0) { AddSection(); } } } HandleRef href = new HandleRef(handle, BlockSize); uint blockId = _sections[href.Section][href.Offset]; if (blockId != 0) { throw new InvalidDataException(); } return(handle); }
private uint TakeBlocks(int blocksNeeded) { lock (_sync) { bool resized = false; while (true) { int found = 0; int last = int.MinValue; int first = int.MaxValue; foreach (int free in _freeBlocks.EnumerateFrom(_prevFreeBlock)) { if (_reservedBlocks.Contains(free)) { continue; } first = Math.Min(first, free); found = (last + 1 != free) ? 1 : found + 1; last = free; if (found == blocksNeeded) { _prevFreeBlock = first; 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"); } resized = true; AddSection(); } } }
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; } } } }