stream.hpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  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. #if !defined(BOOST_SPIRIT_KARMA_STREAM_MAY_01_2007_0310PM)
  6. #define BOOST_SPIRIT_KARMA_STREAM_MAY_01_2007_0310PM
  7. #if defined(_MSC_VER)
  8. #pragma once
  9. #endif
  10. #include <boost/spirit/home/support/common_terminals.hpp>
  11. #include <boost/spirit/home/support/info.hpp>
  12. #include <boost/spirit/home/support/container.hpp>
  13. #include <boost/spirit/home/support/detail/hold_any.hpp>
  14. #include <boost/spirit/home/support/detail/get_encoding.hpp>
  15. #include <boost/spirit/home/support/detail/is_spirit_tag.hpp>
  16. #include <boost/spirit/home/karma/domain.hpp>
  17. #include <boost/spirit/home/karma/meta_compiler.hpp>
  18. #include <boost/spirit/home/karma/delimit_out.hpp>
  19. #include <boost/spirit/home/karma/auxiliary/lazy.hpp>
  20. #include <boost/spirit/home/karma/stream/detail/format_manip.hpp>
  21. #include <boost/spirit/home/karma/detail/generate_to.hpp>
  22. #include <boost/spirit/home/karma/detail/get_casetag.hpp>
  23. #include <boost/spirit/home/karma/detail/extract_from.hpp>
  24. #include <boost/fusion/include/at.hpp>
  25. #include <boost/fusion/include/vector.hpp>
  26. #include <boost/fusion/include/cons.hpp>
  27. #include <boost/core/enable_if.hpp>
  28. #include <boost/mpl/bool.hpp>
  29. #include <boost/type_traits/is_same.hpp>
  30. #include <ostream>
  31. ///////////////////////////////////////////////////////////////////////////////
  32. namespace boost { namespace spirit
  33. {
  34. namespace tag
  35. {
  36. template <typename Char = char>
  37. struct stream_tag
  38. {
  39. BOOST_SPIRIT_IS_TAG()
  40. };
  41. }
  42. namespace karma
  43. {
  44. ///////////////////////////////////////////////////////////////////////
  45. // This one is the class that the user can instantiate directly in
  46. // order to create a customized int generator
  47. template <typename Char = char>
  48. struct stream_generator
  49. : spirit::terminal<tag::stream_tag<Char> >
  50. {};
  51. }
  52. ///////////////////////////////////////////////////////////////////////////
  53. // Enablers
  54. ///////////////////////////////////////////////////////////////////////////
  55. template <>
  56. struct use_terminal<karma::domain, tag::stream> // enables stream
  57. : mpl::true_ {};
  58. template <>
  59. struct use_terminal<karma::domain, tag::wstream> // enables wstream
  60. : mpl::true_ {};
  61. template <typename A0>
  62. struct use_terminal<karma::domain // enables stream(...)
  63. , terminal_ex<tag::stream, fusion::vector1<A0> >
  64. > : mpl::true_ {};
  65. template <typename A0>
  66. struct use_terminal<karma::domain // enables wstream(...)
  67. , terminal_ex<tag::wstream, fusion::vector1<A0> >
  68. > : mpl::true_ {};
  69. template <> // enables stream(f)
  70. struct use_lazy_terminal<
  71. karma::domain, tag::stream, 1 /*arity*/
  72. > : mpl::true_ {};
  73. template <> // enables wstream(f)
  74. struct use_lazy_terminal<
  75. karma::domain, tag::wstream, 1 /*arity*/
  76. > : mpl::true_ {};
  77. // enables stream_generator<char_type>
  78. template <typename Char>
  79. struct use_terminal<karma::domain, tag::stream_tag<Char> >
  80. : mpl::true_ {};
  81. template <typename Char, typename A0>
  82. struct use_terminal<karma::domain
  83. , terminal_ex<tag::stream_tag<Char>, fusion::vector1<A0> >
  84. > : mpl::true_ {};
  85. template <typename Char>
  86. struct use_lazy_terminal<
  87. karma::domain, tag::stream_tag<Char>, 1 /*arity*/
  88. > : mpl::true_ {};
  89. }}
  90. ///////////////////////////////////////////////////////////////////////////////
  91. namespace boost { namespace spirit { namespace karma
  92. {
  93. #ifndef BOOST_SPIRIT_NO_PREDEFINED_TERMINALS
  94. using spirit::stream;
  95. using spirit::wstream;
  96. #endif
  97. using spirit::stream_type;
  98. using spirit::wstream_type;
  99. namespace detail
  100. {
  101. #ifdef _MSC_VER
  102. # pragma warning(push)
  103. # pragma warning(disable: 4512) // assignment operator could not be generated.
  104. #endif
  105. template <typename OutputIterator, typename Char, typename CharEncoding
  106. , typename Tag>
  107. struct psbuf : std::basic_streambuf<Char>
  108. {
  109. psbuf(OutputIterator& sink) : sink_(sink) {}
  110. protected:
  111. typename psbuf::int_type overflow(typename psbuf::int_type ch) BOOST_OVERRIDE
  112. {
  113. if (psbuf::traits_type::eq_int_type(ch, psbuf::traits_type::eof()))
  114. return psbuf::traits_type::not_eof(ch);
  115. return detail::generate_to(sink_, psbuf::traits_type::to_char_type(ch),
  116. CharEncoding(), Tag()) ? ch : psbuf::traits_type::eof();
  117. }
  118. private:
  119. OutputIterator& sink_;
  120. };
  121. #ifdef _MSC_VER
  122. # pragma warning(pop)
  123. #endif
  124. }
  125. ///////////////////////////////////////////////////////////////////////////
  126. template <typename Char, typename CharEncoding, typename Tag>
  127. struct any_stream_generator
  128. : primitive_generator<any_stream_generator<Char, CharEncoding, Tag> >
  129. {
  130. template <typename Context, typename Unused = unused_type>
  131. struct attribute
  132. {
  133. typedef spirit::basic_hold_any<Char> type;
  134. };
  135. // any_stream_generator has an attached attribute
  136. template <
  137. typename OutputIterator, typename Context, typename Delimiter
  138. , typename Attribute
  139. >
  140. static bool generate(OutputIterator& sink, Context& context
  141. , Delimiter const& d, Attribute const& attr)
  142. {
  143. if (!traits::has_optional_value(attr))
  144. return false;
  145. // use existing operator<<()
  146. typedef typename attribute<Context>::type attribute_type;
  147. {
  148. detail::psbuf<OutputIterator, Char, CharEncoding, Tag> pseudobuf(sink);
  149. std::basic_ostream<Char> ostr(&pseudobuf);
  150. ostr << traits::extract_from<attribute_type>(attr, context) << std::flush;
  151. if (!ostr.good())
  152. return false;
  153. }
  154. return karma::delimit_out(sink, d); // always do post-delimiting
  155. }
  156. // this is a special overload to detect if the output iterator has been
  157. // generated by a format_manip object.
  158. template <
  159. typename T, typename Traits, typename Properties, typename Context
  160. , typename Delimiter, typename Attribute
  161. >
  162. static bool generate(
  163. karma::detail::output_iterator<
  164. karma::ostream_iterator<T, Char, Traits>, Properties
  165. >& sink, Context& context, Delimiter const& d
  166. , Attribute const& attr)
  167. {
  168. typedef karma::detail::output_iterator<
  169. karma::ostream_iterator<T, Char, Traits>, Properties
  170. > output_iterator;
  171. if (!traits::has_optional_value(attr))
  172. return false;
  173. // use existing operator<<()
  174. typedef typename attribute<Context>::type attribute_type;
  175. {
  176. detail::psbuf<output_iterator, Char, CharEncoding, Tag> pseudobuf(sink);
  177. std::basic_ostream<Char> ostr(&pseudobuf);
  178. ostr.imbue(sink.get_ostream().getloc());
  179. ostr << traits::extract_from<attribute_type>(attr, context)
  180. << std::flush;
  181. if (!ostr.good())
  182. return false;
  183. }
  184. return karma::delimit_out(sink, d); // always do post-delimiting
  185. }
  186. // this any_stream has no parameter attached, it needs to have been
  187. // initialized from a value/variable
  188. template <typename OutputIterator, typename Context
  189. , typename Delimiter>
  190. static bool
  191. generate(OutputIterator&, Context&, Delimiter const&, unused_type)
  192. {
  193. // It is not possible (doesn't make sense) to use stream generators
  194. // without providing any attribute, as the generator doesn't 'know'
  195. // what to output. The following assertion fires if this situation
  196. // is detected in your code.
  197. BOOST_SPIRIT_ASSERT_FAIL(OutputIterator, stream_not_usable_without_attribute, ());
  198. return false;
  199. }
  200. template <typename Context>
  201. info what(Context& /*context*/) const
  202. {
  203. return info("stream");
  204. }
  205. };
  206. template <typename T, typename Char, typename CharEncoding, typename Tag>
  207. struct lit_stream_generator
  208. : primitive_generator<lit_stream_generator<T, Char, CharEncoding, Tag> >
  209. {
  210. template <typename Context, typename Unused>
  211. struct attribute
  212. {
  213. typedef unused_type type;
  214. };
  215. lit_stream_generator(typename add_reference<T>::type t)
  216. : t_(t)
  217. {}
  218. // lit_stream_generator has an attached parameter
  219. // this overload will be used in the normal case (not called from
  220. // format_manip).
  221. template <
  222. typename OutputIterator, typename Context, typename Delimiter
  223. , typename Attribute>
  224. bool generate(OutputIterator& sink, Context&, Delimiter const& d
  225. , Attribute const&) const
  226. {
  227. detail::psbuf<OutputIterator, Char, CharEncoding, Tag> pseudobuf(sink);
  228. std::basic_ostream<Char> ostr(&pseudobuf);
  229. ostr << t_ << std::flush; // use existing operator<<()
  230. if (ostr.good())
  231. return karma::delimit_out(sink, d); // always do post-delimiting
  232. return false;
  233. }
  234. // this is a special overload to detect if the output iterator has been
  235. // generated by a format_manip object.
  236. template <
  237. typename T1, typename Traits, typename Properties
  238. , typename Context, typename Delimiter, typename Attribute>
  239. bool generate(
  240. karma::detail::output_iterator<
  241. karma::ostream_iterator<T1, Char, Traits>, Properties
  242. >& sink, Context&, Delimiter const& d, Attribute const&) const
  243. {
  244. typedef karma::detail::output_iterator<
  245. karma::ostream_iterator<T1, Char, Traits>, Properties
  246. > output_iterator;
  247. {
  248. detail::psbuf<output_iterator, Char, CharEncoding, Tag> pseudobuf(sink);
  249. std::basic_ostream<Char> ostr(&pseudobuf);
  250. ostr.imbue(sink.get_ostream().getloc());
  251. ostr << t_ << std::flush; // use existing operator<<()
  252. if (!ostr.good())
  253. return false;
  254. }
  255. return karma::delimit_out(sink, d); // always do post-delimiting
  256. }
  257. template <typename Context>
  258. info what(Context& /*context*/) const
  259. {
  260. return info("any-stream");
  261. }
  262. T t_;
  263. };
  264. ///////////////////////////////////////////////////////////////////////////
  265. // Generator generators: make_xxx function (objects)
  266. ///////////////////////////////////////////////////////////////////////////
  267. template <typename Char, typename Modifiers>
  268. struct make_stream
  269. {
  270. static bool const lower =
  271. has_modifier<Modifiers, tag::char_code_base<tag::lower> >::value;
  272. static bool const upper =
  273. has_modifier<Modifiers, tag::char_code_base<tag::upper> >::value;
  274. typedef any_stream_generator<
  275. Char
  276. , typename spirit::detail::get_encoding_with_case<
  277. Modifiers, unused_type, lower || upper>::type
  278. , typename detail::get_casetag<Modifiers, lower || upper>::type
  279. > result_type;
  280. result_type operator()(unused_type, unused_type) const
  281. {
  282. return result_type();
  283. }
  284. };
  285. // stream
  286. template <typename Modifiers>
  287. struct make_primitive<tag::stream, Modifiers>
  288. : make_stream<char, Modifiers> {};
  289. // wstream
  290. template <typename Modifiers>
  291. struct make_primitive<tag::wstream, Modifiers>
  292. : make_stream<wchar_t, Modifiers> {};
  293. // any_stream_generator<char_type>
  294. template <typename Char, typename Modifiers>
  295. struct make_primitive<tag::stream_tag<Char>, Modifiers>
  296. : make_stream<Char, Modifiers> {};
  297. ///////////////////////////////////////////////////////////////////////////
  298. template <typename Char, typename A0, typename Modifiers>
  299. struct make_any_stream
  300. {
  301. static bool const lower =
  302. has_modifier<Modifiers, tag::char_code_base<tag::lower> >::value;
  303. static bool const upper =
  304. has_modifier<Modifiers, tag::char_code_base<tag::upper> >::value;
  305. typedef typename add_const<A0>::type const_attribute;
  306. typedef lit_stream_generator<
  307. const_attribute, Char
  308. , typename spirit::detail::get_encoding_with_case<
  309. Modifiers, unused_type, lower || upper>::type
  310. , typename detail::get_casetag<Modifiers, lower || upper>::type
  311. > result_type;
  312. template <typename Terminal>
  313. result_type operator()(Terminal const& term, unused_type) const
  314. {
  315. return result_type(fusion::at_c<0>(term.args));
  316. }
  317. };
  318. // stream(...)
  319. template <typename Modifiers, typename A0>
  320. struct make_primitive<
  321. terminal_ex<tag::stream, fusion::vector1<A0> >, Modifiers>
  322. : make_any_stream<char, A0, Modifiers> {};
  323. // wstream(...)
  324. template <typename Modifiers, typename A0>
  325. struct make_primitive<
  326. terminal_ex<tag::wstream, fusion::vector1<A0> >, Modifiers>
  327. : make_any_stream<wchar_t, A0, Modifiers> {};
  328. // any_stream_generator<char_type>(...)
  329. template <typename Char, typename Modifiers, typename A0>
  330. struct make_primitive<
  331. terminal_ex<tag::stream_tag<Char>, fusion::vector1<A0> >
  332. , Modifiers>
  333. : make_any_stream<Char, A0, Modifiers> {};
  334. }}}
  335. #endif