コード例 #1
0
        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);
                }
            }
        }