jk-ferret 0.11.8.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (228) hide show
  1. data/CHANGELOG +24 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README +90 -0
  4. data/RELEASE_CHANGES +137 -0
  5. data/RELEASE_NOTES +60 -0
  6. data/Rakefile +443 -0
  7. data/TODO +109 -0
  8. data/TUTORIAL +231 -0
  9. data/bin/ferret-browser +79 -0
  10. data/ext/BZLIB_blocksort.c +1094 -0
  11. data/ext/BZLIB_bzlib.c +1578 -0
  12. data/ext/BZLIB_compress.c +672 -0
  13. data/ext/BZLIB_crctable.c +104 -0
  14. data/ext/BZLIB_decompress.c +626 -0
  15. data/ext/BZLIB_huffman.c +205 -0
  16. data/ext/BZLIB_randtable.c +84 -0
  17. data/ext/STEMMER_api.c +66 -0
  18. data/ext/STEMMER_libstemmer.c +93 -0
  19. data/ext/STEMMER_stem_ISO_8859_1_danish.c +337 -0
  20. data/ext/STEMMER_stem_ISO_8859_1_dutch.c +624 -0
  21. data/ext/STEMMER_stem_ISO_8859_1_english.c +1117 -0
  22. data/ext/STEMMER_stem_ISO_8859_1_finnish.c +762 -0
  23. data/ext/STEMMER_stem_ISO_8859_1_french.c +1246 -0
  24. data/ext/STEMMER_stem_ISO_8859_1_german.c +503 -0
  25. data/ext/STEMMER_stem_ISO_8859_1_hungarian.c +1230 -0
  26. data/ext/STEMMER_stem_ISO_8859_1_italian.c +1065 -0
  27. data/ext/STEMMER_stem_ISO_8859_1_norwegian.c +297 -0
  28. data/ext/STEMMER_stem_ISO_8859_1_porter.c +749 -0
  29. data/ext/STEMMER_stem_ISO_8859_1_portuguese.c +1017 -0
  30. data/ext/STEMMER_stem_ISO_8859_1_spanish.c +1093 -0
  31. data/ext/STEMMER_stem_ISO_8859_1_swedish.c +307 -0
  32. data/ext/STEMMER_stem_ISO_8859_2_romanian.c +998 -0
  33. data/ext/STEMMER_stem_KOI8_R_russian.c +700 -0
  34. data/ext/STEMMER_stem_UTF_8_danish.c +339 -0
  35. data/ext/STEMMER_stem_UTF_8_dutch.c +634 -0
  36. data/ext/STEMMER_stem_UTF_8_english.c +1125 -0
  37. data/ext/STEMMER_stem_UTF_8_finnish.c +768 -0
  38. data/ext/STEMMER_stem_UTF_8_french.c +1256 -0
  39. data/ext/STEMMER_stem_UTF_8_german.c +509 -0
  40. data/ext/STEMMER_stem_UTF_8_hungarian.c +1234 -0
  41. data/ext/STEMMER_stem_UTF_8_italian.c +1073 -0
  42. data/ext/STEMMER_stem_UTF_8_norwegian.c +299 -0
  43. data/ext/STEMMER_stem_UTF_8_porter.c +755 -0
  44. data/ext/STEMMER_stem_UTF_8_portuguese.c +1023 -0
  45. data/ext/STEMMER_stem_UTF_8_romanian.c +1004 -0
  46. data/ext/STEMMER_stem_UTF_8_russian.c +694 -0
  47. data/ext/STEMMER_stem_UTF_8_spanish.c +1097 -0
  48. data/ext/STEMMER_stem_UTF_8_swedish.c +309 -0
  49. data/ext/STEMMER_stem_UTF_8_turkish.c +2205 -0
  50. data/ext/STEMMER_utilities.c +478 -0
  51. data/ext/analysis.c +1710 -0
  52. data/ext/analysis.h +266 -0
  53. data/ext/api.h +26 -0
  54. data/ext/array.c +125 -0
  55. data/ext/array.h +62 -0
  56. data/ext/bitvector.c +96 -0
  57. data/ext/bitvector.h +594 -0
  58. data/ext/bzlib.h +282 -0
  59. data/ext/bzlib_private.h +503 -0
  60. data/ext/compound_io.c +384 -0
  61. data/ext/config.h +52 -0
  62. data/ext/document.c +159 -0
  63. data/ext/document.h +63 -0
  64. data/ext/except.c +102 -0
  65. data/ext/except.h +176 -0
  66. data/ext/extconf.rb +15 -0
  67. data/ext/ferret.c +416 -0
  68. data/ext/ferret.h +94 -0
  69. data/ext/field_index.c +262 -0
  70. data/ext/field_index.h +52 -0
  71. data/ext/filter.c +157 -0
  72. data/ext/fs_store.c +493 -0
  73. data/ext/global.c +458 -0
  74. data/ext/global.h +302 -0
  75. data/ext/hash.c +524 -0
  76. data/ext/hash.h +515 -0
  77. data/ext/hashset.c +192 -0
  78. data/ext/hashset.h +215 -0
  79. data/ext/header.h +58 -0
  80. data/ext/helper.c +63 -0
  81. data/ext/helper.h +21 -0
  82. data/ext/index.c +6804 -0
  83. data/ext/index.h +935 -0
  84. data/ext/internal.h +1019 -0
  85. data/ext/lang.c +10 -0
  86. data/ext/lang.h +68 -0
  87. data/ext/libstemmer.h +79 -0
  88. data/ext/mempool.c +88 -0
  89. data/ext/mempool.h +43 -0
  90. data/ext/modules.h +190 -0
  91. data/ext/multimapper.c +351 -0
  92. data/ext/multimapper.h +60 -0
  93. data/ext/posh.c +1006 -0
  94. data/ext/posh.h +973 -0
  95. data/ext/priorityqueue.c +149 -0
  96. data/ext/priorityqueue.h +155 -0
  97. data/ext/q_boolean.c +1621 -0
  98. data/ext/q_const_score.c +162 -0
  99. data/ext/q_filtered_query.c +212 -0
  100. data/ext/q_fuzzy.c +280 -0
  101. data/ext/q_match_all.c +149 -0
  102. data/ext/q_multi_term.c +673 -0
  103. data/ext/q_parser.c +3103 -0
  104. data/ext/q_phrase.c +1206 -0
  105. data/ext/q_prefix.c +98 -0
  106. data/ext/q_range.c +682 -0
  107. data/ext/q_span.c +2390 -0
  108. data/ext/q_term.c +337 -0
  109. data/ext/q_wildcard.c +167 -0
  110. data/ext/r_analysis.c +2626 -0
  111. data/ext/r_index.c +3468 -0
  112. data/ext/r_qparser.c +635 -0
  113. data/ext/r_search.c +4490 -0
  114. data/ext/r_store.c +513 -0
  115. data/ext/r_utils.c +1131 -0
  116. data/ext/ram_store.c +476 -0
  117. data/ext/scanner.c +895 -0
  118. data/ext/scanner.h +36 -0
  119. data/ext/scanner_mb.c +6701 -0
  120. data/ext/scanner_utf8.c +4415 -0
  121. data/ext/search.c +1864 -0
  122. data/ext/search.h +953 -0
  123. data/ext/similarity.c +151 -0
  124. data/ext/similarity.h +89 -0
  125. data/ext/sort.c +786 -0
  126. data/ext/stem_ISO_8859_1_danish.h +16 -0
  127. data/ext/stem_ISO_8859_1_dutch.h +16 -0
  128. data/ext/stem_ISO_8859_1_english.h +16 -0
  129. data/ext/stem_ISO_8859_1_finnish.h +16 -0
  130. data/ext/stem_ISO_8859_1_french.h +16 -0
  131. data/ext/stem_ISO_8859_1_german.h +16 -0
  132. data/ext/stem_ISO_8859_1_hungarian.h +16 -0
  133. data/ext/stem_ISO_8859_1_italian.h +16 -0
  134. data/ext/stem_ISO_8859_1_norwegian.h +16 -0
  135. data/ext/stem_ISO_8859_1_porter.h +16 -0
  136. data/ext/stem_ISO_8859_1_portuguese.h +16 -0
  137. data/ext/stem_ISO_8859_1_spanish.h +16 -0
  138. data/ext/stem_ISO_8859_1_swedish.h +16 -0
  139. data/ext/stem_ISO_8859_2_romanian.h +16 -0
  140. data/ext/stem_KOI8_R_russian.h +16 -0
  141. data/ext/stem_UTF_8_danish.h +16 -0
  142. data/ext/stem_UTF_8_dutch.h +16 -0
  143. data/ext/stem_UTF_8_english.h +16 -0
  144. data/ext/stem_UTF_8_finnish.h +16 -0
  145. data/ext/stem_UTF_8_french.h +16 -0
  146. data/ext/stem_UTF_8_german.h +16 -0
  147. data/ext/stem_UTF_8_hungarian.h +16 -0
  148. data/ext/stem_UTF_8_italian.h +16 -0
  149. data/ext/stem_UTF_8_norwegian.h +16 -0
  150. data/ext/stem_UTF_8_porter.h +16 -0
  151. data/ext/stem_UTF_8_portuguese.h +16 -0
  152. data/ext/stem_UTF_8_romanian.h +16 -0
  153. data/ext/stem_UTF_8_russian.h +16 -0
  154. data/ext/stem_UTF_8_spanish.h +16 -0
  155. data/ext/stem_UTF_8_swedish.h +16 -0
  156. data/ext/stem_UTF_8_turkish.h +16 -0
  157. data/ext/stopwords.c +410 -0
  158. data/ext/store.c +698 -0
  159. data/ext/store.h +799 -0
  160. data/ext/symbol.c +10 -0
  161. data/ext/symbol.h +23 -0
  162. data/ext/term_vectors.c +73 -0
  163. data/ext/threading.h +31 -0
  164. data/ext/win32.h +62 -0
  165. data/lib/ferret.rb +30 -0
  166. data/lib/ferret/browser.rb +246 -0
  167. data/lib/ferret/browser/s/global.js +192 -0
  168. data/lib/ferret/browser/s/style.css +148 -0
  169. data/lib/ferret/browser/views/document/list.rhtml +49 -0
  170. data/lib/ferret/browser/views/document/show.rhtml +27 -0
  171. data/lib/ferret/browser/views/error/index.rhtml +7 -0
  172. data/lib/ferret/browser/views/help/index.rhtml +8 -0
  173. data/lib/ferret/browser/views/home/index.rhtml +29 -0
  174. data/lib/ferret/browser/views/layout.rhtml +22 -0
  175. data/lib/ferret/browser/views/term-vector/index.rhtml +4 -0
  176. data/lib/ferret/browser/views/term/index.rhtml +199 -0
  177. data/lib/ferret/browser/views/term/termdocs.rhtml +1 -0
  178. data/lib/ferret/browser/webrick.rb +14 -0
  179. data/lib/ferret/document.rb +130 -0
  180. data/lib/ferret/field_infos.rb +44 -0
  181. data/lib/ferret/field_symbol.rb +87 -0
  182. data/lib/ferret/index.rb +973 -0
  183. data/lib/ferret/number_tools.rb +157 -0
  184. data/lib/ferret/version.rb +3 -0
  185. data/setup.rb +1555 -0
  186. data/test/long_running/largefile/tc_largefile.rb +46 -0
  187. data/test/test_all.rb +5 -0
  188. data/test/test_helper.rb +29 -0
  189. data/test/test_installed.rb +1 -0
  190. data/test/threading/number_to_spoken.rb +132 -0
  191. data/test/threading/thread_safety_index_test.rb +88 -0
  192. data/test/threading/thread_safety_read_write_test.rb +73 -0
  193. data/test/threading/thread_safety_test.rb +133 -0
  194. data/test/unit/analysis/tc_analyzer.rb +550 -0
  195. data/test/unit/analysis/tc_token_stream.rb +653 -0
  196. data/test/unit/index/tc_index.rb +867 -0
  197. data/test/unit/index/tc_index_reader.rb +699 -0
  198. data/test/unit/index/tc_index_writer.rb +447 -0
  199. data/test/unit/index/th_doc.rb +332 -0
  200. data/test/unit/query_parser/tc_query_parser.rb +238 -0
  201. data/test/unit/search/tc_filter.rb +156 -0
  202. data/test/unit/search/tc_fuzzy_query.rb +147 -0
  203. data/test/unit/search/tc_index_searcher.rb +67 -0
  204. data/test/unit/search/tc_multi_searcher.rb +128 -0
  205. data/test/unit/search/tc_multiple_search_requests.rb +58 -0
  206. data/test/unit/search/tc_search_and_sort.rb +179 -0
  207. data/test/unit/search/tc_sort.rb +49 -0
  208. data/test/unit/search/tc_sort_field.rb +27 -0
  209. data/test/unit/search/tc_spans.rb +190 -0
  210. data/test/unit/search/tm_searcher.rb +436 -0
  211. data/test/unit/store/tc_fs_store.rb +115 -0
  212. data/test/unit/store/tc_ram_store.rb +35 -0
  213. data/test/unit/store/tm_store.rb +34 -0
  214. data/test/unit/store/tm_store_lock.rb +68 -0
  215. data/test/unit/tc_document.rb +81 -0
  216. data/test/unit/tc_field_symbol.rb +26 -0
  217. data/test/unit/ts_analysis.rb +2 -0
  218. data/test/unit/ts_index.rb +2 -0
  219. data/test/unit/ts_largefile.rb +4 -0
  220. data/test/unit/ts_query_parser.rb +2 -0
  221. data/test/unit/ts_search.rb +2 -0
  222. data/test/unit/ts_store.rb +2 -0
  223. data/test/unit/ts_utils.rb +2 -0
  224. data/test/unit/utils/tc_bit_vector.rb +295 -0
  225. data/test/unit/utils/tc_number_tools.rb +117 -0
  226. data/test/unit/utils/tc_priority_queue.rb +106 -0
  227. data/test/utils/content_generator.rb +226 -0
  228. metadata +319 -0
