Breaking News

Saturday, October 16, 2010

How to: create Custom ByteArray class

A friend sent this to me, as an Urgent question,

Write a class called ByteArray that implement allocating, reading and writing to an array of bytes. The runtime environment has a limitation. The maximum continuous memory size that it can allocated is 64k bytes. It can allocate many 64K ( or less) chunks.
The ByteArray class should hide this limitation and support allocating arrays larger than 64K as in the following example :

ByteArray ba = new ByteArray (250000); // Create
ba[150000] = 15; // Write byte
byte x = ba[190000]; // Read byte

This question is really asking for if you know how to implement the index. I responded with the following one minute recipe.


class ByteArray
{
    byte[] _Byte;
    const int _MaxSizeinKB = 64;
    const int _MaxSizeInBytes = _MaxSizeinKB * 1024;
    public ByteArray(int nLength)
    {
        if (nLength > _MaxSizeInBytes)
            throw new InsufficientMemoryException("Cannot allocate more than " + _MaxSizeinKB.ToString() + "KB");
        else
            _Byte = new byte[nLength];
    }

    public byte this[int nIndex]
    {
        get { return _Byte[nIndex]; }
        set { _Byte[nIndex] = value; }
    }
}

Usage is as above in the question. Enjoy!

Thanks for pointing out.

I have updated the code the reflect the same.

--EDIT--

This is an update based upon the comment that I received. I missed the last sentence; that is,
The ByteArray class should hide this limitation and support allocating arrays larger than 64k
This update adds rest of the functionality; following is the updated ByteArray class:
class ByteArrayEx
{
    private List lstArray = new List();
    public int _nSize;
    public int _nChunks;

    public const int _MaxSizeLimit = 65536;//3;//65536;//64K
    public ByteArrayEx(int nSize)
    {
        _nSize = nSize;
        if (nSize > _MaxSizeLimit)
        {
            //1. Calculate the number of 64K chunks
            int nChunks = nSize / _MaxSizeLimit;

            //130K; 64K + 64K + 2K
            //64 = 130/
            //2 = 64k x 2 = 128k
            //Remaining = 128 - 130 = 2
            //Remaining = nLengh - AllocatedSize

            int nAllocatedSize = 0;
            //2. Loop through the chunks
            for (int i = 0; i < nChunks; i++)
            {
                //3. Allocate the size
                nAllocatedSize = _MaxSizeLimit + nAllocatedSize;
                lstArray.Add(new byte[_MaxSizeLimit]);

            }

            //4. Allocate remaining bytes
            int nRemainingBytes = nSize - nAllocatedSize;
            if (nRemainingBytes > 0)
                lstArray.Add(new byte[nRemainingBytes]);

            _nChunks = lstArray.Count;
        }
        else
            lstArray.Add(new byte[nSize]);

    }

    public byte this[int nIndex]
    {
        get
        {
            //1. Get the index of array list item
            //2. Convert the incoming index to Index of byte array
            int nByteIndex = nIndex % _MaxSizeLimit;

            return ((byte[])(lstArray[GetBlockIndex(nIndex)]))[nByteIndex];
        }
        set
        {
            //1. Get the index/block of array list
            //2. Convert the incoming index to Index of byte array

            int nBlockIndex = GetBlockIndex(nIndex);
            int nByteIndex = nIndex % _MaxSizeLimit;

            ((byte[])(lstArray[nBlockIndex]))[nByteIndex] = value;
        }
    }

    /// 
    /// Block, represents the index of List item
    /// 
    /// Incoming Index    /// Actual Block Index
    private int GetBlockIndex(int nIndex)
    {
        int nAllocatedSize = 0;
        //2. Loop through the chunks
        int nBlockIndex = 0;
        for (int i = 0; i < _nChunks; i++)
        {
            //3. Allocate the size
            nAllocatedSize = _MaxSizeLimit + nAllocatedSize;
            if (nIndex <= nAllocatedSize)
            {
                nBlockIndex = i;
                break;
            }
        }
        return nBlockIndex;
    }
}

Usage is as follows:
ByteArray ba = new ByteArray (250000); // Create
ba[150000] = 15; // Write byte
byte x = ba[190000]; // Read byte

Couple of things to note; the 64K limit that is in the ByteArrayEx class can be anything; for instance:

In case of 64K of it would create single array to contain all the byte array elements.
In case of 128K (64K x 2 = 128K), it will create 2 items in the array list of size 64K each.
In case of 130K (64K x 2 + 2K more = 128K + 2K = 130K) it will create 3 items in the array list; this time, two items of size 64K and third item of size 2K. So array list would contain 3 byte arrays.

Hope you get the idea.

You can change the 64K limit to 32K or 8K or 3K, etc; and it will work as above.

Checkout the output, for the following given input:
class Program
{
    static void Main(string[] args)
    {
        //Test 1
        ByteArrayEx baTest1 = new ByteArrayEx(133120);// (64 + 64 + 2) * 1024; //130K or 133120 bytes

        baTest1[0] = (byte)'c';//Write
        Console.WriteLine(string.Format("Written byte:[{0}]", Convert.ToChar(baTest1[0])));

        baTest1[133110] = (byte)'d';//Write more
        Console.WriteLine(string.Format("Written byte:[{0}]", Convert.ToChar(baTest1[133110])));

        byte r = baTest1[133110];// be[133110];

        Console.WriteLine(string.Format("Reading byte:[{0}]", Convert.ToChar(r)));
        Console.WriteLine(string.Format("Max Limit: {0}, Size: {1}, Chunks: {2}", ByteArrayEx._MaxSizeLimit,
            baTest1._nSize, baTest1._nChunks));


        //Test 2
        ByteArrayEx byteArray = new ByteArrayEx(250000); // Create
        byteArray[150000] = 15; // Write byte
        byte x = byteArray[190000]; // Read byte
        Console.WriteLine(string.Format("byte:[{0}]", x));

        Console.WriteLine(string.Format("Max Limit: {0}, Size: {1}, Chunks: {2}", ByteArrayEx._MaxSizeLimit,
        byteArray._nSize, byteArray._nChunks));

        Console.ReadKey();


    }
} 
 
Note that, I have the List class to demostrate the functionality. You can add any class that provides array like functionality.

2 comments:

  1. Anonymous6:58 PM

    But your solution does not solve the following requirement:

    The ByteArray class should hide this limitation and support allocating arrays larger than 64k

    You need to have multiple array for each 64k chunk.

    ReplyDelete
  2. Thanks for pointing out. I have updated the code to reflect the required functionality.

    ReplyDelete

Designed By Published.. Blogger Templates