// include/strector.hh // This file is part of libpbe; see http://svn.chezphil.org/libpbe/ // (C) 2008 Philip Endecott // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #ifndef libpbe_strector_hh #define libpbe_strector_hh // strector: stretchy-vector // ------------------------- // // Provides a vector which stretches when new elements are accessed // using operator[]. // // Since the stretch may cause the vector to re-allocate, operator[] // on a mutable strector invalidates iterators, references and pointers // to its elements unless the index is less than capacity(). // // What should operator[] do for a const strector when you access a // beyond-the-end element? It can't stretch the vector. It could be // undefined (like vector). It could throw. It could return a default // T by value - but then it would have to return by value in all cases. // The option that I've chosen is to return a const reference to a static // T. This is broken if you try to compare addresses of elements. It // is also broken if you expected the reference to change when you wrote // to that element via a mutable reference to the strector, but that would // be broken anyway unless size() < index < capacity() due to the // iterator-invalidation rules. The use of a static may also have // thread-safety problems. // // An additional optional constructor parameter allows you to specify a value // used for new elements when the vector is resized during operator[] and // when a beyond-the-end element is read as above. #include namespace pbe { template < typename T, typename ALLOC=std::allocator > class strector: public std::vector { typedef std::vector base_t; const T default_t; public: // Same ctors as std::vector: strector() {} strector(typename base_t::size_type n): base_t(n) {} strector(typename base_t::size_type n, const T& t): base_t(n,t), default_t(t) {} // The copy-ctor takes a base_t, so we can copy from another strector or // from a compatible std::vector: strector(const base_t& other): base_t(other) {} template strector(iter first, iter last): base_t(first,last) {} // Additional ctor to specify default_t: explicit strector(const T& default_t_): default_t(default_t_) {} typename base_t::reference operator[](typename base_t::size_type n) { if (n>=base_t::size()) { base_t::resize(n+1,default_t); } return base_t::operator[](n); } typename base_t::const_reference operator[](typename base_t::size_type n) const { if (n>=base_t::size()) { return default_t; } return base_t::operator[](n); } }; }; #endif