/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ /* * Copyright 2013 Andrea Canciani * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Author(s): Andrea Canciani */ #ifndef SIMPLEDATA_LIST_H #define SIMPLEDATA_LIST_H #include "simpleops/compiler.h" typedef struct _simpledata_list { struct _simpledata_list *next; struct _simpledata_list *prev; } simpledata_list_t; static simpleops_inline void simpledata_list_init_head (simpledata_list_t *head) { head->next = head->prev = head; } static simpleops_inline simpleops_bool_t simpledata_list_is_empty (const simpledata_list_t *head) { return head == head->next; } static simpleops_inline void _simpledata_list_insert_helper (simpledata_list_t *prev, simpledata_list_t *next, simpledata_list_t *el) { next->prev = el; el->next = next; el->prev = prev; prev->next = el; } static simpleops_inline void _simpledata_list_remove_helper (simpledata_list_t *prev, simpledata_list_t *next) { next->prev = prev; prev->next = next; } static simpleops_inline void simpledata_list_remove (simpledata_list_t *el) { _simpledata_list_remove_helper (el->prev, el->next); } static simpleops_inline void simpledata_list_insert (simpledata_list_t *pos, simpledata_list_t *el) { _simpledata_list_insert_helper (pos, pos->next, el); } static simpleops_inline void simpledata_list_prepend (simpledata_list_t *head, simpledata_list_t *el) { simpledata_list_insert (head, el); } static simpleops_inline void simpledata_list_append (simpledata_list_t *head, simpledata_list_t *el) { _simpledata_list_insert_helper (head->prev, head, el); } static simpleops_inline simpledata_list_t * simpledata_list_first (simpledata_list_t *head) { /* This assumes that the list is not empty */ return head->next; } static simpleops_inline simpledata_list_t * simpledata_list_last (simpledata_list_t *head) { /* This assumes that the list is not empty */ return head->prev; } static simpleops_inline void simpledata_list_foreach (const simpledata_list_t *head, void (*f) (const simpledata_list_t *el, void *arg), void *arg) { const simpledata_list_t *el; for (el = head->next; el != head; el = el->next) f (el, arg); } static simpleops_inline void _simpledata_list_merge (simpledata_list_t *head_a, simpledata_list_t *head_b, int (*cmp) (const simpledata_list_t *a, const simpledata_list_t *b, void *arg), void *arg) { simpledata_list_t *head, *tmp, *curr_a, *curr_b; head = head_a; curr_a = simpledata_list_first(head_a); curr_b = simpledata_list_first(head_b); do { while (curr_a != head_a && cmp(curr_a, curr_b, arg) <= 0) curr_a = curr_a->next; curr_b->prev = curr_a->prev; curr_a->prev->next = curr_b; if (curr_a == head_a) break; tmp = head_a; head_a = head_b; head_b = tmp; tmp = curr_a; curr_a = curr_b; curr_b = tmp; } while (1); head->prev = head_b->prev; head->prev->next = head; } static simpleops_inline void simpledata_list_merge (simpledata_list_t *head_a, simpledata_list_t *head_b, int (*cmp) (const simpledata_list_t *a, const simpledata_list_t *b, void *arg), void *arg) { if (simpledata_list_is_empty(head_b)) return; if (simpledata_list_is_empty(head_a)) { *head_a = *head_b; head_a->prev->next = head_a; head_a->next->prev = head_a; return; } _simpledata_list_merge(head_a, head_b, cmp, arg); } static simpleops_inline void _simpledata_list_sort (simpledata_list_t *head, simpledata_list_t *remaining_head, size_t level, int (*cmp) (const simpledata_list_t *a, const simpledata_list_t *b, void *arg), void *arg) { simpledata_list_t head_other, *first, *curr; size_t i; first = simpledata_list_first(head); curr = first->next; /* Single element */ if (curr == head) return; head_other.next = curr->next; head_other.prev = head->prev; if (cmp(first, curr, arg) <= 0) { /* Two elements, already sorted */ if (head_other.next == head) return; } else { /* Two elements, inverted */ head->next = curr; curr->next = first; first->next = head; head->prev = first; curr->prev = head; first->prev = curr; /* Two elements, manually sorted */ if (head_other.next == head) return; curr = first; } head->prev = curr; curr->next = head; for (i = 0; i < level; i++) { head_other.prev->next = &head_other; head_other.next->prev = &head_other; simpledata_list_init_head (remaining_head); _simpledata_list_sort (&head_other, remaining_head, i, cmp, arg); _simpledata_list_merge (head, &head_other, cmp, arg); if (simpledata_list_is_empty(remaining_head)) return; head_other = *remaining_head; } *remaining_head = head_other; remaining_head->prev->next = remaining_head; remaining_head->next->prev = remaining_head; } static simpleops_inline void simpledata_list_sort (simpledata_list_t *head, int (*cmp) (const simpledata_list_t *a, const simpledata_list_t *b, void *arg), void *arg) { simpledata_list_t tmp; if (!simpledata_list_is_empty(head)) _simpledata_list_sort(head, &tmp, (size_t)-1, cmp, arg); } #endif