1 // Copyright (c) 2001-2011 Joel de Guzman 2 // Copyright (c) 2001-2011 Hartmut Kaiser 3 // 4 // Distributed under the Boost Software License, Version 1.0. (See accompanying 5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 7 #if !defined(BOOST_SPIRIT_KARMA_POSITIVE_MAR_03_2007_0945PM) 8 #define BOOST_SPIRIT_KARMA_POSITIVE_MAR_03_2007_0945PM 9 10 #if defined(_MSC_VER) 11 #pragma once 12 #endif 13 14 #include <boost/spirit/home/karma/domain.hpp> 15 #include <boost/spirit/home/karma/generator.hpp> 16 #include <boost/spirit/home/karma/meta_compiler.hpp> 17 #include <boost/spirit/home/karma/detail/indirect_iterator.hpp> 18 #include <boost/spirit/home/karma/detail/output_iterator.hpp> 19 #include <boost/spirit/home/karma/detail/get_stricttag.hpp> 20 #include <boost/spirit/home/karma/detail/pass_container.hpp> 21 #include <boost/spirit/home/karma/detail/fail_function.hpp> 22 #include <boost/spirit/home/support/info.hpp> 23 #include <boost/spirit/home/support/unused.hpp> 24 #include <boost/spirit/home/support/container.hpp> 25 #include <boost/spirit/home/support/has_semantic_action.hpp> 26 #include <boost/spirit/home/support/handles_container.hpp> 27 #include <boost/spirit/home/karma/detail/attributes.hpp> 28 #include <boost/proto/operators.hpp> 29 #include <boost/proto/tags.hpp> 30 #include <boost/type_traits/add_const.hpp> 31 32 namespace boost { namespace spirit 33 { 34 /////////////////////////////////////////////////////////////////////////// 35 // Enablers 36 /////////////////////////////////////////////////////////////////////////// 37 template <> 38 struct use_operator<karma::domain, proto::tag::unary_plus> // enables +g 39 : mpl::true_ {}; 40 }} 41 42 /////////////////////////////////////////////////////////////////////////////// 43 namespace boost { namespace spirit { namespace karma 44 { 45 template <typename Subject, typename Strict, typename Derived> 46 struct base_plus : unary_generator<Derived> 47 { 48 private: 49 // Ignore return value in relaxed mode (failing subject generators 50 // are just skipped). This allows to selectively generate items in 51 // the provided attribute. 52 template <typename F, typename Attribute> generate_subjectboost::spirit::karma::base_plus53 bool generate_subject(F f, Attribute const&, bool& result, mpl::false_) const 54 { 55 bool r = !f(subject); 56 if (r) 57 result = true; 58 else if (!f.is_at_end()) 59 f.next(); 60 return true; 61 } 62 63 template <typename F, typename Attribute> generate_subjectboost::spirit::karma::base_plus64 bool generate_subject(F f, Attribute const&, bool& result, mpl::true_) const 65 { 66 bool r = !f(subject); 67 if (r) 68 result = true; 69 return r; 70 } 71 72 // There is no way to distinguish a failed generator from a 73 // generator to be skipped. We assume the user takes responsibility 74 // for ending the loop if no attribute is specified. 75 template <typename F> generate_subjectboost::spirit::karma::base_plus76 bool generate_subject(F f, unused_type, bool& result, mpl::false_) const 77 { 78 bool r = f(subject); 79 if (!r) 80 result = true; 81 return !r; 82 } 83 84 // template <typename F> 85 // bool generate_subject(F f, unused_type, bool& result, mpl::true_) const 86 // { 87 // bool r = f(subject); 88 // if (!r) 89 // result = true; 90 // return !r; 91 // } 92 93 public: 94 typedef Subject subject_type; 95 typedef typename subject_type::properties properties; 96 97 // Build a std::vector from the subjects attribute. Note 98 // that build_std_vector may return unused_type if the 99 // subject's attribute is an unused_type. 100 template <typename Context, typename Iterator> 101 struct attribute 102 : traits::build_std_vector< 103 typename traits::attribute_of<subject_type, Context, Iterator>::type 104 > 105 {}; 106 base_plusboost::spirit::karma::base_plus107 base_plus(Subject const& subject) 108 : subject(subject) {} 109 110 template < 111 typename OutputIterator, typename Context, typename Delimiter 112 , typename Attribute> generateboost::spirit::karma::base_plus113 bool generate(OutputIterator& sink, Context& ctx 114 , Delimiter const& d, Attribute const& attr) const 115 { 116 typedef detail::fail_function< 117 OutputIterator, Context, Delimiter> fail_function; 118 119 typedef typename traits::container_iterator< 120 typename add_const<Attribute>::type 121 >::type iterator_type; 122 123 typedef 124 typename traits::make_indirect_iterator<iterator_type>::type 125 indirect_iterator_type; 126 typedef detail::pass_container< 127 fail_function, Attribute, indirect_iterator_type, mpl::false_> 128 pass_container; 129 130 iterator_type it = traits::begin(attr); 131 iterator_type end = traits::end(attr); 132 133 // plus fails if the parameter is empty 134 if (traits::compare(it, end)) 135 return false; 136 137 pass_container pass(fail_function(sink, ctx, d), 138 indirect_iterator_type(it), indirect_iterator_type(end)); 139 140 // from now on plus fails if the underlying output fails or overall 141 // no subject generators succeeded 142 bool result = false; 143 while (!pass.is_at_end()) 144 { 145 if (!generate_subject(pass, attr, result, Strict())) 146 break; 147 } 148 return result && detail::sink_is_good(sink); 149 } 150 151 template <typename Context> whatboost::spirit::karma::base_plus152 info what(Context& context) const 153 { 154 return info("plus", subject.what(context)); 155 } 156 157 Subject subject; 158 }; 159 160 template <typename Subject> 161 struct plus 162 : base_plus<Subject, mpl::false_, plus<Subject> > 163 { 164 typedef base_plus<Subject, mpl::false_, plus> base_plus_; 165 plusboost::spirit::karma::plus166 plus(Subject const& subject) 167 : base_plus_(subject) {} 168 }; 169 170 template <typename Subject> 171 struct strict_plus 172 : base_plus<Subject, mpl::true_, strict_plus<Subject> > 173 { 174 typedef base_plus<Subject, mpl::true_, strict_plus> base_plus_; 175 strict_plusboost::spirit::karma::strict_plus176 strict_plus(Subject const& subject) 177 : base_plus_(subject) {} 178 }; 179 180 /////////////////////////////////////////////////////////////////////////// 181 // Generator generators: make_xxx function (objects) 182 /////////////////////////////////////////////////////////////////////////// 183 namespace detail 184 { 185 template <typename Elements, bool strict_mode = false> 186 struct make_plus 187 : make_unary_composite<Elements, plus> 188 {}; 189 190 template <typename Elements> 191 struct make_plus<Elements, true> 192 : make_unary_composite<Elements, strict_plus> 193 {}; 194 } 195 196 template <typename Elements, typename Modifiers> 197 struct make_composite<proto::tag::unary_plus, Elements, Modifiers> 198 : detail::make_plus<Elements, detail::get_stricttag<Modifiers>::value> 199 {}; 200 }}} 201 202 namespace boost { namespace spirit { namespace traits 203 { 204 /////////////////////////////////////////////////////////////////////////// 205 template <typename Subject> 206 struct has_semantic_action<karma::plus<Subject> > 207 : unary_has_semantic_action<Subject> {}; 208 209 template <typename Subject> 210 struct has_semantic_action<karma::strict_plus<Subject> > 211 : unary_has_semantic_action<Subject> {}; 212 213 /////////////////////////////////////////////////////////////////////////// 214 template <typename Subject, typename Attribute, typename Context 215 , typename Iterator> 216 struct handles_container<karma::plus<Subject>, Attribute 217 , Context, Iterator> 218 : mpl::true_ {}; 219 220 template <typename Subject, typename Attribute, typename Context 221 , typename Iterator> 222 struct handles_container<karma::strict_plus<Subject>, Attribute 223 , Context, Iterator> 224 : mpl::true_ {}; 225 }}} 226 227 #endif 228