From fdad53197e5870d9c7108dd4608f2f415b614cc2 Mon Sep 17 00:00:00 2001 From: Petr Tesarik Date: Tue, 2 Oct 2012 22:37:25 +0200 Subject: [PATCH] Do not destroy cursors in an erased area Instead of destroying the cursors, move them to the nearest following position. This ensures that existing cursors will never get invalidated indirectly through the hed API. That is, if you call hed_get_cursor(), the resulting cursor stays valid until you call hed_put_cursor() on it. Preserving the insert point is tricky: 1. There can now be zero-sized insertion blocks with an active insert point, and these must not be killed. 2. It is important to slide the insertion point when erase block includes the end of an insertion, even if the insertion block itself is not erased. --- libhed/file.c | 46 ++++++++++++++++++++++++---------------------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/libhed/file.c b/libhed/file.c index ee835d7..dc00424 100644 --- a/libhed/file.c +++ b/libhed/file.c @@ -356,19 +356,23 @@ move_blockoffs(const struct file_block *old, struct file_block *new, } } -/* Destroy blockoffs referencing @block from @start to @end */ +/* Move cursors in the range @block:<@start;@end> to @newpos */ static void -nuke_blockoffs(const struct file_block *block, - hed_uoff_t start, hed_uoff_t end) +move_cursors_abs(const struct file_block *block, + hed_uoff_t start, hed_uoff_t end, + const hed_cursor_t *newpos) { - blockoff_t *blockoff, *nextoff; + hed_cursor_t *curs, *nextcurs; - BDEBUG("Nuking blockoffs from <%p>:%llx:%llx\n", - block, start, end); - list_for_each_entry_safe(blockoff, nextoff, &block->refs, list) - if (blockoff->off >= start && blockoff->off <= end) { - blockoff->block = NULL; - list_del_init(&blockoff->list); + BDEBUG("Moving blockoffs from <%p>:%llx:%llx to <%p>:%llx\n", + block, start, end, newpos->block, newpos->off); + + list_for_each_entry_safe(curs, nextcurs, &block->refs, list) + if (curs->off >= start && curs->off <= end) { + curs->pos = newpos->pos; + curs->block = newpos->block; + curs->off = newpos->off; + list_move(&curs->list, &newpos->block->refs); } } @@ -457,10 +461,10 @@ file_free_block(struct hed_file *file, struct file_block *block) static bool kill_block_if_empty(struct hed_file *file, struct file_block *block) { - if (!hed_block_is_eof(block) && block->t.size == 0) { + if (!hed_block_is_eof(block) && block->t.size == 0 && + list_empty(&block->refs)) { /* No recalculation needed, zero size. */ unchain_block(file_blocks(file), block); - assert(list_empty(&block->refs)); file_free_block(file, block); return true; } @@ -1594,14 +1598,14 @@ file_erase_continuous(struct hed_file *file, blockoff_t *blockoff, size_t len) { struct file_block *block = blockoff->block; hed_uoff_t block_offset = blockoff->off; - blockoff_t *cur; - /* Move to the new position, so blockoff does not get destroyed */ + /* Find the new position */ hed_move_relative(blockoff, len); + /* Move all other cursors in the erased range to the new position */ assert(len > 0); - nuke_blockoffs(block, block_offset, - block_offset + len - (len < block->t.size)); + move_cursors_abs(block, block_offset, + block_offset + len - 1, blockoff); if (!block_offset) { block->dataoff += len; @@ -1616,11 +1620,6 @@ file_erase_continuous(struct hed_file *file, blockoff_t *blockoff, size_t len) block->t.size -= len; recalc_block_recursive(file_blocks(file), block); - /* Move the insert point if needed */ - list_for_each_entry(cur, &block->refs, list) - if (cur->off >= block->t.size) - cur->pos -= len; - kill_block_if_empty(file, block); return 0; } @@ -1659,7 +1658,10 @@ hed_file_erase_block(struct hed_file *file, blockoff_t *blockoff, eofblock->t.size += len; recalc_block_recursive(file_blocks(file), eofblock); - slide_blockoffs(file, blockoff->block, blockoff->pos, -len); + struct hed_block *slideblock = prev_block(blockoff->block); + if (!is_a_block(file_blocks(file), slideblock)) + slideblock = blockoff->block; + slide_blockoffs(file, slideblock, blockoff->pos, -len); return todo; } -- 2.11.4.GIT