/// <summary>Remove the value at the specified location</summary>
        /// <param name="level">Index of the level (0-based)</param>
        /// <param name="offset">Offset in the level (0-based)</param>
        /// <returns>Value that was removed</returns>
        public T RemoveAt(int level, int offset)
        {
            Contract.Assert(level >= 0 && offset >= 0 && offset < 1 << level);
            //TODO: check if level is allocated ?

            var segment = m_levels[level];

            Contract.Assert(segment != null && segment.Length == 1 << level);
            T removed = segment[offset];

            if (level == 0)
            {             // removing the last inserted value
                segment[0] = default(T);
            }
            else if (level == 1)
            {             // split the first level in two
                if (IsFree(0))
                {         // move up to root
                    // ex: remove 'b' at (1,1) and move the 'a' back to the root
                    // 0 [_]	=> [a]
                    // 1 [a,b]	=> [_,_]

                    m_root[0]  = segment[1 - offset];
                    segment[0] = default(T);
                    segment[1] = default(T);
                }
                else
                {                 // merge the root in missing spot
                    // ex: remove 'b' at (1,1) and move the 'c' down a level
                    //		  N = 3		N = 2
                    //		0 [c]	=>	0 [_]
                    //		1 [a,b]	=>	1 [a,c]

                    ColaStore.MergeSimple <T>(segment, m_root[0], segment[1 - offset], m_comparer);
                    m_root[0] = default(T);
                }
            }
            else if ((m_count & 1) == 1)
            {             // Remove an item from an odd-numbered set
                // Since the new count will be even, we only need to merge the root in place with the level that is missing a spot

                // ex: replace the 'b' at (2,1) with the 'e' in the root
                //		  N = 5			  N = 4
                //		0 [e]		=>	0 [_]
                //		1 [_,_]			1 [_,_]
                //		2 [a,b,c,d]	=>	2 [a,c,d,e]

                ColaStore.MergeInPlace <T>(segment, offset, m_root[0], m_comparer);
                m_root[0] = default(T);
            }
            else
            {
                // we are missing a spot in out modified segment, that need to fill
                // > we will take the first non empty segment, and break it in pieces
                //  > its last item will be used to fill the empty spot
                //  > the rest of its items will be spread to all the previous empty segments

                // find the first non empty segment that can be broken
                int firstNonEmptyLevel = ColaStore.LowestBit(m_count);

                if (firstNonEmptyLevel == level)
                {                 // we are the first level, this is easy !
                    // move the empty spot at the start
                    if (offset > 0)
                    {
                        Array.Copy(segment, 0, segment, 1, offset);
                    }

                    // and spread the rest to all the previous levels
                    ColaStore.SpreadLevel(level, m_levels);
                    //TODO: modify SpreadLevel(..) to take the offset of the value to skip ?
                }
                else
                {                 // break that level, and merge its last item with the level that is missing one spot
                    // break down this level
                    T tmp = ColaStore.SpreadLevel(firstNonEmptyLevel, m_levels);

                    // merge its last item with the empty spot in the modified level
                    ColaStore.MergeInPlace(m_levels[level], offset, tmp, m_comparer);
                }
            }

            --m_count;

            if (m_levels.Length > MAX_SPARE_ORDER)
            {             // maybe release the last level if it is empty
                ShrinkIfRequired();
            }

            CheckInvariants();

            return(removed);
        }