بهینهسازی 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را اعمال کنید — جابهجایی یک ویرایش فقط زمانی مفید است که توالیهای همجوار از یک نوع قبلاً ادغام شده باشند.
مسائل رایج
| Issue | Cause | Fix |
|---|---|---|
| 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 | تغییری که توسط برابریها احاطه شده را جابجا میکند تا یکی از آنها را حذف کند |
EditOperationsOrder | Enum که کنترل میکند آیا DeleteFirst یا InsertFirst در یک موقعیت مشترک تولید شود |