// returns the block at which the specifed number of blocks have been allocated
        // returns -1 if blocks could not be allocated
        public int Allocate(int blocks)
        {
            // Walk down the tree, stopping at the first node that can allocate the needed number of blocks
            int offset = -1;

            if (root != null)
            {
                root = root.Allocate(blocks, out offset);
            }
            return(offset);
        }
        public override IMemTreeNode Allocate(int blocks, out int offset)
        {
            // locate a child node that can allocate blocks
            int leftDelta, rightDelta;

            leftDelta  = leftChild.ContiguousBlocks - blocks;
            rightDelta = rightChild.ContiguousBlocks - blocks;

            if (leftDelta < 0 && rightDelta < 0)
            {
                offset = -1;
                return(this);
            }

            if (leftDelta < 0)
            {
                // left delta is negative, so make sure it loses out in the next if statement
                leftDelta = rightDelta + 1;
            }
            else if (rightDelta < 0)
            {
                // right delta is negative, so make sure it loses out in the next if statement
                rightDelta = leftDelta + 1;
            }

            // check which side has a contiguous block closest to the size we need
            if (leftDelta < rightDelta)
            {
                // note that this CAN'T fail and return -1; We've just checked that there IS a contiguous block that will hold the allocation
                leftChild = leftChild.Allocate(blocks, out offset);
                if (leftChild == null)
                {
                    // left child was consumed by allocation
                    return(rightChild);
                }
                else
                {
                    // This index nodes will continue to exist, so update the contiguous block count
                    // THIS can be optimized. Taking into account that we know the contiguous count for the subnodes before the allocation, and how many blocks we'll be shaving off
                    // it is possible to determine wether we actually need to do this update or not.
                    contiguousBlocks = (leftChild.ContiguousBlocks < rightChild.ContiguousBlocks) ? rightChild.ContiguousBlocks : leftChild.ContiguousBlocks;
                    return(this);
                }
            }
            else
            {
                // note that this CAN'T fail and return -1; We've just checked that there IS a contiguous block that will hold the allocation
                rightChild = rightChild.Allocate(blocks, out offset);
                if (rightChild == null)
                {
                    // right child was consumed by allocation
                    return(leftChild);
                }
                else
                {
                    // This index nodes will continue to exist, so update the contiguous block count
                    // THIS can be optimized. Taking into account that we know the contiguous count for the subnodes before the allocation, and how many blocks we'll be shaving off
                    // it is possible to determine wether we actually need to do this update or not.
                    contiguousBlocks = (leftChild.ContiguousBlocks < rightChild.ContiguousBlocks) ? rightChild.ContiguousBlocks : leftChild.ContiguousBlocks;
                    return(this);
                }
            }


            //leftChild = leftChild.Allocate(blocks, out offset);
            //if (offset == -1)
            //{

            //    rightChild = rightChild.Allocate(blocks, out offset);
            //    if (rightChild == null)
            //    {   // right child was consumed by allocation
            //        return leftChild;
            //    }
            //    else
            //    {
            //        // This index nodes will continue to exist, so update the contiguous block count
            //        // THIS can be optimized. Taking into account that we know the contiguous count for the subnodes before the allocation, and how many blocks we'll be shaving off
            //        // it is possible to determine wether we actually need to do this update or not.
            //        contiguousBlocks = (contiguousBlocks < rightChild.ContiguousBlocks) ? rightChild.ContiguousBlocks : contiguousBlocks;
            //        return this;
            //    }
            //}
            //else if (leftChild == null)
            //{   // left child was consumed by allocation
            //    return rightChild;
            //}
            //else
            //{
            //    // This index nodes will continue to exist, so update the contiguous block count
            //    // THIS can be optimized. Taking into account that we know the contiguous count for the subnodes before the allocation, and how many blocks we'll be shaving off
            //    // it is possible to determine wether we actually need to do this update or not.
            //    contiguousBlocks = (leftChild.ContiguousBlocks < contiguousBlocks) ? contiguousBlocks : leftChild.ContiguousBlocks;
            //    return this;
            //}
        }