OSDN Git Service

a01962b8e72e06f18d530d06eab0e412a2790d75
[bbk/bchanl.git] / src / subjectlist.c
1 /*
2  * subjectlist.c
3  *
4  * Copyright (c) 2011 project bchan
5  *
6  * This software is provided 'as-is', without any express or implied
7  * warranty. In no event will the authors be held liable for any damages
8  * arising from the use of this software.
9  *
10  * Permission is granted to anyone to use this software for any purpose,
11  * including commercial applications, and to alter it and redistribute it
12  * freely, subject to the following restrictions:
13  *
14  * 1. The origin of this software must not be misrepresented; you must not
15  *    claim that you wrote the original software. If you use this software
16  *    in a product, an acknowledgment in the product documentation would be
17  *    appreciated but is not required.
18  *
19  * 2. Altered source versions must be plainly marked as such, and must not be
20  *    misrepresented as being the original software.
21  *
22  * 3. This notice may not be removed or altered from any source
23  *    distribution.
24  *
25  */
26
27 #include        <basic.h>
28 #include        <bstdio.h>
29 #include        <bstdlib.h>
30 #include        <bstring.h>
31 #include        <tstring.h>
32
33 #include    "subjectlist.h"
34 #include    "subjectparser.h"
35 #include    "array.h"
36
37 #ifdef BCHANL_CONFIG_DEBUG
38 # define DP(arg) printf arg
39 # define DP_ER(msg, err) printf("%s (%d/%x)\n", msg, err>>16, err)
40 #else
41 # define DP(arg) /**/
42 # define DP_ER(msg, err) /**/
43 #endif
44
45 struct sbjtlist_tuple_t_ {
46         sbjtparser_thread_t *parser_thread;
47         W index; /* by subject.txt */
48         W resnum;
49         STIME since;
50         DOUBLE vigor;
51 };
52
53 struct sbjtlist_originarray_t_ {
54         arraybase_t base;
55 };
56 typedef struct sbjtlist_originarray_t_ sbjtlist_originarray_t;
57
58 struct sbjtlist_sortedarray_t_ {
59         arraybase_t base;
60 };
61 typedef struct sbjtlist_sortedarray_t_ sbjtlist_sortedarray_t;
62
63 struct sbjtlist_t_ {
64         sbjtlist_originarray_t origin;
65         sbjtlist_sortedarray_t sorted;
66         W sortby;
67 };
68
69 struct sbjtlist_iterator_t_ {
70         Bool descending;
71         W i;
72         sbjtlist_sortedarray_t *array;
73 };
74
75 EXPORT VOID sbjtlist_tuple_gettitle(sbjtlist_tuple_t *tuple, TC **str, W *len)
76 {
77         sbjtparser_thread_gettitlestr(tuple->parser_thread, str, len);
78 }
79
80 EXPORT VOID sbjtlist_tuple_getthreadnumberstr(sbjtlist_tuple_t *tuple, UB **str, W *len)
81 {
82         *str = tuple->parser_thread->number;
83         *len = tuple->parser_thread->number_len;
84 }
85
86 EXPORT VOID sbjtlist_tuple_getnumber(sbjtlist_tuple_t *tuple, W *num)
87 {
88         *num = tuple->index + 1;
89 }
90
91 EXPORT VOID sbjtlist_tuple_getresnumber(sbjtlist_tuple_t *tuple, W *num)
92 {
93         *num = tuple->resnum;
94 }
95
96 EXPORT VOID sbjtlist_tuple_getresnumberstr(sbjtlist_tuple_t *tuple, TC **str, W *len)
97 {
98         sbjtparser_thread_getresnumstr(tuple->parser_thread, str, len);
99 }
100
101 EXPORT VOID sbjtlist_tuple_getsinceSTIME(sbjtlist_tuple_t *tuple, STIME *since)
102 {
103         *since = tuple->since;
104 }
105
106 EXPORT VOID sbjtlist_tuple_getsince(sbjtlist_tuple_t *tuple, DATE_TIM *since)
107 {
108         STIME tim;
109         sbjtlist_tuple_getsinceSTIME(tuple, &tim);
110         get_tod(since, tim, 0);
111 }
112
113 EXPORT VOID sbjtlist_tuple_getvigor(sbjtlist_tuple_t *tuple, W *vigor)
114 {
115         *vigor = tuple->vigor * 10;
116 }
117
118 LOCAL W sbjtlist_tuple_compare_resnumber(sbjtlist_tuple_t *t1, sbjtlist_tuple_t *t2)
119 {
120         W n1, n2;
121         sbjtlist_tuple_getresnumber(t1, &n1);
122         sbjtlist_tuple_getresnumber(t2, &n2);
123         if (n1 > n2) {
124                 return 1;
125         }
126         if (n1 < n2) {
127                 return -1;
128         }
129         return 0;
130 }
131
132 LOCAL W sbjtlist_tuple_compare_vigor(sbjtlist_tuple_t *t1, sbjtlist_tuple_t *t2)
133 {
134         if (t1->vigor > t2->vigor) {
135                 return 1;
136         }
137         if (t1->vigor < t2->vigor) {
138                 return -1;
139         }
140         return 0;
141 }
142
143 LOCAL W sbjtlist_tuple_initialize(sbjtlist_tuple_t *tuple, sbjtparser_thread_t *parser_thread, W index, STIME current)
144 {
145         W since_u, len;
146         TC *str;
147
148         tuple->parser_thread = parser_thread;
149         tuple->index = index;
150
151         since_u = atoi(tuple->parser_thread->number);
152         tuple->since = since_u - 473385600;
153
154         sbjtparser_thread_getresnumstr(tuple->parser_thread, &str, &len);
155         tuple->resnum = tc_atoi(str + 2);
156
157         tuple->vigor = (DOUBLE)tuple->resnum * 60.0 * 60.0 * 24.0 / (DOUBLE)(current - tuple->since); /* res per day */
158
159         return 0;
160 }
161
162 LOCAL VOID sbjtlist_tuple_finalize(sbjtlist_tuple_t *tuple)
163 {
164         sbjtparser_thread_delete(tuple->parser_thread);
165 }
166
167 /**/
168
169 LOCAL W sbjtlist_originarray_append(sbjtlist_originarray_t *array, sbjtparser_thread_t *parser_thread, STIME current)
170 {
171         sbjtlist_tuple_t tuple;
172         W err;
173
174         err = sbjtlist_tuple_initialize(&tuple, parser_thread, arraybase_length(&array->base), current);
175         if (err < 0) {
176                 return err;
177         }
178
179         return arraybase_appendunit(&array->base, &tuple);
180 }
181
182 LOCAL Bool sbjtlist_originarray_getbyindex(sbjtlist_originarray_t *array, W i, sbjtlist_tuple_t **tuple)
183 {
184         return arraybase_getunitbyindex(&array->base, i, (VP*)tuple);
185 }
186
187 LOCAL VOID sbjtlist_originarray_truncate(sbjtlist_originarray_t *array, W newlength)
188 {
189         arraybase_truncate(&array->base, newlength);
190 }
191
192 LOCAL W sbjtlist_originarray_length(sbjtlist_originarray_t *array)
193 {
194         return arraybase_length(&array->base);
195 }
196
197 LOCAL W sbjtlist_originarray_initialize(sbjtlist_originarray_t *array)
198 {
199         return arraybase_initialize(&array->base, sizeof(sbjtlist_tuple_t), 512);
200 }
201
202 LOCAL VOID sbjtlist_originarray_finalize(sbjtlist_originarray_t *array)
203 {
204         arraybase_finalize(&array->base);
205 }
206
207 LOCAL W sbjtlist_sortedarray_append(sbjtlist_sortedarray_t *array, sbjtlist_tuple_t *tuple)
208 {
209         return arraybase_appendunit(&array->base, &tuple);
210 }
211
212 LOCAL Bool sbjtlist_sortedarray_getbyindex(sbjtlist_sortedarray_t *array, W index, sbjtlist_tuple_t **tuple)
213 {
214         Bool ret;
215         VP p;
216         ret = arraybase_getunitbyindex(&array->base, index, &p);
217         if (ret == False) {
218                 return ret;
219         }
220         *tuple = *((sbjtlist_tuple_t**)p);
221         return True;
222 }
223
224 LOCAL VOID sbjtlist_sortedarray_truncate(sbjtlist_sortedarray_t *array, W newlength)
225 {
226         arraybase_truncate(&array->base, newlength);
227 }
228
229 LOCAL W sbjtlist_sortedarray_length(sbjtlist_sortedarray_t *array)
230 {
231         return arraybase_length(&array->base);
232 }
233
234 LOCAL W sbjtlist_sortedarray_initialize(sbjtlist_sortedarray_t *array)
235 {
236         return arraybase_initialize(&array->base, sizeof(sbjtlist_tuple_t*), 512);
237 }
238
239 LOCAL VOID sbjtlist_sortedarray_finalize(sbjtlist_sortedarray_t *array)
240 {
241         arraybase_finalize(&array->base);
242 }
243
244 /**/
245
246 EXPORT W sbjtlist_appendthread(sbjtlist_t *list, sbjtparser_thread_t *parser_thread, STIME current)
247 {
248         return sbjtlist_originarray_append(&list->origin, parser_thread, current);
249 }
250
251 LOCAL Bool sbjtlist_checkfilterwordexist(TC *title, W title_len, TC *filterword, W filterword_len)
252 {
253         Bool found = False;
254         TC *cur;
255         TC ch;
256         W cmp;
257
258         cur = title;
259         ch = filterword[0];
260         for (;;) {
261                 cur = tc_strchr(cur, ch);
262                 if (cur == NULL) {
263                         break;
264                 }
265                 if (cur > title + title_len) {
266                         break;
267                 }
268                 cmp = tc_strncmp(cur, filterword, filterword_len);
269                 if (cmp == 0) {
270                         found = True;
271                         break;
272                 }
273                 cur++;
274         }
275
276         return found;
277 }
278
279 LOCAL W sbjtlist_copyarraywithfilter(sbjtlist_t *list, TC *filterword, W filterword_len)
280 {
281         W i, len, err, title_len;
282         TC *title;
283         Bool found, exist;
284         sbjtlist_tuple_t *tuple;
285
286         len = sbjtlist_originarray_length(&list->origin);
287         if (filterword != NULL) {
288                 for (i = 0; i < len; i++) {
289                         found = sbjtlist_originarray_getbyindex(&list->origin, i, &tuple);
290                         if (found == False) {
291                                 break;
292                         }
293                         sbjtlist_tuple_gettitle(tuple, &title, &title_len);
294                         exist = sbjtlist_checkfilterwordexist(title, title_len, filterword, filterword_len);
295                         if (exist == False) {
296                                 continue;
297                         }
298                         err = sbjtlist_sortedarray_append(&list->sorted, tuple);
299                         if (err < 0) {
300                                 return err;
301                         }
302                 }
303         } else {
304                 for (i = 0; i < len; i++) {
305                         found = sbjtlist_originarray_getbyindex(&list->origin, i, &tuple);
306                         if (found == False) {
307                                 break;
308                         }
309                         err = sbjtlist_sortedarray_append(&list->sorted, tuple);
310                         if (err < 0) {
311                                 return err;
312                         }
313                 }
314         }
315
316         return 0;
317 }
318
319 LOCAL W sbjtlist_sort_compare(sbjtlist_tuple_t *t1, sbjtlist_tuple_t *t2, W by)
320 {
321         if (by == SBJTLIST_SORTBY_SINCE) {
322                 return strcmp(t1->parser_thread->number, t2->parser_thread->number);
323         }
324         if (by == SBJTLIST_SORTBY_RES) {
325                 return sbjtlist_tuple_compare_resnumber(t1, t2);
326         }
327         if (by == SBJTLIST_SORTBY_VIGOR) {
328                 return sbjtlist_tuple_compare_vigor(t1, t2);
329         }
330         /* SBJTLIST_SORTBY_NUMBER */
331         if (t1->index > t2->index) {
332                 return 1;
333         }
334         if (t1->index < t2->index) {
335                 return -1;
336         }
337         return 0;
338 }
339
340 LOCAL VOID sbjtlist_sort_swap(sbjtlist_tuple_t *t1, sbjtlist_tuple_t *t2)
341 {
342         sbjtlist_tuple_t t;
343
344         memcpy(&t, t1, sizeof(sbjtlist_tuple_t));
345         memcpy(t1, t2, sizeof(sbjtlist_tuple_t));
346         memcpy(t2, &t, sizeof(sbjtlist_tuple_t));
347 }
348
349 LOCAL VOID sbjtlist_sortedarray_combsort(sbjtlist_sortedarray_t *array, W by)
350 {
351         W h, swaps, i, len, result;
352         sbjtlist_tuple_t *tuple_i, *tuple_i_h;
353
354         len = sbjtlist_sortedarray_length(array);
355         if (len <= 1) {
356                 return;
357         }
358         h = len * 10 / 13;
359
360         for (;;) {
361                 swaps = 0;
362                 for (i = 0; i + h < len; ++i) {
363                         sbjtlist_sortedarray_getbyindex(array, i, &tuple_i);
364                         sbjtlist_sortedarray_getbyindex(array, i + h, &tuple_i_h);
365                         result = sbjtlist_sort_compare(tuple_i, tuple_i_h, by);
366                         if (result > 0) {
367                                 sbjtlist_sort_swap(tuple_i, tuple_i_h);
368                                 ++swaps;
369                         }
370                 }
371                 if (h == 1) {
372                         if (swaps == 0) {
373                                 break;
374                         }
375                 } else {
376                         h = h * 10 / 13;
377                 }
378         }
379 }
380
381 EXPORT W sbjtlist_sort(sbjtlist_t *list, W by, TC *filterword, W filterword_len)
382 {
383         W err;
384
385         sbjtlist_sortedarray_truncate(&list->sorted, 0);
386
387         err = sbjtlist_copyarraywithfilter(list, filterword, filterword_len);
388         if (err < 0) {
389                 return err;
390         }
391         sbjtlist_sortedarray_combsort(&list->sorted, by);
392
393         return 0;
394 }
395
396 EXPORT VOID sbjtlist_clear(sbjtlist_t *list)
397 {
398         W i, len;
399         Bool found;
400         sbjtlist_tuple_t *tuple;
401
402         len = sbjtlist_originarray_length(&list->origin);
403         for (i = 0; i < len; i++) {
404                 found = sbjtlist_originarray_getbyindex(&list->origin, i, &tuple);
405                 if (found == True) {
406                         sbjtlist_tuple_finalize(tuple);
407                 }
408         }
409         sbjtlist_originarray_truncate(&list->origin, 0);
410         sbjtlist_sortedarray_truncate(&list->sorted, 0);
411 }
412
413 LOCAL sbjtlist_iterator_t* sbjtlist_iterator_new(Bool descending, sbjtlist_t *target)
414 {
415         sbjtlist_iterator_t *iter;
416
417         iter = malloc(sizeof(sbjtlist_iterator_t));
418         if (iter == NULL) {
419                 return NULL;
420         }
421         iter->descending = descending;
422         if (descending == True) {
423                 iter->i = sbjtlist_sortedarray_length(&target->sorted) - 1;
424         } else {
425                 iter->i = 0;
426         }
427         iter->array = &target->sorted;
428
429         return iter;
430 }
431
432 LOCAL VOID sbjtlist_iterator_delete(sbjtlist_iterator_t *iter)
433 {
434         free(iter);
435 }
436
437 EXPORT Bool sbjtlist_iterator_next(sbjtlist_iterator_t *iter, sbjtlist_tuple_t **item)
438 {
439         Bool found;
440
441         found = sbjtlist_sortedarray_getbyindex(iter->array, iter->i, item);
442         if (found == False) {
443                 return False;
444         }
445
446         if (iter->descending == True) {
447                 iter->i--;
448         } else {
449                 iter->i++;
450         }
451
452         return True;
453 }
454
455 EXPORT sbjtlist_iterator_t* sbjtlist_startread(sbjtlist_t *list, Bool descending)
456 {
457         return sbjtlist_iterator_new(descending, list);
458 }
459
460 EXPORT VOID sbjtlist_endread(sbjtlist_t *list, sbjtlist_iterator_t *iter)
461 {
462         return sbjtlist_iterator_delete(iter);
463 }
464
465 EXPORT sbjtlist_t* sbjtlist_new()
466 {
467         sbjtlist_t *list;
468         W err;
469
470         list = malloc(sizeof(sbjtlist_t));
471         if (list == NULL) {
472                 return NULL;
473         }
474         err = sbjtlist_originarray_initialize(&list->origin);
475         if (err < 0) {
476                 free(list);
477                 return NULL;
478         }
479         err = sbjtlist_sortedarray_initialize(&list->sorted);
480         if (err < 0) {
481                 sbjtlist_originarray_finalize(&list->origin);
482                 free(list);
483                 return NULL;
484         }
485         list->sortby = SBJTLIST_SORTBY_NUMBER;
486
487         return list;
488 }
489
490 EXPORT VOID sbjtlist_delete(sbjtlist_t *list)
491 {
492         sbjtlist_clear(list);
493         sbjtlist_sortedarray_finalize(&list->sorted);
494         sbjtlist_originarray_finalize(&list->origin);
495         free(list);
496 }