Home | History | Annotate | Download | only in utils
      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