opener-opinion-detector-basic 2.0.0 → 2.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (148) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -0
  3. data/ext/hack/Rakefile +0 -2
  4. data/lib/opener/opinion_detector_basic/version.rb +1 -1
  5. data/opener-opinion-detector-basic.gemspec +0 -1
  6. data/task/compile.rake +1 -1
  7. data/task/requirements.rake +0 -1
  8. metadata +2 -142
  9. data/core/vendor/src/crfsuite/AUTHORS +0 -1
  10. data/core/vendor/src/crfsuite/COPYING +0 -27
  11. data/core/vendor/src/crfsuite/ChangeLog +0 -103
  12. data/core/vendor/src/crfsuite/INSTALL +0 -236
  13. data/core/vendor/src/crfsuite/Makefile.am +0 -19
  14. data/core/vendor/src/crfsuite/Makefile.in +0 -783
  15. data/core/vendor/src/crfsuite/README +0 -183
  16. data/core/vendor/src/crfsuite/aclocal.m4 +0 -9018
  17. data/core/vendor/src/crfsuite/autogen.sh +0 -38
  18. data/core/vendor/src/crfsuite/compile +0 -143
  19. data/core/vendor/src/crfsuite/config.guess +0 -1502
  20. data/core/vendor/src/crfsuite/config.h.in +0 -198
  21. data/core/vendor/src/crfsuite/config.sub +0 -1714
  22. data/core/vendor/src/crfsuite/configure +0 -14273
  23. data/core/vendor/src/crfsuite/configure.in +0 -149
  24. data/core/vendor/src/crfsuite/crfsuite.sln +0 -42
  25. data/core/vendor/src/crfsuite/depcomp +0 -630
  26. data/core/vendor/src/crfsuite/example/chunking.py +0 -49
  27. data/core/vendor/src/crfsuite/example/crfutils.py +0 -179
  28. data/core/vendor/src/crfsuite/example/ner.py +0 -270
  29. data/core/vendor/src/crfsuite/example/pos.py +0 -78
  30. data/core/vendor/src/crfsuite/example/template.py +0 -88
  31. data/core/vendor/src/crfsuite/frontend/Makefile.am +0 -29
  32. data/core/vendor/src/crfsuite/frontend/Makefile.in +0 -640
  33. data/core/vendor/src/crfsuite/frontend/dump.c +0 -116
  34. data/core/vendor/src/crfsuite/frontend/frontend.vcxproj +0 -129
  35. data/core/vendor/src/crfsuite/frontend/iwa.c +0 -273
  36. data/core/vendor/src/crfsuite/frontend/iwa.h +0 -65
  37. data/core/vendor/src/crfsuite/frontend/learn.c +0 -439
  38. data/core/vendor/src/crfsuite/frontend/main.c +0 -137
  39. data/core/vendor/src/crfsuite/frontend/option.c +0 -93
  40. data/core/vendor/src/crfsuite/frontend/option.h +0 -86
  41. data/core/vendor/src/crfsuite/frontend/readdata.h +0 -38
  42. data/core/vendor/src/crfsuite/frontend/reader.c +0 -136
  43. data/core/vendor/src/crfsuite/frontend/tag.c +0 -427
  44. data/core/vendor/src/crfsuite/genbinary.sh.in +0 -15
  45. data/core/vendor/src/crfsuite/include/Makefile.am +0 -11
  46. data/core/vendor/src/crfsuite/include/Makefile.in +0 -461
  47. data/core/vendor/src/crfsuite/include/crfsuite.h +0 -1063
  48. data/core/vendor/src/crfsuite/include/crfsuite.hpp +0 -555
  49. data/core/vendor/src/crfsuite/include/crfsuite_api.hpp +0 -400
  50. data/core/vendor/src/crfsuite/include/os.h +0 -61
  51. data/core/vendor/src/crfsuite/install-sh +0 -520
  52. data/core/vendor/src/crfsuite/lib/cqdb/COPYING +0 -28
  53. data/core/vendor/src/crfsuite/lib/cqdb/Makefile.am +0 -21
  54. data/core/vendor/src/crfsuite/lib/cqdb/Makefile.in +0 -549
  55. data/core/vendor/src/crfsuite/lib/cqdb/cqdb.vcxproj +0 -86
  56. data/core/vendor/src/crfsuite/lib/cqdb/include/cqdb.h +0 -524
  57. data/core/vendor/src/crfsuite/lib/cqdb/src/cqdb.c +0 -587
  58. data/core/vendor/src/crfsuite/lib/cqdb/src/lookup3.c +0 -976
  59. data/core/vendor/src/crfsuite/lib/crf/Makefile.am +0 -46
  60. data/core/vendor/src/crfsuite/lib/crf/Makefile.in +0 -721
  61. data/core/vendor/src/crfsuite/lib/crf/crf.vcxproj +0 -216
  62. data/core/vendor/src/crfsuite/lib/crf/src/crf1d.h +0 -353
  63. data/core/vendor/src/crfsuite/lib/crf/src/crf1d_context.c +0 -705
  64. data/core/vendor/src/crfsuite/lib/crf/src/crf1d_encode.c +0 -943
  65. data/core/vendor/src/crfsuite/lib/crf/src/crf1d_feature.c +0 -352
  66. data/core/vendor/src/crfsuite/lib/crf/src/crf1d_model.c +0 -994
  67. data/core/vendor/src/crfsuite/lib/crf/src/crf1d_tag.c +0 -550
  68. data/core/vendor/src/crfsuite/lib/crf/src/crfsuite.c +0 -492
  69. data/core/vendor/src/crfsuite/lib/crf/src/crfsuite_internal.h +0 -236
  70. data/core/vendor/src/crfsuite/lib/crf/src/crfsuite_train.c +0 -272
  71. data/core/vendor/src/crfsuite/lib/crf/src/dataset.c +0 -106
  72. data/core/vendor/src/crfsuite/lib/crf/src/dictionary.c +0 -118
  73. data/core/vendor/src/crfsuite/lib/crf/src/holdout.c +0 -80
  74. data/core/vendor/src/crfsuite/lib/crf/src/logging.c +0 -91
  75. data/core/vendor/src/crfsuite/lib/crf/src/logging.h +0 -48
  76. data/core/vendor/src/crfsuite/lib/crf/src/params.c +0 -335
  77. data/core/vendor/src/crfsuite/lib/crf/src/params.h +0 -80
  78. data/core/vendor/src/crfsuite/lib/crf/src/quark.c +0 -172
  79. data/core/vendor/src/crfsuite/lib/crf/src/quark.h +0 -46
  80. data/core/vendor/src/crfsuite/lib/crf/src/rumavl.c +0 -1107
  81. data/core/vendor/src/crfsuite/lib/crf/src/rumavl.h +0 -160
  82. data/core/vendor/src/crfsuite/lib/crf/src/train_arow.c +0 -408
  83. data/core/vendor/src/crfsuite/lib/crf/src/train_averaged_perceptron.c +0 -242
  84. data/core/vendor/src/crfsuite/lib/crf/src/train_l2sgd.c +0 -507
  85. data/core/vendor/src/crfsuite/lib/crf/src/train_lbfgs.c +0 -338
  86. data/core/vendor/src/crfsuite/lib/crf/src/train_passive_aggressive.c +0 -435
  87. data/core/vendor/src/crfsuite/lib/crf/src/vecmath.h +0 -341
  88. data/core/vendor/src/crfsuite/ltmain.sh +0 -8413
  89. data/core/vendor/src/crfsuite/missing +0 -376
  90. data/core/vendor/src/crfsuite/swig/Makefile.am +0 -13
  91. data/core/vendor/src/crfsuite/swig/Makefile.in +0 -365
  92. data/core/vendor/src/crfsuite/swig/crfsuite.cpp +0 -2
  93. data/core/vendor/src/crfsuite/swig/export.i +0 -32
  94. data/core/vendor/src/crfsuite/swig/python/README +0 -92
  95. data/core/vendor/src/crfsuite/swig/python/crfsuite.py +0 -329
  96. data/core/vendor/src/crfsuite/swig/python/export_wrap.cpp +0 -14355
  97. data/core/vendor/src/crfsuite/swig/python/export_wrap.h +0 -63
  98. data/core/vendor/src/crfsuite/swig/python/prepare.sh +0 -9
  99. data/core/vendor/src/crfsuite/swig/python/sample_tag.py +0 -52
  100. data/core/vendor/src/crfsuite/swig/python/sample_train.py +0 -68
  101. data/core/vendor/src/crfsuite/swig/python/setup.py +0 -44
  102. data/core/vendor/src/crfsuite/win32/stdint.h +0 -679
  103. data/core/vendor/src/liblbfgs/AUTHORS +0 -1
  104. data/core/vendor/src/liblbfgs/COPYING +0 -22
  105. data/core/vendor/src/liblbfgs/ChangeLog +0 -120
  106. data/core/vendor/src/liblbfgs/INSTALL +0 -231
  107. data/core/vendor/src/liblbfgs/Makefile.am +0 -10
  108. data/core/vendor/src/liblbfgs/Makefile.in +0 -638
  109. data/core/vendor/src/liblbfgs/NEWS +0 -0
  110. data/core/vendor/src/liblbfgs/README +0 -71
  111. data/core/vendor/src/liblbfgs/aclocal.m4 +0 -6985
  112. data/core/vendor/src/liblbfgs/autogen.sh +0 -38
  113. data/core/vendor/src/liblbfgs/config.guess +0 -1411
  114. data/core/vendor/src/liblbfgs/config.h.in +0 -64
  115. data/core/vendor/src/liblbfgs/config.sub +0 -1500
  116. data/core/vendor/src/liblbfgs/configure +0 -21146
  117. data/core/vendor/src/liblbfgs/configure.in +0 -107
  118. data/core/vendor/src/liblbfgs/depcomp +0 -522
  119. data/core/vendor/src/liblbfgs/include/lbfgs.h +0 -745
  120. data/core/vendor/src/liblbfgs/install-sh +0 -322
  121. data/core/vendor/src/liblbfgs/lbfgs.sln +0 -26
  122. data/core/vendor/src/liblbfgs/lib/Makefile.am +0 -24
  123. data/core/vendor/src/liblbfgs/lib/Makefile.in +0 -499
  124. data/core/vendor/src/liblbfgs/lib/arithmetic_ansi.h +0 -133
  125. data/core/vendor/src/liblbfgs/lib/arithmetic_sse_double.h +0 -294
  126. data/core/vendor/src/liblbfgs/lib/arithmetic_sse_float.h +0 -298
  127. data/core/vendor/src/liblbfgs/lib/lbfgs.c +0 -1371
  128. data/core/vendor/src/liblbfgs/lib/lib.vcxproj +0 -95
  129. data/core/vendor/src/liblbfgs/ltmain.sh +0 -6426
  130. data/core/vendor/src/liblbfgs/missing +0 -353
  131. data/core/vendor/src/liblbfgs/sample/Makefile.am +0 -15
  132. data/core/vendor/src/liblbfgs/sample/Makefile.in +0 -433
  133. data/core/vendor/src/liblbfgs/sample/sample.c +0 -81
  134. data/core/vendor/src/liblbfgs/sample/sample.cpp +0 -126
  135. data/core/vendor/src/liblbfgs/sample/sample.vcxproj +0 -105
  136. data/core/vendor/src/svm_light/LICENSE.txt +0 -59
  137. data/core/vendor/src/svm_light/Makefile +0 -105
  138. data/core/vendor/src/svm_light/kernel.h +0 -40
  139. data/core/vendor/src/svm_light/svm_classify.c +0 -197
  140. data/core/vendor/src/svm_light/svm_common.c +0 -985
  141. data/core/vendor/src/svm_light/svm_common.h +0 -301
  142. data/core/vendor/src/svm_light/svm_hideo.c +0 -1062
  143. data/core/vendor/src/svm_light/svm_learn.c +0 -4147
  144. data/core/vendor/src/svm_light/svm_learn.h +0 -169
  145. data/core/vendor/src/svm_light/svm_learn_main.c +0 -397
  146. data/core/vendor/src/svm_light/svm_loqo.c +0 -211
  147. data/task/c.rake +0 -36
  148. data/task/submodules.rake +0 -5
