You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and dots ('.'), can be up to 35 characters long. Letters must be lowercase.
768 lines
23 KiB
768 lines
23 KiB
// 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 <boost/spirit/home/support/common_terminals.hpp> |
|
#include <boost/spirit/home/support/info.hpp> |
|
#include <boost/spirit/home/support/unused.hpp> |
|
#include <boost/spirit/home/support/attributes_fwd.hpp> |
|
#include <boost/spirit/home/support/detail/get_encoding.hpp> |
|
#include <boost/spirit/home/karma/detail/attributes.hpp> |
|
#include <boost/spirit/home/karma/detail/extract_from.hpp> |
|
#include <boost/spirit/home/karma/domain.hpp> |
|
#include <boost/spirit/home/karma/meta_compiler.hpp> |
|
#include <boost/spirit/home/karma/reference.hpp> |
|
#include <boost/spirit/home/karma/generate.hpp> |
|
#include <boost/spirit/home/karma/delimit_out.hpp> |
|
#include <boost/spirit/home/karma/detail/get_casetag.hpp> |
|
#include <boost/spirit/home/karma/detail/string_generate.hpp> |
|
#include <boost/config.hpp> |
|
#include <boost/shared_ptr.hpp> |
|
#include <boost/mpl/if.hpp> |
|
#include <map> |
|
#include <set> |
|
|
|
#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 <typename T, typename Attribute, typename Enable> |
|
struct symbols_lookup |
|
{ |
|
typedef |
|
mpl::eval_if<fusion::traits::is_sequence<T> |
|
, traits::detail::value_at_c<T, 0> |
|
, detail::add_const_ref<T> > sequence_type; |
|
typedef typename |
|
mpl::eval_if<traits::is_container<T> |
|
, traits::container_value<T> |
|
, sequence_type>::type type; |
|
|
|
// fusion sequence |
|
template <typename T_> |
|
static type call(T_ const& t, mpl::false_, mpl::true_) |
|
{ |
|
return fusion::at_c<0>(t); |
|
} |
|
|
|
// container |
|
template <typename T_, typename IsSequence> |
|
static type call(T_ const& t, mpl::true_, IsSequence) |
|
{ |
|
return t[0]; |
|
} |
|
|
|
// not a container and not a fusion sequence |
|
template <typename T_> |
|
static type call(T_ const& t, mpl::false_, mpl::false_) |
|
{ |
|
return t; |
|
} |
|
|
|
static type call(T const& t) |
|
{ |
|
typedef typename traits::is_container<T>::type is_container; |
|
typedef typename fusion::traits::is_sequence<T>::type is_sequence; |
|
|
|
return call(t, is_container(), is_sequence()); |
|
} |
|
}; |
|
|
|
template <typename Attribute> |
|
struct symbols_lookup<Attribute, Attribute> |
|
{ |
|
typedef Attribute const& type; |
|
|
|
static type call(Attribute const& t) |
|
{ |
|
return t; |
|
} |
|
}; |
|
|
|
template <typename Attribute, typename T, typename Enable> |
|
struct symbols_value |
|
{ |
|
typedef |
|
mpl::eval_if<fusion::traits::is_sequence<T> |
|
, traits::detail::value_at_c<T, 1> |
|
, mpl::identity<unused_type> > sequence_type; |
|
typedef typename |
|
mpl::eval_if<traits::is_container<T> |
|
, traits::container_value<T> |
|
, sequence_type>::type type; |
|
|
|
// fusion sequence |
|
template <typename T_> |
|
static type call(T_ const& t, mpl::false_, mpl::true_) |
|
{ |
|
return fusion::at_c<1>(t); |
|
} |
|
|
|
// container |
|
template <typename T_, typename IsSequence> |
|
static type call(T_ const& t, mpl::true_, IsSequence) |
|
{ |
|
return t[1]; |
|
} |
|
|
|
// not a container nor a fusion sequence |
|
template <typename T_> |
|
static type call(T_ const&, mpl::false_, mpl::false_) |
|
{ |
|
return unused; |
|
} |
|
|
|
static type call(T const& t) |
|
{ |
|
typedef typename traits::is_container<T>::type is_container; |
|
typedef typename fusion::traits::is_sequence<T>::type is_sequence; |
|
|
|
return call(t, is_container(), is_sequence()); |
|
} |
|
}; |
|
|
|
template <typename Attribute> |
|
struct symbols_value<Attribute, Attribute> |
|
{ |
|
typedef unused_type type; |
|
|
|
static type call(Attribute const&) |
|
{ |
|
return unused; |
|
} |
|
}; |
|
}}} |
|
|
|
/////////////////////////////////////////////////////////////////////////////// |
|
namespace boost { namespace spirit { namespace karma |
|
{ |
|
/////////////////////////////////////////////////////////////////////////// |
|
template <typename T, typename Attribute> |
|
struct symbols_lookup |
|
: mpl::if_< |
|
traits::not_is_unused<T> |
|
, std::map<Attribute, T> |
|
, std::set<Attribute> |
|
> |
|
{}; |
|
|
|
/////////////////////////////////////////////////////////////////////////// |
|
namespace detail |
|
{ |
|
/////////////////////////////////////////////////////////////////////// |
|
template <typename CharEncoding, typename Tag> |
|
struct generate_encoded |
|
{ |
|
typedef typename |
|
proto::terminal<tag::char_code<Tag, CharEncoding> >::type |
|
encoding_type; |
|
|
|
template <typename OutputIterator, typename Expr, typename Attribute> |
|
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<unused_type, unused_type> |
|
{ |
|
template <typename OutputIterator, typename Expr, typename Attribute> |
|
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<T, Attribute>::type |
|
, typename CharEncoding = unused_type, typename Tag = unused_type> |
|
struct symbols |
|
: proto::extends< |
|
typename proto::terminal< |
|
reference<symbols<Attribute, T, Lookup, CharEncoding, Tag> > |
|
>::type |
|
, symbols<Attribute, T, Lookup, CharEncoding, Tag> > |
|
, primitive_generator< |
|
symbols<Attribute, T, Lookup, CharEncoding, Tag> > |
|
{ |
|
typedef T value_type; // the value associated with each entry |
|
|
|
typedef reference<symbols> reference_; |
|
typedef typename proto::terminal<reference_>::type terminal; |
|
typedef proto::extends<terminal, symbols> base_type; |
|
|
|
template <typename Context, typename Unused> |
|
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 <typename CharEncoding_, typename Tag_> |
|
symbols(symbols<Attribute, T, Lookup, CharEncoding_, Tag_> const& syms) |
|
: base_type(terminal::make(reference_(*this))) |
|
, add(*this) |
|
, remove(*this) |
|
, lookup(syms.lookup) |
|
, name_(syms.name_) |
|
{} |
|
|
|
template <typename Symbols, typename Data> |
|
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<Symbols>::type si = boost::begin(syms); |
|
typename range_const_iterator<Data>::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 <typename CharEncoding_, typename Tag_> |
|
symbols& |
|
operator=(symbols<Attribute, T, Lookup, CharEncoding_, Tag_> const& rhs) |
|
{ |
|
*lookup = *rhs.lookup; |
|
name_ = rhs.name_; |
|
return *this; |
|
} |
|
|
|
void clear() |
|
{ |
|
lookup->clear(); |
|
} |
|
|
|
struct adder; |
|
struct remover; |
|
|
|
template <typename Attr, typename T_> |
|
adder const& |
|
operator=(std::pair<Attr, T_> const& p) |
|
{ |
|
lookup->clear(); |
|
return add(p.first, p.second); |
|
} |
|
|
|
template <typename Attr, typename T_> |
|
friend adder const& |
|
operator+= (symbols& sym, std::pair<Attr, T_> const& p) |
|
{ |
|
return sym.add(p.first, p.second); |
|
} |
|
|
|
template <typename Attr> |
|
friend remover const& |
|
operator-= (symbols& sym, Attr const& attr) |
|
{ |
|
return sym.remove(attr); |
|
} |
|
|
|
#if defined(BOOST_NO_RVALUE_REFERENCES) |
|
// non-const version needed to suppress proto's += kicking in |
|
template <typename Attr, typename T_> |
|
friend adder const& |
|
operator+= (symbols& sym, std::pair<Attr, T_>& p) |
|
{ |
|
return sym.add(p.first, p.second); |
|
} |
|
|
|
// non-const version needed to suppress proto's -= kicking in |
|
template <typename Attr> |
|
friend remover const& |
|
operator-= (symbols& sym, Attr& attr) |
|
{ |
|
return sym.remove(attr); |
|
} |
|
#else |
|
// for rvalue references |
|
template <typename Attr, typename T_> |
|
friend adder const& |
|
operator+= (symbols& sym, std::pair<Attr, T_>&& p) |
|
{ |
|
return sym.add(p.first, p.second); |
|
} |
|
|
|
// for rvalue references |
|
template <typename Attr> |
|
friend remover const& |
|
operator-= (symbols& sym, Attr&& attr) |
|
{ |
|
return sym.remove(attr); |
|
} |
|
#endif |
|
template <typename F> |
|
void for_each(F f) const |
|
{ |
|
std::for_each(lookup->begin(), lookup->end(), f); |
|
} |
|
|
|
template <typename Attr> |
|
value_type* find(Attr const& attr) |
|
{ |
|
typename Lookup::iterator it = lookup->find(attr); |
|
return (it != lookup->end()) ? &(*it).second : 0; |
|
} |
|
|
|
template <typename Attr> |
|
value_type& at(Attr const& attr) |
|
{ |
|
return (*lookup)[attr]; |
|
} |
|
|
|
/////////////////////////////////////////////////////////////////////// |
|
template <typename OutputIterator, typename Context, typename Delimiter |
|
, typename Attr> |
|
bool generate(OutputIterator& sink, Context&, Delimiter const& d |
|
, Attr const& attr) const |
|
{ |
|
typename Lookup::iterator it = lookup->find( |
|
traits::symbols_lookup<Attr, Attribute>::call(attr)); |
|
if (it == lookup->end()) |
|
return false; |
|
|
|
return karma::detail::generate_encoded<CharEncoding, Tag>::call( |
|
sink, (*it).second |
|
, traits::symbols_value<Attribute, Attr>::call(attr)) && |
|
karma::delimit_out(sink, d); |
|
} |
|
|
|
template <typename Context> |
|
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 <typename, typename = unused_type> |
|
struct result { typedef adder const& type; }; |
|
|
|
adder(symbols& sym) |
|
: sym(sym) |
|
{ |
|
} |
|
|
|
template <typename Attr> |
|
adder const& |
|
operator()(Attr const& attr, T const& val = T()) const |
|
{ |
|
sym.lookup->insert(typename Lookup::value_type(attr, val)); |
|
return *this; |
|
} |
|
|
|
template <typename Attr> |
|
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 <typename> |
|
struct result { typedef remover const& type; }; |
|
|
|
remover(symbols& sym) |
|
: sym(sym) |
|
{ |
|
} |
|
|
|
template <typename Attr> |
|
remover const& |
|
operator()(Attr const& attr) const |
|
{ |
|
sym.lookup->erase(attr); |
|
return *this; |
|
} |
|
|
|
template <typename Attr> |
|
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> lookup; |
|
std::string name_; |
|
}; |
|
|
|
/////////////////////////////////////////////////////////////////////////// |
|
// specialization for unused stored type |
|
template < |
|
typename Attribute, typename Lookup |
|
, typename CharEncoding, typename Tag> |
|
struct symbols<Attribute, unused_type, Lookup, CharEncoding, Tag> |
|
: proto::extends< |
|
typename proto::terminal< |
|
spirit::karma::reference< |
|
symbols<Attribute, unused_type, Lookup, CharEncoding, Tag> > |
|
>::type |
|
, symbols<Attribute, unused_type, Lookup, CharEncoding, Tag> |
|
> |
|
, spirit::karma::generator< |
|
symbols<Attribute, unused_type, Lookup, CharEncoding, Tag> > |
|
{ |
|
typedef unused_type value_type; // the value associated with each entry |
|
|
|
typedef spirit::karma::reference<symbols> reference_; |
|
typedef typename proto::terminal<reference_>::type terminal; |
|
typedef proto::extends<terminal, symbols> base_type; |
|
|
|
template <typename Context, typename Unused> |
|
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 <typename CharEncoding_, typename Tag_> |
|
symbols(symbols<Attribute, unused_type, Lookup, CharEncoding_, Tag_> const& syms) |
|
: base_type(terminal::make(reference_(*this))) |
|
, add(*this) |
|
, remove(*this) |
|
, lookup(syms.lookup) |
|
, name_(syms.name_) |
|
{} |
|
|
|
template <typename Symbols, typename Data> |
|
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<Symbols>::type si = boost::begin(syms); |
|
typename range_const_iterator<Data>::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 <typename CharEncoding_, typename Tag_> |
|
symbols& |
|
operator=(symbols<Attribute, unused_type, Lookup, CharEncoding_, Tag_> const& rhs) |
|
{ |
|
*lookup = *rhs.lookup; |
|
name_ = rhs.name_; |
|
return *this; |
|
} |
|
|
|
void clear() |
|
{ |
|
lookup->clear(); |
|
} |
|
|
|
struct adder; |
|
struct remover; |
|
|
|
template <typename Attr> |
|
adder const& |
|
operator=(Attr const& attr) |
|
{ |
|
lookup->clear(); |
|
return add(attr); |
|
} |
|
|
|
template <typename Attr> |
|
friend adder const& |
|
operator+= (symbols& sym, Attr const& attr) |
|
{ |
|
return sym.add(attr); |
|
} |
|
|
|
template <typename Attr> |
|
friend remover const& |
|
operator-= (symbols& sym, Attr const& attr) |
|
{ |
|
return sym.remove(attr); |
|
} |
|
|
|
// non-const version needed to suppress proto's += kicking in |
|
template <typename Attr> |
|
friend adder const& |
|
operator+= (symbols& sym, Attr& attr) |
|
{ |
|
return sym.add(attr); |
|
} |
|
|
|
// non-const version needed to suppress proto's -= kicking in |
|
template <typename Attr> |
|
friend remover const& |
|
operator-= (symbols& sym, Attr& attr) |
|
{ |
|
return sym.remove(attr); |
|
} |
|
|
|
template <typename F> |
|
void for_each(F f) const |
|
{ |
|
std::for_each(lookup->begin(), lookup->end(), f); |
|
} |
|
|
|
template <typename Attr> |
|
value_type const* find(Attr const& attr) |
|
{ |
|
typename Lookup::iterator it = lookup->find(attr); |
|
return (it != lookup->end()) ? &unused : 0; |
|
} |
|
|
|
template <typename Attr> |
|
value_type at(Attr const& attr) |
|
{ |
|
typename Lookup::iterator it = lookup->find(attr); |
|
if (it == lookup->end()) |
|
add(attr); |
|
return unused; |
|
} |
|
|
|
/////////////////////////////////////////////////////////////////////// |
|
template <typename OutputIterator, typename Context, typename Delimiter |
|
, typename Attr> |
|
bool generate(OutputIterator& sink, Context&, Delimiter const& d |
|
, Attr const& attr) const |
|
{ |
|
typename Lookup::iterator it = lookup->find( |
|
traits::symbols_lookup<Attr, Attribute>::call(attr)); |
|
if (it == lookup->end()) |
|
return false; |
|
|
|
return karma::detail::generate_encoded<CharEncoding, Tag>:: |
|
call(sink |
|
, traits::symbols_lookup<Attr, Attribute>::call(attr) |
|
, unused) && |
|
karma::delimit_out(sink, d); |
|
} |
|
|
|
template <typename Context> |
|
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 <typename, typename = unused_type> |
|
struct result { typedef adder const& type; }; |
|
|
|
adder(symbols& sym) |
|
: sym(sym) |
|
{ |
|
} |
|
|
|
template <typename Attr> |
|
adder const& |
|
operator()(Attr const& attr) const |
|
{ |
|
sym.lookup->insert(attr); |
|
return *this; |
|
} |
|
|
|
template <typename Attr> |
|
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 <typename> |
|
struct result { typedef remover const& type; }; |
|
|
|
remover(symbols& sym) |
|
: sym(sym) |
|
{ |
|
} |
|
|
|
template <typename Attr> |
|
remover const& |
|
operator()(Attr const& attr) const |
|
{ |
|
sym.lookup->erase(attr); |
|
return *this; |
|
} |
|
|
|
template <typename Attr> |
|
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> lookup; |
|
std::string name_; |
|
}; |
|
|
|
/////////////////////////////////////////////////////////////////////////// |
|
// Generator generators: make_xxx function (objects) |
|
/////////////////////////////////////////////////////////////////////////// |
|
template <typename Attribute, typename T, typename Lookup |
|
, typename CharEnconding, typename Tag, typename Modifiers> |
|
struct make_primitive< |
|
reference<symbols<Attribute, T, Lookup, CharEnconding, Tag> > |
|
, Modifiers> |
|
{ |
|
static bool const lower = |
|
has_modifier<Modifiers, tag::char_code_base<tag::lower> >::value; |
|
static bool const upper = |
|
has_modifier<Modifiers, tag::char_code_base<tag::upper> >::value; |
|
|
|
typedef reference< |
|
symbols<Attribute, T, Lookup, CharEnconding, Tag> |
|
> 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<Modifiers, lower || upper>::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 <typename Attribute, typename T, typename Lookup |
|
, typename CharEncoding, typename Tag |
|
, typename Attr, typename Context, typename Iterator> |
|
struct handles_container<karma::symbols<Attribute, T, Lookup, CharEncoding, Tag> |
|
, Attr, Context, Iterator> |
|
: traits::is_container<Attr> {}; |
|
}}} |
|
|
|
#if defined(BOOST_MSVC) |
|
# pragma warning(pop) |
|
#endif |
|
|
|
#endif |
|
|
|
|