left_right_sequence.h
Go to the documentation of this file.
00001 // 
00002 // Copyright (c) 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_LEFT_RIGHT_SEQUENCE_INCLUDED
00021 #define BK_LIB_LEFT_RIGHT_SEQUENCE_INCLUDED
00022 #ifdef _MSC_VER
00023 #pragma warning( push )
00024 #pragma warning (disable : 4200)
00025 #endif
00026 #include "type_manip.h"
00027 #include <iterator>
00028 #include <cassert>
00029 #include <cstring>
00030 namespace bk_lib { namespace detail {
00031 
00032 // base class for left_right_sequence
00033 // see below
00034 template <class L, class R>
00035 class left_right_rep {
00036 public: 
00037         typedef L left_type;
00038         typedef R right_type;
00039         typedef unsigned int size_type;
00040         typedef L*       left_iterator;
00041         typedef const L* const_left_iterator;
00042         typedef std::reverse_iterator<R*>       right_iterator;
00043         typedef std::reverse_iterator<const R*> const_right_iterator;
00044 
00045         typedef typename bk_lib::detail::align_of<left_type>::type  left_align_type;
00046         typedef typename bk_lib::detail::align_of<right_type>::type right_align_type;
00047 
00048         typedef typename bk_lib::detail::if_then_else<
00049                 sizeof(left_type) >= sizeof(right_type), 
00050                 left_type,
00051                 right_type>::type max_type;
00052         typedef typename bk_lib::detail::if_then_else<
00053                 sizeof(left_align_type) >= sizeof(right_align_type), 
00054                 left_align_type,
00055                 right_align_type>::type align_type;
00056                 
00057         left_right_rep() : buf_(0), cap_(0), free_(0), left_(0), right_(0) {}
00058         
00059         bool      empty()         const { return left_ == 0 && right_ == cap_; }
00060         size_type left_size()     const { return left_/sizeof(left_type); }
00061         size_type right_size()    const { return (cap_-right_)/sizeof(right_type); }
00062         size_type size()          const { return left_size() + right_size(); }
00063         size_type left_capacity() const { return (cap_ / sizeof(left_type)); }
00064         size_type right_capacity()const { return (cap_ / sizeof(right_type)); }
00065         const_left_iterator  left_begin() const { return const_left_iterator(reinterpret_cast<const left_type*>(begin())); }
00066         const_left_iterator  left_end()   const { return const_left_iterator(reinterpret_cast<const left_type*>(buf_+left_)); }
00067               left_iterator  left_begin()       { return left_iterator(reinterpret_cast<left_type*>(begin())); }
00068               left_iterator  left_end()         { return left_iterator(reinterpret_cast<left_type*>(buf_+left_)); }
00069         const_right_iterator right_begin()const { return const_right_iterator(reinterpret_cast<const right_type*>(end())); }
00070         const_right_iterator right_end()  const { return const_right_iterator(reinterpret_cast<const right_type*>(buf_+right_)); }
00071               right_iterator right_begin()      { return right_iterator(reinterpret_cast<right_type*>(end())); }
00072               right_iterator right_end()        { return right_iterator(reinterpret_cast<right_type*>(buf_+right_)); }
00073         const left_type&     left(size_type i)const { return *(left_begin()+i); }
00074               left_type&     left(size_type i)      { return *(left_begin()+i); }
00075 
00076         void clear(bool releaseMem = false) {
00077                 if (releaseMem) {
00078                         release();
00079                         buf_  = 0; 
00080                         cap_  = 0;
00081                         free_ = 0;
00082                 }
00083                 left_ = 0;
00084                 right_= cap_;
00085         }
00086         void push_left(const left_type& x) {
00087                 if ((left_ + sizeof(left_type)) > right_) {
00088                         realloc();
00089                 }
00090                 new (left())left_type(x);
00091                 left_ += sizeof(left_type);
00092         }
00093 
00094         void push_right(const right_type& x) {
00095                 if ( (left_ + sizeof(right_type)) > right_ ) {
00096                         realloc();
00097                 }
00098                 right_ -= sizeof(right_type);
00099                 new (right()) right_type(x);
00100         }
00101         void pop_left() {
00102                 assert(left_size() != 0);
00103                 left_ -= sizeof(left_type);
00104         }
00105         void pop_right() {
00106                 assert(right_size() != 0);
00107                 right_ += sizeof(right_type);
00108         }
00109 
00110         void erase_left(left_iterator it) {
00111                 if (it != left_end()) {
00112                         left_iterator x = it++;
00113                         std::memmove(x, it, (left_end()-it)*sizeof(left_type));
00114                         left_ -= sizeof(left_type);
00115                 }
00116         }
00117         void erase_left_unordered(left_iterator it) {
00118                 if (it != left_end()) {
00119                         left_ -= sizeof(left_type);
00120                         *it    = *reinterpret_cast<left_type*>(left());
00121                 }
00122         }
00123         void erase_right(right_iterator it) {
00124                 if (it != right_end()) {
00125                         right_type* r = (++it).base();
00126                         right_type* b = reinterpret_cast<right_type*>(right());
00127                         assert(r >= b);
00128                         std::memmove(b+1, b, (r-b)*sizeof(right_type));
00129                         right_ += sizeof(right_type);
00130                 }
00131         }
00132         void erase_right_unordered(right_iterator it) {
00133                 if (it != right_end()) {
00134                         *it    = *reinterpret_cast<right_type*>(right());
00135                         right_+= sizeof(right_type);
00136                 }
00137         }
00138         void shrink_left(left_iterator it) {
00139                 left_ = static_cast<size_type>((it - left_begin())*sizeof(left_type));
00140         }
00141         void shrink_right(right_iterator it) {
00142                 buf_type* x = reinterpret_cast<buf_type*>(it.base());
00143                 right_ = static_cast<size_type>(x - begin());
00144         }
00145         enum { block_size      = ((sizeof(max_type)+(sizeof(align_type)-1)) / sizeof(align_type)) * sizeof(align_type) };
00146 protected:
00147         left_right_rep(const left_right_rep&) { }
00148         left_right_rep& operator=(const left_right_rep&) { return *this; }
00149         typedef unsigned char buf_type;
00150         buf_type*       begin()      { return buf_; }
00151         const buf_type* begin()const { return buf_; }
00152         buf_type*       end()        { return buf_+cap_; }
00153         const buf_type* end()  const { return buf_+cap_; }
00154         buf_type*       left()       { return buf_+left_; }
00155         buf_type*       right()      { return buf_+right_; }
00156         size_type    capacity()const { return cap_ / block_size; }
00157         size_type    raw_size()const { return left_ + (cap_-right_); }
00158         void release()               { if (free_ != 0) { ::operator delete(buf_); } }
00159         void realloc();
00160         buf_type* buf_;
00161         size_type cap_ : 31;
00162         size_type free_:  1;
00163         size_type left_;
00164         size_type right_;
00165 };
00166 
00167 template <class L, class R>
00168 void left_right_rep<L, R>::realloc() {
00169         size_type new_cap = ((capacity()*3)>>1) * block_size;
00170         size_type min_cap = 4 * block_size;
00171         if (new_cap < min_cap) new_cap = min_cap;
00172         buf_type* temp = (buf_type*)::operator new(new_cap*sizeof(buf_type));
00173         // copy left
00174         std::memcpy(temp, begin(), left_size()*sizeof(L));
00175         // copy right
00176         size_type r = cap_ - right_;
00177         std::memcpy(temp+(new_cap-r), right(), right_size() * sizeof(R));
00178         // swap
00179         release();
00180         buf_   = temp;
00181         cap_   = new_cap;
00182         free_  = 1;
00183         right_ = new_cap - r;
00184 }
00185 
00186 // always store sequence in heap-allocated buffer
00187 template <class L, class R>
00188 struct no_inline_buffer : public left_right_rep<L, R> {
00189         typedef typename left_right_rep<L, R>::buf_type buf_type;
00190         enum { inline_raw_cap = 0 };
00191         buf_type* extra()           { return 0; }
00192 };
00193 
00194 // store small sequences directly inside of object
00195 template <class L, class R, unsigned cap>
00196 struct with_inline_buffer : public left_right_rep<L, R> {
00197         typedef typename left_right_rep<L, R>::buf_type   buf_type;
00198         typedef typename left_right_rep<L, R>::align_type align_type;
00199         enum { inline_raw_cap = cap };
00200         buf_type* extra()           { return rep_.mem; }
00201         union X {
00202                 align_type align;
00203                 buf_type   mem[inline_raw_cap];
00204         } rep_;
00205 };
00206 
00207 // select proper base class for left_right_sequence based
00208 // on parameter i
00209 template <class L, class R, unsigned i>
00210 struct select_base {
00211 private:
00212         typedef unsigned char        buf_type;
00213         typedef left_right_rep<L, R> base_type;
00214         typedef typename base_type::size_type size_type;
00215         typedef typename base_type::align_type align_type;
00216         typedef no_inline_buffer<L, R> no_extra_type;
00217         typedef with_inline_buffer<L, R, sizeof(align_type)> with_extra_type;
00218         
00219         enum { padding         = sizeof(with_extra_type) - (sizeof(no_extra_type)+sizeof(align_type)) };
00220         enum { size_with_pad   = sizeof(no_extra_type) + padding };
00221         enum { store_extra     = (i > size_with_pad) && (i - size_with_pad) >= base_type::block_size };
00222         enum { inline_raw_cap  = store_extra ? ((i - size_with_pad)/base_type::block_size)*base_type::block_size : 0 };
00223 public:
00224         typedef typename if_then_else<
00225                 store_extra!=0, 
00226                 with_inline_buffer<L, R, inline_raw_cap>,
00227                 no_inline_buffer<L, R> >::type type;
00228 };
00229 
00230 
00231 } // bk_lib::detail
00232 
00234 
00244 template <class L, class R, unsigned i>
00245 class left_right_sequence : public bk_lib::detail::select_base<L, R, i>::type {
00246 public:
00247         typedef typename bk_lib::detail::select_base<L, R, i>::type base_type;
00248         typedef typename base_type::left_type  left_type;
00249         typedef typename base_type::right_type right_type;
00250         typedef typename base_type::size_type  size_type;
00251         typedef typename base_type::align_type align_type;
00252         typedef typename base_type::max_type   max_type;
00253         typedef typename base_type::buf_type   buf_type;
00254 
00255         typedef typename base_type::left_iterator       left_iterator;
00256         typedef typename base_type::const_left_iterator const_left_iterator;
00257         typedef typename base_type::right_iterator       right_iterator;
00258         typedef typename base_type::const_right_iterator const_right_iterator;
00259             
00260         left_right_sequence() {
00261                 this->buf_  = this->extra();
00262                 this->cap_  = base_type::inline_raw_cap;
00263                 this->free_ = 0;
00264                 this->left_ = 0;
00265                 this->right_= base_type::inline_raw_cap;
00266         }
00267         left_right_sequence(const left_right_sequence& other);
00268         ~left_right_sequence() { this->release(); }
00269         left_right_sequence& operator=(const left_right_sequence&);
00270 
00271         void try_shrink() {
00272                 if (this->raw_size() <= base_type::inline_raw_cap && this->buf_ != this->extra()) {
00273                         buf_type* e = this->extra();
00274                         size_type c = base_type::inline_raw_cap;
00275                         size_type r = c - (this->right_size()*sizeof(right_type));
00276                         std::memcpy(e,   this->begin(), this->left_size() * sizeof(left_type));
00277                         std::memcpy(e+r, this->right(), this->right_size()* sizeof(right_type));
00278                         this->release();
00279                         this->buf_  = e;
00280                         this->cap_  = c;
00281                         this->free_ = 0;
00282                         this->right_= r;
00283                 }
00284         }
00285         void move(left_right_sequence& other) {
00286                 this->clear(true);
00287                 if (other.raw_size() <= base_type::inline_raw_cap) {
00288                         copy(other);
00289                         other.clear(true);
00290                 }
00291                 else {
00292                         this->buf_   = other.buf_;
00293                         this->cap_   = other.cap_;
00294                         this->free_  = other.free_;
00295                         this->left_  = other.left_;
00296                         this->right_ = other.right_;
00297                         other.buf_  = other.extra();
00298                         other.cap_  = base_type::inline_raw_cap;
00299                         other.free_ = 0;
00300                         other.left_ = 0;
00301                         other.right_= base_type::inline_raw_cap;
00302                 }
00303         }
00304 private:
00305         void      copy(const left_right_sequence&);
00306 };
00307 
00308 template <class L, class R, unsigned i>
00309 void left_right_sequence<L, R, i>::copy(const left_right_sequence& other) {
00310         size_type os = other.raw_size();
00311         if ( os <= base_type::inline_raw_cap ) {
00312                 this->buf_ = this->extra();
00313                 this->cap_ = base_type::inline_raw_cap;
00314                 this->free_= 0;
00315         }
00316         else {
00317                 os         = ((os + (base_type::block_size-1)) / base_type::block_size) * base_type::block_size;
00318                 this->buf_ = (buf_type*)::operator new(os*sizeof(buf_type));
00319                 this->cap_ = os;
00320                 this->free_= 1;
00321         }
00322         this->left_ = other.left_;
00323         this->right_= this->cap_ - (other.right_size()*sizeof(right_type));
00324         std::memcpy(this->begin(), other.begin(), other.left_size()*sizeof(left_type));
00325         std::memcpy(this->right(), const_cast<left_right_sequence&>(other).right(), other.right_size()*sizeof(right_type));
00326 }
00327 
00328 template <class L, class R, unsigned i>
00329 left_right_sequence<L, R, i>::left_right_sequence(const left_right_sequence& other) : base_type(other) {
00330         copy(other);
00331 }
00332 
00333 template <class L, class R, unsigned i>
00334 left_right_sequence<L, R, i>& left_right_sequence<L, R, i>::operator=(const left_right_sequence& other) {
00335         if (this != &other) {
00336                 this->release();
00337                 copy(other);
00338         }
00339         return *this;
00340 }
00341 
00342 
00343 } // namespace bk_lib
00344 
00345 
00346 #ifdef _MSC_VER
00347 #pragma warning(pop)
00348 #endif
00349 #endif
00350 


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