بهینه‌سازی Diff

بهینه‌سازی Diff

بهینه‌سازی Diff

این راهنما نشان می‌دهد چگونه یک diff خام — فهرستی از DiffOperation مقدارها (به Diff برای چگونگی ساخت آن‌ها) — به یک فرم استاندارد و حداقل با استفاده از post-processing passes در DiffOptimization sub-namespace. هر عبور implements IDiffOptimizationOperation و diff list را در محل تغییر می‌دهد، بنابراین عبورها می‌توانند به‌صورت زنجیره‌ای در توالی برای ساده‌سازی تدریجی نتیجه متصل شوند.


قرارداد بهینه‌سازی

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 را به شکل کانونی و حداقل آن ادغام می‌کند: بازه‌های مجاور از یک نوع عملیات را ترکیب می‌کند، و برای بازهٔ ترکیبی حذف/درج، هر پیشوند مشترک را به برابری قبلی و هر پسوند مشترک را به برابری بعدی انتقال می‌دهد.

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

حذف برابری‌های کوتاه

MergingOptimizer یک گذر تمیزکاری معنایی (semantic clean-up pass) انجام می‌دهد: برابرهایی (equalities) که بزرگتر از ویرایش‌های اطرافشان نیستند حذف می‌کند، آن توالی‌های کوتاه مشترک را به حذف/درج همجوار (adjacent delete/insert) می‌پیوندد، و سپس نتیجه را به شکل کاننیکال (canonical form) ادغام می‌کند.

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

لغزاندن ویرایش‌ها در برابرها (equalities)

OperationsSlideMerger یک ویرایش تک را که از هر دو طرف توسط برابرها (equalities) احاطه شده است به طرف دیگر جابجا می‌کند، یکی از آن برابرها را حذف می‌کند و diff را بیشتر canonicalizing می‌کند.

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

کنترل ترتیب حذف/درج (delete/insert)

زمانی که یک حذف و یک درج برای همان موقعیت صادر می‌شوند، enum EditOperationsOrder تعیین می‌کند که بهینه‌ساز کدامیک را ابتدا در دنباله عملیات حاصل قرار دهد: DeleteFirst یا InsertFirst.

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

نکات و بهترین روش‌ها

  • ابتدا OperationsMerger را اجرا کنید تا ویرایش‌های خام را پیش از اعمال گذرهای معنایی (semantic passes) ترکیب کند — MergingOptimizer و OperationsSlideMerger هر دو فرض می‌کنند عملیات‌های هم‌نوع مجاور قبلاً ترکیب شده‌اند.
  • یک مقدار EditOperationsOrder را انتخاب کنید و به طور یکسان در تمام بهینه‌سازهای یک خط لوله استفاده کنید؛ ترکیب DeleteFirst و InsertFirst بین گذرها می‌تواند ترتیب را که یک گذر قبلی برقرار کرده بود، برگرداند.
  • تمام سه بهینه‌ساز List<DiffOperation> را در محل تغییر می‌دهند — اگر نیاز دارید diff غیر بهینه‌شده را برای مقایسه نگه دارید، ابتدا لیست را کپی کنید.
  • از آنجا که هر بهینه‌ساز IDiffOptimizationOperation را پیاده‌سازی می‌کند، می‌توانید یک خط لوله را به عنوان IDiffOptimizationOperation[] نگه دارید و Execute را برای هر یک در یک حلقه صدا بزنید به‌جای اینکه هر عبور را به‌صورت سخت‌کد شده با نام فراخوانی کنید.
  • پس از عبورهای ادغام، OperationsSlideMerger را اعمال کنید — جابه‌جایی یک ویرایش فقط زمانی مفید است که توالی‌های همجوار از یک نوع قبلاً ادغام شده باشند.

مسائل رایج

IssueCauseFix
Diff هنوز شامل برابری‌های ریز و پاره‌پاره استفقط OperationsMerger اجرا شد؛ برابری‌های کوتاه بین ویرایش‌ها هرگز ترکیب نشدندهمچنین MergingOptimizer را پس از OperationsMerger اجرا کنید
ترتیب حذف/درج به‌صورت غیرمنتظره‌ای بین عبورها تغییر می‌کندمقادیر مختلف EditOperationsOrder به بهینه‌سازهای متفاوت پاس داده شدبرای هر بهینه‌ساز در خط لوله از همان مقدار EditOperationsOrder استفاده کنید
به نظر می‌رسد بهینه‌ساز هیچ اثری نداردفهرست diff از پیش در قالب قانونمند بود، یا یک نسخه از فهرست به‌جای مرجع اصلی بهینه شدتأیید کنید که همان مرجع List<DiffOperation> را که کد پایین‌دست می‌خواند، پاس می‌دهید

FAQ

عبارت «فرم کانونی» برای یک diff چه معنایی دارد؟

به این معنی است که عملیات‌های همجوار از یک نوع ادغام شده‌اند و هر پیشوند/پسوند مشترک در توالی‌های ترکیبی حذف/درج به همسایگی مساوی منتقل شده است، به‌طوری که توالی دیگر تکه‌تکه‌سازی اضافه‌ای ندارد.

آیا لازم است از هر سه بهینه‌ساز استفاده کنم؟

خیر. IDiffOptimizationOperation به شما اجازه می‌دهد فقط پاس‌های مورد نیاز را اعمال کنید، اما اجرای OperationsMerger قبل از پاس‌های معنایی (MergingOptimizer، OperationsSlideMerger) نتایج یکدست‌ترین را می‌دهد.

تفاوت بین OperationsMerger و MergingOptimizer چیست؟

OperationsMerger ترکیب ساختاری (دنباله‌های یک‌نوع، پیشوند/پسوند مشترک) را انجام می‌دهد. MergingOptimizer پیشرفته‌تر عمل می‌کند و مساوی‌های کوتاهی که توسط ویرایش‌ها احاطه شده‌اند را دوباره به حذف/درج مجاور می‌پیوندد قبل از ادغام مجدد.

آیا EditOperationsOrder آنچه diff نشان می‌دهد را تغییر می‌دهد؟

خیر. این فقط ترتیب انتشار حذف و درج را که بر روی همان موقعیت اعمال می‌شوند کنترل می‌کند — بازسازی متن نهایی تحت تأثیر قرار نمی‌گیرد.


API Reference خلاصه

کلاس / متدتوضیح
IDiffOptimizationOperationرابطی برای عبور پس‌پردازشی که diff را در‌جا نرمال‌سازی می‌کند
IDiffOptimizationOperation.Execute(diffs)عبور بهینه‌سازی را بر روی فهرست قابل تغییر مقادیر DiffOperation اجرا می‌کند
OperationsMergerعملیات‌های هم‌نوع مجاور را ترکیب می‌کند و پیشوند/پسوند مشترک را به مساوات‌ها تبدیل می‌گیرد
MergingOptimizerمساوات‌های کوتاهی که توسط ویرایش‌ها احاطه شده‌اند را حذف می‌کند، سپس دوباره به شکل کانونی ادغام می‌کند
OperationsSlideMergerتغییری که توسط برابری‌ها احاطه شده را جابجا می‌کند تا یکی از آن‌ها را حذف کند
EditOperationsOrderEnum که کنترل می‌کند آیا DeleteFirst یا InsertFirst در یک موقعیت مشترک تولید شود

همچنین ببینید:

 فارسی