3 * Library to deal with pinyin.
5 * Copyright (C) 2011 Peng Wu <alexepico@gmail.com>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 #include "chewing_large_table.h"
24 #include "pinyin_phrase2.h"
25 #include "pinyin_parser2.h"
28 /* internal class definition */
31 class ChewingLengthIndexLevel{
34 GArray * m_chewing_array_indexes;
37 /* constructor/destructor */
38 ChewingLengthIndexLevel();
39 ~ChewingLengthIndexLevel();
41 /* load/store method */
42 bool load(MemoryChunk * chunk, table_offset_t offset, table_offset_t end);
43 bool store(MemoryChunk * new_chunk, table_offset_t offset,
44 table_offset_t & end);
47 int search(pinyin_option_t options, int phrase_length,
48 /* in */ ChewingKey keys[],
49 /* out */ PhraseIndexRanges ranges) const;
51 /* add/remove index method */
52 int add_index(int phrase_length, /* in */ ChewingKey keys[],
53 /* in */ phrase_token_t token);
54 int remove_index(int phrase_length, /* in */ ChewingKey keys[],
55 /* in */ phrase_token_t token);
57 /* get length method */
58 int get_length() const;
62 template<size_t phrase_length>
63 class ChewingArrayIndexLevel{
65 typedef PinyinIndexItem2<phrase_length> IndexItem;
70 /* compress consecutive tokens */
71 int convert(pinyin_option_t options,
75 PhraseIndexRanges ranges) const;
78 /* load/store method */
79 bool load(MemoryChunk * chunk, table_offset_t offset, table_offset_t end);
80 bool store(MemoryChunk * new_chunk, table_offset_t offset,
81 table_offset_t & end);
84 int search(pinyin_option_t options, /* in */ChewingKey keys[],
85 /* out */ PhraseIndexRanges ranges) const;
87 /* add/remove index method */
88 int add_index(/* in */ ChewingKey keys[], /* in */ phrase_token_t token);
89 int remove_index(/* in */ ChewingKey keys[],
90 /* in */ phrase_token_t token);
92 /* get length method */
93 int get_length() const;
99 using namespace pinyin;
101 /* class implementation */
103 ChewingBitmapIndexLevel::ChewingBitmapIndexLevel(pinyin_option_t options)
104 : m_options(options) {
105 memset(m_chewing_length_indexes, 0, sizeof(m_chewing_length_indexes));
108 void ChewingBitmapIndexLevel::reset() {
109 for (int k = CHEWING_ZERO_INITIAL; k < CHEWING_NUMBER_OF_INITIALS; ++k)
110 for (int l = CHEWING_ZERO_MIDDLE; l < CHEWING_NUMBER_OF_MIDDLES; ++l)
111 for (int m = CHEWING_ZERO_FINAL; m < CHEWING_NUMBER_OF_FINALS; ++m)
112 for (int n = CHEWING_ZERO_TONE; n < CHEWING_NUMBER_OF_TONES;
114 ChewingLengthIndexLevel * & length_array =
115 m_chewing_length_indexes[k][l][m][n];
125 int ChewingBitmapIndexLevel::search(int phrase_length,
126 /* in */ ChewingKey keys[],
127 /* out */ PhraseIndexRanges ranges) const {
128 assert(phrase_length > 0);
129 return initial_level_search(phrase_length, keys, ranges);
132 int ChewingBitmapIndexLevel::initial_level_search (int phrase_length,
133 /* in */ ChewingKey keys[], /* out */ PhraseIndexRanges ranges) const {
136 #define MATCH(AMBIGUITY, ORIGIN, ANOTHER) case ORIGIN: \
138 result |= middle_and_final_level_search(ORIGIN, phrase_length, \
140 if (m_options & AMBIGUITY) { \
141 result |= middle_and_final_level_search(ANOTHER, \
148 /* deal with ambiguities */
149 int result = SEARCH_NONE;
150 const ChewingKey & first_key = keys[0];
152 switch(first_key.m_initial) {
153 MATCH(PINYIN_AMB_C_CH, CHEWING_C, CHEWING_CH);
154 MATCH(PINYIN_AMB_C_CH, CHEWING_CH, CHEWING_C);
155 MATCH(PINYIN_AMB_Z_ZH, CHEWING_Z, CHEWING_ZH);
156 MATCH(PINYIN_AMB_Z_ZH, CHEWING_ZH, CHEWING_Z);
157 MATCH(PINYIN_AMB_S_SH, CHEWING_S, CHEWING_SH);
158 MATCH(PINYIN_AMB_S_SH, CHEWING_SH, CHEWING_S);
159 MATCH(PINYIN_AMB_L_R, CHEWING_R, CHEWING_L);
160 MATCH(PINYIN_AMB_L_N, CHEWING_N, CHEWING_L);
161 MATCH(PINYIN_AMB_F_H, CHEWING_F, CHEWING_H);
162 MATCH(PINYIN_AMB_F_H, CHEWING_H, CHEWING_F);
163 MATCH(PINYIN_AMB_G_K, CHEWING_G, CHEWING_K);
164 MATCH(PINYIN_AMB_G_K, CHEWING_K, CHEWING_G);
168 result |= middle_and_final_level_search
169 (CHEWING_L, phrase_length, keys, ranges);
171 if (m_options & PINYIN_AMB_L_N)
172 result |= middle_and_final_level_search
173 (CHEWING_N, phrase_length, keys,ranges);
175 if (m_options & PINYIN_AMB_L_R)
176 result |= middle_and_final_level_search
177 (CHEWING_R, phrase_length, keys, ranges);
182 result |= middle_and_final_level_search
183 ((ChewingInitial) first_key.m_initial,
184 phrase_length, keys, ranges);
193 int ChewingBitmapIndexLevel::middle_and_final_level_search
194 (ChewingInitial initial, int phrase_length, /* in */ ChewingKey keys[],
195 /* out */ PhraseIndexRanges ranges) const {
198 #define MATCH(AMBIGUITY, ORIGIN, ANOTHER) case ORIGIN: \
200 result = tone_level_search \
202 ORIGIN, phrase_length, keys, ranges); \
203 if (m_options & AMBIGUITY) { \
204 result |= tone_level_search \
206 ANOTHER, phrase_length, keys, ranges); \
211 int result = SEARCH_NONE;
212 const ChewingKey & first_key = keys[0];
213 const ChewingMiddle middle = (ChewingMiddle)first_key.m_middle;
215 switch(first_key.m_final) {
216 case CHEWING_ZERO_FINAL:
218 if (middle == CHEWING_ZERO_MIDDLE) { /* in-complete pinyin */
219 if (!(m_options & PINYIN_INCOMPLETE))
221 for (int m = CHEWING_ZERO_MIDDLE;
222 m < CHEWING_NUMBER_OF_MIDDLES; ++m)
223 for (int n = CHEWING_ZERO_FINAL;
224 n < CHEWING_NUMBER_OF_FINALS; ++n) {
226 if (CHEWING_ZERO_MIDDLE == m &&
227 CHEWING_ZERO_FINAL == n)
230 result |= tone_level_search
231 (initial, (ChewingMiddle) m, (ChewingFinal) n,
232 phrase_length, keys, ranges);
235 } else { /* normal pinyin */
236 result |= tone_level_search
237 (initial, middle, CHEWING_ZERO_FINAL,
238 phrase_length, keys, ranges);
243 MATCH(PINYIN_AMB_AN_ANG, CHEWING_AN, CHEWING_ANG);
244 MATCH(PINYIN_AMB_AN_ANG, CHEWING_ANG, CHEWING_AN);
245 MATCH(PINYIN_AMB_EN_ENG, CHEWING_EN, CHEWING_ENG);
246 MATCH(PINYIN_AMB_EN_ENG, CHEWING_ENG, CHEWING_EN);
247 MATCH(PINYIN_AMB_IN_ING, PINYIN_IN, PINYIN_ING);
248 MATCH(PINYIN_AMB_IN_ING, PINYIN_ING, PINYIN_IN);
252 result |= tone_level_search
253 (initial, middle, (ChewingFinal) first_key.m_final,
254 phrase_length, keys, ranges);
263 int ChewingBitmapIndexLevel::tone_level_search
264 (ChewingInitial initial, ChewingMiddle middle, ChewingFinal final,
265 int phrase_length, /* in */ ChewingKey keys[],
266 /* out */ PhraseIndexRanges ranges) const {
268 int result = SEARCH_NONE;
269 const ChewingKey & first_key = keys[0];
271 switch (first_key.m_tone) {
272 case CHEWING_ZERO_TONE:
274 /* deal with zero tone in chewing large table. */
275 for (int i = CHEWING_ZERO_TONE; i < CHEWING_NUMBER_OF_TONES; ++i) {
276 ChewingLengthIndexLevel * phrases =
277 m_chewing_length_indexes
278 [initial][middle][final][(ChewingTone)i];
280 result |= phrases->search
281 (m_options, phrase_length - 1, keys + 1, ranges);
287 ChewingLengthIndexLevel * phrases =
288 m_chewing_length_indexes
289 [initial][middle][final][CHEWING_ZERO_TONE];
291 result |= phrases->search
292 (m_options, phrase_length - 1, keys + 1, ranges);
294 phrases = m_chewing_length_indexes
295 [initial][middle][final][(ChewingTone) first_key.m_tone];
297 result |= phrases->search
298 (m_options, phrase_length - 1, keys + 1, ranges);
306 ChewingLengthIndexLevel::ChewingLengthIndexLevel() {
307 m_chewing_array_indexes = g_array_new(FALSE, TRUE, sizeof(void *));
310 ChewingLengthIndexLevel::~ChewingLengthIndexLevel() {
311 #define CASE(len) case len: \
313 ChewingArrayIndexLevel<len> * & array = g_array_index \
314 (m_chewing_array_indexes, ChewingArrayIndexLevel<len> *, len); \
321 for (guint i = 0; i < m_chewing_array_indexes->len; ++i) {
344 g_array_free(m_chewing_array_indexes, TRUE);
345 m_chewing_array_indexes = NULL;
349 int ChewingLengthIndexLevel::search(pinyin_option_t options, int phrase_length,
350 /* in */ ChewingKey keys[],
351 /* out */ PhraseIndexRanges ranges) const {
352 int result = SEARCH_NONE;
353 if (m_chewing_array_indexes->len < phrase_length + 1)
355 if (m_chewing_array_indexes->len > phrase_length + 1)
356 result |= SEARCH_CONTINUED;
358 #define CASE(len) case len: \
360 ChewingArrayIndexLevel<len> * & array = g_array_index \
361 (m_chewing_array_indexes, ChewingArrayIndexLevel<len> *, len); \
364 result |= array->search(options, keys, ranges); \
368 switch (phrase_length) {
393 template<size_t phrase_length>
394 int ChewingArrayIndexLevel<phrase_length>::search
395 (pinyin_option_t options, /* in */ChewingKey keys[],
396 /* out */ PhraseIndexRanges ranges) const {
397 IndexItem * chunk_begin = NULL, * chunk_end = NULL;
398 chunk_begin = (IndexItem *) m_chunk.begin();
399 chunk_end = (IndexItem *) m_chunk.end();
402 ChewingKey left_keys[phrase_length], right_keys[phrase_length];
403 compute_lower_value2(options, keys, left_keys, phrase_length);
404 compute_upper_value2(options, keys, right_keys, phrase_length);
406 IndexItem left(left_keys, -1), right(right_keys, -1);
408 IndexItem * begin = std_lite::lower_bound
409 (chunk_begin, chunk_end, left,
410 phrase_exact_less_than2<phrase_length>);
411 IndexItem * end = std_lite::upper_bound
412 (chunk_begin, chunk_end, right,
413 phrase_exact_less_than2<phrase_length>);
415 return convert(options, keys, begin, end, ranges);
418 /* compress consecutive tokens */
419 template<size_t phrase_length>
420 int ChewingArrayIndexLevel<phrase_length>::convert
421 (pinyin_option_t options, ChewingKey keys[],
422 IndexItem * begin, IndexItem * end,
423 PhraseIndexRanges ranges) const {
424 IndexItem * iter = NULL;
425 PhraseIndexRange cursor;
426 GArray * head, * cursor_head = NULL;
428 int result = SEARCH_NONE;
429 /* TODO: check the below code */
430 cursor.m_range_begin = null_token; cursor.m_range_end = null_token;
431 for (iter = begin; iter != end; ++iter) {
432 if (0 != pinyin_compare_with_ambiguities2
433 (options, keys, iter->m_keys, phrase_length))
436 phrase_token_t token = iter->m_token;
437 head = ranges[PHRASE_INDEX_LIBRARY_INDEX(token)];
443 if (null_token == cursor.m_range_begin) {
444 cursor.m_range_begin = token;
445 cursor.m_range_end = token + 1;
447 } else if (cursor.m_range_end == token &&
448 PHRASE_INDEX_LIBRARY_INDEX(cursor.m_range_begin) ==
449 PHRASE_INDEX_LIBRARY_INDEX(token)) {
450 ++cursor.m_range_end;
452 g_array_append_val(cursor_head, cursor);
453 cursor.m_range_begin = token; cursor.m_range_end = token + 1;
458 if (null_token == cursor.m_range_begin)
461 g_array_append_val(cursor_head, cursor);
466 /* add/remove index method */
468 int ChewingBitmapIndexLevel::add_index(int phrase_length,
469 /* in */ ChewingKey keys[],
470 /* in */ phrase_token_t token) {
471 const ChewingKey first_key = keys[0];
472 ChewingLengthIndexLevel * & length_array = m_chewing_length_indexes
473 [first_key.m_initial][first_key.m_middle]
474 [first_key.m_final][first_key.m_tone];
476 if (NULL == length_array) {
477 length_array = new ChewingLengthIndexLevel();
480 return length_array->add_index(phrase_length - 1, keys + 1, token);
483 int ChewingBitmapIndexLevel::remove_index(int phrase_length,
484 /* in */ ChewingKey keys[],
485 /* in */ phrase_token_t token) {
486 const ChewingKey first_key = keys[0];
487 ChewingLengthIndexLevel * & length_array = m_chewing_length_indexes
488 [first_key.m_initial][first_key.m_middle]
489 [first_key.m_final][first_key.m_tone];
491 if (NULL == length_array)
492 return ERROR_REMOVE_ITEM_DONOT_EXISTS;
494 int retval = length_array->remove_index(phrase_length - 1, keys + 1, token);
496 /* remove empty array. */
497 if (0 == length_array->get_length()) {
505 int ChewingLengthIndexLevel::add_index(int phrase_length,
506 /* in */ ChewingKey keys[],
507 /* in */ phrase_token_t token) {
508 if (!(phrase_length + 1 < MAX_PHRASE_LENGTH))
509 return ERROR_PHRASE_TOO_LONG;
511 if (m_chewing_array_indexes->len <= phrase_length)
512 g_array_set_size(m_chewing_array_indexes, phrase_length + 1);
514 #define CASE(len) case len: \
516 ChewingArrayIndexLevel<len> * & array = g_array_index \
517 (m_chewing_array_indexes, \
518 ChewingArrayIndexLevel<len> *, len); \
520 array = new ChewingArrayIndexLevel<len>; \
521 return array->add_index(keys, token); \
524 switch(phrase_length) {
548 int ChewingLengthIndexLevel::remove_index(int phrase_length,
549 /* in */ ChewingKey keys[],
550 /* in */ phrase_token_t token) {
551 if (!(phrase_length + 1 < MAX_PHRASE_LENGTH))
552 return ERROR_PHRASE_TOO_LONG;
554 if (m_chewing_array_indexes->len <= phrase_length)
555 return ERROR_REMOVE_ITEM_DONOT_EXISTS;
557 #define CASE(len) case len: \
559 ChewingArrayIndexLevel<len> * & array = g_array_index \
560 (m_chewing_array_indexes, \
561 ChewingArrayIndexLevel<len> *, len); \
563 return ERROR_REMOVE_ITEM_DONOT_EXISTS; \
564 int retval = array->remove_index(keys, token); \
566 /* remove empty array. */ \
567 if (0 == array->get_length()) { \
571 /* shrink self array. */ \
572 g_array_set_size(m_chewing_array_indexes, \
578 switch (phrase_length) {
602 template<size_t phrase_length>
603 int ChewingArrayIndexLevel<phrase_length>::add_index
604 (/* in */ ChewingKey keys[], /* in */ phrase_token_t token) {
605 IndexItem * begin, * end;
607 IndexItem add_elem(keys, token);
608 begin = (IndexItem *) m_chunk.begin();
609 end = (IndexItem *) m_chunk.end();
611 std_lite::pair<IndexItem *, IndexItem *> range;
612 range = std_lite::equal_range
613 (begin, end, add_elem, phrase_exact_less_than2<phrase_length>);
615 IndexItem * cur_elem;
616 for (cur_elem = range.first;
617 cur_elem != range.second; ++cur_elem) {
618 if (cur_elem->m_token == token)
619 return ERROR_INSERT_ITEM_EXISTS;
620 if (cur_elem->m_token > token)
624 int offset = (cur_elem - begin) * sizeof(IndexItem);
625 m_chunk.insert_content(offset, &add_elem, sizeof(IndexItem));
629 template<size_t phrase_length>
630 int ChewingArrayIndexLevel<phrase_length>::remove_index
631 (/* in */ ChewingKey keys[], /* in */ phrase_token_t token) {
632 IndexItem * begin, * end;
634 IndexItem remove_elem(keys, token);
635 begin = (IndexItem *) m_chunk.begin();
636 end = (IndexItem *) m_chunk.end();
638 std_lite::pair<IndexItem *, IndexItem *> range;
639 range = std_lite::equal_range
640 (begin, end, remove_elem, phrase_exact_less_than2<phrase_length>);
642 IndexItem * cur_elem;
643 for (cur_elem = range.first;
644 cur_elem != range.second; ++cur_elem) {
645 if (cur_elem->m_token == token)
649 if (cur_elem == range.second)
650 return ERROR_REMOVE_ITEM_DONOT_EXISTS;
652 int offset = (cur_elem - begin) * sizeof(IndexItem);
653 m_chunk.remove_content(offset, sizeof(IndexItem));
658 /* load text method */
659 bool ChewingLargeTable::load_text(FILE * infile) {
662 phrase_token_t token;
665 while (!feof(infile)) {
666 fscanf(infile, "%s", pinyin);
667 fscanf(infile, "%s", phrase);
668 fscanf(infile, "%u", &token);
669 fscanf(infile, "%ld", &freq);
674 glong len = g_utf8_strlen(phrase, -1);
676 FullPinyinParser2 parser;
677 ChewingKeyVector keys;
678 ChewingKeyRestVector key_rests;
680 keys = g_array_new(FALSE, FALSE, sizeof(ChewingKey));
681 key_rests = g_array_new(FALSE, FALSE, sizeof(ChewingKeyRest));
683 pinyin_option_t options = USE_TONE;
684 parser.parse(options, keys, key_rests, pinyin, strlen(pinyin));
686 if (len != keys->len) {
687 fprintf(stderr, "ChewingLargeTable::load_text:%s\t%s\t%u\t%ld\n",
688 pinyin, phrase, token, freq);
692 add_index(keys->len, (ChewingKey *)keys->data, token);
694 g_array_free(keys, TRUE);
695 g_array_free(key_rests, TRUE);
702 /* load/store method */
704 bool ChewingBitmapIndexLevel::load(MemoryChunk * chunk, table_offset_t offset,
705 table_offset_t end) {
707 char * begin = (char *) chunk->begin();
708 table_offset_t phrase_begin, phrase_end;
709 table_offset_t * index = (table_offset_t *) (begin + offset);
712 for (int k = 0; k < CHEWING_NUMBER_OF_INITIALS; ++k)
713 for (int l = 0; l < CHEWING_NUMBER_OF_MIDDLES; ++l)
714 for (int m = 0; m < CHEWING_NUMBER_OF_FINALS; ++m)
715 for (int n = 0; n < CHEWING_NUMBER_OF_TONES; ++n) {
716 phrase_begin = phrase_end;
720 if (phrase_begin == phrase_end) /* null pointer */
723 /* after reset() all phrases are null pointer. */
724 ChewingLengthIndexLevel * phrases = new ChewingLengthIndexLevel;
725 m_chewing_length_indexes[k][l][m][n] = phrases;
727 phrases->load(chunk, phrase_begin, phrase_end - 1);
728 assert(phrase_end <= end);
729 assert(*(begin + phrase_end - 1) == c_separate);
732 offset += (CHEWING_NUMBER_OF_INITIALS * CHEWING_NUMBER_OF_MIDDLES * CHEWING_NUMBER_OF_FINALS * CHEWING_NUMBER_OF_TONES + 1) * sizeof(table_offset_t);
733 assert(c_separate == *(begin + offset));
737 bool ChewingBitmapIndexLevel::store(MemoryChunk * new_chunk,
738 table_offset_t offset,
739 table_offset_t & end) {
740 table_offset_t phrase_end;
741 table_offset_t index = offset;
742 offset += (CHEWING_NUMBER_OF_INITIALS * CHEWING_NUMBER_OF_MIDDLES * CHEWING_NUMBER_OF_FINALS * CHEWING_NUMBER_OF_TONES + 1) * sizeof(table_offset_t);
745 new_chunk->set_content(offset, &c_separate, sizeof(char));
746 offset += sizeof(char);
747 new_chunk->set_content(index, &offset, sizeof(table_offset_t));
748 index += sizeof(table_offset_t);
750 for (int k = 0; k < CHEWING_NUMBER_OF_INITIALS; ++k)
751 for (int l = 0; l < CHEWING_NUMBER_OF_MIDDLES; ++l)
752 for (int m = 0; m < CHEWING_NUMBER_OF_FINALS; ++m)
753 for (int n = 0; n < CHEWING_NUMBER_OF_TONES; ++n) {
754 ChewingLengthIndexLevel * phrases =
755 m_chewing_length_indexes[k][l][m][n];
757 if (NULL == phrases) { /* null pointer */
758 new_chunk->set_content(index, &offset,
759 sizeof(table_offset_t));
760 index += sizeof(table_offset_t);
765 phrases->store(new_chunk, offset, phrase_end);
769 new_chunk->set_content(offset, &c_separate, sizeof(char));
770 offset += sizeof(char);
771 new_chunk->set_content(index, &offset,
772 sizeof(table_offset_t));
773 index += sizeof(table_offset_t);
780 bool ChewingLengthIndexLevel::load(MemoryChunk * chunk, table_offset_t offset,
781 table_offset_t end) {
782 char * begin = (char *) chunk->begin();
783 guint32 nindex = *((guint32 *)(begin + offset)); /* number of index */
784 table_offset_t * index = (table_offset_t *)
785 (begin + offset + sizeof(guint32));
787 table_offset_t phrase_begin, phrase_end = *index;
788 g_array_set_size(m_chewing_array_indexes, 0);
789 for (guint32 i = 0; i < nindex; ++i) {
790 phrase_begin = phrase_end;
794 if (phrase_begin == phrase_end) {
796 g_array_append_val(m_chewing_array_indexes, null);
800 #define CASE(len) case len: \
802 ChewingArrayIndexLevel<len> * phrase = \
803 new ChewingArrayIndexLevel<len>; \
804 phrase->load(chunk, phrase_begin, phrase_end - 1); \
805 assert(*(begin + phrase_end - 1) == c_separate); \
806 assert(phrase_end <= end); \
807 g_array_append_val(m_chewing_array_indexes, phrase); \
836 offset += sizeof(guint32) + (nindex + 1) * sizeof(table_offset_t);
837 assert(c_separate == *(begin + offset));
841 bool ChewingLengthIndexLevel::store(MemoryChunk * new_chunk,
842 table_offset_t offset,
843 table_offset_t & end) {
844 guint32 nindex = m_chewing_array_indexes->len; /* number of index */
845 new_chunk->set_content(offset, &nindex, sizeof(guint32));
846 table_offset_t index = offset + sizeof(guint32);
848 offset += sizeof(guint32) + (nindex + 1) * sizeof(table_offset_t);
849 new_chunk->set_content(offset, &c_separate, sizeof(char));
850 offset += sizeof(char);
851 new_chunk->set_content(index, &offset, sizeof(table_offset_t));
852 index += sizeof(table_offset_t);
854 table_offset_t phrase_end;
855 for (guint32 i = 0; i < nindex; ++i) {
856 #define CASE(len) case len: \
858 ChewingArrayIndexLevel<len> * phrase = g_array_index \
859 (m_chewing_array_indexes, ChewingArrayIndexLevel<len> *, len); \
860 if (NULL == phrase) { \
861 new_chunk->set_content \
862 (index, &offset, sizeof(table_offset_t)); \
863 index += sizeof(table_offset_t); \
866 phrase->store(new_chunk, offset, phrase_end); \
867 offset = phrase_end; \
894 new_chunk->set_content(offset, &c_separate, sizeof(char));
895 offset += sizeof(char);
896 new_chunk->set_content(index, &offset, sizeof(table_offset_t));
897 index += sizeof(table_offset_t);
904 template<size_t phrase_length>
905 bool ChewingArrayIndexLevel<phrase_length>::
906 load(MemoryChunk * chunk, table_offset_t offset, table_offset_t end) {
907 char * begin = (char *) chunk->begin();
908 m_chunk.set_chunk(begin + offset, end - offset, NULL);
912 template<size_t phrase_length>
913 bool ChewingArrayIndexLevel<phrase_length>::
914 store(MemoryChunk * new_chunk, table_offset_t offset, table_offset_t & end) {
915 new_chunk->set_content(offset, m_chunk.begin(), m_chunk.size());
916 end = offset + m_chunk.size();
921 /* get length method */
923 int ChewingLengthIndexLevel::get_length() const {
924 int length = m_chewing_array_indexes->len;
926 /* trim trailing zero. */
927 for (int i = length - 1; i >= 0; --i) {
928 void * array = g_array_index(m_chewing_array_indexes, void *, i);
939 template<size_t phrase_length>
940 int ChewingArrayIndexLevel<phrase_length>::get_length() const {
941 IndexItem * chunk_begin = NULL, * chunk_end = NULL;
942 chunk_begin = (IndexItem *) m_chunk.begin();
943 chunk_end = (IndexItem *) m_chunk.end();
945 return chunk_end - chunk_begin;