Update:
It turns out there are are 2 ways to obtain the correct bounds for the second memmove()
. One is to find the start of the sets to delete as the destination and add state.level
for the source (the start of the sets to delete is the last set to be all the same type, or the one encountered before the first set with not all nodes of the same type).
The other is to find the start of the next sets after the deleted region as the source, and subtract state.level
to get the destination. The latter means no previous set needs to be recorded in the first loop in the delete branch, but also means that the 'first index that needs to be updated' needs to be found via the loop that updates the indices.
As such, the duplication can be resolved by creating this function:
static unsigned octree_offset(Octree *const octree, const State *const state, const int delta, const unsigned size) {
unsigned set = 0, level = state->level;
do {
unsigned offset = state->offset[level];
while (++offset&7) {
uint16_t *const node_ptr = (uint16_t *)octree->set+offset;
if (*node_ptr&0x8000) {
if (!set)
set = (offset>>3)+(*node_ptr&0x7FFF);
*node_ptr += delta;
}
}
} while (++level != 5);
if (set) {
Node8 *const set_ptr = octree->set+set;
memmove(set_ptr+delta, set_ptr, (size-set)*sizeof(Node8));
return set;
}
return size;
}
The function would be used as octree_offset(octree, &state, -state.level, prev_size);
in the delete branch and octree_offset(octree, &state, state.level, prev_size);
in the insert branch. I have also decided to move prev_size
to outside the main if (state.level)
block, and the do while()
loops in each branch and the memmove()
calls can be replaced with the corresponding calls to this function.