From e5cfb776949eb8b9db8a01191aa1241ac22da0e4 Mon Sep 17 00:00:00 2001 From: Keisuke Kuroyanagi Date: Thu, 24 Oct 2013 17:28:30 -0700 Subject: [PATCH] Introduce ExclusiveOwnershipPointer. Bug: 11073222 Change-Id: I841527f0247f2ade07796406729b3a4a8958aa57 --- native/jni/Android.mk | 3 +- ...oid_inputmethod_latin_BinaryDictionary.cpp | 6 +- .../suggest/core/dictionary/dictionary.cpp | 38 +++---- .../src/suggest/core/dictionary/dictionary.h | 26 ++--- .../dictionary_structure_with_buffer_policy.h | 3 + ...y_structure_with_buffer_policy_factory.cpp | 32 +++--- ...ary_structure_with_buffer_policy_factory.h | 6 +- .../structure/v2/patricia_trie_policy.h | 16 ++- .../v3/dynamic_patricia_trie_policy.cpp | 12 +-- .../v3/dynamic_patricia_trie_policy.h | 19 ++-- .../dictionary/utils/mmapped_buffer.cpp | 99 +++++++++++++++++++ .../dictionary/utils/mmapped_buffer.h | 79 ++------------- .../src/utils/exclusive_ownership_pointer.h | 91 +++++++++++++++++ 13 files changed, 280 insertions(+), 150 deletions(-) create mode 100644 native/jni/src/suggest/policyimpl/dictionary/utils/mmapped_buffer.cpp create mode 100644 native/jni/src/utils/exclusive_ownership_pointer.h diff --git a/native/jni/Android.mk b/native/jni/Android.mk index 280d99669..c83ae065a 100644 --- a/native/jni/Android.mk +++ b/native/jni/Android.mk @@ -91,7 +91,8 @@ LATIN_IME_CORE_SRC_FILES := \ byte_array_utils.cpp \ dict_file_writing_utils.cpp \ forgetting_curve_utils.cpp \ - format_utils.cpp) \ + format_utils.cpp \ + mmapped_buffer.cpp) \ suggest/policyimpl/gesture/gesture_suggest_policy_factory.cpp \ $(addprefix suggest/policyimpl/typing/, \ scoring_params.cpp \ diff --git a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp index f623b8d9d..3becc7e39 100644 --- a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp +++ b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp @@ -86,11 +86,11 @@ static jlong latinime_BinaryDictionary_open(JNIEnv *env, jclass clazz, jstring s char sourceDirChars[sourceDirUtf8Length + 1]; env->GetStringUTFRegion(sourceDir, 0, env->GetStringLength(sourceDir), sourceDirChars); sourceDirChars[sourceDirUtf8Length] = '\0'; - DictionaryStructureWithBufferPolicy *const dictionaryStructureWithBufferPolicy = + DictionaryStructureWithBufferPolicy::StructurePoilcyPtr dictionaryStructureWithBufferPolicy( DictionaryStructureWithBufferPolicyFactory::newDictionaryStructureWithBufferPolicy( sourceDirChars, static_cast(dictOffset), static_cast(dictSize), - isUpdatable == JNI_TRUE); - if (!dictionaryStructureWithBufferPolicy) { + isUpdatable == JNI_TRUE)); + if (!dictionaryStructureWithBufferPolicy.get()) { return 0; } diff --git a/native/jni/src/suggest/core/dictionary/dictionary.cpp b/native/jni/src/suggest/core/dictionary/dictionary.cpp index 264b46056..7b83f27df 100644 --- a/native/jni/src/suggest/core/dictionary/dictionary.cpp +++ b/native/jni/src/suggest/core/dictionary/dictionary.cpp @@ -21,9 +21,7 @@ #include #include "defines.h" -#include "suggest/core/dictionary/bigram_dictionary.h" #include "suggest/core/policy/dictionary_header_structure_policy.h" -#include "suggest/core/policy/dictionary_structure_with_buffer_policy.h" #include "suggest/core/session/dic_traverse_session.h" #include "suggest/core/suggest.h" #include "suggest/core/suggest_options.h" @@ -35,22 +33,15 @@ namespace latinime { const int Dictionary::HEADER_ATTRIBUTE_BUFFER_SIZE = 32; -Dictionary::Dictionary(JNIEnv *env, - DictionaryStructureWithBufferPolicy *const dictionaryStructureWithBufferPolicy) +Dictionary::Dictionary(JNIEnv *env, const DictionaryStructureWithBufferPolicy::StructurePoilcyPtr + &dictionaryStructureWithBufferPolicy) : mDictionaryStructureWithBufferPolicy(dictionaryStructureWithBufferPolicy), - mBigramDictionary(new BigramDictionary(mDictionaryStructureWithBufferPolicy)), + mBigramDictionary(new BigramDictionary(mDictionaryStructureWithBufferPolicy.get())), mGestureSuggest(new Suggest(GestureSuggestPolicyFactory::getGestureSuggestPolicy())), mTypingSuggest(new Suggest(TypingSuggestPolicyFactory::getTypingSuggestPolicy())) { logDictionaryInfo(env); } -Dictionary::~Dictionary() { - delete mBigramDictionary; - delete mGestureSuggest; - delete mTypingSuggest; - delete mDictionaryStructureWithBufferPolicy; -} - int Dictionary::getSuggestions(ProximityInfo *proximityInfo, DicTraverseSession *traverseSession, int *xcoordinates, int *ycoordinates, int *times, int *pointerIds, int *inputCodePoints, int inputSize, int *prevWordCodePoints, int prevWordLength, int commitPoint, @@ -60,7 +51,7 @@ int Dictionary::getSuggestions(ProximityInfo *proximityInfo, DicTraverseSession if (suggestOptions->isGesture()) { DicTraverseSession::initSessionInstance( traverseSession, this, prevWordCodePoints, prevWordLength, suggestOptions); - result = mGestureSuggest->getSuggestions(proximityInfo, traverseSession, xcoordinates, + result = mGestureSuggest.get()->getSuggestions(proximityInfo, traverseSession, xcoordinates, ycoordinates, times, pointerIds, inputCodePoints, inputSize, commitPoint, outWords, frequencies, spaceIndices, outputTypes, outputAutoCommitFirstWordConfidence); if (DEBUG_DICT) { @@ -70,7 +61,7 @@ int Dictionary::getSuggestions(ProximityInfo *proximityInfo, DicTraverseSession } else { DicTraverseSession::initSessionInstance( traverseSession, this, prevWordCodePoints, prevWordLength, suggestOptions); - result = mTypingSuggest->getSuggestions(proximityInfo, traverseSession, xcoordinates, + result = mTypingSuggest.get()->getSuggestions(proximityInfo, traverseSession, xcoordinates, ycoordinates, times, pointerIds, inputCodePoints, inputSize, commitPoint, outWords, frequencies, spaceIndices, outputTypes, outputAutoCommitFirstWordConfidence); @@ -84,7 +75,8 @@ int Dictionary::getSuggestions(ProximityInfo *proximityInfo, DicTraverseSession int Dictionary::getBigrams(const int *word, int length, int *outWords, int *frequencies, int *outputTypes) const { if (length <= 0) return 0; - return mBigramDictionary->getPredictions(word, length, outWords, frequencies, outputTypes); + return mBigramDictionary.get()->getPredictions(word, length, outWords, frequencies, + outputTypes); } int Dictionary::getProbability(const int *word, int length) const { @@ -98,39 +90,39 @@ int Dictionary::getProbability(const int *word, int length) const { int Dictionary::getBigramProbability(const int *word0, int length0, const int *word1, int length1) const { - return mBigramDictionary->getBigramProbability(word0, length0, word1, length1); + return mBigramDictionary.get()->getBigramProbability(word0, length0, word1, length1); } void Dictionary::addUnigramWord(const int *const word, const int length, const int probability) { - mDictionaryStructureWithBufferPolicy->addUnigramWord(word, length, probability); + mDictionaryStructureWithBufferPolicy.get()->addUnigramWord(word, length, probability); } void Dictionary::addBigramWords(const int *const word0, const int length0, const int *const word1, const int length1, const int probability) { - mDictionaryStructureWithBufferPolicy->addBigramWords(word0, length0, word1, length1, + mDictionaryStructureWithBufferPolicy.get()->addBigramWords(word0, length0, word1, length1, probability); } void Dictionary::removeBigramWords(const int *const word0, const int length0, const int *const word1, const int length1) { - mDictionaryStructureWithBufferPolicy->removeBigramWords(word0, length0, word1, length1); + mDictionaryStructureWithBufferPolicy.get()->removeBigramWords(word0, length0, word1, length1); } void Dictionary::flush(const char *const filePath) { - mDictionaryStructureWithBufferPolicy->flush(filePath); + mDictionaryStructureWithBufferPolicy.get()->flush(filePath); } void Dictionary::flushWithGC(const char *const filePath) { - mDictionaryStructureWithBufferPolicy->flushWithGC(filePath); + mDictionaryStructureWithBufferPolicy.get()->flushWithGC(filePath); } bool Dictionary::needsToRunGC(const bool mindsBlockByGC) { - return mDictionaryStructureWithBufferPolicy->needsToRunGC(mindsBlockByGC); + return mDictionaryStructureWithBufferPolicy.get()->needsToRunGC(mindsBlockByGC); } void Dictionary::getProperty(const char *const query, char *const outResult, const int maxResultLength) { - return mDictionaryStructureWithBufferPolicy->getProperty(query, outResult, maxResultLength); + return mDictionaryStructureWithBufferPolicy.get()->getProperty(query, outResult, maxResultLength); } void Dictionary::logDictionaryInfo(JNIEnv *const env) const { diff --git a/native/jni/src/suggest/core/dictionary/dictionary.h b/native/jni/src/suggest/core/dictionary/dictionary.h index 0195d5bf0..e52a40f1d 100644 --- a/native/jni/src/suggest/core/dictionary/dictionary.h +++ b/native/jni/src/suggest/core/dictionary/dictionary.h @@ -21,14 +21,16 @@ #include "defines.h" #include "jni.h" +#include "suggest/core/dictionary/bigram_dictionary.h" +#include "suggest/core/policy/dictionary_structure_with_buffer_policy.h" +#include "suggest/core/suggest_interface.h" +#include "utils/exclusive_ownership_pointer.h" namespace latinime { -class BigramDictionary; class DictionaryStructureWithBufferPolicy; class DicTraverseSession; class ProximityInfo; -class SuggestInterface; class SuggestOptions; class Dictionary { @@ -53,8 +55,8 @@ class Dictionary { static const int KIND_FLAG_POSSIBLY_OFFENSIVE = 0x80000000; static const int KIND_FLAG_EXACT_MATCH = 0x40000000; - Dictionary(JNIEnv *env, - DictionaryStructureWithBufferPolicy *const dictionaryStructureWithBufferPoilcy); + Dictionary(JNIEnv *env, const DictionaryStructureWithBufferPolicy::StructurePoilcyPtr + &dictionaryStructureWithBufferPoilcy); int getSuggestions(ProximityInfo *proximityInfo, DicTraverseSession *traverseSession, int *xcoordinates, int *ycoordinates, int *times, int *pointerIds, int *inputCodePoints, @@ -87,20 +89,22 @@ class Dictionary { const int maxResultLength); const DictionaryStructureWithBufferPolicy *getDictionaryStructurePolicy() const { - return mDictionaryStructureWithBufferPolicy; + return mDictionaryStructureWithBufferPolicy.get(); } - virtual ~Dictionary(); - private: DISALLOW_IMPLICIT_CONSTRUCTORS(Dictionary); + typedef ExclusiveOwnershipPointer BigramDictionaryPtr; + typedef ExclusiveOwnershipPointer SuggestInterfacePtr; + static const int HEADER_ATTRIBUTE_BUFFER_SIZE; - DictionaryStructureWithBufferPolicy *const mDictionaryStructureWithBufferPolicy; - const BigramDictionary *const mBigramDictionary; - const SuggestInterface *const mGestureSuggest; - const SuggestInterface *const mTypingSuggest; + const DictionaryStructureWithBufferPolicy::StructurePoilcyPtr + mDictionaryStructureWithBufferPolicy; + const BigramDictionaryPtr mBigramDictionary; + const SuggestInterfacePtr mGestureSuggest; + const SuggestInterfacePtr mTypingSuggest; void logDictionaryInfo(JNIEnv *const env) const; }; diff --git a/native/jni/src/suggest/core/policy/dictionary_structure_with_buffer_policy.h b/native/jni/src/suggest/core/policy/dictionary_structure_with_buffer_policy.h index 610de48ab..e649844dc 100644 --- a/native/jni/src/suggest/core/policy/dictionary_structure_with_buffer_policy.h +++ b/native/jni/src/suggest/core/policy/dictionary_structure_with_buffer_policy.h @@ -18,6 +18,7 @@ #define LATINIME_DICTIONARY_STRUCTURE_POLICY_H #include "defines.h" +#include "utils/exclusive_ownership_pointer.h" namespace latinime { @@ -33,6 +34,8 @@ class DictionaryShortcutsStructurePolicy; */ class DictionaryStructureWithBufferPolicy { public: + typedef ExclusiveOwnershipPointer StructurePoilcyPtr; + virtual ~DictionaryStructureWithBufferPolicy() {} virtual int getRootPosition() const = 0; diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/dictionary_structure_with_buffer_policy_factory.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/dictionary_structure_with_buffer_policy_factory.cpp index baa9cf142..81783b53e 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/structure/dictionary_structure_with_buffer_policy_factory.cpp +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/dictionary_structure_with_buffer_policy_factory.cpp @@ -26,30 +26,32 @@ namespace latinime { -/* static */ DictionaryStructureWithBufferPolicy *DictionaryStructureWithBufferPolicyFactory - ::newDictionaryStructureWithBufferPolicy(const char *const path, const int bufOffset, - const int size, const bool isUpdatable) { - // Allocated buffer in MmapedBuffer::openBuffer() will be freed in the destructor of - // impl classes of DictionaryStructureWithBufferPolicy. - const MmappedBuffer *const mmapedBuffer = MmappedBuffer::openBuffer(path, bufOffset, size, - isUpdatable); - if (!mmapedBuffer) { - return 0; +/* static */ DictionaryStructureWithBufferPolicy::StructurePoilcyPtr + DictionaryStructureWithBufferPolicyFactory + ::newDictionaryStructureWithBufferPolicy(const char *const path, + const int bufOffset, const int size, const bool isUpdatable) { + // Allocated buffer in MmapedBuffer::newBuffer() will be freed in the destructor of + // MmappedBufferWrapper if the instance has the responsibility. + MmappedBuffer::MmappedBufferPtr mmappedBuffer(MmappedBuffer::openBuffer(path, bufOffset, size, + isUpdatable)); + if (!mmappedBuffer.get()) { + return DictionaryStructureWithBufferPolicy::StructurePoilcyPtr(0); } - switch (FormatUtils::detectFormatVersion(mmapedBuffer->getBuffer(), - mmapedBuffer->getBufferSize())) { + switch (FormatUtils::detectFormatVersion(mmappedBuffer.get()->getBuffer(), + mmappedBuffer.get()->getBufferSize())) { case FormatUtils::VERSION_2: - return new PatriciaTriePolicy(mmapedBuffer); + return DictionaryStructureWithBufferPolicy::StructurePoilcyPtr( + new PatriciaTriePolicy(mmappedBuffer)); case FormatUtils::VERSION_3: - return new DynamicPatriciaTriePolicy(mmapedBuffer); + return DictionaryStructureWithBufferPolicy::StructurePoilcyPtr( + new DynamicPatriciaTriePolicy(mmappedBuffer)); case FormatUtils::VERSION_4: // TODO: Support version 4 dictionary format. // Fall through. default: AKLOGE("DICT: dictionary format is unknown, bad magic number"); - delete mmapedBuffer; ASSERT(false); - return 0; + return DictionaryStructureWithBufferPolicy::StructurePoilcyPtr(0); } } diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/dictionary_structure_with_buffer_policy_factory.h b/native/jni/src/suggest/policyimpl/dictionary/structure/dictionary_structure_with_buffer_policy_factory.h index 8cebc3b16..1359575f1 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/structure/dictionary_structure_with_buffer_policy_factory.h +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/dictionary_structure_with_buffer_policy_factory.h @@ -21,13 +21,15 @@ #include "defines.h" #include "suggest/core/policy/dictionary_structure_with_buffer_policy.h" +#include "utils/exclusive_ownership_pointer.h" namespace latinime { class DictionaryStructureWithBufferPolicyFactory { public: - static DictionaryStructureWithBufferPolicy *newDictionaryStructureWithBufferPolicy( - const char *const path, const int bufOffset, const int size, const bool isUpdatable); + static DictionaryStructureWithBufferPolicy::StructurePoilcyPtr + newDictionaryStructureWithBufferPolicy(const char *const path, const int bufOffset, + const int size, const bool isUpdatable); private: DISALLOW_IMPLICIT_CONSTRUCTORS(DictionaryStructureWithBufferPolicyFactory); diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.h index 31e6186b7..5d99632a5 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.h +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.h @@ -34,16 +34,14 @@ class DicNodeVector; class PatriciaTriePolicy : public DictionaryStructureWithBufferPolicy { public: - PatriciaTriePolicy(const MmappedBuffer *const buffer) - : mBuffer(buffer), mHeaderPolicy(mBuffer->getBuffer(), FormatUtils::VERSION_2), - mDictRoot(mBuffer->getBuffer() + mHeaderPolicy.getSize()), - mDictBufferSize(mBuffer->getBufferSize() - mHeaderPolicy.getSize()), + PatriciaTriePolicy(const MmappedBuffer::MmappedBufferPtr &mmappedBuffer) + : mMmappedBuffer(mmappedBuffer), + mHeaderPolicy(mMmappedBuffer.get()->getBuffer(), FormatUtils::VERSION_2), + mDictRoot(mMmappedBuffer.get()->getBuffer() + mHeaderPolicy.getSize()), + mDictBufferSize(mMmappedBuffer.get()->getBufferSize() + - mHeaderPolicy.getSize()), mBigramListPolicy(mDictRoot), mShortcutListPolicy(mDictRoot) {} - ~PatriciaTriePolicy() { - delete mBuffer; - } - AK_FORCE_INLINE int getRootPosition() const { return 0; } @@ -125,7 +123,7 @@ class PatriciaTriePolicy : public DictionaryStructureWithBufferPolicy { private: DISALLOW_IMPLICIT_CONSTRUCTORS(PatriciaTriePolicy); - const MmappedBuffer *const mBuffer; + const MmappedBuffer::MmappedBufferPtr mMmappedBuffer; const HeaderPolicy mHeaderPolicy; const uint8_t *const mDictRoot; const int mDictBufferSize; diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v3/dynamic_patricia_trie_policy.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v3/dynamic_patricia_trie_policy.cpp index 246458d09..b9d4739da 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/structure/v3/dynamic_patricia_trie_policy.cpp +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v3/dynamic_patricia_trie_policy.cpp @@ -216,7 +216,7 @@ int DynamicPatriciaTriePolicy::getBigramsPositionOfPtNode(const int ptNodePos) c bool DynamicPatriciaTriePolicy::addUnigramWord(const int *const word, const int length, const int probability) { - if (!mBuffer->isUpdatable()) { + if (!mMmappedBuffer.get()->isUpdatable()) { AKLOGI("Warning: addUnigramWord() is called for non-updatable dictionary."); return false; } @@ -244,7 +244,7 @@ bool DynamicPatriciaTriePolicy::addUnigramWord(const int *const word, const int bool DynamicPatriciaTriePolicy::addBigramWords(const int *const word0, const int length0, const int *const word1, const int length1, const int probability) { - if (!mBuffer->isUpdatable()) { + if (!mMmappedBuffer.get()->isUpdatable()) { AKLOGI("Warning: addBigramWords() is called for non-updatable dictionary."); return false; } @@ -278,7 +278,7 @@ bool DynamicPatriciaTriePolicy::addBigramWords(const int *const word0, const int bool DynamicPatriciaTriePolicy::removeBigramWords(const int *const word0, const int length0, const int *const word1, const int length1) { - if (!mBuffer->isUpdatable()) { + if (!mMmappedBuffer.get()->isUpdatable()) { AKLOGI("Warning: removeBigramWords() is called for non-updatable dictionary."); return false; } @@ -308,7 +308,7 @@ bool DynamicPatriciaTriePolicy::removeBigramWords(const int *const word0, const } void DynamicPatriciaTriePolicy::flush(const char *const filePath) { - if (!mBuffer->isUpdatable()) { + if (!mMmappedBuffer.get()->isUpdatable()) { AKLOGI("Warning: flush() is called for non-updatable dictionary."); return; } @@ -318,7 +318,7 @@ void DynamicPatriciaTriePolicy::flush(const char *const filePath) { } void DynamicPatriciaTriePolicy::flushWithGC(const char *const filePath) { - if (!mBuffer->isUpdatable()) { + if (!mMmappedBuffer.get()->isUpdatable()) { AKLOGI("Warning: flushWithGC() is called for non-updatable dictionary."); return; } @@ -334,7 +334,7 @@ void DynamicPatriciaTriePolicy::flushWithGC(const char *const filePath) { } bool DynamicPatriciaTriePolicy::needsToRunGC(const bool mindsBlockByGC) const { - if (!mBuffer->isUpdatable()) { + if (!mMmappedBuffer.get()->isUpdatable()) { AKLOGI("Warning: needsToRunGC() is called for non-updatable dictionary."); return false; } diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v3/dynamic_patricia_trie_policy.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v3/dynamic_patricia_trie_policy.h index 1a924c177..6a7f91ef6 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/structure/v3/dynamic_patricia_trie_policy.h +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v3/dynamic_patricia_trie_policy.h @@ -33,21 +33,20 @@ class DicNodeVector; class DynamicPatriciaTriePolicy : public DictionaryStructureWithBufferPolicy { public: - DynamicPatriciaTriePolicy(const MmappedBuffer *const buffer) - : mBuffer(buffer), mHeaderPolicy(mBuffer->getBuffer(), FormatUtils::VERSION_3), - mBufferWithExtendableBuffer(mBuffer->getBuffer() + mHeaderPolicy.getSize(), - mBuffer->getBufferSize() - mHeaderPolicy.getSize(), - BufferWithExtendableBuffer::DEFAULT_MAX_ADDITIONAL_BUFFER_SIZE), + DynamicPatriciaTriePolicy(const MmappedBuffer::MmappedBufferPtr &mmappedBuffer) + : mMmappedBuffer(mmappedBuffer), + mHeaderPolicy(mMmappedBuffer.get()->getBuffer(), FormatUtils::VERSION_3), + mBufferWithExtendableBuffer(mMmappedBuffer.get()->getBuffer() + + mHeaderPolicy.getSize(), mMmappedBuffer.get()->getBufferSize() + - mHeaderPolicy.getSize(), + BufferWithExtendableBuffer + ::DEFAULT_MAX_ADDITIONAL_BUFFER_SIZE), mShortcutListPolicy(&mBufferWithExtendableBuffer), mBigramListPolicy(&mHeaderPolicy, &mBufferWithExtendableBuffer, &mShortcutListPolicy, mHeaderPolicy.isDecayingDict()), mUnigramCount(mHeaderPolicy.getUnigramCount()), mBigramCount(mHeaderPolicy.getBigramCount()), mNeedsToDecayForTesting(false) {} - ~DynamicPatriciaTriePolicy() { - delete mBuffer; - } - AK_FORCE_INLINE int getRootPosition() const { return 0; } @@ -110,7 +109,7 @@ class DynamicPatriciaTriePolicy : public DictionaryStructureWithBufferPolicy { static const int MAX_DICT_EXTENDED_REGION_SIZE; static const int MIN_DICT_SIZE_TO_REFUSE_DYNAMIC_OPERATIONS; - const MmappedBuffer *const mBuffer; + const MmappedBuffer::MmappedBufferPtr mMmappedBuffer; const HeaderPolicy mHeaderPolicy; BufferWithExtendableBuffer mBufferWithExtendableBuffer; DynamicShortcutListPolicy mShortcutListPolicy; diff --git a/native/jni/src/suggest/policyimpl/dictionary/utils/mmapped_buffer.cpp b/native/jni/src/suggest/policyimpl/dictionary/utils/mmapped_buffer.cpp new file mode 100644 index 000000000..71f863290 --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/utils/mmapped_buffer.cpp @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2013, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "suggest/policyimpl/dictionary/utils/mmapped_buffer.h" + +#include +#include +#include +#include +#include +#include + +#include "suggest/policyimpl/dictionary/utils/file_utils.h" + +namespace latinime { + +/* static */ MmappedBuffer::MmappedBufferPtr MmappedBuffer::openBuffer( + const char *const path, const int bufferOffset, const int bufferSize, + const bool isUpdatable) { + const int openMode = isUpdatable ? O_RDWR : O_RDONLY; + const int mmapFd = open(path, openMode); + if (mmapFd < 0) { + AKLOGE("DICT: Can't open the source. path=%s errno=%d", path, errno); + return MmappedBufferPtr(0); + } + const int pagesize = getpagesize(); + const int offset = bufferOffset % pagesize; + int alignedOffset = bufferOffset - offset; + int alignedSize = bufferSize + offset; + const int protMode = isUpdatable ? PROT_READ | PROT_WRITE : PROT_READ; + void *const mmappedBuffer = mmap(0, alignedSize, protMode, MAP_PRIVATE, mmapFd, + alignedOffset); + if (mmappedBuffer == MAP_FAILED) { + AKLOGE("DICT: Can't mmap dictionary. errno=%d", errno); + close(mmapFd); + return MmappedBufferPtr(0); + } + uint8_t *const buffer = static_cast(mmappedBuffer) + offset; + if (!buffer) { + AKLOGE("DICT: buffer is null"); + close(mmapFd); + return MmappedBufferPtr(0); + } + return MmappedBufferPtr(new MmappedBuffer(buffer, bufferSize, mmappedBuffer, alignedSize, + mmapFd, isUpdatable)); +} + +/* static */ MmappedBuffer::MmappedBufferPtr MmappedBuffer::openBuffer( + const char *const path, const bool isUpdatable) { + const int fileSize = FileUtils::getFileSize(path); + if (fileSize == -1) { + return MmappedBufferPtr(0); + } else if (fileSize == 0) { + return MmappedBufferPtr(new MmappedBuffer(isUpdatable)); + } else { + return openBuffer(path, 0 /* bufferOffset */, fileSize, isUpdatable); + } +} + +/* static */ MmappedBuffer::MmappedBufferPtr MmappedBuffer::openBuffer( + const char *const dirPath, const char *const fileName, const bool isUpdatable) { + const int filePathBufferSize = PATH_MAX + 1 /* terminator */; + char filePath[filePathBufferSize]; + const int filePathLength = snprintf(filePath, filePathBufferSize, "%s%s", dirPath, + fileName); + if (filePathLength >= filePathBufferSize) { + return 0; + } + return openBuffer(filePath, isUpdatable); +} + +MmappedBuffer::~MmappedBuffer() { + if (mAlignedSize == 0) { + return; + } + int ret = munmap(mMmappedBuffer, mAlignedSize); + if (ret != 0) { + AKLOGE("DICT: Failure in munmap. ret=%d errno=%d", ret, errno); + } + ret = close(mMmapFd); + if (ret != 0) { + AKLOGE("DICT: Failure in close. ret=%d errno=%d", ret, errno); + } +} + +} // namespace latinime diff --git a/native/jni/src/suggest/policyimpl/dictionary/utils/mmapped_buffer.h b/native/jni/src/suggest/policyimpl/dictionary/utils/mmapped_buffer.h index 82138355d..73a733b0c 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/utils/mmapped_buffer.h +++ b/native/jni/src/suggest/policyimpl/dictionary/utils/mmapped_buffer.h @@ -17,88 +17,27 @@ #ifndef LATINIME_MMAPPED_BUFFER_H #define LATINIME_MMAPPED_BUFFER_H -#include -#include -#include -#include #include -#include -#include #include "defines.h" -#include "suggest/policyimpl/dictionary/utils/file_utils.h" +#include "utils/exclusive_ownership_pointer.h" namespace latinime { class MmappedBuffer { public: - static MmappedBuffer *openBuffer(const char *const path, const int bufferOffset, - const int bufferSize, const bool isUpdatable) { - const int openMode = isUpdatable ? O_RDWR : O_RDONLY; - const int mmapFd = open(path, openMode); - if (mmapFd < 0) { - AKLOGE("DICT: Can't open the source. path=%s errno=%d", path, errno); - return 0; - } - const int pagesize = getpagesize(); - const int offset = bufferOffset % pagesize; - int alignedOffset = bufferOffset - offset; - int alignedSize = bufferSize + offset; - const int protMode = isUpdatable ? PROT_READ | PROT_WRITE : PROT_READ; - void *const mmappedBuffer = mmap(0, alignedSize, protMode, MAP_PRIVATE, mmapFd, - alignedOffset); - if (mmappedBuffer == MAP_FAILED) { - AKLOGE("DICT: Can't mmap dictionary. errno=%d", errno); - close(mmapFd); - return 0; - } - uint8_t *const buffer = static_cast(mmappedBuffer) + offset; - if (!buffer) { - AKLOGE("DICT: buffer is null"); - close(mmapFd); - return 0; - } - return new MmappedBuffer(buffer, bufferSize, mmappedBuffer, alignedSize, mmapFd, - isUpdatable); - } + typedef ExclusiveOwnershipPointer MmappedBufferPtr; + + static MmappedBufferPtr openBuffer(const char *const path, + const int bufferOffset, const int bufferSize, const bool isUpdatable); // Mmap entire file. - static MmappedBuffer *openBuffer(const char *const path, const bool isUpdatable) { - const int fileSize = FileUtils::getFileSize(path); - if (fileSize == -1) { - return 0; - } else if (fileSize == 0) { - return new MmappedBuffer(isUpdatable); - } else { - return openBuffer(path, 0 /* bufferOffset */, fileSize, isUpdatable); - } - } + static MmappedBufferPtr openBuffer(const char *const path, const bool isUpdatable); - static MmappedBuffer *openBuffer(const char *const dirPath, const char *const fileName, - const bool isUpdatable) { - const int filePathBufferSize = PATH_MAX + 1 /* terminator */; - char filePath[filePathBufferSize]; - const int filePathLength = snprintf(filePath, filePathBufferSize, "%s%s", dirPath, - fileName); - if (filePathLength >= filePathBufferSize) { - return 0; - } - return openBuffer(filePath, isUpdatable); - } + static MmappedBufferPtr openBuffer(const char *const dirPath, const char *const fileName, + const bool isUpdatable); - ~MmappedBuffer() { - if (mAlignedSize == 0) { - return; - } - int ret = munmap(mMmappedBuffer, mAlignedSize); - if (ret != 0) { - AKLOGE("DICT: Failure in munmap. ret=%d errno=%d", ret, errno); - } - ret = close(mMmapFd); - if (ret != 0) { - AKLOGE("DICT: Failure in close. ret=%d errno=%d", ret, errno); - } - } + ~MmappedBuffer(); AK_FORCE_INLINE uint8_t *getBuffer() const { return mBuffer; diff --git a/native/jni/src/utils/exclusive_ownership_pointer.h b/native/jni/src/utils/exclusive_ownership_pointer.h new file mode 100644 index 000000000..3cf78954a --- /dev/null +++ b/native/jni/src/utils/exclusive_ownership_pointer.h @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2013, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LATINIME_EXCLUSIVE_OWNERSHIP_POINTER_H +#define LATINIME_EXCLUSIVE_OWNERSHIP_POINTER_H + +#include "defines.h" + +namespace latinime { + +template +class ExclusiveOwnershipPointer { + public: + // This instance become an owner of the raw pointer. + ExclusiveOwnershipPointer(T *const rawPointer) + : mPointer(rawPointer), + mSharedOwnerPtr(new (ExclusiveOwnershipPointer *)(this)) {} + + // Move the ownership. + ExclusiveOwnershipPointer(const ExclusiveOwnershipPointer &pointer) + : mPointer(pointer.mPointer), mSharedOwnerPtr(pointer.mSharedOwnerPtr) { + transferOwnership(&pointer); + } + + ~ExclusiveOwnershipPointer() { + deletePointersIfHavingOwnership(); + } + + // Move the ownership. + ExclusiveOwnershipPointer &operator=(const ExclusiveOwnershipPointer &pointer) { + // Delete pointers when this is an owner of another pointer. + deletePointersIfHavingOwnership(); + mPointer = pointer.mPointer; + mSharedOwnerPtr = pointer.mSharedOwnerPtr; + transferOwnership(pointer); + return *this; + } + + T *get() const { + return mPointer; + } + + private: + // This class allows to copy and assign and ensures only one instance has the ownership of the + // managed pointer. + + ExclusiveOwnershipPointer() : mPointer(0), mSharedOwnerPtr(0) {} + + void transferOwnership(const ExclusiveOwnershipPointer *const src) { + if (*mSharedOwnerPtr != src) { + AKLOGE("Failed to transfer the ownership because src is not the current owner." + "src: %p, owner: %p", src, *mSharedOwnerPtr); + ASSERT(false); + return; + } + // Transfer the ownership from src to this instance. + *mSharedOwnerPtr = this; + } + + void deletePointersIfHavingOwnership() { + if (mSharedOwnerPtr && *mSharedOwnerPtr == this) { + if (mPointer) { + if (DEBUG_DICT) { + AKLOGI("Releasing pointer: %p", mPointer); + } + delete mPointer; + } + delete mSharedOwnerPtr; + } + } + + T *mPointer; + // mSharedOwnerPtr points a shared memory space where the instance which has the ownership is + // stored. + ExclusiveOwnershipPointer **mSharedOwnerPtr; +}; +} // namespace latinime +#endif /* LATINIME_EXCLUSIVE_OWNERSHIP_POINTER_H */