blob: e681c8a75f0de41b77a9d4d20583aa7c21a0ce36 [file] [log] [blame]
/*=============================================================================
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 <utility>
#include <string>
#include <cassert>
#include <boost/scoped_ptr.hpp>
#include <boost/iterator/iterator_traits.hpp>
#include <boost/utility/string_ref.hpp>
#include <stdexcept>
#include "fwd.hpp"
#include "files.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 boost::string_ref 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
int get_tag() const { return value_->tag_; }
file_ptr get_file() const
{ return value_->get_file(); }
string_iterator get_position() const
{ return value_->get_position(); }
boost::string_ref 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<value_builder> 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<value::iterator>::type,
boost::iterator_difference<value::iterator>::type,
boost::iterator_pointer<value::iterator>::type,
boost::iterator_reference<value::iterator>::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