2009-03-04 04:31:44 +01:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2005 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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define LOG_TAG "Vector"
|
|
|
|
|
|
|
|
#include <stdio.h>
|
2016-09-28 19:07:20 +02:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
2009-03-04 04:31:44 +01:00
|
|
|
|
2017-01-10 22:19:54 +01:00
|
|
|
#include <log/log.h>
|
2009-03-04 04:31:44 +01:00
|
|
|
#include <utils/Errors.h>
|
|
|
|
#include <utils/VectorImpl.h>
|
|
|
|
|
2016-09-28 19:07:20 +02:00
|
|
|
#include <safe_iop.h>
|
|
|
|
|
2015-09-23 17:22:59 +02:00
|
|
|
#include "SharedBuffer.h"
|
|
|
|
|
2009-03-04 04:31:44 +01:00
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
namespace android {
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
const size_t kMinVectorCapacity = 4;
|
|
|
|
|
|
|
|
static inline size_t max(size_t a, size_t b) {
|
|
|
|
return a>b ? a : b;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
VectorImpl::VectorImpl(size_t itemSize, uint32_t flags)
|
|
|
|
: mStorage(0), mCount(0), mFlags(flags), mItemSize(itemSize)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
VectorImpl::VectorImpl(const VectorImpl& rhs)
|
|
|
|
: mStorage(rhs.mStorage), mCount(rhs.mCount),
|
|
|
|
mFlags(rhs.mFlags), mItemSize(rhs.mItemSize)
|
|
|
|
{
|
|
|
|
if (mStorage) {
|
2012-09-01 01:20:23 +02:00
|
|
|
SharedBuffer::bufferFromData(mStorage)->acquire();
|
2009-03-04 04:31:44 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
VectorImpl::~VectorImpl()
|
|
|
|
{
|
2012-08-10 04:39:15 +02:00
|
|
|
ALOGW_IF(mCount,
|
|
|
|
"[%p] subclasses of VectorImpl must call finish_vector()"
|
2009-03-04 04:31:44 +01:00
|
|
|
" in their destructor. Leaking %d bytes.",
|
|
|
|
this, (int)(mCount*mItemSize));
|
|
|
|
// We can't call _do_destroy() here because the vtable is already gone.
|
|
|
|
}
|
|
|
|
|
|
|
|
VectorImpl& VectorImpl::operator = (const VectorImpl& rhs)
|
|
|
|
{
|
2012-08-10 04:39:15 +02:00
|
|
|
LOG_ALWAYS_FATAL_IF(mItemSize != rhs.mItemSize,
|
2009-03-04 04:31:44 +01:00
|
|
|
"Vector<> have different types (this=%p, rhs=%p)", this, &rhs);
|
|
|
|
if (this != &rhs) {
|
|
|
|
release_storage();
|
|
|
|
if (rhs.mCount) {
|
|
|
|
mStorage = rhs.mStorage;
|
|
|
|
mCount = rhs.mCount;
|
2012-09-01 01:20:23 +02:00
|
|
|
SharedBuffer::bufferFromData(mStorage)->acquire();
|
2009-03-04 04:31:44 +01:00
|
|
|
} else {
|
|
|
|
mStorage = 0;
|
|
|
|
mCount = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
void* VectorImpl::editArrayImpl()
|
|
|
|
{
|
|
|
|
if (mStorage) {
|
2015-08-28 13:59:48 +02:00
|
|
|
const SharedBuffer* sb = SharedBuffer::bufferFromData(mStorage);
|
|
|
|
SharedBuffer* editable = sb->attemptEdit();
|
|
|
|
if (editable == 0) {
|
|
|
|
// If we're here, we're not the only owner of the buffer.
|
|
|
|
// We must make a copy of it.
|
|
|
|
editable = SharedBuffer::alloc(sb->size());
|
|
|
|
// Fail instead of returning a pointer to storage that's not
|
|
|
|
// editable. Otherwise we'd be editing the contents of a buffer
|
|
|
|
// for which we're not the only owner, which is undefined behaviour.
|
|
|
|
LOG_ALWAYS_FATAL_IF(editable == NULL);
|
|
|
|
_do_copy(editable->data(), mStorage, mCount);
|
|
|
|
release_storage();
|
|
|
|
mStorage = editable->data();
|
2009-03-04 04:31:44 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return mStorage;
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t VectorImpl::capacity() const
|
|
|
|
{
|
|
|
|
if (mStorage) {
|
2012-09-01 01:20:23 +02:00
|
|
|
return SharedBuffer::bufferFromData(mStorage)->size() / mItemSize;
|
2009-03-04 04:31:44 +01:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
ssize_t VectorImpl::insertVectorAt(const VectorImpl& vector, size_t index)
|
|
|
|
{
|
2010-06-16 10:53:36 +02:00
|
|
|
return insertArrayAt(vector.arrayImpl(), index, vector.size());
|
2009-03-04 04:31:44 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
ssize_t VectorImpl::appendVector(const VectorImpl& vector)
|
|
|
|
{
|
|
|
|
return insertVectorAt(vector, size());
|
|
|
|
}
|
|
|
|
|
2010-06-16 10:53:36 +02:00
|
|
|
ssize_t VectorImpl::insertArrayAt(const void* array, size_t index, size_t length)
|
|
|
|
{
|
|
|
|
if (index > size())
|
|
|
|
return BAD_INDEX;
|
|
|
|
void* where = _grow(index, length);
|
|
|
|
if (where) {
|
|
|
|
_do_copy(where, array, length);
|
|
|
|
}
|
|
|
|
return where ? index : (ssize_t)NO_MEMORY;
|
|
|
|
}
|
|
|
|
|
|
|
|
ssize_t VectorImpl::appendArray(const void* array, size_t length)
|
|
|
|
{
|
|
|
|
return insertArrayAt(array, size(), length);
|
|
|
|
}
|
|
|
|
|
2009-03-04 04:31:44 +01:00
|
|
|
ssize_t VectorImpl::insertAt(size_t index, size_t numItems)
|
|
|
|
{
|
|
|
|
return insertAt(0, index, numItems);
|
|
|
|
}
|
|
|
|
|
|
|
|
ssize_t VectorImpl::insertAt(const void* item, size_t index, size_t numItems)
|
|
|
|
{
|
|
|
|
if (index > size())
|
|
|
|
return BAD_INDEX;
|
|
|
|
void* where = _grow(index, numItems);
|
|
|
|
if (where) {
|
|
|
|
if (item) {
|
|
|
|
_do_splat(where, item, numItems);
|
|
|
|
} else {
|
|
|
|
_do_construct(where, numItems);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return where ? index : (ssize_t)NO_MEMORY;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int sortProxy(const void* lhs, const void* rhs, void* func)
|
|
|
|
{
|
|
|
|
return (*(VectorImpl::compar_t)func)(lhs, rhs);
|
|
|
|
}
|
|
|
|
|
|
|
|
status_t VectorImpl::sort(VectorImpl::compar_t cmp)
|
|
|
|
{
|
|
|
|
return sort(sortProxy, (void*)cmp);
|
|
|
|
}
|
|
|
|
|
|
|
|
status_t VectorImpl::sort(VectorImpl::compar_r_t cmp, void* state)
|
|
|
|
{
|
|
|
|
// the sort must be stable. we're using insertion sort which
|
|
|
|
// is well suited for small and already sorted arrays
|
|
|
|
// for big arrays, it could be better to use mergesort
|
|
|
|
const ssize_t count = size();
|
|
|
|
if (count > 1) {
|
|
|
|
void* array = const_cast<void*>(arrayImpl());
|
|
|
|
void* temp = 0;
|
|
|
|
ssize_t i = 1;
|
|
|
|
while (i < count) {
|
|
|
|
void* item = reinterpret_cast<char*>(array) + mItemSize*(i);
|
|
|
|
void* curr = reinterpret_cast<char*>(array) + mItemSize*(i-1);
|
|
|
|
if (cmp(curr, item, state) > 0) {
|
|
|
|
|
|
|
|
if (!temp) {
|
|
|
|
// we're going to have to modify the array...
|
|
|
|
array = editArrayImpl();
|
|
|
|
if (!array) return NO_MEMORY;
|
|
|
|
temp = malloc(mItemSize);
|
|
|
|
if (!temp) return NO_MEMORY;
|
|
|
|
item = reinterpret_cast<char*>(array) + mItemSize*(i);
|
|
|
|
curr = reinterpret_cast<char*>(array) + mItemSize*(i-1);
|
2010-03-29 22:45:18 +02:00
|
|
|
} else {
|
|
|
|
_do_destroy(temp, 1);
|
2009-03-04 04:31:44 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
_do_copy(temp, item, 1);
|
|
|
|
|
|
|
|
ssize_t j = i-1;
|
|
|
|
void* next = reinterpret_cast<char*>(array) + mItemSize*(i);
|
|
|
|
do {
|
2010-03-29 22:45:18 +02:00
|
|
|
_do_destroy(next, 1);
|
2009-03-04 04:31:44 +01:00
|
|
|
_do_copy(next, curr, 1);
|
|
|
|
next = curr;
|
|
|
|
--j;
|
2015-08-28 15:40:23 +02:00
|
|
|
curr = NULL;
|
|
|
|
if (j >= 0) {
|
|
|
|
curr = reinterpret_cast<char*>(array) + mItemSize*(j);
|
|
|
|
}
|
2009-03-04 04:31:44 +01:00
|
|
|
} while (j>=0 && (cmp(curr, temp, state) > 0));
|
|
|
|
|
2010-03-29 22:45:18 +02:00
|
|
|
_do_destroy(next, 1);
|
2009-03-04 04:31:44 +01:00
|
|
|
_do_copy(next, temp, 1);
|
|
|
|
}
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (temp) {
|
|
|
|
_do_destroy(temp, 1);
|
|
|
|
free(temp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NO_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
void VectorImpl::pop()
|
|
|
|
{
|
|
|
|
if (size())
|
|
|
|
removeItemsAt(size()-1, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void VectorImpl::push()
|
|
|
|
{
|
|
|
|
push(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void VectorImpl::push(const void* item)
|
|
|
|
{
|
|
|
|
insertAt(item, size());
|
|
|
|
}
|
|
|
|
|
|
|
|
ssize_t VectorImpl::add()
|
|
|
|
{
|
|
|
|
return add(0);
|
|
|
|
}
|
|
|
|
|
2010-06-16 10:53:36 +02:00
|
|
|
ssize_t VectorImpl::add(const void* item)
|
2009-03-04 04:31:44 +01:00
|
|
|
{
|
2010-06-16 10:53:36 +02:00
|
|
|
return insertAt(item, size());
|
2009-03-04 04:31:44 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
ssize_t VectorImpl::replaceAt(size_t index)
|
|
|
|
{
|
|
|
|
return replaceAt(0, index);
|
|
|
|
}
|
|
|
|
|
|
|
|
ssize_t VectorImpl::replaceAt(const void* prototype, size_t index)
|
|
|
|
{
|
2012-01-09 19:35:44 +01:00
|
|
|
ALOG_ASSERT(index<size(),
|
2009-03-04 04:31:44 +01:00
|
|
|
"[%p] replace: index=%d, size=%d", this, (int)index, (int)size());
|
|
|
|
|
2012-08-10 04:39:15 +02:00
|
|
|
if (index >= size()) {
|
|
|
|
return BAD_INDEX;
|
|
|
|
}
|
|
|
|
|
2009-03-04 04:31:44 +01:00
|
|
|
void* item = editItemLocation(index);
|
2011-07-14 09:29:49 +02:00
|
|
|
if (item != prototype) {
|
|
|
|
if (item == 0)
|
|
|
|
return NO_MEMORY;
|
|
|
|
_do_destroy(item, 1);
|
|
|
|
if (prototype == 0) {
|
|
|
|
_do_construct(item, 1);
|
|
|
|
} else {
|
|
|
|
_do_copy(item, prototype, 1);
|
|
|
|
}
|
2009-03-04 04:31:44 +01:00
|
|
|
}
|
|
|
|
return ssize_t(index);
|
|
|
|
}
|
|
|
|
|
|
|
|
ssize_t VectorImpl::removeItemsAt(size_t index, size_t count)
|
|
|
|
{
|
2012-01-09 19:35:44 +01:00
|
|
|
ALOG_ASSERT((index+count)<=size(),
|
2009-03-04 04:31:44 +01:00
|
|
|
"[%p] remove: index=%d, count=%d, size=%d",
|
|
|
|
this, (int)index, (int)count, (int)size());
|
|
|
|
|
|
|
|
if ((index+count) > size())
|
|
|
|
return BAD_VALUE;
|
|
|
|
_shrink(index, count);
|
|
|
|
return index;
|
|
|
|
}
|
|
|
|
|
|
|
|
void VectorImpl::finish_vector()
|
|
|
|
{
|
|
|
|
release_storage();
|
|
|
|
mStorage = 0;
|
|
|
|
mCount = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void VectorImpl::clear()
|
|
|
|
{
|
|
|
|
_shrink(0, mCount);
|
|
|
|
}
|
|
|
|
|
|
|
|
void* VectorImpl::editItemLocation(size_t index)
|
|
|
|
{
|
2012-01-09 19:35:44 +01:00
|
|
|
ALOG_ASSERT(index<capacity(),
|
2011-07-12 01:26:18 +02:00
|
|
|
"[%p] editItemLocation: index=%d, capacity=%d, count=%d",
|
2009-03-04 04:31:44 +01:00
|
|
|
this, (int)index, (int)capacity(), (int)mCount);
|
2012-08-10 04:39:15 +02:00
|
|
|
|
|
|
|
if (index < capacity()) {
|
|
|
|
void* buffer = editArrayImpl();
|
|
|
|
if (buffer) {
|
|
|
|
return reinterpret_cast<char*>(buffer) + index*mItemSize;
|
|
|
|
}
|
|
|
|
}
|
2009-03-04 04:31:44 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
const void* VectorImpl::itemLocation(size_t index) const
|
|
|
|
{
|
2012-01-09 19:35:44 +01:00
|
|
|
ALOG_ASSERT(index<capacity(),
|
2011-07-12 01:26:18 +02:00
|
|
|
"[%p] itemLocation: index=%d, capacity=%d, count=%d",
|
2009-03-04 04:31:44 +01:00
|
|
|
this, (int)index, (int)capacity(), (int)mCount);
|
|
|
|
|
2012-08-10 04:39:15 +02:00
|
|
|
if (index < capacity()) {
|
|
|
|
const void* buffer = arrayImpl();
|
|
|
|
if (buffer) {
|
|
|
|
return reinterpret_cast<const char*>(buffer) + index*mItemSize;
|
|
|
|
}
|
|
|
|
}
|
2009-03-04 04:31:44 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
ssize_t VectorImpl::setCapacity(size_t new_capacity)
|
|
|
|
{
|
2015-08-28 13:59:48 +02:00
|
|
|
// The capacity must always be greater than or equal to the size
|
|
|
|
// of this vector.
|
|
|
|
if (new_capacity <= size()) {
|
|
|
|
return capacity();
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t new_allocation_size = 0;
|
|
|
|
LOG_ALWAYS_FATAL_IF(!safe_mul(&new_allocation_size, new_capacity, mItemSize));
|
|
|
|
SharedBuffer* sb = SharedBuffer::alloc(new_allocation_size);
|
2009-03-04 04:31:44 +01:00
|
|
|
if (sb) {
|
|
|
|
void* array = sb->data();
|
|
|
|
_do_copy(array, mStorage, size());
|
|
|
|
release_storage();
|
|
|
|
mStorage = const_cast<void*>(array);
|
|
|
|
} else {
|
|
|
|
return NO_MEMORY;
|
|
|
|
}
|
|
|
|
return new_capacity;
|
|
|
|
}
|
|
|
|
|
2013-03-11 18:16:48 +01:00
|
|
|
ssize_t VectorImpl::resize(size_t size) {
|
|
|
|
ssize_t result = NO_ERROR;
|
|
|
|
if (size > mCount) {
|
|
|
|
result = insertAt(mCount, size - mCount);
|
|
|
|
} else if (size < mCount) {
|
|
|
|
result = removeItemsAt(size, mCount - size);
|
|
|
|
}
|
|
|
|
return result < 0 ? result : size;
|
|
|
|
}
|
|
|
|
|
2009-03-04 04:31:44 +01:00
|
|
|
void VectorImpl::release_storage()
|
|
|
|
{
|
|
|
|
if (mStorage) {
|
2012-09-01 01:20:23 +02:00
|
|
|
const SharedBuffer* sb = SharedBuffer::bufferFromData(mStorage);
|
2009-03-04 04:31:44 +01:00
|
|
|
if (sb->release(SharedBuffer::eKeepStorage) == 1) {
|
|
|
|
_do_destroy(mStorage, mCount);
|
|
|
|
SharedBuffer::dealloc(sb);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void* VectorImpl::_grow(size_t where, size_t amount)
|
|
|
|
{
|
2011-10-20 12:56:00 +02:00
|
|
|
// ALOGV("_grow(this=%p, where=%d, amount=%d) count=%d, capacity=%d",
|
2009-03-04 04:31:44 +01:00
|
|
|
// this, (int)where, (int)amount, (int)mCount, (int)capacity());
|
|
|
|
|
2012-01-09 19:35:44 +01:00
|
|
|
ALOG_ASSERT(where <= mCount,
|
2011-07-14 07:22:02 +02:00
|
|
|
"[%p] _grow: where=%d, amount=%d, count=%d",
|
|
|
|
this, (int)where, (int)amount, (int)mCount); // caller already checked
|
|
|
|
|
2015-08-28 13:59:48 +02:00
|
|
|
size_t new_size;
|
|
|
|
LOG_ALWAYS_FATAL_IF(!safe_add(&new_size, mCount, amount), "new_size overflow");
|
|
|
|
|
2009-03-04 04:31:44 +01:00
|
|
|
if (capacity() < new_size) {
|
2015-08-28 13:59:48 +02:00
|
|
|
// NOTE: This implementation used to resize vectors as per ((3*x + 1) / 2)
|
|
|
|
// (sigh..). Also note, the " + 1" was necessary to handle the special case
|
|
|
|
// where x == 1, where the resized_capacity will be equal to the old
|
|
|
|
// capacity without the +1. The old calculation wouldn't work properly
|
|
|
|
// if x was zero.
|
|
|
|
//
|
|
|
|
// This approximates the old calculation, using (x + (x/2) + 1) instead.
|
|
|
|
size_t new_capacity = 0;
|
|
|
|
LOG_ALWAYS_FATAL_IF(!safe_add(&new_capacity, new_size, (new_size / 2)),
|
|
|
|
"new_capacity overflow");
|
|
|
|
LOG_ALWAYS_FATAL_IF(!safe_add(&new_capacity, new_capacity, static_cast<size_t>(1u)),
|
|
|
|
"new_capacity overflow");
|
|
|
|
new_capacity = max(kMinVectorCapacity, new_capacity);
|
|
|
|
|
|
|
|
size_t new_alloc_size = 0;
|
|
|
|
LOG_ALWAYS_FATAL_IF(!safe_mul(&new_alloc_size, new_capacity, mItemSize),
|
|
|
|
"new_alloc_size overflow");
|
|
|
|
|
2011-10-20 12:56:00 +02:00
|
|
|
// ALOGV("grow vector %p, new_capacity=%d", this, (int)new_capacity);
|
2009-03-04 04:31:44 +01:00
|
|
|
if ((mStorage) &&
|
|
|
|
(mCount==where) &&
|
|
|
|
(mFlags & HAS_TRIVIAL_COPY) &&
|
|
|
|
(mFlags & HAS_TRIVIAL_DTOR))
|
|
|
|
{
|
2012-09-01 01:20:23 +02:00
|
|
|
const SharedBuffer* cur_sb = SharedBuffer::bufferFromData(mStorage);
|
2015-08-28 13:59:48 +02:00
|
|
|
SharedBuffer* sb = cur_sb->editResize(new_alloc_size);
|
fix corruption in Vector<> when malloc falied
1. When alloc or realloc failed in the function SharedBuffer::editResize,
it would return a NULL pointer, then mStorage would update to be 1 by
SharedBuffer::data() if no pointer check here, which is an obviously
wrong address, and would cause corruption when used it e.g. in capacity().
So add the pointer check here for the return value of SharedBuffer::editResize,
if it's NULL do not use it to update mStorage, to avoid the value of mStorage
polluted.
2. when alloc or realloc falied in _grow & _shrink function, mStorage keep
the original value, so mCount should not be updated here.
Otherwise, mStorage might be 0 but mCount>0, so a corruption would happend
when it try to delete items from the Vector since mCount>0.
Change-Id: I7c3814e843c459834ca5eed392e8d63d1cb7d2d8
Signed-off-by: Shuo Gao <shuo.gao@intel.com>
Signed-off-by: Jian Luo <jian.luo@intel.com>
Signed-off-by: Bruce Beare <bruce.j.beare@intel.com>
Signed-off-by: Jack Ren <jack.ren@intel.com>
Author-tracking-BZ: 139626
2013-10-17 05:36:11 +02:00
|
|
|
if (sb) {
|
|
|
|
mStorage = sb->data();
|
|
|
|
} else {
|
|
|
|
return NULL;
|
|
|
|
}
|
2009-03-04 04:31:44 +01:00
|
|
|
} else {
|
2015-08-28 13:59:48 +02:00
|
|
|
SharedBuffer* sb = SharedBuffer::alloc(new_alloc_size);
|
2009-03-04 04:31:44 +01:00
|
|
|
if (sb) {
|
|
|
|
void* array = sb->data();
|
2011-07-14 09:29:49 +02:00
|
|
|
if (where != 0) {
|
2009-03-04 04:31:44 +01:00
|
|
|
_do_copy(array, mStorage, where);
|
|
|
|
}
|
2011-07-14 09:29:49 +02:00
|
|
|
if (where != mCount) {
|
2009-03-04 04:31:44 +01:00
|
|
|
const void* from = reinterpret_cast<const uint8_t *>(mStorage) + where*mItemSize;
|
|
|
|
void* dest = reinterpret_cast<uint8_t *>(array) + (where+amount)*mItemSize;
|
|
|
|
_do_copy(dest, from, mCount-where);
|
|
|
|
}
|
|
|
|
release_storage();
|
|
|
|
mStorage = const_cast<void*>(array);
|
fix corruption in Vector<> when malloc falied
1. When alloc or realloc failed in the function SharedBuffer::editResize,
it would return a NULL pointer, then mStorage would update to be 1 by
SharedBuffer::data() if no pointer check here, which is an obviously
wrong address, and would cause corruption when used it e.g. in capacity().
So add the pointer check here for the return value of SharedBuffer::editResize,
if it's NULL do not use it to update mStorage, to avoid the value of mStorage
polluted.
2. when alloc or realloc falied in _grow & _shrink function, mStorage keep
the original value, so mCount should not be updated here.
Otherwise, mStorage might be 0 but mCount>0, so a corruption would happend
when it try to delete items from the Vector since mCount>0.
Change-Id: I7c3814e843c459834ca5eed392e8d63d1cb7d2d8
Signed-off-by: Shuo Gao <shuo.gao@intel.com>
Signed-off-by: Jian Luo <jian.luo@intel.com>
Signed-off-by: Bruce Beare <bruce.j.beare@intel.com>
Signed-off-by: Jack Ren <jack.ren@intel.com>
Author-tracking-BZ: 139626
2013-10-17 05:36:11 +02:00
|
|
|
} else {
|
|
|
|
return NULL;
|
2009-03-04 04:31:44 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
2012-05-18 01:52:21 +02:00
|
|
|
void* array = editArrayImpl();
|
2011-07-14 09:29:49 +02:00
|
|
|
if (where != mCount) {
|
2009-03-04 04:31:44 +01:00
|
|
|
const void* from = reinterpret_cast<const uint8_t *>(array) + where*mItemSize;
|
2011-07-14 09:29:49 +02:00
|
|
|
void* to = reinterpret_cast<uint8_t *>(array) + (where+amount)*mItemSize;
|
|
|
|
_do_move_forward(to, from, mCount - where);
|
2009-03-04 04:31:44 +01:00
|
|
|
}
|
|
|
|
}
|
2011-07-14 09:29:49 +02:00
|
|
|
mCount = new_size;
|
2009-03-04 04:31:44 +01:00
|
|
|
void* free_space = const_cast<void*>(itemLocation(where));
|
|
|
|
return free_space;
|
|
|
|
}
|
|
|
|
|
|
|
|
void VectorImpl::_shrink(size_t where, size_t amount)
|
|
|
|
{
|
|
|
|
if (!mStorage)
|
|
|
|
return;
|
|
|
|
|
2011-10-20 12:56:00 +02:00
|
|
|
// ALOGV("_shrink(this=%p, where=%d, amount=%d) count=%d, capacity=%d",
|
2009-03-04 04:31:44 +01:00
|
|
|
// this, (int)where, (int)amount, (int)mCount, (int)capacity());
|
|
|
|
|
2012-01-09 19:35:44 +01:00
|
|
|
ALOG_ASSERT(where + amount <= mCount,
|
2011-07-14 07:22:02 +02:00
|
|
|
"[%p] _shrink: where=%d, amount=%d, count=%d",
|
|
|
|
this, (int)where, (int)amount, (int)mCount); // caller already checked
|
2009-03-04 04:31:44 +01:00
|
|
|
|
2015-08-28 13:59:48 +02:00
|
|
|
size_t new_size;
|
|
|
|
LOG_ALWAYS_FATAL_IF(!safe_sub(&new_size, mCount, amount));
|
|
|
|
|
|
|
|
if (new_size < (capacity() / 2)) {
|
|
|
|
// NOTE: (new_size * 2) is safe because capacity didn't overflow and
|
|
|
|
// new_size < (capacity / 2)).
|
|
|
|
const size_t new_capacity = max(kMinVectorCapacity, new_size * 2);
|
|
|
|
|
|
|
|
// NOTE: (new_capacity * mItemSize), (where * mItemSize) and
|
|
|
|
// ((where + amount) * mItemSize) beyond this point are safe because
|
|
|
|
// we are always reducing the capacity of the underlying SharedBuffer.
|
|
|
|
// In other words, (old_capacity * mItemSize) did not overflow, and
|
|
|
|
// where < (where + amount) < new_capacity < old_capacity.
|
2011-07-14 09:29:49 +02:00
|
|
|
if ((where == new_size) &&
|
2009-03-04 04:31:44 +01:00
|
|
|
(mFlags & HAS_TRIVIAL_COPY) &&
|
|
|
|
(mFlags & HAS_TRIVIAL_DTOR))
|
|
|
|
{
|
2012-09-01 01:20:23 +02:00
|
|
|
const SharedBuffer* cur_sb = SharedBuffer::bufferFromData(mStorage);
|
2009-03-04 04:31:44 +01:00
|
|
|
SharedBuffer* sb = cur_sb->editResize(new_capacity * mItemSize);
|
fix corruption in Vector<> when malloc falied
1. When alloc or realloc failed in the function SharedBuffer::editResize,
it would return a NULL pointer, then mStorage would update to be 1 by
SharedBuffer::data() if no pointer check here, which is an obviously
wrong address, and would cause corruption when used it e.g. in capacity().
So add the pointer check here for the return value of SharedBuffer::editResize,
if it's NULL do not use it to update mStorage, to avoid the value of mStorage
polluted.
2. when alloc or realloc falied in _grow & _shrink function, mStorage keep
the original value, so mCount should not be updated here.
Otherwise, mStorage might be 0 but mCount>0, so a corruption would happend
when it try to delete items from the Vector since mCount>0.
Change-Id: I7c3814e843c459834ca5eed392e8d63d1cb7d2d8
Signed-off-by: Shuo Gao <shuo.gao@intel.com>
Signed-off-by: Jian Luo <jian.luo@intel.com>
Signed-off-by: Bruce Beare <bruce.j.beare@intel.com>
Signed-off-by: Jack Ren <jack.ren@intel.com>
Author-tracking-BZ: 139626
2013-10-17 05:36:11 +02:00
|
|
|
if (sb) {
|
|
|
|
mStorage = sb->data();
|
|
|
|
} else {
|
|
|
|
return;
|
|
|
|
}
|
2009-03-04 04:31:44 +01:00
|
|
|
} else {
|
|
|
|
SharedBuffer* sb = SharedBuffer::alloc(new_capacity * mItemSize);
|
|
|
|
if (sb) {
|
|
|
|
void* array = sb->data();
|
2011-07-14 09:29:49 +02:00
|
|
|
if (where != 0) {
|
2009-03-04 04:31:44 +01:00
|
|
|
_do_copy(array, mStorage, where);
|
|
|
|
}
|
2011-07-14 09:29:49 +02:00
|
|
|
if (where != new_size) {
|
2009-03-04 04:31:44 +01:00
|
|
|
const void* from = reinterpret_cast<const uint8_t *>(mStorage) + (where+amount)*mItemSize;
|
|
|
|
void* dest = reinterpret_cast<uint8_t *>(array) + where*mItemSize;
|
2011-07-14 09:29:49 +02:00
|
|
|
_do_copy(dest, from, new_size - where);
|
2009-03-04 04:31:44 +01:00
|
|
|
}
|
|
|
|
release_storage();
|
|
|
|
mStorage = const_cast<void*>(array);
|
fix corruption in Vector<> when malloc falied
1. When alloc or realloc failed in the function SharedBuffer::editResize,
it would return a NULL pointer, then mStorage would update to be 1 by
SharedBuffer::data() if no pointer check here, which is an obviously
wrong address, and would cause corruption when used it e.g. in capacity().
So add the pointer check here for the return value of SharedBuffer::editResize,
if it's NULL do not use it to update mStorage, to avoid the value of mStorage
polluted.
2. when alloc or realloc falied in _grow & _shrink function, mStorage keep
the original value, so mCount should not be updated here.
Otherwise, mStorage might be 0 but mCount>0, so a corruption would happend
when it try to delete items from the Vector since mCount>0.
Change-Id: I7c3814e843c459834ca5eed392e8d63d1cb7d2d8
Signed-off-by: Shuo Gao <shuo.gao@intel.com>
Signed-off-by: Jian Luo <jian.luo@intel.com>
Signed-off-by: Bruce Beare <bruce.j.beare@intel.com>
Signed-off-by: Jack Ren <jack.ren@intel.com>
Author-tracking-BZ: 139626
2013-10-17 05:36:11 +02:00
|
|
|
} else{
|
|
|
|
return;
|
2009-03-04 04:31:44 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
2011-07-14 09:29:49 +02:00
|
|
|
void* array = editArrayImpl();
|
2009-03-04 04:31:44 +01:00
|
|
|
void* to = reinterpret_cast<uint8_t *>(array) + where*mItemSize;
|
|
|
|
_do_destroy(to, amount);
|
2011-07-14 09:29:49 +02:00
|
|
|
if (where != new_size) {
|
2009-03-04 04:31:44 +01:00
|
|
|
const void* from = reinterpret_cast<uint8_t *>(array) + (where+amount)*mItemSize;
|
2011-07-14 09:29:49 +02:00
|
|
|
_do_move_backward(to, from, new_size - where);
|
2009-03-04 04:31:44 +01:00
|
|
|
}
|
|
|
|
}
|
2011-07-14 09:29:49 +02:00
|
|
|
mCount = new_size;
|
2009-03-04 04:31:44 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
size_t VectorImpl::itemSize() const {
|
|
|
|
return mItemSize;
|
|
|
|
}
|
|
|
|
|
|
|
|
void VectorImpl::_do_construct(void* storage, size_t num) const
|
|
|
|
{
|
|
|
|
if (!(mFlags & HAS_TRIVIAL_CTOR)) {
|
|
|
|
do_construct(storage, num);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void VectorImpl::_do_destroy(void* storage, size_t num) const
|
|
|
|
{
|
|
|
|
if (!(mFlags & HAS_TRIVIAL_DTOR)) {
|
|
|
|
do_destroy(storage, num);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void VectorImpl::_do_copy(void* dest, const void* from, size_t num) const
|
|
|
|
{
|
|
|
|
if (!(mFlags & HAS_TRIVIAL_COPY)) {
|
|
|
|
do_copy(dest, from, num);
|
|
|
|
} else {
|
|
|
|
memcpy(dest, from, num*itemSize());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void VectorImpl::_do_splat(void* dest, const void* item, size_t num) const {
|
|
|
|
do_splat(dest, item, num);
|
|
|
|
}
|
|
|
|
|
|
|
|
void VectorImpl::_do_move_forward(void* dest, const void* from, size_t num) const {
|
|
|
|
do_move_forward(dest, from, num);
|
|
|
|
}
|
|
|
|
|
|
|
|
void VectorImpl::_do_move_backward(void* dest, const void* from, size_t num) const {
|
|
|
|
do_move_backward(dest, from, num);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
SortedVectorImpl::SortedVectorImpl(size_t itemSize, uint32_t flags)
|
|
|
|
: VectorImpl(itemSize, flags)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
SortedVectorImpl::SortedVectorImpl(const VectorImpl& rhs)
|
|
|
|
: VectorImpl(rhs)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
SortedVectorImpl::~SortedVectorImpl()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
SortedVectorImpl& SortedVectorImpl::operator = (const SortedVectorImpl& rhs)
|
|
|
|
{
|
|
|
|
return static_cast<SortedVectorImpl&>( VectorImpl::operator = (static_cast<const VectorImpl&>(rhs)) );
|
|
|
|
}
|
|
|
|
|
|
|
|
ssize_t SortedVectorImpl::indexOf(const void* item) const
|
|
|
|
{
|
|
|
|
return _indexOrderOf(item);
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t SortedVectorImpl::orderOf(const void* item) const
|
|
|
|
{
|
|
|
|
size_t o;
|
|
|
|
_indexOrderOf(item, &o);
|
|
|
|
return o;
|
|
|
|
}
|
|
|
|
|
|
|
|
ssize_t SortedVectorImpl::_indexOrderOf(const void* item, size_t* order) const
|
|
|
|
{
|
2015-08-22 23:27:03 +02:00
|
|
|
if (order) *order = 0;
|
|
|
|
if (isEmpty()) {
|
|
|
|
return NAME_NOT_FOUND;
|
|
|
|
}
|
2009-03-04 04:31:44 +01:00
|
|
|
// binary search
|
|
|
|
ssize_t err = NAME_NOT_FOUND;
|
|
|
|
ssize_t l = 0;
|
|
|
|
ssize_t h = size()-1;
|
|
|
|
ssize_t mid;
|
|
|
|
const void* a = arrayImpl();
|
|
|
|
const size_t s = itemSize();
|
|
|
|
while (l <= h) {
|
|
|
|
mid = l + (h - l)/2;
|
|
|
|
const void* const curr = reinterpret_cast<const char *>(a) + (mid*s);
|
|
|
|
const int c = do_compare(curr, item);
|
|
|
|
if (c == 0) {
|
|
|
|
err = l = mid;
|
|
|
|
break;
|
|
|
|
} else if (c < 0) {
|
|
|
|
l = mid + 1;
|
|
|
|
} else {
|
|
|
|
h = mid - 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (order) *order = l;
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
ssize_t SortedVectorImpl::add(const void* item)
|
|
|
|
{
|
|
|
|
size_t order;
|
|
|
|
ssize_t index = _indexOrderOf(item, &order);
|
|
|
|
if (index < 0) {
|
|
|
|
index = VectorImpl::insertAt(item, order, 1);
|
|
|
|
} else {
|
|
|
|
index = VectorImpl::replaceAt(item, index);
|
|
|
|
}
|
|
|
|
return index;
|
|
|
|
}
|
|
|
|
|
|
|
|
ssize_t SortedVectorImpl::merge(const VectorImpl& vector)
|
|
|
|
{
|
|
|
|
// naive merge...
|
|
|
|
if (!vector.isEmpty()) {
|
|
|
|
const void* buffer = vector.arrayImpl();
|
|
|
|
const size_t is = itemSize();
|
|
|
|
size_t s = vector.size();
|
|
|
|
for (size_t i=0 ; i<s ; i++) {
|
|
|
|
ssize_t err = add( reinterpret_cast<const char*>(buffer) + i*is );
|
|
|
|
if (err<0) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NO_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
ssize_t SortedVectorImpl::merge(const SortedVectorImpl& vector)
|
|
|
|
{
|
|
|
|
// we've merging a sorted vector... nice!
|
|
|
|
ssize_t err = NO_ERROR;
|
|
|
|
if (!vector.isEmpty()) {
|
|
|
|
// first take care of the case where the vectors are sorted together
|
|
|
|
if (do_compare(vector.itemLocation(vector.size()-1), arrayImpl()) <= 0) {
|
|
|
|
err = VectorImpl::insertVectorAt(static_cast<const VectorImpl&>(vector), 0);
|
|
|
|
} else if (do_compare(vector.arrayImpl(), itemLocation(size()-1)) >= 0) {
|
|
|
|
err = VectorImpl::appendVector(static_cast<const VectorImpl&>(vector));
|
|
|
|
} else {
|
|
|
|
// this could be made a little better
|
|
|
|
err = merge(static_cast<const VectorImpl&>(vector));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
ssize_t SortedVectorImpl::remove(const void* item)
|
|
|
|
{
|
|
|
|
ssize_t i = indexOf(item);
|
|
|
|
if (i>=0) {
|
|
|
|
VectorImpl::removeItemsAt(i, 1);
|
|
|
|
}
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
}; // namespace android
|
|
|
|
|