internal void Add(Pointer data, int size, ref int dstOffset) { int treeIndex; switch (size) { case 32: treeIndex = (int)Index.Index32; break; case 16: treeIndex = (int)Index.Index16; break; case 8: treeIndex = (int)Index.Index8; break; case 4: treeIndex = (int)Index.Index4; break; case 2: treeIndex = (int)Index.Index2; break; case 1: treeIndex = (int)Index.Index1; break; default: throw new ArgumentException(); } var node = _tree[treeIndex].Get(data); if (node != null) { dstOffset = node.Offset; return; } // Before incrementing the current offset try if there is a gap that can // be used for the requested data. var offset = int.MinValue; var gapIndex = treeIndex; while (gapIndex != (int)Index.IndexCount - 1) { var gap = _gaps[treeIndex]; // Check if there is a gap. if (gap != null) { var gapOffset = gap.Offset; var gapLength = gap.Length; // Destroy the gap for now. _gaps[treeIndex] = gap.Next; FreeGap(gap); offset = gapOffset; if (!offset.IsAligned(size)) { throw new Exception("Alignment required"); } gapLength -= size; if (gapLength > 0) { AddGap(gapOffset, gapLength); } } gapIndex++; } if (offset == int.MinValue) { // Get how many bytes have to be skipped so the address is aligned accordingly // to the 'size'. var diff = Size.AlignDiff(size); if (diff != 0) { AddGap(Size, diff); Size += diff; } offset = Size; Size += size; } // Add the initial node to the right index. node = Tree.NewNode(data, size, offset, false); if (node == null) { throw new OutOfMemoryException(); } _tree[treeIndex].Put(node); Alignment = Math.Max(Alignment, size); dstOffset = offset; // Now create a bunch of shared constants that are based on the data pattern. // We stop at size 4, it probably doesn't make sense to split constants down // to 1 byte. var count = 1; while (size > 4) { size >>= 1; count <<= 1; if (treeIndex == 0) { throw new IndexOutOfRangeException(); } treeIndex--; var pData = data; for (var i = 0; i < count; i++, pData += size) { node = _tree[treeIndex].Get(pData); if (node != null) { continue; } node = Tree.NewNode(pData, size, offset + (i * size), true); _tree[treeIndex].Put(node); } } }