opener-opinion-detector-basic 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (168) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +30 -0
  3. data/bin/opinion-detector-basic +19 -0
  4. data/bin/opinion-detector-basic-server +10 -0
  5. data/config.ru +4 -0
  6. data/core/opinion_detector_basic_multi.py +499 -0
  7. data/core/packages/KafNafParser-1.3.tar.gz +0 -0
  8. data/core/packages/VUA_pylib-1.4.tar.gz +0 -0
  9. data/core/site-packages/pre_build/VUKafParserPy-1.0-py2.7.egg-info/PKG-INFO +10 -0
  10. data/core/site-packages/pre_build/VUKafParserPy-1.0-py2.7.egg-info/SOURCES.txt +7 -0
  11. data/core/site-packages/pre_build/VUKafParserPy-1.0-py2.7.egg-info/dependency_links.txt +1 -0
  12. data/core/site-packages/pre_build/VUKafParserPy-1.0-py2.7.egg-info/installed-files.txt +11 -0
  13. data/core/site-packages/pre_build/VUKafParserPy-1.0-py2.7.egg-info/top_level.txt +1 -0
  14. data/core/site-packages/pre_build/VUKafParserPy/KafDataObjectsMod.py +165 -0
  15. data/core/site-packages/pre_build/VUKafParserPy/KafDataObjectsMod.pyc +0 -0
  16. data/core/site-packages/pre_build/VUKafParserPy/KafParserMod.py +439 -0
  17. data/core/site-packages/pre_build/VUKafParserPy/KafParserMod.pyc +0 -0
  18. data/core/site-packages/pre_build/VUKafParserPy/__init__.py +7 -0
  19. data/core/site-packages/pre_build/VUKafParserPy/__init__.pyc +0 -0
  20. data/core/vendor/src/crfsuite/AUTHORS +1 -0
  21. data/core/vendor/src/crfsuite/COPYING +27 -0
  22. data/core/vendor/src/crfsuite/ChangeLog +103 -0
  23. data/core/vendor/src/crfsuite/INSTALL +236 -0
  24. data/core/vendor/src/crfsuite/Makefile.am +19 -0
  25. data/core/vendor/src/crfsuite/Makefile.in +783 -0
  26. data/core/vendor/src/crfsuite/README +183 -0
  27. data/core/vendor/src/crfsuite/aclocal.m4 +9018 -0
  28. data/core/vendor/src/crfsuite/autogen.sh +38 -0
  29. data/core/vendor/src/crfsuite/compile +143 -0
  30. data/core/vendor/src/crfsuite/config.guess +1502 -0
  31. data/core/vendor/src/crfsuite/config.h.in +198 -0
  32. data/core/vendor/src/crfsuite/config.sub +1714 -0
  33. data/core/vendor/src/crfsuite/configure +14273 -0
  34. data/core/vendor/src/crfsuite/configure.in +149 -0
  35. data/core/vendor/src/crfsuite/crfsuite.sln +42 -0
  36. data/core/vendor/src/crfsuite/depcomp +630 -0
  37. data/core/vendor/src/crfsuite/example/chunking.py +49 -0
  38. data/core/vendor/src/crfsuite/example/crfutils.py +179 -0
  39. data/core/vendor/src/crfsuite/example/ner.py +270 -0
  40. data/core/vendor/src/crfsuite/example/pos.py +78 -0
  41. data/core/vendor/src/crfsuite/example/template.py +88 -0
  42. data/core/vendor/src/crfsuite/frontend/Makefile.am +29 -0
  43. data/core/vendor/src/crfsuite/frontend/Makefile.in +640 -0
  44. data/core/vendor/src/crfsuite/frontend/dump.c +116 -0
  45. data/core/vendor/src/crfsuite/frontend/frontend.vcxproj +129 -0
  46. data/core/vendor/src/crfsuite/frontend/iwa.c +273 -0
  47. data/core/vendor/src/crfsuite/frontend/iwa.h +65 -0
  48. data/core/vendor/src/crfsuite/frontend/learn.c +439 -0
  49. data/core/vendor/src/crfsuite/frontend/main.c +137 -0
  50. data/core/vendor/src/crfsuite/frontend/option.c +93 -0
  51. data/core/vendor/src/crfsuite/frontend/option.h +86 -0
  52. data/core/vendor/src/crfsuite/frontend/readdata.h +38 -0
  53. data/core/vendor/src/crfsuite/frontend/reader.c +136 -0
  54. data/core/vendor/src/crfsuite/frontend/tag.c +427 -0
  55. data/core/vendor/src/crfsuite/genbinary.sh.in +15 -0
  56. data/core/vendor/src/crfsuite/include/Makefile.am +11 -0
  57. data/core/vendor/src/crfsuite/include/Makefile.in +461 -0
  58. data/core/vendor/src/crfsuite/include/crfsuite.h +1063 -0
  59. data/core/vendor/src/crfsuite/include/crfsuite.hpp +555 -0
  60. data/core/vendor/src/crfsuite/include/crfsuite_api.hpp +400 -0
  61. data/core/vendor/src/crfsuite/include/os.h +61 -0
  62. data/core/vendor/src/crfsuite/install-sh +520 -0
  63. data/core/vendor/src/crfsuite/lib/cqdb/COPYING +28 -0
  64. data/core/vendor/src/crfsuite/lib/cqdb/Makefile.am +21 -0
  65. data/core/vendor/src/crfsuite/lib/cqdb/Makefile.in +549 -0
  66. data/core/vendor/src/crfsuite/lib/cqdb/cqdb.vcxproj +86 -0
  67. data/core/vendor/src/crfsuite/lib/cqdb/include/cqdb.h +524 -0
  68. data/core/vendor/src/crfsuite/lib/cqdb/src/cqdb.c +587 -0
  69. data/core/vendor/src/crfsuite/lib/cqdb/src/lookup3.c +976 -0
  70. data/core/vendor/src/crfsuite/lib/crf/Makefile.am +46 -0
  71. data/core/vendor/src/crfsuite/lib/crf/Makefile.in +721 -0
  72. data/core/vendor/src/crfsuite/lib/crf/crf.vcxproj +216 -0
  73. data/core/vendor/src/crfsuite/lib/crf/src/crf1d.h +353 -0
  74. data/core/vendor/src/crfsuite/lib/crf/src/crf1d_context.c +705 -0
  75. data/core/vendor/src/crfsuite/lib/crf/src/crf1d_encode.c +943 -0
  76. data/core/vendor/src/crfsuite/lib/crf/src/crf1d_feature.c +352 -0
  77. data/core/vendor/src/crfsuite/lib/crf/src/crf1d_model.c +994 -0
  78. data/core/vendor/src/crfsuite/lib/crf/src/crf1d_tag.c +550 -0
  79. data/core/vendor/src/crfsuite/lib/crf/src/crfsuite.c +492 -0
  80. data/core/vendor/src/crfsuite/lib/crf/src/crfsuite_internal.h +236 -0
  81. data/core/vendor/src/crfsuite/lib/crf/src/crfsuite_train.c +272 -0
  82. data/core/vendor/src/crfsuite/lib/crf/src/dataset.c +106 -0
  83. data/core/vendor/src/crfsuite/lib/crf/src/dictionary.c +118 -0
  84. data/core/vendor/src/crfsuite/lib/crf/src/holdout.c +80 -0
  85. data/core/vendor/src/crfsuite/lib/crf/src/logging.c +91 -0
  86. data/core/vendor/src/crfsuite/lib/crf/src/logging.h +48 -0
  87. data/core/vendor/src/crfsuite/lib/crf/src/params.c +335 -0
  88. data/core/vendor/src/crfsuite/lib/crf/src/params.h +80 -0
  89. data/core/vendor/src/crfsuite/lib/crf/src/quark.c +172 -0
  90. data/core/vendor/src/crfsuite/lib/crf/src/quark.h +46 -0
  91. data/core/vendor/src/crfsuite/lib/crf/src/rumavl.c +1107 -0
  92. data/core/vendor/src/crfsuite/lib/crf/src/rumavl.h +160 -0
  93. data/core/vendor/src/crfsuite/lib/crf/src/train_arow.c +408 -0
  94. data/core/vendor/src/crfsuite/lib/crf/src/train_averaged_perceptron.c +242 -0
  95. data/core/vendor/src/crfsuite/lib/crf/src/train_l2sgd.c +507 -0
  96. data/core/vendor/src/crfsuite/lib/crf/src/train_lbfgs.c +338 -0
  97. data/core/vendor/src/crfsuite/lib/crf/src/train_passive_aggressive.c +435 -0
  98. data/core/vendor/src/crfsuite/lib/crf/src/vecmath.h +341 -0
  99. data/core/vendor/src/crfsuite/ltmain.sh +8413 -0
  100. data/core/vendor/src/crfsuite/missing +376 -0
  101. data/core/vendor/src/crfsuite/swig/Makefile.am +13 -0
  102. data/core/vendor/src/crfsuite/swig/Makefile.in +365 -0
  103. data/core/vendor/src/crfsuite/swig/crfsuite.cpp +2 -0
  104. data/core/vendor/src/crfsuite/swig/export.i +32 -0
  105. data/core/vendor/src/crfsuite/swig/python/README +92 -0
  106. data/core/vendor/src/crfsuite/swig/python/crfsuite.py +329 -0
  107. data/core/vendor/src/crfsuite/swig/python/export_wrap.cpp +14355 -0
  108. data/core/vendor/src/crfsuite/swig/python/export_wrap.h +63 -0
  109. data/core/vendor/src/crfsuite/swig/python/prepare.sh +9 -0
  110. data/core/vendor/src/crfsuite/swig/python/sample_tag.py +52 -0
  111. data/core/vendor/src/crfsuite/swig/python/sample_train.py +68 -0
  112. data/core/vendor/src/crfsuite/swig/python/setup.py +44 -0
  113. data/core/vendor/src/crfsuite/win32/stdint.h +679 -0
  114. data/core/vendor/src/liblbfgs/AUTHORS +1 -0
  115. data/core/vendor/src/liblbfgs/COPYING +22 -0
  116. data/core/vendor/src/liblbfgs/ChangeLog +120 -0
  117. data/core/vendor/src/liblbfgs/INSTALL +231 -0
  118. data/core/vendor/src/liblbfgs/Makefile.am +10 -0
  119. data/core/vendor/src/liblbfgs/Makefile.in +638 -0
  120. data/core/vendor/src/liblbfgs/NEWS +0 -0
  121. data/core/vendor/src/liblbfgs/README +71 -0
  122. data/core/vendor/src/liblbfgs/aclocal.m4 +6985 -0
  123. data/core/vendor/src/liblbfgs/autogen.sh +38 -0
  124. data/core/vendor/src/liblbfgs/config.guess +1411 -0
  125. data/core/vendor/src/liblbfgs/config.h.in +64 -0
  126. data/core/vendor/src/liblbfgs/config.sub +1500 -0
  127. data/core/vendor/src/liblbfgs/configure +21146 -0
  128. data/core/vendor/src/liblbfgs/configure.in +107 -0
  129. data/core/vendor/src/liblbfgs/depcomp +522 -0
  130. data/core/vendor/src/liblbfgs/include/lbfgs.h +745 -0
  131. data/core/vendor/src/liblbfgs/install-sh +322 -0
  132. data/core/vendor/src/liblbfgs/lbfgs.sln +26 -0
  133. data/core/vendor/src/liblbfgs/lib/Makefile.am +24 -0
  134. data/core/vendor/src/liblbfgs/lib/Makefile.in +499 -0
  135. data/core/vendor/src/liblbfgs/lib/arithmetic_ansi.h +133 -0
  136. data/core/vendor/src/liblbfgs/lib/arithmetic_sse_double.h +294 -0
  137. data/core/vendor/src/liblbfgs/lib/arithmetic_sse_float.h +298 -0
  138. data/core/vendor/src/liblbfgs/lib/lbfgs.c +1371 -0
  139. data/core/vendor/src/liblbfgs/lib/lib.vcxproj +95 -0
  140. data/core/vendor/src/liblbfgs/ltmain.sh +6426 -0
  141. data/core/vendor/src/liblbfgs/missing +353 -0
  142. data/core/vendor/src/liblbfgs/sample/Makefile.am +15 -0
  143. data/core/vendor/src/liblbfgs/sample/Makefile.in +433 -0
  144. data/core/vendor/src/liblbfgs/sample/sample.c +81 -0
  145. data/core/vendor/src/liblbfgs/sample/sample.cpp +126 -0
  146. data/core/vendor/src/liblbfgs/sample/sample.vcxproj +105 -0
  147. data/core/vendor/src/svm_light/LICENSE.txt +59 -0
  148. data/core/vendor/src/svm_light/Makefile +105 -0
  149. data/core/vendor/src/svm_light/kernel.h +40 -0
  150. data/core/vendor/src/svm_light/svm_classify.c +197 -0
  151. data/core/vendor/src/svm_light/svm_common.c +985 -0
  152. data/core/vendor/src/svm_light/svm_common.h +301 -0
  153. data/core/vendor/src/svm_light/svm_hideo.c +1062 -0
  154. data/core/vendor/src/svm_light/svm_learn.c +4147 -0
  155. data/core/vendor/src/svm_light/svm_learn.h +169 -0
  156. data/core/vendor/src/svm_light/svm_learn_main.c +397 -0
  157. data/core/vendor/src/svm_light/svm_loqo.c +211 -0
  158. data/ext/hack/Rakefile +17 -0
  159. data/ext/hack/support.rb +88 -0
  160. data/lib/opener/opinion_detector_basic.rb +91 -0
  161. data/lib/opener/opinion_detector_basic/public/markdown.css +284 -0
  162. data/lib/opener/opinion_detector_basic/server.rb +16 -0
  163. data/lib/opener/opinion_detector_basic/version.rb +5 -0
  164. data/lib/opener/opinion_detector_basic/views/index.erb +97 -0
  165. data/lib/opener/opinion_detector_basic/views/result.erb +15 -0
  166. data/opener-opinion-detector-basic.gemspec +36 -0
  167. data/pre_build_requirements.txt +1 -0
  168. metadata +309 -0
