Пример #1
0
        /// <summary>
        /// Remove all of the children
        /// </summary>
        /// <param name="context"></param>
        /// <param name="current"></param>
        public void Remove(TContext context, BasePrimitive <TItem> current)
        {
            var children = current?.Attributes.GetAttributeOrDefault(_attribute);

            if (children != null)
            {
                // work from the top downwards, otherwise we will throw an exception due to
                // out of range indices
                for (var i = children.Length - 1; i >= 0; i--)
                {
                    var i1 = i;
                    _connector.Remove(i1, children[i1]);
                }
            }
        }
Пример #2
0
        public void Update(TContext context, BasePrimitive <TItem> current, BasePrimitive <TItem> next)
        {
            var currentList = current?.Attributes.GetAttributeOrDefault(_attribute);
            var nextList    = next?.Attributes.GetAttributeOrDefault(_attribute);

            // get an id to allow for easy viewing
            long loggingId = 0;


            if (IsLoggingEnabled.Value)
            {
                loggingId = Interlocked.Increment(ref LoggingId);
                Logging.Instance.LogInformation("CollectionUpdate:Begin {id} current Length:{currentLength} next Length:{nextLength}", loggingId, currentList?.Length ?? 0, nextList?.Length ?? 0);
            }

            IEnumerable <Operation <TTarget> > operations;

            // get a list of operations that transform currentList to nextList

            IReadOnlyList <Operation <TTarget> > comparisonOperations;

            if (IsLoggingEnabled.Value)
            {
                using var _ = Benchmark.Create((d, __) =>
                {
                    Logging.Instance.LogInformation("CollectionUpdate:Timings {id} duration:{duration}ms, algorithm:{algorithm}", loggingId, d, _collectionComparer.GetType().FriendlyName());
                });

                comparisonOperations = _collectionComparer.Compare(currentList, nextList);
            }
            else
            {
                comparisonOperations = _collectionComparer.Compare(currentList, nextList);
            }

            if (IsLoggingEnabled.Value)
            {
                Logging.Instance.LogInformation("CollectionUpdate:Raw {id} change count:{count}", loggingId, comparisonOperations.Count);
            }


            // only perform an attempt at a compaction if there is an insert and a delete both in existence
            if (comparisonOperations.Count >= 2 && comparisonOperations.Any(f => f.GetType() == typeof(DeleteOp <IPrimitive>)) && comparisonOperations.Any(f => f.GetType() == typeof(InsertOp <IPrimitive>)))
            {
                if (IsLoggingEnabled.Value)
                {
                    Logging.Instance.LogInformation("CollectionUpdate:Compacting Changes");
                }

                // create our collection change compactor which will look to reduce the number of updates made

                var collectionChangeCompactor = new CollectionChangeCompactor <TTarget>(currentList ?? nextList);

                foreach (var operation in comparisonOperations)
                {
                    switch (operation)
                    {
                    case InsertOp <TTarget> op:
                        collectionChangeCompactor.Insert(op.Index, op.Item);
                        break;

                    case DeleteOp <TTarget> op:
                        collectionChangeCompactor.Delete(op.Index);
                        break;

                    case MoveOp <TTarget> op:
                        collectionChangeCompactor.Delete(op.From);
                        collectionChangeCompactor.Insert(op.To, op.Item);
                        break;

                    case UpdateOp <TTarget> op:
                        collectionChangeCompactor.Update(op.Index, op.ToItem);
                        break;
                    }
                }

                operations = collectionChangeCompactor.GetChangOps();
            }
            else
            {
                operations = comparisonOperations;
            }

            // now apply changes

            foreach (var operation in operations)
            {
                switch (operation)
                {
                case UpdateOp <TTarget> op:

                    if (IsLoggingEnabled.Value)
                    {
                        Logging.Instance.LogInformation("CollectionUpdate:Update {id} {index}:{item}", loggingId, op.Index, op.FromItem, op.ToItem);
                    }

                    _connector.Update(op.Index, op.FromItem, op.ToItem);
                    break;

                case DeleteOp <TTarget> op:

                    if (IsLoggingEnabled.Value)
                    {
                        Logging.Instance.LogInformation("CollectionUpdate:Delete {id} {index}:{item}", loggingId, op.Index, op.Item);
                    }

                    _connector.Remove(op.Index, op.Item);
                    break;

                case InsertOp <TTarget> op:

                    if (IsLoggingEnabled.Value)
                    {
                        Logging.Instance.LogInformation("CollectionUpdate:Insert {id} {index}:{item}", loggingId, op.Index, op.Item);
                    }

                    _connector.Insert(op.Index, op.Item);
                    break;

                default:
                    throw new ArgumentOutOfRangeException();
                }
            }

            if (IsLoggingEnabled.Value)
            {
                Logging.Instance.LogInformation("CollectionUpdate:End {id}", loggingId);
            }
        }
Пример #3
0
        public static void RemoveChildren <TContext, TView>(this IShadowMapper mapper, TContext context, IShadow <TView> shadow, BasePrimitive <TView> current) where TView : class
        {
            var adapter = shadow.State.Get <IBackingDataHandler <TContext, TView> >();

            adapter.Remove(context, current);
        }