data/ext/similarity.c ADDED
@@ -0,0 +1,151 @@
1
+ #include "similarity.h"
2
+ #include "search.h"
3
+ #include "array.h"
4
+ #include "helper.h"
5
+ #include "symbol.h"
6
+ #include <math.h>
7
+ #include <stdlib.h>
8
+ #include <string.h>
9
+ #include "internal.h"
10
+
11
+ /****************************************************************************
12
+ *
13
+ * Term
14
+ *
15
+ ****************************************************************************/
16
+
17
+ Term *term_new(Symbol field, const char *text)
18
+ {
19
+ Term *t = ALLOC(Term);
20
+ t->field = field;
21
+ t->text = estrdup(text);
22
+ return t;
23
+ }
24
+
25
+ void term_destroy(Term *self)
26
+ {
27
+ free(self->text);
28
+ free(self);
29
+ }
30
+
31
+ int term_eq(const void *t1, const void *t2)
32
+ {
33
+ return (strcmp(((Term *)t1)->text, ((Term *)t2)->text)) == 0 &&
34
+ (((Term *)t1)->field == ((Term *)t2)->field);
35
+ }
36
+
37
+ unsigned long term_hash(const void *t)
38
+ {
39
+ return str_hash(((Term *)t)->text) * sym_hash(((Term *)t)->field);
40
+ }
41
+
42
+ /****************************************************************************
43
+ *
44
+ * Similarity
45
+ *
46
+ ****************************************************************************/
47
+
48
+ static float simdef_length_norm(Similarity *s, Symbol field, int num_terms)
49
+ {
50
+ (void)s;
51
+ (void)field;
52
+ return (float)(1.0 / sqrt(num_terms));
53
+ }
54
+
55
+ static float simdef_query_norm(struct Similarity *s, float sum_of_squared_weights)
56
+ {
57
+ (void)s;
58
+ return (float)(1.0 / sqrt(sum_of_squared_weights));
59
+ }
60
+
61
+ static float simdef_tf(struct Similarity *s, float freq)
62
+ {
63
+ (void)s;
64
+ return (float)sqrt(freq);
65
+ }
66
+
67
+ static float simdef_sloppy_freq(struct Similarity *s, int distance)
68
+ {
69
+ (void)s;
70
+ return (float)(1.0 / (double)(distance + 1));
71
+ }
72
+
73
+ static float simdef_idf_term(struct Similarity *s, Symbol field, char *term,
74
+ Searcher *searcher)
75
+ {
76
+ return s->idf(s, searcher->doc_freq(searcher, field, term),
77
+ searcher->max_doc(searcher));
78
+ }
79
+
80
+ static float simdef_idf_phrase(struct Similarity *s, Symbol field,
81
+ PhrasePosition *positions,
82
+ int pp_cnt, Searcher *searcher)
83
+ {
84
+ float idf = 0.0;
85
+ int i, j;
86
+ for (i = 0; i < pp_cnt; i++) {
87
+ char **terms = positions[i].terms;
88
+ for (j = ary_size(terms) - 1; j >= 0; j--) {
89
+ idf += sim_idf_term(s, field, terms[j], searcher);
90
+ }
91
+ }
92
+ return idf;
93
+ }
94
+
95
+ static float simdef_idf(struct Similarity *s, int doc_freq, int num_docs)
96
+ {
97
+ (void)s;
98
+ return (float)(log((float)num_docs/(float)(doc_freq+1)) + 1.0);
99
+ }
100
+
101
+ static float simdef_coord(struct Similarity *s, int overlap, int max_overlap)
102
+ {
103
+ (void)s;
104
+ return (float)((double)overlap / (double)max_overlap);
105
+ }
106
+
107
+ static float simdef_decode_norm(struct Similarity *s, uchar b)
108
+ {
109
+ return s->norm_table[b];
110
+ }
111
+
112
+ static uchar simdef_encode_norm(struct Similarity *s, float f)
113
+ {
114
+ (void)s;
115
+ return float2byte(f);
116
+ }
117
+
118
+ static void simdef_destroy(Similarity *s)
119
+ {
120
+ (void)s;
121
+ /* nothing to do here */
122
+ }
123
+
124
+ static Similarity default_similarity = {
125
+ NULL,
126
+ {0},
127
+ &simdef_length_norm,
128
+ &simdef_query_norm,
129
+ &simdef_tf,
130
+ &simdef_sloppy_freq,
131
+ &simdef_idf_term,
132
+ &simdef_idf_phrase,
133
+ &simdef_idf,
134
+ &simdef_coord,
135
+ &simdef_decode_norm,
136
+ &simdef_encode_norm,
137
+ &simdef_destroy
138
+ };
139
+
140
+ Similarity *sim_create_default()
141
+ {
142
+ int i;
143
+ if (!default_similarity.data) {
144
+ for (i = 0; i < 256; i++) {
145
+ default_similarity.norm_table[i] = byte2float((unsigned char)i);
146
+ }
147
+
148
+ default_similarity.data = &default_similarity;
149
+ }
150
+ return &default_similarity;
151
+ }
data/ext/similarity.h ADDED
@@ -0,0 +1,89 @@
1
+ #ifndef FRT_SIMILARITY_H
2
+ #define FRT_SIMILARITY_H
3
+
4
+ #ifdef __cplusplus
5
+ extern "C" {
6
+ #endif
7
+
8
+ #include "symbol.h"
9
+
10
+ typedef struct FrtSearcher FrtSearcher;
11
+
12
+ /****************************************************************************
13
+ *
14
+ * FrtTerm
15
+ *
16
+ ****************************************************************************/
17
+
18
+ typedef struct FrtTerm
19
+ {
20
+ FrtSymbol field;
21
+ char *text;
22
+ } FrtTerm;
23
+
24
+ extern FrtTerm *frt_term_new(FrtSymbol field, const char *text);
25
+ extern void frt_term_destroy(FrtTerm *self);
26
+ extern int frt_term_eq(const void *t1, const void *t2);
27
+ extern unsigned long frt_term_hash(const void *t);
28
+
29
+ /***************************************************************************
30
+ *
31
+ * FrtPhrasePosition
32
+ *
33
+ ***************************************************************************/
34
+
35
+ typedef struct FrtPhrasePosition
36
+ {
37
+ int pos;
38
+ char **terms;
39
+ } FrtPhrasePosition;
40
+
41
+ /***************************************************************************
42
+ *
43
+ * FrtSimilarity
44
+ *
45
+ ***************************************************************************/
46
+
47
+ typedef struct FrtSimilarity FrtSimilarity;
48
+
49
+ struct FrtSimilarity
50
+ {
51
+ void *data;
52
+ float norm_table[256];
53
+ float (*length_norm)(FrtSimilarity *self, FrtSymbol field, int num_terms);
54
+ float (*query_norm)(FrtSimilarity *self, float sum_of_squared_weights);
55
+ float (*tf)(FrtSimilarity *self, float freq);
56
+ float (*sloppy_freq)(FrtSimilarity *self, int distance);
57
+ float (*idf_term)(FrtSimilarity *self, FrtSymbol field, char *term,
58
+ FrtSearcher *searcher);
59
+ float (*idf_phrase)(FrtSimilarity *self, FrtSymbol field,
60
+ FrtPhrasePosition *positions,
61
+ int pp_cnt, FrtSearcher *searcher);
62
+ float (*idf)(FrtSimilarity *self, int doc_freq, int num_docs);
63
+ float (*coord)(FrtSimilarity *self, int overlap, int max_overlap);
64
+ float (*decode_norm)(FrtSimilarity *self, unsigned char b);
65
+ unsigned char (*encode_norm)(FrtSimilarity *self, float f);
66
+ void (*destroy)(FrtSimilarity *self);
67
+ };
68
+
69
+ #define frt_sim_length_norm(msim, field, num_terms) msim->length_norm(msim, field, num_terms)
70
+ #define frt_sim_query_norm(msim, sosw) msim->query_norm(msim, sosw)
71
+ #define frt_sim_tf(msim, freq) msim->tf(msim, freq)
72
+ #define frt_sim_sloppy_freq(msim, distance) msim->sloppy_freq(msim, distance)
73
+ #define frt_sim_idf_term(msim, field, term, searcher)\
74
+ msim->idf_term(msim, field, term, searcher)
75
+ #define frt_sim_idf_phrase(msim, field, positions, pos_cnt, searcher)\
76
+ msim->idf_phrase(msim, field, positions, pos_cnt, searcher)
77
+ #define frt_sim_idf(msim, doc_freq, num_docs) msim->idf(msim, doc_freq, num_docs)
78
+ #define frt_sim_coord(msim, overlap, max_overlap) msim->coord(msim, overlap, max_overlap)
79
+ #define frt_sim_decode_norm(msim, b) msim->decode_norm(msim, b)
80
+ #define frt_sim_encode_norm(msim, f) msim->encode_norm(msim, f)
81
+ #define frt_sim_destroy(msim) msim->destroy(msim)
82
+
83
+ FrtSimilarity *frt_sim_create_default();
84
+
85
+ #ifdef __cplusplus
86
+ } // extern "C"
87
+ #endif
88
+
89
+ #endif
data/ext/sort.c ADDED
@@ -0,0 +1,786 @@
1
+ #include <string.h>
2
+ #include "search.h"
3
+ #include "index.h"
4
+ #include "field_index.h"
5
+ #include "symbol.h"
6
+ #include "internal.h"
7
+
8
+ /***************************************************************************
9
+ *
10
+ * SortField
11
+ *
12
+ ***************************************************************************/
13
+
14
+ static INLINE SortField *sort_field_alloc(Symbol field,
15
+ SortType type,
16
+ bool reverse,
17
+ int (*compare)(void *index_ptr, Hit *hit1, Hit *hit2),
18
+ void (*get_val)(void *index_ptr, Hit *hit1, Comparable *comparable),
19
+ const FieldIndexClass *field_index_class)
20
+ {
21
+ SortField *self = ALLOC(SortField);
22
+ self->field = field;
23
+ self->type = type;
24
+ self->reverse = reverse;
25
+ self->field_index_class = field_index_class;
26
+ self->compare = compare;
27
+ self->get_val = get_val;
28
+ return self;
29
+ }
30
+
31
+ SortField *sort_field_new(Symbol field, SortType type, bool reverse)
32
+ {
33
+ SortField *sf = NULL;
34
+ switch (type) {
35
+ case SORT_TYPE_SCORE:
36
+ sf = sort_field_score_new(reverse);
37
+ break;
38
+ case SORT_TYPE_DOC:
39
+ sf = sort_field_doc_new(reverse);
40
+ break;
41
+ case SORT_TYPE_BYTE:
42
+ sf = sort_field_byte_new(field, reverse);
43
+ break;
44
+ case SORT_TYPE_INTEGER:
45
+ sf = sort_field_int_new(field, reverse);
46
+ break;
47
+ case SORT_TYPE_FLOAT:
48
+ sf = sort_field_float_new(field, reverse);
49
+ break;
50
+ case SORT_TYPE_STRING:
51
+ sf = sort_field_string_new(field, reverse);
52
+ break;
53
+ case SORT_TYPE_AUTO:
54
+ sf = sort_field_auto_new(field, reverse);
55
+ break;
56
+ }
57
+ return sf;
58
+ }
59
+
60
+ void sort_field_destroy(void *p)
61
+ {
62
+ free(p);
63
+ }
64
+
65
+ /*
66
+ * field:<type>!
67
+ */
68
+ char *sort_field_to_s(SortField *self)
69
+ {
70
+ char *str;
71
+ char *type = NULL;
72
+ switch (self->type) {
73
+ case SORT_TYPE_SCORE:
74
+ type = "<SCORE>";
75
+ break;
76
+ case SORT_TYPE_DOC:
77
+ type = "<DOC>";
78
+ break;
79
+ case SORT_TYPE_BYTE:
80
+ type = "<byte>";
81
+ break;
82
+ case SORT_TYPE_INTEGER:
83
+ type = "<integer>";
84
+ break;
85
+ case SORT_TYPE_FLOAT:
86
+ type = "<float>";
87
+ break;
88
+ case SORT_TYPE_STRING:
89
+ type = "<string>";
90
+ break;
91
+ case SORT_TYPE_AUTO:
92
+ type = "<auto>";
93
+ break;
94
+ }
95
+ if (self->field) {
96
+ str = ALLOC_N(char, 3 + sym_len(self->field) + strlen(type));
97
+ sprintf(str, "%s:%s%s", S(self->field), type, (self->reverse ? "!" : ""));
98
+ }
99
+ else {
100
+ str = ALLOC_N(char, 2 + strlen(type));
101
+ sprintf(str, "%s%s", type, (self->reverse ? "!" : ""));
102
+ }
103
+ return str;
104
+ }
105
+
106
+ /***************************************************************************
107
+ * ScoreSortField
108
+ ***************************************************************************/
109
+
110
+ static void sf_score_get_val(void *index, Hit *hit, Comparable *comparable)
111
+ {
112
+ (void)index;
113
+ comparable->val.f = hit->score;
114
+ }
115
+
116
+ static int sf_score_compare(void *index_ptr, Hit *hit2, Hit *hit1)
117
+ {
118
+ float val1 = hit1->score;
119
+ float val2 = hit2->score;
120
+ (void)index_ptr;
121
+
122
+ if (val1 > val2) return 1;
123
+ else if (val1 < val2) return -1;
124
+ else return 0;
125
+ }
126
+
127
+ SortField *sort_field_score_new(bool reverse)
128
+ {
129
+ return sort_field_alloc(NULL, SORT_TYPE_SCORE, reverse,
130
+ &sf_score_compare, &sf_score_get_val, NULL);
131
+ }
132
+
133
+ const SortField SORT_FIELD_SCORE = {
134
+ NULL, /* field_index_class */
135
+ NULL, /* field */
136
+ SORT_TYPE_SCORE, /* type */
137
+ false, /* reverse */
138
+ &sf_score_compare, /* compare */
139
+ &sf_score_get_val, /* get_val */
140
+ };
141
+
142
+ const SortField SORT_FIELD_SCORE_REV = {
143
+ NULL, /* field_index_class */
144
+ NULL, /* field */
145
+ SORT_TYPE_SCORE, /* type */
146
+ true, /* reverse */
147
+ &sf_score_compare, /* compare */
148
+ &sf_score_get_val, /* get_val */
149
+ };
150
+
151
+ /**************************************************************************
152
+ * DocSortField
153
+ ***************************************************************************/
154
+
155
+ static void sf_doc_get_val(void *index, Hit *hit, Comparable *comparable)
156
+ {
157
+ (void)index;
158
+ comparable->val.l = hit->doc;
159
+ }
160
+
161
+ static int sf_doc_compare(void *index_ptr, Hit *hit1, Hit *hit2)
162
+ {
163
+ int val1 = hit1->doc;
164
+ int val2 = hit2->doc;
165
+ (void)index_ptr;
166
+
167
+ if (val1 > val2) return 1;
168
+ else if (val1 < val2) return -1;
169
+ else return 0;
170
+ }
171
+
172
+ SortField *sort_field_doc_new(bool reverse)
173
+ {
174
+ return sort_field_alloc(NULL, SORT_TYPE_DOC, reverse,
175
+ &sf_doc_compare, &sf_doc_get_val, NULL);
176
+ }
177
+
178
+ const SortField SORT_FIELD_DOC = {
179
+ NULL, /* field_index_class */
180
+ NULL, /* field */
181
+ SORT_TYPE_DOC, /* type */
182
+ false, /* reverse */
183
+ &sf_doc_compare, /* compare */
184
+ &sf_doc_get_val, /* get_val */
185
+ };
186
+
187
+ const SortField SORT_FIELD_DOC_REV = {
188
+ NULL, /* field_index_class */
189
+ NULL, /* field */
190
+ SORT_TYPE_DOC, /* type */
191
+ true, /* reverse */
192
+ &sf_doc_compare, /* compare */
193
+ &sf_doc_get_val, /* get_val */
194
+ };
195
+
196
+ /***************************************************************************
197
+ * ByteSortField
198
+ ***************************************************************************/
199
+
200
+ static void sf_byte_get_val(void *index, Hit *hit, Comparable *comparable)
201
+ {
202
+ comparable->val.l = ((long *)index)[hit->doc];
203
+ }
204
+
205
+ static int sf_byte_compare(void *index, Hit *hit1, Hit *hit2)
206
+ {
207
+ long val1 = ((long *)index)[hit1->doc];
208
+ long val2 = ((long *)index)[hit2->doc];
209
+ if (val1 > val2) return 1;
210
+ else if (val1 < val2) return -1;
211
+ else return 0;
212
+ }
213
+
214
+ SortField *sort_field_byte_new(Symbol field, bool reverse)
215
+ {
216
+ return sort_field_alloc(field, SORT_TYPE_BYTE, reverse,
217
+ &sf_byte_compare, &sf_byte_get_val,
218
+ &BYTE_FIELD_INDEX_CLASS);
219
+ }
220
+
221
+ /***************************************************************************
222
+ * IntegerSortField
223
+ ***************************************************************************/
224
+
225
+ static void sf_int_get_val(void *index, Hit *hit, Comparable *comparable)
226
+ {
227
+ comparable->val.l = ((long *)index)[hit->doc];
228
+ }
229
+
230
+ static int sf_int_compare(void *index, Hit *hit1, Hit *hit2)
231
+ {
232
+ long val1 = ((long *)index)[hit1->doc];
233
+ long val2 = ((long *)index)[hit2->doc];
234
+ if (val1 > val2) return 1;
235
+ else if (val1 < val2) return -1;
236
+ else return 0;
237
+ }
238
+
239
+ SortField *sort_field_int_new(Symbol field, bool reverse)
240
+ {
241
+ return sort_field_alloc(field, SORT_TYPE_INTEGER, reverse,
242
+ &sf_int_compare, &sf_int_get_val,
243
+ &INTEGER_FIELD_INDEX_CLASS);
244
+ }
245
+
246
+ /***************************************************************************
247
+ * FloatSortField
248
+ ***************************************************************************/
249
+
250
+ static void sf_float_get_val(void *index, Hit *hit, Comparable *comparable)
251
+ {
252
+ comparable->val.f = ((float *)index)[hit->doc];
253
+ }
254
+
255
+ static int sf_float_compare(void *index, Hit *hit1, Hit *hit2)
256
+ {
257
+ float val1 = ((float *)index)[hit1->doc];
258
+ float val2 = ((float *)index)[hit2->doc];
259
+ if (val1 > val2) return 1;
260
+ else if (val1 < val2) return -1;
261
+ else return 0;
262
+ }
263
+
264
+ SortField *sort_field_float_new(Symbol field, bool reverse)
265
+ {
266
+ return sort_field_alloc(field, SORT_TYPE_FLOAT, reverse,
267
+ &sf_float_compare, &sf_float_get_val,
268
+ &FLOAT_FIELD_INDEX_CLASS);
269
+ }
270
+
271
+ /***************************************************************************
272
+ * StringSortField
273
+ ***************************************************************************/
274
+
275
+ static void sf_string_get_val(void *index, Hit *hit, Comparable *comparable)
276
+ {
277
+ comparable->val.s
278
+ = ((StringIndex *)index)->values[
279
+ ((StringIndex *)index)->index[hit->doc]];
280
+ }
281
+
282
+ static int sf_string_compare(void *index, Hit *hit1, Hit *hit2)
283
+ {
284
+ char *s1 = ((StringIndex *)index)->values[
285
+ ((StringIndex *)index)->index[hit1->doc]];
286
+ char *s2 = ((StringIndex *)index)->values[
287
+ ((StringIndex *)index)->index[hit2->doc]];
288
+
289
+ if (s1 == NULL) return s2 ? 1 : 0;
290
+ if (s2 == NULL) return -1;
291
+
292
+ #ifdef POSH_OS_WIN32
293
+ return strcmp(s1, s2);
294
+ #else
295
+ return strcoll(s1, s2);
296
+ #endif
297
+
298
+ /*
299
+ * TODO: investigate whether it would be a good idea to presort strings.
300
+ *
301
+ int val1 = index->index[hit1->doc];
302
+ int val2 = index->index[hit2->doc];
303
+ if (val1 > val2) return 1;
304
+ else if (val1 < val2) return -1;
305
+ else return 0;
306
+ */
307
+ }
308
+
309
+ SortField *sort_field_string_new(Symbol field, bool reverse)
310
+ {
311
+ return sort_field_alloc(field, SORT_TYPE_STRING, reverse,
312
+ &sf_string_compare, &sf_string_get_val,
313
+ &STRING_FIELD_INDEX_CLASS);
314
+ }
315
+
316
+ /***************************************************************************
317
+ * AutoSortField
318
+ ***************************************************************************/
319
+
320
+ SortField *sort_field_auto_new(Symbol field, bool reverse)
321
+ {
322
+ return sort_field_alloc(field, SORT_TYPE_AUTO, reverse, NULL, NULL, NULL);
323
+ }
324
+
325
+ /***************************************************************************
326
+ *
327
+ * FieldSortedHitQueue
328
+ *
329
+ ***************************************************************************/
330
+
331
+ /***************************************************************************
332
+ * Comparator
333
+ ***************************************************************************/
334
+
335
+ typedef struct Comparator {
336
+ void *index;
337
+ bool reverse : 1;
338
+ int (*compare)(void *index_ptr, Hit *hit1, Hit *hit2);
339
+ } Comparator;
340
+
341
+ static Comparator *comparator_new(void *index, bool reverse,
342
+ int (*compare)(void *index_ptr, Hit *hit1, Hit *hit2))
343
+ {
344
+ Comparator *self = ALLOC(Comparator);
345
+ self->index = index;
346
+ self->reverse = reverse;
347
+ self->compare = compare;
348
+ return self;
349
+ }
350
+
351
+ /***************************************************************************
352
+ * Sorter
353
+ ***************************************************************************/
354
+
355
+ typedef struct Sorter {
356
+ Comparator **comparators;
357
+ int c_cnt;
358
+ Sort *sort;
359
+ } Sorter;
360
+
361
+ #define SET_AUTO(upper_type, lower_type) \
362
+ sf->type = SORT_TYPE_ ## upper_type;\
363
+ sf->field_index_class = &upper_type ## _FIELD_INDEX_CLASS;\
364
+ sf->compare = sf_ ## lower_type ## _compare;\
365
+ sf->get_val = sf_ ## lower_type ## _get_val
366
+
367
+ static void sort_field_auto_evaluate(SortField *sf, char *text)
368
+ {
369
+ int int_val;
370
+ float float_val;
371
+ int text_len = 0, scan_len = 0;
372
+
373
+ text_len = (int)strlen(text);
374
+ sscanf(text, "%d%n", &int_val, &scan_len);
375
+ if (scan_len == text_len) {
376
+ SET_AUTO(INTEGER, int);
377
+ } else {
378
+ sscanf(text, "%f%n", &float_val, &scan_len);
379
+ if (scan_len == text_len) {
380
+ SET_AUTO(FLOAT, float);
381
+ } else {
382
+ SET_AUTO(STRING, string);
383
+ }
384
+ }
385
+ }
386
+ /*
387
+ static INLINE void set_auto(SortField *sf,
388
+ SortType type,
389
+ const FieldIndexClass *field_index_class,
390
+ int (*compare)(void *index_ptr, Hit *hit1, Hit *hit2),
391
+ void (*get_val)(void *index_ptr, Hit *hit1, Comparable *comparable))
392
+ {
393
+ sf->type = type;
394
+ sf->field_index_class = field_index_class;
395
+ sf->compare = compare;
396
+ sf->get_val = get_val;
397
+ }
398
+
399
+ static void sort_field_auto_evaluate(SortField *sf, char *text)
400
+ {
401
+ int int_val;
402
+ float float_val;
403
+ int text_len = 0, scan_len = 0;
404
+
405
+ text_len = (int)strlen(text);
406
+ sscanf(text, "%d%n", &int_val, &scan_len);
407
+ if (scan_len == text_len) {
408
+ set_auto(sf, SORT_TYPE_INTEGER, &INTEGER_FIELD_INDEX_CLASS,
409
+ sf_int_compare, sf_int_get_val);
410
+ } else {
411
+ sscanf(text, "%f%n", &float_val, &scan_len);
412
+ if (scan_len == text_len) {
413
+ set_auto(sf, SORT_TYPE_FLOAT, &FLOAT_FIELD_INDEX_CLASS,
414
+ sf_float_compare, sf_float_get_val);
415
+ } else {
416
+ set_auto(sf, SORT_TYPE_STRING, &STRING_FIELD_INDEX_CLASS,
417
+ sf_string_compare, sf_string_get_val);
418
+ }
419
+ }
420
+ }
421
+ */
422
+
423
+ static Comparator *sorter_get_comparator(SortField *sf, IndexReader *ir)
424
+ {
425
+ void *index = NULL;
426
+
427
+ if (sf->type > SORT_TYPE_DOC) {
428
+ FieldIndex *field_index = NULL;
429
+ if (sf->type == SORT_TYPE_AUTO) {
430
+ TermEnum *te = ir_terms(ir, sf->field);
431
+ if (!te->next(te) && (ir->num_docs(ir) > 0)) {
432
+ RAISE(ARG_ERROR,
433
+ "Cannot sort by field \"%s\" as there are no terms "
434
+ "in that field in the index.", S(sf->field));
435
+ }
436
+ sort_field_auto_evaluate(sf, te->curr_term);
437
+ te->close(te);
438
+ }
439
+ mutex_lock(&ir->field_index_mutex);
440
+ field_index = field_index_get(ir, sf->field, sf->field_index_class);
441
+ mutex_unlock(&ir->field_index_mutex);
442
+ index = field_index->index;
443
+ }
444
+ return comparator_new(index, sf->reverse, sf->compare);
445
+ }
446
+
447
+ static void sorter_destroy(Sorter *self)
448
+ {
449
+ int i;
450
+
451
+ for (i = 0; i < self->c_cnt; i++) {
452
+ free(self->comparators[i]);
453
+ }
454
+ free(self->comparators);
455
+ free(self);
456
+ }
457
+
458
+ static Sorter *sorter_new(Sort *sort)
459
+ {
460
+ Sorter *self = ALLOC(Sorter);
461
+ self->c_cnt = sort->size;
462
+ self->comparators = ALLOC_AND_ZERO_N(Comparator *, self->c_cnt);
463
+ self->sort = sort;
464
+ return self;
465
+ }
466
+
467
+ /***************************************************************************
468
+ * FieldSortedHitQueue
469
+ ***************************************************************************/
470
+
471
+ static bool fshq_less_than(const void *hit1, const void *hit2)
472
+ {
473
+ int cmp = 0;
474
+ printf("Whoops, shouldn't call this.\n");
475
+ if (cmp != 0) {
476
+ return cmp;
477
+ } else {
478
+ return ((Hit *)hit1)->score < ((Hit *)hit2)->score;
479
+ }
480
+ }
481
+
482
+ static INLINE bool fshq_lt(Sorter *sorter, Hit *hit1, Hit *hit2)
483
+ {
484
+ Comparator *comp;
485
+ int diff = 0, i;
486
+ for (i = 0; i < sorter->c_cnt && diff == 0; i++) {
487
+ comp = sorter->comparators[i];
488
+ if (comp->reverse) {
489
+ diff = comp->compare(comp->index, hit2, hit1);
490
+ } else {
491
+ diff = comp->compare(comp->index, hit1, hit2);
492
+ }
493
+ }
494
+
495
+ if (diff != 0) {
496
+ return diff > 0;
497
+ } else {
498
+ return hit1->doc > hit2->doc;
499
+ }
500
+ }
501
+
502
+ void fshq_pq_down(PriorityQueue *pq)
503
+ {
504
+ register int i = 1;
505
+ register int j = 2; /* i << 1; */
506
+ register int k = 3; /* j + 1; */
507
+ Hit **heap = (Hit **)pq->heap;
508
+ Hit *node = heap[i]; /* save top node */
509
+ Sorter *sorter = (Sorter *)heap[0];
510
+
511
+ if ((k <= pq->size) && fshq_lt(sorter, heap[k], heap[j])) {
512
+ j = k;
513
+ }
514
+
515
+ while ((j <= pq->size) && fshq_lt(sorter, heap[j], node)) {
516
+ heap[i] = heap[j]; /* shift up child */
517
+ i = j;
518
+ j = i << 1;
519
+ k = j + 1;
520
+ if ((k <= pq->size) && fshq_lt(sorter, heap[k], heap[j])) {
521
+ j = k;
522
+ }
523
+ }
524
+ heap[i] = node;
525
+ }
526
+
527
+ Hit *fshq_pq_pop(PriorityQueue *pq)
528
+ {
529
+ if (pq->size > 0) {
530
+ Hit *hit = (Hit *)pq->heap[1]; /* save first value */
531
+ pq->heap[1] = pq->heap[pq->size]; /* move last to first */
532
+ pq->heap[pq->size] = NULL;
533
+ pq->size--;
534
+ fshq_pq_down(pq); /* adjust heap */
535
+ return hit;
536
+ } else {
537
+ return NULL;
538
+ }
539
+ }
540
+
541
+ static INLINE void fshq_pq_up(PriorityQueue *pq)
542
+ {
543
+ Hit **heap = (Hit **)pq->heap;
544
+ Hit *node;
545
+ int i = pq->size;
546
+ int j = i >> 1;
547
+ Sorter *sorter = (Sorter *)heap[0];
548
+ node = heap[i];
549
+
550
+ while ((j > 0) && fshq_lt(sorter, node, heap[j])) {
551
+ heap[i] = heap[j];
552
+ i = j;
553
+ j = j >> 1;
554
+ }
555
+ heap[i] = node;
556
+ }
557
+
558
+ void fshq_pq_insert(PriorityQueue *pq, Hit *hit)
559
+ {
560
+ if (pq->size < pq->capa) {
561
+ Hit *new_hit = ALLOC(Hit);
562
+ memcpy(new_hit, hit, sizeof(Hit));
563
+ pq->size++;
564
+ if (pq->size >= pq->mem_capa) {
565
+ pq->mem_capa <<= 1;
566
+ REALLOC_N(pq->heap, void *, pq->mem_capa);
567
+ }
568
+ pq->heap[pq->size] = new_hit;
569
+ fshq_pq_up(pq);
570
+ } else if (pq->size > 0
571
+ && fshq_lt((Sorter *)pq->heap[0], (Hit *)pq->heap[1], hit)) {
572
+ memcpy(pq->heap[1], hit, sizeof(Hit));
573
+ fshq_pq_down(pq);
574
+ }
575
+ }
576
+
577
+ void fshq_pq_destroy(PriorityQueue *self)
578
+ {
579
+ sorter_destroy((Sorter *)self->heap[0]);
580
+ pq_destroy(self);
581
+ }
582
+
583
+ PriorityQueue *fshq_pq_new(int size, Sort *sort, IndexReader *ir)
584
+ {
585
+ PriorityQueue *self = pq_new(size, &fshq_less_than, &free);
586
+ int i;
587
+ Sorter *sorter = sorter_new(sort);
588
+ SortField *sf;
589
+
590
+ for (i = 0; i < sort->size; i++) {
591
+ sf = sort->sort_fields[i];
592
+ sorter->comparators[i] = sorter_get_comparator(sf, ir);
593
+ }
594
+ self->heap[0] = sorter;
595
+
596
+ return self;
597
+ }
598
+
599
+ Hit *fshq_pq_pop_fd(PriorityQueue *pq)
600
+ {
601
+ if (pq->size <= 0) {
602
+ return NULL;
603
+ }
604
+ else {
605
+ int j;
606
+ Sorter *sorter = (Sorter *)pq->heap[0];
607
+ const int cmp_cnt = sorter->c_cnt;
608
+ SortField **sort_fields = sorter->sort->sort_fields;
609
+ Hit *hit = (Hit *)pq->heap[1]; /* save first value */
610
+ FieldDoc *field_doc;
611
+ Comparable *comparables;
612
+ Comparator **comparators = sorter->comparators;
613
+ pq->heap[1] = pq->heap[pq->size]; /* move last to first */
614
+ pq->heap[pq->size] = NULL;
615
+ pq->size--;
616
+ fshq_pq_down(pq); /* adjust heap */
617
+
618
+ field_doc = (FieldDoc *)emalloc(sizeof(FieldDoc)
619
+ + sizeof(Comparable) * cmp_cnt);
620
+ comparables = field_doc->comparables;
621
+ memcpy(field_doc, hit, sizeof(Hit));
622
+ field_doc->size = cmp_cnt;
623
+
624
+ for (j = 0; j < cmp_cnt; j++) {
625
+ SortField *sf = sort_fields[j];
626
+ Comparator *comparator = comparators[j];
627
+ sf->get_val(comparator->index, hit, &(comparables[j]));
628
+ comparables[j].type = sf->type;
629
+ comparables[j].reverse = comparator->reverse;
630
+ }
631
+ free(hit);
632
+ return (Hit *)field_doc;
633
+ }
634
+ }
635
+
636
+ /***************************************************************************
637
+ * FieldDoc
638
+ ***************************************************************************/
639
+
640
+ void fd_destroy(FieldDoc *fd)
641
+ {
642
+ free(fd);
643
+ }
644
+
645
+ /***************************************************************************
646
+ * FieldDocSortedHitQueue
647
+ ***************************************************************************/
648
+
649
+ bool fdshq_lt(FieldDoc *fd1, FieldDoc *fd2)
650
+ {
651
+ int c = 0, i;
652
+ Comparable *cmps1 = fd1->comparables;
653
+ Comparable *cmps2 = fd2->comparables;
654
+
655
+ for (i = 0; i < fd1->size && c == 0; i++) {
656
+ int type = cmps1[i].type;
657
+ switch (type) {
658
+ case SORT_TYPE_SCORE:
659
+ if (cmps1[i].val.f < cmps2[i].val.f) c = 1;
660
+ if (cmps1[i].val.f > cmps2[i].val.f) c = -1;
661
+ break;
662
+ case SORT_TYPE_FLOAT:
663
+ if (cmps1[i].val.f > cmps2[i].val.f) c = 1;
664
+ if (cmps1[i].val.f < cmps2[i].val.f) c = -1;
665
+ break;
666
+ case SORT_TYPE_DOC:
667
+ if (fd1->hit.doc > fd2->hit.doc) c = 1;
668
+ if (fd1->hit.doc < fd2->hit.doc) c = -1;
669
+ break;
670
+ case SORT_TYPE_INTEGER:
671
+ if (cmps1[i].val.l > cmps2[i].val.l) c = 1;
672
+ if (cmps1[i].val.l < cmps2[i].val.l) c = -1;
673
+ break;
674
+ case SORT_TYPE_BYTE:
675
+ if (cmps1[i].val.l > cmps2[i].val.l) c = 1;
676
+ if (cmps1[i].val.l < cmps2[i].val.l) c = -1;
677
+ break;
678
+ case SORT_TYPE_STRING:
679
+ do {
680
+ char *s1 = cmps1[i].val.s;
681
+ char *s2 = cmps2[i].val.s;
682
+ if (s1 == NULL) c = s2 ? 1 : 0;
683
+ else if (s2 == NULL) c = -1;
684
+ #ifdef POSH_OS_WIN32
685
+ else c = strcmp(s1, s2);
686
+ #else
687
+ else c = strcoll(s1, s2);
688
+ #endif
689
+ } while (0);
690
+ break;
691
+ default:
692
+ RAISE(ARG_ERROR, "Unknown sort type: %d.", type);
693
+ break;
694
+ }
695
+ if (cmps1[i].reverse) {
696
+ c = -c;
697
+ }
698
+ }
699
+ if (c == 0) {
700
+ return fd1->hit.doc > fd2->hit.doc;
701
+ }
702
+ else {
703
+ return c > 0;
704
+ }
705
+ }
706
+
707
+ /***************************************************************************
708
+ *
709
+ * Sort
710
+ *
711
+ ***************************************************************************/
712
+
713
+ #define SORT_INIT_SIZE 4
714
+
715
+ Sort *sort_new()
716
+ {
717
+ Sort *self = ALLOC(Sort);
718
+ self->size = 0;
719
+ self->capa = SORT_INIT_SIZE;
720
+ self->sort_fields = ALLOC_N(SortField *, SORT_INIT_SIZE);
721
+ self->destroy_all = true;
722
+ self->start = 0;
723
+
724
+ return self;
725
+ }
726
+
727
+ void sort_clear(Sort *self)
728
+ {
729
+ int i;
730
+ if (self->destroy_all) {
731
+ for (i = 0; i < self->size; i++) {
732
+ sort_field_destroy(self->sort_fields[i]);
733
+ }
734
+ }
735
+ self->size = 0;
736
+ }
737
+
738
+ void sort_destroy(void *p)
739
+ {
740
+ Sort *self = (Sort *)p;
741
+ sort_clear(self);
742
+ free(self->sort_fields);
743
+ free(self);
744
+ }
745
+
746
+ void sort_add_sort_field(Sort *self, SortField *sf)
747
+ {
748
+ if (self->size == self->capa) {
749
+ self->capa <<= 1;
750
+ REALLOC_N(self->sort_fields, SortField *, self->capa);
751
+ }
752
+
753
+ self->sort_fields[self->size] = sf;
754
+ self->size++;
755
+ }
756
+
757
+ char *sort_to_s(Sort *self)
758
+ {
759
+ int i, len = 20;
760
+ char *s;
761
+ char *str;
762
+ char **sf_strs = ALLOC_N(char *, self->size);
763
+
764
+ for (i = 0; i < self->size; i++) {
765
+ sf_strs[i] = s = sort_field_to_s(self->sort_fields[i]);
766
+ len += (int)strlen(s) + 2;
767
+ }
768
+
769
+ str = ALLOC_N(char, len);
770
+ s = "Sort[";
771
+ len = (int)strlen(s);
772
+ memcpy(str, s, len);
773
+
774
+ s = str + len;
775
+ for (i = 0; i < self->size; i++) {
776
+ s += sprintf(s, "%s, ", sf_strs[i]);
777
+ free(sf_strs[i]);
778
+ }
779
+ free(sf_strs);
780
+
781
+ if (self->size > 0) {
782
+ s -= 2;
783
+ }
784
+ sprintf(s, "]");
785
+ return str;
786
+ }