/*============================================================================= 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) =============================================================================*/ // An easy way to store data parsed for quickbook. #if !defined(BOOST_SPIRIT_QUICKBOOK_VALUES_HPP) #define BOOST_SPIRIT_QUICKBOOK_VALUES_HPP #include #include #include #include #include #include #include #include "files.hpp" #include "fwd.hpp" #include "string_view.hpp" namespace quickbook { struct value; struct value_builder; struct value_error; namespace detail { //////////////////////////////////////////////////////////////////////// // Node struct value_node { private: value_node(value_node const&); value_node& operator=(value_node const&); public: typedef int tag_type; protected: explicit value_node(tag_type); virtual ~value_node(); public: virtual char const* type_name() const = 0; virtual value_node* clone() const = 0; 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 int get_int() const; virtual bool check() const; virtual bool empty() const; virtual bool is_encoded() const; virtual bool is_list() const; virtual bool equals(value_node*) const; virtual value_node* get_list() const; int ref_count_; const tag_type tag_; value_node* next_; friend void intrusive_ptr_add_ref(value_node* ptr) { ++ptr->ref_count_; } friend void intrusive_ptr_release(value_node* ptr) { if (--ptr->ref_count_ == 0) delete ptr; } }; //////////////////////////////////////////////////////////////////////// // Value base // // This defines most of the public methods for value. // 'begin' and 'end' are defined with the iterators later. struct value_base { public: struct iterator; typedef iterator const_iterator; typedef value_node::tag_type tag_type; enum { default_tag = 0 }; protected: explicit value_base(value_node* base) : value_(base) { assert(value_); } ~value_base() {} void swap(value_base& x) { std::swap(value_, x.value_); } public: bool check() const { return value_->check(); } bool empty() const { return value_->empty(); } bool is_encoded() const { return value_->is_encoded(); } bool is_list() const { return value_->is_list(); } iterator begin() const; iterator end() const; // Item accessors tag_type get_tag() const { return value_->tag_; } file_ptr get_file() const { return value_->get_file(); } string_iterator get_position() const { return value_->get_position(); } quickbook::string_view get_quickbook() const { return value_->get_quickbook(); } std::string get_encoded() const { return value_->get_encoded(); } int get_int() const { return value_->get_int(); } // Equality is pretty inefficient. Not really designed for anything // more than testing purposes. friend bool operator==(value_base const& x, value_base const& y) { return x.value_->equals(y.value_); } protected: value_node* value_; // value_builder needs to access 'value_' to get the node // from a value. friend struct quickbook::value_builder; }; //////////////////////////////////////////////////////////////////////// // Reference and proxy values for use in iterators struct value_ref : public value_base { public: explicit value_ref(value_node* base) : value_base(base) {} }; struct value_proxy : public value_base { public: explicit value_proxy(value_node* base) : value_base(base) {} value_proxy* operator->() { return this; } value_ref operator*() const { return value_ref(value_); } }; //////////////////////////////////////////////////////////////////////// // Iterators struct value_base::iterator : public boost::forward_iterator_helper< iterator, value, int, value_proxy, value_ref> { public: iterator(); explicit iterator(value_node* p) : ptr_(p) {} friend bool operator==(iterator x, iterator y) { return x.ptr_ == y.ptr_; } iterator& operator++() { ptr_ = ptr_->next_; return *this; } value_ref operator*() const { return value_ref(ptr_); } value_proxy operator->() const { return value_proxy(ptr_); } private: value_node* ptr_; }; inline value_base::iterator value_base::begin() const { return iterator(value_->get_list()); } inline value_base::iterator value_base::end() const { return iterator(); } //////////////////////////////////////////////////////////////////////// // Reference counting for values struct value_counted : public value_base { value_counted& operator=(value_counted const&); protected: value_counted(); value_counted(value_counted const&); value_counted(value_base const&); value_counted(value_node*); ~value_counted(); }; //////////////////////////////////////////////////////////////////////// // List builder // // Values are immutable, so this class is used to build a list of // value nodes before constructing the value. struct value_list_builder { value_list_builder(value_list_builder const&); value_list_builder& operator=(value_list_builder const&); public: value_list_builder(); value_list_builder(value_node*); ~value_list_builder(); void swap(value_list_builder& b); value_node* release(); void append(value_node*); void sort(); bool empty() const; private: value_node* head_; value_node** back_; }; } //////////////////////////////////////////////////////////////////////////// // Value // // Most of the methods are in value_base. struct value : public detail::value_counted { public: value(); value(value const&); value(detail::value_base const&); explicit value(detail::value_node*); value& operator=(value); void swap(value& x) { detail::value_counted::swap(x); } }; // Empty value empty_value(value::tag_type = value::default_tag); // Integers value int_value(int, value::tag_type = value::default_tag); // String types // Quickbook strings contain a reference to the original quickbook source. value qbk_value( file_ptr const&, string_iterator, string_iterator, value::tag_type = value::default_tag); // Encoded strings are either plain text or boostbook. value encoded_value( std::string const&, value::tag_type = value::default_tag); // An encoded quickbook string is an encoded string that contains a // reference to the quickbook source it was generated from. value encoded_qbk_value( file_ptr const&, string_iterator, string_iterator, std::string const&, value::tag_type = value::default_tag); //////////////////////////////////////////////////////////////////////////// // Value Builder // // Used to incrementally build a valueeter tree. struct value_builder { public: value_builder(); void swap(value_builder& b); void save(); void restore(); value release(); void insert(value const&); void extend(value const&); void start_list(value::tag_type = value::default_tag); void finish_list(); void clear_list(); void sort_list(); bool empty() const; private: detail::value_list_builder current; value::tag_type list_tag; boost::scoped_ptr saved; }; //////////////////////////////////////////////////////////////////////////// // Value Error // struct value_error : public std::logic_error { public: explicit value_error(std::string const&); }; //////////////////////////////////////////////////////////////////////////// // Value Consumer // // Convenience class for unpacking value values. struct value_consumer { public: struct iterator : public boost::input_iterator_helper< iterator, boost::iterator_value::type, boost::iterator_difference::type, boost::iterator_pointer::type, boost::iterator_reference::type> { public: iterator(); explicit iterator(value::iterator* p) : ptr_(p) {} friend bool operator==(iterator x, iterator y) { return *x.ptr_ == *y.ptr_; } iterator& operator++() { ++*ptr_; return *this; } reference operator*() const { return **ptr_; } pointer operator->() const { return ptr_->operator->(); } private: value::iterator* ptr_; }; typedef iterator const_iterator; typedef iterator::reference reference; value_consumer(value const& x) : list_(x), pos_(x.begin()), end_(x.end()) { } value_consumer(reference x) : list_(x), pos_(x.begin()), end_(x.end()) { } reference consume() { assert_check(); return *pos_++; } reference consume(value::tag_type t) { assert_check(t); return *pos_++; } value optional_consume() { if (check()) { return *pos_++; } else { return value(); } } value optional_consume(value::tag_type t) { if (check(t)) { return *pos_++; } else { return value(); } } bool check() const { return pos_ != end_; } bool check(value::tag_type t) const { return pos_ != end_ && t == pos_->get_tag(); } void finish() const { if (pos_ != end_) throw value_error("Not all values handled."); } iterator begin() { return iterator(&pos_); } iterator end() { return iterator(&end_); } private: void assert_check() const { if (pos_ == end_) throw value_error("Attempt to read past end of value list."); } void assert_check(value::tag_type t) const { assert_check(); if (t != pos_->get_tag()) throw value_error("Incorrect value tag."); } value list_; value::iterator pos_, end_; }; } #endif