/* @license 2021 Neil Edelman, distributed under the terms of the [MIT License](https://opensource.org/licenses/MIT). @subtitle Recur trait Included by `list.h`. @param[LC_] A one-argument macro producing a name that is responsible for the name of the functions. The caller is responsible for undefining `LC_`. @param[COMPARE_NAME, COMPARE_IS_EQUAL, COMPARE] Optional unique name that satisfies `C` naming conventions when mangled, and a function implementing, for `COMPARE_IS_EQUAL`, bipredicate_fn> that establishes an equivalence relation, or for `COMPARE`, compare_fn> that establishes a total order. There can be multiple comparable functions, but only one can omit `COMPARE_NAME`. @std C89 */ #if !defined(LC_) || !(defined(LIST_IS_EQUAL) ^ defined(LIST_COMPARE)) \ || !defined(L_) || !defined(PL_) #error Unexpected preprocessor symbols. #endif #ifndef LIST_CODA_H /* */ /** Returns a boolean given two read-only listlink>. */ typedef int (*PLC_(bipredicate_fn))(const struct L_(listlink) *, const struct L_(listlink) *); #ifdef LIST_COMPARE /* */ /** @return If `lista` piecewise equals `listb`, which both can be null. @order \O(min(|`lista`|, |`listb`|)) @allow */ static int LC_(is_equal)(const struct L_(list) *const lista, const struct L_(list) *const listb) { const struct L_(listlink) *a, *b; if(!lista) return !listb; if(!listb) return 0; for(a = lista->u.flat.next, b = listb->u.flat.next; ; a = a->next, b = b->next) { if(!a->next) return !b->next; if(!b->next) return 0; if(!PLC_(is_equal)(a, b)) return 0; } } /** Moves all local-duplicates of `from` to the end of `to`. For example, if `from` is `(A, B, B, A)`, it would concatenate the second `(B)` to `to` and leave `(A, B, A)` in `from`. If one sort> `from` first, `(A, A, B, B)`, the global duplicates will be transferred, `(A, B)`. @order \O(|`from`|) @allow */ static void LC_(duplicates_to)(struct L_(list) *const from, struct L_(list) *const to) { struct L_(listlink) *a = from->u.flat.next, *b, *temp; assert(from); if(!(b = a->next)) return; while(b->next) { if(!PLC_(is_equal)(a, b)) { a = b, b = b->next; } else { temp = b, b = b->next; PL_(remove)(temp); if(to) PL_(push)(to, temp); } } } static void PLC_(unused_coda_coda)(void); static void PLC_(unused_coda)(void) { #ifdef LIST_COMPARE /* */ LC_(is_equal)(0, 0); LC_(duplicates_to)(0, 0); PLC_(unused_coda_coda)(); } static void PLC_(unused_coda_coda)(void) { PLC_(unused_coda)(); } #ifdef BOX_COMPARE #undef BOX_COMPARE #endif #ifdef BOX_IS_EQUAL #undef BOX_IS_EQUAL #endif #ifdef BOX_COMPARE_NAME #undef BOX_COMPARE_NAME #endif