Optimize meld in qr module

The goal of `qr_meld()` is to change the following four fields
`(a->prev, a->prev->next, b->prev, b->prev->next)` from the values
`(a->prev, a, b->prev, b)` to `(b->prev, b, a->prev, a)`.

This commit changes

```
a->prev->next = b;
b->prev->next = a;
temp = a->prev;
a->prev = b->prev;
b->prev = temp;
```

to

```
temp = a->prev;
a->prev = b->prev;
b->prev = temp;
a->prev->next = a;
b->prev->next = b;
```

The benefit is that we can use `b->prev->next` for `temp`, and so
there's no need to pass in `a_type`.

The restriction is that `b` cannot be a `qr_next()` macro, so users
of `qr_meld()` must pay attention.  (Before this change, neither `a`
nor `b` could be a `qr_next()` macro.)
This commit is contained in:
Yinan Zhang 2020-04-01 15:04:24 -07:00
parent 0d6d9e8586
commit c9d56cddf2
2 changed files with 16 additions and 14 deletions

View File

@ -32,21 +32,23 @@ struct { \
(a_qrelm)->a_field.qre_next = (a_qr); \ (a_qrelm)->a_field.qre_next = (a_qr); \
} while (0) } while (0)
#define qr_meld(a_qr_a, a_qr_b, a_type, a_field) do { \ /* a_qr_a can directly be a qr_next() macro, but a_qr_b cannot. */
a_type *t; \ #define qr_meld(a_qr_a, a_qr_b, a_field) do { \
(a_qr_a)->a_field.qre_prev->a_field.qre_next = (a_qr_b); \ (a_qr_b)->a_field.qre_prev->a_field.qre_next = \
(a_qr_b)->a_field.qre_prev->a_field.qre_next = (a_qr_a); \ (a_qr_a)->a_field.qre_prev; \
t = (a_qr_a)->a_field.qre_prev; \
(a_qr_a)->a_field.qre_prev = (a_qr_b)->a_field.qre_prev; \ (a_qr_a)->a_field.qre_prev = (a_qr_b)->a_field.qre_prev; \
(a_qr_b)->a_field.qre_prev = t; \ (a_qr_b)->a_field.qre_prev = \
(a_qr_b)->a_field.qre_prev->a_field.qre_next; \
(a_qr_a)->a_field.qre_prev->a_field.qre_next = (a_qr_a); \
(a_qr_b)->a_field.qre_prev->a_field.qre_next = (a_qr_b); \
} while (0) } while (0)
/* /*
* qr_meld() and qr_split() are functionally equivalent, so there's no need to * qr_meld() and qr_split() are functionally equivalent, so there's no need to
* have two copies of the code. * have two copies of the code.
*/ */
#define qr_split(a_qr_a, a_qr_b, a_type, a_field) \ #define qr_split(a_qr_a, a_qr_b, a_field) \
qr_meld((a_qr_a), (a_qr_b), a_type, a_field) qr_meld((a_qr_a), (a_qr_b), a_field)
#define qr_remove(a_qr, a_field) do { \ #define qr_remove(a_qr, a_field) do { \
(a_qr)->a_field.qre_prev->a_field.qre_next \ (a_qr)->a_field.qre_prev->a_field.qre_next \

View File

@ -212,22 +212,22 @@ TEST_BEGIN(test_qr_meld_split) {
qr_after_insert(&entries[i - 1], &entries[i], link); qr_after_insert(&entries[i - 1], &entries[i], link);
} }
qr_split(&entries[0], &entries[SPLIT_INDEX], ring_t, link); qr_split(&entries[0], &entries[SPLIT_INDEX], link);
test_split_entries(entries); test_split_entries(entries);
qr_meld(&entries[0], &entries[SPLIT_INDEX], ring_t, link); qr_meld(&entries[0], &entries[SPLIT_INDEX], link);
test_entries_ring(entries); test_entries_ring(entries);
qr_meld(&entries[0], &entries[SPLIT_INDEX], ring_t, link); qr_meld(&entries[0], &entries[SPLIT_INDEX], link);
test_split_entries(entries); test_split_entries(entries);
qr_split(&entries[0], &entries[SPLIT_INDEX], ring_t, link); qr_split(&entries[0], &entries[SPLIT_INDEX], link);
test_entries_ring(entries); test_entries_ring(entries);
qr_split(&entries[0], &entries[0], ring_t, link); qr_split(&entries[0], &entries[0], link);
test_entries_ring(entries); test_entries_ring(entries);
qr_meld(&entries[0], &entries[0], ring_t, link); qr_meld(&entries[0], &entries[0], link);
test_entries_ring(entries); test_entries_ring(entries);
} }
TEST_END TEST_END