/* -*- 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 #include #include #include #include #include #include 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 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 iterator; typedef __wrapper_iterator 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 vector(_Iterator first, _Iterator last) { // Because of template matching, vector(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 void range_initialize(_Iterator first, _Iterator last, random_access_iterator_tag); // Initialize from an input iterator. template 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 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 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 vector<_T>::vector() :mBegin(NULL), mCapacity(0), mLength(0) { } template vector<_T>::vector(const size_type num, const value_type& init_value) { repeat_initialize(num, init_value); } template void vector<_T>::repeat_initialize(const size_type num, const value_type& init_value) { if (num < max_size()) { mBegin = static_cast(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 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) { pointer oldBegin = mBegin; mBegin = static_cast( realloc(mBegin, new_size * sizeof(value_type))); if (!mBegin) { mBegin = oldBegin; return false; } } else { pointer newBegin = static_cast( 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 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) { *(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 void vector<_T>::pop_back() { if (mLength > 0) { --mLength; if (!is_pod::value) { (mBegin + mLength)->~_T(); } } } template typename vector<_T>::iterator vector<_T>::erase(iterator pos) { if (mLength) { std::copy(pos + 1, end(), pos); --mLength; if (!is_pod::value) { end()->~_T(); } } return pos; } template 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) { while (last != end()) { last->~_T(); ++last; } } mLength -= len; } return first; } template void vector<_T>::clear() { if(mBegin) { if (is_pod::value) { free(mBegin); } else { deallocate(); } } mBegin = NULL; mCapacity = 0; mLength = 0; } template 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) { 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 void vector<_T>::swap(vector& other) { std::swap(mBegin, other.mBegin); std::swap(mCapacity, other.mCapacity); std::swap(mLength, other.mLength); } template template 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 template 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(num) < max_size()) { mBegin = static_cast(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 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 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 _T vector<_T>::sDummy; } // namespace std #endif // ANDROID_ASTL_VECTOR__