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