pod_vector.h
Go to the documentation of this file.
00001 // 
00002 // Copyright (c) 2006-2010, Benjamin Kaufmann
00003 // 
00004 // This file is part of Clasp. See http://www.cs.uni-potsdam.de/clasp/ 
00005 // 
00006 // Clasp is free software; you can redistribute it and/or modify
00007 // it under the terms of the GNU General Public License as published by
00008 // the Free Software Foundation; either version 2 of the License, or
00009 // (at your option) any later version.
00010 // 
00011 // Clasp is distributed in the hope that it will be useful,
00012 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 // GNU General Public License for more details.
00015 // 
00016 // You should have received a copy of the GNU General Public License
00017 // along with Clasp; if not, write to the Free Software
00018 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00019 //
00020 #ifndef BK_LIB_POD_VECTOR_H_INCLUDED
00021 #define BK_LIB_POD_VECTOR_H_INCLUDED
00022 #include "type_manip.h"
00023 #include <iterator>
00024 #include <memory>
00025 #include <cstring>
00026 #include <algorithm>
00027 #include <cassert>
00028 #include <stdexcept>
00029 namespace bk_lib { namespace detail {
00030         template <class T>
00031         void fill(T* first, T* last, const T& x) {
00032                 assert(first <= last);
00033                 switch ((last - first) & 7u)
00034                 {
00035                 case 0:
00036                                 while (first != last)
00037                                 {
00038                                 new(first++) T(x);
00039                 case 7: new(first++) T(x);
00040                 case 6: new(first++) T(x);
00041                 case 5: new(first++) T(x);
00042                 case 4: new(first++) T(x);
00043                 case 3: new(first++) T(x);
00044                 case 2: new(first++) T(x);
00045                 case 1: new(first++) T(x);
00046                                 assert(first <= last);
00047                                 }
00048                 }
00049         }
00050         template <class Iter, class T>
00051         void copy(Iter first, Iter last, std::size_t s, T* out) {
00052                 switch (s & 7u)
00053                 {
00054                 case 0:
00055                                 while (first != last)
00056                                 {
00057                                 new(out++) T(*first++);
00058                 case 7: new(out++) T(*first++);
00059                 case 6: new(out++) T(*first++);
00060                 case 5: new(out++) T(*first++);
00061                 case 4: new(out++) T(*first++);
00062                 case 3: new(out++) T(*first++);
00063                 case 2: new(out++) T(*first++);
00064                 case 1: new(out++) T(*first++);
00065                                 }
00066                 }
00067         }
00068         template <class T>
00069         struct Fill {
00070                 Fill(const T& val) : val_(val) {}
00071                 void operator()(T* first, std::size_t n) const { detail::fill(first, first + n, val_); }
00072                 const T& val_;
00073         private: Fill& operator=(const Fill&);
00074         };
00075         template <class Iter>
00076         struct Copy {
00077                 Copy(Iter first, Iter last) : first_(first), last_(last) {}
00078                 template <class T>
00079                 void operator()(T* out, std::size_t n) const { detail::copy(first_, last_, n, out); }
00080                 Iter first_;
00081                 Iter last_;
00082         };
00083         template <class T>
00084         struct Memcpy {
00085                 Memcpy(const T* first) : first_(first) {}
00086                 void operator()(T* out, std::size_t n) const { 
00087                         std::memcpy(out, first_, n*sizeof(T));
00088                 }
00089                 const T* first_;
00090         };
00091         typedef char yes_type;
00092         typedef char (&no_type)[2];
00093         template <class T>
00094         struct IterType {
00095                 static yes_type isPtr(const volatile void*);
00096                 static no_type isPtr(...);
00097                 static yes_type isLong(int64);
00098                 static no_type  isLong(...);
00099                 static T& makeT();
00100                 enum { ptr = sizeof(isPtr(makeT())) == sizeof(yes_type) };
00101                 enum { num = sizeof(isLong(makeT())) == sizeof(yes_type) }; 
00102                 enum { value = ptr ? 1 : num ? 2 : 0 };
00103         };
00104 
00105 } // end namespace bk_lib::detail
00106 
00108 
00114 template <class T, class Allocator = std::allocator<T> >
00115 class pod_vector {
00116 public:
00117         // types:
00118         typedef          pod_vector<T,Allocator>          this_type;//not standard
00119         typedef          Allocator                        allocator_type;
00120         typedef typename Allocator::reference             reference;
00121         typedef typename Allocator::const_reference       const_reference;
00122         typedef typename Allocator::pointer               iterator;
00123         typedef typename Allocator::const_pointer         const_iterator;
00124         typedef typename Allocator::pointer               pointer;
00125         typedef typename Allocator::const_pointer         const_pointer;
00126         typedef std::reverse_iterator<iterator>           reverse_iterator;
00127         typedef std::reverse_iterator<const_iterator>     const_reverse_iterator;
00128         typedef          T                                value_type;   
00129         typedef typename detail::if_then_else<
00130                 sizeof(typename Allocator::size_type)<=sizeof(unsigned int), 
00131                 typename Allocator::size_type, 
00132                 unsigned int>::type                           size_type;
00133         typedef typename detail::if_then_else<
00134                 sizeof(typename Allocator::difference_type)<=sizeof(int), 
00135                 typename Allocator::difference_type, 
00136                 int>::type                                    difference_type;
00137         // ctors
00139 
00142         pod_vector() : ebo_(0, allocator_type()) { }
00143         
00145 
00148         explicit pod_vector(const allocator_type& a) : ebo_(0, a) { }
00149 
00151 
00154         explicit pod_vector(size_type n, const T& value = T(), const allocator_type& a = allocator_type()) 
00155                 : ebo_(n, a) {
00156                 detail::fill(ebo_.buf, ebo_.buf + n, value);    
00157                 ebo_.size = n;
00158         }
00159 
00161 
00164         template <class Iter>
00165         pod_vector(Iter first, Iter last, const allocator_type& a = allocator_type(), typename detail::disable_if<detail::IterType<Iter>::num>::type* = 0) 
00166                 : ebo_(0, a) {
00167                 insert_range(end(), first, last, typename std::iterator_traits<Iter>::iterator_category());
00168         }
00169         
00171 
00174         pod_vector(const pod_vector& other) : ebo_(other.size(), other.get_allocator()) {
00175                 std::memcpy(ebo_.buf, other.begin(), other.size()*sizeof(T));
00176                 ebo_.size = other.size();
00177         }
00178 
00179         pod_vector& operator=(const pod_vector& other) {
00180                 if (this != &other) {
00181                         assign(other.begin(), other.end());
00182                 }
00183                 return *this;
00184         }
00185 
00187 
00190         ~pod_vector() { }
00191 
00196         
00198         size_type size()     const { return ebo_.size; }
00200         size_type max_size() const { 
00201                 typename allocator_type::size_type x = get_allocator().max_size();
00202                 std::size_t                        y = size_type(-1)/sizeof(T);
00203                 return static_cast<size_type>(std::min(std::size_t(x), y));
00204         }
00206         size_type capacity() const  { return ebo_.cap; }
00208         bool empty() const { return ebo_.size == 0;  }
00209 
00210         const_iterator begin() const { return ebo_.buf; }
00211         const_iterator end()   const { return ebo_.buf+ebo_.size;}
00212         const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); }
00213         const_reverse_iterator rend()   const { return const_reverse_iterator(begin()); }
00214 
00215         iterator       begin()  { return ebo_.buf; }
00216         iterator       end()    { return ebo_.buf+ebo_.size; }
00217         reverse_iterator rbegin() { return reverse_iterator(end()); }
00218         reverse_iterator rend()   { return reverse_iterator(begin()); }
00219         
00221         allocator_type get_allocator() const { return ebo_; }
00222         
00224 
00228         
00230 
00233         reference operator[](size_type n) {
00234                 assert(n < size());
00235                 return ebo_.buf[n];
00236         }
00237         
00239 
00242         const_reference operator[](size_type n) const {
00243                 assert(n < size());
00244                 return ebo_.buf[n];
00245         }
00246         
00248         const_reference at(size_type n) const {
00249                 if (n < size()) return ebo_.buf[n];
00250                 throw std::range_error("pod_vector::at");
00251         }
00253         reference at(size_type n) {
00254                 if (n < size()) return ebo_.buf[n];
00255                 throw std::range_error("pod_vector::at");
00256         }
00257         
00259         reference front() { assert(!empty()); return *ebo_.buf; }
00261         const_reference front() const { assert(!empty()); return *ebo_.buf; }
00262         
00264         reference back() { assert(!empty()); return ebo_.buf[ebo_.size-1]; }
00265         
00267         const_reference back() const { assert(!empty()); return ebo_.buf[ebo_.size-1]; }
00268         
00270 
00274         
00276 
00279         void clear() { ebo_.size = 0; }
00280 
00281         void assign(size_type n, const T& val) {
00282                 clear();
00283                 insert(end(), n, val);
00284         }
00285         
00286         template <class Iter>
00287         void assign(Iter first, Iter last) {
00288                 clear();
00289                 insert(end(), first, last);
00290         }
00291         
00293 
00300         iterator erase(iterator pos) {
00301                 assert(!empty() && pos != end());
00302                 erase(pos, pos + 1);
00303                 return pos;
00304         }
00305 
00307 
00310         iterator erase(iterator first, iterator last) {
00311                 if (end() - last > 0) {
00312                         std::memmove(first, last, (end() - last) * sizeof(T));
00313                 }
00314                 ebo_.size -= static_cast<size_type>(last - first);
00315                 return first;
00316         }
00317 
00319 
00326         void resize(size_type ns, const T& val = T()) {
00327                 if (ns > size()) {
00328                         ns <= capacity() ? detail::fill(end(), end()+(ns-size()), val) : append_realloc(ns-size(), val);
00329                 }
00330                 ebo_.size = ns;
00331         }
00332 
00334 
00342         void reserve(size_type n) {
00343                 if (n > capacity()) {
00344                         T* temp = ebo_.allocate(n);
00345                         std::memcpy(temp, ebo_.buf, size()*sizeof(T));
00346                         ebo_.release();
00347                         ebo_.buf = temp;
00348                         ebo_.cap = n;
00349                 }
00350         }
00351 
00352         void swap(pod_vector& other) {
00353                 std::swap(ebo_.buf, other.ebo_.buf);
00354                 std::swap(ebo_.size, other.ebo_.size);
00355                 std::swap(ebo_.cap, other.ebo_.cap);
00356         }
00357 
00359         void push_back(const T& x) {
00360                 if (size() < capacity()) {
00361                         new ((ebo_.buf+ebo_.size++)) T(x);
00362                 }
00363                 else {
00364                         append_realloc(1, x);
00365                 }
00366         }
00367         
00369 
00372         void pop_back() {
00373                 assert(!empty());
00374                 --ebo_.size;
00375         }
00376 
00378 
00385         iterator insert(iterator pos, const T& val) {
00386                 return insert(pos, (size_type)1, val);
00387         }
00388 
00390 
00393         iterator insert(iterator pos, size_type n, const T& val) {
00394                 size_type off = static_cast<size_type>(pos-begin());
00395                 insert_impl(pos, n, detail::Fill<T>(val));
00396                 return ebo_.buf + off;
00397         }
00398 
00400 
00407         template <class Iter>
00408         void insert(iterator pos, Iter first, Iter last, typename detail::disable_if<detail::IterType<Iter>::num>::type* = 0) {
00409                 insert_range(pos, first, last, typename std::iterator_traits<Iter>::iterator_category());
00410         }
00411 
00412         
00417         
00419 
00427         void resize_no_init(size_type ns) {
00428                 reserve(ns);
00429                 ebo_.size = ns;
00430         }
00432 private:
00433         size_type grow_size(size_type n) {
00434                 size_type new_cap = size() + n;
00435                 assert(new_cap > size() && "pod_vector: max size exceeded!");
00436                 assert(new_cap > capacity());
00437                 if (new_cap < 4) new_cap = 1 << (new_cap+1);
00438                 size_type x = (capacity()*3)>>1;
00439                 if (new_cap < x) new_cap = x;
00440                 return new_cap;
00441         }
00442         void append_realloc(size_type n, const T& x) {
00443                 size_type new_cap = grow_size(n);
00444                 pointer temp      = ebo_.allocate(new_cap);
00445                 std::memcpy(temp, ebo_.buf, size()*sizeof(T));
00446                 detail::fill(temp+size(), temp+size()+n, x);
00447                 ebo_.release();
00448                 ebo_.buf  = temp;
00449                 ebo_.cap  = new_cap;
00450                 ebo_.size+= n;
00451         }
00452         void move_right(iterator pos, size_type n) {
00453                 assert( (pos || n == 0) && (ebo_.eos() - pos) >= (int)n);
00454                 std::memmove(pos + n, pos, (end() - pos) * sizeof(T));
00455         }
00456         template <class It>
00457         void insert_range(iterator pos, It first, It last,  std::random_access_iterator_tag, 
00458                 typename detail::disable_if<detail::same_type<pointer, It>::value == 0 && detail::same_type<const_pointer, It>::value == 0>::type* = 0) {
00459                 assert( (first < begin() || first >= end()) && "pod_vec::insert(): Precondition violated!");
00460                 typename allocator_type::difference_type diff = std::distance(first, last);
00461                 assert(diff == 0 || (static_cast<size_type>(size()+diff) > size() && "pod_vector: max size exceeded!"));
00462                 insert_impl(pos, static_cast<size_type>(diff), detail::Memcpy<T>(first));
00463         }
00464         template <class It>
00465         void insert_range(iterator pos, It first, It last,  std::forward_iterator_tag) {
00466                 typename allocator_type::difference_type diff = std::distance(first, last);
00467                 assert(diff == 0 || (static_cast<size_type>(size()+diff) > size() && "pod_vector: max size exceeded!"));
00468                 insert_impl(pos, static_cast<size_type>(diff), detail::Copy<It>(first, last));
00469         }
00470         template <class Iter>
00471         void insert_range(iterator pos, Iter first, Iter last, std::input_iterator_tag) {
00472                 pod_vector<T> temp;
00473                 while (first != last) temp.push_back(*first++);
00474                 insert(pos, temp.begin(), temp.end());
00475         }
00476         
00477         // NOTE: template parameter ST should always equal size_type
00478         // and is only needed to workaround an internal compiler error
00479         // in gcc 3.4.3
00480         template <class ST, class P>
00481         void insert_impl(iterator pos, ST n, const P& pred) {
00482                 assert(n == 0 || (size()+n) > size() );
00483                 if (size()+n <= capacity()) {
00484                         move_right(pos, n);
00485                         pred(pos, n);
00486                         ebo_.size += n;
00487                 }
00488                 else {
00489                         size_type new_cap = grow_size(n);
00490                         pointer temp      = ebo_.allocate(new_cap);
00491                         size_type prefix  = static_cast<size_type>(pos-begin());
00492                         // copy prefix
00493                         std::memcpy(temp, begin(), prefix*sizeof(T));
00494                         // insert new stuff
00495                         pred(temp+prefix, n);
00496                         // copy suffix
00497                         std::memcpy(temp+prefix+n, pos, (end()-pos)*sizeof(T));
00498                         ebo_.release();
00499                         ebo_.buf  = temp;
00500                         ebo_.size+= n;
00501                         ebo_.cap  = new_cap;
00502                 }
00503         }
00504         struct ebo : public Allocator { // empty-base-optimization
00505                 typedef typename this_type::size_type size_type;
00506                 typedef typename this_type::allocator_type A;
00507                 pointer    buf;  // pointer to array
00508                 size_type  size; // current size (used elements)
00509                 size_type  cap;  // max size before regrow
00510                 ebo(size_type n, const Allocator& a) : Allocator(a), buf(0), size(0), cap(n) {
00511                         if (n > 0) {  buf = A::allocate(n); }
00512                 }
00513                 ~ebo()            { release(); }
00514                 void release()    { if (buf) A::deallocate(buf, cap); }
00515                 T*   eos() const  { return buf + cap; }
00516         }      ebo_;
00517 };
00518 
00519 template <class T, class A>
00520 inline bool operator==(const pod_vector<T, A>& lhs, const pod_vector<T, A>& rhs) {
00521         return lhs.size() == rhs.size()
00522                 && std::equal(lhs.begin(), lhs.end(), rhs.begin());
00523 }
00524 
00525 template <class T, class A>
00526 inline bool operator!=(const pod_vector<T, A>& lhs, const pod_vector<T, A>& rhs) {
00527         return ! (lhs == rhs);
00528 }
00529 
00530 template <class T, class A>
00531 inline bool operator<(const pod_vector<T, A>& lhs, const pod_vector<T, A>& rhs) {
00532         return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
00533 }
00534 
00535 template <class T, class A>
00536 inline bool operator>(const pod_vector<T, A>& lhs, const pod_vector<T, A>& rhs) {
00537         return rhs < lhs;
00538 }
00539 
00540 template <class T, class A>
00541 inline bool operator<=(const pod_vector<T, A>& lhs, const pod_vector<T, A>& rhs) {  
00542         return !(rhs < lhs);
00543 }
00544 
00545 template <class T, class A>
00546 inline bool operator>=(const pod_vector<T, A>& lhs, const pod_vector<T, A>& rhs) {
00547         return !(lhs < rhs);
00548 }
00549 
00550 template <class T, class A>
00551 inline void swap(pod_vector<T, A>& lhs, pod_vector<T, A>& rhs) { 
00552         lhs.swap(rhs);
00553 }
00554 
00555 }
00556 
00557 #endif 
00558 


clasp
Author(s): Benjamin Kaufmann
autogenerated on Thu Aug 27 2015 12:41:39