blob: f692882f2fdca8de2e70e27d2d8ed7142daf227d [file] [log] [blame]
/*
* 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 "suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h"
namespace latinime {
const size_t BufferWithExtendableBuffer::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;
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[0] : mOriginalBuffer;
if (usesAdditionalBuffer) {
*pos -= mOriginalBufferSize;
}
ByteArrayUtils::writeUintAndAdvancePosition(buffer, data, size, pos);
if (usesAdditionalBuffer) {
*pos += mOriginalBufferSize;
}
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[0] : mOriginalBuffer;
if (usesAdditionalBuffer) {
*pos -= mOriginalBufferSize;
}
ByteArrayUtils::writeCodePointsAndAdvancePosition(buffer, codePoints, codePointCount,
writesTerminator, pos);
if (usesAdditionalBuffer) {
*pos += mOriginalBufferSize;
}
return true;
}
bool BufferWithExtendableBuffer::extendBuffer() {
const size_t sizeAfterExtending =
mAdditionalBuffer.size() + EXTEND_ADDITIONAL_BUFFER_SIZE_STEP;
if (sizeAfterExtending > mMaxAdditionalBufferSize) {
return false;
}
mAdditionalBuffer.resize(mAdditionalBuffer.size() + EXTEND_ADDITIONAL_BUFFER_SIZE_STEP);
return true;
}
bool BufferWithExtendableBuffer::checkAndPrepareWriting(const int pos, const int size) {
if (isInAdditionalBuffer(pos)) {
const int tailPosition = getTailPosition();
if (pos == tailPosition) {
// Append data to the tail.
if (pos + size > static_cast<int>(mAdditionalBuffer.size()) + mOriginalBufferSize) {
// Need to extend buffer.
if (!extendBuffer()) {
return false;
}
}
mUsedAdditionalBufferSize += size;
} else if (pos + size > tailPosition) {
// The access will beyond the tail of used region.
return false;
}
} else {
if (pos < 0 || mOriginalBufferSize < pos + size) {
// Invalid position or violate the boundary.
return false;
}
}
return true;
}
}