123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268 |
- ///////////////////////////////////////////////////////////////////////////////
- // sequence_stack.hpp
- //
- // Copyright 2008 Eric Niebler. Distributed under the Boost
- // Software License, Version 1.0. (See accompanying file
- // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
- #ifndef BOOST_XPRESSIVE_DETAIL_SEQUENCE_STACK_HPP_EAN_10_04_2005
- #define BOOST_XPRESSIVE_DETAIL_SEQUENCE_STACK_HPP_EAN_10_04_2005
- // MS compatible compilers support #pragma once
- #if defined(_MSC_VER)
- # pragma once
- # pragma warning(push)
- # pragma warning(disable : 4127) // conditional expression constant
- #endif
- #include <cstddef>
- #include <algorithm>
- #include <functional>
- namespace boost { namespace xpressive { namespace detail
- {
- struct fill_t {} const fill = {};
- //////////////////////////////////////////////////////////////////////////
- // sequence_stack
- //
- // For storing a stack of sequences of type T, where each sequence
- // is guaranteed to be stored in contiguous memory.
- template<typename T>
- struct sequence_stack
- {
- struct allocate_guard_t;
- friend struct allocate_guard_t;
- struct allocate_guard_t
- {
- std::size_t i;
- T *p;
- bool dismissed;
- ~allocate_guard_t()
- {
- if(!this->dismissed)
- sequence_stack::deallocate(this->p, this->i);
- }
- };
- private:
- static T *allocate(std::size_t size, T const &t)
- {
- allocate_guard_t guard = {0, (T *)::operator new(size * sizeof(T)), false};
- for(; guard.i < size; ++guard.i)
- ::new((void *)(guard.p + guard.i)) T(t);
- guard.dismissed = true;
- return guard.p;
- }
- static void deallocate(T *p, std::size_t i)
- {
- while(i-- > 0)
- (p+i)->~T();
- ::operator delete(p);
- }
- struct chunk
- {
- chunk(std::size_t size, T const &t, std::size_t count, chunk *back, chunk *next)
- : begin_(allocate(size, t))
- , curr_(begin_ + count)
- , end_(begin_ + size)
- , back_(back)
- , next_(next)
- {
- if(this->back_)
- this->back_->next_ = this;
- if(this->next_)
- this->next_->back_ = this;
- }
- ~chunk()
- {
- deallocate(this->begin_, this->size());
- }
- std::size_t size() const
- {
- return static_cast<std::size_t>(this->end_ - this->begin_);
- }
- T *const begin_, *curr_, *const end_;
- chunk *back_, *next_;
- private:
- chunk &operator =(chunk const &);
- };
- chunk *current_chunk_;
- // Cache these for faster access
- T *begin_;
- T *curr_;
- T *end_;
- T *grow_(std::size_t count, T const &t)
- {
- if(this->current_chunk_)
- {
- // write the cached value of current into the expr.
- // OK to do this even if later statements throw.
- this->current_chunk_->curr_ = this->curr_;
- // Do we have a expr with enough available memory already?
- if(this->current_chunk_->next_ && count <= this->current_chunk_->next_->size())
- {
- this->current_chunk_ = this->current_chunk_->next_;
- this->curr_ = this->current_chunk_->curr_ = this->current_chunk_->begin_ + count;
- this->end_ = this->current_chunk_->end_;
- this->begin_ = this->current_chunk_->begin_;
- std::fill_n(this->begin_, count, t);
- return this->begin_;
- }
- // grow exponentially
- std::size_t new_size = (std::max)(
- count
- , static_cast<std::size_t>(static_cast<double>(this->current_chunk_->size()) * 1.5)
- );
- // Create a new expr and insert it into the list
- this->current_chunk_ = new chunk(new_size, t, count, this->current_chunk_, this->current_chunk_->next_);
- }
- else
- {
- // first chunk is 256
- std::size_t new_size = (std::max)(count, static_cast<std::size_t>(256U));
- // Create a new expr and insert it into the list
- this->current_chunk_ = new chunk(new_size, t, count, 0, 0);
- }
- this->begin_ = this->current_chunk_->begin_;
- this->curr_ = this->current_chunk_->curr_;
- this->end_ = this->current_chunk_->end_;
- return this->begin_;
- }
- void unwind_chunk_()
- {
- // write the cached value of curr_ into current_chunk_
- this->current_chunk_->curr_ = this->begin_;
- // make the previous chunk the current
- this->current_chunk_ = this->current_chunk_->back_;
- // update the cache
- this->begin_ = this->current_chunk_->begin_;
- this->curr_ = this->current_chunk_->curr_;
- this->end_ = this->current_chunk_->end_;
- }
- bool in_current_chunk(T *ptr) const
- {
- return !std::less<void*>()(ptr, this->begin_) && std::less<void*>()(ptr, this->end_);
- }
- public:
- sequence_stack()
- : current_chunk_(0)
- , begin_(0)
- , curr_(0)
- , end_(0)
- {
- }
- ~sequence_stack()
- {
- this->clear();
- }
- // walk to the front of the linked list
- void unwind()
- {
- if(this->current_chunk_)
- {
- while(this->current_chunk_->back_)
- {
- this->current_chunk_->curr_ = this->current_chunk_->begin_;
- this->current_chunk_ = this->current_chunk_->back_;
- }
- this->begin_ = this->curr_ = this->current_chunk_->curr_ = this->current_chunk_->begin_;
- this->end_ = this->current_chunk_->end_;
- }
- }
- void clear()
- {
- // walk to the front of the list
- this->unwind();
- // delete the list
- for(chunk *next; this->current_chunk_; this->current_chunk_ = next)
- {
- next = this->current_chunk_->next_;
- delete this->current_chunk_;
- }
- this->begin_ = this->curr_ = this->end_ = 0;
- }
- T *push_sequence(std::size_t count, T const &t)
- {
- // Check to see if we have overflowed this buffer
- std::size_t size_left = static_cast< std::size_t >(this->end_ - this->curr_);
- if (size_left < count)
- {
- // allocate a new block and return a ptr to the new memory
- return this->grow_(count, t);
- }
- // This is the ptr to return
- T *ptr = this->curr_;
- // Advance the high-water mark
- this->curr_ += count;
- return ptr;
- }
- T *push_sequence(std::size_t count, T const &t, fill_t)
- {
- T *ptr = this->push_sequence(count, t);
- std::fill_n(ptr, count, t);
- return ptr;
- }
- void unwind_to(T *ptr)
- {
- while(!this->in_current_chunk(ptr))
- {
- // completely unwind the current chunk, move to the previous chunk
- this->unwind_chunk_();
- }
- this->current_chunk_->curr_ = this->curr_ = ptr;
- }
- // shrink-to-fit: remove any unused nodes in the chain
- void conserve()
- {
- if(this->current_chunk_)
- {
- for(chunk *next; this->current_chunk_->next_; this->current_chunk_->next_ = next)
- {
- next = this->current_chunk_->next_->next_;
- delete this->current_chunk_->next_;
- }
- }
- }
- };
- }}} // namespace boost::xpressive::detail
- #if defined(_MSC_VER)
- # pragma warning(pop)
- #endif
- #endif
|