buffer_with_extendable_buffer.cpp revision 6810e8df1ef7cdc37869f43a91f52695a1db8f0c
1/* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include "suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h" 18 19namespace latinime { 20 21const size_t BufferWithExtendableBuffer::DEFAULT_MAX_ADDITIONAL_BUFFER_SIZE = 1024 * 1024; 22const int BufferWithExtendableBuffer::NEAR_BUFFER_LIMIT_THRESHOLD_PERCENTILE = 90; 23// TODO: Needs to allocate larger memory corresponding to the current vector size. 24const size_t BufferWithExtendableBuffer::EXTEND_ADDITIONAL_BUFFER_SIZE_STEP = 128 * 1024; 25 26uint32_t BufferWithExtendableBuffer::readUint(const int size, const int pos) const { 27 const bool readingPosIsInAdditionalBuffer = isInAdditionalBuffer(pos); 28 const int posInBuffer = readingPosIsInAdditionalBuffer ? pos - mOriginalBufferSize : pos; 29 return ByteArrayUtils::readUint(getBuffer(readingPosIsInAdditionalBuffer), size, posInBuffer); 30} 31 32uint32_t BufferWithExtendableBuffer::readUintAndAdvancePosition(const int size, 33 int *const pos) const { 34 const int value = readUint(size, *pos); 35 *pos += size; 36 return value; 37} 38 39void BufferWithExtendableBuffer::readCodePointsAndAdvancePosition(const int maxCodePointCount, 40 int *const outCodePoints, int *outCodePointCount, int *const pos) const { 41 const bool readingPosIsInAdditionalBuffer = isInAdditionalBuffer(*pos); 42 if (readingPosIsInAdditionalBuffer) { 43 *pos -= mOriginalBufferSize; 44 } 45 *outCodePointCount = ByteArrayUtils::readStringAndAdvancePosition( 46 getBuffer(readingPosIsInAdditionalBuffer), maxCodePointCount, outCodePoints, pos); 47 if (readingPosIsInAdditionalBuffer) { 48 *pos += mOriginalBufferSize; 49 } 50} 51 52bool BufferWithExtendableBuffer::writeUint(const uint32_t data, const int size, const int pos) { 53 int writingPos = pos; 54 return writeUintAndAdvancePosition(data, size, &writingPos); 55} 56 57bool BufferWithExtendableBuffer::writeUintAndAdvancePosition(const uint32_t data, const int size, 58 int *const pos) { 59 if (!(size >= 1 && size <= 4)) { 60 AKLOGI("writeUintAndAdvancePosition() is called with invalid size: %d", size); 61 ASSERT(false); 62 return false; 63 } 64 if (!checkAndPrepareWriting(*pos, size)) { 65 return false; 66 } 67 const bool usesAdditionalBuffer = isInAdditionalBuffer(*pos); 68 uint8_t *const buffer = usesAdditionalBuffer ? &mAdditionalBuffer[0] : mOriginalBuffer; 69 if (usesAdditionalBuffer) { 70 *pos -= mOriginalBufferSize; 71 } 72 ByteArrayUtils::writeUintAndAdvancePosition(buffer, data, size, pos); 73 if (usesAdditionalBuffer) { 74 *pos += mOriginalBufferSize; 75 } 76 return true; 77} 78 79bool BufferWithExtendableBuffer::writeCodePointsAndAdvancePosition(const int *const codePoints, 80 const int codePointCount, const bool writesTerminator, int *const pos) { 81 const size_t size = ByteArrayUtils::calculateRequiredByteCountToStoreCodePoints( 82 codePoints, codePointCount, writesTerminator); 83 if (!checkAndPrepareWriting(*pos, size)) { 84 return false; 85 } 86 const bool usesAdditionalBuffer = isInAdditionalBuffer(*pos); 87 uint8_t *const buffer = usesAdditionalBuffer ? &mAdditionalBuffer[0] : mOriginalBuffer; 88 if (usesAdditionalBuffer) { 89 *pos -= mOriginalBufferSize; 90 } 91 ByteArrayUtils::writeCodePointsAndAdvancePosition(buffer, codePoints, codePointCount, 92 writesTerminator, pos); 93 if (usesAdditionalBuffer) { 94 *pos += mOriginalBufferSize; 95 } 96 return true; 97} 98 99bool BufferWithExtendableBuffer::extendBuffer() { 100 const size_t sizeAfterExtending = 101 mAdditionalBuffer.size() + EXTEND_ADDITIONAL_BUFFER_SIZE_STEP; 102 if (sizeAfterExtending > mMaxAdditionalBufferSize) { 103 return false; 104 } 105 mAdditionalBuffer.resize(mAdditionalBuffer.size() + EXTEND_ADDITIONAL_BUFFER_SIZE_STEP); 106 return true; 107} 108 109bool BufferWithExtendableBuffer::checkAndPrepareWriting(const int pos, const int size) { 110 if (pos < 0 || size < 0) { 111 // Invalid position or size. 112 return false; 113 } 114 const size_t totalRequiredSize = static_cast<size_t>(pos + size); 115 if (!isInAdditionalBuffer(pos)) { 116 // Here don't need to care about the additional buffer. 117 if (static_cast<size_t>(mOriginalBufferSize) < totalRequiredSize) { 118 // Violate the boundary. 119 return false; 120 } 121 // The buffer has sufficient capacity. 122 return true; 123 } 124 // Hereafter, pos is in the additional buffer. 125 const size_t tailPosition = static_cast<size_t>(getTailPosition()); 126 if (totalRequiredSize <= tailPosition) { 127 // The buffer has sufficient capacity. 128 return true; 129 } 130 if (static_cast<size_t>(pos) != tailPosition) { 131 // The additional buffer must be extended from the tail position. 132 return false; 133 } 134 const size_t extendSize = totalRequiredSize - 135 std::min(mAdditionalBuffer.size() + mOriginalBufferSize, totalRequiredSize); 136 if (extendSize > 0 && !extendBuffer()) { 137 // Failed to extend the buffer. 138 return false; 139 } 140 mUsedAdditionalBufferSize += size; 141 return true; 142} 143 144bool BufferWithExtendableBuffer::copy(const BufferWithExtendableBuffer *const sourceBuffer) { 145 int copyingPos = 0; 146 const int tailPos = sourceBuffer->getTailPosition(); 147 const int maxDataChunkSize = sizeof(uint32_t); 148 while (copyingPos < tailPos) { 149 const int remainingSize = tailPos - copyingPos; 150 const int copyingSize = (remainingSize >= maxDataChunkSize) ? 151 maxDataChunkSize : remainingSize; 152 const uint32_t data = sourceBuffer->readUint(copyingSize, copyingPos); 153 if (!writeUint(data, copyingSize, copyingPos)) { 154 return false; 155 } 156 copyingPos += copyingSize; 157 } 158 return true; 159} 160 161} 162