#ifndef CLICK_VECTOR_HH #define CLICK_VECTOR_HH #include #include CLICK_DECLS /** @file @brief Click's vector container template. */ /** @cond never */ template class vector_memory { public: typedef int size_type; typedef typename AM::type type; typedef type *iterator; inline bool need_argument_copy(const type *argp) const { return fast_argument::is_reference && (uintptr_t) argp - (uintptr_t) l_ < (size_t) (n_ * sizeof(type)); } vector_memory() : l_(0), n_(0), capacity_(0) { } ~vector_memory(); void assign(const vector_memory &x); void assign(size_type n, const type *vp); void resize(size_type n, const type *vp); iterator begin() { return l_; } iterator end() { return l_ + n_; } iterator insert(iterator it, const type *vp); iterator erase(iterator a, iterator b); inline void push_back(const type *vp) { if (n_ < capacity_) { AM::mark_undefined(l_ + n_, 1); AM::fill(l_ + n_, 1, vp); ++n_; } else reserve_and_push_back(-1, vp); } #if HAVE_CXX_RVALUE_REFERENCES inline void move_construct_back(type* vp) { if (n_ < capacity_) { AM::mark_undefined(l_ + n_, 1); AM::move_construct(l_ + n_, vp); ++n_; } else reserve_and_push_back(-1, vp); } #endif inline void pop_back() { assert(n_ > 0); --n_; AM::destroy(l_ + n_, 1); AM::mark_noaccess(l_ + n_, 1); } inline void clear() { AM::destroy(l_, n_); AM::mark_noaccess(l_, n_); n_ = 0; } bool reserve_and_push_back(size_type n, const type *vp); void swap(vector_memory &x); type *l_; size_type n_; size_type capacity_; }; /** @endcond never */ /** @class Vector @brief Vector template. Vector implements a vector, or growable array, suitable for use in the kernel or at user level. Its interface should be compatible with C++'s std::vector, although that type has more methods. Vector elements are accessed with operator[] like arrays, and can be resized and expanded through append operations (see push_back() and resize()). A common (and efficient) usage pattern grows a Vector through repeated push_back() calls. Vector iterators are pointers into the underlying array. This can simplify interactions between Vector and code that expects conventional C arrays. Vector's push_front() and pop_front() operations are quite expensive (O(size()) complexity). For fast push_front() and pop_front() operations, use Deque. Example code: @code Vector v; printf("%d\n", v.size()); // prints "0" v.push_back(1); v.push_back(2); printf("%d\n", v.size()); // prints "2" printf("%d %d\n", v[0], v[1]); // prints "1 2" Vector::iterator it = v.begin(); int *ip = it; // Vector iterators are pointers assert(it == v.end() - 2); v.erase(v.begin()); printf("%d\n", v.size()); // prints "1" printf("%d\n", v[0]); // prints "2" @endcode */ template class Vector { typedef typename array_memory::type array_memory_type; mutable vector_memory vm_; public: typedef T value_type; ///< Value type. typedef T &reference; ///< Reference to value type. typedef const T &const_reference; ///< Const reference to value type. typedef T *pointer; ///< Pointer to value type. typedef const T *const_pointer; ///< Pointer to const value type. /** @brief Type used for value arguments (either T or const T &). */ typedef typename fast_argument::type value_argument_type; typedef const T &const_access_type; typedef int size_type; ///< Type of sizes (size()). typedef T *iterator; ///< Iterator type. typedef const T *const_iterator; ///< Const iterator type. /** @brief Constant passed to reserve() to grow the Vector. */ enum { RESERVE_GROW = (size_type) -1 }; explicit inline Vector(); explicit inline Vector(size_type n, value_argument_type v); inline Vector(const Vector &x); #if HAVE_CXX_RVALUE_REFERENCES inline Vector(Vector &&x); #endif inline Vector &operator=(const Vector &x); #if HAVE_CXX_RVALUE_REFERENCES inline Vector &operator=(Vector &&x); #endif inline Vector &assign(size_type n, value_argument_type v = T()); inline iterator begin(); inline iterator end(); inline const_iterator begin() const; inline const_iterator end() const; inline const_iterator cbegin() const; inline const_iterator cend() const; inline size_type size() const; inline size_type capacity() const; inline bool empty() const; inline void resize(size_type n, value_argument_type v = T()); inline bool reserve(size_type n); inline T &operator[](size_type i); inline const T &operator[](size_type i) const; inline T &at(size_type i); inline const T &at(size_type i) const; inline T &front(); inline const T &front() const; inline T &back(); inline const T &back() const; inline T &unchecked_at(size_type i); inline const T &unchecked_at(size_type i) const; inline T &at_u(size_type i) CLICK_DEPRECATED; inline const T &at_u(size_type i) const CLICK_DEPRECATED; inline T *data(); inline const T *data() const; inline void push_back(value_argument_type v); #if HAVE_CXX_RVALUE_REFERENCES template > inline typename A::enable_rvalue_reference push_back(T &&v); #endif inline void pop_back(); inline void push_front(value_argument_type v); inline void pop_front(); inline iterator insert(iterator it, value_argument_type v); inline iterator erase(iterator it); inline iterator erase(iterator a, iterator b); inline void clear(); inline void swap(Vector &x); }; /** @brief Construct an empty vector. */ template inline Vector::Vector() { } /** @brief Construct a vector containing @a n copies of @a v. */ template inline Vector::Vector(size_type n, value_argument_type v) { vm_.resize(n, array_memory_type::cast(&v)); } /** @brief Construct a vector as a copy of @a x. */ template inline Vector::Vector(const Vector &x) { vm_.assign(x.vm_); } #if HAVE_CXX_RVALUE_REFERENCES /** @overload */ template inline Vector::Vector(Vector &&x) { vm_.swap(x.vm_); } #endif /** @brief Return the number of elements. */ template inline typename Vector::size_type Vector::size() const { return vm_.n_; } /** @brief Test if the vector is empty (size() == 0). */ template inline bool Vector::empty() const { return vm_.n_ == 0; } /** @brief Return the vector's capacity. The capacity is greater than or equal to the size(). Functions such as resize(n) will not allocate new memory for the vector if n <= capacity(). */ template inline typename Vector::size_type Vector::capacity() const { return vm_.capacity_; } /** @brief Return an iterator for the first element in the vector. */ template inline typename Vector::iterator Vector::begin() { return (iterator) vm_.l_; } /** @overload */ template inline typename Vector::const_iterator Vector::begin() const { return (const_iterator) vm_.l_; } /** @brief Return an iterator for the end of the vector. @invariant end() == begin() + size() */ template inline typename Vector::iterator Vector::end() { return (iterator) vm_.l_ + vm_.n_; } /** @overload */ template inline typename Vector::const_iterator Vector::end() const { return (const_iterator) vm_.l_ + vm_.n_; } /** @brief Return a const_iterator for the beginning of the vector. */ template inline typename Vector::const_iterator Vector::cbegin() const { return (const_iterator) vm_.l_; } /** @brief Return a const_iterator for the end of the vector. @invariant cend() == cbegin() + size() */ template inline typename Vector::const_iterator Vector::cend() const { return (iterator) vm_.l_ + vm_.n_; } /** @brief Return a reference to the ith element. @pre 0 <= @a i < size() */ template inline T &Vector::operator[](size_type i) { assert((unsigned) i < (unsigned) vm_.n_); return *(T *)&vm_.l_[i]; } /** @overload */ template inline const T &Vector::operator[](size_type i) const { assert((unsigned) i < (unsigned) vm_.n_); return *(T *)&vm_.l_[i]; } /** @brief Return a reference to the ith element. @pre 0 <= @a i < size() @sa operator[]() */ template inline T &Vector::at(size_type i) { return operator[](i); } /** @overload */ template inline const T &Vector::at(size_type i) const { return operator[](i); } /** @brief Return a reference to the first element. @pre !empty() */ template inline T &Vector::front() { return operator[](0); } /** @overload */ template inline const T &Vector::front() const { return operator[](0); } /** @brief Return a reference to the last element (number size()-1). @pre !empty() */ template inline T &Vector::back() { return operator[](vm_.n_ - 1); } /** @overload */ template inline const T &Vector::back() const { return operator[](vm_.n_ - 1); } /** @brief Return a reference to the ith element. @pre 0 <= @a i < size() Unlike operator[]() and at(), this function does not check bounds, even if assertions are enabled. Use with caution. */ template inline T &Vector::unchecked_at(size_type i) { return *(T *)&vm_.l_[i]; } /** @overload */ template inline const T &Vector::unchecked_at(size_type i) const { return *(T *)&vm_.l_[i]; } /** @cond never */ template inline T &Vector::at_u(size_type i) { return unchecked_at(i); } template inline const T &Vector::at_u(size_type i) const { return unchecked_at(i); } /** @endcond never */ /** @brief Return a pointer to the vector's data. May be null if empty(). */ template inline T *Vector::data() { return (T *) vm_.l_; } /** @overload */ template inline const T *Vector::data() const { return (const T *) vm_.l_; } /** @brief Resize the vector to contain @a n elements. @param n new size @param v value used to fill new elements */ template inline void Vector::resize(size_type n, value_argument_type v) { vm_.resize(n, array_memory_type::cast(&v)); } /** @brief Append element @a v. A copy of @a v is inserted at position size(). Takes amortized O(1) time. */ template inline void Vector::push_back(value_argument_type v) { vm_.push_back(array_memory_type::cast(&v)); } #if HAVE_CXX_RVALUE_REFERENCES /** @overload */ template template inline typename A::enable_rvalue_reference Vector::push_back(T&& v) { vm_.move_construct_back(array_memory_type::cast(&v)); } #endif /** @brief Remove the last element. Takes O(1) time. */ template inline void Vector::pop_back() { vm_.pop_back(); } /** @brief Prepend element @a v. A copy of @a v is added to position 0. Other elements are shifted one position forward. Takes O(size()) time. */ template inline void Vector::push_front(value_argument_type v) { vm_.insert(vm_.l_, array_memory_type::cast(&v)); } /** @brief Remove the first element. Other elements are shifted one position backward. Takes O(size()) time. */ template inline void Vector::pop_front() { vm_.erase(vm_.l_, vm_.l_ + 1); } /** @brief Insert @a v before position @a it. @return An iterator pointing at the new element. */ template inline typename Vector::iterator Vector::insert(iterator it, value_argument_type v) { return (iterator) vm_.insert(array_memory_type::cast(it), array_memory_type::cast(&v)); } /** @brief Remove the element at position @a it. @return An iterator pointing at the element following @a it. */ template inline typename Vector::iterator Vector::erase(iterator it) { return (it < end() ? erase(it, it + 1) : it); } /** @brief Remove the elements in [@a a, @a b). @return An iterator corresponding to @a b. */ template inline typename Vector::iterator Vector::erase(iterator a, iterator b) { return (iterator) vm_.erase(array_memory_type::cast(a), array_memory_type::cast(b)); } /** @brief Remove all elements. @post size() == 0 */ template inline void Vector::clear() { vm_.clear(); } /** @brief Reserve space for at least @a n more elements. @return true iff reserve succeeded. This function changes the vector's capacity(), not its size(). If reserve(@a n) succeeds, then any succeeding call to resize(@a m) with @a m < @a n will succeed without allocating vector memory. */ template inline bool Vector::reserve(size_type n) { return vm_.reserve_and_push_back(n, 0); } /** @brief Swap the contents of this vector and @a x. */ template inline void Vector::swap(Vector &x) { vm_.swap(x.vm_); } /** @brief Replace this vector's contents with a copy of @a x. */ template inline Vector &Vector::operator=(const Vector &x) { vm_.assign(x.vm_); return *this; } #if HAVE_CXX_RVALUE_REFERENCES template inline Vector &Vector::operator=(Vector &&x) { vm_.swap(x.vm_); return *this; } #endif /** @brief Replace this vector's contents with @a n copies of @a v. @post size() == @a n */ template inline Vector &Vector::assign(size_type n, value_argument_type v) { vm_.assign(n, array_memory_type::cast(&v)); return *this; } template inline void click_swap(Vector &a, Vector &b) { a.swap(b); } template inline void assign_consume(Vector &a, Vector &b) { a.swap(b); } CLICK_ENDDECLS #include #endif