lib/Ext/util/Collection.js
function(oldKey, item) {
        var me = this,
            sorted = me.sorted,
            presorted = me.presorted,
            filtered = me.filtered,
            filterable = me.mixins.filterable,
            items = me.items,
            keys = me.keys,
            all = me.all,
            map = me.map,
            returnItem = null,
            oldItemsLn = items.length,
            subjectToOptimize = false,
            oldItem, index, newKey;

        if (arguments.length == 1) {
            item = oldKey;
            oldKey = newKey = me.getKey(item);
            subjectToOptimize = true;
        } else {
            newKey = me.getKey(item);
        }

        oldItem = map[oldKey];
        if (typeof oldKey == 'undefined' || oldKey === null || typeof oldItem == 'undefined') {
            return me.add(newKey, item);
        }

        me.map[newKey] = item;
        if (newKey !== oldKey) {
            delete me.map[oldKey];
        }

        if (sorted && me.getAutoSort()) {
            if (!subjectToOptimize) {
                Ext.Array.remove(items, oldItem);
                Ext.Array.remove(keys, oldKey);
            } else {
                var itemsFrom = items.indexOf(oldItem);
            }
            if (!presorted) {
                Ext.Array.remove(all, oldItem);
                all.push(item);
                me.dirtyIndices = true;
            } else {
                var allTo = this.findInsertionIndex(all, item, undefined, true),
                    allFrom = all.indexOf(item);

                if (allTo !== allFrom) {
                    move(all, allFrom, allTo);
                    me.dirtyIndices = true;
                }
            }

            if (filtered && me.getAutoFilter()) {
                // If the item is now filtered we check if it was not filtered
                // before. If that is the case then we subtract from the length
                if (filterable.isFiltered.call(me, item)) {
                    if (oldItemsLn !== items.length) {
                        me.length--;
                    }

                    if (subjectToOptimize) {
                        Ext.Array.remove(items, oldItem);
                        Ext.Array.remove(keys, oldKey);
                    }

                    return null;
                }
                // If the item was filtered, but now it is not anymore then we
                // add to the length
                else if (oldItemsLn === items.length) {
                    me.length++;
                    returnItem = item;
                }
            }

            if (!subjectToOptimize) {
                index = this.findInsertionIndex(items, item);

                Ext.Array.splice(keys, index, 0, newKey);
                Ext.Array.splice(items, index, 0, item);
            } else {
                index = this.findInsertionIndex(items, item, undefined, true);

                move(keys, itemsFrom, index);
                move(items, itemsFrom, index);
            }
        } else {
            if (filtered) {
                if (me.getAutoFilter() && filterable.isFiltered.call(me, item)) {
                    if (me.indexOf(oldItem) !== -1) {
                        Ext.Array.remove(items, oldItem);
                        Ext.Array.remove(keys, oldKey);
                        me.length--;
                        me.dirtyIndices = true;
                    }
                    return null;
                }
                else if (me.indexOf(oldItem) === -1) {
                    items.push(item);
                    keys.push(newKey);
                    me.indices[newKey] = me.length;
                    me.length++;
                    return item;
                }
            }

            index = me.indexOf(oldItem);

            keys[index] = newKey;
            items[index] = item;

            if (newKey !== oldKey) {
                this.dirtyIndices = true;
            }
        }

        return returnItem;


        function move(array, from, to) {
            if( to === from ) return;

            var target = array[from];
            var increment = to < from ? -1 : 1;

            for(var k = from; k != to; k += increment){
                array[k] = array[k + increment];
            }
            array[to] = target;
        }
    }
function(oldKey, item) {
        var me = this,
            sorted = me.sorted,
            presorted = me.presorted,
            filtered = me.filtered,
            filterable = me.mixins.filterable,
            items = me.items,
            keys = me.keys,
            all = me.all,
            map = me.map,
            returnItem = null,
            oldItemsLn = items.length,
            subjectToOptimize = false,
            oldItem, index, newKey;

        if (arguments.length == 1) {
            item = oldKey;
            oldKey = newKey = me.getKey(item);
            subjectToOptimize = true;
        } else {
            newKey = me.getKey(item);
        }

        oldItem = map[oldKey];
        if (typeof oldKey == 'undefined' || oldKey === null || typeof oldItem == 'undefined') {
            return me.add(newKey, item);
        }

        me.map[newKey] = item;
        if (newKey !== oldKey) {
            delete me.map[oldKey];
        }

        if (sorted && me.getAutoSort()) {
            if (!subjectToOptimize) {
                Ext.Array.remove(items, oldItem);
                Ext.Array.remove(keys, oldKey);
            } else {
                var itemsFrom = items.indexOf(oldItem);
            }
            if (!presorted) {
                Ext.Array.remove(all, oldItem);
                all.push(item);
                me.dirtyIndices = true;
            } else {
                var allTo = this.findInsertionIndex(all, item, undefined, true),
                    allFrom = all.indexOf(item);

                if (allTo !== allFrom) {
                    move(all, allFrom, allTo);
                    me.dirtyIndices = true;
                }
            }

            if (filtered && me.getAutoFilter()) {
                // If the item is now filtered we check if it was not filtered
                // before. If that is the case then we subtract from the length
                if (filterable.isFiltered.call(me, item)) {
                    if (oldItemsLn !== items.length) {
                        me.length--;
                    }

                    if (subjectToOptimize) {
                        Ext.Array.remove(items, oldItem);
                        Ext.Array.remove(keys, oldKey);
                    }

                    return null;
                }
                // If the item was filtered, but now it is not anymore then we
                // add to the length
                else if (oldItemsLn === items.length) {
                    me.length++;
                    returnItem = item;
                }
            }

            if (!subjectToOptimize) {
                index = this.findInsertionIndex(items, item);

                Ext.Array.splice(keys, index, 0, newKey);
                Ext.Array.splice(items, index, 0, item);
            } else {
                index = this.findInsertionIndex(items, item, undefined, true);

                move(keys, itemsFrom, index);
                move(items, itemsFrom, index);
            }
        } else {
            if (filtered) {
                if (me.getAutoFilter() && filterable.isFiltered.call(me, item)) {
                    if (me.indexOf(oldItem) !== -1) {
                        Ext.Array.remove(items, oldItem);
                        Ext.Array.remove(keys, oldKey);
                        me.length--;
                        me.dirtyIndices = true;
                    }
                    return null;
                }
                else if (me.indexOf(oldItem) === -1) {
                    items.push(item);
                    keys.push(newKey);
                    me.indices[newKey] = me.length;
                    me.length++;
                    return item;
                }
            }

            index = me.indexOf(oldItem);

            keys[index] = newKey;
            items[index] = item;

            if (newKey !== oldKey) {
                this.dirtyIndices = true;
            }
        }

        return returnItem;


        function move(array, from, to) {
            if( to === from ) return;

            var target = array[from];
            var increment = to < from ? -1 : 1;

            for(var k = from; k != to; k += increment){
                array[k] = array[k + increment];
            }
            array[to] = target;
        }
    }
Replaces an item in the collection. Fires the {@link #replace} event when complete.
@param {String} oldKey

The key associated with the item to replace, or the replacement item.

If you supplied a {@link #getKey} implementation for this MixedCollection, or if the key of your stored items is
in a property called **id**, then the MixedCollection will be able to _derive_ the key of the replacement item.
If you want to replace an item with one having the same key value, then just pass the replacement item in this
parameter.
@param {Object} item {Object} item (optional) If the first parameter passed was a key, the item to associate with
that key.
@return {Object} The new item.