/tools/quickbook/src/values.cpp
https://github.com/eile/boost-svn · C++ · 1023 lines · 770 code · 192 blank · 61 comment · 52 complexity · 4dd4729f00e3cdc098a7a4080c39d5c6 MD5 · raw file
- /*=============================================================================
- 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/intrusive_ptr.hpp>
- #include <boost/current_function.hpp>
- #include <boost/lexical_cast.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() {
- }
-
- value_node* value_node::store() { return this; }
- file_position value_node::get_position() const { UNDEFINED_ERROR(); }
- int value_node::get_int() const { UNDEFINED_ERROR(); }
- std::string value_node::get_quickbook() const { UNDEFINED_ERROR(); }
- value_node::qbk_range value_node::get_quickbook_range() const { UNDEFINED_ERROR(); }
- std::string value_node::get_boostbook() 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_string() 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_string() 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 value_empty_impl : public value_node
- {
- static value_node* new_(value::tag_type t);
- protected:
- explicit value_empty_impl(value::tag_type t)
- : value_node(t) {}
- private:
- char const* type_name() const { return "empty"; }
-
- virtual value_node* clone() const
- { return new value_empty_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 value_empty_impl
- {
- static value_nil_impl instance;
- private:
- value_nil_impl()
- : value_empty_impl(value::default_tag)
- {
- intrusive_ptr_add_ref(&instance);
- next_ = &value_list_end_impl::instance;
- }
- };
- value_nil_impl value_nil_impl::instance;
- value_node* value_empty_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 value_empty_impl(t);
- }
- }
- value empty_value(value::tag_type t)
- {
- return value(detail::value_empty_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;
- }
- ////////////////////////////////////////////////////////////////////////////
- // stored_value
- stored_value::stored_value()
- : detail::value_counted()
- {
- }
- stored_value::stored_value(stored_value const& x)
- : detail::value_counted(x)
- {
- }
- stored_value::stored_value(detail::value_base const& x)
- : detail::value_counted(x.value_->store())
- {
- }
- stored_value& stored_value::operator=(stored_value x)
- {
- swap(x);
- return *this;
- }
- ////////////////////////////////////////////////////////////////////////////
- // Integers
- namespace detail
- {
- struct value_int_impl : public value_node
- {
- public:
- explicit value_int_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_quickbook() const;
- virtual std::string get_boostbook() const;
- virtual bool empty() const;
- virtual bool equals(value_node*) const;
- int value_;
- };
- value_int_impl::value_int_impl(int v, value::tag_type t)
- : value_node(t)
- , value_(v)
- {}
- value_node* value_int_impl::clone() const
- {
- return new value_int_impl(value_, tag_);
- }
- int value_int_impl::get_int() const
- {
- return value_;
- }
- std::string value_int_impl::get_quickbook() const
- {
- return boost::lexical_cast<std::string>(value_);
- }
- std::string value_int_impl::get_boostbook() const
- {
- return boost::lexical_cast<std::string>(value_);
- }
- bool value_int_impl::empty() const
- {
- return false;
- }
- bool value_int_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::value_int_impl(v, t));
- }
- ////////////////////////////////////////////////////////////////////////////
- // Strings
- namespace detail
- {
- struct value_string_impl : public value_node
- {
- public:
- explicit value_string_impl(std::string const&, value::tag_type);
- private:
- char const* type_name() const { return "boostbook"; }
- virtual ~value_string_impl();
- virtual value_node* clone() const;
- virtual std::string get_boostbook() const;
- virtual bool is_string() const;
- virtual bool empty() const;
- virtual bool equals(value_node*) const;
- std::string value_;
- };
-
- struct value_qbk_string_impl : public value_node
- {
- public:
- explicit value_qbk_string_impl(
- std::string const&, file_position, value::tag_type);
- explicit value_qbk_string_impl(
- quickbook::iterator begin, quickbook::iterator end,
- value::tag_type);
- private:
- char const* type_name() const { return "quickbook"; }
- virtual ~value_qbk_string_impl();
- virtual value_node* clone() const;
- virtual file_position get_position() const;
- virtual std::string get_quickbook() const;
- qbk_range get_quickbook_range() const;
- virtual bool is_string() const;
- virtual bool empty() const;
- virtual bool equals(value_node*) const;
-
- std::string value_;
- file_position position_;
- };
- struct value_qbk_ref_impl : public value_node
- {
- public:
- explicit value_qbk_ref_impl(quickbook::iterator begin, quickbook::iterator end, value::tag_type);
- private:
- char const* type_name() const { return "quickbook"; }
- virtual ~value_qbk_ref_impl();
- virtual value_node* clone() const;
- virtual value_node* store();
- virtual file_position get_position() const;
- virtual std::string get_quickbook() const;
- qbk_range get_quickbook_range() const;
- virtual bool is_string() const;
- virtual bool empty() const;
- virtual bool equals(value_node*) const;
- quickbook::iterator begin_;
- quickbook::iterator end_;
- };
-
- struct value_qbk_bbk_impl : public value_node
- {
- private:
- char const* type_name() const { return "quickbook/boostbook"; }
- value_qbk_bbk_impl(
- std::string const& qbk, std::string const& bbk,
- file_position const&, value::tag_type);
- value_qbk_bbk_impl(std::string const&, value::tag_type);
- value_qbk_bbk_impl(
- quickbook::iterator, quickbook::iterator,
- std::string const&, value::tag_type);
-
- virtual ~value_qbk_bbk_impl();
- virtual value_node* clone() const;
- virtual file_position get_position() const;
- virtual std::string get_quickbook() const;
- qbk_range get_quickbook_range() const;
- virtual std::string get_boostbook() const;
- virtual bool is_string() const;
- virtual bool empty() const;
- virtual bool equals(value_node*) const;
- std::string qbk_value_;
- std::string bbk_value_;
- file_position position_;
-
- friend quickbook::value quickbook::qbk_bbk_value(
- std::string const&, quickbook::value::tag_type);
- friend quickbook::value quickbook::qbk_bbk_value(
- quickbook::iterator, quickbook::iterator,
- std::string const&, quickbook::value::tag_type);
- };
- // value_string_impl
-
- value_string_impl::value_string_impl(
- std::string const& val,
- value::tag_type tag
- )
- : value_node(tag), value_(val)
- {
- }
-
- value_string_impl::~value_string_impl()
- {
- }
- value_node* value_string_impl::clone() const
- {
- return new value_string_impl(value_, tag_);
- }
-
- std::string value_string_impl::get_boostbook() const
- { return value_; }
- bool value_string_impl::is_string() const
- { return true; }
- bool value_string_impl::empty() const
- { return value_.empty(); }
- bool value_string_impl::equals(value_node* other) const {
- try {
- return value_ == other->get_boostbook();
- }
- catch(value_undefined_method&) {
- return false;
- }
- }
- // value_qbk_string_impl
-
- value_qbk_string_impl::value_qbk_string_impl(
- std::string const& v,
- file_position p,
- value::tag_type tag)
- : value_node(tag)
- , value_(v)
- , position_(p)
- {}
- value_qbk_string_impl::value_qbk_string_impl(
- quickbook::iterator begin, quickbook::iterator end,
- value::tag_type tag)
- : value_node(tag)
- , value_(begin, end)
- , position_(begin.get_position())
- {}
-
- value_qbk_string_impl::~value_qbk_string_impl()
- {}
-
- value_node* value_qbk_string_impl::clone() const
- {
- return new value_qbk_string_impl(value_, position_, tag_);
- }
- file_position value_qbk_string_impl::get_position() const
- { return position_; }
- std::string value_qbk_string_impl::get_quickbook() const
- { return value_; }
- value::qbk_range value_qbk_string_impl::get_quickbook_range() const
- { return qbk_range(
- iterator(value_.begin(), position_),
- iterator(value_.end())); }
- bool value_qbk_string_impl::is_string() const
- { return true; }
- bool value_qbk_string_impl::empty() const
- { return value_.empty(); }
- bool value_qbk_string_impl::equals(value_node* other) const {
- try {
- return value_ == other->get_quickbook();
- }
- catch(value_undefined_method&) {
- return false;
- }
- }
- // value_qbk_ref_impl
-
- value_qbk_ref_impl::value_qbk_ref_impl(
- quickbook::iterator begin, quickbook::iterator end,
- value::tag_type tag
- ) : value_node(tag), begin_(begin), end_(end)
- {
- }
-
- value_qbk_ref_impl::~value_qbk_ref_impl()
- {
- }
-
- value_node* value_qbk_ref_impl::clone() const
- {
- return new value_qbk_ref_impl(begin_, end_, tag_);
- }
- value_node* value_qbk_ref_impl::store()
- {
- return new value_qbk_string_impl(begin_, end_, tag_);
- }
- file_position value_qbk_ref_impl::get_position() const
- { return begin_.get_position(); }
- std::string value_qbk_ref_impl::get_quickbook() const
- { return std::string(begin_.base(), end_.base()); }
- value::qbk_range value_qbk_ref_impl::get_quickbook_range() const
- { return qbk_range(begin_, end_); }
- bool value_qbk_ref_impl::is_string() const
- { return true; }
- bool value_qbk_ref_impl::empty() const
- { return begin_ == end_; }
-
- bool value_qbk_ref_impl::equals(value_node* other) const {
- try {
- return this->get_quickbook() == other->get_quickbook();
- }
- catch(value_undefined_method&) {
- return false;
- }
- }
- // value_qbk_bbk_impl
-
- value_qbk_bbk_impl::value_qbk_bbk_impl(
- std::string const& qbk,
- std::string const& bbk,
- file_position const& pos,
- value::tag_type tag)
- : value_node(tag)
- , qbk_value_(qbk)
- , bbk_value_(bbk)
- , position_(pos)
-
- {
- }
-
- value_qbk_bbk_impl::value_qbk_bbk_impl(
- quickbook::iterator begin,
- quickbook::iterator end,
- std::string const& bbk,
- value::tag_type tag)
- : value_node(tag)
- , qbk_value_(begin.base(), end.base())
- , bbk_value_(bbk)
- , position_(begin.get_position())
-
- {
- }
-
- value_qbk_bbk_impl::value_qbk_bbk_impl(
- std::string const& val,
- value::tag_type tag)
- : value_node(tag)
- , qbk_value_(val)
- , bbk_value_(val)
- , position_()
- {
- }
-
- value_qbk_bbk_impl::~value_qbk_bbk_impl()
- {
- }
- value_node* value_qbk_bbk_impl::clone() const
- {
- return new value_qbk_bbk_impl(
- qbk_value_, bbk_value_, position_, tag_);
- }
- file_position value_qbk_bbk_impl::get_position() const
- { return position_; }
- std::string value_qbk_bbk_impl::get_quickbook() const
- { return qbk_value_; }
- value::qbk_range value_qbk_bbk_impl::get_quickbook_range() const
- { return qbk_range(
- iterator(qbk_value_.begin(), position_),
- iterator(qbk_value_.end())); }
- std::string value_qbk_bbk_impl::get_boostbook() const
- { return bbk_value_; }
- bool value_qbk_bbk_impl::is_string() const
- { return true; }
- // Should this test the quickbook, the boostbook or both?
- bool value_qbk_bbk_impl::empty() const
- { return bbk_value_.empty(); }
- bool value_qbk_bbk_impl::equals(value_node* other) const {
- try {
- return this->get_quickbook() == other->get_quickbook();
- }
- catch(value_undefined_method&) {}
- try {
- return this->get_boostbook() == other->get_boostbook();
- }
- catch(value_undefined_method&) {}
- return false;
- }
- }
- value qbk_value(iterator x, iterator y, value::tag_type t)
- {
- return value(new detail::value_qbk_ref_impl(x, y, t));
- }
- value qbk_value(std::string const& x, file_position pos, value::tag_type t)
- {
- return value(new detail::value_qbk_string_impl(x, pos, t));
- }
- value bbk_value(std::string const& x, value::tag_type t)
- {
- return value(new detail::value_string_impl(x, t));
- }
- value qbk_bbk_value(std::string const& x, value::tag_type t)
- {
- return value(new detail::value_qbk_bbk_impl(x,t));
- }
- value qbk_bbk_value(
- iterator x, iterator y,
- std::string const& z, value::tag_type t)
- {
- return value(new detail::value_qbk_bbk_impl(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 value_node* store();
- 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);
- }
- value_node* value_list_impl::store()
- {
- value_node* pos = head_;
- boost::intrusive_ptr<value_node> new_node;
- for(;;) {
- if(pos == &value_list_end_impl::instance)
- return this;
- new_node = pos->store();
- if(new_node.get() != pos) break;
- pos = pos->next_;
- }
- value_list_builder build;
- value_node* pos2 = head_;
- for(;pos2 != pos; pos2 = pos2->next_)
- build.append(pos2);
- build.append(new_node.get());
- pos2 = pos2->next_;
- for(;pos2 != &value_list_end_impl::instance; pos2 = pos2->next_)
- build.append(pos2->store());
- return new value_list_impl(build, tag_);
- }
- 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);
- }
- }
- //////////////////////////////////////////////////////////////////////////
- // 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::reset() {
- detail::value_list_builder new_builder;
- current.swap(new_builder);
- list_tag = value::default_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) {
- value::tag_type saved_tag = tag;
- save();
- list_tag = saved_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();
- }
- ////////////////////////////////////////////////////////////////////////////
- // Iterator
- namespace detail
- {
- value::iterator::iterator()
- : ptr_(&value_list_end_impl::instance) {}
- }
- }