@@ -0,0 +1,46 @@
1
+ /*
2
+ * Quark object.
3
+ *
4
+ * Copyright (c) 2007-2010, Naoaki Okazaki
5
+ * All rights reserved.
6
+ *
7
+ * Redistribution and use in source and binary forms, with or without
8
+ * modification, are permitted provided that the following conditions are met:
9
+ * * Redistributions of source code must retain the above copyright
10
+ * notice, this list of conditions and the following disclaimer.
11
+ * * Redistributions in binary form must reproduce the above copyright
12
+ * notice, this list of conditions and the following disclaimer in the
13
+ * documentation and/or other materials provided with the distribution.
14
+ * * Neither the names of the authors nor the names of its contributors
15
+ * may be used to endorse or promote products derived from this
16
+ * software without specific prior written permission.
17
+ *
18
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
22
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
+ */
30
+
31
+ /* $Id$ */
32
+
33
+ #ifndef __QUARK_H__
34
+ #define __QUARK_H__
35
+
36
+ struct tag_quark;
37
+ typedef struct tag_quark quark_t;
38
+
39
+ quark_t* quark_new();
40
+ void quark_delete(quark_t* qrk);
41
+ int quark_get(quark_t* qrk, const char *str);
42
+ int quark_to_id(quark_t* qrk, const char *str);
43
+ const char *quark_to_string(quark_t* qrk, int qid);
44
+ int quark_num(quark_t* qrk);
45
+
46
+ #endif/*__QUARK_H__*/
@@ -0,0 +1,1107 @@
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
+ }