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