/*============================================================================= Copyright (c) 2001-2011 Joel de Guzman Copyright (c) 2001-2011 Hartmut Kaiser Copyright (c) 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_DETAIL2) #define BOOST_SPIRIT_UTREE_DETAIL2 #if defined(BOOST_MSVC) # pragma warning(push) # pragma warning(disable: 4800) #endif #include #include #include #include #include namespace boost { namespace spirit { namespace detail { inline char& fast_string::info() { return buff[small_string_size]; } inline char fast_string::info() const { return buff[small_string_size]; } inline int fast_string::get_type() const { return info() >> 1; } inline void fast_string::set_type(int t) { info() = (t << 1) | (info() & 1); } inline short fast_string::tag() const { return (int(buff[small_string_size-2]) << 8) + (unsigned char)buff[small_string_size-1]; } inline void fast_string::tag(short tag) { buff[small_string_size-2] = tag >> 8; buff[small_string_size-1] = tag & 0xff; } inline bool fast_string::is_heap_allocated() const { return info() & 1; } inline std::size_t fast_string::size() const { if (is_heap_allocated()) return heap.size; else return max_string_len - buff[max_string_len]; } inline char const* fast_string::str() const { if (is_heap_allocated()) return heap.str; else return buff; } template inline void fast_string::construct(Iterator f, Iterator l) { unsigned const size = l-f; char* str; if (size < max_string_len) { // if it fits, store it in-situ; small_string_size minus the length // of the string is placed in buff[small_string_size - 1] str = buff; buff[max_string_len] = static_cast(max_string_len - size); info() &= ~0x1; } else { // else, store it in the heap str = new char[size + 1]; // add one for the null char heap.str = str; heap.size = size; info() |= 0x1; } for (std::size_t i = 0; i != size; ++i) { *str++ = *f++; } *str = '\0'; // add the null char } inline void fast_string::swap(fast_string& other) { std::swap(*this, other); } inline void fast_string::free() { if (is_heap_allocated()) { delete [] heap.str; } } inline void fast_string::copy(fast_string const& other) { construct(other.str(), other.str() + other.size()); } inline void fast_string::initialize() { for (std::size_t i = 0; i != buff_size / (sizeof(long)/sizeof(char)); ++i) lbuff[i] = 0; } struct list::node : boost::noncopyable { template node(T const& val, node* next, node* prev) : val(val), next(next), prev(prev) {} void unlink() { prev->next = next; next->prev = prev; } utree val; node* next; node* prev; }; template class list::node_iterator : public boost::iterator_facade< node_iterator , Value , boost::bidirectional_traversal_tag> { public: node_iterator() : node(0), prev(0) {} node_iterator(list::node* node, list::node* prev) : node(node), prev(prev) {} private: friend class boost::iterator_core_access; friend class boost::spirit::utree; friend struct boost::spirit::detail::list; void increment() { if (node != 0) // not at end { prev = node; node = node->next; } } void decrement() { if (prev != 0) // not at begin { node = prev; prev = prev->prev; } } bool equal(node_iterator const& other) const { return node == other.node; } typename node_iterator::reference dereference() const { return node->val; } list::node* node; list::node* prev; }; template class list::node_iterator > : public boost::iterator_facade< node_iterator > , boost::reference_wrapper , boost::bidirectional_traversal_tag> { public: node_iterator() : node(0), prev(0), curr(nil_node) {} node_iterator(list::node* node, list::node* prev) : node(node), prev(prev), curr(node ? node->val : nil_node) {} private: friend class boost::iterator_core_access; friend class boost::spirit::utree; friend struct boost::spirit::detail::list; void increment() { if (node != 0) // not at end { prev = node; node = node->next; curr = boost::ref(node ? node->val : nil_node); } } void decrement() { if (prev != 0) // not at begin { node = prev; prev = prev->prev; curr = boost::ref(node ? node->val : nil_node); } } bool equal(node_iterator const& other) const { return node == other.node; } typename node_iterator::reference dereference() const { return curr; } list::node* node; list::node* prev; static Value nil_node; mutable boost::reference_wrapper curr; }; template Value list::node_iterator >::nil_node = Value(); inline void list::free() { node* p = first; while (p != 0) { node* next = p->next; delete p; p = next; } } inline void list::copy(list const& other) { node* p = other.first; while (p != 0) { push_back(p->val); p = p->next; } } inline void list::default_construct() { first = last = 0; size = 0; } template inline void list::insert(T const& val, Iterator pos) { if (!pos.node) { push_back(val); return; } detail::list::node* new_node = new detail::list::node(val, pos.node, pos.node->prev); if (pos.node->prev) pos.node->prev->next = new_node; else first = new_node; pos.node->prev = new_node; ++size; } template inline void list::push_front(T const& val) { detail::list::node* new_node; if (first == 0) { new_node = new detail::list::node(val, 0, 0); first = last = new_node; ++size; } else { new_node = new detail::list::node(val, first, first->prev); first->prev = new_node; first = new_node; ++size; } } template inline void list::push_back(T const& val) { if (last == 0) push_front(val); else { detail::list::node* new_node = new detail::list::node(val, last->next, last); last->next = new_node; last = new_node; ++size; } } inline void list::pop_front() { BOOST_ASSERT(size != 0); if (first == last) // there's only one item { delete first; size = 0; first = last = 0; } else { node* np = first; first = first->next; first->prev = 0; delete np; --size; } } inline void list::pop_back() { BOOST_ASSERT(size != 0); if (first == last) // there's only one item { delete first; size = 0; first = last = 0; } else { node* np = last; last = last->prev; last->next = 0; delete np; --size; } } inline list::node* list::erase(node* pos) { BOOST_ASSERT(pos != 0); if (pos == first) { pop_front(); return first; } else if (pos == last) { pop_back(); return 0; } else { node* next(pos->next); pos->unlink(); delete pos; --size; return next; } } /////////////////////////////////////////////////////////////////////////// // simple binder for binary visitation (we don't want to bring in the big guns) template struct bind_impl { typedef typename F::result_type result_type; X& x; // always by reference F f; bind_impl(F f, X& x) : x(x), f(f) {} template typename F::result_type operator()(Y& y) const { return f(x, y); } template typename F::result_type operator()(Y const& y) const { return f(x, y); } }; template bind_impl bind(F f, X const& x) { return bind_impl(f, x); } template bind_impl bind(F f, X& x) { return bind_impl(f, x); } template struct visit_impl { template typename F::result_type static apply(UTreeX& x, F f) // single dispatch { typedef typename boost::mpl::if_, typename UTreeX::const_iterator, typename UTreeX::iterator>::type iterator; typedef boost::iterator_range list_range; typedef utree_type type; switch (x.get_type()) { default: BOOST_THROW_EXCEPTION( bad_type_exception("corrupt utree type", x.get_type())); break; case type::invalid_type: return f(invalid); case type::nil_type: return f(nil); case type::bool_type: return f(x.b); case type::int_type: return f(x.i); case type::double_type: return f(x.d); case type::list_type: return f(list_range(iterator(x.l.first, 0), iterator(0, x.l.last))); case type::range_type: return f(list_range(iterator(x.r.first, 0), iterator(0, x.r.last))); case type::string_type: return f(utf8_string_range_type(x.s.str(), x.s.size())); case type::string_range_type: return f(utf8_string_range_type(x.sr.first, x.sr.last)); case type::symbol_type: return f(utf8_symbol_range_type(x.s.str(), x.s.size())); case type::binary_type: return f(binary_range_type(x.s.str(), x.s.size())); case type::reference_type: return apply(*x.p, f); case type::any_type: return f(any_ptr(x.v.p, x.v.i)); case type::function_type: return f(*x.pf); } } template typename F::result_type static apply(UTreeX& x, UTreeY& y, F f) // double dispatch { typedef typename boost::mpl::if_, typename UTreeX::const_iterator, typename UTreeX::iterator>::type iterator; typedef boost::iterator_range list_range; typedef utree_type type; switch (x.get_type()) { default: BOOST_THROW_EXCEPTION( bad_type_exception("corrupt utree type", x.get_type())); break; case type::invalid_type: return visit_impl::apply(y, detail::bind(f, invalid)); case type::nil_type: return visit_impl::apply(y, detail::bind(f, nil)); case type::bool_type: return visit_impl::apply(y, detail::bind(f, x.b)); case type::int_type: return visit_impl::apply(y, detail::bind(f, x.i)); case type::double_type: return visit_impl::apply(y, detail::bind(f, x.d)); case type::list_type: return visit_impl::apply( y, detail::bind(f, list_range(iterator(x.l.first, 0), iterator(0, x.l.last)))); case type::range_type: return visit_impl::apply( y, detail::bind(f, list_range(iterator(x.r.first, 0), iterator(0, x.r.last)))); case type::string_type: return visit_impl::apply(y, detail::bind( f, utf8_string_range_type(x.s.str(), x.s.size()))); case type::string_range_type: return visit_impl::apply(y, detail::bind( f, utf8_string_range_type(x.sr.first, x.sr.last))); case type::symbol_type: return visit_impl::apply(y, detail::bind( f, utf8_symbol_range_type(x.s.str(), x.s.size()))); case type::binary_type: return visit_impl::apply(y, detail::bind( f, binary_range_type(x.s.str(), x.s.size()))); case type::reference_type: return apply(*x.p, y, f); case type::any_type: return visit_impl::apply( y, detail::bind(f, any_ptr(x.v.p, x.v.i))); case type::function_type: return visit_impl::apply(y, detail::bind(f, *x.pf)); } } }; struct index_impl { static utree& apply(utree& ut, std::size_t i) { switch (ut.get_type()) { case utree_type::reference_type: return apply(ut.deref(), i); case utree_type::range_type: return apply(ut.r.first, i); case utree_type::list_type: return apply(ut.l.first, i); default: BOOST_THROW_EXCEPTION( bad_type_exception ("index operation performed on non-list utree type", ut.get_type())); } } static utree const& apply(utree const& ut, std::size_t i) { switch (ut.get_type()) { case utree_type::reference_type: return apply(ut.deref(), i); case utree_type::range_type: return apply(ut.r.first, i); case utree_type::list_type: return apply(ut.l.first, i); default: BOOST_THROW_EXCEPTION( bad_type_exception ("index operation performed on non-list utree type", ut.get_type())); } } static utree& apply(list::node* node, std::size_t i) { for (; i > 0; --i) node = node->next; return node->val; } static utree const& apply(list::node const* node, std::size_t i) { for (; i > 0; --i) node = node->next; return node->val; } }; }}} namespace boost { namespace spirit { template stored_function::stored_function(F f) : f(f) { } template stored_function::~stored_function() { } template utree stored_function::operator()(utree const& env) const { return f(env); } template utree stored_function::operator()(utree& env) const { return f(env); } template function_base* stored_function::clone() const { return new stored_function(f); } template referenced_function::referenced_function(F& f) : f(f) { } template referenced_function::~referenced_function() { } template utree referenced_function::operator()(utree const& env) const { return f(env); } template utree referenced_function::operator()(utree& env) const { return f(env); } template function_base* referenced_function::clone() const { return new referenced_function(f); } inline utree::utree(utree::invalid_type) { s.initialize(); set_type(type::invalid_type); } inline utree::utree(utree::nil_type) { s.initialize(); set_type(type::nil_type); } inline utree::utree(bool b_) { s.initialize(); b = b_; set_type(type::bool_type); } inline utree::utree(char c) { s.initialize(); // char constructs a single element string s.construct(&c, &c+1); set_type(type::string_type); } inline utree::utree(unsigned int i_) { s.initialize(); i = i_; set_type(type::int_type); } inline utree::utree(int i_) { s.initialize(); i = i_; set_type(type::int_type); } inline utree::utree(double d_) { s.initialize(); d = d_; set_type(type::double_type); } inline utree::utree(char const* str) { s.initialize(); s.construct(str, str + strlen(str)); set_type(type::string_type); } inline utree::utree(char const* str, std::size_t len) { s.initialize(); s.construct(str, str + len); set_type(type::string_type); } inline utree::utree(std::string const& str) { s.initialize(); s.construct(str.begin(), str.end()); set_type(type::string_type); } template inline utree::utree(basic_string const& bin) { s.initialize(); s.construct(bin.begin(), bin.end()); set_type(type_); } inline utree::utree(boost::reference_wrapper ref) { s.initialize(); p = ref.get_pointer(); set_type(type::reference_type); } inline utree::utree(any_ptr const& p) { s.initialize(); v.p = p.p; v.i = p.i; set_type(type::any_type); } inline utree::utree(function_base const& pf_) { s.initialize(); pf = pf_.clone(); set_type(type::function_type); } inline utree::utree(function_base* pf_) { s.initialize(); pf = pf_; set_type(type::function_type); } template inline utree::utree(boost::iterator_range r) { s.initialize(); assign(r.begin(), r.end()); } inline utree::utree(range r, shallow_tag) { s.initialize(); this->r.first = r.begin().node; this->r.last = r.end().prev; set_type(type::range_type); } inline utree::utree(const_range r, shallow_tag) { s.initialize(); this->r.first = r.begin().node; this->r.last = r.end().prev; set_type(type::range_type); } inline utree::utree(utf8_string_range_type const& str, shallow_tag) { s.initialize(); this->sr.first = str.begin(); this->sr.last = str.end(); set_type(type::string_range_type); } inline utree::utree(utree const& other) { s.initialize(); copy(other); } inline utree::~utree() { free(); } inline utree& utree::operator=(utree const& other) { if (this != &other) { free(); copy(other); } return *this; } inline utree& utree::operator=(nil_type) { free(); set_type(type::nil_type); return *this; } inline utree& utree::operator=(bool b_) { free(); b = b_; set_type(type::bool_type); return *this; } inline utree& utree::operator=(char c) { // char constructs a single element string free(); s.construct(&c, &c+1); set_type(type::string_type); return *this; } inline utree& utree::operator=(unsigned int i_) { free(); i = i_; set_type(type::int_type); return *this; } inline utree& utree::operator=(int i_) { free(); i = i_; set_type(type::int_type); return *this; } inline utree& utree::operator=(double d_) { free(); d = d_; set_type(type::double_type); return *this; } inline utree& utree::operator=(char const* s_) { free(); s.construct(s_, s_ + strlen(s_)); set_type(type::string_type); return *this; } inline utree& utree::operator=(std::string const& s_) { free(); s.construct(s_.begin(), s_.end()); set_type(type::string_type); return *this; } template inline utree& utree::operator=(basic_string const& bin) { free(); s.construct(bin.begin(), bin.end()); set_type(type_); return *this; } inline utree& utree::operator=(boost::reference_wrapper ref) { free(); p = ref.get_pointer(); set_type(type::reference_type); return *this; } inline utree& utree::operator=(any_ptr const& p) { free(); v.p = p.p; v.i = p.i; set_type(type::any_type); return *this; } inline utree& utree::operator=(function_base const& pf_) { free(); pf = pf_.clone(); set_type(type::function_type); return *this; } inline utree& utree::operator=(function_base* pf_) { free(); pf = pf_; set_type(type::function_type); return *this; } template inline utree& utree::operator=(boost::iterator_range r) { free(); assign(r.begin(), r.end()); return *this; } template typename boost::result_of::type inline utree::visit(utree const& x, F f) { return detail::visit_impl::apply(x, f); } template typename boost::result_of::type inline utree::visit(utree& x, F f) { return detail::visit_impl::apply(x, f); } template typename boost::result_of::type inline utree::visit(utree const& x, utree const& y, F f) { return detail::visit_impl::apply(x, y, f); } template typename boost::result_of::type inline utree::visit(utree const& x, utree& y, F f) { return detail::visit_impl::apply(x, y, f); } template typename boost::result_of::type inline utree::visit(utree& x, utree const& y, F f) { return detail::visit_impl::apply(x, y, f); } template typename boost::result_of::type inline utree::visit(utree& x, utree& y, F f) { return detail::visit_impl::apply(x, y, f); } inline utree::reference get(utree::reference ut, utree::size_type i) { return detail::index_impl::apply(ut, i); } inline utree::const_reference get(utree::const_reference ut, utree::size_type i) { return detail::index_impl::apply(ut, i); } template inline void utree::push_front(T const& val) { if (get_type() == type::reference_type) return p->push_front(val); ensure_list_type("push_front()"); l.push_front(val); } template inline void utree::push_back(T const& val) { if (get_type() == type::reference_type) return p->push_back(val); ensure_list_type("push_back()"); l.push_back(val); } template inline utree::iterator utree::insert(iterator pos, T const& val) { if (get_type() == type::reference_type) return p->insert(pos, val); ensure_list_type("insert()"); if (!pos.node) { l.push_back(val); return utree::iterator(l.first, 0); // begin(); } l.insert(val, pos); return utree::iterator(pos.node->prev, pos.node->prev->prev); } template inline void utree::insert(iterator pos, std::size_t n, T const& val) { if (get_type() == type::reference_type) return p->insert(pos, n, val); ensure_list_type("insert()"); for (std::size_t i = 0; i != n; ++i) insert(pos, val); } template inline void utree::insert(iterator pos, Iterator first, Iterator last) { if (get_type() == type::reference_type) return p->insert(pos, first, last); ensure_list_type("insert()"); while (first != last) insert(pos, *first++); } template inline void utree::assign(Iterator first, Iterator last) { if (get_type() == type::reference_type) return p->assign(first, last); clear(); set_type(type::list_type); while (first != last) { push_back(*first); ++first; } } inline void utree::clear() { if (get_type() == type::reference_type) return p->clear(); // clear will always make this an invalid type free(); set_type(type::invalid_type); } inline void utree::pop_front() { if (get_type() == type::reference_type) return p->pop_front(); if (get_type() != type::list_type) BOOST_THROW_EXCEPTION( bad_type_exception ("pop_front() called on non-list utree type", get_type())); l.pop_front(); } inline void utree::pop_back() { if (get_type() == type::reference_type) return p->pop_back(); if (get_type() != type::list_type) BOOST_THROW_EXCEPTION( bad_type_exception ("pop_back() called on non-list utree type", get_type())); l.pop_back(); } inline utree::iterator utree::erase(iterator pos) { if (get_type() == type::reference_type) return p->erase(pos); if (get_type() != type::list_type) BOOST_THROW_EXCEPTION( bad_type_exception ("erase() called on non-list utree type", get_type())); detail::list::node* np = l.erase(pos.node); return iterator(np, np?np->prev:l.last); } inline utree::iterator utree::erase(iterator first, iterator last) { if (get_type() == type::reference_type) return p->erase(first, last); if (get_type() != type::list_type) BOOST_THROW_EXCEPTION( bad_type_exception ("erase() called on non-list utree type", get_type())); while (first != last) erase(first++); return last; } inline utree::iterator utree::begin() { if (get_type() == type::reference_type) return p->begin(); else if (get_type() == type::range_type) return iterator(r.first, 0); // otherwise... ensure_list_type("begin()"); return iterator(l.first, 0); } inline utree::iterator utree::end() { if (get_type() == type::reference_type) return p->end(); else if (get_type() == type::range_type) return iterator(0, r.first); // otherwise... ensure_list_type("end()"); return iterator(0, l.last); } inline utree::ref_iterator utree::ref_begin() { if (get_type() == type::reference_type) return p->ref_begin(); else if (get_type() == type::range_type) return ref_iterator(r.first, 0); // otherwise... ensure_list_type("ref_begin()"); return ref_iterator(l.first, 0); } inline utree::ref_iterator utree::ref_end() { if (get_type() == type::reference_type) return p->ref_end(); else if (get_type() == type::range_type) return ref_iterator(0, r.first); // otherwise... ensure_list_type("ref_end()"); return ref_iterator(0, l.last); } inline utree::const_iterator utree::begin() const { if (get_type() == type::reference_type) return ((utree const*)p)->begin(); if (get_type() == type::range_type) return const_iterator(r.first, 0); // otherwise... if (get_type() != type::list_type) BOOST_THROW_EXCEPTION( bad_type_exception ("begin() called on non-list utree type", get_type())); return const_iterator(l.first, 0); } inline utree::const_iterator utree::end() const { if (get_type() == type::reference_type) return ((utree const*)p)->end(); if (get_type() == type::range_type) return const_iterator(0, r.first); // otherwise... if (get_type() != type::list_type) BOOST_THROW_EXCEPTION( bad_type_exception ("end() called on non-list utree type", get_type())); return const_iterator(0, l.last); } inline bool utree::empty() const { type::info t = get_type(); if (t == type::reference_type) return ((utree const*)p)->empty(); if (t == type::range_type) return r.first == 0; if (t == type::list_type) return l.size == 0; return t == type::nil_type || t == type::invalid_type; } inline std::size_t utree::size() const { type::info t = get_type(); if (t == type::reference_type) return ((utree const*)p)->size(); if (t == type::range_type) { // FIXME: O(n), and we have the room to store the size of a range // in the union if we compute it when assigned/constructed. std::size_t size = 0; detail::list::node* n = r.first; while (n) { n = n->next; ++size; } return size; } if (t == type::list_type) return l.size; if (t == type::string_type) return s.size(); if (t == type::symbol_type) return s.size(); if (t == type::binary_type) return s.size(); if (t == type::string_range_type) return sr.last - sr.first; if (t != type::nil_type) BOOST_THROW_EXCEPTION( bad_type_exception ("size() called on non-list and non-string utree type", get_type())); return 0; } inline utree_type::info utree::which() const { return get_type(); } inline utree& utree::front() { if (get_type() == type::reference_type) return p->front(); if (get_type() == type::range_type) { if (!r.first) BOOST_THROW_EXCEPTION( empty_exception("front() called on empty utree range")); return r.first->val; } // otherwise... if (get_type() != type::list_type) BOOST_THROW_EXCEPTION( bad_type_exception ("front() called on non-list utree type", get_type())); else if (!l.first) BOOST_THROW_EXCEPTION( empty_exception("front() called on empty utree list")); return l.first->val; } inline utree& utree::back() { if (get_type() == type::reference_type) return p->back(); if (get_type() == type::range_type) { if (!r.last) BOOST_THROW_EXCEPTION( empty_exception("back() called on empty utree range")); return r.last->val; } // otherwise... if (get_type() != type::list_type) BOOST_THROW_EXCEPTION( bad_type_exception ("back() called on non-list utree type", get_type())); else if (!l.last) BOOST_THROW_EXCEPTION( empty_exception("back() called on empty utree list")); return l.last->val; } inline utree const& utree::front() const { if (get_type() == type::reference_type) return ((utree const*)p)->front(); if (get_type() == type::range_type) { if (!r.first) BOOST_THROW_EXCEPTION( empty_exception("front() called on empty utree range")); return r.first->val; } // otherwise... if (get_type() != type::list_type) BOOST_THROW_EXCEPTION( bad_type_exception ("front() called on non-list utree type", get_type())); else if (!l.first) BOOST_THROW_EXCEPTION( empty_exception("front() called on empty utree list")); return l.first->val; } inline utree const& utree::back() const { if (get_type() == type::reference_type) return ((utree const*)p)->back(); if (get_type() == type::range_type) { if (!r.last) BOOST_THROW_EXCEPTION( empty_exception("back() called on empty utree range")); return r.last->val; } // otherwise... if (get_type() != type::list_type) BOOST_THROW_EXCEPTION( bad_type_exception ("back() called on non-list utree type", get_type())); else if (!l.last) BOOST_THROW_EXCEPTION( empty_exception("back() called on empty utree list")); return l.last->val; } inline void utree::swap(utree& other) { s.swap(other.s); } inline utree::type::info utree::get_type() const { // the fast string holds the type info return static_cast(s.get_type()); } inline void utree::set_type(type::info t) { // the fast string holds the type info s.set_type(t); } inline void utree::ensure_list_type(char const* failed_in) { type::info t = get_type(); if (t == type::invalid_type) { set_type(type::list_type); l.default_construct(); } else if (get_type() != type::list_type) { std::string msg = failed_in; msg += "called on non-list and non-invalid utree type"; BOOST_THROW_EXCEPTION(bad_type_exception(msg.c_str(), get_type())); } } inline void utree::free() { switch (get_type()) { case type::binary_type: case type::symbol_type: case type::string_type: s.free(); break; case type::list_type: l.free(); break; case type::function_type: delete pf; break; default: break; }; s.initialize(); } inline void utree::copy(utree const& other) { set_type(other.get_type()); switch (other.get_type()) { default: BOOST_THROW_EXCEPTION( bad_type_exception("corrupt utree type", other.get_type())); break; case type::invalid_type: case type::nil_type: s.tag(other.s.tag()); break; case type::bool_type: b = other.b; s.tag(other.s.tag()); break; case type::int_type: i = other.i; s.tag(other.s.tag()); break; case type::double_type: d = other.d; s.tag(other.s.tag()); break; case type::reference_type: p = other.p; s.tag(other.s.tag()); break; case type::any_type: v = other.v; s.tag(other.s.tag()); break; case type::range_type: r = other.r; s.tag(other.s.tag()); break; case type::string_range_type: sr = other.sr; s.tag(other.s.tag()); break; case type::function_type: pf = other.pf->clone(); s.tag(other.s.tag()); break; case type::string_type: case type::symbol_type: case type::binary_type: s.copy(other.s); s.tag(other.s.tag()); break; case type::list_type: l.copy(other.l); s.tag(other.s.tag()); break; } } template struct is_iterator_range : boost::mpl::false_ {}; template struct is_iterator_range > : boost::mpl::true_ {}; template struct utree_cast { typedef To result_type; template To dispatch(From const& val, boost::mpl::true_) const { return To(val); // From is convertible to To } template To dispatch(From const&, boost::mpl::false_) const { // From is NOT convertible to To !!! throw std::bad_cast(); return To(); } template To operator()(From const& val) const { // boost::iterator_range has a templated constructor, accepting // any argument and hence any type is 'convertible' to it. typedef typename boost::mpl::eval_if< is_iterator_range , boost::is_same, boost::is_convertible >::type is_convertible; return dispatch(val, is_convertible()); } }; template struct utree_cast { typedef T* result_type; template T* operator()(From const&) const { // From is NOT convertible to T !!! throw std::bad_cast(); return 0; } T* operator()(any_ptr const& p) const { return p.get(); } }; template inline T utree::get() const { return utree::visit(*this, utree_cast()); } inline utree& utree::deref() { return (get_type() == type::reference_type) ? *p : *this; } inline utree const& utree::deref() const { return (get_type() == type::reference_type) ? *p : *this; } inline short utree::tag() const { return s.tag(); } inline void utree::tag(short tag) { s.tag(tag); } inline utree utree::eval(utree const& env) const { if (get_type() == type::reference_type) return deref().eval(env); if (get_type() != type::function_type) BOOST_THROW_EXCEPTION( bad_type_exception( "eval() called on non-function utree type", get_type())); return (*pf)(env); } inline utree utree::eval(utree& env) const { if (get_type() == type::reference_type) return deref().eval(env); if (get_type() != type::function_type) BOOST_THROW_EXCEPTION( bad_type_exception( "eval() called on non-function utree type", get_type())); return (*pf)(env); } inline utree utree::operator() (utree const& env) const { return eval(env); } inline utree utree::operator() (utree& env) const { return eval(env); } }} #if defined(BOOST_MSVC) # pragma warning(pop) #endif #endif