@@ -1,1107 +0,0 @@
1
- /*----------------------------------------------------------------------------
2
- * RumAVL - Threaded AVL Tree Implementation
3
- *
4
- * Copyright (c) 2005-2007 Jesse Long <jpl@unknown.za.net>
5
- * All rights reserved.
6
- *
7
- * Permission is hereby granted, free of charge, to any person obtaining a
8
- * copy of this software and associated documentation files (the "Software"),
9
- * to deal in the Software without restriction, including without limitation
10
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11
- * and/or sell copies of the Software, and to permit persons to whom the
12
- * Software is furnished to do so, subject to the following conditions:
13
- *
14
- * 1. The above copyright notice and this permission notice shall be
15
- * included in all copies or substantial portions of the Software.
16
- * 2. The origin of the Software must not be misrepresented; you must not
17
- * claim that you wrote the original Software.
18
- * 3. Altered source versions of the Software must be plainly marked as
19
- * such, and must not be misrepresented as being the original Software.
20
- *
21
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27
- * DEALINGS IN THE SOFTWARE.
28
- *--------------------------------------------------------------------------*/
29
-
30
- /*----------------------------------------------------------------------------
31
- * Although not required by the license, I would appreciate it if you would
32
- * send me a mail notifying me of bugfixes and enhancements you make to this
33
- * code. My email address is <jpl@unknown.za.net>
34
- *--------------------------------------------------------------------------*/
35
-
36
- /*----------------------------------------------------------------------------
37
- * DEVELOPEMENT NOTES
38
- *
39
- * Links
40
- * Each node has two links, link[0] is the left child, and link[1] is the
41
- * right child. When a link points to a node that is actually below it in
42
- * the BST, the respective thread flag is marked 0. When the link is a
43
- * thread, the respective thread flag is marked 1, or 2 if the thread is
44
- * to the opposite edge of the BST.
45
- *
46
- * Direction
47
- * In RumAVL we use the numbers -1 (RUMAVL_DESC) and +1 (RUMAVL_ASC) to
48
- * indicate direction, where -1 (RUMAVL_DESC) means left or descending in
49
- * value, and +1 (RUMAVL_ASC) means right or ascending in value.
50
- *
51
- * Threads
52
- * In RumAVL, the threads (non-bst links of leaves) are implemented in a
53
- * sort of circular list. It is important to note that you cannot go
54
- * through the entire list by following the same link, as you would when
55
- * going through a linked list. Draw an example threaded AVL tree on paper
56
- * and see why.
57
- *
58
- *--------------------------------------------------------------------------*/
59
-
60
- #include <stdlib.h>
61
- #include <string.h>
62
-
63
- #include "rumavl.h"
64
-
65
- /* For memory allocation debugging
66
- #ifdef USE_MEMBUG
67
- #define MEMBUG_DEFINES
68
- #include <membug.h>
69
- #endif */
70
-
71
-
72
-
73
-
74
- /*****************************************************************************
75
- *
76
- * MACROS - to make readability better
77
- *
78
- ****************************************************************************/
79
-
80
- /* Link numbers */
81
- #define LEFT (0)
82
- #define RIGHT (1)
83
-
84
- /* Direction to link no, expects RUMAVL_DESC or RUMAVL_ASC */
85
- #define LINK_NO(i) (((i) + 1) / 2) /* -1 => 0; 1 => 1 */
86
- /* Get opposite link number, expects LEFT or RIGHT */
87
- #define OTHER_LINK(i) ((i) ^ 1) /* 1 => 0; 0 => 1 */
88
-
89
- /* link no to direction, expects LEFT or RIGHT */
90
- #define DIR_NO(i) (((i) * 2) - 1) /* 0 => -1; 1 => 1 */
91
- /* opposite direction, expects RUMAVL_DESC or RUMAVL_ASC */
92
- #define OTHER_DIR(i) ((i) * -1) /* -1 => 1; 1 => -1 */
93
-
94
- /* Memory allocation functions */
95
- #define mem_alloc(tree, bytes) mem_mgr((tree), NULL, (bytes))
96
- #define mem_free(tree, ptr) mem_mgr((tree), (ptr), 0)
97
- #define mem_relloc(tree, ptr, bytes) mem_mgr((tree), (ptr), (bytes))
98
-
99
-
100
-
101
-
102
- /*****************************************************************************
103
- *
104
- * DATA TYPES
105
- *
106
- ****************************************************************************/
107
-
108
- /*
109
- * RUMAVL - the handle on the tree
110
- *
111
- * All settings for a tree are in the RUMAVL object, including memory
112
- * management, delete and overwrite callback functions, and the record
113
- * comparison function pointer.
114
- */
115
- struct rumavl {
116
- RUMAVL_NODE *root; /* root node in tree */
117
- size_t reclen; /* length of records */
118
- int (*cmp)(const void *, /* function to compare records */
119
- const void *,
120
- size_t,
121
- void *);
122
- int (*owcb)(RUMAVL *, RUMAVL_NODE *, void *, const void *, void *);
123
- int (*delcb)(RUMAVL *, RUMAVL_NODE *, void *, void *);
124
- void *(*alloc)(void *, size_t, void *);
125
- void *udata; /* user data for callbacks */
126
- };
127
-
128
- /*
129
- * RUMAVL_NODE - the node structure
130
- *
131
- * RUMAVL_NODE's contain all information about a specific node, including
132
- * links to the right and left children of the node, and flags (thread)
133
- * indicating whether or not the links are threads or not, and the balance
134
- * factor of the node.
135
- *
136
- * The record associated with each node is allocated along with the node,
137
- * and can be found directly after the node, by using the NODE_REC() macro.
138
- */
139
- struct rumavl_node {
140
- RUMAVL_NODE *link[2]; /* links to child nodes */
141
- char thread[2]; /* flags for links, normal link or thread? */
142
- signed char balance; /* balance factor for node */
143
- void *rec;
144
- #define NODE_REC(node) ((node)->rec)
145
- };
146
-
147
- /*
148
- * RUMAVL_STACK - a stack of nodes forming a path to a node
149
- *
150
- * RUMAVL_STACK's are used while deleting and inserting nodes, where effects
151
- * could be felt by all parents of the node. RUMAVL_STACK's are implemented
152
- * in a singly linked list. This is a change from the method used by most AVL
153
- * trees, where a static array node pointers are allocated. Linked lists allow
154
- * fo an unlimited height in the AVL tree.
155
- *
156
- * node is a pointer to the parent node's pointer to the node in question.
157
- * dir is the direction of the descent from this node.
158
- */
159
- typedef struct rumavl_stack RUMAVL_STACK;
160
- struct rumavl_stack {
161
- RUMAVL_STACK *next;
162
- RUMAVL_NODE **node;
163
- int dir;
164
- };
165
-
166
- /* various other RumAVL specific structs defined in rumavl.h */
167
-
168
-
169
-
170
-
171
- /*****************************************************************************
172
- *
173
- * FORWARD DECLERATIONS
174
- *
175
- ****************************************************************************/
176
-
177
- static RUMAVL_NODE *seq_next (RUMAVL_NODE *node, int dir);
178
- static RUMAVL_NODE *node_new(RUMAVL *tree, const void *record);
179
- static void node_destroy (RUMAVL *tree, RUMAVL_NODE *node);
180
- static int stack_push (RUMAVL *tree, RUMAVL_STACK **stack, RUMAVL_NODE **node,
181
- int dir);
182
- static void stack_destroy(RUMAVL *tree, RUMAVL_STACK *stack);
183
- static void stack_update(RUMAVL *tree, RUMAVL_STACK *stack, signed char diff);
184
-
185
- static signed char balance (RUMAVL_NODE **node, int dir);
186
- static signed char rotate (RUMAVL_NODE **node, int dir);
187
-
188
- static void *mem_mgr (RUMAVL *tree, void *ptr, size_t size);
189
-
190
- static int rec_cmp (RUMAVL *tree, const void *reca, const void *recb);
191
- static int my_cmp (const void *a, const void *b, size_t n, void *udata);
192
-
193
- static int insert_cb (RUMAVL *t, RUMAVL_NODE *n, void *r1, const void *r2,
194
- void *udata);
195
-
196
-
197
-
198
- /*****************************************************************************
199
- *
200
- * PUBLIC FUNCTIONS
201
- *
202
- ****************************************************************************/
203
-
204
- /*----------------------------------------------------------------------------
205
- * rumavl_new - allocates a new RUMAVL object, and initialises it. This is the
206
- * only time the user gets to set the record length and record comparison
207
- * function, to avoid data loss.
208
- *--------------------------------------------------------------------------*/
209
- RUMAVL *rumavl_new (size_t reclen,
210
- int (*cmp)(const void *, const void *, size_t, void *),
211
- void *(*alloc)(void *, size_t, void *),
212
- void *udata)
213
- {
214
- RUMAVL *tree;
215
-
216
- if (reclen < 1)
217
- return NULL;
218
-
219
- if (alloc == NULL)
220
- tree = malloc(sizeof(RUMAVL));
221
- else
222
- tree = alloc(NULL, sizeof(RUMAVL), udata);
223
-
224
- if (tree == NULL)
225
- return NULL;
226
-
227
- tree->root = NULL;
228
-
229
- tree->owcb = NULL;
230
- tree->delcb = NULL;
231
-
232
- tree->alloc = alloc;
233
-
234
- tree->reclen = reclen;
235
- tree->udata = udata;
236
-
237
- if (cmp == NULL)
238
- tree->cmp = my_cmp;
239
- else
240
- tree->cmp = cmp;
241
-
242
- return tree;
243
- }
244
-
245
- /*----------------------------------------------------------------------------
246
- * rumavl_destroy - cleanly frees all memory used by the RUMAVL, as well as
247
- * all nodes. All nodes are passed to the delete callback function in case the
248
- * user has a special way of destroying nodes. The return value of the delete
249
- * callback function is ignored, because once we start destroying we cant
250
- * simply undestroy half the nodes.
251
- *--------------------------------------------------------------------------*/
252
- void rumavl_destroy (RUMAVL *tree)
253
- {
254
- RUMAVL_NODE *node, *tmp;
255
-
256
- if (tree->root != NULL){
257
- /* walk through tree deleting all */
258
- node = tree->root;
259
- while (node->thread[LEFT] == 0) /* move to bottom left most node */
260
- node = node->link[LEFT];
261
- while (node != NULL){
262
- tmp = seq_next(node, RUMAVL_ASC);
263
- if (tree->delcb != NULL){
264
- tree->delcb(tree, node, NODE_REC(node), tree->udata);
265
- }
266
- node_destroy(tree, node);
267
- node = tmp;
268
- }
269
- }
270
-
271
- if (tree->alloc == NULL)
272
- free(tree);
273
- else
274
- tree->alloc(tree, 0, tree->udata);
275
- }
276
-
277
- /*---------------------------------------------------------------------------
278
- * rumavl_udata - get a pointer to the tree's user pointer
279
- *-------------------------------------------------------------------------*/
280
- void **rumavl_udata (RUMAVL *tree)
281
- {
282
- return &tree->udata;
283
- }
284
-
285
- int (**rumavl_owcb(RUMAVL *tree))(RUMAVL *, RUMAVL_NODE *, void *,
286
- const void *, void *)
287
- {
288
- return &tree->owcb;
289
- }
290
-
291
- int (**rumavl_delcb(RUMAVL *tree))(RUMAVL *, RUMAVL_NODE *, void *, void *)
292
- {
293
- return &tree->delcb;
294
- }
295
-
296
- /*----------------------------------------------------------------------------
297
- * rumavl_set - set a node, overwriting if necessary, or creating if the node
298
- * does not exist
299
- *--------------------------------------------------------------------------*/
300
- int rumavl_set (RUMAVL *tree, const void *record)
301
- {
302
- RUMAVL_NODE **node, *tmp;
303
- RUMAVL_STACK *stack;
304
- int ln;
305
-
306
- if (tree->root == NULL){
307
- /* This is the first node in the tree */
308
- if ((tree->root = node_new(tree, record)) == NULL)
309
- return RUMAVL_ERR_NOMEM;
310
- tree->root->link[LEFT] = tree->root;
311
- tree->root->link[RIGHT] = tree->root;
312
- tree->root->thread[LEFT] = 2;
313
- tree->root->thread[RIGHT] = 2;
314
- return 0;
315
- }
316
-
317
- /* Since the tree is not empty, we must descend towards the nodes ideal
318
- * possition, and we may even find an existing node with the same record.
319
- * We keep a list parents for the eventual node position, because these
320
- * parents may become inbalanced by a new insertion. */
321
-
322
- stack = NULL;
323
- node = &tree->root;
324
- for (;;){
325
- if ((ln = rec_cmp(tree, record, NODE_REC(*node))) == 0){
326
- /* OK, we found the exact node we wish to set, and we now
327
- * overwrite it. No change happens to the tree structure */
328
- stack_destroy(tree, stack);
329
-
330
- if (tree->owcb != NULL &&
331
- (ln = tree->owcb(tree, *node, NODE_REC(*node),
332
- record, tree->udata)) != 0){
333
- return ln;
334
- }
335
-
336
- memcpy(NODE_REC(*node), record, tree->reclen);
337
- return 0;
338
- }
339
-
340
- /* *node is not the node we seek */
341
-
342
- if (stack_push(tree, &stack, node, ln)){
343
- stack_destroy(tree, stack);
344
- return RUMAVL_ERR_NOMEM;
345
- }
346
-
347
- ln = LINK_NO(ln);
348
- if ((*node)->thread[ln] > 0){
349
- /* This is as close to the correct node as we can get. We will
350
- * now break and add the new node as a leaf */
351
- break;
352
- }
353
-
354
- node = &(*node)->link[ln];
355
- }
356
-
357
- /* we have reached a leaf, add new node here */
358
- if ((tmp = node_new(tree, record)) == NULL){
359
- stack_destroy(tree, stack);
360
- return RUMAVL_ERR_NOMEM;
361
- }
362
- /* new child inherits parent thread */
363
- tmp->link[ln] = (*node)->link[ln];
364
- tmp->thread[ln] = (*node)->thread[ln];
365
- if (tmp->thread[ln] == 2)
366
- tmp->link[ln]->link[OTHER_LINK(ln)] = tmp;
367
-
368
- tmp->link[OTHER_LINK(ln)] = *node;
369
- tmp->thread[OTHER_LINK(ln)] = 1;
370
- (*node)->link[ln] = tmp;
371
- (*node)->thread[ln] = 0;
372
-
373
- /* all parentage is now one level heavier - balance where necessary */
374
- stack_update(tree, stack, +1);
375
-
376
- return 0;
377
- }
378
-
379
-
380
- /*----------------------------------------------------------------------------
381
- * rumavl_insert - like rumavl_set, but only works if the node does not
382
- * exist. Temporarily replaces overwrite callback with a function that
383
- * always prevents overwrite, and calls rumavl_set()
384
- *--------------------------------------------------------------------------*/
385
- int rumavl_insert (RUMAVL *tree, const void *record)
386
- {
387
- int retv;
388
- int (*tmp)(RUMAVL *, RUMAVL_NODE *, void *, const void *, void *);
389
-
390
- tmp = tree->owcb;
391
- tree->owcb = insert_cb;
392
- retv = rumavl_set(tree, record);
393
- tree->owcb = tmp;
394
- return retv;
395
- }
396
-
397
- /*----------------------------------------------------------------------------
398
- * rumavl_delete - deletes a node. Beware! this function is the worst part of
399
- * the library. Think (and draw pictures) when you edit this function.
400
- *--------------------------------------------------------------------------*/
401
- int rumavl_delete (RUMAVL *tree, const void *record)
402
- {
403
- RUMAVL_NODE **node, *tmpnode;
404
- RUMAVL_STACK *stack;
405
- int dir, ln;
406
-
407
- if (tree->root == NULL) /* tree is empty */
408
- return RUMAVL_ERR_NOENT;
409
-
410
- stack = NULL;
411
- node = &tree->root;
412
-
413
- /* Find desired node */
414
- while ((dir = rec_cmp(tree, record, NODE_REC(*node))) != 0){
415
- if (stack_push(tree, &stack, node, dir) != 0)
416
- goto nomemout;
417
-
418
- if ((*node)->thread[LINK_NO(dir)] > 0){
419
- /* desired node does not exist */
420
- stack_destroy(tree, stack);
421
- return RUMAVL_ERR_NOENT;
422
- }
423
- node = &(*node)->link[LINK_NO(dir)];
424
- }
425
-
426
- /* OK, we got the node to be deleted, now get confirmation from user */
427
- if (tree->delcb != NULL &&
428
- (ln = tree->delcb(tree, *node, NODE_REC(*node), tree->udata))
429
- != 0){
430
- stack_destroy(tree, stack);
431
- return ln;
432
- }
433
-
434
- if ((*node)->thread[LEFT] > 0){
435
- if ((*node)->thread[RIGHT] > 0){
436
- /* ooh look, we're a leaf */
437
- tmpnode = *node;
438
- if (stack != NULL){
439
- /* This node has a parent, which will need to take over a
440
- * thread from the node being deleted. First we work out
441
- * which (left/right) child we are of parent, then give
442
- * parent the respective thread. If the thread destination
443
- * points back to us (edge of tree thread), update it to
444
- * point to our parent. */
445
- ln = LINK_NO(stack->dir);
446
- (*stack->node)->link[ln] = tmpnode->link[ln];
447
- (*stack->node)->thread[ln] = tmpnode->thread[ln];
448
- if ((*stack->node)->thread[ln] == 2)
449
- (*stack->node)->link[ln]->link[OTHER_LINK(ln)] =
450
- *stack->node;
451
- }else{
452
- /*
453
- * the only time stack will == NULL is when we are
454
- * deleting the root of the tree. We already know that
455
- * this is a leaf, so we will be leaving the tree empty.
456
- */
457
- tree->root = NULL;
458
- }
459
- node_destroy(tree, tmpnode);
460
- }else{
461
- /* *node has only one child, and can be pruned by replacing
462
- * *node with its only child. This block of code and the next
463
- * should be identical, except that all directions and link
464
- * numbers are opposite.
465
- *
466
- * Let node being deleted = DELNODE for this comment.
467
- * DELNODE only has one child (the right child). The left
468
- * most descendant of DELNODE will have a thread (left thread)
469
- * pointing to DELNODE. This thread must be updated to point
470
- * to the node currently pointed to by DELNODE's left thread.
471
- *
472
- * DELNODE's left thread may point to the opposite edge of the
473
- * BST. In this case, the destination of the thread will have
474
- * a thread back to DELNODE. This will need to be updated to
475
- * point back to the leftmost descendant of DELNODE.
476
- */
477
- tmpnode = *node; /* node being deleted */
478
- *node = (*node)->link[RIGHT]; /* right child */
479
- /* find left most descendant */
480
- while ((*node)->thread[LEFT] == 0)
481
- node = &(*node)->link[LEFT];
482
- /* inherit thread from node being deleted */
483
- (*node)->link[LEFT] = tmpnode->link[LEFT];
484
- (*node)->thread[LEFT] = tmpnode->thread[LEFT];
485
- /* update reverse thread if necessary */
486
- if ((*node)->thread[LEFT] == 2)
487
- (*node)->link[LEFT]->link[RIGHT] = *node;
488
- node_destroy(tree, tmpnode);
489
- }
490
- }else if ((*node)->thread[RIGHT] > 0){
491
- /* see above */
492
- tmpnode = *node;
493
- *node = (*node)->link[LEFT];
494
- while ((*node)->thread[RIGHT] == 0)
495
- node = &(*node)->link[RIGHT];
496
- (*node)->link[RIGHT] = tmpnode->link[RIGHT];
497
- (*node)->thread[RIGHT] = tmpnode->thread[RIGHT];
498
- if ((*node)->thread[RIGHT] == 2)
499
- (*node)->link[RIGHT]->link[LEFT] = *node;
500
- node_destroy(tree, tmpnode);
501
- }else{
502
- /* Delete a node with children on both sides. We do this by replacing
503
- * the node to be deleted (delnode) with its inner most child
504
- * on the heavier side (repnode). This in place replacement is quicker
505
- * than the previously used method of rotating delnode until it is a
506
- * (semi) leaf.
507
- *
508
- * At this point node points to delnode's parent's link to delnode. */
509
- RUMAVL_NODE *repnode, *parent;
510
- int outdir, outln;
511
-
512
- /* find heaviest subtree */
513
- if ((*node)->balance > 0){
514
- outdir = +1; /* outter direction */
515
- dir = -1; /* inner direction */
516
- outln = 1; /* outer link number */
517
- ln = 0; /* inner link number */
518
- }else{
519
- outdir = -1; /* same as above, but opposite subtree */
520
- dir = +1;
521
- outln = 0;
522
- ln = 1;
523
- }
524
-
525
- /* Add node to be deleted to the list of nodes to be rebalanced.
526
- * Rememer that the replacement node will actually be acted apon,
527
- * and that the replacement node should feel the effect of its own
528
- * move */
529
- if (stack_push(tree, &stack, node, outdir) != 0)
530
- goto nomemout;
531
-
532
- parent = *node;
533
- repnode = parent->link[outln];
534
-
535
- if (repnode->thread[ln] != 0){
536
- /* repnode inherits delnode's lighter tree, and balance, and gets
537
- * balance readjusted below */
538
- repnode->link[ln] = (*node)->link[ln];
539
- repnode->thread[ln] = (*node)->thread[ln];
540
- repnode->balance = (*node)->balance;
541
- }else{
542
- /* Now we add delnodes direct child to the list of "to update".
543
- * We pass a pointer to delnode's link to its direct child to
544
- * stack_push(), but that pointer is invalid, because when
545
- * stack_update() tries to access the link, delnode would have
546
- * been destroyed. So, we remember the stack position at which
547
- * we passed the faulty pointer to stack_push, and update its
548
- * node pointer when we find repnode to point to repnodes
549
- * link on the same side */
550
- RUMAVL_STACK *tmpstack;
551
-
552
- if (stack_push(tree, &stack, &parent->link[outln], dir) != 0)
553
- goto nomemout;
554
-
555
- tmpstack = stack;
556
-
557
- parent = repnode;
558
- repnode = repnode->link[ln];
559
-
560
- /* move towards the innermost child of delnode */
561
- while (repnode->thread[ln] == 0){
562
- if (stack_push(tree, &stack, &parent->link[ln], dir) != 0)
563
- goto nomemout;
564
- parent = repnode;
565
- repnode = repnode->link[ln];
566
- }
567
-
568
- if (repnode->thread[outln] == 0){
569
- /* repnode's parent inherits repnodes only child */
570
- parent->link[ln] = repnode->link[outln];
571
- }else{
572
- /* parent already has a link to repnode, but it must now be
573
- * marked as a thread */
574
- parent->thread[ln] = 1;
575
- }
576
-
577
- repnode->link[0] = (*node)->link[0];
578
- repnode->thread[0] = (*node)->thread[0];
579
- repnode->link[1] = (*node)->link[1];
580
- repnode->thread[1] = (*node)->thread[1];
581
- repnode->balance = (*node)->balance;
582
-
583
- /* see comment above */
584
- tmpstack->node = &repnode->link[outln];
585
- }
586
- node_destroy(tree, *node);
587
- *node = repnode;
588
-
589
- /* innermost child in lighter tree has an invalid thread to delnode,
590
- * update it to point to repnode */
591
- repnode = seq_next(repnode, dir);
592
- repnode->link[outln] = *node;
593
- }
594
-
595
- /* update parents' balances */
596
- stack_update(tree, stack, -1);
597
- return 0;
598
-
599
- nomemout:
600
- stack_destroy(tree, stack);
601
- return RUMAVL_ERR_NOMEM;
602
- }
603
-
604
- /*----------------------------------------------------------------------------
605
- * rumavl_find
606
- *
607
- * Returns a pointer to the record that matches "record".
608
- *--------------------------------------------------------------------------*/
609
- void *rumavl_find (RUMAVL *tree, const void *find)
610
- {
611
- void *record;
612
- rumavl_node_find(tree, find, &record);
613
- return record;
614
- }
615
-
616
- void *(**rumavl_alloc(RUMAVL *tree))(void *ptr, size_t size, void *udata)
617
- {
618
- return &tree->alloc;
619
- }
620
-
621
- /*----------------------------------------------------------------------------
622
- * rumavl_record_size - returns size of all records in a tree
623
- *--------------------------------------------------------------------------*/
624
- size_t rumavl_record_size (RUMAVL *tree)
625
- {
626
- return tree->reclen;
627
- }
628
-
629
- /*----------------------------------------------------------------------------
630
- * rumavl_node_find
631
- *
632
- * Returns a pointer to the node that matches "record".
633
- *--------------------------------------------------------------------------*/
634
- RUMAVL_NODE *rumavl_node_find (RUMAVL *tree, const void *find, void **record)
635
- {
636
- RUMAVL_NODE *node;
637
- int ln;
638
-
639
- if (find == NULL || tree->root == NULL)
640
- goto fail;
641
-
642
- node = tree->root;
643
- for (;;){
644
- if ((ln = rec_cmp(tree, find, NODE_REC(node))) == 0){
645
- if (record != NULL)
646
- *record = NODE_REC(node);
647
- return node;
648
- }
649
-
650
- ln = LINK_NO(ln);
651
- if (node->thread[ln] > 0)
652
- break;
653
-
654
- node = node->link[ln];
655
- }
656
- /* we didn't find the desired node */
657
-
658
- fail:
659
- if (record != NULL)
660
- *record = NULL;
661
-
662
- return NULL;
663
- }
664
-
665
- /*----------------------------------------------------------------------------
666
- * rumavl_node_next - find next node
667
- *--------------------------------------------------------------------------*/
668
- RUMAVL_NODE *rumavl_node_next (RUMAVL *tree, RUMAVL_NODE *node, int dir,
669
- void **record)
670
- {
671
- /* make sure `dir' is either RUMAVL_ASC or RUMAVL_DESC */
672
- if (dir == 0)
673
- goto fail;
674
- else if (dir > 0)
675
- dir = RUMAVL_ASC;
676
- else
677
- dir = RUMAVL_DESC;
678
-
679
- /* if node is uninitialised, start with first possible node in `dir'
680
- * direction */
681
- if (node == NULL){
682
- /* unless the tree is empty of course */
683
- if (tree->root == NULL)
684
- goto fail;
685
-
686
- dir = OTHER_LINK(LINK_NO(dir));
687
- node = tree->root;
688
- while (node->thread[dir] == 0){
689
- node = node->link[dir];
690
- }
691
- goto found;
692
- }
693
-
694
- if ((node = seq_next(node, dir)) == NULL)
695
- goto fail;
696
-
697
- /* fall through */
698
-
699
- found:
700
- if (record != NULL)
701
- *record = NODE_REC(node);
702
- return node;
703
-
704
- fail:
705
- if (record != NULL)
706
- *record = NULL;
707
- return NULL;
708
- }
709
-
710
- /*----------------------------------------------------------------------------
711
- * rumavl_node_record - returns a pointer to the record stored in a node
712
- *--------------------------------------------------------------------------*/
713
- void *rumavl_node_record (RUMAVL_NODE *node)
714
- {
715
- return NODE_REC(node);
716
- }
717
-
718
- /*----------------------------------------------------------------------------
719
- * rumavl_foreach - loop through entire tree, using temporary iterator
720
- *--------------------------------------------------------------------------*/
721
- extern int rumavl_foreach (RUMAVL *tree, int dir,
722
- int (*cbfn)(RUMAVL *, void *, void *), void *udata)
723
- {
724
- RUMAVL_NODE *node;
725
- int retv;
726
- void *record;
727
-
728
- if (cbfn == NULL)
729
- return RUMAVL_ERR_INVAL;
730
-
731
- retv = RUMAVL_ERR_NOENT;
732
- node = NULL;
733
- while ((node = rumavl_node_next(tree, node, dir, &record)) != NULL){
734
- if ((retv = cbfn(tree, record, udata)) != 0)
735
- break;
736
- }
737
-
738
- return retv;
739
- }
740
-
741
- /*----------------------------------------------------------------------------
742
- * rumavl_strerror - return string description of RumAVL error code
743
- *--------------------------------------------------------------------------*/
744
- const char *rumavl_strerror (int errno)
745
- {
746
- switch (errno){
747
- case 0:
748
- return "Operation successful";
749
- case RUMAVL_ERR_INVAL:
750
- return "Invalid argument to function";
751
- case RUMAVL_ERR_NOMEM:
752
- return "Insufficient memory to complete operation";
753
- case RUMAVL_ERR_NOENT:
754
- return "Entry does not exist";
755
- case RUMAVL_ERR_EORNG:
756
- return "No more entries in range";
757
- case RUMAVL_ERR_EXIST:
758
- return "Entry already exists";
759
- }
760
- return "UNKNOWN ERROR";
761
- }
762
-
763
-
764
-
765
-
766
- /*****************************************************************************
767
- *
768
- * PRIVATE FUNCTIONS
769
- *
770
- ****************************************************************************/
771
-
772
- /*----------------------------------------------------------------------------
773
- * insert_cb - used by rumavl_insert() to disallow any overwriting by
774
- * rumavl_set()
775
- *--------------------------------------------------------------------------*/
776
- static int insert_cb (RUMAVL *t, RUMAVL_NODE *n, void *r1, const void *r2,
777
- void *udata)
778
- {
779
- (void) t; (void) r1; (void) r2; (void) udata; (void) n;
780
- return RUMAVL_ERR_EXIST;
781
- }
782
-
783
- /*----------------------------------------------------------------------------
784
- * seq_next - return a pointer to the next node in sequence
785
- *--------------------------------------------------------------------------*/
786
- static RUMAVL_NODE *seq_next (RUMAVL_NODE *node, int dir)
787
- {
788
- int ln;
789
-
790
- ln = LINK_NO(dir);
791
- if (node->thread[ln] == 2){
792
- return NULL;
793
- }else if (node->thread[ln] == 1){
794
- return node->link[ln];
795
- }
796
- node = node->link[ln];
797
- ln = OTHER_LINK(ln);
798
- while (node->thread[ln] == 0){
799
- node = node->link[ln];
800
- }
801
- return node;
802
- }
803
-
804
- /*----------------------------------------------------------------------------
805
- * node_new - create a new node. MUST update link[] and thread[] after calling
806
- * this function
807
- *--------------------------------------------------------------------------*/
808
- static RUMAVL_NODE *node_new(RUMAVL *tree, const void *record)
809
- {
810
- RUMAVL_NODE *node;
811
-
812
- if ((node = mem_alloc(tree, sizeof(RUMAVL_NODE))) == NULL)
813
- return NULL;
814
-
815
- if ((node->rec = mem_alloc(tree, tree->reclen)) == NULL){
816
- mem_free(tree, node);
817
- return NULL;
818
- }
819
-
820
- memcpy(node->rec, record, tree->reclen);
821
- node->balance = 0;
822
- node->link[0] = NULL;
823
- node->link[1] = NULL;
824
- node->thread[0] = 0;
825
- node->thread[1] = 0;
826
- return node;
827
- }
828
-
829
- /*----------------------------------------------------------------------------
830
- * node_destroy - cleanly destroy node
831
- *--------------------------------------------------------------------------*/
832
- static void node_destroy (RUMAVL *tree, RUMAVL_NODE *node)
833
- {
834
- mem_free(tree, node);
835
- }
836
-
837
- /*----------------------------------------------------------------------------
838
- * stack_push - push a node entry onto stack, for rumavl_set() and
839
- * rumavl_delete(). If this is the first entry, *stack should == NULL
840
- *--------------------------------------------------------------------------*/
841
- static int stack_push(RUMAVL *tree, RUMAVL_STACK **stack, RUMAVL_NODE **node,
842
- int dir)
843
- {
844
- RUMAVL_STACK *tmp;
845
-
846
- if ((tmp = mem_alloc(tree, sizeof(RUMAVL_STACK))) == NULL)
847
- return -1;
848
-
849
- tmp->next = *stack;
850
- *stack = tmp;
851
- tmp->node = node;
852
- tmp->dir = dir;
853
-
854
- return 0;
855
- }
856
-
857
- /*----------------------------------------------------------------------------
858
- * stack_destroy - free up a stack
859
- *--------------------------------------------------------------------------*/
860
- static void stack_destroy(RUMAVL *tree, RUMAVL_STACK *stack)
861
- {
862
- RUMAVL_STACK *tmp;
863
- while (stack != NULL){
864
- tmp = stack;
865
- stack = stack->next;
866
- mem_free(tree, tmp);
867
- }
868
- }
869
-
870
- /*----------------------------------------------------------------------------
871
- * stack_update - goes up stack readjusting balance as needed. This function
872
- * serves as a testiment to the philosophy of commenting while you code, 'cos
873
- * hell if I can remember how I got to this. I think is has something to do
874
- * with the varying effects on tree height, depending on exactly which sub
875
- * tree, or sub-sub tree was modified. TODO study and comment
876
- *--------------------------------------------------------------------------*/
877
- static void stack_update(RUMAVL *tree, RUMAVL_STACK *stack, signed char diff)
878
- {
879
- RUMAVL_STACK *tmpstack;
880
-
881
- /* if diff becomes 0, we quit, because no further change to ancestors
882
- * can be made */
883
- while (stack != NULL && diff != 0){
884
- signed char ob, nb;
885
- ob = (*stack->node)->balance;
886
- (*stack->node)->balance += diff * (signed char)stack->dir;
887
- nb = (*stack->node)->balance;
888
- if (diff < 0){
889
- if (stack->dir == -1 && ob < 0){
890
- if (nb > 0)
891
- nb = 0;
892
- diff = (nb - ob) * -1;
893
- }else if (stack->dir == 1 && ob > 0){
894
- if (nb < 0)
895
- nb = 0;
896
- diff = nb - ob;
897
- }else{
898
- diff = 0;
899
- }
900
- }else{
901
- if (stack->dir == -1 && nb < 0){
902
- if (ob > 0)
903
- ob = 0;
904
- diff = (nb - ob) * -1;
905
- }else if (stack->dir == 1 && nb > 0){
906
- if (ob < 0)
907
- ob = 0;
908
- diff = nb - ob;
909
- }else{
910
- diff = 0;
911
- }
912
- }
913
- while ((*stack->node)->balance > 1){
914
- diff += balance(stack->node, -1);
915
- }
916
- while ((*stack->node)->balance < -1){
917
- diff += balance(stack->node, 1);
918
- }
919
- tmpstack = stack;
920
- stack = stack->next;
921
- mem_free(tree, tmpstack);
922
- }
923
-
924
- /* we may exit early if diff becomes 0. We still need to free all stack
925
- * entries */
926
- while (stack != NULL){
927
- tmpstack = stack;
928
- stack = stack->next;
929
- mem_free(tree, tmpstack);
930
- }
931
- }
932
-
933
- /*----------------------------------------------------------------------------
934
- * my_cmp - a wrapper around memcmp() for default record comparison function.
935
- *--------------------------------------------------------------------------*/
936
- static int my_cmp (const void *a, const void *b, size_t n, void *udata)
937
- {
938
- (void) udata;
939
- return memcmp(a, b, n);
940
- }
941
-
942
- /*----------------------------------------------------------------------------
943
- * rec_cmp - a wrapper around the record comparison function, that only
944
- * returns 0, RUMAVL_ASC or RUMAVL_DESC.
945
- *--------------------------------------------------------------------------*/
946
- static int rec_cmp (RUMAVL *tree, const void *reca, const void *recb)
947
- {
948
- int retv;
949
- retv = tree->cmp(reca, recb, tree->reclen, tree->udata);
950
- if (retv < 0)
951
- return RUMAVL_DESC;
952
- if (retv > 0)
953
- return RUMAVL_ASC;
954
- return 0;
955
- }
956
-
957
- /*----------------------------------------------------------------------------
958
- * Balance - rotate or double rotate as needed. Sometimes simply rotating a
959
- * tree is inefficient, as it leaves the tree as inbalanced as it was before
960
- * the rotate. To rectify this, we first rotate the heavier child so that the
961
- * heavier grandchild is on the outside, then rotate as per normal.
962
- *
963
- * TODO Check all callers, and make sure that they call this function sanely,
964
- * and then remove unnecessary checks.
965
- *--------------------------------------------------------------------------*/
966
- static signed char balance (RUMAVL_NODE **node, int dir)
967
- {
968
- int ln;
969
- signed char retv;
970
-
971
- if (node == NULL || *node == NULL || (dir * dir) != 1)
972
- return 0;
973
-
974
- ln = OTHER_LINK(LINK_NO(dir)); /* link number of new root */
975
-
976
- /* new root must exist */
977
- if ((*node)->thread[ln] > 0)
978
- return 0;
979
-
980
- retv = 0;
981
- if ((*node)->link[ln]->balance == (char) dir &&
982
- (*node)->link[ln]->thread[OTHER_LINK(ln)] == 0){
983
- /* double rotate if inner grandchild is heaviest */
984
- retv = rotate (&((*node)->link[ln]), OTHER_DIR(dir));
985
- }
986
-
987
- return retv + rotate (node, dir);
988
- }
989
-
990
- /*----------------------------------------------------------------------------
991
- * rotate
992
- *
993
- * rotates a tree rooted at *node. dir determines the direction of the rotate,
994
- * dir < 0 -> left rotate; dir >= 0 -> right rotate
995
- *
996
- * TODO How sure are we that all callers pass decent `dir' values?
997
- * TODO Restudy the tree height modification and balance factor algorithms,
998
- * and document them.
999
- *--------------------------------------------------------------------------*/
1000
- static signed char rotate (RUMAVL_NODE **node, int dir)
1001
- {
1002
- RUMAVL_NODE *tmp;
1003
- signed char a, b, ad, bd, retv;
1004
- int ln;
1005
-
1006
- /* force |dir| to be either -1 or +1 */
1007
- if (node == NULL || *node == NULL || (dir * dir) != 1)
1008
- return 0;
1009
-
1010
- ln = LINK_NO(dir);
1011
- ln = OTHER_LINK(ln); /* link number of new root */
1012
-
1013
- /* new root must exist */
1014
- if ((*node)->thread[ln] > 0)
1015
- return 0;
1016
-
1017
- /* calculate effect on tree height */
1018
- if ((dir == 1 && (*node)->balance < 0 && (*node)->link[0]->balance >= 0)||
1019
- (dir == -1 && (*node)->balance > 0 && (*node)->link[1]->balance <= 0)){
1020
- retv = 0;
1021
- }else{
1022
- if (dir == 1){
1023
- if ((*node)->balance < -1)
1024
- retv = -1;
1025
- else if ((*node)->balance == -1)
1026
- retv = 0;
1027
- else
1028
- retv = +1;
1029
- }else{
1030
- if ((*node)->balance > 1)
1031
- retv = -1;
1032
- else if ((*node)->balance == 1)
1033
- retv = 0;
1034
- else
1035
- retv = +1;
1036
- }
1037
- }
1038
-
1039
-
1040
- /* rotate tree */
1041
- tmp = *node;
1042
- *node = tmp->link[ln];
1043
- if ((*node)->thread[OTHER_LINK(ln)] > 0){
1044
- tmp->thread[ln] = 1;
1045
- }else{
1046
- tmp->link[ln] = (*node)->link[OTHER_LINK(ln)];
1047
- tmp->thread[ln] = 0;
1048
- }
1049
- (*node)->link[OTHER_LINK(ln)] = tmp;
1050
- (*node)->thread[OTHER_LINK(ln)] = 0;
1051
-
1052
-
1053
-
1054
- /* rebalance factors after rotate matrix */
1055
- a = tmp->balance;
1056
- b = (*node)->balance;
1057
-
1058
- if (a > 0)
1059
- ad = 1;
1060
- else if (a < 0)
1061
- ad = -1;
1062
- else
1063
- ad = 0;
1064
-
1065
- if (b > 0)
1066
- bd = 1;
1067
- else if (b < 0)
1068
- bd = -1;
1069
- else
1070
- bd = 0;
1071
-
1072
- if (ad == OTHER_DIR(dir)){
1073
- if (bd == OTHER_DIR(dir)){
1074
- tmp->balance += (b * -1) + dir;
1075
- if (tmp->balance * dir > 0)
1076
- (*node)->balance = (tmp->balance - (b * -1)) + dir;
1077
- else
1078
- (*node)->balance += dir;
1079
- }else{
1080
- tmp->balance += dir;
1081
- (*node)->balance += dir;
1082
- }
1083
- }else{
1084
- if (bd == OTHER_DIR(dir)){
1085
- tmp->balance += (b * -1) + dir;
1086
- (*node)->balance += dir + tmp->balance;
1087
- }else{
1088
- tmp->balance += dir;
1089
- (*node)->balance += dir + tmp->balance;
1090
- }
1091
- }
1092
-
1093
- return retv;
1094
- }
1095
-
1096
- /*----------------------------------------------------------------------------
1097
- * mem_alloc
1098
- *
1099
- * default memory allocation function (malloc wrapper)
1100
- *--------------------------------------------------------------------------*/
1101
- static void *mem_mgr (RUMAVL *tree, void *ptr, size_t size)
1102
- {
1103
- if (tree->alloc != NULL)
1104
- return tree->alloc(ptr, size, tree->udata);
1105
-
1106
- return realloc(ptr, size);
1107
- }