// Copyright (c) 2001-2011 Hartmut Kaiser // // 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_KARMA_SYMBOLS_NOV_23_2009_1251PM) #define BOOST_SPIRIT_KARMA_SYMBOLS_NOV_23_2009_1251PM #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined(BOOST_MSVC) # pragma warning(push) # pragma warning(disable: 4355) // 'this' : used in base member initializer list warning #endif /////////////////////////////////////////////////////////////////////////////// namespace boost { namespace spirit { namespace traits { template struct symbols_lookup { typedef mpl::eval_if , traits::detail::value_at_c , detail::add_const_ref > sequence_type; typedef typename mpl::eval_if , traits::container_value , sequence_type>::type type; // fusion sequence template static type call(T_ const& t, mpl::false_, mpl::true_) { return fusion::at_c<0>(t); } // container template static type call(T_ const& t, mpl::true_, IsSequence) { return t[0]; } // not a container and not a fusion sequence template static type call(T_ const& t, mpl::false_, mpl::false_) { return t; } static type call(T const& t) { typedef typename traits::is_container::type is_container; typedef typename fusion::traits::is_sequence::type is_sequence; return call(t, is_container(), is_sequence()); } }; template struct symbols_lookup { typedef Attribute const& type; static type call(Attribute const& t) { return t; } }; template struct symbols_value { typedef mpl::eval_if , traits::detail::value_at_c , mpl::identity > sequence_type; typedef typename mpl::eval_if , traits::container_value , sequence_type>::type type; // fusion sequence template static type call(T_ const& t, mpl::false_, mpl::true_) { return fusion::at_c<1>(t); } // container template static type call(T_ const& t, mpl::true_, IsSequence) { return t[1]; } // not a container nor a fusion sequence template static type call(T_ const&, mpl::false_, mpl::false_) { return unused; } static type call(T const& t) { typedef typename traits::is_container::type is_container; typedef typename fusion::traits::is_sequence::type is_sequence; return call(t, is_container(), is_sequence()); } }; template struct symbols_value { typedef unused_type type; static type call(Attribute const&) { return unused; } }; }}} /////////////////////////////////////////////////////////////////////////////// namespace boost { namespace spirit { namespace karma { /////////////////////////////////////////////////////////////////////////// template struct symbols_lookup : mpl::if_< traits::not_is_unused , std::map , std::set > {}; /////////////////////////////////////////////////////////////////////////// namespace detail { /////////////////////////////////////////////////////////////////////// template struct generate_encoded { typedef typename proto::terminal >::type encoding_type; template static bool call(OutputIterator& sink, Expr const& expr , Attribute const& attr) { encoding_type const encoding = encoding_type(); return karma::generate(sink, encoding[expr], attr); } }; template <> struct generate_encoded { template static bool call(OutputIterator& sink, Expr const& expr , Attribute const& attr) { return karma::generate(sink, expr, attr); } }; } template < typename Attribute = char, typename T = unused_type , typename Lookup = typename symbols_lookup::type , typename CharEncoding = unused_type, typename Tag = unused_type> struct symbols : proto::extends< typename proto::terminal< reference > >::type , symbols > , primitive_generator< symbols > { typedef T value_type; // the value associated with each entry typedef reference reference_; typedef typename proto::terminal::type terminal; typedef proto::extends base_type; template struct attribute { typedef Attribute type; }; symbols(std::string const& name = "symbols") : base_type(terminal::make(reference_(*this))) , add(*this) , remove(*this) , lookup(new Lookup()) , name_(name) {} symbols(symbols const& syms) : base_type(terminal::make(reference_(*this))) , add(*this) , remove(*this) , lookup(syms.lookup) , name_(syms.name_) {} template symbols(symbols const& syms) : base_type(terminal::make(reference_(*this))) , add(*this) , remove(*this) , lookup(syms.lookup) , name_(syms.name_) {} template symbols(Symbols const& syms, Data const& data , std::string const& name = "symbols") : base_type(terminal::make(reference_(*this))) , add(*this) , remove(*this) , lookup(new Lookup()) , name_(name) { typename range_const_iterator::type si = boost::begin(syms); typename range_const_iterator::type di = boost::begin(data); while (si != boost::end(syms)) add(*si++, *di++); } symbols& operator=(symbols const& rhs) { *lookup = *rhs.lookup; name_ = rhs.name_; return *this; } template symbols& operator=(symbols const& rhs) { *lookup = *rhs.lookup; name_ = rhs.name_; return *this; } void clear() { lookup->clear(); } struct adder; struct remover; template adder const& operator=(std::pair const& p) { lookup->clear(); return add(p.first, p.second); } template friend adder const& operator+= (symbols& sym, std::pair const& p) { return sym.add(p.first, p.second); } template friend remover const& operator-= (symbols& sym, Attr const& attr) { return sym.remove(attr); } #if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) // non-const version needed to suppress proto's += kicking in template friend adder const& operator+= (symbols& sym, std::pair& p) { return sym.add(p.first, p.second); } // non-const version needed to suppress proto's -= kicking in template friend remover const& operator-= (symbols& sym, Attr& attr) { return sym.remove(attr); } #else // for rvalue references template friend adder const& operator+= (symbols& sym, std::pair&& p) { return sym.add(p.first, p.second); } // for rvalue references template friend remover const& operator-= (symbols& sym, Attr&& attr) { return sym.remove(attr); } #endif template void for_each(F f) const { std::for_each(lookup->begin(), lookup->end(), f); } template value_type* find(Attr const& attr) { typename Lookup::iterator it = lookup->find(attr); return (it != lookup->end()) ? &(*it).second : 0; } template value_type& at(Attr const& attr) { return (*lookup)[attr]; } /////////////////////////////////////////////////////////////////////// template bool generate(OutputIterator& sink, Context&, Delimiter const& d , Attr const& attr) const { typename Lookup::iterator it = lookup->find( traits::symbols_lookup::call(attr)); if (it == lookup->end()) return false; return karma::detail::generate_encoded::call( sink, (*it).second , traits::symbols_value::call(attr)) && karma::delimit_out(sink, d); } template info what(Context&) const { return info(name_); } void name(std::string const &str) { name_ = str; } std::string const &name() const { return name_; } /////////////////////////////////////////////////////////////////////// struct adder { template struct result { typedef adder const& type; }; adder(symbols& sym) : sym(sym) { } template adder const& operator()(Attr const& attr, T const& val = T()) const { sym.lookup->insert(typename Lookup::value_type(attr, val)); return *this; } template adder const& operator, (Attr const& attr) const { sym.lookup->insert(typename Lookup::value_type(attr, T())); return *this; } symbols& sym; private: // silence MSVC warning C4512: assignment operator could not be generated adder& operator= (adder const&); }; struct remover { template struct result { typedef remover const& type; }; remover(symbols& sym) : sym(sym) { } template remover const& operator()(Attr const& attr) const { sym.lookup->erase(attr); return *this; } template remover const& operator, (Attr const& attr) const { sym.lookup->erase(attr); return *this; } symbols& sym; private: // silence MSVC warning C4512: assignment operator could not be generated remover& operator= (remover const&); }; adder add; remover remove; shared_ptr lookup; std::string name_; }; /////////////////////////////////////////////////////////////////////////// // specialization for unused stored type template < typename Attribute, typename Lookup , typename CharEncoding, typename Tag> struct symbols : proto::extends< typename proto::terminal< spirit::karma::reference< symbols > >::type , symbols > , spirit::karma::generator< symbols > { typedef unused_type value_type; // the value associated with each entry typedef spirit::karma::reference reference_; typedef typename proto::terminal::type terminal; typedef proto::extends base_type; template struct attribute { typedef Attribute type; }; symbols(std::string const& name = "symbols") : base_type(terminal::make(reference_(*this))) , add(*this) , remove(*this) , lookup(new Lookup()) , name_(name) {} symbols(symbols const& syms) : base_type(terminal::make(reference_(*this))) , add(*this) , remove(*this) , lookup(syms.lookup) , name_(syms.name_) {} template symbols(symbols const& syms) : base_type(terminal::make(reference_(*this))) , add(*this) , remove(*this) , lookup(syms.lookup) , name_(syms.name_) {} template symbols(Symbols const& syms, Data const& data , std::string const& name = "symbols") : base_type(terminal::make(reference_(*this))) , add(*this) , remove(*this) , lookup(new Lookup()) , name_(name) { typename range_const_iterator::type si = boost::begin(syms); typename range_const_iterator::type di = boost::begin(data); while (si != boost::end(syms)) add(*si++, *di++); } symbols& operator=(symbols const& rhs) { *lookup = *rhs.lookup; name_ = rhs.name_; return *this; } template symbols& operator=(symbols const& rhs) { *lookup = *rhs.lookup; name_ = rhs.name_; return *this; } void clear() { lookup->clear(); } struct adder; struct remover; template adder const& operator=(Attr const& attr) { lookup->clear(); return add(attr); } template friend adder const& operator+= (symbols& sym, Attr const& attr) { return sym.add(attr); } template friend remover const& operator-= (symbols& sym, Attr const& attr) { return sym.remove(attr); } // non-const version needed to suppress proto's += kicking in template friend adder const& operator+= (symbols& sym, Attr& attr) { return sym.add(attr); } // non-const version needed to suppress proto's -= kicking in template friend remover const& operator-= (symbols& sym, Attr& attr) { return sym.remove(attr); } template void for_each(F f) const { std::for_each(lookup->begin(), lookup->end(), f); } template value_type const* find(Attr const& attr) { typename Lookup::iterator it = lookup->find(attr); return (it != lookup->end()) ? &unused : 0; } template value_type at(Attr const& attr) { typename Lookup::iterator it = lookup->find(attr); if (it == lookup->end()) add(attr); return unused; } /////////////////////////////////////////////////////////////////////// template bool generate(OutputIterator& sink, Context&, Delimiter const& d , Attr const& attr) const { typename Lookup::iterator it = lookup->find( traits::symbols_lookup::call(attr)); if (it == lookup->end()) return false; return karma::detail::generate_encoded:: call(sink , traits::symbols_lookup::call(attr) , unused) && karma::delimit_out(sink, d); } template info what(Context&) const { return info(name_); } void name(std::string const &str) { name_ = str; } std::string const &name() const { return name_; } /////////////////////////////////////////////////////////////////////// struct adder { template struct result { typedef adder const& type; }; adder(symbols& sym) : sym(sym) { } template adder const& operator()(Attr const& attr) const { sym.lookup->insert(attr); return *this; } template adder const& operator, (Attr const& attr) const { sym.lookup->insert(attr); return *this; } symbols& sym; private: // silence MSVC warning C4512: assignment operator could not be generated adder& operator= (adder const&); }; struct remover { template struct result { typedef remover const& type; }; remover(symbols& sym) : sym(sym) { } template remover const& operator()(Attr const& attr) const { sym.lookup->erase(attr); return *this; } template remover const& operator, (Attr const& attr) const { sym.lookup->erase(attr); return *this; } symbols& sym; private: // silence MSVC warning C4512: assignment operator could not be generated remover& operator= (remover const&); }; adder add; remover remove; shared_ptr lookup; std::string name_; }; /////////////////////////////////////////////////////////////////////////// // Generator generators: make_xxx function (objects) /////////////////////////////////////////////////////////////////////////// template struct make_primitive< reference > , Modifiers> { static bool const lower = has_modifier >::value; static bool const upper = has_modifier >::value; typedef reference< symbols > reference_; typedef typename mpl::if_c< lower || upper , symbols< Attribute, T, Lookup , typename spirit::detail::get_encoding_with_case< Modifiers, unused_type, lower || upper>::type , typename detail::get_casetag::type> , reference_>::type result_type; result_type operator()(reference_ ref, unused_type) const { return result_type(ref.ref.get()); } }; }}} namespace boost { namespace spirit { namespace traits { /////////////////////////////////////////////////////////////////////////// template struct handles_container , Attr, Context, Iterator> : traits::is_container {}; }}} #if defined(BOOST_MSVC) # pragma warning(pop) #endif #endif