/// <summary>
        /// Splits the dictionary at the given node.
        /// </summary>
        /// <returns>Dictionary at the new node</returns>
        private C5Lib.KeyValuePair <int, IDictionary <TKey, TValue> > SplitNode(
            C5Lib.KeyValuePair <int, IDictionary <TKey, TValue> > node)
        {
            C5Lib.KeyValuePair <int, IDictionary <TKey, TValue> > nextNode;
            var nextHash = _circle.TrySuccessor(node.Key, out nextNode)
                                               ? nextNode.Key
                                               : _maxHash;

            var midHash = node.Key + (int)((nextHash - (long)node.Key) / 2);

            Debug.Assert(node.Key < nextHash && node.Key < midHash && midHash < nextHash);

            if (_circle.Contains(midHash))
            {
                // TODO allow larger sub-dictionaries, to avoid exception?
                throw new Exception(
                          "Run out of nodes. Hash code is not evenly distributed enough.");
            }

            // now take (ideally half) the keys from the old node and insert them into the new node

            var dictionary    = node.Value;
            var entriesToMove =
                dictionary.Where(kv => _equalityComparer.GetHashCode(kv.Key) >= midHash)
                .ToList();

            var emptyDictionary =
                new Dictionary <TKey, TValue>(LargeDictionaryFactory.MaxDictionarySize,
                                              _equalityComparer);

            IDictionary <TKey, TValue> dictionaryForMidNode;

            if (entriesToMove.Count == dictionary.Count)
            {
                // optimisation where *all* of the keys need moving

                _circle[node.Key]    = emptyDictionary;
                _circle[midHash]     = dictionary;
                dictionaryForMidNode = dictionary;
            }
            else
            {
                foreach (var entryToMove in entriesToMove)
                {
                    var removed = dictionary.Remove(entryToMove.Key);
                    Debug.Assert(removed);

                    emptyDictionary.Add(entryToMove.Key, entryToMove.Value);
                }

                _circle[midHash]     = emptyDictionary;
                dictionaryForMidNode = emptyDictionary;
            }

            return(new C5Lib.KeyValuePair <int, IDictionary <TKey, TValue> >(midHash,
                                                                             dictionaryForMidNode));
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="ConsistentHashLargeDictionary{TKey, TValue}"/> class.
        /// </summary>
        /// <param name="initialCapacity">The initial capacity.</param>
        /// <param name="equalityComparer">The equality comparer.</param>
        public ConsistentHashLargeDictionary(
            int initialCapacity = 0,
            [CanBeNull] IEqualityComparer <TKey> equalityComparer = null)
        {
            _equalityComparer = equalityComparer ?? EqualityComparer <TKey> .Default;

            var nodeCount = initialCapacity > 0
                                                ? (int)Math.Ceiling(initialCapacity /
                                                                    (double)
                                                                    LargeDictionaryFactory.MaxDictionarySize)
                                                : 1;

            // split the circle into 'nodeCount' dictionaries spread equaly apart

            // optimisation for small dictionaries: just create the single node at the minimum point
            // on the circle

            if (nodeCount == 1)
            {
                _circle[_minHash] = new Dictionary <TKey, TValue>(initialCapacity, equalityComparer);
            }
            else
            {
                // for larger dictionaries, create the points on the circle, but leave the creation
                // of each dictionary until actually need to add to it

                var hashGap = (_maxHash - (long)_minHash) / nodeCount;

                // need to use a long for the hash to avoid wrapping around on the last gap.  It's safe
                // to cast as has is always bounded by MIN_HASH and MAX_HASH which are ints.

                for (long hash = _minHash; hash < _maxHash; hash += hashGap)
                {
                    _circle[(int)hash] = null;
                }
            }

            _firstNode = _circle.First();
        }