/* * libpinyin * Library to deal with pinyin. * * Copyright (C) 2011 Peng Wu * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef PHRASE_LOGGER_H #define PHRASE_LOGGER_H #include #include "novel_types.h" #include "memory_chunk.h" /** * File Format * Logger Record type: add/remove/modify * * Modify Header: header/null token/len/old data chunk/new data chunk * * Add Record: add/token/len/data chunk * Remove Record: remove/token/len/data chunk * Modify Record: modify/token/old len/new len/old data chunk/new data chunk * */ namespace pinyin{ enum LOG_TYPE{ LOG_INVALID_RECORD = 0, LOG_ADD_RECORD = 1, LOG_REMOVE_RECORD, LOG_MODIFY_RECORD, LOG_MODIFY_HEADER }; /** * PhraseIndexLogger: * * The logger of phrase index changes. * */ class PhraseIndexLogger{ protected: MemoryChunk * m_chunk; size_t m_offset; bool m_error; void reset(){ if ( m_chunk ){ delete m_chunk; m_chunk = NULL; } m_offset = 0; m_error = false; } public: /** * PhraseIndexLogger::PhraseIndexLogger: * * The constructor of the PhraseIndexLogger. * */ PhraseIndexLogger():m_offset(0), m_error(false){ m_chunk = new MemoryChunk; } /** * PhraseIndexLogger::~PhraseIndexLogger: * * The destructor of the PhraseIndexLogger. * */ ~PhraseIndexLogger(){ reset(); } /** * PhraseIndexLogger::load: * @chunk: the memory chunk of the logs. * @returns: whether the load operation is successful. * * Load the logs from the memory chunk. * */ bool load(MemoryChunk * chunk) { reset(); m_chunk = chunk; return true; } /** * PhraseIndexLogger::store: * @new_chunk: the new memory chunk to store the logs. * @returns: whether the store operation is successful. * * Store the logs to the new memory chunk. * */ bool store(MemoryChunk * new_chunk){ new_chunk->set_content(0, m_chunk->begin(), m_chunk->size()); return true; } /** * PhraseIndexLogger::has_next_record: * @returns: whether this logger has next record. * * Whether this logger has next record. * */ bool has_next_record(){ if (m_error) return false; return m_offset < m_chunk->size(); } /** * PhraseIndexLogger::rewind: * @returns: whether the rewind operation is successful. * * Rewind this logger to the begin of logs. * */ bool rewind(){ m_offset = 0; return true; } /** * PhraseIndexLogger::next_record: * @log_type: the type of this log record. * @token: the token of this log record. * @oldone: the original content of the phrase item. * @newone: the new content of the phrase item. * * Read the next log record. * * Prolog: has_next_record() returned true. * */ bool next_record(LOG_TYPE & log_type, phrase_token_t & token, MemoryChunk * oldone, MemoryChunk * newone){ log_type = LOG_INVALID_RECORD; token = null_token; size_t offset = m_offset; m_chunk->get_content(offset, &log_type, sizeof(LOG_TYPE)); offset += sizeof(LOG_TYPE); m_chunk->get_content(offset, &token, sizeof(phrase_token_t)); offset += sizeof(phrase_token_t); oldone->set_size(0); newone->set_size(0); switch(log_type){ case LOG_ADD_RECORD:{ guint16 len = 0; m_chunk->get_content(offset, &len, sizeof(guint16)); offset += sizeof(guint16); newone->set_content(0, ((char *)m_chunk->begin()) + offset, len); offset += len; break; } case LOG_REMOVE_RECORD:{ guint16 len = 0; m_chunk->get_content(offset, &len, sizeof(guint16)); offset += sizeof(guint16); oldone->set_content(0, ((char *)m_chunk->begin()) + offset, len); offset += len; break; } case LOG_MODIFY_RECORD:{ guint16 oldlen = 0, newlen = 0; m_chunk->get_content(offset, &oldlen, sizeof(guint16)); offset += sizeof(guint16); m_chunk->get_content(offset, &newlen, sizeof(guint16)); offset += sizeof(guint16); oldone->set_content(0, ((char *)m_chunk->begin()) + offset, oldlen); offset += oldlen; newone->set_content(0, ((char *)m_chunk->begin()) + offset, newlen); offset += newlen; break; } case LOG_MODIFY_HEADER:{ assert(token == null_token); guint16 len = 0; m_chunk->get_content(offset, &len, sizeof(guint16)); offset += sizeof(guint16); oldone->set_content(0, ((char *)m_chunk->begin()) + offset, len); offset += len; newone->set_content(0, ((char *)m_chunk->begin()) + offset, len); offset += len; break; } default: m_error = true; return false; } m_offset = offset; return true; } /** * PhraseIndexLogger::append_record: * @log_type: the type of this log record. * @token: the token of this log record. * @oldone: the original content of the phrase item. * @newone: the new content of the phrase item. * * Append one log record to the logger. * */ bool append_record(LOG_TYPE log_type, phrase_token_t token, MemoryChunk * oldone, MemoryChunk * newone){ MemoryChunk chunk; size_t offset = 0; chunk.set_content(offset, &log_type, sizeof(LOG_TYPE)); offset += sizeof(LOG_TYPE); chunk.set_content(offset, &token, sizeof(phrase_token_t)); offset += sizeof(phrase_token_t); switch(log_type){ case LOG_ADD_RECORD:{ assert( NULL == oldone ); assert( NULL != newone ); /* use newone chunk */ guint16 len = newone->size(); chunk.set_content(offset, &len, sizeof(guint16)); offset += sizeof(guint16); chunk.set_content(offset, newone->begin(), newone->size()); offset += newone->size(); break; } case LOG_REMOVE_RECORD:{ assert(NULL != oldone); assert(NULL == newone); /* use oldone chunk */ guint16 len = oldone->size(); chunk.set_content(offset, &len, sizeof(guint16)); offset += sizeof(guint16); chunk.set_content(offset, oldone->begin(), oldone->size()); offset += oldone->size(); break; } case LOG_MODIFY_RECORD:{ assert(NULL != oldone); assert(NULL != newone); guint16 oldlen = oldone->size(); guint16 newlen = newone->size(); chunk.set_content(offset, &oldlen, sizeof(guint16)); offset += sizeof(guint16); chunk.set_content(offset, &newlen, sizeof(guint16)); offset += sizeof(guint16); chunk.set_content(offset, oldone->begin(), oldone->size()); offset += oldlen; chunk.set_content(offset, newone->begin(), newone->size()); offset += newlen; break; } case LOG_MODIFY_HEADER:{ assert(NULL != oldone); assert(NULL != newone); assert(null_token == token); guint16 oldlen = oldone->size(); guint16 newlen = newone->size(); assert(oldlen == newlen); chunk.set_content(offset, &oldlen, sizeof(guint16)); offset += sizeof(guint16); chunk.set_content(offset, oldone->begin(), oldone->size()); offset += oldlen; chunk.set_content(offset, newone->begin(), newone->size()); offset += newlen; break; } default: assert(false); } /* store log record. */ m_chunk->set_content(m_chunk->size(), chunk.begin(), chunk.size()); return true; } }; }; #endif