Index: third_party/android_prediction/suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.cpp |
diff --git a/third_party/android_prediction/suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.cpp b/third_party/android_prediction/suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..3ab4ba84b9428df43c8da428ac113b87ade22cdd |
--- /dev/null |
+++ b/third_party/android_prediction/suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.cpp |
@@ -0,0 +1,168 @@ |
+/* |
+ * 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 "third_party/android_prediction/suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h" |
+ |
+namespace latinime { |
+ |
+const size_t BufferWithExtendableBuffer::DEFAULT_MAX_ADDITIONAL_BUFFER_SIZE = 1024 * 1024; |
+const int BufferWithExtendableBuffer::NEAR_BUFFER_LIMIT_THRESHOLD_PERCENTILE = 90; |
+// TODO: Needs to allocate larger memory corresponding to the current vector size. |
+const size_t BufferWithExtendableBuffer::EXTEND_ADDITIONAL_BUFFER_SIZE_STEP = 128 * 1024; |
+ |
+uint32_t BufferWithExtendableBuffer::readUint(const int size, const int pos) const { |
+ const bool readingPosIsInAdditionalBuffer = isInAdditionalBuffer(pos); |
+ const int posInBuffer = readingPosIsInAdditionalBuffer ? pos - mOriginalBuffer.size() : pos; |
+ return ByteArrayUtils::readUint(getBuffer(readingPosIsInAdditionalBuffer), size, posInBuffer); |
+} |
+ |
+uint32_t BufferWithExtendableBuffer::readUintAndAdvancePosition(const int size, |
+ int *const pos) const { |
+ const int value = readUint(size, *pos); |
+ *pos += size; |
+ return value; |
+} |
+ |
+void BufferWithExtendableBuffer::readCodePointsAndAdvancePosition(const int maxCodePointCount, |
+ int *const outCodePoints, int *outCodePointCount, int *const pos) const { |
+ const bool readingPosIsInAdditionalBuffer = isInAdditionalBuffer(*pos); |
+ if (readingPosIsInAdditionalBuffer) { |
+ *pos -= mOriginalBuffer.size(); |
+ } |
+ *outCodePointCount = ByteArrayUtils::readStringAndAdvancePosition( |
+ getBuffer(readingPosIsInAdditionalBuffer), maxCodePointCount, outCodePoints, pos); |
+ if (readingPosIsInAdditionalBuffer) { |
+ *pos += mOriginalBuffer.size(); |
+ } |
+} |
+ |
+bool BufferWithExtendableBuffer::extend(const int size) { |
+ return checkAndPrepareWriting(getTailPosition(), size); |
+} |
+ |
+bool BufferWithExtendableBuffer::writeUint(const uint32_t data, const int size, const int pos) { |
+ int writingPos = pos; |
+ return writeUintAndAdvancePosition(data, size, &writingPos); |
+} |
+ |
+bool BufferWithExtendableBuffer::writeUintAndAdvancePosition(const uint32_t data, const int size, |
+ int *const pos) { |
+ if (!(size >= 1 && size <= 4)) { |
+ AKLOGI("writeUintAndAdvancePosition() is called with invalid size: %d", size); |
+ ASSERT(false); |
+ return false; |
+ } |
+ if (!checkAndPrepareWriting(*pos, size)) { |
+ return false; |
+ } |
+ const bool usesAdditionalBuffer = isInAdditionalBuffer(*pos); |
+ uint8_t *const buffer = |
+ usesAdditionalBuffer ? mAdditionalBuffer.data() : mOriginalBuffer.data(); |
+ if (usesAdditionalBuffer) { |
+ *pos -= mOriginalBuffer.size(); |
+ } |
+ ByteArrayUtils::writeUintAndAdvancePosition(buffer, data, size, pos); |
+ if (usesAdditionalBuffer) { |
+ *pos += mOriginalBuffer.size(); |
+ } |
+ return true; |
+} |
+ |
+bool BufferWithExtendableBuffer::writeCodePointsAndAdvancePosition(const int *const codePoints, |
+ const int codePointCount, const bool writesTerminator, int *const pos) { |
+ const size_t size = ByteArrayUtils::calculateRequiredByteCountToStoreCodePoints( |
+ codePoints, codePointCount, writesTerminator); |
+ if (!checkAndPrepareWriting(*pos, size)) { |
+ return false; |
+ } |
+ const bool usesAdditionalBuffer = isInAdditionalBuffer(*pos); |
+ uint8_t *const buffer = |
+ usesAdditionalBuffer ? mAdditionalBuffer.data() : mOriginalBuffer.data(); |
+ if (usesAdditionalBuffer) { |
+ *pos -= mOriginalBuffer.size(); |
+ } |
+ ByteArrayUtils::writeCodePointsAndAdvancePosition(buffer, codePoints, codePointCount, |
+ writesTerminator, pos); |
+ if (usesAdditionalBuffer) { |
+ *pos += mOriginalBuffer.size(); |
+ } |
+ return true; |
+} |
+ |
+bool BufferWithExtendableBuffer::extendBuffer(const size_t size) { |
+ const size_t extendSize = std::max(EXTEND_ADDITIONAL_BUFFER_SIZE_STEP, size); |
+ const size_t sizeAfterExtending = |
+ std::min(mAdditionalBuffer.size() + extendSize, mMaxAdditionalBufferSize); |
+ if (sizeAfterExtending < mAdditionalBuffer.size() + size) { |
+ return false; |
+ } |
+ mAdditionalBuffer.resize(sizeAfterExtending); |
+ return true; |
+} |
+ |
+bool BufferWithExtendableBuffer::checkAndPrepareWriting(const int pos, const int size) { |
+ if (pos < 0 || size < 0) { |
+ // Invalid position or size. |
+ return false; |
+ } |
+ const size_t totalRequiredSize = static_cast<size_t>(pos + size); |
+ if (!isInAdditionalBuffer(pos)) { |
+ // Here don't need to care about the additional buffer. |
+ if (mOriginalBuffer.size() < totalRequiredSize) { |
+ // Violate the boundary. |
+ return false; |
+ } |
+ // The buffer has sufficient capacity. |
+ return true; |
+ } |
+ // Hereafter, pos is in the additional buffer. |
+ const size_t tailPosition = static_cast<size_t>(getTailPosition()); |
+ if (totalRequiredSize <= tailPosition) { |
+ // The buffer has sufficient capacity. |
+ return true; |
+ } |
+ if (static_cast<size_t>(pos) != tailPosition) { |
+ // The additional buffer must be extended from the tail position. |
+ return false; |
+ } |
+ const size_t extendSize = totalRequiredSize - |
+ std::min(mAdditionalBuffer.size() + mOriginalBuffer.size(), totalRequiredSize); |
+ if (extendSize > 0 && !extendBuffer(extendSize)) { |
+ // Failed to extend the buffer. |
+ return false; |
+ } |
+ mUsedAdditionalBufferSize += size; |
+ return true; |
+} |
+ |
+bool BufferWithExtendableBuffer::copy(const BufferWithExtendableBuffer *const sourceBuffer) { |
+ int copyingPos = 0; |
+ const int tailPos = sourceBuffer->getTailPosition(); |
+ const int maxDataChunkSize = sizeof(uint32_t); |
+ while (copyingPos < tailPos) { |
+ const int remainingSize = tailPos - copyingPos; |
+ const int copyingSize = (remainingSize >= maxDataChunkSize) ? |
+ maxDataChunkSize : remainingSize; |
+ const uint32_t data = sourceBuffer->readUint(copyingSize, copyingPos); |
+ if (!writeUint(data, copyingSize, copyingPos)) { |
+ return false; |
+ } |
+ copyingPos += copyingSize; |
+ } |
+ return true; |
+} |
+ |
+} |