diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/undo.cpp | 56 | ||||
-rw-r--r-- | src/undo.h | 44 |
2 files changed, 62 insertions, 38 deletions
diff --git a/src/undo.cpp b/src/undo.cpp index 584883d..468c61a 100644 --- a/src/undo.cpp +++ b/src/undo.cpp @@ -50,43 +50,55 @@ UndoStack::push(UndoToken *token) #ifdef DEBUG g_printf("UNDO PUSH %p\n", token); #endif - token->pc = cmdline.pc; - SLIST_INSERT_HEAD(&head, token, tokens); + + /* + * There can very well be 0 undo tokens + * per input character (e.g. NOPs like space). + */ + while (heads->len <= cmdline.pc) + g_ptr_array_add(heads, NULL); + g_assert(heads->len == cmdline.pc+1); + + SLIST_NEXT(token, tokens) = + (UndoToken *)g_ptr_array_index(heads, heads->len-1); + g_ptr_array_index(heads, heads->len-1) = token; } void UndoStack::pop(gint pc) { - while (!SLIST_EMPTY(&head) && SLIST_FIRST(&head)->pc >= pc) { - UndoToken *top = SLIST_FIRST(&head); + while ((gint)heads->len > pc) { + UndoToken *top = + (UndoToken *)g_ptr_array_remove_index(heads, heads->len-1); + + while (top) { + UndoToken *next = SLIST_NEXT(top, tokens); + #ifdef DEBUG - g_printf("UNDO POP %p\n", top); - fflush(stdout); + g_printf("UNDO POP %p\n", top); + fflush(stdout); #endif - top->run(); + top->run(); - SLIST_REMOVE_HEAD(&head, tokens); - delete top; + delete top; + top = next; + } } } void UndoStack::clear(void) { - UndoToken *cur; - - while ((cur = SLIST_FIRST(&head))) { - SLIST_REMOVE_HEAD(&head, tokens); - delete cur; + while (heads->len) { + UndoToken *top = + (UndoToken *)g_ptr_array_remove_index(heads, heads->len-1); + + while (top) { + UndoToken *next = SLIST_NEXT(top, tokens); + delete top; + top = next; + } } } -UndoStack::~UndoStack() -{ - UndoToken *token, *next; - - SLIST_FOREACH_SAFE(token, &head, tokens, next) - delete token; -} - } /* namespace SciTECO */ @@ -33,22 +33,18 @@ namespace SciTECO { +/** + * Undo tokens are generated to revert any + * changes to the editor state, ie. they + * define an action to take upon rubout. + * + * Undo tokens are organized into an undo + * stack. + */ class UndoToken : public Object { public: SLIST_ENTRY(UndoToken) tokens; - /** - * Command-line character position (program counter) - * corresponding to this token. - * - * @todo This wastes memory in macro calls and loops - * because all undo tokens will have the same - * value. It may be better to redesign the undo - * stack data structure - as a list/array pointing - * to undo stacks per character. - */ - gint pc; - virtual ~UndoToken() {} virtual void run(void) = 0; @@ -123,18 +119,34 @@ public: }; extern class UndoStack : public Object { - SLIST_HEAD(Head, UndoToken) head; + /** + * Stack of UndoToken lists. + * + * Each stack element represents + * a command line character (the UndoTokens + * generated by that character), so it's OK + * to use a data structure that may need + * reallocation but is space efficient. + * This data structure allows us to omit the + * command line program counter from the UndoTokens + * but wastes a few bytes for input characters + * that produce no UndoToken (e.g. NOPs like space). + */ + GPtrArray *heads; void push(UndoToken *token); public: bool enabled; - UndoStack(bool _enabled = false) : enabled(_enabled) + UndoStack(bool _enabled = false) + : heads(g_ptr_array_new()), enabled(_enabled) {} + ~UndoStack() { - SLIST_INIT(&head); + clear(); + g_ptr_array_free(heads, TRUE); } - ~UndoStack(); + /** * Allocate and push undo token. |