• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //  Copyright (c) 2001-2011 Hartmut Kaiser
2 //
3 //  Distributed under the Boost Software License, Version 1.0. (See accompanying
4 //  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5 
6 #if !defined(BOOST_SPIRIT_KARMA_SYMBOLS_NOV_23_2009_1251PM)
7 #define BOOST_SPIRIT_KARMA_SYMBOLS_NOV_23_2009_1251PM
8 
9 #include <boost/spirit/home/support/common_terminals.hpp>
10 #include <boost/spirit/home/support/info.hpp>
11 #include <boost/spirit/home/support/unused.hpp>
12 #include <boost/spirit/home/support/attributes_fwd.hpp>
13 #include <boost/spirit/home/support/detail/get_encoding.hpp>
14 #include <boost/spirit/home/karma/detail/attributes.hpp>
15 #include <boost/spirit/home/karma/detail/extract_from.hpp>
16 #include <boost/spirit/home/karma/domain.hpp>
17 #include <boost/spirit/home/karma/meta_compiler.hpp>
18 #include <boost/spirit/home/karma/reference.hpp>
19 #include <boost/spirit/home/karma/generate.hpp>
20 #include <boost/spirit/home/karma/delimit_out.hpp>
21 #include <boost/spirit/home/karma/detail/get_casetag.hpp>
22 #include <boost/spirit/home/karma/detail/string_generate.hpp>
23 #include <boost/config.hpp>
24 #include <boost/proto/extends.hpp>
25 #include <boost/proto/traits.hpp>
26 #include <boost/shared_ptr.hpp>
27 #include <boost/mpl/if.hpp>
28 #include <map>
29 #include <set>
30 
31 #if defined(BOOST_MSVC)
32 # pragma warning(push)
33 # pragma warning(disable: 4355) // 'this' : used in base member initializer list warning
34 #endif
35 
36 ///////////////////////////////////////////////////////////////////////////////
37 namespace boost { namespace spirit { namespace traits
38 {
39     template <typename T, typename Attribute, typename Enable>
40     struct symbols_lookup
41     {
42         typedef
43             mpl::eval_if<fusion::traits::is_sequence<T>
44               , traits::detail::value_at_c<T, 0>
45               , detail::add_const_ref<T> > sequence_type;
46         typedef typename
47             mpl::eval_if<traits::is_container<T>
48               , traits::container_value<T>
49               , sequence_type>::type type;
50 
51         // fusion sequence
52         template <typename T_>
callboost::spirit::traits::symbols_lookup53         static type call(T_ const& t, mpl::false_, mpl::true_)
54         {
55             return fusion::at_c<0>(t);
56         }
57 
58         // container
59         template <typename T_, typename IsSequence>
callboost::spirit::traits::symbols_lookup60         static type call(T_ const& t, mpl::true_, IsSequence)
61         {
62             return t[0];
63         }
64 
65         // not a container and not a fusion sequence
66         template <typename T_>
callboost::spirit::traits::symbols_lookup67         static type call(T_ const& t, mpl::false_, mpl::false_)
68         {
69             return t;
70         }
71 
callboost::spirit::traits::symbols_lookup72         static type call(T const& t)
73         {
74             typedef typename traits::is_container<T>::type is_container;
75             typedef typename fusion::traits::is_sequence<T>::type is_sequence;
76 
77             return call(t, is_container(), is_sequence());
78         }
79     };
80 
81     template <typename Attribute>
82     struct symbols_lookup<Attribute, Attribute>
83     {
84         typedef Attribute const& type;
85 
callboost::spirit::traits::symbols_lookup86         static type call(Attribute const& t)
87         {
88             return t;
89         }
90     };
91 
92     template <typename Attribute, typename T, typename Enable>
93     struct symbols_value
94     {
95         typedef
96             mpl::eval_if<fusion::traits::is_sequence<T>
97               , traits::detail::value_at_c<T, 1>
98               , mpl::identity<unused_type> > sequence_type;
99         typedef typename
100             mpl::eval_if<traits::is_container<T>
101               , traits::container_value<T>
102               , sequence_type>::type type;
103 
104         // fusion sequence
105         template <typename T_>
callboost::spirit::traits::symbols_value106         static type call(T_ const& t, mpl::false_, mpl::true_)
107         {
108             return fusion::at_c<1>(t);
109         }
110 
111         // container
112         template <typename T_, typename IsSequence>
callboost::spirit::traits::symbols_value113         static type call(T_ const& t, mpl::true_, IsSequence)
114         {
115             return t[1];
116         }
117 
118         // not a container nor a fusion sequence
119         template <typename T_>
callboost::spirit::traits::symbols_value120         static type call(T_ const&, mpl::false_, mpl::false_)
121         {
122             return unused;
123         }
124 
callboost::spirit::traits::symbols_value125         static type call(T const& t)
126         {
127             typedef typename traits::is_container<T>::type is_container;
128             typedef typename fusion::traits::is_sequence<T>::type is_sequence;
129 
130             return call(t, is_container(), is_sequence());
131         }
132     };
133 
134     template <typename Attribute>
135     struct symbols_value<Attribute, Attribute>
136     {
137         typedef unused_type type;
138 
callboost::spirit::traits::symbols_value139         static type call(Attribute const&)
140         {
141             return unused;
142         }
143     };
144 }}}
145 
146 ///////////////////////////////////////////////////////////////////////////////
147 namespace boost { namespace spirit { namespace karma
148 {
149     ///////////////////////////////////////////////////////////////////////////
150     template <typename T, typename Attribute>
151     struct symbols_lookup
152       : mpl::if_<
153             traits::not_is_unused<T>
154           , std::map<Attribute, T>
155           , std::set<Attribute>
156         >
157     {};
158 
159     ///////////////////////////////////////////////////////////////////////////
160     namespace detail
161     {
162         ///////////////////////////////////////////////////////////////////////
163         template <typename CharEncoding, typename Tag>
164         struct generate_encoded
165         {
166             typedef typename
167                 proto::terminal<tag::char_code<Tag, CharEncoding> >::type
168             encoding_type;
169 
170             template <typename OutputIterator, typename Expr, typename Attribute>
callboost::spirit::karma::detail::generate_encoded171             static bool call(OutputIterator& sink, Expr const& expr
172               , Attribute const& attr)
173             {
174                 encoding_type const encoding = encoding_type();
175                 return karma::generate(sink, encoding[expr], attr);
176             }
177         };
178 
179         template <>
180         struct generate_encoded<unused_type, unused_type>
181         {
182             template <typename OutputIterator, typename Expr, typename Attribute>
callboost::spirit::karma::detail::generate_encoded183             static bool call(OutputIterator& sink, Expr const& expr
184               , Attribute const& attr)
185             {
186                 return karma::generate(sink, expr, attr);
187             }
188         };
189     }
190 
191     template <
192         typename Attribute = char, typename T = unused_type
193       , typename Lookup = typename symbols_lookup<T, Attribute>::type
194       , typename CharEncoding = unused_type, typename Tag = unused_type>
195     struct symbols
196       : proto::extends<
197             typename proto::terminal<
198                 reference<symbols<Attribute, T, Lookup, CharEncoding, Tag> >
199             >::type
200           , symbols<Attribute, T, Lookup, CharEncoding, Tag> >
201       , primitive_generator<
202             symbols<Attribute, T, Lookup, CharEncoding, Tag> >
203     {
204         typedef T value_type;       // the value associated with each entry
205 
206         typedef reference<symbols> reference_;
207         typedef typename proto::terminal<reference_>::type terminal;
208         typedef proto::extends<terminal, symbols> base_type;
209 
210         template <typename Context, typename Unused>
211         struct attribute
212         {
213             typedef Attribute type;
214         };
215 
symbolsboost::spirit::karma::symbols216         symbols(std::string const& name = "symbols")
217           : base_type(terminal::make(reference_(*this)))
218           , add(*this)
219           , remove(*this)
220           , lookup(new Lookup())
221           , name_(name)
222         {}
223 
symbolsboost::spirit::karma::symbols224         symbols(symbols const& syms)
225           : base_type(terminal::make(reference_(*this)))
226           , add(*this)
227           , remove(*this)
228           , lookup(syms.lookup)
229           , name_(syms.name_)
230         {}
231 
232         template <typename CharEncoding_, typename Tag_>
symbolsboost::spirit::karma::symbols233         symbols(symbols<Attribute, T, Lookup, CharEncoding_, Tag_> const& syms)
234           : base_type(terminal::make(reference_(*this)))
235           , add(*this)
236           , remove(*this)
237           , lookup(syms.lookup)
238           , name_(syms.name_)
239         {}
240 
241         template <typename Symbols, typename Data>
symbolsboost::spirit::karma::symbols242         symbols(Symbols const& syms, Data const& data
243               , std::string const& name = "symbols")
244           : base_type(terminal::make(reference_(*this)))
245           , add(*this)
246           , remove(*this)
247           , lookup(new Lookup())
248           , name_(name)
249         {
250             typename range_const_iterator<Symbols>::type si = boost::begin(syms);
251             typename range_const_iterator<Data>::type di = boost::begin(data);
252             while (si != boost::end(syms))
253                 add(*si++, *di++);
254         }
255 
256         symbols&
operator =boost::spirit::karma::symbols257         operator=(symbols const& rhs)
258         {
259             *lookup = *rhs.lookup;
260             name_ = rhs.name_;
261             return *this;
262         }
263 
264         template <typename CharEncoding_, typename Tag_>
265         symbols&
operator =boost::spirit::karma::symbols266         operator=(symbols<Attribute, T, Lookup, CharEncoding_, Tag_> const& rhs)
267         {
268             *lookup = *rhs.lookup;
269             name_ = rhs.name_;
270             return *this;
271         }
272 
clearboost::spirit::karma::symbols273         void clear()
274         {
275             lookup->clear();
276         }
277 
278         struct adder;
279         struct remover;
280 
281         template <typename Attr, typename T_>
282         adder const&
operator =boost::spirit::karma::symbols283         operator=(std::pair<Attr, T_> const& p)
284         {
285             lookup->clear();
286             return add(p.first, p.second);
287         }
288 
289         template <typename Attr, typename T_>
290         friend adder const&
operator +=(symbols & sym,std::pair<Attr,T_> const & p)291         operator+= (symbols& sym, std::pair<Attr, T_> const& p)
292         {
293             return sym.add(p.first, p.second);
294         }
295 
296         template <typename Attr>
297         friend remover const&
operator -=(symbols & sym,Attr const & attr)298         operator-= (symbols& sym, Attr const& attr)
299         {
300             return sym.remove(attr);
301         }
302 
303 #if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
304         // non-const version needed to suppress proto's += kicking in
305         template <typename Attr, typename T_>
306         friend adder const&
operator +=(symbols & sym,std::pair<Attr,T_> & p)307         operator+= (symbols& sym, std::pair<Attr, T_>& p)
308         {
309             return sym.add(p.first, p.second);
310         }
311 
312         // non-const version needed to suppress proto's -= kicking in
313         template <typename Attr>
314         friend remover const&
operator -=(symbols & sym,Attr & attr)315         operator-= (symbols& sym, Attr& attr)
316         {
317             return sym.remove(attr);
318         }
319 #else
320         // for rvalue references
321         template <typename Attr, typename T_>
322         friend adder const&
operator +=(symbols & sym,std::pair<Attr,T_> && p)323         operator+= (symbols& sym, std::pair<Attr, T_>&& p)
324         {
325             return sym.add(p.first, p.second);
326         }
327 
328         // for rvalue references
329         template <typename Attr>
330         friend remover const&
operator -=(symbols & sym,Attr && attr)331         operator-= (symbols& sym, Attr&& attr)
332         {
333             return sym.remove(attr);
334         }
335 #endif
336         template <typename F>
for_eachboost::spirit::karma::symbols337         void for_each(F f) const
338         {
339             std::for_each(lookup->begin(), lookup->end(), f);
340         }
341 
342         template <typename Attr>
findboost::spirit::karma::symbols343         value_type* find(Attr const& attr)
344         {
345             typename Lookup::iterator it = lookup->find(attr);
346             return (it != lookup->end()) ? &(*it).second : 0;
347         }
348 
349         template <typename Attr>
atboost::spirit::karma::symbols350         value_type& at(Attr const& attr)
351         {
352             return (*lookup)[attr];
353         }
354 
355         ///////////////////////////////////////////////////////////////////////
356         template <typename OutputIterator, typename Context, typename Delimiter
357           , typename Attr>
generateboost::spirit::karma::symbols358         bool generate(OutputIterator& sink, Context&, Delimiter const& d
359           , Attr const& attr) const
360         {
361             typename Lookup::iterator it = lookup->find(
362                 traits::symbols_lookup<Attr, Attribute>::call(attr));
363             if (it == lookup->end())
364                 return false;
365 
366             return karma::detail::generate_encoded<CharEncoding, Tag>::call(
367                         sink, (*it).second
368                       , traits::symbols_value<Attribute, Attr>::call(attr)) &&
369                    karma::delimit_out(sink, d);
370         }
371 
372         template <typename Context>
whatboost::spirit::karma::symbols373         info what(Context&) const
374         {
375             return info(name_);
376         }
377 
nameboost::spirit::karma::symbols378         void name(std::string const &str)
379         {
380             name_ = str;
381         }
nameboost::spirit::karma::symbols382         std::string const &name() const
383         {
384             return name_;
385         }
386 
387         ///////////////////////////////////////////////////////////////////////
388         struct adder
389         {
390             template <typename, typename = unused_type>
391             struct result { typedef adder const& type; };
392 
adderboost::spirit::karma::symbols::adder393             adder(symbols& sym)
394               : sym(sym)
395             {
396             }
397 
398             template <typename Attr>
399             adder const&
operator ()boost::spirit::karma::symbols::adder400             operator()(Attr const& attr, T const& val = T()) const
401             {
402                 sym.lookup->insert(typename Lookup::value_type(attr, val));
403                 return *this;
404             }
405 
406             template <typename Attr>
407             adder const&
operator ,boost::spirit::karma::symbols::adder408             operator, (Attr const& attr) const
409             {
410                 sym.lookup->insert(typename Lookup::value_type(attr, T()));
411                 return *this;
412             }
413 
414             symbols& sym;
415 
416             // silence MSVC warning C4512: assignment operator could not be generated
417             BOOST_DELETED_FUNCTION(adder& operator= (adder const&))
418         };
419 
420         struct remover
421         {
422             template <typename>
423             struct result { typedef remover const& type; };
424 
removerboost::spirit::karma::symbols::remover425             remover(symbols& sym)
426               : sym(sym)
427             {
428             }
429 
430             template <typename Attr>
431             remover const&
operator ()boost::spirit::karma::symbols::remover432             operator()(Attr const& attr) const
433             {
434                 sym.lookup->erase(attr);
435                 return *this;
436             }
437 
438             template <typename Attr>
439             remover const&
operator ,boost::spirit::karma::symbols::remover440             operator, (Attr const& attr) const
441             {
442                 sym.lookup->erase(attr);
443                 return *this;
444             }
445 
446             symbols& sym;
447 
448             // silence MSVC warning C4512: assignment operator could not be generated
449             BOOST_DELETED_FUNCTION(remover& operator= (remover const&))
450         };
451 
452         adder add;
453         remover remove;
454         shared_ptr<Lookup> lookup;
455         std::string name_;
456     };
457 
458     ///////////////////////////////////////////////////////////////////////////
459     // specialization for unused stored type
460     template <
461         typename Attribute, typename Lookup
462       , typename CharEncoding, typename Tag>
463     struct symbols<Attribute, unused_type, Lookup, CharEncoding, Tag>
464       : proto::extends<
465             typename proto::terminal<
466                 spirit::karma::reference<
467                     symbols<Attribute, unused_type, Lookup, CharEncoding, Tag> >
468             >::type
469           , symbols<Attribute, unused_type, Lookup, CharEncoding, Tag>
470         >
471       , spirit::karma::generator<
472             symbols<Attribute, unused_type, Lookup, CharEncoding, Tag> >
473     {
474         typedef unused_type value_type;  // the value associated with each entry
475 
476         typedef spirit::karma::reference<symbols> reference_;
477         typedef typename proto::terminal<reference_>::type terminal;
478         typedef proto::extends<terminal, symbols> base_type;
479 
480         template <typename Context, typename Unused>
481         struct attribute
482         {
483             typedef Attribute type;
484         };
485 
symbolsboost::spirit::karma::symbols486         symbols(std::string const& name = "symbols")
487           : base_type(terminal::make(reference_(*this)))
488           , add(*this)
489           , remove(*this)
490           , lookup(new Lookup())
491           , name_(name)
492         {}
493 
symbolsboost::spirit::karma::symbols494         symbols(symbols const& syms)
495           : base_type(terminal::make(reference_(*this)))
496           , add(*this)
497           , remove(*this)
498           , lookup(syms.lookup)
499           , name_(syms.name_)
500         {}
501 
502         template <typename CharEncoding_, typename Tag_>
symbolsboost::spirit::karma::symbols503         symbols(symbols<Attribute, unused_type, Lookup, CharEncoding_, Tag_> const& syms)
504           : base_type(terminal::make(reference_(*this)))
505           , add(*this)
506           , remove(*this)
507           , lookup(syms.lookup)
508           , name_(syms.name_)
509         {}
510 
511         template <typename Symbols, typename Data>
symbolsboost::spirit::karma::symbols512         symbols(Symbols const& syms, Data const& data
513               , std::string const& name = "symbols")
514           : base_type(terminal::make(reference_(*this)))
515           , add(*this)
516           , remove(*this)
517           , lookup(new Lookup())
518           , name_(name)
519         {
520             typename range_const_iterator<Symbols>::type si = boost::begin(syms);
521             typename range_const_iterator<Data>::type di = boost::begin(data);
522             while (si != boost::end(syms))
523                 add(*si++, *di++);
524         }
525 
526         symbols&
operator =boost::spirit::karma::symbols527         operator=(symbols const& rhs)
528         {
529             *lookup = *rhs.lookup;
530             name_ = rhs.name_;
531             return *this;
532         }
533 
534         template <typename CharEncoding_, typename Tag_>
535         symbols&
operator =boost::spirit::karma::symbols536         operator=(symbols<Attribute, unused_type, Lookup, CharEncoding_, Tag_> const& rhs)
537         {
538             *lookup = *rhs.lookup;
539             name_ = rhs.name_;
540             return *this;
541         }
542 
clearboost::spirit::karma::symbols543         void clear()
544         {
545             lookup->clear();
546         }
547 
548         struct adder;
549         struct remover;
550 
551         template <typename Attr>
552         adder const&
operator =boost::spirit::karma::symbols553         operator=(Attr const& attr)
554         {
555             lookup->clear();
556             return add(attr);
557         }
558 
559         template <typename Attr>
560         friend adder const&
operator +=(symbols & sym,Attr const & attr)561         operator+= (symbols& sym, Attr const& attr)
562         {
563             return sym.add(attr);
564         }
565 
566         template <typename Attr>
567         friend remover const&
operator -=(symbols & sym,Attr const & attr)568         operator-= (symbols& sym, Attr const& attr)
569         {
570             return sym.remove(attr);
571         }
572 
573         // non-const version needed to suppress proto's += kicking in
574         template <typename Attr>
575         friend adder const&
operator +=(symbols & sym,Attr & attr)576         operator+= (symbols& sym, Attr& attr)
577         {
578             return sym.add(attr);
579         }
580 
581         // non-const version needed to suppress proto's -= kicking in
582         template <typename Attr>
583         friend remover const&
operator -=(symbols & sym,Attr & attr)584         operator-= (symbols& sym, Attr& attr)
585         {
586             return sym.remove(attr);
587         }
588 
589         template <typename F>
for_eachboost::spirit::karma::symbols590         void for_each(F f) const
591         {
592             std::for_each(lookup->begin(), lookup->end(), f);
593         }
594 
595         template <typename Attr>
findboost::spirit::karma::symbols596         value_type const* find(Attr const& attr)
597         {
598             typename Lookup::iterator it = lookup->find(attr);
599             return (it != lookup->end()) ? &unused : 0;
600         }
601 
602         template <typename Attr>
atboost::spirit::karma::symbols603         value_type at(Attr const& attr)
604         {
605             typename Lookup::iterator it = lookup->find(attr);
606             if (it == lookup->end())
607                 add(attr);
608             return unused;
609         }
610 
611         ///////////////////////////////////////////////////////////////////////
612         template <typename OutputIterator, typename Context, typename Delimiter
613           , typename Attr>
generateboost::spirit::karma::symbols614         bool generate(OutputIterator& sink, Context&, Delimiter const& d
615           , Attr const& attr) const
616         {
617             typename Lookup::iterator it = lookup->find(
618                 traits::symbols_lookup<Attr, Attribute>::call(attr));
619             if (it == lookup->end())
620                 return false;
621 
622             return karma::detail::generate_encoded<CharEncoding, Tag>::
623                       call(sink
624                         , traits::symbols_lookup<Attr, Attribute>::call(attr)
625                         , unused) &&
626                    karma::delimit_out(sink, d);
627         }
628 
629         template <typename Context>
whatboost::spirit::karma::symbols630         info what(Context&) const
631         {
632             return info(name_);
633         }
634 
nameboost::spirit::karma::symbols635         void name(std::string const &str)
636         {
637             name_ = str;
638         }
nameboost::spirit::karma::symbols639         std::string const &name() const
640         {
641             return name_;
642         }
643 
644         ///////////////////////////////////////////////////////////////////////
645         struct adder
646         {
647             template <typename, typename = unused_type>
648             struct result { typedef adder const& type; };
649 
adderboost::spirit::karma::symbols::adder650             adder(symbols& sym)
651               : sym(sym)
652             {
653             }
654 
655             template <typename Attr>
656             adder const&
operator ()boost::spirit::karma::symbols::adder657             operator()(Attr const& attr) const
658             {
659                 sym.lookup->insert(attr);
660                 return *this;
661             }
662 
663             template <typename Attr>
664             adder const&
operator ,boost::spirit::karma::symbols::adder665             operator, (Attr const& attr) const
666             {
667                 sym.lookup->insert(attr);
668                 return *this;
669             }
670 
671             symbols& sym;
672 
673             // silence MSVC warning C4512: assignment operator could not be generated
674             BOOST_DELETED_FUNCTION(adder& operator= (adder const&))
675         };
676 
677         struct remover
678         {
679             template <typename>
680             struct result { typedef remover const& type; };
681 
removerboost::spirit::karma::symbols::remover682             remover(symbols& sym)
683               : sym(sym)
684             {
685             }
686 
687             template <typename Attr>
688             remover const&
operator ()boost::spirit::karma::symbols::remover689             operator()(Attr const& attr) const
690             {
691                 sym.lookup->erase(attr);
692                 return *this;
693             }
694 
695             template <typename Attr>
696             remover const&
operator ,boost::spirit::karma::symbols::remover697             operator, (Attr const& attr) const
698             {
699                 sym.lookup->erase(attr);
700                 return *this;
701             }
702 
703             symbols& sym;
704 
705             // silence MSVC warning C4512: assignment operator could not be generated
706             BOOST_DELETED_FUNCTION(remover& operator= (remover const&))
707         };
708 
709         adder add;
710         remover remove;
711         shared_ptr<Lookup> lookup;
712         std::string name_;
713     };
714 
715     ///////////////////////////////////////////////////////////////////////////
716     // Generator generators: make_xxx function (objects)
717     ///////////////////////////////////////////////////////////////////////////
718     template <typename Attribute, typename T, typename Lookup
719       , typename CharEnconding, typename Tag, typename Modifiers>
720     struct make_primitive<
721         reference<symbols<Attribute, T, Lookup, CharEnconding, Tag> >
722       , Modifiers>
723     {
724         static bool const lower =
725             has_modifier<Modifiers, tag::char_code_base<tag::lower> >::value;
726         static bool const upper =
727             has_modifier<Modifiers, tag::char_code_base<tag::upper> >::value;
728 
729         typedef reference<
730             symbols<Attribute, T, Lookup, CharEnconding, Tag>
731         > reference_;
732 
733         typedef typename mpl::if_c<
734             lower || upper
735           , symbols<
736                 Attribute, T, Lookup
737               , typename spirit::detail::get_encoding_with_case<
738                     Modifiers, unused_type, lower || upper>::type
739               , typename detail::get_casetag<Modifiers, lower || upper>::type>
740           , reference_>::type
741         result_type;
742 
operator ()boost::spirit::karma::make_primitive743         result_type operator()(reference_ ref, unused_type) const
744         {
745             return result_type(ref.ref.get());
746         }
747     };
748 }}}
749 
750 namespace boost { namespace spirit { namespace traits
751 {
752     ///////////////////////////////////////////////////////////////////////////
753     template <typename Attribute, typename T, typename Lookup
754       , typename CharEncoding, typename Tag
755       , typename Attr, typename Context, typename Iterator>
756     struct handles_container<karma::symbols<Attribute, T, Lookup, CharEncoding, Tag>
757             , Attr, Context, Iterator>
758       : traits::is_container<Attr> {};
759 }}}
760 
761 #if defined(BOOST_MSVC)
762 # pragma warning(pop)
763 #endif
764 
765 #endif
766 
767