| /* |
| * 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_ |