1 ///////////////////////////////////////////////////////////////////////////////
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)
8 #ifndef BOOST_XPRESSIVE_DETAIL_SEQUENCE_STACK_HPP_EAN_10_04_2005
9 #define BOOST_XPRESSIVE_DETAIL_SEQUENCE_STACK_HPP_EAN_10_04_2005
11 // MS compatible compilers support #pragma once
14 # pragma warning(push)
15 # pragma warning(disable : 4127) // conditional expression constant
21 namespace boost { namespace xpressive { namespace detail
24 struct fill_t {} const fill = {};
26 //////////////////////////////////////////////////////////////////////////
29 // For storing a stack of sequences of type T, where each sequence
30 // is guaranteed to be stored in contiguous memory.
34 struct allocate_guard_t;
35 friend struct allocate_guard_t;
36 struct allocate_guard_t
44 sequence_stack::deallocate(this->p, this->i);
48 static T *allocate(std::size_t size, T const &t)
50 allocate_guard_t guard = {0, (T *)::operator new(size * sizeof(T)), false};
52 for(; guard.i < size; ++guard.i)
53 ::new((void *)(guard.p + guard.i)) T(t);
54 guard.dismissed = true;
59 static void deallocate(T *p, std::size_t i)
68 chunk(std::size_t size, T const &t, std::size_t count, chunk *back, chunk *next)
69 : begin_(allocate(size, t))
70 , curr_(begin_ + count)
76 this->back_->next_ = this;
78 this->next_->back_ = this;
83 deallocate(this->begin_, this->size());
86 std::size_t size() const
88 return static_cast<std::size_t>(this->end_ - this->begin_);
91 T *const begin_, *curr_, *const end_;
95 chunk &operator =(chunk const &);
98 chunk *current_chunk_;
100 // Cache these for faster access
105 T *grow_(std::size_t count, T const &t)
107 if(this->current_chunk_)
109 // write the cached value of current into the expr.
110 // OK to do this even if later statements throw.
111 this->current_chunk_->curr_ = this->curr_;
113 // Do we have a expr with enough available memory already?
114 if(this->current_chunk_->next_ && count <= this->current_chunk_->next_->size())
116 this->current_chunk_ = this->current_chunk_->next_;
117 this->curr_ = this->current_chunk_->curr_ = this->current_chunk_->begin_ + count;
118 this->end_ = this->current_chunk_->end_;
119 this->begin_ = this->current_chunk_->begin_;
120 std::fill_n(this->begin_, count, t);
124 // grow exponentially
125 std::size_t new_size = (std::max)(
127 , static_cast<std::size_t>(static_cast<double>(this->current_chunk_->size()) * 1.5)
130 // Create a new expr and insert it into the list
131 this->current_chunk_ = new chunk(new_size, t, count, this->current_chunk_, this->current_chunk_->next_);
135 // first chunk is 256
136 std::size_t new_size = (std::max)(count, static_cast<std::size_t>(256U));
138 // Create a new expr and insert it into the list
139 this->current_chunk_ = new chunk(new_size, t, count, 0, 0);
142 this->begin_ = this->current_chunk_->begin_;
143 this->curr_ = this->current_chunk_->curr_;
144 this->end_ = this->current_chunk_->end_;
150 // write the cached value of curr_ into current_chunk_
151 this->current_chunk_->curr_ = this->begin_;
152 // make the previous chunk the current
153 this->current_chunk_ = this->current_chunk_->back_;
156 this->begin_ = this->current_chunk_->begin_;
157 this->curr_ = this->current_chunk_->curr_;
158 this->end_ = this->current_chunk_->end_;
161 bool in_current_chunk(T *ptr) const
163 return !std::less<void*>()(ptr, this->begin_) && std::less<void*>()(ptr, this->end_);
180 // walk to the front of the linked list
183 if(this->current_chunk_)
185 while(this->current_chunk_->back_)
187 this->current_chunk_->curr_ = this->current_chunk_->begin_;
188 this->current_chunk_ = this->current_chunk_->back_;
191 this->begin_ = this->curr_ = this->current_chunk_->curr_ = this->current_chunk_->begin_;
192 this->end_ = this->current_chunk_->end_;
198 // walk to the front of the list
202 for(chunk *next; this->current_chunk_; this->current_chunk_ = next)
204 next = this->current_chunk_->next_;
205 delete this->current_chunk_;
208 this->begin_ = this->curr_ = this->end_ = 0;
211 T *push_sequence(std::size_t count, T const &t)
213 // This is the ptr to return
214 T *ptr = this->curr_;
216 // Advance the high-water mark
217 this->curr_ += count;
219 // Check to see if we have overflowed this buffer
220 if(std::less<void*>()(this->end_, this->curr_))
222 // oops, back this out.
225 // allocate a new block and return a ptr to the new memory
226 return this->grow_(count, t);
232 T *push_sequence(std::size_t count, T const &t, fill_t)
234 T *ptr = this->push_sequence(count, t);
235 std::fill_n(ptr, count, t);
239 void unwind_to(T *ptr)
241 while(!this->in_current_chunk(ptr))
243 // completely unwind the current chunk, move to the previous chunk
244 this->unwind_chunk_();
246 this->current_chunk_->curr_ = this->curr_ = ptr;
249 // shrink-to-fit: remove any unused nodes in the chain
252 if(this->current_chunk_)
254 for(chunk *next; this->current_chunk_->next_; this->current_chunk_->next_ = next)
256 next = this->current_chunk_->next_->next_;
257 delete this->current_chunk_->next_;
263 }}} // namespace boost::xpressive::detail
265 #if defined(_MSC_VER)
266 # pragma warning(pop)