stream.hpp 13 KB

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