Allow libpinyin to build in cross compile mode.
[platform/upstream/libpinyin.git] / src / storage / phrase_index_logger.h
1 /* 
2  *  libpinyin
3  *  Library to deal with pinyin.
4  *  
5  *  Copyright (C) 2011 Peng Wu <alexepico@gmail.com>
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 2 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, write to the Free Software
19  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
20  */
21
22
23 #ifndef PHRASE_LOGGER_H
24 #define PHRASE_LOGGER_H
25
26 #include <assert.h>
27 #include "novel_types.h"
28 #include "memory_chunk.h"
29
30 /**
31  *  File Format
32  *  Logger Record type: add/remove/modify
33  *
34  *  Modify Header: header/null token/len/old data chunk/new data chunk
35  *
36  *  Add Record:    add/token/len/data chunk
37  *  Remove Record: remove/token/len/data chunk
38  *  Modify Record: modify/token/old len/new len/old data chunk/new data chunk
39  *
40  */
41
42 namespace pinyin{
43
44 enum LOG_TYPE{
45     LOG_ADD_RECORD = 1,
46     LOG_REMOVE_RECORD,
47     LOG_MODIFY_RECORD,
48     LOG_MODIFY_HEADER
49 };
50
51
52 /**
53  * PhraseIndexLogger:
54  *
55  * The logger of phrase index changes.
56  *
57  */
58 class PhraseIndexLogger{
59 protected:
60     MemoryChunk * m_chunk;
61     size_t m_offset;
62     bool m_error;
63
64     void reset(){
65         if ( m_chunk ){
66             delete m_chunk;
67             m_chunk = NULL;
68         }
69         m_offset = 0;
70         m_error = false;
71     }
72 public:
73     /**
74      * PhraseIndexLogger::PhraseIndexLogger:
75      *
76      * The constructor of the PhraseIndexLogger.
77      *
78      */
79     PhraseIndexLogger():m_offset(0), m_error(false){
80         m_chunk = new MemoryChunk;
81     }
82
83     /**
84      * PhraseIndexLogger::~PhraseIndexLogger:
85      *
86      * The destructor of the PhraseIndexLogger.
87      *
88      */
89     ~PhraseIndexLogger(){
90         reset();
91     }
92
93     /**
94      * PhraseIndexLogger::load:
95      * @chunk: the memory chunk of the logs.
96      * @returns: whether the load operation is successful.
97      *
98      * Load the logs from the memory chunk.
99      *
100      */
101     bool load(MemoryChunk * chunk) {
102         reset();
103         m_chunk = chunk;
104         return true;
105     }
106
107     /**
108      * PhraseIndexLogger::store:
109      * @new_chunk: the new memory chunk to store the logs.
110      * @returns: whether the store operation is successful.
111      *
112      * Store the logs to the new memory chunk.
113      *
114      */
115     bool store(MemoryChunk * new_chunk){
116         new_chunk->set_content(0, m_chunk->begin(), m_chunk->size());
117         return true;
118     }
119
120     /**
121      * PhraseIndexLogger::has_next_record:
122      * @returns: whether this logger has next record.
123      *
124      * Whether this logger has next record.
125      *
126      */
127     bool has_next_record(){
128         if (m_error)
129             return false;
130
131         return m_offset < m_chunk->size();
132     }
133
134     /**
135      * PhraseIndexLogger::rewind:
136      * @returns: whether the rewind operation is successful.
137      *
138      * Rewind this logger to the begin of logs.
139      *
140      */
141     bool rewind(){
142         m_offset = 0;
143         return true;
144     }
145
146     /**
147      * PhraseIndexLogger::next_record:
148      * @log_type: the type of this log record.
149      * @token: the token of this log record.
150      * @oldone: the original content of the phrase item.
151      * @newone: the new content of the phrase item.
152      *
153      * Read the next log record.
154      *
155      * Prolog: has_next_record() returned true.
156      *
157      */
158     bool next_record(LOG_TYPE & log_type, phrase_token_t & token,
159                      MemoryChunk * oldone, MemoryChunk * newone){
160         size_t offset = m_offset;
161         m_chunk->get_content(offset, &log_type, sizeof(LOG_TYPE));
162         offset += sizeof(LOG_TYPE);
163         m_chunk->get_content(offset, &token, sizeof(phrase_token_t));
164         offset += sizeof(phrase_token_t);
165
166         oldone->set_size(0); newone->set_size(0);
167
168         switch(log_type){
169         case LOG_ADD_RECORD:{
170             guint16 len = 0;
171             m_chunk->get_content(offset, &len, sizeof(guint16));
172             offset += sizeof(guint16);
173             newone->set_content(0, ((char *)m_chunk->begin()) + offset, len);
174             offset += len;
175             break;
176         }
177         case LOG_REMOVE_RECORD:{
178             guint16 len = 0;
179             m_chunk->get_content(offset, &len, sizeof(guint16));
180             offset += sizeof(guint16);
181             oldone->set_content(0, ((char *)m_chunk->begin()) + offset, len);
182             offset += len;
183             break;
184         }
185         case LOG_MODIFY_RECORD:{
186             guint16 oldlen = 0, newlen = 0;
187             m_chunk->get_content(offset, &oldlen, sizeof(guint16));
188             offset += sizeof(guint16);
189             m_chunk->get_content(offset, &newlen, sizeof(guint16));
190             offset += sizeof(guint16);
191             oldone->set_content(0, ((char *)m_chunk->begin()) + offset,
192                                 oldlen);
193             offset += oldlen;
194             newone->set_content(0, ((char *)m_chunk->begin()) + offset, newlen);
195             offset += newlen;
196             break;
197         }
198         case LOG_MODIFY_HEADER:{
199             assert(token == null_token);
200             guint16 len = 0;
201             m_chunk->get_content(offset, &len, sizeof(guint16));
202             offset += sizeof(guint16);
203             oldone->set_content(0, ((char *)m_chunk->begin()) + offset,
204                                 len);
205             offset += len;
206             newone->set_content(0, ((char *)m_chunk->begin()) + offset,
207                                 len);
208             offset += len;
209             break;
210         }
211         default:
212             m_error = true;
213             return false;
214         }
215
216         m_offset = offset;
217         return true;
218     }
219
220     /**
221      * PhraseIndexLogger::append_record:
222      * @log_type: the type of this log record.
223      * @token: the token of this log record.
224      * @oldone: the original content of the phrase item.
225      * @newone: the new content of the phrase item.
226      *
227      * Append one log record to the logger.
228      *
229      */
230     bool append_record(LOG_TYPE log_type, phrase_token_t token,
231                        MemoryChunk * oldone, MemoryChunk * newone){
232
233         MemoryChunk chunk;
234         size_t offset = 0;
235         chunk.set_content(offset, &log_type, sizeof(LOG_TYPE));
236         offset += sizeof(LOG_TYPE);
237         chunk.set_content(offset, &token, sizeof(phrase_token_t));
238         offset += sizeof(phrase_token_t);
239
240         switch(log_type){
241         case LOG_ADD_RECORD:{
242             assert( NULL == oldone );
243             assert( NULL != newone );
244             /* use newone chunk */
245             guint16 len = newone->size();
246             chunk.set_content(offset, &len, sizeof(guint16));
247             offset += sizeof(guint16);
248             chunk.set_content(offset, newone->begin(), newone->size());
249             offset += newone->size();
250             break;
251         }
252         case LOG_REMOVE_RECORD:{
253             assert(NULL != oldone);
254             assert(NULL == newone);
255             /* use oldone chunk */
256             guint16 len = oldone->size();
257             chunk.set_content(offset, &len, sizeof(guint16));
258             offset += sizeof(guint16);
259             chunk.set_content(offset, oldone->begin(), oldone->size());
260             offset += oldone->size();
261             break;
262         }
263         case LOG_MODIFY_RECORD:{
264             assert(NULL != oldone);
265             assert(NULL != newone);
266             guint16 oldlen = oldone->size();
267             guint16 newlen = newone->size();
268             chunk.set_content(offset, &oldlen, sizeof(guint16));
269             offset += sizeof(guint16);
270             chunk.set_content(offset, &newlen, sizeof(guint16));
271             offset += sizeof(guint16);
272             chunk.set_content(offset, oldone->begin(), oldone->size());
273             offset += oldlen;
274             chunk.set_content(offset, newone->begin(), newone->size());
275             offset += newlen;
276             break;
277         }
278         case LOG_MODIFY_HEADER:{
279             assert(NULL != oldone);
280             assert(NULL != newone);
281             assert(null_token == token);
282             guint16 oldlen = oldone->size();
283             guint16 newlen = newone->size();
284             assert(oldlen == newlen);
285             chunk.set_content(offset, &oldlen, sizeof(guint16));
286             offset += sizeof(guint16);
287             chunk.set_content(offset, oldone->begin(), oldone->size());
288             offset += oldlen;
289             chunk.set_content(offset, newone->begin(), newone->size());
290             offset += newlen;
291             break;
292         }
293         default:
294             assert(false);
295         }
296
297         /* store log record. */
298         m_chunk->set_content(m_chunk->size(), chunk.begin(), chunk.size());
299         return true;
300     }
301 };
302
303 };
304
305 #endif