stream.hpp 14 KB

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