Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:53:52

0001 ///////////////////////////////////////////////////////////////////////////////
0002 // sequence_stack.hpp
0003 //
0004 //  Copyright 2008 Eric Niebler. Distributed under the Boost
0005 //  Software License, Version 1.0. (See accompanying file
0006 //  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0007 
0008 #ifndef BOOST_XPRESSIVE_DETAIL_SEQUENCE_STACK_HPP_EAN_10_04_2005
0009 #define BOOST_XPRESSIVE_DETAIL_SEQUENCE_STACK_HPP_EAN_10_04_2005
0010 
0011 // MS compatible compilers support #pragma once
0012 #if defined(_MSC_VER)
0013 # pragma once
0014 # pragma warning(push)
0015 # pragma warning(disable : 4127) // conditional expression constant
0016 #endif
0017 
0018 #include <cstddef>
0019 #include <algorithm>
0020 #include <functional>
0021 
0022 namespace boost { namespace xpressive { namespace detail
0023 {
0024 
0025 struct fill_t {} const fill = {};
0026 
0027 //////////////////////////////////////////////////////////////////////////
0028 // sequence_stack
0029 //
0030 //   For storing a stack of sequences of type T, where each sequence
0031 //   is guaranteed to be stored in contiguous memory.
0032 template<typename T>
0033 struct sequence_stack
0034 {
0035     struct allocate_guard_t;
0036     friend struct allocate_guard_t;
0037     struct allocate_guard_t
0038     {
0039         std::size_t i;
0040         T *p;
0041         bool dismissed;
0042         ~allocate_guard_t()
0043         {
0044             if(!this->dismissed)
0045                 sequence_stack::deallocate(this->p, this->i);
0046         }
0047     };
0048 private:
0049     static T *allocate(std::size_t size, T const &t)
0050     {
0051         allocate_guard_t guard = {0, (T *)::operator new(size * sizeof(T)), false};
0052 
0053         for(; guard.i < size; ++guard.i)
0054             ::new((void *)(guard.p + guard.i)) T(t);
0055         guard.dismissed = true;
0056 
0057         return guard.p;
0058     }
0059 
0060     static void deallocate(T *p, std::size_t i)
0061     {
0062         while(i-- > 0)
0063             (p+i)->~T();
0064         ::operator delete(p);
0065     }
0066 
0067     struct chunk
0068     {
0069         chunk(std::size_t size, T const &t, std::size_t count, chunk *back, chunk *next)
0070           : begin_(allocate(size, t))
0071           , curr_(begin_ + count)
0072           , end_(begin_ + size)
0073           , back_(back)
0074           , next_(next)
0075         {
0076             if(this->back_)
0077                 this->back_->next_ = this;
0078             if(this->next_)
0079                 this->next_->back_ = this;
0080         }
0081 
0082         ~chunk()
0083         {
0084             deallocate(this->begin_, this->size());
0085         }
0086 
0087         std::size_t size() const
0088         {
0089             return static_cast<std::size_t>(this->end_ - this->begin_);
0090         }
0091 
0092         T *const begin_, *curr_, *const end_;
0093         chunk *back_, *next_;
0094 
0095     private:
0096         chunk &operator =(chunk const &);
0097     };
0098 
0099     chunk *current_chunk_;
0100 
0101     // Cache these for faster access
0102     T *begin_;
0103     T *curr_;
0104     T *end_;
0105 
0106     T *grow_(std::size_t count, T const &t)
0107     {
0108         if(this->current_chunk_)
0109         {
0110             // write the cached value of current into the expr.
0111             // OK to do this even if later statements throw.
0112             this->current_chunk_->curr_ = this->curr_;
0113 
0114             // Do we have a expr with enough available memory already?
0115             if(this->current_chunk_->next_ && count <= this->current_chunk_->next_->size())
0116             {
0117                 this->current_chunk_ = this->current_chunk_->next_;
0118                 this->curr_ = this->current_chunk_->curr_ = this->current_chunk_->begin_ + count;
0119                 this->end_ = this->current_chunk_->end_;
0120                 this->begin_ = this->current_chunk_->begin_;
0121                 std::fill_n(this->begin_, count, t);
0122                 return this->begin_;
0123             }
0124 
0125             // grow exponentially
0126             std::size_t new_size = (std::max)(
0127                 count
0128               , static_cast<std::size_t>(static_cast<double>(this->current_chunk_->size()) * 1.5)
0129             );
0130 
0131             // Create a new expr and insert it into the list
0132             this->current_chunk_ = new chunk(new_size, t, count, this->current_chunk_, this->current_chunk_->next_);
0133         }
0134         else
0135         {
0136             // first chunk is 256
0137             std::size_t new_size = (std::max)(count, static_cast<std::size_t>(256U));
0138 
0139             // Create a new expr and insert it into the list
0140             this->current_chunk_ = new chunk(new_size, t, count, 0, 0);
0141         }
0142 
0143         this->begin_ = this->current_chunk_->begin_;
0144         this->curr_ = this->current_chunk_->curr_;
0145         this->end_ = this->current_chunk_->end_;
0146         return this->begin_;
0147     }
0148 
0149     void unwind_chunk_()
0150     {
0151         // write the cached value of curr_ into current_chunk_
0152         this->current_chunk_->curr_ = this->begin_;
0153         // make the previous chunk the current
0154         this->current_chunk_ = this->current_chunk_->back_;
0155 
0156         // update the cache
0157         this->begin_ = this->current_chunk_->begin_;
0158         this->curr_ = this->current_chunk_->curr_;
0159         this->end_ = this->current_chunk_->end_;
0160     }
0161 
0162     bool in_current_chunk(T *ptr) const
0163     {
0164         return !std::less<void*>()(ptr, this->begin_) && std::less<void*>()(ptr, this->end_);
0165     }
0166 
0167 public:
0168     sequence_stack()
0169       : current_chunk_(0)
0170       , begin_(0)
0171       , curr_(0)
0172       , end_(0)
0173     {
0174     }
0175 
0176     ~sequence_stack()
0177     {
0178         this->clear();
0179     }
0180 
0181     // walk to the front of the linked list
0182     void unwind()
0183     {
0184         if(this->current_chunk_)
0185         {
0186             while(this->current_chunk_->back_)
0187             {
0188                 this->current_chunk_->curr_ = this->current_chunk_->begin_;
0189                 this->current_chunk_ = this->current_chunk_->back_;
0190             }
0191 
0192             this->begin_ = this->curr_ = this->current_chunk_->curr_ = this->current_chunk_->begin_;
0193             this->end_ = this->current_chunk_->end_;
0194         }
0195     }
0196 
0197     void clear()
0198     {
0199         // walk to the front of the list
0200         this->unwind();
0201 
0202         // delete the list
0203         for(chunk *next; this->current_chunk_; this->current_chunk_ = next)
0204         {
0205             next = this->current_chunk_->next_;
0206             delete this->current_chunk_;
0207         }
0208 
0209         this->begin_ = this->curr_ = this->end_ = 0;
0210     }
0211 
0212     T *push_sequence(std::size_t count, T const &t)
0213     {
0214         // Check to see if we have overflowed this buffer
0215         std::size_t size_left = static_cast< std::size_t >(this->end_ - this->curr_);
0216         if (size_left < count)
0217         {
0218             // allocate a new block and return a ptr to the new memory
0219             return this->grow_(count, t);
0220         }
0221 
0222         // This is the ptr to return
0223         T *ptr = this->curr_;
0224 
0225         // Advance the high-water mark
0226         this->curr_ += count;
0227 
0228         return ptr;
0229     }
0230 
0231     T *push_sequence(std::size_t count, T const &t, fill_t)
0232     {
0233         T *ptr = this->push_sequence(count, t);
0234         std::fill_n(ptr, count, t);
0235         return ptr;
0236     }
0237 
0238     void unwind_to(T *ptr)
0239     {
0240         while(!this->in_current_chunk(ptr))
0241         {
0242             // completely unwind the current chunk, move to the previous chunk
0243             this->unwind_chunk_();
0244         }
0245         this->current_chunk_->curr_ = this->curr_ = ptr;
0246     }
0247 
0248     // shrink-to-fit: remove any unused nodes in the chain
0249     void conserve()
0250     {
0251         if(this->current_chunk_)
0252         {
0253             for(chunk *next; this->current_chunk_->next_; this->current_chunk_->next_ = next)
0254             {
0255                 next = this->current_chunk_->next_->next_;
0256                 delete this->current_chunk_->next_;
0257             }
0258         }
0259     }
0260 };
0261 
0262 }}} // namespace boost::xpressive::detail
0263 
0264 #if defined(_MSC_VER)
0265 # pragma warning(pop)
0266 #endif
0267 
0268 #endif