void dmp_range_splice( dmp_pool *pool, dmp_range *onto, dmp_pos pos, dmp_range *from) { dmp_node *tail; dmp_range_normalize(pool, from); tail = dmp_node_at(pool, from->end); if (pos == -1) { dmp_node *after = dmp_node_at(pool, onto->end); tail->next = after->next; after->next = from->start; onto->end = from->end; } else if (pos == 0) { tail->next = onto->start; onto->start = from->start; } else { dmp_node *after = dmp_node_at(pool, pos); tail->next = after->next; after->next = from->start; } }
dmp_pos dmp_range_insert( dmp_pool *pool, dmp_range *run, dmp_pos pos, int op, const char *data, uint32_t offset, uint32_t len) { dmp_node *node; dmp_pos added_at = alloc_node(pool, op, data, offset, len); if (added_at < 0) return pos; node = dmp_node_at(pool, added_at); if (pos == -1) { dmp_node *end = dmp_node_at(pool, run->end); node->next = end->next; end->next = added_at; run->end = added_at; } else if (pos == 0) { node->next = run->start; run->start = added_at; } else { dmp_node *after = dmp_node_at(pool, pos); node->next = after->next; after->next = added_at; } return added_at; }
void test_ranges_0(void) { dmp_pool pool, *p = &pool; dmp_range range, *r = ⦥ uint32_t used; assert(dmp_pool_alloc(p, 4) == 0); assert(dmp_range_init(p, r, 0, "", 0, 0) > 0); assert(r->start > 0); assert(r->start == r->end); assert(dmp_range_len(p, r) == 1); assert(dmp_range_insert(p, r, -1, 0, "ab", 0, 2) > 0); assert(r->start != r->end); assert(dmp_range_len(p, r) == 2); assert(dmp_range_insert(p, r, -1, 0, "", 0, 0) > 0); assert(dmp_range_len(p, r) == 3); assert(dmp_range_insert(p, r, -1, 0, "cd", 0, 2) > 0); assert(dmp_range_insert(p, r, -1, 0, "", 0, 0) > 0); assert(dmp_range_insert(p, r, -1, 0, "ef", 0, 2) > 0); assert(dmp_range_insert(p, r, -1, 0, "", 0, 0) > 0); assert(r->start != r->end); assert(dmp_range_len(p, r) == 7); progress(); used = p->pool_used; dmp_range_normalize(p, r); assert(dmp_range_len(p, r) == 3); assert(strcmp(dmp_node_at(p, r->start)->text, "ab") == 0); assert(strcmp(dmp_node_at(p, r->end)->text, "ef") == 0); assert(dmp_range_insert(p, r, -1, 0, "", 0, 0) > 0); assert(p->pool_used == used); assert(dmp_range_insert(p, r, -1, 0, "", 0, 0) > 0); assert(dmp_range_insert(p, r, -1, 0, "", 0, 0) > 0); assert(dmp_range_insert(p, r, -1, 0, "", 0, 0) > 0); assert(p->pool_used == used); assert(dmp_range_insert(p, r, -1, 0, "", 0, 0) > 0); assert(p->pool_used == used + 1); progress(); }
static dmp_pos alloc_node( dmp_pool *pool, int op, const char *data, uint32_t offset, uint32_t len) { dmp_pos pos; dmp_node *node; assert(pool && data && op >= -1 && op <= 1); /* don't insert zero length INSERT or DELETE ops */ if (len == 0 && op != 0) return -1; if (pool->free_list > 0) { pos = pool->free_list; node = dmp_node_at(pool, pos); pool->free_list = node->next; } else { if (pool->pool_used >= pool->pool_size) (void)grow_pool(pool); pos = pool->pool_used; pool->pool_used += 1; node = dmp_node_at(pool, pos); } node->text = data + offset; node->len = len; node->op = op; node->next = -1; #ifdef BUGALICIOUS if (len > 0) fprintf(stderr, "adding <%c'%.*s'> (len %d) %02x\n", !node->op ? '=' : node->op < 0 ? '-' : '+', node->len, node->text, node->len, (int)*node->text); #endif return pos; }
int dmp_range_len(dmp_pool *pool, dmp_range *run) { int count = 0; dmp_pos scan; for (scan = run->start; scan != -1; ) { dmp_node *node = dmp_node_at(pool, scan); count++; scan = node->next; } return count; }
void dmp_range_normalize(dmp_pool *pool, dmp_range *range) { dmp_pos last_nonzero = -1, *pos = &range->start; while (*pos != -1) { dmp_node *node = dmp_node_at(pool, *pos); if (!node->len) { *pos = node->next; dmp_node_release(pool, dmp_node_pos(pool, node)); } else { last_nonzero = *pos; pos = &node->next; } } if (last_nonzero >= 0) range->end = last_nonzero; }
void dmp_node_release(dmp_pool *pool, dmp_pos idx) { dmp_node *node = dmp_node_at(pool, idx); node->next = pool->free_list; pool->free_list = idx; }