blob: 4ce6e7dfeadf18095ac526acadbb2eb43819da8a [file] [log] [blame]
/*
* Copyright (C) 2016 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.
*/
#ifndef CHRE_UTIL_DYNAMIC_VECTOR_IMPL_H_
#define CHRE_UTIL_DYNAMIC_VECTOR_IMPL_H_
#include "chre/util/dynamic_vector.h"
#include <memory>
#include <new>
#include <utility>
#include "chre/util/container_support.h"
#include "chre/util/memory.h"
namespace chre {
template <typename ElementType>
DynamicVector<ElementType>::DynamicVector() {}
template <typename ElementType>
DynamicVector<ElementType>::DynamicVector(DynamicVector<ElementType> &&other)
: DynamicVectorBase(std::move(other)) {}
template <typename ElementType>
DynamicVector<ElementType>::~DynamicVector() {
clear();
memoryFree(data());
}
template <typename ElementType>
DynamicVector<ElementType> &DynamicVector<ElementType>::operator=(
DynamicVector<ElementType> &&other) {
if (this != &other) {
this->~DynamicVector();
mData = other.mData;
mSize = other.mSize;
mCapacity = other.mCapacity;
other.mData = nullptr;
other.mSize = 0;
other.mCapacity = 0;
}
return *this;
}
template <typename ElementType>
void DynamicVector<ElementType>::clear() {
destroy(data(), mSize);
mSize = 0;
}
template <typename ElementType>
ElementType *DynamicVector<ElementType>::data() {
return static_cast<ElementType *>(mData);
}
template <typename ElementType>
const ElementType *DynamicVector<ElementType>::data() const {
return static_cast<const ElementType *>(mData);
}
template <typename ElementType>
typename DynamicVector<ElementType>::size_type
DynamicVector<ElementType>::size() const {
return mSize;
}
template <typename ElementType>
typename DynamicVector<ElementType>::size_type
DynamicVector<ElementType>::capacity() const {
return mCapacity;
}
template <typename ElementType>
bool DynamicVector<ElementType>::empty() const {
return (mSize == 0);
}
template <typename ElementType>
void DynamicVector<ElementType>::pop_back() {
CHRE_ASSERT(!empty());
erase(mSize - 1);
}
template <typename ElementType>
bool DynamicVector<ElementType>::push_back(const ElementType &element) {
return doPushBack(element, typename std::is_trivial<ElementType>::type());
}
template <typename ElementType>
bool DynamicVector<ElementType>::doPushBack(const ElementType &element,
std::true_type) {
return DynamicVectorBase::doPushBack(static_cast<const void *>(&element),
sizeof(ElementType));
}
template <typename ElementType>
bool DynamicVector<ElementType>::doPushBack(const ElementType &element,
std::false_type) {
bool spaceAvailable = prepareForPush();
if (spaceAvailable) {
new (&data()[mSize++]) ElementType(element);
}
return spaceAvailable;
}
template <typename ElementType>
bool DynamicVector<ElementType>::push_back(ElementType &&element) {
bool spaceAvailable = prepareForPush();
if (spaceAvailable) {
new (&data()[mSize++]) ElementType(std::move(element));
}
return spaceAvailable;
}
template <typename ElementType>
template <typename... Args>
bool DynamicVector<ElementType>::emplace_back(Args &&... args) {
bool spaceAvailable = prepareForPush();
if (spaceAvailable) {
new (&data()[mSize++]) ElementType(std::forward<Args>(args)...);
}
return spaceAvailable;
}
template <typename ElementType>
ElementType &DynamicVector<ElementType>::operator[](size_type index) {
CHRE_ASSERT(index < mSize);
return data()[index];
}
template <typename ElementType>
const ElementType &DynamicVector<ElementType>::operator[](
size_type index) const {
CHRE_ASSERT(index < mSize);
return data()[index];
}
template <typename ElementType>
bool DynamicVector<ElementType>::operator==(
const DynamicVector<ElementType> &other) const {
bool vectorsAreEqual = (mSize == other.mSize);
if (vectorsAreEqual) {
for (size_type i = 0; i < mSize; i++) {
if (!(data()[i] == other.data()[i])) {
vectorsAreEqual = false;
break;
}
}
}
return vectorsAreEqual;
}
template <typename ElementType>
bool DynamicVector<ElementType>::reserve(size_type newCapacity) {
return doReserve(newCapacity, typename std::is_trivial<ElementType>::type());
}
template <typename ElementType>
bool DynamicVector<ElementType>::doReserve(size_type newCapacity,
std::true_type) {
return DynamicVectorBase::doReserve(newCapacity, sizeof(ElementType));
}
template <typename ElementType>
bool DynamicVector<ElementType>::doReserve(size_type newCapacity,
std::false_type) {
bool success = (newCapacity <= mCapacity);
if (!success) {
ElementType *newData = static_cast<ElementType *>(
memoryAlloc(newCapacity * sizeof(ElementType)));
if (newData != nullptr) {
if (data() != nullptr) {
uninitializedMoveOrCopy(data(), mSize, newData);
destroy(data(), mSize);
memoryFree(data());
}
mData = newData;
mCapacity = newCapacity;
success = true;
}
}
return success;
}
template <typename ElementType>
bool DynamicVector<ElementType>::resize(size_type newSize) {
// Remove elements from the back to minimize move operations.
while (mSize > newSize) {
pop_back();
}
bool success = reserve(newSize);
if (success) {
while (mSize < newSize) {
new (&data()[mSize++]) ElementType();
}
}
return success;
}
template <typename ElementType>
bool DynamicVector<ElementType>::insert(size_type index,
const ElementType &element) {
bool inserted = prepareInsert(index);
if (inserted) {
new (&data()[index]) ElementType(element);
}
return inserted;
}
template <typename ElementType>
bool DynamicVector<ElementType>::insert(size_type index,
ElementType &&element) {
bool inserted = prepareInsert(index);
if (inserted) {
new (&data()[index]) ElementType(std::move(element));
}
return inserted;
}
template <typename ElementType>
bool DynamicVector<ElementType>::prepareInsert(size_type index) {
// Insertions are not allowed to create a sparse array.
CHRE_ASSERT(index <= mSize);
// TODO: this can be optimized in the case where we need to grow the vector to
// do the shift when transferring the values from the old array to the new.
bool readyForInsert = (index <= mSize && prepareForPush());
if (readyForInsert) {
// If we aren't simply appending the new object, create an opening where
// we'll insert it
if (index < mSize) {
// Make a duplicate of the last item in the slot where we're growing
uninitializedMoveOrCopy(&data()[mSize - 1], 1, &data()[mSize]);
// Shift all elements starting at index towards the end
for (size_type i = mSize - 1; i > index; i--) {
moveOrCopyAssign(data()[i], data()[i - 1]);
}
data()[index].~ElementType();
}
mSize++;
}
return readyForInsert;
}
template <typename ElementType>
void DynamicVector<ElementType>::erase(size_type index) {
CHRE_ASSERT(index < mSize);
doErase(index, typename std::is_trivial<ElementType>::type());
}
template <typename ElementType>
void DynamicVector<ElementType>::doErase(size_type index, std::true_type) {
DynamicVectorBase::doErase(index, sizeof(ElementType));
}
template <typename ElementType>
void DynamicVector<ElementType>::doErase(size_type index, std::false_type) {
mSize--;
for (size_type i = index; i < mSize; i++) {
moveOrCopyAssign(data()[i], data()[i + 1]);
}
data()[mSize].~ElementType();
}
template <typename ElementType>
typename DynamicVector<ElementType>::size_type DynamicVector<ElementType>::find(
const ElementType &element) const {
// TODO: Consider adding iterator support and making this a free function.
size_type i;
for (i = 0; i < size(); i++) {
if (data()[i] == element) {
break;
}
}
return i;
}
template <typename ElementType>
void DynamicVector<ElementType>::swap(size_type index0, size_type index1) {
CHRE_ASSERT(index0 < mSize && index1 < mSize);
if (index0 != index1) {
typename std::aligned_storage<sizeof(ElementType),
alignof(ElementType)>::type tempStorage;
ElementType &temp = *reinterpret_cast<ElementType *>(&tempStorage);
uninitializedMoveOrCopy(&data()[index0], 1, &temp);
moveOrCopyAssign(data()[index0], data()[index1]);
moveOrCopyAssign(data()[index1], temp);
}
}
template <typename ElementType>
ElementType &DynamicVector<ElementType>::front() {
CHRE_ASSERT(mSize > 0);
return data()[0];
}
template <typename ElementType>
const ElementType &DynamicVector<ElementType>::front() const {
CHRE_ASSERT(mSize > 0);
return data()[0];
}
template <typename ElementType>
ElementType &DynamicVector<ElementType>::back() {
CHRE_ASSERT(mSize > 0);
return data()[mSize - 1];
}
template <typename ElementType>
const ElementType &DynamicVector<ElementType>::back() const {
CHRE_ASSERT(mSize > 0);
return data()[mSize - 1];
}
template <typename ElementType>
bool DynamicVector<ElementType>::prepareForPush() {
return doPrepareForPush(typename std::is_trivial<ElementType>::type());
}
template <typename ElementType>
bool DynamicVector<ElementType>::doPrepareForPush(std::true_type) {
return DynamicVectorBase::doPrepareForPush(sizeof(ElementType));
}
template <typename ElementType>
bool DynamicVector<ElementType>::doPrepareForPush(std::false_type) {
return reserve(getNextGrowthCapacity());
}
template <typename ElementType>
typename DynamicVector<ElementType>::iterator
DynamicVector<ElementType>::begin() {
return data();
}
template <typename ElementType>
typename DynamicVector<ElementType>::iterator
DynamicVector<ElementType>::end() {
return (data() + mSize);
}
template <typename ElementType>
typename DynamicVector<ElementType>::const_iterator
DynamicVector<ElementType>::begin() const {
return cbegin();
}
template <typename ElementType>
typename DynamicVector<ElementType>::const_iterator
DynamicVector<ElementType>::end() const {
return cend();
}
template <typename ElementType>
typename DynamicVector<ElementType>::const_iterator
DynamicVector<ElementType>::cbegin() const {
return data();
}
template <typename ElementType>
typename DynamicVector<ElementType>::const_iterator
DynamicVector<ElementType>::cend() const {
return (data() + mSize);
}
} // namespace chre
#endif // CHRE_UTIL_DYNAMIC_VECTOR_IMPL_H_