• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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"
10 #include <boost/current_function.hpp>
11 #include <boost/lexical_cast.hpp>
12 #include "files.hpp"
13 
14 #define UNDEFINED_ERROR()                                                      \
15     throw value_undefined_method(                                              \
16         std::string(BOOST_CURRENT_FUNCTION) + " not defined for " +            \
17         this->type_name() + " values.");
18 
19 namespace quickbook
20 {
21     ////////////////////////////////////////////////////////////////////////////
22     // Value Error
23 
24     struct value_undefined_method : value_error
25     {
26         value_undefined_method(std::string const&);
27     };
28 
value_error(std::string const & x)29     value_error::value_error(std::string const& x) : std::logic_error(x) {}
30 
value_undefined_method(std::string const & x)31     value_undefined_method::value_undefined_method(std::string const& x)
32         : value_error(x)
33     {
34     }
35 
36     ////////////////////////////////////////////////////////////////////////////
37     // Node
38 
39     namespace detail
40     {
value_node(tag_type t)41         value_node::value_node(tag_type t) : ref_count_(0), tag_(t), next_() {}
42 
~value_node()43         value_node::~value_node() {}
44 
get_file() const45         file_ptr value_node::get_file() const { UNDEFINED_ERROR(); }
get_position() const46         string_iterator value_node::get_position() const { UNDEFINED_ERROR(); }
get_int() const47         int value_node::get_int() const { UNDEFINED_ERROR(); }
get_quickbook() const48         quickbook::string_view value_node::get_quickbook() const
49         {
50             UNDEFINED_ERROR();
51         }
get_encoded() const52         std::string value_node::get_encoded() const { UNDEFINED_ERROR(); }
get_list() const53         value_node* value_node::get_list() const { UNDEFINED_ERROR(); }
54 
empty() const55         bool value_node::empty() const { return false; }
check() const56         bool value_node::check() const { return true; }
is_list() const57         bool value_node::is_list() const { return false; }
is_encoded() const58         bool value_node::is_encoded() const { return false; }
equals(value_node *) const59         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;
72 
73           private:
value_list_end_implquickbook::detail::value_list_end_impl74             value_list_end_impl() : value_node(value::default_tag)
75             {
76                 intrusive_ptr_add_ref(&instance);
77                 next_ = this;
78             }
79 
type_namequickbook::detail::value_list_end_impl80             virtual char const* type_name() const { return "list end"; }
clonequickbook::detail::value_list_end_impl81             virtual value_node* clone() const { UNDEFINED_ERROR(); }
82 
equalsquickbook::detail::value_list_end_impl83             virtual bool equals(value_node* other) const
84             {
85                 return this == other;
86             }
87 
emptyquickbook::detail::value_list_end_impl88             bool empty() const { UNDEFINED_ERROR(); }
checkquickbook::detail::value_list_end_impl89             bool check() const { UNDEFINED_ERROR(); }
is_listquickbook::detail::value_list_end_impl90             bool is_list() const { UNDEFINED_ERROR(); }
is_encodedquickbook::detail::value_list_end_impl91             bool is_encoded() const { UNDEFINED_ERROR(); }
92         };
93 
94         value_list_end_impl value_list_end_impl::instance;
95     }
96 
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 
109           protected:
empty_value_implquickbook::detail::empty_value_impl110             explicit empty_value_impl(value::tag_type t) : value_node(t) {}
111 
112           private:
type_namequickbook::detail::empty_value_impl113             char const* type_name() const { return "empty"; }
114 
clonequickbook::detail::empty_value_impl115             virtual value_node* clone() const
116             {
117                 return new empty_value_impl(tag_);
118             }
119 
emptyquickbook::detail::empty_value_impl120             virtual bool empty() const { return true; }
121 
checkquickbook::detail::empty_value_impl122             virtual bool check() const { return false; }
123 
equalsquickbook::detail::empty_value_impl124             virtual bool equals(value_node* other) const
125             {
126                 return !other->check();
127             }
128 
129             friend value quickbook::empty_value(value::tag_type);
130         };
131 
132         struct value_nil_impl : public empty_value_impl
133         {
134             static value_nil_impl instance;
135 
136           private:
value_nil_implquickbook::detail::value_nil_impl137             value_nil_impl() : empty_value_impl(value::default_tag)
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 
new_(value::tag_type t)146         value_node* empty_value_impl::new_(value::tag_type t)
147         {
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 
empty_value(value::tag_type t)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     {
value_counted()171         value_counted::value_counted() : value_base(&value_nil_impl::instance)
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         }
179 
value_counted(value_counted const & x)180         value_counted::value_counted(value_counted const& x) : value_base(x)
181         {
182             intrusive_ptr_add_ref(value_);
183         }
184 
value_counted(value_base const & x)185         value_counted::value_counted(value_base const& x) : value_base(x)
186         {
187             intrusive_ptr_add_ref(value_);
188         }
189 
value_counted(value_node * x)190         value_counted::value_counted(value_node* x) : value_base(x)
191         {
192             intrusive_ptr_add_ref(value_);
193         }
194 
~value_counted()195         value_counted::~value_counted() { intrusive_ptr_release(value_); }
196     }
197 
198     ////////////////////////////////////////////////////////////////////////////
199     // value
200 
value()201     value::value() : detail::value_counted() {}
202 
value(value const & x)203     value::value(value const& x) : detail::value_counted(x) {}
204 
value(detail::value_base const & x)205     value::value(detail::value_base const& x) : detail::value_counted(x) {}
206 
value(detail::value_node * x)207     value::value(detail::value_node* x) : detail::value_counted(x) {}
208 
operator =(value x)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         {
222           public:
223             explicit int_value_impl(int, value::tag_type);
224 
225           private:
type_namequickbook::detail::int_value_impl226             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 
int_value_impl(int v,value::tag_type t)237         int_value_impl::int_value_impl(int v, value::tag_type t)
238             : value_node(t), value_(v)
239         {
240         }
241 
clone() const242         value_node* int_value_impl::clone() const
243         {
244             return new int_value_impl(value_, tag_);
245         }
246 
get_int() const247         int int_value_impl::get_int() const { return value_; }
248 
get_encoded() const249         std::string int_value_impl::get_encoded() const
250         {
251             return boost::lexical_cast<std::string>(value_);
252         }
253 
empty() const254         bool int_value_impl::empty() const { return false; }
255 
is_encoded() const256         bool int_value_impl::is_encoded() const { return true; }
257 
equals(value_node * other) const258         bool int_value_impl::equals(value_node* other) const
259         {
260             try {
261                 return value_ == other->get_int();
262             } catch (value_undefined_method&) {
263                 return false;
264             }
265         }
266     }
267 
int_value(int v,value::tag_type t)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         {
280           public:
281             explicit encoded_value_impl(std::string const&, value::tag_type);
282 
283           private:
type_namequickbook::detail::encoded_value_impl284             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         };
295 
296         struct qbk_value_impl : public value_node
297         {
298           public:
299             explicit qbk_value_impl(
300                 file_ptr const&,
301                 string_iterator begin,
302                 string_iterator end,
303                 value::tag_type);
304 
305           private:
type_namequickbook::detail::qbk_value_impl306             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;
312             virtual quickbook::string_view get_quickbook() const;
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         };
320 
321         struct encoded_qbk_value_impl : public value_node
322         {
323           private:
type_namequickbook::detail::encoded_qbk_value_impl324             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);
335 
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;
340             virtual quickbook::string_view get_quickbook() const;
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_;
350 
351             friend quickbook::value quickbook::encoded_qbk_value(
352                 file_ptr const&,
353                 string_iterator,
354                 string_iterator,
355                 std::string const&,
356                 quickbook::value::tag_type);
357         };
358 
359         // encoded_value_impl
360 
encoded_value_impl(std::string const & val,value::tag_type tag)361         encoded_value_impl::encoded_value_impl(
362             std::string const& val, value::tag_type tag)
363             : value_node(tag), value_(val)
364         {
365         }
366 
~encoded_value_impl()367         encoded_value_impl::~encoded_value_impl() {}
368 
clone() const369         value_node* encoded_value_impl::clone() const
370         {
371             return new encoded_value_impl(value_, tag_);
372         }
373 
get_encoded() const374         std::string encoded_value_impl::get_encoded() const { return value_; }
375 
empty() const376         bool encoded_value_impl::empty() const { return value_.empty(); }
377 
is_encoded() const378         bool encoded_value_impl::is_encoded() const { return true; }
379 
equals(value_node * other) const380         bool encoded_value_impl::equals(value_node* other) const
381         {
382             try {
383                 return value_ == other->get_encoded();
384             } catch (value_undefined_method&) {
385                 return false;
386             }
387         }
388 
389         // qbk_value_impl
390 
qbk_value_impl(file_ptr const & f,string_iterator begin,string_iterator end,value::tag_type tag)391         qbk_value_impl::qbk_value_impl(
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)
397         {
398         }
399 
~qbk_value_impl()400         qbk_value_impl::~qbk_value_impl() {}
401 
clone() const402         value_node* qbk_value_impl::clone() const
403         {
404             return new qbk_value_impl(file_, begin_, end_, tag_);
405         }
406 
get_file() const407         file_ptr qbk_value_impl::get_file() const { return file_; }
408 
get_position() const409         string_iterator qbk_value_impl::get_position() const { return begin_; }
410 
get_quickbook() const411         quickbook::string_view qbk_value_impl::get_quickbook() const
412         {
413             return quickbook::string_view(begin_, end_ - begin_);
414         }
415 
empty() const416         bool qbk_value_impl::empty() const { return begin_ == end_; }
417 
equals(value_node * other) const418         bool qbk_value_impl::equals(value_node* other) const
419         {
420             try {
421                 return this->get_quickbook() == other->get_quickbook();
422             } catch (value_undefined_method&) {
423                 return false;
424             }
425         }
426 
427         // encoded_qbk_value_impl
428 
encoded_qbk_value_impl(file_ptr const & f,string_iterator begin,string_iterator end,std::string const & encoded,value::tag_type tag)429         encoded_qbk_value_impl::encoded_qbk_value_impl(
430             file_ptr const& f,
431             string_iterator begin,
432             string_iterator end,
433             std::string const& encoded,
434             value::tag_type tag)
435             : value_node(tag)
436             , file_(f)
437             , begin_(begin)
438             , end_(end)
439             , encoded_value_(encoded)
440 
441         {
442         }
443 
~encoded_qbk_value_impl()444         encoded_qbk_value_impl::~encoded_qbk_value_impl() {}
445 
clone() const446         value_node* encoded_qbk_value_impl::clone() const
447         {
448             return new encoded_qbk_value_impl(
449                 file_, begin_, end_, encoded_value_, tag_);
450         }
451 
get_file() const452         file_ptr encoded_qbk_value_impl::get_file() const { return file_; }
453 
get_position() const454         string_iterator encoded_qbk_value_impl::get_position() const
455         {
456             return begin_;
457         }
458 
get_quickbook() const459         quickbook::string_view encoded_qbk_value_impl::get_quickbook() const
460         {
461             return quickbook::string_view(begin_, end_ - begin_);
462         }
463 
get_encoded() const464         std::string encoded_qbk_value_impl::get_encoded() const
465         {
466             return encoded_value_;
467         }
468 
469         // Should this test the quickbook, the boostbook or both?
empty() const470         bool encoded_qbk_value_impl::empty() const
471         {
472             return encoded_value_.empty();
473         }
474 
is_encoded() const475         bool encoded_qbk_value_impl::is_encoded() const { return true; }
476 
equals(value_node * other) const477         bool encoded_qbk_value_impl::equals(value_node* other) const
478         {
479             try {
480                 return this->get_quickbook() == other->get_quickbook();
481             } catch (value_undefined_method&) {
482             }
483 
484             try {
485                 return this->get_encoded() == other->get_encoded();
486             } catch (value_undefined_method&) {
487             }
488 
489             return false;
490         }
491     }
492 
qbk_value(file_ptr const & f,string_iterator x,string_iterator y,value::tag_type t)493     value qbk_value(
494         file_ptr const& f,
495         string_iterator x,
496         string_iterator y,
497         value::tag_type t)
498     {
499         return value(new detail::qbk_value_impl(f, x, y, t));
500     }
501 
encoded_value(std::string const & x,value::tag_type t)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 
encoded_qbk_value(file_ptr const & f,string_iterator x,string_iterator y,std::string const & z,value::tag_type t)507     value encoded_qbk_value(
508         file_ptr const& f,
509         string_iterator x,
510         string_iterator y,
511         std::string const& z,
512         value::tag_type t)
513     {
514         return value(new detail::encoded_qbk_value_impl(f, x, y, z, t));
515     }
516 
517     //////////////////////////////////////////////////////////////////////////
518     // List methods
519 
520     namespace detail
521     {
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 
list_ref_back(value_node ** back)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;
540             }
541 
list_ref(value_node * ptr)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                 }
548             }
549 
list_unref(value_node * ptr)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                 }
557             }
558 
merge_sort(value_node ** l)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             }
566 
merge_sort(value_node ** l,int recurse_limit)567             value_node** merge_sort(value_node** l, int recurse_limit)
568             {
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;
576             }
577 
merge(value_node ** first,value_node ** second,value_node ** third)578             value_node** merge(
579                 value_node** first, value_node** second, value_node** third)
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);
589                     first = &(*first)->next_;
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);
605                     first = &(*first)->next_;
606                 }
607             }
608 
rotate(value_node ** first,value_node ** second,value_node ** third)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             }
618         }
619     }
620 
621     //////////////////////////////////////////////////////////////////////////
622     // Lists
623 
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);
630 
631           private:
632             value_list_impl(value_list_impl const&);
633 
type_namequickbook::detail::value_list_impl634             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;
643 
644             value_node* head_;
645         };
646 
value_list_impl(value::tag_type tag)647         value_list_impl::value_list_impl(value::tag_type tag)
648             : value_node(tag), head_(&value_list_end_impl::instance)
649         {
650         }
651 
value_list_impl(value_list_builder & builder,value::tag_type tag)652         value_list_impl::value_list_impl(
653             value_list_builder& builder, value::tag_type tag)
654             : value_node(tag), head_(builder.release())
655         {
656         }
657 
value_list_impl(value_list_impl const & x)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         }
663 
~value_list_impl()664         value_list_impl::~value_list_impl() { list_unref(head_); }
665 
clone() const666         value_node* value_list_impl::clone() const
667         {
668             return new value_list_impl(*this);
669         }
670 
empty() const671         bool value_list_impl::empty() const
672         {
673             return head_ == &value_list_end_impl::instance;
674         }
675 
is_list() const676         bool value_list_impl::is_list() const { return true; }
677 
get_list() const678         value_node* value_list_impl::get_list() const { return head_; }
679 
equals(value_node * other) const680         bool value_list_impl::equals(value_node* other) const
681         {
682             value_node* x1;
683 
684             try {
685                 x1 = other->get_list();
686             } catch (value_undefined_method&) {
687                 return false;
688             }
689 
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;
694             }
695 
696             return true;
697         }
698     }
699 
700     //////////////////////////////////////////////////////////////////////////
701     // List builder
702 
703     namespace detail
704     {
705         // value_list_builder
706 
value_list_builder()707         value_list_builder::value_list_builder()
708             : head_(&value_list_end_impl::instance), back_(&head_)
709         {
710         }
711 
value_list_builder(value_node * ptr)712         value_list_builder::value_list_builder(value_node* ptr)
713             : head_(ptr), back_(list_ref_back(&head_))
714         {
715         }
716 
~value_list_builder()717         value_list_builder::~value_list_builder() { list_unref(head_); }
718 
swap(value_list_builder & other)719         void value_list_builder::swap(value_list_builder& other)
720         {
721             std::swap(head_, other.head_);
722             std::swap(back_, other.back_);
723             if (back_ == &other.head_) back_ = &head_;
724             if (other.back_ == &head_) other.back_ = &other.head_;
725         }
726 
release()727         value_node* value_list_builder::release()
728         {
729             value_node* r = head_;
730             head_ = &value_list_end_impl::instance;
731             back_ = &head_;
732             return r;
733         }
734 
append(value_node * item)735         void value_list_builder::append(value_node* item)
736         {
737             if (item->next_) item = item->clone();
738             intrusive_ptr_add_ref(item);
739             item->next_ = *back_;
740             *back_ = item;
741             back_ = &item->next_;
742         }
743 
sort()744         void value_list_builder::sort()
745         {
746             back_ = merge_sort(&head_);
747             assert(*back_ == &value_list_end_impl::instance);
748         }
749 
empty() const750         bool value_list_builder::empty() const
751         {
752             return head_ == &value_list_end_impl::instance;
753         }
754     }
755 
756     //////////////////////////////////////////////////////////////////////////
757     // Value builder
758 
value_builder()759     value_builder::value_builder()
760         : current(), list_tag(value::default_tag), saved()
761     {
762     }
763 
swap(value_builder & other)764     void value_builder::swap(value_builder& other)
765     {
766         current.swap(other.current);
767         std::swap(list_tag, other.list_tag);
768         saved.swap(other.saved);
769     }
770 
save()771     void value_builder::save()
772     {
773         boost::scoped_ptr<value_builder> store(new value_builder);
774         swap(*store);
775         saved.swap(store);
776     }
777 
restore()778     void value_builder::restore()
779     {
780         boost::scoped_ptr<value_builder> store;
781         store.swap(saved);
782         swap(*store);
783     }
784 
release()785     value value_builder::release()
786     {
787         return value(new detail::value_list_impl(current, list_tag));
788     }
789 
insert(value const & item)790     void value_builder::insert(value const& item)
791     {
792         current.append(item.value_);
793     }
794 
extend(value const & list)795     void value_builder::extend(value const& list)
796     {
797         for (value::iterator begin = list.begin(), end = list.end();
798              begin != end; ++begin) {
799             insert(*begin);
800         }
801     }
802 
start_list(value::tag_type tag)803     void value_builder::start_list(value::tag_type tag)
804     {
805         save();
806         list_tag = tag;
807     }
808 
finish_list()809     void value_builder::finish_list()
810     {
811         value list = release();
812         restore();
813         insert(list);
814     }
815 
clear_list()816     void value_builder::clear_list() { restore(); }
817 
sort_list()818     void value_builder::sort_list() { current.sort(); }
819 
empty() const820     bool value_builder::empty() const { return current.empty(); }
821 
822     ////////////////////////////////////////////////////////////////////////////
823     // Iterator
824 
825     namespace detail
826     {
iterator()827         value::iterator::iterator() : ptr_(&value_list_end_impl::instance) {}
828     }
829 }
830