/// <summary>
        /// Removes the mapping for this key from this map if present.
        /// </summary>
        /// <remarks>
        /// Expensive: updates both the underlying cache and the local cache.
        /// </remarks>
        /// <param name="key">
        /// The key of the element to remove.
        /// </param>
        /// <returns>
        /// Previous value associated with specified key, or <c>null</c> if
        /// there was no mapping for key. A <c>null</c> return can also
        /// indicate that the dictionary previously associated <c>null</c>
        /// with the specified key, if the implementation supports
        /// <c>null</c> values.
        /// </returns>
        public virtual object RemoveEx(object key)
        {
            switch (m_implType)
            {
            case LiteDictionaryType.Empty:
                return(null);

            case LiteDictionaryType.Single:
                DictionaryEntry entry    = (DictionaryEntry)m_contents;
                object          keyEntry = entry.Key;
                object          prev     = null;
                if (Equals(key, keyEntry))
                {
                    prev       = entry.Value;
                    m_implType = LiteDictionaryType.Empty;
                    m_contents = null;
                }
                return(prev);

            case LiteDictionaryType.Array1:
            case LiteDictionaryType.Array2:
            case LiteDictionaryType.Array3:
            case LiteDictionaryType.Array4:
            case LiteDictionaryType.Array5:
            case LiteDictionaryType.Array6:
            case LiteDictionaryType.Array7:
            case LiteDictionaryType.Array8:
                LiteDictionaryType impl    = m_implType;
                DictionaryEntry[]  entries = (DictionaryEntry[])m_contents;
                int c = impl - LiteDictionaryType.Array1 + 1;
                int i = IndexOf(entries, c, key);
                if (i < 0)
                {
                    return(null);
                }

                object prevValue = entries[i].Value;
                if (c == 1)
                {
                    m_implType = LiteDictionaryType.Empty;
                    m_contents = null;
                }
                else
                {
                    Array.Copy(entries, i + 1, entries, i, c - i - 1);
                    // cannot set entries[c - 1] to null as in Java code
                    // initialize to empty DictionaryEntry instead
                    entries[c - 1] = new DictionaryEntry();
                    m_implType     = --impl;
                }
                return(prevValue);

            case LiteDictionaryType.Other:
                IDictionary map     = (IDictionary)m_contents;
                object      prevVal = map[key];
                map.Remove(key);
                CheckShrinkFromOther();
                return(prevVal);

            default:
                throw new InvalidOperationException();
            }
        }
        /// <summary>
        /// Adds an element with the provided key and value to the
        /// <b>IDictionary</b> object.
        /// </summary>
        /// <param name="value">
        /// The object to use as the value of the element to add.
        /// </param>
        /// <param name="key">
        /// The object to use as the key of the element to add.
        /// </param>
        public virtual void Add(object key, object value)
        {
            switch (m_implType)
            {
            case LiteDictionaryType.Empty:
                m_implType = LiteDictionaryType.Single;
                m_contents = InstantiateEntry(key, value);
                break;

            case LiteDictionaryType.Single:
                DictionaryEntry entry    = (DictionaryEntry)m_contents;
                object          keyEntry = entry.Key;
                if (Equals(key, keyEntry))
                {
                    entry.Value = value;
                    m_contents  = entry;
                }
                else
                {
                    // grow to array implementation
                    DictionaryEntry[] entries = new DictionaryEntry[THRESHOLD];
                    entries[0] = entry;
                    entries[1] = InstantiateEntry(key, value);

                    m_implType = LiteDictionaryType.Array2;
                    m_contents = entries;
                }
                break;

            case LiteDictionaryType.Array1:
            case LiteDictionaryType.Array2:
            case LiteDictionaryType.Array3:
            case LiteDictionaryType.Array4:
            case LiteDictionaryType.Array5:
            case LiteDictionaryType.Array6:
            case LiteDictionaryType.Array7:
            case LiteDictionaryType.Array8:
                LiteDictionaryType impl         = m_implType;
                DictionaryEntry[]  entriesArray = (DictionaryEntry[])m_contents;

                int c = impl - LiteDictionaryType.Array1 + 1;
                int i = IndexOf(entriesArray, c, key);

                if (i >= 0)
                {
                    entriesArray[i].Value = value;
                }
                else
                {
                    // check if adding the object exceeds the "lite" threshold
                    if (c >= THRESHOLD)
                    {
                        // time to switch to a different map implementation
                        IDictionary map = InstantiateDictionary();
                        for (i = 0; i < c; ++i)
                        {
                            DictionaryEntry entr = entriesArray[i];
                            map.Add(entr.Key, entr.Value);
                        }
                        map.Add(key, value);

                        m_implType = LiteDictionaryType.Other;
                        m_contents = map;
                    }
                    else
                    {
                        // use the next available element in the array
                        entriesArray[c] = InstantiateEntry(key, value);
                        m_implType      = impl + 1;
                        m_contents      = entriesArray;
                    }
                }
                break;

            case LiteDictionaryType.Other:
                ((IDictionary)m_contents)[key] = value;
                break;

            default:
                throw new InvalidOperationException();
            }
        }