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);
59 template<int phrase_length>
60 class ChewingArrayIndexLevel{
62 typedef PinyinIndexItem2<phrase_length> IndexItem;
67 /* compress consecutive tokens */
68 int convert(pinyin_option_t options,
72 PhraseIndexRanges ranges) const;
75 /* load/store method */
76 bool load(MemoryChunk * chunk, table_offset_t offset, table_offset_t end);
77 bool store(MemoryChunk * new_chunk, table_offset_t offset,
78 table_offset_t & end);
81 int search(pinyin_option_t options, /* in */ChewingKey keys[],
82 /* out */ PhraseIndexRanges ranges) const;
84 /* add/remove index method */
85 int add_index(/* in */ ChewingKey keys[], /* in */ phrase_token_t token);
86 int remove_index(/* in */ ChewingKey keys[],
87 /* in */ phrase_token_t token);
93 using namespace pinyin;
95 /* class implementation */
97 ChewingBitmapIndexLevel::ChewingBitmapIndexLevel(pinyin_option_t options)
98 : m_options(options) {
99 memset(m_chewing_length_indexes, 0, sizeof(m_chewing_length_indexes));
102 void ChewingBitmapIndexLevel::reset() {
103 for (int k = CHEWING_ZERO_INITIAL; k < CHEWING_NUMBER_OF_INITIALS; ++k)
104 for (int l = CHEWING_ZERO_MIDDLE; l < CHEWING_NUMBER_OF_MIDDLES; ++l)
105 for (int m = CHEWING_ZERO_FINAL; m < CHEWING_NUMBER_OF_FINALS; ++m)
106 for (int n = CHEWING_ZERO_TONE; n < CHEWING_NUMBER_OF_TONES;
108 ChewingLengthIndexLevel * & length_array =
109 m_chewing_length_indexes[k][l][m][n];
119 int ChewingBitmapIndexLevel::search(int phrase_length,
120 /* in */ ChewingKey keys[],
121 /* out */ PhraseIndexRanges ranges) const {
122 assert(phrase_length > 0);
123 return initial_level_search(phrase_length, keys, ranges);
126 int ChewingBitmapIndexLevel::initial_level_search (int phrase_length,
127 /* in */ ChewingKey keys[], /* out */ PhraseIndexRanges ranges) const {
130 #define MATCH(AMBIGUITY, ORIGIN, ANOTHER) case ORIGIN: \
132 result |= middle_and_final_level_search(ORIGIN, phrase_length, \
134 if (m_options & AMBIGUITY) { \
135 result |= middle_and_final_level_search(ANOTHER, \
142 /* deal with ambiguities */
143 int result = SEARCH_NONE;
144 const ChewingKey & first_key = keys[0];
146 switch(first_key.m_initial) {
147 MATCH(PINYIN_AMB_C_CH, CHEWING_C, CHEWING_CH);
148 MATCH(PINYIN_AMB_C_CH, CHEWING_CH, CHEWING_C);
149 MATCH(PINYIN_AMB_Z_ZH, CHEWING_Z, CHEWING_ZH);
150 MATCH(PINYIN_AMB_Z_ZH, CHEWING_ZH, CHEWING_Z);
151 MATCH(PINYIN_AMB_S_SH, CHEWING_S, CHEWING_SH);
152 MATCH(PINYIN_AMB_S_SH, CHEWING_SH, CHEWING_S);
153 MATCH(PINYIN_AMB_L_R, CHEWING_R, CHEWING_L);
154 MATCH(PINYIN_AMB_L_N, CHEWING_N, CHEWING_L);
155 MATCH(PINYIN_AMB_F_H, CHEWING_F, CHEWING_H);
156 MATCH(PINYIN_AMB_F_H, CHEWING_H, CHEWING_F);
157 MATCH(PINYIN_AMB_G_K, CHEWING_G, CHEWING_K);
158 MATCH(PINYIN_AMB_G_K, CHEWING_K, CHEWING_G);
162 result |= middle_and_final_level_search
163 (CHEWING_L, phrase_length, keys, ranges);
165 if (m_options & PINYIN_AMB_L_N)
166 result |= middle_and_final_level_search
167 (CHEWING_N, phrase_length, keys,ranges);
169 if (m_options & PINYIN_AMB_L_R)
170 result |= middle_and_final_level_search
171 (CHEWING_R, phrase_length, keys, ranges);
176 result |= middle_and_final_level_search
177 ((ChewingInitial) first_key.m_initial,
178 phrase_length, keys, ranges);
187 int ChewingBitmapIndexLevel::middle_and_final_level_search
188 (ChewingInitial initial, int phrase_length, /* in */ ChewingKey keys[],
189 /* out */ PhraseIndexRanges ranges) const {
192 #define MATCH(AMBIGUITY, ORIGIN, ANOTHER) case ORIGIN: \
194 result = tone_level_search \
196 ORIGIN, phrase_length, keys, ranges); \
197 if (m_options & AMBIGUITY) { \
198 result |= tone_level_search \
200 ANOTHER, phrase_length, keys, ranges); \
205 int result = SEARCH_NONE;
206 const ChewingKey & first_key = keys[0];
207 const ChewingMiddle middle = (ChewingMiddle)first_key.m_middle;
209 switch(first_key.m_final) {
210 case CHEWING_ZERO_FINAL:
212 if (middle == CHEWING_ZERO_MIDDLE) { /* in-complete pinyin */
213 if (!(m_options & PINYIN_INCOMPLETE))
215 for (int m = CHEWING_ZERO_MIDDLE;
216 m < CHEWING_NUMBER_OF_MIDDLES; ++m)
217 for (int n = CHEWING_ZERO_FINAL;
218 n < CHEWING_NUMBER_OF_FINALS; ++n) {
220 if (CHEWING_ZERO_MIDDLE == m &&
221 CHEWING_ZERO_FINAL == n)
224 result |= tone_level_search
225 (initial, (ChewingMiddle) m, (ChewingFinal) n,
226 phrase_length, keys, ranges);
229 } else { /* normal pinyin */
230 result |= tone_level_search
231 (initial, middle, CHEWING_ZERO_FINAL,
232 phrase_length, keys, ranges);
237 MATCH(PINYIN_AMB_AN_ANG, CHEWING_AN, CHEWING_ANG);
238 MATCH(PINYIN_AMB_AN_ANG, CHEWING_ANG, CHEWING_AN);
239 MATCH(PINYIN_AMB_EN_ENG, CHEWING_EN, CHEWING_ENG);
240 MATCH(PINYIN_AMB_EN_ENG, CHEWING_ENG, CHEWING_EN);
241 MATCH(PINYIN_AMB_IN_ING, PINYIN_IN, PINYIN_ING);
242 MATCH(PINYIN_AMB_IN_ING, PINYIN_ING, PINYIN_IN);
246 result |= tone_level_search
247 (initial, middle, (ChewingFinal) first_key.m_final,
248 phrase_length, keys, ranges);
257 int ChewingBitmapIndexLevel::tone_level_search
258 (ChewingInitial initial, ChewingMiddle middle, ChewingFinal final,
259 int phrase_length, /* in */ ChewingKey keys[],
260 /* out */ PhraseIndexRanges ranges) const {
262 int result = SEARCH_NONE;
263 const ChewingKey & first_key = keys[0];
265 switch (first_key.m_tone) {
266 case CHEWING_ZERO_TONE:
268 /* deal with zero tone in chewing large table. */
269 for (int i = CHEWING_ZERO_TONE; i < CHEWING_NUMBER_OF_TONES; ++i) {
270 ChewingLengthIndexLevel * phrases =
271 m_chewing_length_indexes
272 [initial][middle][final][(ChewingTone)i];
274 result |= phrases->search
275 (m_options, phrase_length - 1, keys + 1, ranges);
281 ChewingLengthIndexLevel * phrases =
282 m_chewing_length_indexes
283 [initial][middle][final][CHEWING_ZERO_TONE];
285 result |= phrases->search
286 (m_options, phrase_length - 1, keys + 1, ranges);
288 phrases = m_chewing_length_indexes
289 [initial][middle][final][(ChewingTone) first_key.m_tone];
291 result |= phrases->search
292 (m_options, phrase_length - 1, keys + 1, ranges);
300 ChewingLengthIndexLevel::ChewingLengthIndexLevel() {
301 m_chewing_array_indexes = g_array_new(FALSE, TRUE, sizeof(void *));
304 ChewingLengthIndexLevel::~ChewingLengthIndexLevel() {
305 #define CASE(len) case len: \
307 ChewingArrayIndexLevel<len> * & array = g_array_index \
308 (m_chewing_array_indexes, ChewingArrayIndexLevel<len> *, len); \
315 for (guint i = 0; i < m_chewing_array_indexes->len; ++i) {
338 g_array_free(m_chewing_array_indexes, TRUE);
339 m_chewing_array_indexes = NULL;
343 int ChewingLengthIndexLevel::search(pinyin_option_t options, int phrase_length,
344 /* in */ ChewingKey keys[],
345 /* out */ PhraseIndexRanges ranges) const {
346 int result = SEARCH_NONE;
347 if (m_chewing_array_indexes->len < phrase_length + 1)
349 if (m_chewing_array_indexes->len > phrase_length + 1)
350 result |= SEARCH_CONTINUED;
352 #define CASE(len) case len: \
354 ChewingArrayIndexLevel<len> * & array = g_array_index \
355 (m_chewing_array_indexes, ChewingArrayIndexLevel<len> *, len); \
358 result |= array->search(options, keys, ranges); \
362 switch (phrase_length) {
387 template<int phrase_length>
388 int ChewingArrayIndexLevel<phrase_length>::search
389 (pinyin_option_t options, /* in */ChewingKey keys[],
390 /* out */ PhraseIndexRanges ranges) const {
391 IndexItem * chunk_begin = NULL, * chunk_end = NULL;
392 chunk_begin = (IndexItem *) m_chunk.begin();
393 chunk_end = (IndexItem *) m_chunk.end();
396 ChewingKey left_keys[phrase_length], right_keys[phrase_length];
397 compute_lower_value2(options, keys, left_keys, phrase_length);
398 compute_upper_value2(options, keys, right_keys, phrase_length);
400 IndexItem left(left_keys, -1), right(right_keys, -1);
402 IndexItem * begin = std_lite::lower_bound
403 (chunk_begin, chunk_end, left,
404 phrase_exact_less_than2<phrase_length>);
405 IndexItem * end = std_lite::upper_bound
406 (chunk_begin, chunk_end, right,
407 phrase_exact_less_than2<phrase_length>);
409 return convert(options, keys, begin, end, ranges);
412 /* compress consecutive tokens */
413 template<int phrase_length>
414 int ChewingArrayIndexLevel<phrase_length>::convert
415 (pinyin_option_t options, ChewingKey keys[],
416 IndexItem * begin, IndexItem * end,
417 PhraseIndexRanges ranges) const {
418 IndexItem * iter = NULL;
419 PhraseIndexRange cursor;
420 GArray * head, * cursor_head = NULL;
422 int result = SEARCH_NONE;
423 /* TODO: check the below code */
424 cursor.m_range_begin = null_token; cursor.m_range_end = null_token;
425 for (iter = begin; iter != end; ++iter) {
426 if (0 != pinyin_compare_with_ambiguities2
427 (options, keys, iter->m_keys, phrase_length))
430 phrase_token_t token = iter->m_token;
431 head = ranges[PHRASE_INDEX_LIBRARY_INDEX(token)];
437 if (null_token == cursor.m_range_begin) {
438 cursor.m_range_begin = token;
439 cursor.m_range_end = token + 1;
441 } else if (cursor.m_range_end == token &&
442 PHRASE_INDEX_LIBRARY_INDEX(cursor.m_range_begin) ==
443 PHRASE_INDEX_LIBRARY_INDEX(token)) {
444 ++cursor.m_range_end;
446 g_array_append_val(cursor_head, cursor);
447 cursor.m_range_begin = token; cursor.m_range_end = token + 1;
452 if (null_token == cursor.m_range_begin)
455 g_array_append_val(cursor_head, cursor);
460 /* add/remove index method */
462 int ChewingBitmapIndexLevel::add_index(int phrase_length,
463 /* in */ ChewingKey keys[],
464 /* in */ phrase_token_t token) {
465 const ChewingKey first_key = keys[0];
466 ChewingLengthIndexLevel * & length_array = m_chewing_length_indexes
467 [first_key.m_initial][first_key.m_middle]
468 [first_key.m_final][first_key.m_tone];
470 if (NULL == length_array) {
471 length_array = new ChewingLengthIndexLevel();
474 return length_array->add_index(phrase_length - 1, keys + 1, token);
477 int ChewingBitmapIndexLevel::remove_index(int phrase_length,
478 /* in */ ChewingKey keys[],
479 /* in */ phrase_token_t token) {
480 const ChewingKey first_key = keys[0];
481 ChewingLengthIndexLevel * & length_array = m_chewing_length_indexes
482 [first_key.m_initial][first_key.m_middle]
483 [first_key.m_final][first_key.m_tone];
486 return length_array->remove_index(phrase_length - 1, keys + 1, token);
487 return ERROR_REMOVE_ITEM_DONOT_EXISTS;
490 int ChewingLengthIndexLevel::add_index(int phrase_length,
491 /* in */ ChewingKey keys[],
492 /* in */ phrase_token_t token) {
493 if (!(phrase_length + 1 < MAX_PHRASE_LENGTH))
494 return ERROR_PHRASE_TOO_LONG;
496 if (m_chewing_array_indexes->len <= phrase_length)
497 g_array_set_size(m_chewing_array_indexes, phrase_length + 1);
499 #define CASE(len) case len: \
501 ChewingArrayIndexLevel<len> * & array = g_array_index \
502 (m_chewing_array_indexes, \
503 ChewingArrayIndexLevel<len> *, len); \
505 array = new ChewingArrayIndexLevel<len>; \
506 return array->add_index(keys, token); \
509 switch(phrase_length) {
533 int ChewingLengthIndexLevel::remove_index(int phrase_length,
534 /* in */ ChewingKey keys[],
535 /* in */ phrase_token_t token) {
536 if (!(phrase_length + 1 < MAX_PHRASE_LENGTH))
537 return ERROR_PHRASE_TOO_LONG;
539 if (m_chewing_array_indexes->len <= phrase_length)
540 return ERROR_REMOVE_ITEM_DONOT_EXISTS;
542 #define CASE(len) case len: \
544 ChewingArrayIndexLevel<len> * & array = g_array_index \
545 (m_chewing_array_indexes, \
546 ChewingArrayIndexLevel<len> *, len); \
548 return ERROR_REMOVE_ITEM_DONOT_EXISTS; \
549 return array->remove_index(keys, token); \
552 switch (phrase_length) {
576 template<int phrase_length>
577 int ChewingArrayIndexLevel<phrase_length>::add_index
578 (/* in */ ChewingKey keys[], /* in */ phrase_token_t token) {
579 IndexItem * begin, * end;
581 IndexItem add_elem(keys, token);
582 begin = (IndexItem *) m_chunk.begin();
583 end = (IndexItem *) m_chunk.end();
585 std_lite::pair<IndexItem *, IndexItem *> range;
586 range = std_lite::equal_range
587 (begin, end, add_elem, phrase_exact_less_than2<phrase_length>);
589 IndexItem * cur_elem;
590 for (cur_elem = range.first;
591 cur_elem != range.second; ++cur_elem) {
592 if (cur_elem->m_token == token)
593 return ERROR_INSERT_ITEM_EXISTS;
594 if (cur_elem->m_token > token)
598 int offset = (cur_elem - begin) * sizeof(IndexItem);
599 m_chunk.insert_content(offset, &add_elem, sizeof(IndexItem));
603 template<int phrase_length>
604 int ChewingArrayIndexLevel<phrase_length>::remove_index
605 (/* in */ ChewingKey keys[], /* in */ phrase_token_t token) {
606 IndexItem * begin, * end;
608 IndexItem remove_elem(keys, token);
609 begin = (IndexItem *) m_chunk.begin();
610 end = (IndexItem *) m_chunk.end();
612 std_lite::pair<IndexItem *, IndexItem *> range;
613 range = std_lite::equal_range
614 (begin, end, remove_elem, phrase_exact_less_than2<phrase_length>);
616 IndexItem * cur_elem;
617 for (cur_elem = range.first;
618 cur_elem != range.second; ++cur_elem) {
619 if (cur_elem->m_token == token)
623 if (cur_elem == range.second)
624 return ERROR_REMOVE_ITEM_DONOT_EXISTS;
626 int offset = (cur_elem - begin) * sizeof(IndexItem);
627 m_chunk.remove_content(offset, sizeof(IndexItem));
632 /* load text method */
633 bool ChewingLargeTable::load_text(FILE * infile) {
636 phrase_token_t token;
639 while (!feof(infile)) {
640 fscanf(infile, "%s", pinyin);
641 fscanf(infile, "%s", phrase);
642 fscanf(infile, "%u", &token);
643 fscanf(infile, "%ld", &freq);
648 glong len = g_utf8_strlen(phrase, -1);
650 FullPinyinParser2 parser;
651 ChewingKeyVector keys;
652 ChewingKeyRestVector key_rests;
654 keys = g_array_new(FALSE, FALSE, sizeof(ChewingKey));
655 key_rests = g_array_new(FALSE, FALSE, sizeof(ChewingKeyRest));
657 pinyin_option_t options = USE_TONE;
658 parser.parse(options, keys, key_rests, pinyin, strlen(pinyin));
660 if (len != keys->len) {
661 fprintf(stderr, "ChewingLargeTable::load_text:%s\t%s\t%u\t%ld\n",
662 pinyin, phrase, token, freq);
666 add_index(keys->len, (ChewingKey *)keys->data, token);
668 g_array_free(keys, TRUE);
669 g_array_free(key_rests, TRUE);
676 /* load/store method */
678 bool ChewingBitmapIndexLevel::load(MemoryChunk * chunk, table_offset_t offset,
679 table_offset_t end) {
681 char * begin = (char *) chunk->begin();
682 table_offset_t phrase_begin, phrase_end;
683 table_offset_t * index = (table_offset_t *) (begin + offset);
686 for (int k = 0; k < CHEWING_NUMBER_OF_INITIALS; ++k)
687 for (int l = 0; l < CHEWING_NUMBER_OF_MIDDLES; ++l)
688 for (int m = 0; m < CHEWING_NUMBER_OF_FINALS; ++m)
689 for (int n = 0; n < CHEWING_NUMBER_OF_TONES; ++n) {
690 phrase_begin = phrase_end;
694 if (phrase_begin == phrase_end) /* null pointer */
697 ChewingLengthIndexLevel * phrases = new ChewingLengthIndexLevel;
698 phrases->load(chunk, phrase_begin, phrase_end - 1);
699 m_chewing_length_indexes[k][l][m][n] = phrases;
701 assert(phrase_end <= end);
702 assert(*(begin + phrase_end - 1) == c_separate);
705 offset += (CHEWING_NUMBER_OF_INITIALS * CHEWING_NUMBER_OF_MIDDLES * CHEWING_NUMBER_OF_FINALS * CHEWING_NUMBER_OF_TONES + 1) * sizeof(table_offset_t);
706 assert(c_separate == *(begin + offset));
710 bool ChewingBitmapIndexLevel::store(MemoryChunk * new_chunk,
711 table_offset_t offset,
712 table_offset_t & end) {
713 table_offset_t phrase_end;
714 table_offset_t index = offset;
715 offset += (CHEWING_NUMBER_OF_INITIALS * CHEWING_NUMBER_OF_MIDDLES * CHEWING_NUMBER_OF_FINALS * CHEWING_NUMBER_OF_TONES + 1) * sizeof(table_offset_t);
718 new_chunk->set_content(offset, &c_separate, sizeof(char));
719 offset += sizeof(char);
720 new_chunk->set_content(index, &offset, sizeof(table_offset_t));
721 index += sizeof(table_offset_t);
723 for (int k = 0; k < CHEWING_NUMBER_OF_INITIALS; ++k)
724 for (int l = 0; l < CHEWING_NUMBER_OF_MIDDLES; ++l)
725 for (int m = 0; m < CHEWING_NUMBER_OF_FINALS; ++m)
726 for (int n = 0; n < CHEWING_NUMBER_OF_TONES; ++n) {
727 ChewingLengthIndexLevel * phrases =
728 m_chewing_length_indexes[k][l][m][n];
730 if (NULL == phrases) { /* null pointer */
731 new_chunk->set_content(index, &offset,
732 sizeof(table_offset_t));
733 index += sizeof(table_offset_t);
738 phrases->store(new_chunk, offset, phrase_end);
742 new_chunk->set_content(offset, &c_separate, sizeof(char));
743 offset += sizeof(char);
744 new_chunk->set_content(index, &offset,
745 sizeof(table_offset_t));
746 index += sizeof(table_offset_t);
753 bool ChewingLengthIndexLevel::load(MemoryChunk * chunk, table_offset_t offset,
754 table_offset_t end) {
755 char * begin = (char *) chunk->begin();
756 guint32 nindex = *((guint32 *)(begin + offset)); /* number of index */
757 table_offset_t * index = (table_offset_t *)
758 (begin + offset + sizeof(guint32));
760 table_offset_t phrase_begin, phrase_end = *index;
761 m_chewing_array_indexes = g_array_new(FALSE, TRUE, sizeof(void *));
762 for (guint32 i = 0; i < nindex; ++i) {
763 phrase_begin = phrase_end;
767 if (phrase_begin == phrase_end) {
769 g_array_append_val(m_chewing_array_indexes, null);
773 #define CASE(len) case len: \
775 ChewingArrayIndexLevel<len> * phrase = \
776 new ChewingArrayIndexLevel<len>; \
777 phrase->load(chunk, phrase_begin, phrase_end - 1); \
778 assert(*(begin + phrase_end - 1) == c_separate); \
779 assert(phrase_end <= end); \
780 g_array_append_val(m_chewing_array_indexes, phrase); \
809 offset += sizeof(guint32) + (nindex + 1) * sizeof(table_offset_t);
810 assert(c_separate == *(begin + offset));
814 bool ChewingLengthIndexLevel::store(MemoryChunk * new_chunk,
815 table_offset_t offset,
816 table_offset_t & end) {
817 guint32 nindex = m_chewing_array_indexes->len; /* number of index */
818 new_chunk->set_content(offset, &nindex, sizeof(guint32));
819 table_offset_t index = offset + sizeof(guint32);
821 offset += sizeof(guint32) + (nindex + 1) * sizeof(table_offset_t);
822 new_chunk->set_content(offset, &c_separate, sizeof(char));
823 offset += sizeof(char);
824 new_chunk->set_content(index, &offset, sizeof(table_offset_t));
825 index += sizeof(table_offset_t);
827 table_offset_t phrase_end;
828 for (guint32 i = 0; i < nindex; ++i) {
829 #define CASE(len) case len: \
831 ChewingArrayIndexLevel<len> * phrase = g_array_index \
832 (m_chewing_array_indexes, ChewingArrayIndexLevel<len> *, i); \
833 if (NULL == phrase) { \
834 new_chunk->set_content \
835 (index, &offset, sizeof(table_offset_t)); \
836 index += sizeof(table_offset_t); \
839 phrase->store(new_chunk, offset, phrase_end); \
840 offset = phrase_end; \
867 new_chunk->set_content(offset, &c_separate, sizeof(char));
868 offset += sizeof(char);
869 new_chunk->set_content(index, &offset, sizeof(table_offset_t));
870 index += sizeof(table_offset_t);
877 template<int phrase_length>
878 bool ChewingArrayIndexLevel<phrase_length>::
879 load(MemoryChunk * chunk, table_offset_t offset, table_offset_t end) {
880 char * begin = (char *) chunk->begin();
881 m_chunk.set_chunk(begin + offset, end - offset, NULL);
885 template<int phrase_length>
886 bool ChewingArrayIndexLevel<phrase_length>::
887 store(MemoryChunk * new_chunk, table_offset_t offset, table_offset_t & end) {
888 new_chunk->set_content(offset, m_chunk.begin(), m_chunk.size());
889 end = offset + m_chunk.size();