Пример #1
0
 private int GetInsertPositionLinear(IList <KeyValuePair <TKey, TObject> > list, KeyValuePair <TKey, TObject> item)
 {
     for (var i = 0; i < list.Count; i++)
     {
         if (_comparer.Compare(item, list[i]) < 0)
         {
             return(i);
         }
     }
     return(_list.Count);
 }
Пример #2
0
        /// <summary>
        /// Dynamic calculation of moved items which produce a result which can be enumerated through in order
        /// </summary>
        /// <returns></returns>
        public IChangeSet <TObject, TKey> Calculate(IChangeSet <TObject, TKey> changes)
        {
            var reducedChanges  = ReduceChanges(changes).ToList();
            var changesByReason = reducedChanges.GroupBy(c => c.Reason).ToDictionary(x => x.Key, x => x.AsEnumerable());

            var result = new List <Change <TObject, TKey> >(reducedChanges.Count);

            var refreshes     = changesByReason.GetOrEmpty(ChangeReason.Refresh);
            var removals      = changesByReason.GetOrEmpty(ChangeReason.Remove);
            var updateChanges = changesByReason.GetOrEmpty(ChangeReason.Update).Concat(refreshes).OrderBy(r => new KeyValuePair <TKey, TObject>(r.Key, r.Current), _comparer);

            var keysToBeRemoved      = updateChanges.Concat(removals).ToDictionary(x => x.Key, x => x);
            var updatePreviousValues = new Dictionary <KeyValuePair <TKey, TObject>, IndexAndNode <KeyValuePair <TKey, TObject> > >();

            if (keysToBeRemoved.Any())
            {
                var index = 0;
                var node  = _list.First;
                while (node != null)
                {
                    if (keysToBeRemoved.ContainsKey(node.Value.Key))
                    {
                        var toBeRemoved = keysToBeRemoved[node.Value.Key];

                        var nodeCopy = node;
                        if (toBeRemoved.Reason == ChangeReason.Remove)
                        {
                            result.Add(new Change <TObject, TKey>(ChangeReason.Remove, toBeRemoved.Key, toBeRemoved.Current, index));
                        }
                        else
                        {
                            var kvp = new KeyValuePair <TKey, TObject>(node.Value.Key, toBeRemoved.Current);
                            updatePreviousValues[kvp] = IndexAndNode.Create(index, node);
                            index++;
                        }

                        node = node.Next;
                        _list.Remove(nodeCopy);
                        keysToBeRemoved.Remove(nodeCopy.Value.Key);

                        if (!keysToBeRemoved.Any())
                        {
                            break;
                        }
                    }
                    else
                    {
                        node = node.Next;
                        index++;
                    }
                }
            }

            var updates = new Queue <Change <TObject, TKey> >(updateChanges);

            if (updates.Any())
            {
                var index = -1;
                var node  = _list.First;

                var alreadyAddedNodes = new SortedSet <KeyValuePair <TKey, TObject> >(_comparer);
                var nodeToBeUpdated   = updates.Peek();
                var kvp = new KeyValuePair <TKey, TObject>(nodeToBeUpdated.Key, nodeToBeUpdated.Current);
                while (node != null)
                {
                    index++;
                    var shouldInsertElement = _comparer.Compare(node.Value, kvp) >= 0;
                    if (shouldInsertElement)
                    {
                        var previous = updatePreviousValues[kvp];

                        // Previous node index is shifter by count of already added nodes
                        // which are less than the one we are about to insert
                        var indexOffset = alreadyAddedNodes.TakeWhile(kv => _comparer.Compare(kvp, node.Value) < 0).Count();

                        var previousIndex = previous.Index + indexOffset;
                        var previousValue = previous.Node.Value;

                        var nodeToAdd = new LinkedListNode <KeyValuePair <TKey, TObject> >(kvp);
                        _list.AddBefore(node, nodeToAdd);

                        if (previousIndex == index)
                        {
                            result.Add(new Change <TObject, TKey>(nodeToBeUpdated.Reason, kvp.Key, kvp.Value, previousValue.Value, index, previousIndex));
                        }
                        else
                        {
                            alreadyAddedNodes.Add(kvp);
                            result.Add(new Change <TObject, TKey>(kvp.Key, kvp.Value, index, previousIndex));
                            result.Add(new Change <TObject, TKey>(nodeToBeUpdated.Reason, kvp.Key, kvp.Value, previousValue.Value, index, index));
                        }

                        node = nodeToAdd;
                        updates.Dequeue();
                        if (!updates.Any())
                        {
                            break;
                        }

                        nodeToBeUpdated = updates.Peek();
                        kvp             = new KeyValuePair <TKey, TObject>(nodeToBeUpdated.Key, nodeToBeUpdated.Current);
                    }
                    node = node.Next;
                }

                if (updates.Any())
                {
                    var previous      = updatePreviousValues[kvp];
                    var previousIndex = previous.Index;
                    var previousValue = previous.Node.Value;

                    if (index == -1)
                    {
                        result.Add(new Change <TObject, TKey>(nodeToBeUpdated.Reason, kvp.Key, kvp.Value, previousValue.Value, 0, 0));
                    }
                    else
                    {
                        result.Add(new Change <TObject, TKey>(kvp.Key, kvp.Value, index, previousIndex));
                        result.Add(new Change <TObject, TKey>(nodeToBeUpdated.Reason, kvp.Key, kvp.Value, previousValue.Value, index, index));
                    }

                    _list.AddLast(kvp);
                }
            }

            var adds = new Queue <Change <TObject, TKey> >(changesByReason.GetOrEmpty(ChangeReason.Add).OrderBy(r => r.CurrentIndex));

            if (adds.Any())
            {
                var index         = -1;
                var node          = _list.First;
                var nodeToBeAdded = adds.Peek();
                var kvp           = new KeyValuePair <TKey, TObject>(nodeToBeAdded.Key, nodeToBeAdded.Current);
                while (node != null)
                {
                    index++;
                    var shouldInsert = _comparer.Compare(node.Value, kvp) > 0;
                    if (shouldInsert)
                    {
                        var nodeToAdd = new LinkedListNode <KeyValuePair <TKey, TObject> >(kvp);
                        _list.AddBefore(node, nodeToAdd);
                        result.Add(new Change <TObject, TKey>(ChangeReason.Add, nodeToBeAdded.Key, nodeToBeAdded.Current, index));

                        node = nodeToAdd;

                        adds.Dequeue();
                        if (!adds.Any())
                        {
                            break;
                        }

                        nodeToBeAdded = adds.Peek();
                        kvp           = new KeyValuePair <TKey, TObject>(nodeToBeAdded.Key, nodeToBeAdded.Current);
                    }
                    node = node.Next;
                }

                if (adds.Any())
                {
                    _list.AddLast(kvp);
                    result.Add(new Change <TObject, TKey>(ChangeReason.Add, nodeToBeAdded.Key, nodeToBeAdded.Current, index));
                }
            }

            return(new ChangeSet <TObject, TKey>(result));
        }