1 /*
2  *  libpinyin
3  *  Library to deal with pinyin.
4  *
5  *  Copyright (C) 2006-2007 Peng Wu
6  *
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 3 of the License, or
10  *  (at your option) any later version.
11  *
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.
16  *
17  *  You should have received a copy of the GNU General Public License
18  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
19  */
20 
21 #ifndef PHRASE_INDEX_H
22 #define PHRASE_INDEX_H
23 
24 #include <stdio.h>
25 #include <glib.h>
26 #include "novel_types.h"
27 #include "chewing_key.h"
28 #include "pinyin_parser2.h"
29 #include "zhuyin_parser2.h"
30 #include "pinyin_phrase3.h"
31 #include "memory_chunk.h"
32 #include "phrase_index_logger.h"
33 #include "table_info.h"
34 
35 /**
36  * Phrase Index File Format
37  *
38  * Indirect Index: Index by Token
39  * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
40  * + Phrase Offset + Phrase Offset + Phrase Offset + ......  +
41  * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
42  * Phrase Content:
43  * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
44  * + Phrase Length + number of  Pronunciations  + Uni-gram Frequency+
45  * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
46  * + Phrase String(UCS4) + n Pronunciations with Frequency +
47  * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
48  */
49 
50 namespace pinyin{
51 
52 /* Store delta info by phrase index logger in user home directory.
53  */
54 
55 const size_t phrase_item_header = sizeof(guint8) + sizeof(guint8) + sizeof(guint32);
56 
57 /**
58  * PhraseItem:
59  *
60  * The PhraseItem to access the items in phrase index.
61  *
62  */
63 class PhraseItem{
64     friend class SubPhraseIndex;
65     friend bool _compute_new_header(PhraseIndexLogger * logger,
66                                     phrase_token_t mask,
67                                     phrase_token_t value,
68                                     guint32 & new_total_freq);
69 
70 private:
71     MemoryChunk m_chunk;
72     bool set_n_pronunciation(guint8 n_prouns);
73 public:
74     /**
75      * PhraseItem::PhraseItem:
76      *
77      * The constructor of the PhraseItem.
78      *
79      */
PhraseItem()80     PhraseItem(){
81         m_chunk.set_size(phrase_item_header);
82         memset(m_chunk.begin(), 0, m_chunk.size());
83     }
84 
85 #if 0
86     PhraseItem(MemoryChunk & chunk){
87         m_chunk.set_content(0, chunk->begin(), chunk->size());
88         assert ( m_chunk.size() >= phrase_item_header);
89     }
90 #endif
91 
92     /**
93      * PhraseItem::get_phrase_length:
94      * @returns: the length of this phrase item.
95      *
96      * Get the length of this phrase item.
97      *
98      */
get_phrase_length()99     guint8 get_phrase_length(){
100         char * buf_begin = (char *)m_chunk.begin();
101         return (*(guint8 *)buf_begin);
102     }
103 
104     /**
105      * PhraseItem::get_n_pronunciation:
106      * @returns: the number of the pronunciations.
107      *
108      * Get the number of the pronunciations.
109      *
110      */
get_n_pronunciation()111     guint8 get_n_pronunciation(){
112         char * buf_begin = ( char *) m_chunk.begin();
113         return (*(guint8 *)(buf_begin + sizeof(guint8)));
114     }
115 
116     /**
117      * PhraseItem::get_unigram_frequency:
118      * @returns: the uni-gram frequency of this phrase item.
119      *
120      * Get the uni-gram frequency of this phrase item.
121      *
122      */
get_unigram_frequency()123     guint32 get_unigram_frequency(){
124         char * buf_begin = (char *)m_chunk.begin();
125         return (*(guint32 *)(buf_begin + sizeof(guint8) + sizeof(guint8)));
126     }
127 
128     /**
129      * PhraseItem::get_pronunciation_possibility:
130      * @keys: the pronunciation keys.
131      * @returns: the possibility of this phrase item pronounces the pinyin.
132      *
133      * Get the possibility of this phrase item pronounces the pinyin.
134      *
135      */
get_pronunciation_possibility(ChewingKey * keys)136     gfloat get_pronunciation_possibility(ChewingKey * keys){
137         guint8 phrase_length = get_phrase_length();
138         guint8 npron = get_n_pronunciation();
139         size_t offset = phrase_item_header + phrase_length * sizeof (ucs4_t);
140         char * buf_begin = (char *)m_chunk.begin();
141         guint32 matched = 0, total_freq =0;
142         for ( int i = 0 ; i < npron ; ++i){
143             char * chewing_begin = buf_begin + offset +
144                 i * (phrase_length * sizeof(ChewingKey) + sizeof(guint32));
145             guint32 * freq = (guint32 *)(chewing_begin +
146                                          phrase_length * sizeof(ChewingKey));
147             total_freq += *freq;
148             if ( 0 == pinyin_compare_with_tones(keys, (ChewingKey *)chewing_begin,
149                                                 phrase_length) ){
150                 matched += *freq;
151             }
152         }
153 
154 #if 1
155         /* an additional safe guard for chewing. */
156         if ( 0 == total_freq )
157             return 0;
158 #endif
159 
160         /* used preprocessor to avoid zero freq, in gen_pinyin_table. */
161         gfloat retval = matched / (gfloat) total_freq;
162         return retval;
163     }
164 
165     /**
166      * PhraseItem::increase_pronunciation_possibility:
167      * @keys: the pronunciation keys.
168      * @delta: the delta to be added to the pronunciation keys.
169      *
170      * Add the delta to the pronunciation of the pronunciation keys.
171      *
172      */
173     void increase_pronunciation_possibility(ChewingKey * keys,
174                                             gint32 delta);
175 
176     /**
177      * PhraseItem::get_phrase_string:
178      * @phrase: the ucs4 character buffer.
179      * @returns: whether the get operation is successful.
180      *
181      * Get the ucs4 characters of this phrase item.
182      *
183      */
184     bool get_phrase_string(ucs4_t * phrase);
185 
186     /**
187      * PhraseItem::set_phrase_string:
188      * @phrase_length: the ucs4 character length of this phrase item.
189      * @phrase: the ucs4 character buffer.
190      * @returns: whether the set operation is successful.
191      *
192      * Set the length and ucs4 characters of this phrase item.
193      *
194      */
195     bool set_phrase_string(guint8 phrase_length, ucs4_t * phrase);
196 
197     /**
198      * PhraseItem::get_nth_pronunciation:
199      * @index: the pronunciation index.
200      * @keys: the pronunciation keys.
201      * @freq: the frequency of the pronunciation.
202      * @returns: whether the get operation is successful.
203      *
204      * Get the nth pronunciation of this phrase item.
205      *
206      */
207     bool get_nth_pronunciation(size_t index,
208                                /* out */ ChewingKey * keys,
209                                /* out */ guint32 & freq);
210 
211     /**
212      * PhraseItem::add_pronunciation:
213      * @keys: the pronunciation keys.
214      * @delta: the delta of the frequency of the pronunciation.
215      * @returns: whether the add operation is successful.
216      *
217      * Add one pronunciation.
218      *
219      */
220     bool add_pronunciation(ChewingKey * keys, guint32 delta);
221 
222     /**
223      * PhraseItem::remove_nth_pronunciation:
224      * @index: the pronunciation index.
225      *
226      * Remove the nth pronunciation.
227      *
228      * Note: Normally don't change the first pronunciation,
229      * which decides the token number.
230      *
231      */
232     void remove_nth_pronunciation(size_t index);
233 
234     bool operator == (const PhraseItem & rhs) const{
235         if (m_chunk.size() != rhs.m_chunk.size())
236             return false;
237         return memcmp(m_chunk.begin(), rhs.m_chunk.begin(),
238                       m_chunk.size()) == 0;
239     }
240 
241     bool operator != (const PhraseItem & rhs) const{
242         return ! (*this == rhs);
243     }
244 };
245 
246 /*
247  *  In Sub Phrase Index, token == (token & PHRASE_MASK).
248  */
249 
250 /**
251  * SubPhraseIndex:
252  *
253  * The SubPhraseIndex class for internal usage.
254  *
255  */
256 class SubPhraseIndex{
257 private:
258     guint32 m_total_freq;
259     MemoryChunk m_phrase_index;
260     MemoryChunk m_phrase_content;
261     MemoryChunk * m_chunk;
262 
reset()263     void reset(){
264         m_total_freq = 0;
265         m_phrase_index.set_size(0);
266         m_phrase_content.set_size(0);
267         if ( m_chunk ){
268             delete m_chunk;
269             m_chunk = NULL;
270         }
271     }
272 
273 public:
274     /**
275      * SubPhraseIndex::SubPhraseIndex:
276      *
277      * The constructor of the SubPhraseIndex.
278      *
279      */
SubPhraseIndex()280     SubPhraseIndex():m_total_freq(0){
281         m_chunk = NULL;
282     }
283 
284     /**
285      * SubPhraseIndex::~SubPhraseIndex:
286      *
287      * The destructor of the SubPhraseIndex.
288      *
289      */
~SubPhraseIndex()290     ~SubPhraseIndex(){
291         reset();
292     }
293 
294     /**
295      * SubPhraseIndex::load:
296      * @chunk: the memory chunk of the binary sub phrase index.
297      * @offset: the begin of binary data in the memory chunk.
298      * @end: the end of binary data in the memory chunk.
299      * @returns: whether the load operation is successful.
300      *
301      * Load the sub phrase index from the memory chunk.
302      *
303      */
304     bool load(MemoryChunk * chunk,
305               table_offset_t offset, table_offset_t end);
306 
307     /**
308      * SubPhraseIndex::store:
309      * @new_chunk: the new memory chunk to store this sub phrase index.
310      * @offset: the begin of binary data in the memory chunk.
311      * @end: the end of stored binary data in the memory chunk.
312      * @returns: whether the store operation is successful.
313      *
314      * Store the sub phrase index to the new memory chunk.
315      *
316      */
317     bool store(MemoryChunk * new_chunk,
318                table_offset_t offset, table_offset_t & end);
319 
320     /**
321      * SubPhraseIndex::diff:
322      * @oldone: the original content of sub phrase index.
323      * @logger: the delta information of user self-learning data.
324      * @returns: whether the diff operation is successful.
325      *
326      * Compare this sub phrase index with the original content of the system
327      * sub phrase index to generate the logger of difference.
328      *
329      * Note: Switch to logger format to reduce user space storage.
330      *
331      */
332     bool diff(SubPhraseIndex * oldone, PhraseIndexLogger * logger);
333 
334     /**
335      * SubPhraseIndex::merge:
336      * @logger: the logger of difference in user home directory.
337      * @returns: whether the merge operation is successful.
338      *
339      * Merge the user logger of difference with this sub phrase index.
340      *
341      */
342     bool merge(PhraseIndexLogger * logger);
343 
344     /**
345      * SubPhraseIndex::get_range:
346      * @range: the token range.
347      * @returns: whether the get operation is successful.
348      *
349      * Get the token range in this sub phrase index.
350      *
351      */
352     int get_range(/* out */ PhraseIndexRange & range);
353 
354     /**
355      * SubPhraseIndex::get_phrase_index_total_freq:
356      * @returns: the total frequency of this sub phrase index.
357      *
358      * Get the total frequency of this sub phrase index.
359      *
360      * Note: maybe call it "Zero-gram".
361      *
362      */
363     guint32 get_phrase_index_total_freq();
364 
365     /**
366      * SubPhraseIndex::add_unigram_frequency:
367      * @token: the phrase token.
368      * @delta: the delta value of the phrase token.
369      * @returns: the status of the add operation.
370      *
371      * Add delta value to the phrase of the token.
372      *
373      * Note: this method is a fast path to add delta value.
374      * Maybe use the get_phrase_item method instead in future.
375      *
376      */
377     int add_unigram_frequency(phrase_token_t token, guint32 delta);
378 
379     /**
380      * SubPhraseIndex::get_phrase_item:
381      * @token: the phrase token.
382      * @item: the phrase item of the token.
383      * @returns: the status of the get operation.
384      *
385      * Get the phrase item from this sub phrase index.
386      *
387      * Note:get_phrase_item function can't modify the phrase item size,
388      * but can increment the freq of the special pronunciation,
389      * or change the content without size increasing.
390      *
391      */
392     int get_phrase_item(phrase_token_t token, PhraseItem & item);
393 
394     /**
395      * SubPhraseIndex::add_phrase_item:
396      * @token: the phrase token.
397      * @item: the phrase item of the token.
398      * @returns: the status of the add operation.
399      *
400      * Add the phrase item to this sub phrase index.
401      *
402      */
403     int add_phrase_item(phrase_token_t token, PhraseItem * item);
404 
405     /**
406      * SubPhraseIndex::remove_phrase_item:
407      * @token: the phrase token.
408      * @item: the removed phrase item of the token.
409      * @returns: the status of the remove operation.
410      *
411      * Remove the phrase item of the token.
412      *
413      * Note: this remove_phrase_item method will substract the unigram
414      * frequency of the removed item from m_total_freq.
415      *
416      */
417     int remove_phrase_item(phrase_token_t token, /* out */ PhraseItem * & item);
418 
419     /**
420      * SubPhraseIndex::mask_out:
421      * @mask: the mask.
422      * @value: the value.
423      * @returns: whether the mask out operation is successful.
424      *
425      * Mask out the matched phrase items.
426      *
427      */
428     bool mask_out(phrase_token_t mask, phrase_token_t value);
429 };
430 
431 /**
432  * FacadePhraseIndex:
433  *
434  * The facade class of phrase index.
435  *
436  */
437 class FacadePhraseIndex{
438 private:
439     guint32 m_total_freq;
440     SubPhraseIndex * m_sub_phrase_indices[PHRASE_INDEX_LIBRARY_COUNT];
441 public:
442     /**
443      * FacadePhraseIndex::FacadePhraseIndex:
444      *
445      * The constructor of the FacadePhraseIndex.
446      *
447      */
FacadePhraseIndex()448     FacadePhraseIndex(){
449         m_total_freq = 0;
450         memset(m_sub_phrase_indices, 0, sizeof(m_sub_phrase_indices));
451     }
452 
453     /**
454      * FacadePhraseIndex::~FacadePhraseIndex:
455      *
456      * The destructor of the FacadePhraseIndex.
457      *
458      */
~FacadePhraseIndex()459     ~FacadePhraseIndex(){
460         for ( size_t i = 0; i < PHRASE_INDEX_LIBRARY_COUNT; ++i){
461             if ( m_sub_phrase_indices[i] ){
462                 delete m_sub_phrase_indices[i];
463                 m_sub_phrase_indices[i] = NULL;
464             }
465         }
466     }
467 
468     /**
469      * FacadePhraseIndex::load_text:
470      * @phrase_index: the index of sub phrase index to be loaded.
471      * @infile: the textual format file of the phrase table.
472      * @type: the type of phonetic table.
473      * @returns: whether the load operation is successful.
474      *
475      * Load one sub phrase index from the textual format file.
476      * Note: load sub phrase index according to the config in future.
477      *
478      */
479     bool load_text(guint8 phrase_index, FILE * infile,
480                    TABLE_PHONETIC_TYPE type);
481 
482     /**
483      * FacadePhraseIndex::load:
484      * @phrase_index: the index of sub phrase index to be loaded.
485      * @chunk: the memory chunk of sub phrase index to be loaded.
486      * @returns: whether the load operation is successful.
487      *
488      * Load one sub phrase index from the memory chunk.
489      *
490      */
491     bool load(guint8 phrase_index, MemoryChunk * chunk);
492 
493     /**
494      * FacadePhraseIndex::store:
495      * @phrase_index: the index of sub phrase index to be stored.
496      * @new_chunk: the memory chunk of sub phrase index to be stored.
497      * @returns: whether the store operation is successful.
498      *
499      * Store one sub phrase index to the memory chunk.
500      *
501      */
502     bool store(guint8 phrase_index, MemoryChunk * new_chunk);
503 
504     /**
505      * FacadePhraseIndex::unload:
506      * @phrase_index: the index of sub phrase index to be unloaded.
507      * @returns: whether the unload operation is successful.
508      *
509      * Unload one sub phrase index.
510      *
511      */
512     bool unload(guint8 phrase_index);
513 
514 
515     /**
516      * FacadePhraseIndex::diff:
517      * @phrase_index: the index of sub phrase index to be differed.
518      * @oldchunk: the original content of sub phrase index.
519      * @newlog: the delta information of user self-learning data.
520      * @returns: whether the diff operation is successful.
521      *
522      * Store user delta information in the logger format.
523      *
524      * Note: the ownership of oldchunk is transfered here.
525      *
526      */
527     bool diff(guint8 phrase_index, MemoryChunk * oldchunk,
528               MemoryChunk * newlog);
529 
530     /**
531      * FacadePhraseIndex::merge:
532      * @phrase_index: the index of sub phrase index to be merged.
533      * @log: the logger of difference in user home directory.
534      * @returns: whether the merge operation is successful.
535      *
536      * Merge the user logger of difference with the sub phrase index.
537      *
538      * Note: the ownership of log is transfered here.
539      *
540      */
541     bool merge(guint8 phrase_index, MemoryChunk * log);
542 
543     /**
544      * FacadePhraseIndex::merge_with_mask:
545      * @phrase_index: the index of sub phrase index to be merged.
546      * @log: the logger of difference in user home directory.
547      * @mask: the mask.
548      * @value: the value.
549      * @returns: whether the merge operation is successful.
550      *
551      * Merge the user logger of difference with mask operation.
552      *
553      * Note: the ownership of log is transfered here.
554      *
555      */
556     bool merge_with_mask(guint8 phrase_index, MemoryChunk * log,
557                          phrase_token_t mask, phrase_token_t value);
558 
559     /**
560      * FacadePhraseIndex::compact:
561      * @returns: whether the compact operation is successful.
562      *
563      * Compat all sub phrase index memory usage.
564      *
565      */
566     bool compact();
567 
568     /**
569      * FacadePhraseIndex::mask_out:
570      * @phrase_index: the index of sub phrase index.
571      * @mask: the mask.
572      * @value: the value.
573      * @returns: whether the mask out operation is successful.
574      *
575      * Mask out the matched phrase items.
576      *
577      * Note: should call compact() after the mask out operation.
578      *
579      */
580     bool mask_out(guint8 phrase_index,
581                   phrase_token_t mask, phrase_token_t value);
582 
583     /**
584      * FacadePhraseIndex::get_sub_phrase_range:
585      * @min_index: the minimal sub phrase index.
586      * @max_index: the maximal sub phrase index.
587      * @returns: the status of the get operation.
588      *
589      * Get the minimum and maximum of the sub phrase index.
590      *
591      */
592     int get_sub_phrase_range(guint8 & min_index, guint8 & max_index);
593 
594     /**
595      * FacadePhraseIndex::get_range:
596      * @phrase_index: the index of sub phrase index.
597      * @range: the token range of the sub phrase index.
598      * @returns: the status of the get operation.
599      *
600      * Get the token range of the sub phrase index.
601      *
602      */
603     int get_range(guint8 phrase_index, /* out */ PhraseIndexRange & range);
604 
605     /**
606      * FacadePhraseIndex::get_phrase_index_total_freq:
607      * @returns: the total freq of the facade phrase index.
608      *
609      * Get the total freq of the facade phrase index.
610      *
611      * Note: maybe call it "Zero-gram".
612      *
613      */
get_phrase_index_total_freq()614     guint32 get_phrase_index_total_freq(){
615         return m_total_freq;
616     }
617 
618     /**
619      * FacadePhraseIndex::add_unigram_frequency:
620      * @token: the phrase token.
621      * @delta: the delta value of the phrase token.
622      * @returns: the status of the add operation.
623      *
624      * Add delta value to the phrase of the token.
625      *
626      */
add_unigram_frequency(phrase_token_t token,guint32 delta)627     int add_unigram_frequency(phrase_token_t token, guint32 delta){
628         guint8 index = PHRASE_INDEX_LIBRARY_INDEX(token);
629         SubPhraseIndex * sub_phrase = m_sub_phrase_indices[index];
630         if ( !sub_phrase )
631             return ERROR_NO_SUB_PHRASE_INDEX;
632         m_total_freq += delta;
633         return sub_phrase->add_unigram_frequency(token, delta);
634     }
635 
636     /**
637      * FacadePhraseIndex::get_phrase_item:
638      * @token: the phrase token.
639      * @item: the phrase item of the token.
640      * @returns: the status of the get operation.
641      *
642      * Get the phrase item from the facade phrase index.
643      *
644      */
get_phrase_item(phrase_token_t token,PhraseItem & item)645     int get_phrase_item(phrase_token_t token, PhraseItem & item){
646         guint8 index = PHRASE_INDEX_LIBRARY_INDEX(token);
647         SubPhraseIndex * sub_phrase = m_sub_phrase_indices[index];
648         if ( !sub_phrase )
649             return ERROR_NO_SUB_PHRASE_INDEX;
650         return sub_phrase->get_phrase_item(token, item);
651     }
652 
653     /**
654      * FacadePhraseIndex::add_phrase_item:
655      * @token: the phrase token.
656      * @item: the phrase item of the token.
657      * @returns: the status of the add operation.
658      *
659      * Add the phrase item to the facade phrase index.
660      *
661      */
add_phrase_item(phrase_token_t token,PhraseItem * item)662     int add_phrase_item(phrase_token_t token, PhraseItem * item){
663         guint8 index = PHRASE_INDEX_LIBRARY_INDEX(token);
664         SubPhraseIndex * & sub_phrase = m_sub_phrase_indices[index];
665         if ( !sub_phrase ){
666             sub_phrase = new SubPhraseIndex;
667         }
668         m_total_freq += item->get_unigram_frequency();
669         return sub_phrase->add_phrase_item(token, item);
670     }
671 
672     /**
673      * FacadePhraseIndex::remove_phrase_item:
674      * @token: the phrase token.
675      * @item: the removed phrase item of the token.
676      * @returns: the status of the remove operation.
677      *
678      * Remove the phrase item of the token.
679      *
680      */
remove_phrase_item(phrase_token_t token,PhraseItem * & item)681     int remove_phrase_item(phrase_token_t token, PhraseItem * & item){
682         guint8 index = PHRASE_INDEX_LIBRARY_INDEX(token);
683         SubPhraseIndex * & sub_phrase = m_sub_phrase_indices[index];
684         if ( !sub_phrase ){
685             return ERROR_NO_SUB_PHRASE_INDEX;
686         }
687         int result = sub_phrase->remove_phrase_item(token, item);
688         if ( result )
689             return result;
690         m_total_freq -= item->get_unigram_frequency();
691         return result;
692     }
693 
694     /**
695      * FacadePhraseIndex::prepare_ranges:
696      * @ranges: the ranges to be prepared.
697      * @returns: whether the prepare operation is successful.
698      *
699      * Prepare the ranges.
700      *
701      */
prepare_ranges(PhraseIndexRanges ranges)702     bool prepare_ranges(PhraseIndexRanges ranges) {
703         /* assume memset(ranges, 0, sizeof(ranges)); */
704         for (size_t i = 0; i < PHRASE_INDEX_LIBRARY_COUNT; ++i) {
705             GArray * & range = ranges[i];
706             assert(NULL == range);
707 
708             SubPhraseIndex * sub_phrase = m_sub_phrase_indices[i];
709             if (sub_phrase) {
710                 range = g_array_new(FALSE, FALSE, sizeof(PhraseIndexRange));
711             }
712         }
713         return true;
714     }
715 
716     /**
717      * FacadePhraseIndex::clear_ranges:
718      * @ranges: the ranges to be cleared.
719      * @returns: whether the clear operation is successful.
720      *
721      * Clear the ranges.
722      *
723      */
clear_ranges(PhraseIndexRanges ranges)724     bool clear_ranges(PhraseIndexRanges ranges) {
725         for (size_t i = 0; i < PHRASE_INDEX_LIBRARY_COUNT; ++i) {
726             GArray * range = ranges[i];
727             if (range) {
728                 g_array_set_size(range, 0);
729             }
730         }
731         return true;
732     }
733 
734     /**
735      * FacadePhraseIndex::destroy_ranges:
736      * @ranges: the ranges to be destroyed.
737      * @returns: whether the destroy operation is successful.
738      *
739      * Destroy the ranges.
740      *
741      */
destroy_ranges(PhraseIndexRanges ranges)742     bool destroy_ranges(PhraseIndexRanges ranges) {
743         for (size_t i = 0; i < PHRASE_INDEX_LIBRARY_COUNT; ++i) {
744             GArray * & range = ranges[i];
745             if (range) {
746                 g_array_free(range, TRUE);
747                 range = NULL;
748             }
749         }
750         return true;
751     }
752 
753     /**
754      * FacadePhraseIndex::prepare_tokens:
755      * @tokens: the tokens to be prepared.
756      * @returns: whether the prepare operation is successful.
757      *
758      * Prepare the tokens.
759      *
760      */
prepare_tokens(PhraseTokens tokens)761     bool prepare_tokens(PhraseTokens tokens) {
762         /* assume memset(tokens, 0, sizeof(tokens)); */
763         for (size_t i = 0; i < PHRASE_INDEX_LIBRARY_COUNT; ++i) {
764             GArray * & token = tokens[i];
765             assert(NULL == token);
766 
767             SubPhraseIndex * sub_phrase = m_sub_phrase_indices[i];
768             if (sub_phrase) {
769                 token = g_array_new(FALSE, FALSE, sizeof(phrase_token_t));
770             }
771         }
772         return true;
773     }
774 
775     /**
776      * FacadePhraseIndex::clear_tokens:
777      * @tokens: the tokens to be cleared.
778      * @return: whether the clear operation is successful.
779      *
780      * Clear the tokens.
781      *
782      */
clear_tokens(PhraseTokens tokens)783     bool clear_tokens(PhraseTokens tokens) {
784         for (size_t i = 0; i < PHRASE_INDEX_LIBRARY_COUNT; ++i) {
785             GArray * token = tokens[i];
786             if (token) {
787                 g_array_set_size(token, 0);
788             }
789         }
790         return true;
791     }
792 
793     /**
794      * FacadePhraseIndex::destroy_tokens:
795      * @tokens: the tokens to be destroyed.
796      * @returns: whether the destroy operation is successful.
797      *
798      * Destroy the tokens.
799      *
800      */
destroy_tokens(PhraseTokens tokens)801     bool destroy_tokens(PhraseTokens tokens) {
802         for (size_t i = 0; i < PHRASE_INDEX_LIBRARY_COUNT; ++i) {
803             GArray * & token = tokens[i];
804             if (token) {
805                 g_array_free(token, TRUE);
806                 token = NULL;
807             }
808         }
809         return true;
810     }
811 
812     /**
813      * FacadePhraseIndex::create_sub_phrase:
814      * @index: the phrase index to be created.
815      * @returns: the result of the create operation.
816      *
817      * Create the sub phrase index.
818      *
819      */
create_sub_phrase(guint8 index)820     int create_sub_phrase(guint8 index) {
821         SubPhraseIndex * & sub_phrase = m_sub_phrase_indices[index];
822         if (sub_phrase) {
823             return ERROR_ALREADY_EXISTS;
824         }
825 
826         sub_phrase = new SubPhraseIndex;
827 
828         return ERROR_OK;
829     }
830 };
831 
832 PhraseIndexLogger * mask_out_phrase_index_logger
833 (PhraseIndexLogger * oldlogger, phrase_token_t mask, phrase_token_t value);
834 
835 };
836 
837 #endif
838