Оптимізація diff

Оптимізація diff

Оптимізація diff

Цей посібник показує, як очистити необроблений diff — список DiffOperation значень (див. Diff для того, як вони створюються) — у канонічну, мінімальну форму за допомогою постобробних проходів у DiffOptimization підпросторі імен. Кожен прохід реалізує IDiffOptimizationOperation і змінює список diff на місці, тому проходи можна ланцюжком виконувати послідовно, поступово спрощуючи результат.


Контракт оптимізації

IDiffOptimizationOperation визначає єдиний метод, Execute(diffs), який нормалізує змінюваний список значень DiffOperation на місці, зберігаючи при цьому вихідний та цільовий тексти, які представляє diff. Кожен оптимізатор у цьому підпросторі реалізує цей інтерфейс, тому їх можна викликати взаємозамінно або комбінувати у конвеєрі.

List<DiffOperation> diffs = new List<DiffOperation>
{
    new DiffOperation(Operation.Equal, "The quick "),
    new DiffOperation(Operation.Delete, "brown "),
    new DiffOperation(Operation.Insert, "red "),
    new DiffOperation(Operation.Equal, "fox")
};

IDiffOptimizationOperation optimizer = new OperationsMerger(EditOperationsOrder.DeleteFirst);
optimizer.Execute(diffs);

Об’єднання суміжних операцій

OperationsMerger об’єднує diff у його канонічну мінімальну форму: він зливає суміжні послідовності одного типу операції, а для змішаного блоку delete/insert переносить будь-який спільний префікс у попередню рівність і будь-який спільний суфікс у наступну рівність.

var merger = new OperationsMerger(EditOperationsOrder.DeleteFirst);
merger.Execute(diffs);

Видалення коротких рівностей

MergingOptimizer виконує семантичний етап очищення: він усуває рівності, які не більші за редагування, що їх оточують, підсуваючи ці короткі спільні ділянки назад у прилегле видалення/вставку, а потім знову об’єднує результат у канонічну форму.

var semanticOptimizer = new MergingOptimizer(EditOperationsOrder.InsertFirst);
semanticOptimizer.Execute(diffs);

Зсув редагувань через рівності

OperationsSlideMerger зсуває окреме редагування, яке з обох боків оточене рівностями, вбік, усуваючи одну з цих рівностей і ще більше канонізуючи diff.

IDiffOptimizationOperation slideMerger = new OperationsSlideMerger();
slideMerger.Execute(diffs);

Керування порядком видалення/вставки

Коли для тієї самої позиції генеруються операції видалення і вставки, перелік EditOperationsOrder визначає, яку з них оптимізатор ставить першою у отриманій послідовності операцій: DeleteFirst або InsertFirst.

var order = EditOperationsOrder.DeleteFirst;
var optimizer = new MergingOptimizer(order);
optimizer.Execute(diffs);

Поради та найкращі практики

  • Запустіть OperationsMerger спочатку, щоб об’єднати необроблені редагування перед застосуванням семантичних етапів — MergingOptimizer і OperationsSlideMerger передбачають, що суміжні операції одного типу вже об’єднані.
  • Виберіть одне значення EditOperationsOrder і використовуйте його послідовно у всіх оптимізаторах конвеєра; змішування DeleteFirst і InsertFirst між етапами може скасувати порядок, встановлений попереднім етапом.
  • Усі три оптимізатори змінюють List<DiffOperation> на місці — спочатку клонувати список, якщо потрібно зберегти неоптимізований diff для порівняння.
  • Оскільки кожен оптимізатор реалізує IDiffOptimizationOperation, ви можете зберігати конвеєр як IDiffOptimizationOperation[] і викликати Execute для кожного у циклі замість жорсткого кодування кожного проходу за назвою.
  • Застосуйте OperationsSlideMerger після проходів злиття — ковзання редагування корисне лише тоді, коли суміжні ділянки одного типу вже об’єднані.

Поширені проблеми

ПроблемаПричинаВиправлення
Diff все ще містить дрібні фрагментовані рівностіБув запущений лише OperationsMerger; короткі рівності між правками ніколи не згорталисяТакож запустіть MergingOptimizer після OperationsMerger
Порядок видалення/вставки несподівано змінюється між проходамиРізні значення EditOperationsOrder передавалися різним оптимізаторамВикористовуйте одне і те ж значення EditOperationsOrder для кожного оптимізатора у конвеєрі
Оптимізатор, схоже, не має впливуСписок diff вже був у канонічній формі, або копія списку була оптимізована замість оригінального посиланняПідтвердьте, що ви передаєте те саме посилання List<DiffOperation>, яке читає код нижчого рівня

FAQ

Що означає «канонічна форма» для diff?

Це означає, що суміжні операції одного типу були об’єднані, а будь-який спільний префікс/суфікс у змішаних ділянках delete/insert був перенесений у сусідню рівність, тому послідовність не містить зайвої фрагментації.

Чи потрібно використовувати всі три оптимізатори?

Ні. IDiffOptimizationOperation дозволяє застосовувати лише потрібні вам проходи, але запуск OperationsMerger перед семантичними проходами (MergingOptimizer, OperationsSlideMerger) дає найпослідовніші результати.

Яка різниця між OperationsMerger та MergingOptimizer?

OperationsMerger виконує структурне об’єднання (послідовності одного типу, загальний префікс/суфікс). MergingOptimizer йде далі і згортає короткі рівності, оточені правками, назад у прилегле видалення/вставку перед повторним злиттям.

Чи змінює EditOperationsOrder те, що представляє diff?

Ні. Він лише контролює порядок випуску видалення та вставки, які застосовуються до того ж положення — відтворення отриманого тексту не змінюється.


API Reference Підсумок

Клас / МетодОпис
IDiffOptimizationOperationІнтерфейс для постобробного проходу, що нормалізує diff на місці
IDiffOptimizationOperation.Execute(diffs)Виконує оптимізаційний прохід по змінному списку значень DiffOperation
OperationsMergerОб’єднує суміжні операції одного типу та виводить спільний префікс/суфікс у рівності
MergingOptimizerВидаляє короткі рівності, оточені правками, а потім знову об’єднує у канонічну форму
OperationsSlideMergerПереміщує правку, оточену рівностями, щоб усунути одну з них
EditOperationsOrderEnum, що контролює, чи буде виведено DeleteFirst чи InsertFirst у спільній позиції

Дивіться також

 Українська