blob: b17cc700cfe8a50c1555c9598cdcd3510952efab [file] [log] [blame]
/* -*- c++ -*- */
/*
* Copyright (C) 2009 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef ANDROID_ASTL_VECTOR__
#define ANDROID_ASTL_VECTOR__
#include <cstddef>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <iterator>
#include <memory>
#include <type_traits.h>
namespace std {
#ifdef _T
#error "_T is a macro."
#endif
// Simple vector implementation. Its purpose is to be able to compile code that
// uses the STL and requires std::vector.
//
// IMPORTANT:
// . This class it is not fully STL compliant. Some constructors/methods maybe
// missing, they will be added on demand.
// . A standard container which offers fixed time access to individual
// elements in any order.
//
// TODO: Use the stack for the default constructor. When the capacity
// grows beyond that move the data to the heap.
template<typename _T>
class vector
{
typedef vector<_T> vector_type;
public:
typedef _T value_type;
typedef _T* pointer;
typedef const _T* const_pointer;
typedef _T& reference;
typedef const _T& const_reference;
typedef __wrapper_iterator<pointer,vector_type> iterator;
typedef __wrapper_iterator<const_pointer,vector_type> const_iterator;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
vector();
// Create a vector with bitwise copies of an exemplar element.
// @param num The number of elements to create.
// @param init_value The element to copy.
explicit vector(const size_type num, const value_type& init_value = value_type());
// Create a vector by copying the elements from [first, last).
//
// If the iterators are random-access, the constructor will be
// able to reserve the memory in a single call before copying the
// elements. If the elements are POD, the constructor uses memmove.
template<typename _Iterator>
vector(_Iterator first, _Iterator last) {
// Because of template matching, vector<int>(int n, int val)
// will now match this constructor (int != size_type) instead
// of the repeat one above. In this case, the _Iterator
// template parameter is an integral type and not an iterator,
// we use that to call the correct initialize impl.
typedef typename is_integral<_Iterator>::type integral;
initialize(first, last, integral());
}
~vector() { clear(); }
// @return true if the vector is empty, false otherwise.
bool empty() const { return mLength == 0; }
size_type size() const { return mLength; }
// @return the maximum size for a vector.
size_type max_size() const { return (~size_type(0)) / sizeof(value_type); }
// Change the capacity to new_size. 0 means shrink to fit. The
// extra memory is not initialized when the capacity is grown.
// @param new_size number of element to be allocated.
// @return true if successful. The STL version returns nothing.
bool reserve(size_type new_size = 0);
// @return The total number of elements that the vector can hold
// before more memory gets allocated.
size_type capacity() const { return mCapacity; }
reference front() { return *mBegin; }
const_reference front() const { return *mBegin; }
reference back() { return mLength ? *(mBegin + mLength - 1) : front(); }
const_reference back() const { return mLength ? *(mBegin + mLength - 1) : front(); }
// Subscript access to the vector's elements. Don't do boundary
// check. Use at() for checked access.
// @param index Of the element (0-based).
// @return A const reference to the element.
const_reference operator[](size_type index) const { return *(mBegin + index); }
// @param index Of the element (0-based).
// @return A reference to the element.
reference operator[](size_type index) { return *(mBegin + index); }
// 'at' is similar to operator[] except that it does check bounds.
const_reference at(const size_type index) const
{ return index < mLength ? *( mBegin + index) : sDummy; }
reference at(const size_type index)
{ return index < mLength ? *( mBegin + index) : sDummy; }
iterator begin() { return iterator(mBegin); }
iterator end() { return iterator(mBegin + mLength); }
const_iterator begin() const { return const_iterator(mBegin); }
const_iterator end() const { return const_iterator(mBegin + mLength); }
// Add data at the end of the vector. Constant in time if the
// memory has been preallocated (e.g using reserve).
// @param elt To be added.
void push_back(const value_type& elt);
// Remove the last element. However, no memory is reclaimed from
// the internal buffer: you need to call reserve() to recover it.
void pop_back();
// Remove the element pointed by the iterator.
// Expensive since the remaining elts must be shifted around.
// @param pos Iterator pointing to the elt to be removed.
// @return An iterator pointing to the next elt or end().
iterator erase(iterator pos);
// Remove a range of elements [first, last)
// @param first Iterator pointing to the first element to be removed.
// @param last Iterator pointing to one past the last element to be removed.
// @return An iterator pointing to the elt next to 'last' or end().
iterator erase(iterator first, iterator last);
// Empty the vector on return. Release the internal buffer. Length
// and capacity are both 0 on return. If you want to keep the
// internal buffer around for reuse, call 'resize'/'erase' instead.
void clear();
// Resize the vector to contain 'size' element. If 'size' is
// smaller than the current size, the extra elements are dropped
// but the reserved memory is not changed (use 'swap' to recover
// memory.) If 'size' is greater, the vector is expanded by
// inserting at the end as many copy of 'init_value' (this may
// lead to some realloc) as necessary. See 'reserve'.
void resize(size_type size, value_type init_value = value_type());
void swap(vector& other);
private:
// See the 2 'initialize' methods first. They desambiguate between
// repeat and range initialize. For range initialize, there is
// another desambiguation based on the nature of the iterators.
// Repeat constructor implementation.
void repeat_initialize(const size_type num,
const value_type& init_value);
// Initialize from a random access iterator.
template<typename _Iterator>
void range_initialize(_Iterator first, _Iterator last,
random_access_iterator_tag);
// Initialize from an input iterator.
template<typename _InputIterator>
void range_initialize(_InputIterator first, _InputIterator last,
input_iterator_tag);
// Repeat constructor that matched the templatized constructor for iterator.
// The last parameter true_type is used by the caller to target this method.
template<typename _Integral>
void initialize(_Integral num, _Integral init_value, true_type) {
repeat_initialize((size_type)num, init_value);
}
// Not a repeat constructor (last param type is false_type). first
// and last are really iterators. Dispatch the call depending on
// the iterators' category.
template<typename _InputIterator>
void initialize(_InputIterator first, _InputIterator last, false_type) {
range_initialize(first, last, android::iterator_category(first));
}
// @return New internal buffer size when it is adjusted automatically.
size_type grow() const;
// Calls the class' deallocator explicitely on each instance in
// the vector.
void deallocate();
pointer mBegin;
size_type mCapacity;
size_type mLength;
static value_type sDummy; // at() doen't throw exception and returns mDummy.
static const size_type kExponentialFactor = 2;
static const size_type kExponentialLimit = 256;
static const size_type kLinearIncrement = 256;
};
// The implementation uses malloc instead of new because Posix states that:
// The pointer returned if the allocation succeeds shall be suitably
// aligned so that it may be assigned to a pointer to any type of
// object and then used to access such an object in the space
// allocated
// So as long as we malloc() more than 4 bytes, the returned block
// must be able to contain a pointer, and thus will be 32-bit
// aligned. I believe the bionic implementation uses a minimum of 8 or 16.
//
// Invariant: mLength <= mCapacity <= max_size()
template<typename _T>
vector<_T>::vector()
:mBegin(NULL), mCapacity(0), mLength(0) { }
template<typename _T>
vector<_T>::vector(const size_type num, const value_type& init_value)
{
repeat_initialize(num, init_value);
}
template<typename _T>
void vector<_T>::repeat_initialize(const size_type num,
const value_type& init_value)
{
if (num < max_size())
{
mBegin = static_cast<pointer>(malloc(num * sizeof(value_type)));
if (mBegin)
{
mLength = mCapacity = num;
std::uninitialized_fill(mBegin, mBegin + mLength, init_value);
return;
}
}
mBegin = NULL;
mLength = mCapacity = 0;
}
template<typename _T>
bool vector<_T>::reserve(size_type new_size)
{
if (0 == new_size)
{
if (0 == mLength) // Free whatever has been reserved.
{
clear();
return true;
}
new_size = mLength; // Shrink to fit.
}
else if (new_size < mLength || new_size > max_size())
{
return false;
}
if (is_pod<value_type>::value)
{
pointer oldBegin = mBegin;
mBegin = static_cast<pointer>(
realloc(mBegin, new_size * sizeof(value_type)));
if (!mBegin)
{
mBegin = oldBegin;
return false;
}
}
else
{
pointer newBegin = static_cast<pointer>(
malloc(new_size * sizeof(value_type)));
if (!newBegin) return false;
if (mBegin != NULL) {
std::uninitialized_copy(mBegin, mBegin + mLength, newBegin);
deallocate();
}
mBegin = newBegin;
}
mCapacity = new_size;
return true;
}
template<typename _T>
void vector<_T>::push_back(const value_type& elt)
{
if (max_size() == mLength) return;
if (mCapacity == mLength)
{
const size_type new_capacity = grow();
if (0 == new_capacity || !reserve(new_capacity)) return;
}
// mLength < mCapacity
if (is_pod<value_type>::value) {
*(mBegin + mLength) = elt;
} else {
// The memory where the new element is added is uninitialized,
// we cannot use assigment (lhs is not valid).
new((void *)(mBegin + mLength)) _T(elt);
}
++mLength;
}
template<typename _T>
void vector<_T>::pop_back()
{
if (mLength > 0)
{
--mLength;
if (!is_pod<value_type>::value)
{
(mBegin + mLength)->~_T();
}
}
}
template<typename _T>
typename vector<_T>::iterator
vector<_T>::erase(iterator pos) {
if (mLength) {
std::copy(pos + 1, end(), pos);
--mLength;
if (!is_pod<value_type>::value) {
end()->~_T();
}
}
return pos;
}
template<typename _T>
typename vector<_T>::iterator
vector<_T>::erase(iterator first, iterator last) {
difference_type len = std::distance(first, last);
if (len > 0) {
last = std::copy(last, end(), first);
if (!is_pod<value_type>::value) {
while (last != end()) {
last->~_T();
++last;
}
}
mLength -= len;
}
return first;
}
template<typename _T>
void vector<_T>::clear()
{
if(mBegin)
{
if (is_pod<value_type>::value)
{
free(mBegin);
}
else
{
deallocate();
}
}
mBegin = NULL;
mCapacity = 0;
mLength = 0;
}
template<typename _T>
void vector<_T>::resize(size_type new_size, value_type init_value)
{
if (mLength == new_size || new_size > max_size()) {
return;
} else if (new_size < mLength) {
if (!is_pod<value_type>::value) {
const pointer end = mBegin + mLength;
for (pointer begin = mBegin + new_size;
begin < end; ++begin) {
begin->~_T();
}
}
mLength = new_size;
return;
}
if (new_size > mCapacity && !reserve(new_size)) {
return;
}
std::uninitialized_fill(mBegin + mLength, mBegin + new_size, init_value);
mLength = new_size;
}
template<typename _T>
void vector<_T>::swap(vector& other)
{
std::swap(mBegin, other.mBegin);
std::swap(mCapacity, other.mCapacity);
std::swap(mLength, other.mLength);
}
template<typename _T>
template<typename _InputIterator>
void vector<_T>::range_initialize(_InputIterator first, _InputIterator last,
input_iterator_tag) {
// There is no way to know how many elements we are going to
// insert, call push_back which will alloc/realloc as needed.
mBegin = NULL;
mLength = mCapacity = 0;
for (; first != last; ++first) {
push_back(*first);
}
}
template<typename _T>
template<typename _Iterator>
void vector<_T>::range_initialize(_Iterator first, _Iterator last,
random_access_iterator_tag) {
typedef typename iterator_traits<_Iterator>::difference_type difference_type;
const difference_type num = std::distance(first, last);
if (0 <= num && static_cast<size_type>(num) < max_size()) {
mBegin = static_cast<pointer>(malloc(num * sizeof(value_type)));
if (mBegin) {
mLength = mCapacity = num;
std::uninitialized_copy(first, last, iterator(mBegin));
return;
}
}
mBegin = NULL;
mLength = mCapacity = 0;
}
// Grow the capacity. Use exponential until kExponentialLimit then
// linear until it reaches max_size().
template<typename _T>
typename vector<_T>::size_type vector<_T>::grow() const
{
size_type new_capacity;
if (mCapacity > kExponentialLimit)
{
new_capacity = mCapacity + kLinearIncrement;
}
else
{
new_capacity = mCapacity == 0 ? kExponentialFactor : mCapacity * kExponentialFactor;
}
if (mCapacity > new_capacity || new_capacity > max_size())
{ // Overflow: cap at max_size() if not there already.
new_capacity = mCapacity == max_size() ? 0 : max_size();
}
return new_capacity;
}
// mBegin should not be NULL.
template<typename _T>
void vector<_T>::deallocate()
{
pointer begin = mBegin;
pointer end = mBegin + mLength;
for (; begin != end; ++begin)
{
begin->~_T();
}
free(mBegin);
}
// Dummy element returned when at() is out of bound.
template<typename _T> _T vector<_T>::sDummy;
} // namespace std
#endif // ANDROID_ASTL_VECTOR__