ОНОВЛЕННЯ: Це питання було предметом мого блогу 8 червня 2012 року . Дякую за чудове запитання!
Чудове запитання. Ми обговорювали проблеми, які ви порушуєте, дуже довго.
Ми хотіли б мати структуру даних, яка має такі характеристики:
- Незмінний.
- Форма дерева.
- Недорогий доступ до батьківських вузлів із дочірніх вузлів.
- Можливо зіставити з вузла на дереві зміщення символів у тексті.
- Наполегливі .
Під наполегливістю я маю на увазі можливість повторно використовувати більшість існуючих вузлів на дереві, коли редагується текстовий буфер. Оскільки вузли незмінні, немає ніякого бар'єру для їх повторного використання. Це нам потрібно для виконання; ми не можемо повторно розбирати величезні уривки файлу кожного разу, коли натискаєте клавішу. Нам потрібно повторно лексикувати та переаналізувати лише ті частини дерева, які вплинули на редагування.
Тепер, коли ви намагаєтесь об'єднати всі п'ять цих речей в одну структуру даних, ви негайно стикаєтеся з проблемами:
- Як в першу чергу побудувати вузол? Батько і дитина обоє посилаються один на одного, і вони незмінні, тож хто з них будується першим?
- Припустимо, вам вдається вирішити цю проблему: як зробити її стійкою? Ви не можете повторно використовувати дочірній вузол у іншого батька, оскільки це означатиме сказати дитині, що у нього є новий батько. Але дитина незмінна.
- Припустимо, вам вдасться вирішити цю проблему: коли ви вставляєте новий символ у буфер редагування, змінюється абсолютне положення кожного вузла, який відображається у позицію після цієї точки . Це ускладнює створення стійкої структури даних, оскільки будь-яка редакція може змінити проміжки більшості вузлів!
Але в команді Рослін ми звичайно робимо неможливі речі. Ми фактично робимо неможливе, зберігаючи два дерева розбору. «Зелене» дерево незмінне, стійке, не має батьківських посилань, будується «знизу вгору», і кожен вузол відстежує його ширину, але не абсолютне положення . Коли редагування трапляється, ми відновлюємо лише ті частини зеленого дерева, на які вплинуло редагування, що, як правило, стосується O (log n) загальних розбірних вузлів дерева.
«Червоне» дерево - це непорушний фасад, який будується навколо зеленого дерева; вона будується "зверху вниз" на вимогу і викидається на кожну редакцію. Він обчислює батьківські посилання, виготовляючи їх на вимогу, коли ви спускаєтесь по дереву зверху . Він створює абсолютні позиції, обчислюючи їх із ширини, знову ж таки, під час спуску.
Ви, користувач, бачите лише червоне дерево; зелене дерево - це деталь реалізації. Якщо ви заглянете у внутрішній стан вузла розбору, то насправді побачите, що там є посилання на інший вузол розбору іншого типу; ось вузол зеленого дерева.
Між іншим, вони називаються "червоними / зеленими деревами", тому що це були кольори маркера на дошці, які ми використовували для складання структури даних на зустрічі дизайнерів. Немає іншого значення для кольорів.
Перевага цієї стратегії полягає в тому, що ми отримуємо всі ті чудові речі: незмінність, наполегливість, батьківські посилання тощо. Вартість полягає в тому, що ця система є складною і може зайняти багато пам’яті, якщо «червоні» фасади стануть великими. В даний час ми робимо експерименти, щоб дізнатися, чи зможемо ми зменшити деякі витрати, не втрачаючи переваг.