• 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 #ifndef BOOST_SPIRIT_KARMA_DIRECTIVE_BUFFER_HPP
7 #define BOOST_SPIRIT_KARMA_DIRECTIVE_BUFFER_HPP
8 
9 #if defined(_MSC_VER)
10 #pragma once
11 #endif
12 
13 #include <boost/spirit/home/karma/meta_compiler.hpp>
14 #include <boost/spirit/home/karma/generator.hpp>
15 #include <boost/spirit/home/karma/domain.hpp>
16 #include <boost/spirit/home/karma/detail/output_iterator.hpp>
17 #include <boost/spirit/home/support/unused.hpp>
18 #include <boost/spirit/home/support/info.hpp>
19 #include <boost/spirit/home/support/common_terminals.hpp>
20 #include <boost/spirit/home/support/has_semantic_action.hpp>
21 #include <boost/spirit/home/support/handles_container.hpp>
22 #include <boost/spirit/home/karma/detail/attributes.hpp>
23 
24 namespace boost { namespace spirit
25 {
26     ///////////////////////////////////////////////////////////////////////////
27     // Enablers
28     ///////////////////////////////////////////////////////////////////////////
29     template <>
30     struct use_directive<karma::domain, tag::buffer> // enables buffer
31       : mpl::true_ {};
32 
33 }}
34 
35 namespace boost { namespace spirit { namespace karma
36 {
37 #ifndef BOOST_SPIRIT_NO_PREDEFINED_TERMINALS
38     using spirit::buffer;
39 #endif
40     using spirit::buffer_type;
41 
42     ///////////////////////////////////////////////////////////////////////////
43     // buffer_directive buffers all generated output of the embedded generator
44     // and flushes it only if the whole embedded generator succeeds
45     ///////////////////////////////////////////////////////////////////////////
46     template <typename Subject>
47     struct buffer_directive : unary_generator<buffer_directive<Subject> >
48     {
49         typedef Subject subject_type;
50         typedef mpl::int_<
51             subject_type::properties::value |
52             generator_properties::countingbuffer
53         > properties;
54 
buffer_directiveboost::spirit::karma::buffer_directive55         buffer_directive(Subject const& subject)
56           : subject(subject) {}
57 
58         template <typename Context, typename Iterator>
59         struct attribute
60           : traits::attribute_of<subject_type, Context, Iterator>
61         {};
62 
63         template <typename OutputIterator, typename Context, typename Delimiter
64           , typename Attribute>
generateboost::spirit::karma::buffer_directive65         bool generate(OutputIterator& sink, Context& ctx, Delimiter const& d
66           , Attribute const& attr) const
67         {
68             // wrap the given output iterator to avoid output as long as the
69             // embedded generator (subject) fails
70             detail::enable_buffering<OutputIterator> buffering(sink);
71             bool r = false;
72             {
73                 detail::disable_counting<OutputIterator> nocounting(sink);
74                 r = subject.generate(sink, ctx, d, attr);
75             }
76             if (r)
77                 buffering.buffer_copy();
78             return r;
79         }
80 
81         template <typename Context>
whatboost::spirit::karma::buffer_directive82         info what(Context& context) const
83         {
84             return info("buffer", subject.what(context));
85         }
86 
87         Subject subject;
88     };
89 
90     ///////////////////////////////////////////////////////////////////////////
91     // Generator generators: make_xxx function (objects)
92     ///////////////////////////////////////////////////////////////////////////
93     template <typename Subject, typename Modifiers>
94     struct make_directive<tag::buffer, Subject, Modifiers>
95     {
96         typedef buffer_directive<Subject> result_type;
operator ()boost::spirit::karma::make_directive97         result_type operator()(unused_type, Subject const& subject
98           , unused_type) const
99         {
100             return result_type(subject);
101         }
102     };
103 
104     // make sure buffer[buffer[...]] does not result in double buffering
105     template <typename Subject, typename Modifiers>
106     struct make_directive<tag::buffer, buffer_directive<Subject>, Modifiers>
107     {
108         typedef buffer_directive<Subject> result_type;
operator ()boost::spirit::karma::make_directive109         result_type operator()(unused_type
110           , buffer_directive<Subject> const& subject, unused_type) const
111         {
112             return subject;
113         }
114     };
115 }}}
116 
117 namespace boost { namespace spirit { namespace traits
118 {
119     ///////////////////////////////////////////////////////////////////////////
120     template <typename Subject>
121     struct has_semantic_action<karma::buffer_directive<Subject> >
122       : unary_has_semantic_action<Subject> {};
123 
124     ///////////////////////////////////////////////////////////////////////////
125     template <typename Subject, typename Attribute, typename Context
126         , typename Iterator>
127     struct handles_container<karma::buffer_directive<Subject>, Attribute
128         , Context, Iterator>
129       : unary_handles_container<Subject, Attribute, Context, Iterator> {};
130 }}}
131 
132 #endif
133