/* Copyright (C) 2017 Daniel Schultz This file is part of FLINT. FLINT is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include #include "flint.h" #include "mpoly.h" /* red-black tree with ui keys ***********************************************/ void mpoly_rbtree_ui_init(mpoly_rbtree_ui_t T, slong data_size) { mpoly_rbnode_ui_struct * nodes; T->length = 0; T->node_alloc = 2; T->nodes = FLINT_ARRAY_ALLOC(T->node_alloc, mpoly_rbnode_ui_struct); T->data = NULL; T->data_alloc = 0; T->data_size = data_size; nodes = T->nodes + 2; /* pointer to head */ nodes[-1].up = -2; nodes[-1].left = -2; /* head */ nodes[-1].right = -2; nodes[-1].key = 0; nodes[-1].color = 0; /* null node */ nodes[-2].up = -2; nodes[-2].left = -2; nodes[-2].right = -2; nodes[-2].key = 0; nodes[-2].color = 0; } /* the memory management of the data chunks must be done prior */ void mpoly_rbtree_ui_clear(mpoly_rbtree_ui_t T) { FLINT_ASSERT(T->node_alloc > 0); flint_free(T->nodes); flint_free(T->data); } static void mpoly_rbtree_ui_fit_length(mpoly_rbtree_ui_t T, slong len) { slong dsize = T->data_size; if (len + 2 > T->node_alloc) { slong new_alloc = FLINT_MAX(len + 2, 2*T->node_alloc); T->nodes = FLINT_ARRAY_REALLOC(T->nodes, new_alloc, mpoly_rbnode_ui_struct); T->node_alloc = new_alloc; } if (dsize*len > T->data_alloc) { slong new_alloc = FLINT_MAX(dsize*len, 2*T->data_alloc); T->data = FLINT_ARRAY_REALLOC(T->data, new_alloc, char); T->data_alloc = new_alloc; } } /* If the key rcx exists, a pointer to its data will be returned and new will be set to 0. Otherwise, a pointer to a new data chunk is returned and new is set to 1. */ void * mpoly_rbtree_ui_lookup(mpoly_rbtree_ui_t T, int * new, ulong rcx) { slong dsize = T->data_size; mpoly_rbnode_ui_struct * nodes = T->nodes + 2; slong rax, rdx, r8, r9, r10, r11; slong n = T->length; r10 = nodes[-1].left; if (n < 1) { mpoly_rbtree_ui_fit_length(T, 1); nodes = T->nodes + 2; rax = 0; nodes[rax].up = -1; nodes[rax].left = -2; nodes[rax].right = -2; nodes[rax].color = 0; nodes[rax].key = rcx; T->length = 1; *new = 1; nodes[-1].left = rax; return T->data + dsize*rax; } Compare: FLINT_ASSERT(r10 >= 0); r8 = nodes[r10].left; r9 = nodes[r10].right; if (rcx < nodes[r10].key) goto GoLeft; if (rcx > nodes[r10].key) goto GoRight; rax = r10; * new = 0; return T->data + dsize*rax; GoLeft: if (r8 < 0) { FLINT_ASSERT(r8 == -2); goto MakeNewLeft; } r10 = r8; goto Compare; GoRight: if (r9 < 0) { FLINT_ASSERT(r9 == -2); goto MakeNewRight; } r10 = r9; goto Compare; MakeNewLeft: mpoly_rbtree_ui_fit_length(T, n + 1); nodes = T->nodes + 2; rdx = n; nodes[r10].left = rdx; goto FixTree; MakeNewRight: mpoly_rbtree_ui_fit_length(T, n + 1); nodes = T->nodes + 2; rdx = n; nodes[r10].right = rdx; FixTree: nodes[rdx].up = r10; nodes[rdx].left = -2; nodes[rdx].right = -2; nodes[rdx].color = 1; nodes[rdx].key = rcx; T->length = n + 1; *new = 1; rax = rdx; FixNode: /*Case1:*/ r8 = nodes[rdx].up; if (r8 < 0) { FLINT_ASSERT(r8 == -1); FLINT_ASSERT(nodes[-1].left == rdx); nodes[rdx].color = 0; return T->data + dsize*rax; } /*Case2:*/ if (nodes[r8].color == 0) return T->data + dsize*rax; /*Case3:*/ r9 = nodes[r8].up; r10 = nodes[r9].left; r11 = nodes[r9].right; if (r8 == r10) r10 = r11; if (r10 < 0 || nodes[r10].color == 0) goto Case4; rdx = r9; nodes[r8].color = 0; nodes[r9].color = 1; nodes[r10].color = 0; goto FixNode; Case4: r10 = nodes[r9].up; /*Case4A:*/ if (rdx != nodes[r8].right || r8 != nodes[r9].left) goto Case4B; r11 = nodes[rdx].left; nodes[r9].left = rdx; nodes[rdx].left = r8; nodes[r8].right = r11; nodes[r8].up = rdx; nodes[rdx].up = r9; nodes[r11].up = r8; goto Case4Done; Case4B: if (rdx != nodes[r8].left || r8 != nodes[r9].right) goto Case5; r11 = nodes[rdx].right; nodes[r9].right = rdx; nodes[rdx].right = r8; nodes[r8].left = r11; nodes[r8].up = rdx; nodes[rdx].up = r9; nodes[r11].up = r8; Case4Done: SLONG_SWAP(rdx, r8); Case5: if (nodes[r10].right == r9) nodes[r10].right = r8; if (nodes[r10].left == r9) nodes[r10].left = r8; nodes[r8].up = r10; nodes[r8].color = 0; nodes[r9].up = r8; nodes[r9].color = 1; r11 = nodes[r8].right; r10 = nodes[r8].left; if (rdx == r10) { nodes[r8].right = r9; nodes[r9].left = r11; nodes[r11].up = r9; } else { nodes[r8].left = r9; nodes[r9].right = r10; nodes[r10].up = r9; } return T->data + dsize*rax; } /* red-black tree with fmpz keys *********************************************/ void mpoly_rbtree_fmpz_init(mpoly_rbtree_fmpz_t T, slong data_size) { mpoly_rbnode_fmpz_struct * nodes; T->length = 0; T->node_alloc = 2; T->nodes = FLINT_ARRAY_ALLOC(T->node_alloc, mpoly_rbnode_fmpz_struct); T->data = NULL; T->data_alloc = 0; T->data_size = data_size; nodes = T->nodes + 2; /* pointer to head */ nodes[-1].up = -2; nodes[-1].left = -2; /* head */ nodes[-1].right = -2; fmpz_init(nodes[-1].key); nodes[-1].color = 0; /* null node */ nodes[-2].up = -2; nodes[-2].left = -2; nodes[-2].right = -2; fmpz_init(nodes[-2].key); nodes[-2].color = 0; } /* the memory management of the data chunks must be done prior */ void mpoly_rbtree_fmpz_clear(mpoly_rbtree_fmpz_t T) { slong i; FLINT_ASSERT(T->node_alloc > 0); for (i = 0; i < T->node_alloc; i++) fmpz_clear(T->nodes[i].key); flint_free(T->nodes); flint_free(T->data); } static void mpoly_rbtree_fmpz_fit_length(mpoly_rbtree_fmpz_t T, slong len) { slong i, dsize = T->data_size; if (len + 2 > T->node_alloc) { slong new_alloc = FLINT_MAX(len + 2, 2*T->node_alloc); T->nodes = FLINT_ARRAY_REALLOC(T->nodes, new_alloc, mpoly_rbnode_fmpz_struct); for (i = T->node_alloc; i < new_alloc; i++) fmpz_init(T->nodes[i].key); T->node_alloc = new_alloc; } if (dsize*len > T->data_alloc) { slong new_alloc = FLINT_MAX(dsize*len, 2*T->data_alloc); T->data = FLINT_ARRAY_REALLOC(T->data, new_alloc, char); T->data_alloc = new_alloc; } } /* If the key rcx exists, a pointer to its data will be returned and new will be set to 0. Otherwise, a pointer to a new data chunk is returned and new is set to 1. */ void * mpoly_rbtree_fmpz_lookup(mpoly_rbtree_fmpz_t T, int * new, const fmpz_t rcx) { slong dsize = T->data_size; mpoly_rbnode_fmpz_struct * nodes = T->nodes + 2; slong rax, rdx, r8, r9, r10, r11; slong n = T->length; int cmp; r10 = nodes[-1].left; if (n < 1) { mpoly_rbtree_fmpz_fit_length(T, 1); nodes = T->nodes + 2; rax = 0; nodes[rax].up = -1; nodes[rax].left = -2; nodes[rax].right = -2; nodes[rax].color = 0; fmpz_set(nodes[rax].key, rcx); T->length = 1; *new = 1; nodes[-1].left = rax; return T->data + dsize*rax; } Compare: FLINT_ASSERT(r10 >= 0); r8 = nodes[r10].left; r9 = nodes[r10].right; cmp = fmpz_cmp(rcx, nodes[r10].key); if (cmp < 0) goto GoLeft; if (cmp > 0) goto GoRight; rax = r10; * new = 0; return T->data + dsize*rax; GoLeft: if (r8 < 0) { FLINT_ASSERT(r8 == -2); goto MakeNewLeft; } r10 = r8; goto Compare; GoRight: if (r9 < 0) { FLINT_ASSERT(r9 == -2); goto MakeNewRight; } r10 = r9; goto Compare; MakeNewLeft: mpoly_rbtree_fmpz_fit_length(T, n + 1); nodes = T->nodes + 2; rdx = n; nodes[r10].left = rdx; goto FixTree; MakeNewRight: mpoly_rbtree_fmpz_fit_length(T, n + 1); nodes = T->nodes + 2; rdx = n; nodes[r10].right = rdx; FixTree: nodes[rdx].up = r10; nodes[rdx].left = -2; nodes[rdx].right = -2; nodes[rdx].color = 1; fmpz_set(nodes[rdx].key, rcx); T->length = n + 1; *new = 1; rax = rdx; FixNode: /*Case1:*/ r8 = nodes[rdx].up; if (r8 < 0) { FLINT_ASSERT(r8 == -1); FLINT_ASSERT(nodes[-1].left == rdx); nodes[rdx].color = 0; return T->data + dsize*rax; } /*Case2:*/ if (nodes[r8].color == 0) return T->data + dsize*rax; /*Case3:*/ r9 = nodes[r8].up; r10 = nodes[r9].left; r11 = nodes[r9].right; if (r8 == r10) r10 = r11; if (r10 < 0 || nodes[r10].color == 0) goto Case4; rdx = r9; nodes[r8].color = 0; nodes[r9].color = 1; nodes[r10].color = 0; goto FixNode; Case4: r10 = nodes[r9].up; /*Case4A:*/ if (rdx != nodes[r8].right || r8 != nodes[r9].left) goto Case4B; r11 = nodes[rdx].left; nodes[r9].left = rdx; nodes[rdx].left = r8; nodes[r8].right = r11; nodes[r8].up = rdx; nodes[rdx].up = r9; nodes[r11].up = r8; goto Case4Done; Case4B: if (rdx != nodes[r8].left || r8 != nodes[r9].right) goto Case5; r11 = nodes[rdx].right; nodes[r9].right = rdx; nodes[rdx].right = r8; nodes[r8].left = r11; nodes[r8].up = rdx; nodes[rdx].up = r9; nodes[r11].up = r8; Case4Done: SLONG_SWAP(rdx, r8); Case5: if (nodes[r10].right == r9) nodes[r10].right = r8; if (nodes[r10].left == r9) nodes[r10].left = r8; nodes[r8].up = r10; nodes[r8].color = 0; nodes[r9].up = r8; nodes[r9].color = 1; r11 = nodes[r8].right; r10 = nodes[r8].left; if (rdx == r10) { nodes[r8].right = r9; nodes[r9].left = r11; nodes[r11].up = r9; } else { nodes[r8].left = r9; nodes[r9].right = r10; nodes[r10].up = r9; } return T->data + dsize*rax; }