PageRenderTime 64ms CodeModel.GetById 12ms app.highlight 48ms RepoModel.GetById 1ms app.codeStats 1ms

/src/contrib/boost-1.52.0/boost/xpressive/detail/utility/sequence_stack.hpp

https://gitlab.com/tylerluo/pythonocc
C++ Header | 259 lines | 185 code | 41 blank | 33 comment | 14 complexity | d9751b6abc706ddc5d4c1aa2d4c970aa MD5 | raw file
  1///////////////////////////////////////////////////////////////////////////////
  2// sequence_stack.hpp
  3//
  4//  Copyright 2008 Eric Niebler. Distributed under the Boost
  5//  Software License, Version 1.0. (See accompanying file
  6//  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  7
  8#ifndef BOOST_XPRESSIVE_DETAIL_SEQUENCE_STACK_HPP_EAN_10_04_2005
  9#define BOOST_XPRESSIVE_DETAIL_SEQUENCE_STACK_HPP_EAN_10_04_2005
 10
 11// MS compatible compilers support #pragma once
 12#if defined(_MSC_VER) && (_MSC_VER >= 1020)
 13# pragma once
 14# pragma warning(push)
 15# pragma warning(disable : 4127) // conditional expression constant
 16#endif
 17
 18#include <algorithm>
 19#include <functional>
 20
 21namespace boost { namespace xpressive { namespace detail
 22{
 23
 24struct fill_t {} const fill = {};
 25
 26//////////////////////////////////////////////////////////////////////////
 27// sequence_stack
 28//
 29//   For storing a stack of sequences of type T, where each sequence
 30//   is guaranteed to be stored in contiguous memory.
 31template<typename T>
 32struct sequence_stack
 33{
 34private:
 35    static T *allocate(std::size_t size, T const &t)
 36    {
 37        std::size_t i = 0;
 38        T *p = (T *)::operator new(size * sizeof(T));
 39        try
 40        {
 41            for(; i < size; ++i)
 42                ::new((void *)(p+i)) T(t);
 43        }
 44        catch(...)
 45        {
 46            deallocate(p, i);
 47            throw;
 48        }
 49        return p;
 50    }
 51
 52    static void deallocate(T *p, std::size_t i)
 53    {
 54        while(i-- > 0)
 55            (p+i)->~T();
 56        ::operator delete(p);
 57    }
 58
 59    struct chunk
 60    {
 61        chunk(std::size_t size, T const &t, std::size_t count, chunk *back, chunk *next)
 62          : begin_(allocate(size, t))
 63          , curr_(begin_ + count)
 64          , end_(begin_ + size)
 65          , back_(back)
 66          , next_(next)
 67        {
 68            if(this->back_)
 69                this->back_->next_ = this;
 70            if(this->next_)
 71                this->next_->back_ = this;
 72        }
 73
 74        ~chunk()
 75        {
 76            deallocate(this->begin_, this->size());
 77        }
 78
 79        std::size_t size() const
 80        {
 81            return static_cast<std::size_t>(this->end_ - this->begin_);
 82        }
 83
 84        T *const begin_, *curr_, *const end_;
 85        chunk *back_, *next_;
 86
 87    private:
 88        chunk &operator =(chunk const &);
 89    };
 90
 91    chunk *current_chunk_;
 92
 93    // Cache these for faster access
 94    T *begin_;
 95    T *curr_;
 96    T *end_;
 97
 98    T *grow_(std::size_t count, T const &t)
 99    {
100        if(this->current_chunk_)
101        {
102            // write the cached value of current into the expr.
103            // OK to do this even if later statements throw.
104            this->current_chunk_->curr_ = this->curr_;
105
106            // Do we have a expr with enough available memory already?
107            if(this->current_chunk_->next_ && count <= this->current_chunk_->next_->size())
108            {
109                this->current_chunk_ = this->current_chunk_->next_;
110                this->curr_ = this->current_chunk_->curr_ = this->current_chunk_->begin_ + count;
111                this->end_ = this->current_chunk_->end_;
112                this->begin_ = this->current_chunk_->begin_;
113                std::fill_n(this->begin_, count, t);
114                return this->begin_;
115            }
116
117            // grow exponentially
118            std::size_t new_size = (std::max)(count, static_cast<std::size_t>(this->current_chunk_->size() * 1.5));
119
120            // Create a new expr and insert it into the list
121            this->current_chunk_ = new chunk(new_size, t, count, this->current_chunk_, this->current_chunk_->next_);
122        }
123        else
124        {
125            // first chunk is 256
126            std::size_t new_size = (std::max)(count, static_cast<std::size_t>(256U));
127
128            // Create a new expr and insert it into the list
129            this->current_chunk_ = new chunk(new_size, t, count, 0, 0);
130        }
131
132        this->begin_ = this->current_chunk_->begin_;
133        this->curr_ = this->current_chunk_->curr_;
134        this->end_ = this->current_chunk_->end_;
135        return this->begin_;
136    }
137
138    void unwind_chunk_()
139    {
140        // write the cached value of curr_ into current_chunk_
141        this->current_chunk_->curr_ = this->begin_;
142        // make the previous chunk the current
143        this->current_chunk_ = this->current_chunk_->back_;
144
145        // update the cache
146        this->begin_ = this->current_chunk_->begin_;
147        this->curr_ = this->current_chunk_->curr_;
148        this->end_ = this->current_chunk_->end_;
149    }
150
151    bool in_current_chunk(T *ptr) const
152    {
153        return !std::less<void*>()(ptr, this->begin_) && std::less<void*>()(ptr, this->end_);
154    }
155
156public:
157    sequence_stack()
158      : current_chunk_(0)
159      , begin_(0)
160      , curr_(0)
161      , end_(0)
162    {
163    }
164
165    ~sequence_stack()
166    {
167        this->clear();
168    }
169
170    // walk to the front of the linked list
171    void unwind()
172    {
173        if(this->current_chunk_)
174        {
175            while(this->current_chunk_->back_)
176            {
177                this->current_chunk_->curr_ = this->current_chunk_->begin_;
178                this->current_chunk_ = this->current_chunk_->back_;
179            }
180
181            this->begin_ = this->curr_ = this->current_chunk_->curr_ = this->current_chunk_->begin_;
182            this->end_ = this->current_chunk_->end_;
183        }
184    }
185
186    void clear()
187    {
188        // walk to the front of the list
189        this->unwind();
190
191        // delete the list
192        for(chunk *next; this->current_chunk_; this->current_chunk_ = next)
193        {
194            next = this->current_chunk_->next_;
195            delete this->current_chunk_;
196        }
197
198        this->begin_ = this->curr_ = this->end_ = 0;
199    }
200
201    T *push_sequence(std::size_t count, T const &t)
202    {
203        // This is the ptr to return
204        T *ptr = this->curr_;
205
206        // Advance the high-water mark
207        this->curr_ += count;
208
209        // Check to see if we have overflowed this buffer
210        if(std::less<void*>()(this->end_, this->curr_))
211        {
212            // oops, back this out.
213            this->curr_ = ptr;
214
215            // allocate a new block and return a ptr to the new memory
216            return this->grow_(count, t);
217        }
218
219        return ptr;
220    }
221
222    T *push_sequence(std::size_t count, T const &t, fill_t)
223    {
224        T *ptr = this->push_sequence(count, t);
225        std::fill_n(ptr, count, t);
226        return ptr;
227    }
228
229    void unwind_to(T *ptr)
230    {
231        while(!this->in_current_chunk(ptr))
232        {
233            // completely unwind the current chunk, move to the previous chunk
234            this->unwind_chunk_();
235        }
236        this->current_chunk_->curr_ = this->curr_ = ptr;
237    }
238
239    // shrink-to-fit: remove any unused nodes in the chain
240    void conserve()
241    {
242        if(this->current_chunk_)
243        {
244            for(chunk *next; this->current_chunk_->next_; this->current_chunk_->next_ = next)
245            {
246                next = this->current_chunk_->next_->next_;
247                delete this->current_chunk_->next_;
248            }
249        }
250    }
251};
252
253}}} // namespace boost::xpressive::detail
254
255#if defined(_MSC_VER) && (_MSC_VER >= 1020)
256# pragma warning(pop)
257#endif
258
259#endif