| /*============================================================================= |
| Copyright (c) 2001-2011 Joel de Guzman |
| Copyright (c) 2001-2011 Hartmut Kaiser |
| Copyright (c) 2010-2011 Bryce Lelbach |
| |
| Distributed under 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) |
| =============================================================================*/ |
| #if !defined(BOOST_SPIRIT_UTREE) |
| #define BOOST_SPIRIT_UTREE |
| |
| #include <cstddef> |
| #include <algorithm> |
| #include <string> |
| #include <iostream> |
| #include <ios> |
| #include <sstream> |
| #include <typeinfo> |
| |
| #include <boost/io/ios_state.hpp> |
| #include <boost/integer.hpp> |
| #include <boost/throw_exception.hpp> |
| #include <boost/assert.hpp> |
| #include <boost/noncopyable.hpp> |
| #include <boost/iterator/iterator_facade.hpp> |
| #include <boost/range/iterator_range.hpp> |
| #include <boost/type_traits/remove_pointer.hpp> |
| #include <boost/type_traits/is_polymorphic.hpp> |
| #include <boost/utility/enable_if.hpp> |
| #include <boost/utility/result_of.hpp> |
| #include <boost/ref.hpp> |
| |
| #include <boost/spirit/home/support/utree/detail/utree_detail1.hpp> |
| |
| #if defined(BOOST_MSVC) |
| # pragma warning(push) |
| # pragma warning(disable: 4804) |
| # pragma warning(disable: 4805) |
| # pragma warning(disable: 4244) |
| #endif |
| |
| namespace boost { namespace spirit |
| { |
| //[utree_exceptions |
| /*` All exceptions thrown by utree are derived from utree_exception. */ |
| struct utree_exception : std::exception {}; |
| |
| /*`The `bad_type_exception` is thrown whenever somebody calls a member |
| function, which applies to certain stored utree_type's only, but this |
| precondition is violated as the `utree` instance holds some other type. |
| */ |
| struct bad_type_exception /*: utree_exception*/; |
| |
| /*`The `empty_exception` is thrown whenever a precondition of a list |
| or range utree method is violated due to the list or range being empty. |
| */ |
| struct empty_exception /*: utree_exception*/; |
| //] |
| |
| //[utree_types |
| /*`Each instance of an `utree` data structure can store exactly one of the |
| following data types at a time: |
| */ |
| struct utree_type |
| { |
| enum info |
| { |
| invalid_type, // the utree has not been initialized (it's |
| // default constructed) |
| nil_type, // nil is the sentinel (empty) utree type. |
| list_type, // A doubly linked list of utrees. |
| range_type, // A range of list::iterators. |
| reference_type, // A reference to another utree. |
| any_type, // A pointer or reference to any C++ type. |
| function_type, // A utree holding a stored_function<F> object, |
| // where F is an unary function object taking a |
| // utree as it's parameter and returning a |
| // utree. |
| |
| // numeric atoms |
| bool_type, // An utree holding a boolean value |
| int_type, // An utree holding a integer (int) value |
| double_type, // An utree holding a floating point (double) value |
| |
| // text atoms (utf8) |
| string_type, // An UTF-8 string |
| string_range_type, // A pair of iterators into an UTF-8 string |
| symbol_type, // An UTF-8 symbol name |
| |
| binary_type // Arbitrary binary data |
| }; |
| typedef boost::uint_t<sizeof(info)*8>::exact exact_integral_type; |
| typedef boost::uint_t<sizeof(info)*8>::fast fast_integral_type; |
| }; |
| //] |
| |
| // streaming operator for utree types - essential for diagnostics |
| inline std::ostream& operator<<(std::ostream& out, utree_type::info t) |
| { |
| boost::io::ios_all_saver saver(out); |
| switch (t) { |
| case utree_type::invalid_type: { out << "invalid"; break; } |
| case utree_type::nil_type: { out << "nil"; break; } |
| case utree_type::list_type: { out << "list"; break; } |
| case utree_type::range_type: { out << "range"; break; } |
| case utree_type::reference_type: { out << "reference"; break; } |
| case utree_type::any_type: { out << "any"; break; } |
| case utree_type::function_type: { out << "function"; break; } |
| case utree_type::bool_type: { out << "bool"; break; } |
| case utree_type::int_type: { out << "int"; break; } |
| case utree_type::double_type: { out << "double"; break; } |
| case utree_type::string_type: { out << "string"; break; } |
| case utree_type::string_range_type: { out << "string_range"; break; } |
| case utree_type::symbol_type: { out << "symbol"; break; } |
| case utree_type::binary_type: { out << "binary"; break; } |
| default: { out << "unknown"; break; } |
| } |
| out << std::hex << "[0x" |
| << static_cast<utree_type::fast_integral_type>(t) << "]"; |
| return out; |
| } |
| |
| struct bad_type_exception : utree_exception |
| { |
| std::string msg; |
| |
| bad_type_exception(char const* error, utree_type::info got) |
| : msg() |
| { |
| std::ostringstream oss; |
| oss << "utree: " << error |
| << " (got utree type '" << got << "')"; |
| msg = oss.str(); |
| } |
| |
| bad_type_exception(char const* error, utree_type::info got1, |
| utree_type::info got2) |
| : msg() |
| { |
| std::ostringstream oss; |
| oss << "utree: " << error |
| << " (got utree types '" << got1 << "' and '" << got2 << "')"; |
| msg = oss.str(); |
| } |
| |
| virtual ~bad_type_exception() throw() {} |
| |
| virtual char const* what() const throw() |
| { return msg.c_str(); } |
| }; |
| |
| struct empty_exception : utree_exception |
| { |
| char const* msg; |
| |
| empty_exception(char const* error) : msg(error) {} |
| |
| virtual ~empty_exception() throw() {} |
| |
| virtual char const* what() const throw() |
| { return msg; } |
| }; |
| |
| /////////////////////////////////////////////////////////////////////////// |
| // A typed string with parametric Base storage. The storage can be any |
| // range or (stl container) of chars. |
| /////////////////////////////////////////////////////////////////////////// |
| template <typename Base, utree_type::info type_> |
| struct basic_string : Base |
| { |
| static utree_type::info const type = type_; |
| |
| basic_string() |
| : Base() {} |
| |
| basic_string(Base const& base) |
| : Base(base) {} |
| |
| template <typename Iterator> |
| basic_string(Iterator bits, std::size_t len) |
| : Base(bits, bits + len) {} |
| |
| template <typename Iterator> |
| basic_string(Iterator first, Iterator last) |
| : Base(first, last) {} |
| |
| basic_string& operator=(basic_string const& other) |
| { |
| Base::operator=(other); |
| return *this; |
| } |
| |
| basic_string& operator=(Base const& other) |
| { |
| Base::operator=(other); |
| return *this; |
| } |
| }; |
| |
| //[utree_strings |
| /*`The `utree` string types described below are used by the `utree` API |
| only. These are not used to store information in the `utree` itself. |
| Their purpose is to refer to different internal `utree` node types |
| only. For instance, creating a `utree` from a binary data type will |
| create a `binary_type` utree node (see above). |
| */ |
| /*`The binary data type can be represented either verbatim as a sequence |
| of bytes or as a pair of iterators into some other stored binary data |
| sequence. Use this string type to access/create a `binary_type` `utree`. |
| */ |
| typedef basic_string< |
| boost::iterator_range<char const*>, utree_type::binary_type |
| > binary_range_type; |
| typedef basic_string< |
| std::string, utree_type::binary_type |
| > binary_string_type; |
| |
| /*`The UTF-8 string can be represented either verbatim as a sequence of |
| characters or as a pair of iterators into some other stored binary data |
| sequence. Use this string type to access/create a `string_type` `utree`. |
| */ |
| typedef basic_string< |
| boost::iterator_range<char const*>, utree_type::string_type |
| > utf8_string_range_type; |
| typedef basic_string< |
| std::string, utree_type::string_type |
| > utf8_string_type; |
| |
| /*`The UTF-8 symbol can be represented either verbatim as a sequence of |
| characters or as a pair of iterators into some other stored binary data |
| sequence. Use this string type to access/create a `symbol_type` `utree`. |
| */ |
| typedef basic_string< |
| boost::iterator_range<char const*>, utree_type::symbol_type |
| > utf8_symbol_range_type; |
| typedef basic_string< |
| std::string, utree_type::symbol_type |
| > utf8_symbol_type; |
| //] |
| |
| /////////////////////////////////////////////////////////////////////////// |
| // Our function type |
| /////////////////////////////////////////////////////////////////////////// |
| class utree; |
| |
| //[utree_function_object_interface |
| struct function_base |
| { |
| virtual ~function_base() {} |
| virtual utree operator()(utree const& env) const = 0; |
| virtual utree operator()(utree& env) const = 0; |
| |
| // Calling f.clone() must return a newly allocated function_base |
| // instance that is equal to f. |
| virtual function_base* clone() const = 0; |
| }; |
| |
| template <typename F> |
| struct stored_function : function_base |
| { |
| F f; |
| stored_function(F f = F()); |
| virtual ~stored_function(); |
| virtual utree operator()(utree const& env) const; |
| virtual utree operator()(utree& env) const; |
| virtual function_base* clone() const; |
| }; |
| |
| template <typename F> |
| struct referenced_function : function_base |
| { |
| F& f; |
| referenced_function(F& f); |
| virtual ~referenced_function(); |
| virtual utree operator()(utree const& env) const; |
| virtual utree operator()(utree& env) const; |
| virtual function_base* clone() const; |
| }; |
| //] |
| |
| /////////////////////////////////////////////////////////////////////////// |
| // Shallow tag. Instructs utree to hold an iterator_range |
| // as-is without deep copying the range. |
| /////////////////////////////////////////////////////////////////////////// |
| struct shallow_tag {}; |
| shallow_tag const shallow = {}; |
| |
| /////////////////////////////////////////////////////////////////////////// |
| // A void* plus type_info |
| /////////////////////////////////////////////////////////////////////////// |
| class any_ptr |
| { |
| public: |
| template <typename Ptr> |
| typename boost::disable_if< |
| boost::is_polymorphic< |
| typename boost::remove_pointer<Ptr>::type>, |
| Ptr>::type |
| get() const |
| { |
| if (*i == typeid(Ptr)) |
| { |
| return static_cast<Ptr>(p); |
| } |
| boost::throw_exception(std::bad_cast()); |
| } |
| |
| template <typename T> |
| any_ptr(T* p) |
| : p(p), i(&typeid(T*)) |
| {} |
| |
| friend bool operator==(any_ptr const& a, any_ptr const& b) |
| { |
| return (a.p == b.p) && (*a.i == *b.i); |
| } |
| |
| private: |
| // constructor is private |
| any_ptr(void* p, std::type_info const* i) |
| : p(p), i(i) {} |
| |
| template <typename UTreeX, typename UTreeY> |
| friend struct detail::visit_impl; |
| |
| friend class utree; |
| |
| void* p; |
| std::type_info const* i; |
| }; |
| |
| //[utree |
| class utree { |
| public: |
| /////////////////////////////////////////////////////////////////////// |
| // The invalid type |
| struct invalid_type {}; |
| |
| /////////////////////////////////////////////////////////////////////// |
| // The nil type |
| struct nil_type {}; |
| |
| /////////////////////////////////////////////////////////////////////// |
| // The list type, this can be used to initialize an utree to hold an |
| // empty list |
| struct list_type; |
| |
| //[utree_container_types |
| typedef utree value_type; |
| typedef utree& reference; |
| typedef utree const& const_reference; |
| typedef std::ptrdiff_t difference_type; |
| typedef std::size_t size_type; |
| |
| typedef detail::list::node_iterator<utree> iterator; |
| typedef detail::list::node_iterator<utree const> const_iterator; |
| //] |
| |
| typedef detail::list::node_iterator<boost::reference_wrapper<utree> > |
| ref_iterator; |
| |
| typedef boost::iterator_range<iterator> range; |
| typedef boost::iterator_range<const_iterator> const_range; |
| |
| // dtor |
| ~utree(); |
| |
| //////////////////////////////////////////////////////////////////////// |
| //[utree_initialization |
| /*`A `utree` can be constructed or initialized from a wide range of |
| data types, allowing to create `utree` instances for every |
| possible node type (see the description of `utree_type::info` above). |
| For this reason it exposes a constructor and an assignment operator |
| for each of the allowed node types as shown below. All constructors |
| are non-explicit on purpose, allowing to use an utree instance as |
| the attribute to almost any Qi parser. |
| */ |
| // This constructs an `invalid_type` node. When used in places |
| // where a boost::optional is expected (i.e. as an attribute for the |
| // optional component), this represents the 'empty' state. |
| utree(invalid_type = invalid_type()); |
| |
| // This initializes a `nil_type` node, which represents a valid, |
| // 'initialized empty' utree (different from invalid_type!). |
| utree(nil_type); |
| reference operator=(nil_type); |
| |
| // This initializes a `boolean_type` node, which can hold 'true' or |
| // 'false' only. |
| explicit utree(bool); |
| reference operator=(bool); |
| |
| // This initializes an `integer_type` node, which can hold arbitrary |
| // integers. For convenience these functions are overloaded for signed |
| // and unsigned integer types. |
| utree(unsigned int); |
| utree(int); |
| reference operator=(unsigned int); |
| reference operator=(int); |
| |
| // This initializes a `double_type` node, which can hold arbitrary |
| // floating point (double) values. |
| utree(double); |
| reference operator=(double); |
| |
| // This initializes a `string_type` node, which can hold a narrow |
| // character sequence (usually an UTF-8 string). |
| utree(char); |
| utree(char const*); |
| utree(char const*, std::size_t); |
| utree(std::string const&); |
| reference operator=(char); |
| reference operator=(char const*); |
| reference operator=(std::string const&); |
| |
| // This constructs a `string_range_type` node, which does not copy the |
| // data but stores the iterator range to the character sequence the |
| // range has been initialized from. |
| utree(utf8_string_range_type const&, shallow_tag); |
| |
| // This initializes a `reference_type` node, which holds a reference to |
| // another utree node. All operations on such a node are automatically |
| // forwarded to the referenced utree instance. |
| utree(boost::reference_wrapper<utree>); |
| reference operator=(boost::reference_wrapper<utree>); |
| |
| // This initializes an `any_type` node, which can hold a pointer to an |
| // instance of any type together with the typeid of that type. When |
| // accessing that pointer the typeid will be checked, causing a |
| // std::bad_cast to be thrown if the typeids do not match. |
| utree(any_ptr const&); |
| reference operator=(any_ptr const&); |
| |
| // This initializes a `range_type` node, which holds an utree list node |
| // the elements of which are copy constructed (assigned) from the |
| // elements referenced by the given range of iterators. |
| template <class Iterator> |
| utree(boost::iterator_range<Iterator>); |
| template <class Iterator> |
| reference operator=(boost::iterator_range<Iterator>); |
| |
| // This initializes a `function_type` node from a polymorphic function |
| // object pointer (takes ownership) or reference. |
| utree(function_base const&); |
| reference operator=(function_base const&); |
| utree(function_base*); |
| reference operator=(function_base*); |
| |
| // This initializes either a `string_type`, a `symbol_type`, or a |
| // `binary_type` node (depending on the template parameter `type_`), |
| // which will hold the corresponding narrow character sequence (usually |
| // an UTF-8 string). |
| template <class Base, utree_type::info type_> |
| utree(basic_string<Base, type_> const&); |
| template <class Base, utree_type::info type_> |
| reference operator=(basic_string<Base, type_> const&); |
| //] |
| |
| // copy |
| utree(const_reference); |
| reference operator=(const_reference); |
| |
| // range |
| utree(range, shallow_tag); |
| utree(const_range, shallow_tag); |
| |
| // assign dispatch |
| template <class Iterator> |
| void assign(Iterator, Iterator); |
| |
| //////////////////////////////////////////////////////////////////////// |
| |
| //////////////////////////////////////////////////////////////////////// |
| // function object visitation interface |
| |
| // single dispatch |
| template <class F> |
| typename boost::result_of<F(utree const&)>::type |
| static visit(utree const&, F); |
| |
| template <class F> |
| typename boost::result_of<F(utree&)>::type |
| static visit(utree&, F); |
| |
| // double dispatch |
| template <class F> |
| typename boost::result_of<F(utree const&, utree const&)>::type |
| static visit(utree const&, utree const&, F); |
| |
| template <class F> |
| typename boost::result_of<F(utree&, utree const&)>::type |
| static visit(utree&, utree const&, F); |
| |
| template <class F> |
| typename boost::result_of<F(utree const&, utree&)>::type |
| static visit(utree const&, utree&, F); |
| |
| template <class F> |
| typename boost::result_of<F(utree&, utree&)>::type |
| static visit(utree&, utree&, F); |
| |
| //////////////////////////////////////////////////////////////////////// |
| |
| /////////////////////////////////////////////////////////////////////// |
| //[utree_container_functions |
| // STL Container interface |
| |
| // insertion |
| template <class T> |
| void push_back(T const&); |
| template <class T> |
| void push_front(T const&); |
| template <class T> |
| iterator insert(iterator, T const&); |
| template <class T> |
| void insert(iterator, std::size_t, T const&); |
| template <class Iterator> |
| void insert(iterator, Iterator, Iterator); |
| |
| // erasure |
| void pop_front(); |
| void pop_back(); |
| iterator erase(iterator); |
| iterator erase(iterator, iterator); |
| |
| // front access |
| reference front(); |
| const_reference front() const; |
| iterator begin(); |
| const_iterator begin() const; |
| ref_iterator ref_begin(); |
| |
| // back access |
| reference back(); |
| const_reference back() const; |
| iterator end(); |
| const_iterator end() const; |
| ref_iterator ref_end(); |
| //] |
| |
| // This clears the utree instance and resets its type to `invalid_type` |
| void clear(); |
| |
| void swap(utree&); |
| |
| bool empty() const; |
| |
| size_type size() const; |
| /*`[warning `size()` has O(n) complexity on `utree` ranges. On utree |
| lists, it has O(1) complexity.]`*/ |
| |
| //////////////////////////////////////////////////////////////////////// |
| |
| //[utree_variant_functions |
| // return the data type (`utree_type::info`) of the currently stored |
| // data item |
| utree_type::info which() const; |
| |
| // access the currently stored data in a type safe manner, this will |
| // throw a `std::bad_cast()` if the currently stored data item is not |
| // default convertible to `T`. |
| template <class T> |
| T get() const; |
| //] |
| |
| reference deref(); |
| const_reference deref() const; |
| |
| short tag() const; |
| void tag(short); |
| |
| utree eval(utree const&) const; |
| utree eval(utree&) const; |
| |
| utree operator() (utree const&) const; |
| utree operator() (utree&) const; |
| //<- |
| protected: |
| void ensure_list_type(char const* failed_in = "ensure_list_type()"); |
| |
| private: |
| typedef utree_type type; |
| |
| template <class UTreeX, class UTreeY> |
| friend struct detail::visit_impl; |
| friend struct detail::index_impl; |
| |
| type::info get_type() const; |
| void set_type(type::info); |
| void free(); |
| void copy(const_reference); |
| |
| union { |
| detail::fast_string s; |
| detail::list l; |
| detail::range r; |
| detail::string_range sr; |
| detail::void_ptr v; |
| bool b; |
| int i; |
| double d; |
| utree* p; |
| function_base* pf; |
| }; |
| //-> |
| }; |
| //] |
| |
| //[utree_tuple_interface |
| /*<-*/inline/*->*/ |
| utree::reference get(utree::reference, utree::size_type); |
| /*<-*/inline/*->*/ |
| utree::const_reference get(utree::const_reference, utree::size_type); |
| /*`[warning `get()` has O(n) complexity.]`*/ |
| //] |
| |
| struct utree::list_type : utree |
| { |
| using utree::operator=; |
| |
| list_type() : utree() { ensure_list_type("list_type()"); } |
| |
| template <typename T0> |
| list_type(T0 t0) : utree(t0) {} |
| |
| template <typename T0, typename T1> |
| list_type(T0 t0, T1 t1) : utree(t0, t1) {} |
| }; |
| |
| /////////////////////////////////////////////////////////////////////////// |
| // predefined instances for singular types |
| utree::invalid_type const invalid = {}; |
| utree::nil_type const nil = {}; |
| utree::list_type const empty_list = utree::list_type(); |
| }} |
| |
| #if defined(BOOST_MSVC) |
| #pragma warning(pop) |
| #endif |
| |
| #endif |
| |