blob: 978d4d1e65dacf486bf5e1240d52617fc5b7d694 [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 <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
{
public:
typedef _T value_type;
typedef _T* pointer;
typedef const _T* const_pointer;
typedef _T& reference;
typedef const _T& const_reference;
typedef pointer iterator;
typedef const_pointer 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());
~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.
// @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); }
// We don't have iterator, use pointers for now. begin and end
// return NULL if the vector has been cleared or not initialized.
iterator begin() { return mBegin; }
iterator end() { return mBegin + mLength; }
const_iterator begin() const { return mBegin; }
const_iterator end() const { return 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();
// 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();
void swap(vector& other);
private:
// @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 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)
{
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;
std::uninitialized_copy(mBegin, mBegin + mLength, newBegin);
if (mBegin) 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
*(mBegin + mLength) = 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>
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>::swap(vector& other)
{
std::swap(mBegin, other.mBegin);
std::swap(mCapacity, other.mCapacity);
std::swap(mLength, other.mLength);
}
// 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);
}
} // namespace std
#endif // ANDROID_ASTL_VECTOR__