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 19 namespace latinime { 20 21 const size_t BufferWithExtendableBuffer::DEFAULT_MAX_ADDITIONAL_BUFFER_SIZE = 1024 * 1024; 22 const int BufferWithExtendableBuffer::NEAR_BUFFER_LIMIT_THRESHOLD_PERCENTILE = 90; 23 // TODO: Needs to allocate larger memory corresponding to the current vector size. 24 const size_t BufferWithExtendableBuffer::EXTEND_ADDITIONAL_BUFFER_SIZE_STEP = 128 * 1024; 25 26 uint32_t BufferWithExtendableBuffer::readUint(const int size, const int pos) const { 27 const bool readingPosIsInAdditionalBuffer = isInAdditionalBuffer(pos); 28 const int posInBuffer = readingPosIsInAdditionalBuffer ? pos - mOriginalBuffer.size() : pos; 29 return ByteArrayUtils::readUint(getBuffer(readingPosIsInAdditionalBuffer), size, posInBuffer); 30 } 31 32 uint32_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 39 void 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 -= mOriginalBuffer.size(); 44 } 45 *outCodePointCount = ByteArrayUtils::readStringAndAdvancePosition( 46 getBuffer(readingPosIsInAdditionalBuffer), maxCodePointCount, outCodePoints, pos); 47 if (readingPosIsInAdditionalBuffer) { 48 *pos += mOriginalBuffer.size(); 49 } 50 } 51 52 bool BufferWithExtendableBuffer::extend(const int size) { 53 return checkAndPrepareWriting(getTailPosition(), size); 54 } 55 56 bool BufferWithExtendableBuffer::writeUint(const uint32_t data, const int size, const int pos) { 57 int writingPos = pos; 58 return writeUintAndAdvancePosition(data, size, &writingPos); 59 } 60 61 bool BufferWithExtendableBuffer::writeUintAndAdvancePosition(const uint32_t data, const int size, 62 int *const pos) { 63 if (!(size >= 1 && size <= 4)) { 64 AKLOGI("writeUintAndAdvancePosition() is called with invalid size: %d", size); 65 ASSERT(false); 66 return false; 67 } 68 if (!checkAndPrepareWriting(*pos, size)) { 69 return false; 70 } 71 const bool usesAdditionalBuffer = isInAdditionalBuffer(*pos); 72 uint8_t *const buffer = 73 usesAdditionalBuffer ? mAdditionalBuffer.data() : mOriginalBuffer.data(); 74 if (usesAdditionalBuffer) { 75 *pos -= mOriginalBuffer.size(); 76 } 77 ByteArrayUtils::writeUintAndAdvancePosition(buffer, data, size, pos); 78 if (usesAdditionalBuffer) { 79 *pos += mOriginalBuffer.size(); 80 } 81 return true; 82 } 83 84 bool BufferWithExtendableBuffer::writeCodePointsAndAdvancePosition(const int *const codePoints, 85 const int codePointCount, const bool writesTerminator, int *const pos) { 86 const size_t size = ByteArrayUtils::calculateRequiredByteCountToStoreCodePoints( 87 codePoints, codePointCount, writesTerminator); 88 if (!checkAndPrepareWriting(*pos, size)) { 89 return false; 90 } 91 const bool usesAdditionalBuffer = isInAdditionalBuffer(*pos); 92 uint8_t *const buffer = 93 usesAdditionalBuffer ? mAdditionalBuffer.data() : mOriginalBuffer.data(); 94 if (usesAdditionalBuffer) { 95 *pos -= mOriginalBuffer.size(); 96 } 97 ByteArrayUtils::writeCodePointsAndAdvancePosition(buffer, codePoints, codePointCount, 98 writesTerminator, pos); 99 if (usesAdditionalBuffer) { 100 *pos += mOriginalBuffer.size(); 101 } 102 return true; 103 } 104 105 bool BufferWithExtendableBuffer::extendBuffer(const size_t size) { 106 const size_t extendSize = std::max(EXTEND_ADDITIONAL_BUFFER_SIZE_STEP, size); 107 const size_t sizeAfterExtending = 108 std::min(mAdditionalBuffer.size() + extendSize, mMaxAdditionalBufferSize); 109 if (sizeAfterExtending < mAdditionalBuffer.size() + size) { 110 return false; 111 } 112 mAdditionalBuffer.resize(sizeAfterExtending); 113 return true; 114 } 115 116 bool BufferWithExtendableBuffer::checkAndPrepareWriting(const int pos, const int size) { 117 if (pos < 0 || size < 0) { 118 // Invalid position or size. 119 return false; 120 } 121 const size_t totalRequiredSize = static_cast<size_t>(pos + size); 122 if (!isInAdditionalBuffer(pos)) { 123 // Here don't need to care about the additional buffer. 124 if (mOriginalBuffer.size() < totalRequiredSize) { 125 // Violate the boundary. 126 return false; 127 } 128 // The buffer has sufficient capacity. 129 return true; 130 } 131 // Hereafter, pos is in the additional buffer. 132 const size_t tailPosition = static_cast<size_t>(getTailPosition()); 133 if (totalRequiredSize <= tailPosition) { 134 // The buffer has sufficient capacity. 135 return true; 136 } 137 if (static_cast<size_t>(pos) != tailPosition) { 138 // The additional buffer must be extended from the tail position. 139 return false; 140 } 141 const size_t extendSize = totalRequiredSize - 142 std::min(mAdditionalBuffer.size() + mOriginalBuffer.size(), totalRequiredSize); 143 if (extendSize > 0 && !extendBuffer(extendSize)) { 144 // Failed to extend the buffer. 145 return false; 146 } 147 mUsedAdditionalBufferSize += size; 148 return true; 149 } 150 151 bool BufferWithExtendableBuffer::copy(const BufferWithExtendableBuffer *const sourceBuffer) { 152 int copyingPos = 0; 153 const int tailPos = sourceBuffer->getTailPosition(); 154 const int maxDataChunkSize = sizeof(uint32_t); 155 while (copyingPos < tailPos) { 156 const int remainingSize = tailPos - copyingPos; 157 const int copyingSize = (remainingSize >= maxDataChunkSize) ? 158 maxDataChunkSize : remainingSize; 159 const uint32_t data = sourceBuffer->readUint(copyingSize, copyingPos); 160 if (!writeUint(data, copyingSize, copyingPos)) { 161 return false; 162 } 163 copyingPos += copyingSize; 164 } 165 return true; 166 } 167 168 } 169