begin to write import iterator
[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
63     void reset(){
64         if ( m_chunk ){
65             delete m_chunk;
66             m_chunk = NULL;
67         }
68         m_offset = 0;
69     }
70 public:
71     /**
72      * PhraseIndexLogger::PhraseIndexLogger:
73      *
74      * The constructor of the PhraseIndexLogger.
75      *
76      */
77     PhraseIndexLogger():m_offset(0){
78         m_chunk = new MemoryChunk;
79     }
80
81     /**
82      * PhraseIndexLogger::~PhraseIndexLogger:
83      *
84      * The destructor of the PhraseIndexLogger.
85      *
86      */
87     ~PhraseIndexLogger(){
88         reset();
89     }
90
91     /**
92      * PhraseIndexLogger::load:
93      * @chunk: the memory chunk of the logs.
94      * @returns: whether the load operation is successful.
95      *
96      * Load the logs from the memory chunk.
97      *
98      */
99     bool load(MemoryChunk * chunk) {
100         reset();
101         m_chunk = chunk;
102         return true;
103     }
104
105     /**
106      * PhraseIndexLogger::store:
107      * @new_chunk: the new memory chunk to store the logs.
108      * @returns: whether the store operation is successful.
109      *
110      * Store the logs to the new memory chunk.
111      *
112      */
113     bool store(MemoryChunk * new_chunk){
114         new_chunk->set_content(0, m_chunk->begin(), m_chunk->size());
115         return true;
116     }
117
118     /**
119      * PhraseIndexLogger::has_next_record:
120      * @returns: whether this logger has next record.
121      *
122      * Whether this logger has next record.
123      *
124      */
125     bool has_next_record(){
126         return m_offset < m_chunk->size();
127     }
128
129     /**
130      * PhraseIndexLogger::rewind:
131      * @returns: whether the rewind operation is successful.
132      *
133      * Rewind this logger to the begin of logs.
134      *
135      */
136     bool rewind(){
137         m_offset = 0;
138         return true;
139     }
140
141     /**
142      * PhraseIndexLogger::next_record:
143      * @log_type: the type of this log record.
144      * @token: the token of this log record.
145      * @oldone: the original content of the phrase item.
146      * @newone: the new content of the phrase item.
147      *
148      * Read the next log record.
149      *
150      * Prolog: has_next_record() returned true.
151      *
152      */
153     bool next_record(LOG_TYPE & log_type, phrase_token_t & token,
154                      MemoryChunk * oldone, MemoryChunk * newone){
155         size_t offset = m_offset;
156         m_chunk->get_content(offset, &log_type, sizeof(LOG_TYPE));
157         offset += sizeof(LOG_TYPE);
158         m_chunk->get_content(offset, &token, sizeof(phrase_token_t));
159         offset += sizeof(phrase_token_t);
160
161         oldone->set_size(0); newone->set_size(0);
162
163         switch(log_type){
164         case LOG_ADD_RECORD:{
165             guint16 len = 0;
166             m_chunk->get_content(offset, &len, sizeof(guint16));
167             offset += sizeof(guint16);
168             newone->set_content(0, ((char *)m_chunk->begin()) + offset, len);
169             offset += len;
170             break;
171         }
172         case LOG_REMOVE_RECORD:{
173             guint16 len = 0;
174             m_chunk->get_content(offset, &len, sizeof(guint16));
175             offset += sizeof(guint16);
176             oldone->set_content(0, ((char *)m_chunk->begin()) + offset, len);
177             offset += len;
178             break;
179         }
180         case LOG_MODIFY_RECORD:{
181             guint16 oldlen = 0, newlen = 0;
182             m_chunk->get_content(offset, &oldlen, sizeof(guint16));
183             offset += sizeof(guint16);
184             m_chunk->get_content(offset, &newlen, sizeof(guint16));
185             offset += sizeof(guint16);
186             oldone->set_content(0, ((char *)m_chunk->begin()) + offset,
187                                 oldlen);
188             offset += oldlen;
189             newone->set_content(0, ((char *)m_chunk->begin()) + offset, newlen);
190             offset += newlen;
191             break;
192         }
193         case LOG_MODIFY_HEADER:{
194             assert(token == null_token);
195             guint16 len = 0;
196             m_chunk->get_content(offset, &len, sizeof(guint16));
197             offset += sizeof(guint16);
198             oldone->set_content(0, ((char *)m_chunk->begin()) + offset,
199                                 len);
200             offset += len;
201             newone->set_content(0, ((char *)m_chunk->begin()) + offset,
202                                 len);
203             offset += len;
204             break;
205         }
206         default:
207             assert(false);
208         }
209
210         m_offset = offset;
211         return true;
212     }
213
214     /**
215      * PhraseIndexLogger::append_record:
216      * @log_type: the type of this log record.
217      * @token: the token of this log record.
218      * @oldone: the original content of the phrase item.
219      * @newone: the new content of the phrase item.
220      *
221      * Append one log record to the logger.
222      *
223      */
224     bool append_record(LOG_TYPE log_type, phrase_token_t token,
225                        MemoryChunk * oldone, MemoryChunk * newone){
226
227         MemoryChunk chunk;
228         size_t offset = 0;
229         chunk.set_content(offset, &log_type, sizeof(LOG_TYPE));
230         offset += sizeof(LOG_TYPE);
231         chunk.set_content(offset, &token, sizeof(phrase_token_t));
232         offset += sizeof(phrase_token_t);
233
234         switch(log_type){
235         case LOG_ADD_RECORD:{
236             assert( NULL == oldone );
237             assert( NULL != newone );
238             /* use newone chunk */
239             guint16 len = newone->size();
240             chunk.set_content(offset, &len, sizeof(guint16));
241             offset += sizeof(guint16);
242             chunk.set_content(offset, newone->begin(), newone->size());
243             offset += newone->size();
244             break;
245         }
246         case LOG_REMOVE_RECORD:{
247             assert(NULL != oldone);
248             assert(NULL == newone);
249             /* use oldone chunk */
250             guint16 len = oldone->size();
251             chunk.set_content(offset, &len, sizeof(guint16));
252             offset += sizeof(guint16);
253             chunk.set_content(offset, oldone->begin(), oldone->size());
254             offset += oldone->size();
255             break;
256         }
257         case LOG_MODIFY_RECORD:{
258             assert(NULL != oldone);
259             assert(NULL != newone);
260             guint16 oldlen = oldone->size();
261             guint16 newlen = newone->size();
262             chunk.set_content(offset, &oldlen, sizeof(guint16));
263             offset += sizeof(guint16);
264             chunk.set_content(offset, &newlen, sizeof(guint16));
265             offset += sizeof(guint16);
266             chunk.set_content(offset, oldone->begin(), oldone->size());
267             offset += oldlen;
268             chunk.set_content(offset, newone->begin(), newone->size());
269             offset += newlen;
270             break;
271         }
272         case LOG_MODIFY_HEADER:{
273             assert(NULL != oldone);
274             assert(NULL != newone);
275             assert(null_token == token);
276             guint16 oldlen = oldone->size();
277             guint16 newlen = newone->size();
278             assert(oldlen == newlen);
279             chunk.set_content(offset, &oldlen, sizeof(guint16));
280             offset += sizeof(guint16);
281             chunk.set_content(offset, oldone->begin(), oldone->size());
282             offset += oldlen;
283             chunk.set_content(offset, newone->begin(), newone->size());
284             offset += newlen;
285             break;
286         }
287         default:
288             assert(false);
289         }
290
291         /* store log record. */
292         m_chunk->set_content(m_chunk->size(), chunk.begin(), chunk.size());
293         return true;
294     }
295 };
296
297 };
298
299 #endif