mirror of
https://github.com/boostorg/quickbook.git
synced 2026-01-19 16:32:16 +00:00
830 lines
24 KiB
C++
830 lines
24 KiB
C++
/*=============================================================================
|
|
Copyright (c) 2010-2011 Daniel James
|
|
|
|
Use, modification and distribution is subject to 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)
|
|
=============================================================================*/
|
|
|
|
#include "values.hpp"
|
|
#include <boost/current_function.hpp>
|
|
#include <boost/lexical_cast.hpp>
|
|
#include "files.hpp"
|
|
|
|
#define UNDEFINED_ERROR() \
|
|
throw value_undefined_method( \
|
|
std::string(BOOST_CURRENT_FUNCTION) + " not defined for " + \
|
|
this->type_name() + " values.");
|
|
|
|
namespace quickbook
|
|
{
|
|
////////////////////////////////////////////////////////////////////////////
|
|
// Value Error
|
|
|
|
struct value_undefined_method : value_error
|
|
{
|
|
value_undefined_method(std::string const&);
|
|
};
|
|
|
|
value_error::value_error(std::string const& x) : std::logic_error(x) {}
|
|
|
|
value_undefined_method::value_undefined_method(std::string const& x)
|
|
: value_error(x)
|
|
{
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
// Node
|
|
|
|
namespace detail
|
|
{
|
|
value_node::value_node(tag_type t) : ref_count_(0), tag_(t), next_() {}
|
|
|
|
value_node::~value_node() {}
|
|
|
|
file_ptr value_node::get_file() const { UNDEFINED_ERROR(); }
|
|
string_iterator value_node::get_position() const { UNDEFINED_ERROR(); }
|
|
int value_node::get_int() const { UNDEFINED_ERROR(); }
|
|
quickbook::string_view value_node::get_quickbook() const
|
|
{
|
|
UNDEFINED_ERROR();
|
|
}
|
|
std::string value_node::get_encoded() const { UNDEFINED_ERROR(); }
|
|
value_node* value_node::get_list() const { UNDEFINED_ERROR(); }
|
|
|
|
bool value_node::empty() const { return false; }
|
|
bool value_node::check() const { return true; }
|
|
bool value_node::is_list() const { return false; }
|
|
bool value_node::is_encoded() const { return false; }
|
|
bool value_node::equals(value_node*) const { UNDEFINED_ERROR(); }
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
// List end value
|
|
//
|
|
// A special value for marking the end of lists.
|
|
|
|
namespace detail
|
|
{
|
|
struct value_list_end_impl : public value_node
|
|
{
|
|
static value_list_end_impl instance;
|
|
|
|
private:
|
|
value_list_end_impl() : value_node(value::default_tag)
|
|
{
|
|
intrusive_ptr_add_ref(&instance);
|
|
next_ = this;
|
|
}
|
|
|
|
virtual char const* type_name() const { return "list end"; }
|
|
virtual value_node* clone() const { UNDEFINED_ERROR(); }
|
|
|
|
virtual bool equals(value_node* other) const
|
|
{
|
|
return this == other;
|
|
}
|
|
|
|
bool empty() const { UNDEFINED_ERROR(); }
|
|
bool check() const { UNDEFINED_ERROR(); }
|
|
bool is_list() const { UNDEFINED_ERROR(); }
|
|
bool is_encoded() const { UNDEFINED_ERROR(); }
|
|
};
|
|
|
|
value_list_end_impl value_list_end_impl::instance;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
// Empty/nil values
|
|
//
|
|
// (nil is just a special case of empty, don't be mislead by the name
|
|
// the type is not important).
|
|
|
|
namespace detail
|
|
{
|
|
struct empty_value_impl : public value_node
|
|
{
|
|
static value_node* new_(value::tag_type t);
|
|
|
|
protected:
|
|
explicit empty_value_impl(value::tag_type t) : value_node(t) {}
|
|
|
|
private:
|
|
char const* type_name() const { return "empty"; }
|
|
|
|
virtual value_node* clone() const
|
|
{
|
|
return new empty_value_impl(tag_);
|
|
}
|
|
|
|
virtual bool empty() const { return true; }
|
|
|
|
virtual bool check() const { return false; }
|
|
|
|
virtual bool equals(value_node* other) const
|
|
{
|
|
return !other->check();
|
|
}
|
|
|
|
friend value quickbook::empty_value(value::tag_type);
|
|
};
|
|
|
|
struct value_nil_impl : public empty_value_impl
|
|
{
|
|
static value_nil_impl instance;
|
|
|
|
private:
|
|
value_nil_impl() : empty_value_impl(value::default_tag)
|
|
{
|
|
intrusive_ptr_add_ref(&instance);
|
|
next_ = &value_list_end_impl::instance;
|
|
}
|
|
};
|
|
|
|
value_nil_impl value_nil_impl::instance;
|
|
|
|
value_node* empty_value_impl::new_(value::tag_type t)
|
|
{
|
|
// The return value from this function is always placed in an
|
|
// intrusive_ptr which will manage the memory correctly.
|
|
// Note that value_nil_impl increments its reference count
|
|
// in its constructor, so that it will never be deleted by the
|
|
// intrusive pointer.
|
|
|
|
if (t == value::default_tag)
|
|
return &value_nil_impl::instance;
|
|
else
|
|
return new empty_value_impl(t);
|
|
}
|
|
}
|
|
|
|
value empty_value(value::tag_type t)
|
|
{
|
|
return value(detail::empty_value_impl::new_(t));
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
// value_counted
|
|
|
|
namespace detail
|
|
{
|
|
value_counted::value_counted() : value_base(&value_nil_impl::instance)
|
|
{
|
|
// Even though empty is not on the heap, its reference
|
|
// counter needs to be incremented so that the destructor
|
|
// doesn't try to delete it.
|
|
|
|
intrusive_ptr_add_ref(value_);
|
|
}
|
|
|
|
value_counted::value_counted(value_counted const& x) : value_base(x)
|
|
{
|
|
intrusive_ptr_add_ref(value_);
|
|
}
|
|
|
|
value_counted::value_counted(value_base const& x) : value_base(x)
|
|
{
|
|
intrusive_ptr_add_ref(value_);
|
|
}
|
|
|
|
value_counted::value_counted(value_node* x) : value_base(x)
|
|
{
|
|
intrusive_ptr_add_ref(value_);
|
|
}
|
|
|
|
value_counted::~value_counted() { intrusive_ptr_release(value_); }
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
// value
|
|
|
|
value::value() : detail::value_counted() {}
|
|
|
|
value::value(value const& x) : detail::value_counted(x) {}
|
|
|
|
value::value(detail::value_base const& x) : detail::value_counted(x) {}
|
|
|
|
value::value(detail::value_node* x) : detail::value_counted(x) {}
|
|
|
|
value& value::operator=(value x)
|
|
{
|
|
swap(x);
|
|
return *this;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
// Integers
|
|
|
|
namespace detail
|
|
{
|
|
struct int_value_impl : public value_node
|
|
{
|
|
public:
|
|
explicit int_value_impl(int, value::tag_type);
|
|
|
|
private:
|
|
char const* type_name() const { return "integer"; }
|
|
virtual value_node* clone() const;
|
|
virtual int get_int() const;
|
|
virtual std::string get_encoded() const;
|
|
virtual bool empty() const;
|
|
virtual bool is_encoded() const;
|
|
virtual bool equals(value_node*) const;
|
|
|
|
int value_;
|
|
};
|
|
|
|
int_value_impl::int_value_impl(int v, value::tag_type t)
|
|
: value_node(t), value_(v)
|
|
{
|
|
}
|
|
|
|
value_node* int_value_impl::clone() const
|
|
{
|
|
return new int_value_impl(value_, tag_);
|
|
}
|
|
|
|
int int_value_impl::get_int() const { return value_; }
|
|
|
|
std::string int_value_impl::get_encoded() const
|
|
{
|
|
return boost::lexical_cast<std::string>(value_);
|
|
}
|
|
|
|
bool int_value_impl::empty() const { return false; }
|
|
|
|
bool int_value_impl::is_encoded() const { return true; }
|
|
|
|
bool int_value_impl::equals(value_node* other) const
|
|
{
|
|
try {
|
|
return value_ == other->get_int();
|
|
} catch (value_undefined_method&) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
value int_value(int v, value::tag_type t)
|
|
{
|
|
return value(new detail::int_value_impl(v, t));
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
// Strings
|
|
|
|
namespace detail
|
|
{
|
|
struct encoded_value_impl : public value_node
|
|
{
|
|
public:
|
|
explicit encoded_value_impl(std::string const&, value::tag_type);
|
|
|
|
private:
|
|
char const* type_name() const { return "encoded text"; }
|
|
|
|
virtual ~encoded_value_impl();
|
|
virtual value_node* clone() const;
|
|
virtual std::string get_encoded() const;
|
|
virtual bool empty() const;
|
|
virtual bool is_encoded() const;
|
|
virtual bool equals(value_node*) const;
|
|
|
|
std::string value_;
|
|
};
|
|
|
|
struct qbk_value_impl : public value_node
|
|
{
|
|
public:
|
|
explicit qbk_value_impl(
|
|
file_ptr const&,
|
|
string_iterator begin,
|
|
string_iterator end,
|
|
value::tag_type);
|
|
|
|
private:
|
|
char const* type_name() const { return "quickbook"; }
|
|
|
|
virtual ~qbk_value_impl();
|
|
virtual value_node* clone() const;
|
|
virtual file_ptr get_file() const;
|
|
virtual string_iterator get_position() const;
|
|
virtual quickbook::string_view get_quickbook() const;
|
|
virtual bool empty() const;
|
|
virtual bool equals(value_node*) const;
|
|
|
|
file_ptr file_;
|
|
string_iterator begin_;
|
|
string_iterator end_;
|
|
};
|
|
|
|
struct encoded_qbk_value_impl : public value_node
|
|
{
|
|
private:
|
|
char const* type_name() const
|
|
{
|
|
return "encoded text with quickbook reference";
|
|
}
|
|
|
|
encoded_qbk_value_impl(
|
|
file_ptr const&,
|
|
string_iterator,
|
|
string_iterator,
|
|
std::string const&,
|
|
value::tag_type);
|
|
|
|
virtual ~encoded_qbk_value_impl();
|
|
virtual value_node* clone() const;
|
|
virtual file_ptr get_file() const;
|
|
virtual string_iterator get_position() const;
|
|
virtual quickbook::string_view get_quickbook() const;
|
|
virtual std::string get_encoded() const;
|
|
virtual bool empty() const;
|
|
virtual bool is_encoded() const;
|
|
virtual bool equals(value_node*) const;
|
|
|
|
file_ptr file_;
|
|
string_iterator begin_;
|
|
string_iterator end_;
|
|
std::string encoded_value_;
|
|
|
|
friend quickbook::value quickbook::encoded_qbk_value(
|
|
file_ptr const&,
|
|
string_iterator,
|
|
string_iterator,
|
|
std::string const&,
|
|
quickbook::value::tag_type);
|
|
};
|
|
|
|
// encoded_value_impl
|
|
|
|
encoded_value_impl::encoded_value_impl(
|
|
std::string const& val, value::tag_type tag)
|
|
: value_node(tag), value_(val)
|
|
{
|
|
}
|
|
|
|
encoded_value_impl::~encoded_value_impl() {}
|
|
|
|
value_node* encoded_value_impl::clone() const
|
|
{
|
|
return new encoded_value_impl(value_, tag_);
|
|
}
|
|
|
|
std::string encoded_value_impl::get_encoded() const { return value_; }
|
|
|
|
bool encoded_value_impl::empty() const { return value_.empty(); }
|
|
|
|
bool encoded_value_impl::is_encoded() const { return true; }
|
|
|
|
bool encoded_value_impl::equals(value_node* other) const
|
|
{
|
|
try {
|
|
return value_ == other->get_encoded();
|
|
} catch (value_undefined_method&) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// qbk_value_impl
|
|
|
|
qbk_value_impl::qbk_value_impl(
|
|
file_ptr const& f,
|
|
string_iterator begin,
|
|
string_iterator end,
|
|
value::tag_type tag)
|
|
: value_node(tag), file_(f), begin_(begin), end_(end)
|
|
{
|
|
}
|
|
|
|
qbk_value_impl::~qbk_value_impl() {}
|
|
|
|
value_node* qbk_value_impl::clone() const
|
|
{
|
|
return new qbk_value_impl(file_, begin_, end_, tag_);
|
|
}
|
|
|
|
file_ptr qbk_value_impl::get_file() const { return file_; }
|
|
|
|
string_iterator qbk_value_impl::get_position() const { return begin_; }
|
|
|
|
quickbook::string_view qbk_value_impl::get_quickbook() const
|
|
{
|
|
return quickbook::string_view(begin_, end_ - begin_);
|
|
}
|
|
|
|
bool qbk_value_impl::empty() const { return begin_ == end_; }
|
|
|
|
bool qbk_value_impl::equals(value_node* other) const
|
|
{
|
|
try {
|
|
return this->get_quickbook() == other->get_quickbook();
|
|
} catch (value_undefined_method&) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// encoded_qbk_value_impl
|
|
|
|
encoded_qbk_value_impl::encoded_qbk_value_impl(
|
|
file_ptr const& f,
|
|
string_iterator begin,
|
|
string_iterator end,
|
|
std::string const& encoded,
|
|
value::tag_type tag)
|
|
: value_node(tag)
|
|
, file_(f)
|
|
, begin_(begin)
|
|
, end_(end)
|
|
, encoded_value_(encoded)
|
|
|
|
{
|
|
}
|
|
|
|
encoded_qbk_value_impl::~encoded_qbk_value_impl() {}
|
|
|
|
value_node* encoded_qbk_value_impl::clone() const
|
|
{
|
|
return new encoded_qbk_value_impl(
|
|
file_, begin_, end_, encoded_value_, tag_);
|
|
}
|
|
|
|
file_ptr encoded_qbk_value_impl::get_file() const { return file_; }
|
|
|
|
string_iterator encoded_qbk_value_impl::get_position() const
|
|
{
|
|
return begin_;
|
|
}
|
|
|
|
quickbook::string_view encoded_qbk_value_impl::get_quickbook() const
|
|
{
|
|
return quickbook::string_view(begin_, end_ - begin_);
|
|
}
|
|
|
|
std::string encoded_qbk_value_impl::get_encoded() const
|
|
{
|
|
return encoded_value_;
|
|
}
|
|
|
|
// Should this test the quickbook, the boostbook or both?
|
|
bool encoded_qbk_value_impl::empty() const
|
|
{
|
|
return encoded_value_.empty();
|
|
}
|
|
|
|
bool encoded_qbk_value_impl::is_encoded() const { return true; }
|
|
|
|
bool encoded_qbk_value_impl::equals(value_node* other) const
|
|
{
|
|
try {
|
|
return this->get_quickbook() == other->get_quickbook();
|
|
} catch (value_undefined_method&) {
|
|
}
|
|
|
|
try {
|
|
return this->get_encoded() == other->get_encoded();
|
|
} catch (value_undefined_method&) {
|
|
}
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
value qbk_value(
|
|
file_ptr const& f,
|
|
string_iterator x,
|
|
string_iterator y,
|
|
value::tag_type t)
|
|
{
|
|
return value(new detail::qbk_value_impl(f, x, y, t));
|
|
}
|
|
|
|
value encoded_value(std::string const& x, value::tag_type t)
|
|
{
|
|
return value(new detail::encoded_value_impl(x, t));
|
|
}
|
|
|
|
value encoded_qbk_value(
|
|
file_ptr const& f,
|
|
string_iterator x,
|
|
string_iterator y,
|
|
std::string const& z,
|
|
value::tag_type t)
|
|
{
|
|
return value(new detail::encoded_qbk_value_impl(f, x, y, z, t));
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// List methods
|
|
|
|
namespace detail
|
|
{
|
|
namespace
|
|
{
|
|
value_node** list_ref_back(value_node**);
|
|
void list_ref(value_node*);
|
|
void list_unref(value_node*);
|
|
value_node** merge_sort(value_node**);
|
|
value_node** merge_sort(value_node**, int);
|
|
value_node** merge(value_node**, value_node**, value_node**);
|
|
void rotate(value_node**, value_node**, value_node**);
|
|
|
|
value_node** list_ref_back(value_node** back)
|
|
{
|
|
while (*back != &value_list_end_impl::instance) {
|
|
intrusive_ptr_add_ref(*back);
|
|
back = &(*back)->next_;
|
|
}
|
|
|
|
return back;
|
|
}
|
|
|
|
void list_ref(value_node* ptr)
|
|
{
|
|
while (ptr != &value_list_end_impl::instance) {
|
|
intrusive_ptr_add_ref(ptr);
|
|
ptr = ptr->next_;
|
|
}
|
|
}
|
|
|
|
void list_unref(value_node* ptr)
|
|
{
|
|
while (ptr != &value_list_end_impl::instance) {
|
|
value_node* next = ptr->next_;
|
|
intrusive_ptr_release(ptr);
|
|
ptr = next;
|
|
}
|
|
}
|
|
|
|
value_node** merge_sort(value_node** l)
|
|
{
|
|
if (*l == &value_list_end_impl::instance)
|
|
return l;
|
|
else
|
|
return merge_sort(l, 9999);
|
|
}
|
|
|
|
value_node** merge_sort(value_node** l, int recurse_limit)
|
|
{
|
|
value_node** p = &(*l)->next_;
|
|
for (int count = 0; count < recurse_limit &&
|
|
*p != &value_list_end_impl::instance;
|
|
++count) {
|
|
p = merge(l, p, merge_sort(p, count));
|
|
}
|
|
return p;
|
|
}
|
|
|
|
value_node** merge(
|
|
value_node** first, value_node** second, value_node** third)
|
|
{
|
|
for (;;) {
|
|
for (;;) {
|
|
if (first == second) return third;
|
|
if ((*second)->tag_ < (*first)->tag_) break;
|
|
first = &(*first)->next_;
|
|
}
|
|
|
|
rotate(first, second, third);
|
|
first = &(*first)->next_;
|
|
|
|
// Since the two ranges were just swapped, the order is now:
|
|
// first...third...second
|
|
//
|
|
// Also, that since the second section of the list was
|
|
// originally before the first, if the heads are equal
|
|
// we need to swap to maintain the order.
|
|
|
|
for (;;) {
|
|
if (first == third) return second;
|
|
if ((*third)->tag_ <= (*first)->tag_) break;
|
|
first = &(*first)->next_;
|
|
}
|
|
|
|
rotate(first, third, second);
|
|
first = &(*first)->next_;
|
|
}
|
|
}
|
|
|
|
void rotate(
|
|
value_node** first, value_node** second, value_node** third)
|
|
{
|
|
value_node* tmp = *first;
|
|
*first = *second;
|
|
*second = *third;
|
|
*third = tmp;
|
|
// if(*second != &value_list_end_impl::instance) back = second;
|
|
}
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Lists
|
|
|
|
namespace detail
|
|
{
|
|
struct value_list_impl : public value_node
|
|
{
|
|
value_list_impl(value::tag_type);
|
|
value_list_impl(value_list_builder&, value::tag_type);
|
|
|
|
private:
|
|
value_list_impl(value_list_impl const&);
|
|
|
|
char const* type_name() const { return "list"; }
|
|
|
|
virtual ~value_list_impl();
|
|
virtual value_node* clone() const;
|
|
virtual bool empty() const;
|
|
virtual bool equals(value_node*) const;
|
|
|
|
virtual bool is_list() const;
|
|
virtual value_node* get_list() const;
|
|
|
|
value_node* head_;
|
|
};
|
|
|
|
value_list_impl::value_list_impl(value::tag_type tag)
|
|
: value_node(tag), head_(&value_list_end_impl::instance)
|
|
{
|
|
}
|
|
|
|
value_list_impl::value_list_impl(
|
|
value_list_builder& builder, value::tag_type tag)
|
|
: value_node(tag), head_(builder.release())
|
|
{
|
|
}
|
|
|
|
value_list_impl::value_list_impl(value_list_impl const& x)
|
|
: value_node(x.tag_), head_(x.head_)
|
|
{
|
|
list_ref(head_);
|
|
}
|
|
|
|
value_list_impl::~value_list_impl() { list_unref(head_); }
|
|
|
|
value_node* value_list_impl::clone() const
|
|
{
|
|
return new value_list_impl(*this);
|
|
}
|
|
|
|
bool value_list_impl::empty() const
|
|
{
|
|
return head_ == &value_list_end_impl::instance;
|
|
}
|
|
|
|
bool value_list_impl::is_list() const { return true; }
|
|
|
|
value_node* value_list_impl::get_list() const { return head_; }
|
|
|
|
bool value_list_impl::equals(value_node* other) const
|
|
{
|
|
value_node* x1;
|
|
|
|
try {
|
|
x1 = other->get_list();
|
|
} catch (value_undefined_method&) {
|
|
return false;
|
|
}
|
|
|
|
for (value_node *x2 = head_; x1 != x2;
|
|
x1 = x1->next_, x2 = x2->next_) {
|
|
if (x2 == &value_list_end_impl::instance || !x1->equals(x2))
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// List builder
|
|
|
|
namespace detail
|
|
{
|
|
// value_list_builder
|
|
|
|
value_list_builder::value_list_builder()
|
|
: head_(&value_list_end_impl::instance), back_(&head_)
|
|
{
|
|
}
|
|
|
|
value_list_builder::value_list_builder(value_node* ptr)
|
|
: head_(ptr), back_(list_ref_back(&head_))
|
|
{
|
|
}
|
|
|
|
value_list_builder::~value_list_builder() { list_unref(head_); }
|
|
|
|
void value_list_builder::swap(value_list_builder& other)
|
|
{
|
|
std::swap(head_, other.head_);
|
|
std::swap(back_, other.back_);
|
|
if (back_ == &other.head_) back_ = &head_;
|
|
if (other.back_ == &head_) other.back_ = &other.head_;
|
|
}
|
|
|
|
value_node* value_list_builder::release()
|
|
{
|
|
value_node* r = head_;
|
|
head_ = &value_list_end_impl::instance;
|
|
back_ = &head_;
|
|
return r;
|
|
}
|
|
|
|
void value_list_builder::append(value_node* item)
|
|
{
|
|
if (item->next_) item = item->clone();
|
|
intrusive_ptr_add_ref(item);
|
|
item->next_ = *back_;
|
|
*back_ = item;
|
|
back_ = &item->next_;
|
|
}
|
|
|
|
void value_list_builder::sort()
|
|
{
|
|
back_ = merge_sort(&head_);
|
|
assert(*back_ == &value_list_end_impl::instance);
|
|
}
|
|
|
|
bool value_list_builder::empty() const
|
|
{
|
|
return head_ == &value_list_end_impl::instance;
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Value builder
|
|
|
|
value_builder::value_builder()
|
|
: current(), list_tag(value::default_tag), saved()
|
|
{
|
|
}
|
|
|
|
void value_builder::swap(value_builder& other)
|
|
{
|
|
current.swap(other.current);
|
|
std::swap(list_tag, other.list_tag);
|
|
saved.swap(other.saved);
|
|
}
|
|
|
|
void value_builder::save()
|
|
{
|
|
boost::scoped_ptr<value_builder> store(new value_builder);
|
|
swap(*store);
|
|
saved.swap(store);
|
|
}
|
|
|
|
void value_builder::restore()
|
|
{
|
|
boost::scoped_ptr<value_builder> store;
|
|
store.swap(saved);
|
|
swap(*store);
|
|
}
|
|
|
|
value value_builder::release()
|
|
{
|
|
return value(new detail::value_list_impl(current, list_tag));
|
|
}
|
|
|
|
void value_builder::insert(value const& item)
|
|
{
|
|
current.append(item.value_);
|
|
}
|
|
|
|
void value_builder::extend(value const& list)
|
|
{
|
|
for (value::iterator begin = list.begin(), end = list.end();
|
|
begin != end; ++begin) {
|
|
insert(*begin);
|
|
}
|
|
}
|
|
|
|
void value_builder::start_list(value::tag_type tag)
|
|
{
|
|
save();
|
|
list_tag = tag;
|
|
}
|
|
|
|
void value_builder::finish_list()
|
|
{
|
|
value list = release();
|
|
restore();
|
|
insert(list);
|
|
}
|
|
|
|
void value_builder::clear_list() { restore(); }
|
|
|
|
void value_builder::sort_list() { current.sort(); }
|
|
|
|
bool value_builder::empty() const { return current.empty(); }
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
// Iterator
|
|
|
|
namespace detail
|
|
{
|
|
value::iterator::iterator() : ptr_(&value_list_end_impl::instance) {}
|
|
}
|
|
}
|