/*============================================================================= 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 #include #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(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 store(new value_builder); swap(*store); saved.swap(store); } void value_builder::restore() { boost::scoped_ptr 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) {} } }