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