/// <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); }