]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | /*============================================================================= |
2 | Copyright (c) 2010-2011 Daniel James | |
3 | ||
4 | Use, modification and distribution is subject to the Boost Software | |
5 | License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at | |
6 | http://www.boost.org/LICENSE_1_0.txt) | |
7 | =============================================================================*/ | |
8 | ||
9 | #include "values.hpp" | |
7c673cae FG |
10 | #include <boost/current_function.hpp> |
11 | #include <boost/lexical_cast.hpp> | |
11fdf7f2 | 12 | #include "files.hpp" |
7c673cae | 13 | |
11fdf7f2 TL |
14 | #define UNDEFINED_ERROR() \ |
15 | throw value_undefined_method( \ | |
16 | std::string(BOOST_CURRENT_FUNCTION) + " not defined for " + \ | |
17 | this->type_name() + " values."); | |
7c673cae FG |
18 | |
19 | namespace quickbook | |
20 | { | |
21 | //////////////////////////////////////////////////////////////////////////// | |
22 | // Value Error | |
11fdf7f2 | 23 | |
7c673cae FG |
24 | struct value_undefined_method : value_error |
25 | { | |
26 | value_undefined_method(std::string const&); | |
27 | }; | |
11fdf7f2 TL |
28 | |
29 | value_error::value_error(std::string const& x) : std::logic_error(x) {} | |
7c673cae FG |
30 | |
31 | value_undefined_method::value_undefined_method(std::string const& x) | |
11fdf7f2 TL |
32 | : value_error(x) |
33 | { | |
34 | } | |
7c673cae FG |
35 | |
36 | //////////////////////////////////////////////////////////////////////////// | |
37 | // Node | |
38 | ||
39 | namespace detail | |
40 | { | |
11fdf7f2 TL |
41 | value_node::value_node(tag_type t) : ref_count_(0), tag_(t), next_() {} |
42 | ||
43 | value_node::~value_node() {} | |
44 | ||
7c673cae FG |
45 | file_ptr value_node::get_file() const { UNDEFINED_ERROR(); } |
46 | string_iterator value_node::get_position() const { UNDEFINED_ERROR(); } | |
47 | int value_node::get_int() const { UNDEFINED_ERROR(); } | |
11fdf7f2 TL |
48 | quickbook::string_view value_node::get_quickbook() const |
49 | { | |
50 | UNDEFINED_ERROR(); | |
51 | } | |
7c673cae FG |
52 | std::string value_node::get_encoded() const { UNDEFINED_ERROR(); } |
53 | value_node* value_node::get_list() const { UNDEFINED_ERROR(); } | |
54 | ||
55 | bool value_node::empty() const { return false; } | |
56 | bool value_node::check() const { return true; } | |
57 | bool value_node::is_list() const { return false; } | |
58 | bool value_node::is_encoded() const { return false; } | |
59 | bool value_node::equals(value_node*) const { UNDEFINED_ERROR(); } | |
60 | } | |
61 | ||
62 | //////////////////////////////////////////////////////////////////////////// | |
63 | // List end value | |
64 | // | |
65 | // A special value for marking the end of lists. | |
66 | ||
67 | namespace detail | |
68 | { | |
69 | struct value_list_end_impl : public value_node | |
70 | { | |
71 | static value_list_end_impl instance; | |
11fdf7f2 TL |
72 | |
73 | private: | |
74 | value_list_end_impl() : value_node(value::default_tag) | |
7c673cae FG |
75 | { |
76 | intrusive_ptr_add_ref(&instance); | |
77 | next_ = this; | |
78 | } | |
79 | ||
80 | virtual char const* type_name() const { return "list end"; } | |
81 | virtual value_node* clone() const { UNDEFINED_ERROR(); } | |
82 | ||
83 | virtual bool equals(value_node* other) const | |
11fdf7f2 TL |
84 | { |
85 | return this == other; | |
86 | } | |
7c673cae FG |
87 | |
88 | bool empty() const { UNDEFINED_ERROR(); } | |
89 | bool check() const { UNDEFINED_ERROR(); } | |
90 | bool is_list() const { UNDEFINED_ERROR(); } | |
91 | bool is_encoded() const { UNDEFINED_ERROR(); } | |
92 | }; | |
93 | ||
94 | value_list_end_impl value_list_end_impl::instance; | |
95 | } | |
11fdf7f2 | 96 | |
7c673cae FG |
97 | //////////////////////////////////////////////////////////////////////////// |
98 | // Empty/nil values | |
99 | // | |
100 | // (nil is just a special case of empty, don't be mislead by the name | |
101 | // the type is not important). | |
102 | ||
103 | namespace detail | |
104 | { | |
105 | struct empty_value_impl : public value_node | |
106 | { | |
107 | static value_node* new_(value::tag_type t); | |
108 | ||
11fdf7f2 TL |
109 | protected: |
110 | explicit empty_value_impl(value::tag_type t) : value_node(t) {} | |
7c673cae | 111 | |
11fdf7f2 | 112 | private: |
7c673cae | 113 | char const* type_name() const { return "empty"; } |
11fdf7f2 | 114 | |
7c673cae | 115 | virtual value_node* clone() const |
11fdf7f2 TL |
116 | { |
117 | return new empty_value_impl(tag_); | |
118 | } | |
7c673cae | 119 | |
11fdf7f2 | 120 | virtual bool empty() const { return true; } |
7c673cae | 121 | |
11fdf7f2 | 122 | virtual bool check() const { return false; } |
7c673cae FG |
123 | |
124 | virtual bool equals(value_node* other) const | |
11fdf7f2 TL |
125 | { |
126 | return !other->check(); | |
127 | } | |
128 | ||
7c673cae FG |
129 | friend value quickbook::empty_value(value::tag_type); |
130 | }; | |
11fdf7f2 | 131 | |
7c673cae FG |
132 | struct value_nil_impl : public empty_value_impl |
133 | { | |
134 | static value_nil_impl instance; | |
11fdf7f2 TL |
135 | |
136 | private: | |
137 | value_nil_impl() : empty_value_impl(value::default_tag) | |
7c673cae FG |
138 | { |
139 | intrusive_ptr_add_ref(&instance); | |
140 | next_ = &value_list_end_impl::instance; | |
141 | } | |
142 | }; | |
143 | ||
144 | value_nil_impl value_nil_impl::instance; | |
145 | ||
11fdf7f2 TL |
146 | value_node* empty_value_impl::new_(value::tag_type t) |
147 | { | |
7c673cae FG |
148 | // The return value from this function is always placed in an |
149 | // intrusive_ptr which will manage the memory correctly. | |
150 | // Note that value_nil_impl increments its reference count | |
151 | // in its constructor, so that it will never be deleted by the | |
152 | // intrusive pointer. | |
153 | ||
154 | if (t == value::default_tag) | |
155 | return &value_nil_impl::instance; | |
156 | else | |
157 | return new empty_value_impl(t); | |
158 | } | |
159 | } | |
160 | ||
161 | value empty_value(value::tag_type t) | |
162 | { | |
163 | return value(detail::empty_value_impl::new_(t)); | |
164 | } | |
165 | ||
166 | //////////////////////////////////////////////////////////////////////////// | |
167 | // value_counted | |
168 | ||
169 | namespace detail | |
170 | { | |
11fdf7f2 | 171 | value_counted::value_counted() : value_base(&value_nil_impl::instance) |
7c673cae FG |
172 | { |
173 | // Even though empty is not on the heap, its reference | |
174 | // counter needs to be incremented so that the destructor | |
175 | // doesn't try to delete it. | |
176 | ||
177 | intrusive_ptr_add_ref(value_); | |
178 | } | |
11fdf7f2 TL |
179 | |
180 | value_counted::value_counted(value_counted const& x) : value_base(x) | |
7c673cae FG |
181 | { |
182 | intrusive_ptr_add_ref(value_); | |
183 | } | |
11fdf7f2 TL |
184 | |
185 | value_counted::value_counted(value_base const& x) : value_base(x) | |
7c673cae FG |
186 | { |
187 | intrusive_ptr_add_ref(value_); | |
188 | } | |
11fdf7f2 TL |
189 | |
190 | value_counted::value_counted(value_node* x) : value_base(x) | |
7c673cae FG |
191 | { |
192 | intrusive_ptr_add_ref(value_); | |
193 | } | |
11fdf7f2 TL |
194 | |
195 | value_counted::~value_counted() { intrusive_ptr_release(value_); } | |
7c673cae | 196 | } |
11fdf7f2 | 197 | |
7c673cae FG |
198 | //////////////////////////////////////////////////////////////////////////// |
199 | // value | |
200 | ||
11fdf7f2 | 201 | value::value() : detail::value_counted() {} |
7c673cae | 202 | |
11fdf7f2 | 203 | value::value(value const& x) : detail::value_counted(x) {} |
7c673cae | 204 | |
11fdf7f2 | 205 | value::value(detail::value_base const& x) : detail::value_counted(x) {} |
7c673cae | 206 | |
11fdf7f2 | 207 | value::value(detail::value_node* x) : detail::value_counted(x) {} |
7c673cae FG |
208 | |
209 | value& value::operator=(value x) | |
210 | { | |
211 | swap(x); | |
212 | return *this; | |
213 | } | |
214 | ||
215 | //////////////////////////////////////////////////////////////////////////// | |
216 | // Integers | |
217 | ||
218 | namespace detail | |
219 | { | |
220 | struct int_value_impl : public value_node | |
221 | { | |
11fdf7f2 | 222 | public: |
7c673cae | 223 | explicit int_value_impl(int, value::tag_type); |
11fdf7f2 TL |
224 | |
225 | private: | |
7c673cae FG |
226 | char const* type_name() const { return "integer"; } |
227 | virtual value_node* clone() const; | |
228 | virtual int get_int() const; | |
229 | virtual std::string get_encoded() const; | |
230 | virtual bool empty() const; | |
231 | virtual bool is_encoded() const; | |
232 | virtual bool equals(value_node*) const; | |
233 | ||
234 | int value_; | |
235 | }; | |
236 | ||
237 | int_value_impl::int_value_impl(int v, value::tag_type t) | |
11fdf7f2 TL |
238 | : value_node(t), value_(v) |
239 | { | |
240 | } | |
7c673cae FG |
241 | |
242 | value_node* int_value_impl::clone() const | |
243 | { | |
244 | return new int_value_impl(value_, tag_); | |
245 | } | |
246 | ||
11fdf7f2 | 247 | int int_value_impl::get_int() const { return value_; } |
7c673cae FG |
248 | |
249 | std::string int_value_impl::get_encoded() const | |
250 | { | |
251 | return boost::lexical_cast<std::string>(value_); | |
252 | } | |
253 | ||
11fdf7f2 | 254 | bool int_value_impl::empty() const { return false; } |
7c673cae | 255 | |
11fdf7f2 | 256 | bool int_value_impl::is_encoded() const { return true; } |
7c673cae | 257 | |
11fdf7f2 TL |
258 | bool int_value_impl::equals(value_node* other) const |
259 | { | |
7c673cae FG |
260 | try { |
261 | return value_ == other->get_int(); | |
11fdf7f2 | 262 | } catch (value_undefined_method&) { |
7c673cae FG |
263 | return false; |
264 | } | |
265 | } | |
266 | } | |
267 | ||
268 | value int_value(int v, value::tag_type t) | |
269 | { | |
270 | return value(new detail::int_value_impl(v, t)); | |
271 | } | |
272 | ||
273 | //////////////////////////////////////////////////////////////////////////// | |
274 | // Strings | |
275 | ||
276 | namespace detail | |
277 | { | |
278 | struct encoded_value_impl : public value_node | |
279 | { | |
11fdf7f2 | 280 | public: |
7c673cae | 281 | explicit encoded_value_impl(std::string const&, value::tag_type); |
11fdf7f2 TL |
282 | |
283 | private: | |
7c673cae FG |
284 | char const* type_name() const { return "encoded text"; } |
285 | ||
286 | virtual ~encoded_value_impl(); | |
287 | virtual value_node* clone() const; | |
288 | virtual std::string get_encoded() const; | |
289 | virtual bool empty() const; | |
290 | virtual bool is_encoded() const; | |
291 | virtual bool equals(value_node*) const; | |
292 | ||
293 | std::string value_; | |
294 | }; | |
11fdf7f2 | 295 | |
7c673cae FG |
296 | struct qbk_value_impl : public value_node |
297 | { | |
11fdf7f2 | 298 | public: |
7c673cae | 299 | explicit qbk_value_impl( |
11fdf7f2 TL |
300 | file_ptr const&, |
301 | string_iterator begin, | |
302 | string_iterator end, | |
303 | value::tag_type); | |
304 | ||
305 | private: | |
7c673cae FG |
306 | char const* type_name() const { return "quickbook"; } |
307 | ||
308 | virtual ~qbk_value_impl(); | |
309 | virtual value_node* clone() const; | |
310 | virtual file_ptr get_file() const; | |
311 | virtual string_iterator get_position() const; | |
b32b8144 | 312 | virtual quickbook::string_view get_quickbook() const; |
7c673cae FG |
313 | virtual bool empty() const; |
314 | virtual bool equals(value_node*) const; | |
315 | ||
316 | file_ptr file_; | |
317 | string_iterator begin_; | |
318 | string_iterator end_; | |
319 | }; | |
11fdf7f2 | 320 | |
7c673cae FG |
321 | struct encoded_qbk_value_impl : public value_node |
322 | { | |
11fdf7f2 TL |
323 | private: |
324 | char const* type_name() const | |
325 | { | |
326 | return "encoded text with quickbook reference"; | |
327 | } | |
328 | ||
329 | encoded_qbk_value_impl( | |
330 | file_ptr const&, | |
331 | string_iterator, | |
332 | string_iterator, | |
333 | std::string const&, | |
334 | value::tag_type); | |
7c673cae | 335 | |
7c673cae FG |
336 | virtual ~encoded_qbk_value_impl(); |
337 | virtual value_node* clone() const; | |
338 | virtual file_ptr get_file() const; | |
339 | virtual string_iterator get_position() const; | |
b32b8144 | 340 | virtual quickbook::string_view get_quickbook() const; |
7c673cae FG |
341 | virtual std::string get_encoded() const; |
342 | virtual bool empty() const; | |
343 | virtual bool is_encoded() const; | |
344 | virtual bool equals(value_node*) const; | |
345 | ||
346 | file_ptr file_; | |
347 | string_iterator begin_; | |
348 | string_iterator end_; | |
349 | std::string encoded_value_; | |
11fdf7f2 | 350 | |
7c673cae | 351 | friend quickbook::value quickbook::encoded_qbk_value( |
11fdf7f2 TL |
352 | file_ptr const&, |
353 | string_iterator, | |
354 | string_iterator, | |
355 | std::string const&, | |
356 | quickbook::value::tag_type); | |
7c673cae FG |
357 | }; |
358 | ||
359 | // encoded_value_impl | |
11fdf7f2 | 360 | |
7c673cae | 361 | encoded_value_impl::encoded_value_impl( |
11fdf7f2 | 362 | std::string const& val, value::tag_type tag) |
7c673cae FG |
363 | : value_node(tag), value_(val) |
364 | { | |
365 | } | |
11fdf7f2 TL |
366 | |
367 | encoded_value_impl::~encoded_value_impl() {} | |
7c673cae FG |
368 | |
369 | value_node* encoded_value_impl::clone() const | |
370 | { | |
371 | return new encoded_value_impl(value_, tag_); | |
372 | } | |
7c673cae | 373 | |
11fdf7f2 TL |
374 | std::string encoded_value_impl::get_encoded() const { return value_; } |
375 | ||
376 | bool encoded_value_impl::empty() const { return value_.empty(); } | |
7c673cae | 377 | |
11fdf7f2 | 378 | bool encoded_value_impl::is_encoded() const { return true; } |
7c673cae | 379 | |
11fdf7f2 TL |
380 | bool encoded_value_impl::equals(value_node* other) const |
381 | { | |
7c673cae FG |
382 | try { |
383 | return value_ == other->get_encoded(); | |
11fdf7f2 | 384 | } catch (value_undefined_method&) { |
7c673cae FG |
385 | return false; |
386 | } | |
387 | } | |
388 | ||
389 | // qbk_value_impl | |
11fdf7f2 | 390 | |
7c673cae | 391 | qbk_value_impl::qbk_value_impl( |
11fdf7f2 TL |
392 | file_ptr const& f, |
393 | string_iterator begin, | |
394 | string_iterator end, | |
395 | value::tag_type tag) | |
396 | : value_node(tag), file_(f), begin_(begin), end_(end) | |
7c673cae FG |
397 | { |
398 | } | |
11fdf7f2 TL |
399 | |
400 | qbk_value_impl::~qbk_value_impl() {} | |
401 | ||
7c673cae FG |
402 | value_node* qbk_value_impl::clone() const |
403 | { | |
404 | return new qbk_value_impl(file_, begin_, end_, tag_); | |
405 | } | |
406 | ||
11fdf7f2 | 407 | file_ptr qbk_value_impl::get_file() const { return file_; } |
7c673cae | 408 | |
11fdf7f2 | 409 | string_iterator qbk_value_impl::get_position() const { return begin_; } |
7c673cae | 410 | |
b32b8144 | 411 | quickbook::string_view qbk_value_impl::get_quickbook() const |
11fdf7f2 TL |
412 | { |
413 | return quickbook::string_view(begin_, end_ - begin_); | |
414 | } | |
7c673cae | 415 | |
11fdf7f2 TL |
416 | bool qbk_value_impl::empty() const { return begin_ == end_; } |
417 | ||
418 | bool qbk_value_impl::equals(value_node* other) const | |
419 | { | |
7c673cae FG |
420 | try { |
421 | return this->get_quickbook() == other->get_quickbook(); | |
11fdf7f2 | 422 | } catch (value_undefined_method&) { |
7c673cae FG |
423 | return false; |
424 | } | |
425 | } | |
426 | ||
427 | // encoded_qbk_value_impl | |
11fdf7f2 | 428 | |
7c673cae | 429 | encoded_qbk_value_impl::encoded_qbk_value_impl( |
11fdf7f2 TL |
430 | file_ptr const& f, |
431 | string_iterator begin, | |
432 | string_iterator end, | |
433 | std::string const& encoded, | |
434 | value::tag_type tag) | |
7c673cae FG |
435 | : value_node(tag) |
436 | , file_(f) | |
437 | , begin_(begin) | |
438 | , end_(end) | |
439 | , encoded_value_(encoded) | |
11fdf7f2 | 440 | |
7c673cae FG |
441 | { |
442 | } | |
443 | ||
11fdf7f2 TL |
444 | encoded_qbk_value_impl::~encoded_qbk_value_impl() {} |
445 | ||
7c673cae FG |
446 | value_node* encoded_qbk_value_impl::clone() const |
447 | { | |
448 | return new encoded_qbk_value_impl( | |
11fdf7f2 | 449 | file_, begin_, end_, encoded_value_, tag_); |
7c673cae FG |
450 | } |
451 | ||
11fdf7f2 | 452 | file_ptr encoded_qbk_value_impl::get_file() const { return file_; } |
7c673cae FG |
453 | |
454 | string_iterator encoded_qbk_value_impl::get_position() const | |
11fdf7f2 TL |
455 | { |
456 | return begin_; | |
457 | } | |
7c673cae | 458 | |
b32b8144 | 459 | quickbook::string_view encoded_qbk_value_impl::get_quickbook() const |
11fdf7f2 TL |
460 | { |
461 | return quickbook::string_view(begin_, end_ - begin_); | |
462 | } | |
7c673cae FG |
463 | |
464 | std::string encoded_qbk_value_impl::get_encoded() const | |
11fdf7f2 TL |
465 | { |
466 | return encoded_value_; | |
467 | } | |
7c673cae FG |
468 | |
469 | // Should this test the quickbook, the boostbook or both? | |
470 | bool encoded_qbk_value_impl::empty() const | |
11fdf7f2 TL |
471 | { |
472 | return encoded_value_.empty(); | |
473 | } | |
7c673cae | 474 | |
11fdf7f2 | 475 | bool encoded_qbk_value_impl::is_encoded() const { return true; } |
7c673cae | 476 | |
11fdf7f2 TL |
477 | bool encoded_qbk_value_impl::equals(value_node* other) const |
478 | { | |
7c673cae FG |
479 | try { |
480 | return this->get_quickbook() == other->get_quickbook(); | |
11fdf7f2 | 481 | } catch (value_undefined_method&) { |
7c673cae | 482 | } |
7c673cae FG |
483 | |
484 | try { | |
485 | return this->get_encoded() == other->get_encoded(); | |
11fdf7f2 | 486 | } catch (value_undefined_method&) { |
7c673cae | 487 | } |
7c673cae FG |
488 | |
489 | return false; | |
490 | } | |
491 | } | |
492 | ||
11fdf7f2 TL |
493 | value qbk_value( |
494 | file_ptr const& f, | |
495 | string_iterator x, | |
496 | string_iterator y, | |
497 | value::tag_type t) | |
7c673cae FG |
498 | { |
499 | return value(new detail::qbk_value_impl(f, x, y, t)); | |
500 | } | |
501 | ||
502 | value encoded_value(std::string const& x, value::tag_type t) | |
503 | { | |
504 | return value(new detail::encoded_value_impl(x, t)); | |
505 | } | |
506 | ||
507 | value encoded_qbk_value( | |
11fdf7f2 TL |
508 | file_ptr const& f, |
509 | string_iterator x, | |
510 | string_iterator y, | |
511 | std::string const& z, | |
512 | value::tag_type t) | |
7c673cae | 513 | { |
11fdf7f2 | 514 | return value(new detail::encoded_qbk_value_impl(f, x, y, z, t)); |
7c673cae FG |
515 | } |
516 | ||
517 | ////////////////////////////////////////////////////////////////////////// | |
518 | // List methods | |
11fdf7f2 | 519 | |
7c673cae FG |
520 | namespace detail |
521 | { | |
11fdf7f2 TL |
522 | namespace |
523 | { | |
524 | value_node** list_ref_back(value_node**); | |
525 | void list_ref(value_node*); | |
526 | void list_unref(value_node*); | |
527 | value_node** merge_sort(value_node**); | |
528 | value_node** merge_sort(value_node**, int); | |
529 | value_node** merge(value_node**, value_node**, value_node**); | |
530 | void rotate(value_node**, value_node**, value_node**); | |
531 | ||
532 | value_node** list_ref_back(value_node** back) | |
533 | { | |
534 | while (*back != &value_list_end_impl::instance) { | |
535 | intrusive_ptr_add_ref(*back); | |
536 | back = &(*back)->next_; | |
537 | } | |
538 | ||
539 | return back; | |
7c673cae | 540 | } |
7c673cae | 541 | |
11fdf7f2 TL |
542 | void list_ref(value_node* ptr) |
543 | { | |
544 | while (ptr != &value_list_end_impl::instance) { | |
545 | intrusive_ptr_add_ref(ptr); | |
546 | ptr = ptr->next_; | |
547 | } | |
7c673cae | 548 | } |
7c673cae | 549 | |
11fdf7f2 TL |
550 | void list_unref(value_node* ptr) |
551 | { | |
552 | while (ptr != &value_list_end_impl::instance) { | |
553 | value_node* next = ptr->next_; | |
554 | intrusive_ptr_release(ptr); | |
555 | ptr = next; | |
556 | } | |
7c673cae | 557 | } |
7c673cae | 558 | |
11fdf7f2 TL |
559 | value_node** merge_sort(value_node** l) |
560 | { | |
561 | if (*l == &value_list_end_impl::instance) | |
562 | return l; | |
563 | else | |
564 | return merge_sort(l, 9999); | |
565 | } | |
7c673cae | 566 | |
11fdf7f2 | 567 | value_node** merge_sort(value_node** l, int recurse_limit) |
7c673cae | 568 | { |
11fdf7f2 TL |
569 | value_node** p = &(*l)->next_; |
570 | for (int count = 0; count < recurse_limit && | |
571 | *p != &value_list_end_impl::instance; | |
572 | ++count) { | |
573 | p = merge(l, p, merge_sort(p, count)); | |
574 | } | |
575 | return p; | |
7c673cae | 576 | } |
11fdf7f2 TL |
577 | |
578 | value_node** merge( | |
7c673cae | 579 | value_node** first, value_node** second, value_node** third) |
11fdf7f2 TL |
580 | { |
581 | for (;;) { | |
582 | for (;;) { | |
583 | if (first == second) return third; | |
584 | if ((*second)->tag_ < (*first)->tag_) break; | |
585 | first = &(*first)->next_; | |
586 | } | |
587 | ||
588 | rotate(first, second, third); | |
7c673cae | 589 | first = &(*first)->next_; |
11fdf7f2 TL |
590 | |
591 | // Since the two ranges were just swapped, the order is now: | |
592 | // first...third...second | |
593 | // | |
594 | // Also, that since the second section of the list was | |
595 | // originally before the first, if the heads are equal | |
596 | // we need to swap to maintain the order. | |
597 | ||
598 | for (;;) { | |
599 | if (first == third) return second; | |
600 | if ((*third)->tag_ <= (*first)->tag_) break; | |
601 | first = &(*first)->next_; | |
602 | } | |
603 | ||
604 | rotate(first, third, second); | |
7c673cae FG |
605 | first = &(*first)->next_; |
606 | } | |
7c673cae | 607 | } |
7c673cae | 608 | |
11fdf7f2 TL |
609 | void rotate( |
610 | value_node** first, value_node** second, value_node** third) | |
611 | { | |
612 | value_node* tmp = *first; | |
613 | *first = *second; | |
614 | *second = *third; | |
615 | *third = tmp; | |
616 | // if(*second != &value_list_end_impl::instance) back = second; | |
617 | } | |
7c673cae FG |
618 | } |
619 | } | |
7c673cae FG |
620 | |
621 | ////////////////////////////////////////////////////////////////////////// | |
622 | // Lists | |
11fdf7f2 | 623 | |
7c673cae FG |
624 | namespace detail |
625 | { | |
626 | struct value_list_impl : public value_node | |
627 | { | |
628 | value_list_impl(value::tag_type); | |
629 | value_list_impl(value_list_builder&, value::tag_type); | |
11fdf7f2 TL |
630 | |
631 | private: | |
7c673cae FG |
632 | value_list_impl(value_list_impl const&); |
633 | ||
634 | char const* type_name() const { return "list"; } | |
635 | ||
636 | virtual ~value_list_impl(); | |
637 | virtual value_node* clone() const; | |
638 | virtual bool empty() const; | |
639 | virtual bool equals(value_node*) const; | |
640 | ||
641 | virtual bool is_list() const; | |
642 | virtual value_node* get_list() const; | |
11fdf7f2 | 643 | |
7c673cae FG |
644 | value_node* head_; |
645 | }; | |
11fdf7f2 | 646 | |
7c673cae FG |
647 | value_list_impl::value_list_impl(value::tag_type tag) |
648 | : value_node(tag), head_(&value_list_end_impl::instance) | |
11fdf7f2 TL |
649 | { |
650 | } | |
651 | ||
652 | value_list_impl::value_list_impl( | |
653 | value_list_builder& builder, value::tag_type tag) | |
7c673cae FG |
654 | : value_node(tag), head_(builder.release()) |
655 | { | |
656 | } | |
657 | ||
658 | value_list_impl::value_list_impl(value_list_impl const& x) | |
659 | : value_node(x.tag_), head_(x.head_) | |
660 | { | |
661 | list_ref(head_); | |
662 | } | |
11fdf7f2 TL |
663 | |
664 | value_list_impl::~value_list_impl() { list_unref(head_); } | |
7c673cae FG |
665 | |
666 | value_node* value_list_impl::clone() const | |
667 | { | |
668 | return new value_list_impl(*this); | |
669 | } | |
670 | ||
671 | bool value_list_impl::empty() const | |
672 | { | |
673 | return head_ == &value_list_end_impl::instance; | |
674 | } | |
7c673cae | 675 | |
11fdf7f2 TL |
676 | bool value_list_impl::is_list() const { return true; } |
677 | ||
678 | value_node* value_list_impl::get_list() const { return head_; } | |
679 | ||
680 | bool value_list_impl::equals(value_node* other) const | |
681 | { | |
7c673cae FG |
682 | value_node* x1; |
683 | ||
684 | try { | |
11fdf7f2 TL |
685 | x1 = other->get_list(); |
686 | } catch (value_undefined_method&) { | |
7c673cae FG |
687 | return false; |
688 | } | |
689 | ||
11fdf7f2 TL |
690 | for (value_node *x2 = head_; x1 != x2; |
691 | x1 = x1->next_, x2 = x2->next_) { | |
692 | if (x2 == &value_list_end_impl::instance || !x1->equals(x2)) | |
693 | return false; | |
7c673cae | 694 | } |
11fdf7f2 | 695 | |
7c673cae FG |
696 | return true; |
697 | } | |
698 | } | |
699 | ||
700 | ////////////////////////////////////////////////////////////////////////// | |
701 | // List builder | |
11fdf7f2 | 702 | |
7c673cae FG |
703 | namespace detail |
704 | { | |
705 | // value_list_builder | |
11fdf7f2 | 706 | |
7c673cae | 707 | value_list_builder::value_list_builder() |
11fdf7f2 TL |
708 | : head_(&value_list_end_impl::instance), back_(&head_) |
709 | { | |
710 | } | |
7c673cae FG |
711 | |
712 | value_list_builder::value_list_builder(value_node* ptr) | |
11fdf7f2 | 713 | : head_(ptr), back_(list_ref_back(&head_)) |
7c673cae | 714 | { |
7c673cae FG |
715 | } |
716 | ||
11fdf7f2 TL |
717 | value_list_builder::~value_list_builder() { list_unref(head_); } |
718 | ||
719 | void value_list_builder::swap(value_list_builder& other) | |
720 | { | |
7c673cae FG |
721 | std::swap(head_, other.head_); |
722 | std::swap(back_, other.back_); | |
11fdf7f2 TL |
723 | if (back_ == &other.head_) back_ = &head_; |
724 | if (other.back_ == &head_) other.back_ = &other.head_; | |
7c673cae FG |
725 | } |
726 | ||
11fdf7f2 TL |
727 | value_node* value_list_builder::release() |
728 | { | |
7c673cae FG |
729 | value_node* r = head_; |
730 | head_ = &value_list_end_impl::instance; | |
731 | back_ = &head_; | |
732 | return r; | |
733 | } | |
11fdf7f2 | 734 | |
7c673cae FG |
735 | void value_list_builder::append(value_node* item) |
736 | { | |
11fdf7f2 | 737 | if (item->next_) item = item->clone(); |
7c673cae FG |
738 | intrusive_ptr_add_ref(item); |
739 | item->next_ = *back_; | |
740 | *back_ = item; | |
741 | back_ = &item->next_; | |
742 | } | |
11fdf7f2 | 743 | |
7c673cae FG |
744 | void value_list_builder::sort() |
745 | { | |
746 | back_ = merge_sort(&head_); | |
747 | assert(*back_ == &value_list_end_impl::instance); | |
748 | } | |
749 | ||
750 | bool value_list_builder::empty() const | |
751 | { | |
752 | return head_ == &value_list_end_impl::instance; | |
753 | } | |
754 | } | |
755 | ||
756 | ////////////////////////////////////////////////////////////////////////// | |
757 | // Value builder | |
11fdf7f2 | 758 | |
7c673cae | 759 | value_builder::value_builder() |
11fdf7f2 | 760 | : current(), list_tag(value::default_tag), saved() |
7c673cae FG |
761 | { |
762 | } | |
11fdf7f2 TL |
763 | |
764 | void value_builder::swap(value_builder& other) | |
765 | { | |
7c673cae FG |
766 | current.swap(other.current); |
767 | std::swap(list_tag, other.list_tag); | |
768 | saved.swap(other.saved); | |
769 | } | |
11fdf7f2 TL |
770 | |
771 | void value_builder::save() | |
772 | { | |
7c673cae FG |
773 | boost::scoped_ptr<value_builder> store(new value_builder); |
774 | swap(*store); | |
775 | saved.swap(store); | |
776 | } | |
777 | ||
11fdf7f2 TL |
778 | void value_builder::restore() |
779 | { | |
7c673cae FG |
780 | boost::scoped_ptr<value_builder> store; |
781 | store.swap(saved); | |
782 | swap(*store); | |
783 | } | |
784 | ||
11fdf7f2 TL |
785 | value value_builder::release() |
786 | { | |
7c673cae FG |
787 | return value(new detail::value_list_impl(current, list_tag)); |
788 | } | |
789 | ||
11fdf7f2 TL |
790 | void value_builder::insert(value const& item) |
791 | { | |
7c673cae FG |
792 | current.append(item.value_); |
793 | } | |
794 | ||
11fdf7f2 TL |
795 | void value_builder::extend(value const& list) |
796 | { | |
7c673cae | 797 | for (value::iterator begin = list.begin(), end = list.end(); |
11fdf7f2 | 798 | begin != end; ++begin) { |
7c673cae FG |
799 | insert(*begin); |
800 | } | |
801 | } | |
802 | ||
11fdf7f2 TL |
803 | void value_builder::start_list(value::tag_type tag) |
804 | { | |
7c673cae FG |
805 | save(); |
806 | list_tag = tag; | |
807 | } | |
808 | ||
11fdf7f2 TL |
809 | void value_builder::finish_list() |
810 | { | |
7c673cae FG |
811 | value list = release(); |
812 | restore(); | |
813 | insert(list); | |
814 | } | |
815 | ||
11fdf7f2 | 816 | void value_builder::clear_list() { restore(); } |
7c673cae | 817 | |
11fdf7f2 | 818 | void value_builder::sort_list() { current.sort(); } |
7c673cae | 819 | |
11fdf7f2 | 820 | bool value_builder::empty() const { return current.empty(); } |
7c673cae FG |
821 | |
822 | //////////////////////////////////////////////////////////////////////////// | |
823 | // Iterator | |
824 | ||
825 | namespace detail | |
826 | { | |
11fdf7f2 | 827 | value::iterator::iterator() : ptr_(&value_list_end_impl::instance) {} |
7c673cae FG |
828 | } |
829 | } |