output_iterator.hpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650
  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_OUTPUT_ITERATOR_MAY_26_2007_0506PM)
  6. #define BOOST_SPIRIT_KARMA_OUTPUT_ITERATOR_MAY_26_2007_0506PM
  7. #if defined(_MSC_VER)
  8. #pragma once
  9. #endif
  10. #include <iterator>
  11. #include <vector>
  12. #include <algorithm>
  13. #include <boost/config.hpp>
  14. #include <boost/noncopyable.hpp>
  15. #include <boost/mpl/if.hpp>
  16. #include <boost/spirit/home/karma/generator.hpp>
  17. #include <boost/spirit/home/support/iterators/ostream_iterator.hpp>
  18. #include <boost/spirit/home/support/unused.hpp>
  19. #if defined(BOOST_MSVC) && defined(BOOST_SPIRIT_UNICODE)
  20. #include <boost/spirit/home/support/char_encoding/unicode.hpp>
  21. #endif
  22. namespace boost { namespace spirit { namespace karma { namespace detail
  23. {
  24. ///////////////////////////////////////////////////////////////////////////
  25. // This class is used to keep track of the current position in the output.
  26. ///////////////////////////////////////////////////////////////////////////
  27. class position_sink
  28. {
  29. public:
  30. position_sink() : count(0), line(1), column(1) {}
  31. void tidy() { count = 0; line = 1; column = 1; }
  32. template <typename T>
  33. void output(T const& value)
  34. {
  35. ++count;
  36. if (value == '\n') {
  37. ++line;
  38. column = 1;
  39. }
  40. else {
  41. ++column;
  42. }
  43. }
  44. std::size_t get_count() const { return count; }
  45. std::size_t get_line() const { return line; }
  46. std::size_t get_column() const { return column; }
  47. private:
  48. std::size_t count;
  49. std::size_t line;
  50. std::size_t column;
  51. };
  52. ///////////////////////////////////////////////////////////////////////////
  53. struct position_policy
  54. {
  55. position_policy() {}
  56. position_policy(position_policy const& rhs)
  57. : track_position_data(rhs.track_position_data) {}
  58. template <typename T>
  59. void output(T const& value)
  60. {
  61. // track position in the output
  62. track_position_data.output(value);
  63. }
  64. // return the current count in the output
  65. std::size_t get_out_count() const
  66. {
  67. return track_position_data.get_count();
  68. }
  69. // return the current line in the output
  70. std::size_t get_line() const
  71. {
  72. return track_position_data.get_line();
  73. }
  74. // return the current column in the output
  75. std::size_t get_column() const
  76. {
  77. return track_position_data.get_column();
  78. }
  79. private:
  80. position_sink track_position_data; // for position tracking
  81. };
  82. struct no_position_policy
  83. {
  84. no_position_policy() {}
  85. no_position_policy(no_position_policy const&) {}
  86. template <typename T>
  87. void output(T const& /*value*/) {}
  88. };
  89. ///////////////////////////////////////////////////////////////////////////
  90. // This class is used to count the number of characters streamed into the
  91. // output.
  92. ///////////////////////////////////////////////////////////////////////////
  93. template <typename OutputIterator>
  94. class counting_sink : boost::noncopyable
  95. {
  96. public:
  97. counting_sink(OutputIterator& sink_, std::size_t count_ = 0
  98. , bool enabled = true)
  99. : count(count_), initial_count(count), prev_count(0), sink(sink_)
  100. {
  101. prev_count = sink.chain_counting(enabled ? this : NULL);
  102. }
  103. ~counting_sink()
  104. {
  105. if (prev_count) // propagate count
  106. prev_count->update_count(count-initial_count);
  107. sink.chain_counting(prev_count);
  108. }
  109. void output()
  110. {
  111. ++count;
  112. }
  113. std::size_t get_count() const { return count; }
  114. // propagate count from embedded counters
  115. void update_count(std::size_t c)
  116. {
  117. count += c;
  118. }
  119. private:
  120. std::size_t count;
  121. std::size_t initial_count;
  122. counting_sink* prev_count; // previous counter in chain
  123. OutputIterator& sink;
  124. };
  125. ///////////////////////////////////////////////////////////////////////////
  126. template <typename OutputIterator>
  127. struct counting_policy
  128. {
  129. public:
  130. counting_policy() : count(NULL) {}
  131. counting_policy(counting_policy const& rhs) : count(rhs.count) {}
  132. // functions related to counting
  133. counting_sink<OutputIterator>* chain_counting(
  134. counting_sink<OutputIterator>* count_data)
  135. {
  136. counting_sink<OutputIterator>* prev_count = count;
  137. count = count_data;
  138. return prev_count;
  139. }
  140. template <typename T>
  141. void output(T const&)
  142. {
  143. // count characters, if appropriate
  144. if (NULL != count)
  145. count->output();
  146. }
  147. private:
  148. counting_sink<OutputIterator>* count; // for counting
  149. };
  150. struct no_counting_policy
  151. {
  152. no_counting_policy() {}
  153. no_counting_policy(no_counting_policy const&) {}
  154. template <typename T>
  155. void output(T const& /*value*/) {}
  156. };
  157. ///////////////////////////////////////////////////////////////////////////
  158. // The following classes are used to intercept the output into a buffer
  159. // allowing to do things like alignment, character escaping etc.
  160. ///////////////////////////////////////////////////////////////////////////
  161. class buffer_sink : boost::noncopyable
  162. {
  163. // wchar_t is only 16-bits on Windows. If BOOST_SPIRIT_UNICODE is
  164. // defined, the character type is 32-bits wide so we need to make
  165. // sure the buffer is at least that wide.
  166. #if (defined(_MSC_VER) || defined(__SIZEOF_WCHAR_T__) && __SIZEOF_WCHAR_T__ == 2) && defined(BOOST_SPIRIT_UNICODE)
  167. typedef spirit::char_encoding::unicode::char_type buffer_char_type;
  168. #else
  169. typedef wchar_t buffer_char_type;
  170. #endif
  171. public:
  172. buffer_sink()
  173. : width(0) {}
  174. ~buffer_sink()
  175. {
  176. tidy();
  177. }
  178. void enable(std::size_t width_)
  179. {
  180. tidy(); // release existing buffer
  181. width = (width_ == std::size_t(-1)) ? 0 : width_;
  182. buffer.reserve(width);
  183. }
  184. void tidy()
  185. {
  186. buffer.clear();
  187. width = 0;
  188. }
  189. template <typename T>
  190. void output(T const& value)
  191. {
  192. BOOST_STATIC_ASSERT(sizeof(T) <= sizeof(buffer_char_type));
  193. buffer.push_back(value);
  194. }
  195. template <typename OutputIterator_>
  196. bool copy(OutputIterator_& sink, std::size_t maxwidth) const
  197. {
  198. #if defined(BOOST_MSVC)
  199. #pragma warning(push)
  200. #pragma warning(disable: 4267)
  201. #endif
  202. typename std::basic_string<buffer_char_type>::const_iterator end =
  203. buffer.begin() + (std::min)(buffer.size(), maxwidth);
  204. #if defined(BOOST_MSVC)
  205. #pragma warning(disable: 4244) // conversion from 'x' to 'y', possible loss of data
  206. #endif
  207. std::copy(buffer.begin(), end, sink);
  208. #if defined(BOOST_MSVC)
  209. #pragma warning(pop)
  210. #endif
  211. return true;
  212. }
  213. template <typename RestIterator>
  214. bool copy_rest(RestIterator& sink, std::size_t start_at) const
  215. {
  216. #if defined(BOOST_MSVC)
  217. #pragma warning(push)
  218. #pragma warning(disable: 4267)
  219. #endif
  220. typename std::basic_string<buffer_char_type>::const_iterator begin =
  221. buffer.begin() + (std::min)(buffer.size(), start_at);
  222. #if defined(BOOST_MSVC)
  223. #pragma warning(disable: 4244) // conversion from 'x' to 'y', possible loss of data
  224. #endif
  225. std::copy(begin, buffer.end(), sink);
  226. #if defined(BOOST_MSVC)
  227. #pragma warning(pop)
  228. #endif
  229. return true;
  230. }
  231. std::size_t buffer_size() const
  232. {
  233. return buffer.size();
  234. }
  235. private:
  236. std::size_t width;
  237. std::basic_string<buffer_char_type> buffer;
  238. };
  239. ///////////////////////////////////////////////////////////////////////////
  240. struct buffering_policy
  241. {
  242. public:
  243. buffering_policy() : buffer(NULL) {}
  244. buffering_policy(buffering_policy const& rhs) : buffer(rhs.buffer) {}
  245. // functions related to buffering
  246. buffer_sink* chain_buffering(buffer_sink* buffer_data)
  247. {
  248. buffer_sink* prev_buffer = buffer;
  249. buffer = buffer_data;
  250. return prev_buffer;
  251. }
  252. template <typename T>
  253. bool output(T const& value)
  254. {
  255. // buffer characters, if appropriate
  256. if (NULL != buffer) {
  257. buffer->output(value);
  258. return false;
  259. }
  260. return true;
  261. }
  262. bool has_buffer() const { return NULL != buffer; }
  263. private:
  264. buffer_sink* buffer;
  265. };
  266. struct no_buffering_policy
  267. {
  268. no_buffering_policy() {}
  269. no_buffering_policy(no_buffering_policy const&) {}
  270. template <typename T>
  271. bool output(T const& /*value*/)
  272. {
  273. return true;
  274. }
  275. bool has_buffer() const { return false; }
  276. };
  277. ///////////////////////////////////////////////////////////////////////////
  278. // forward declaration only
  279. template <typename OutputIterator>
  280. struct enable_buffering;
  281. template <typename OutputIterator, typename Properties
  282. , typename Derived = unused_type>
  283. class output_iterator;
  284. ///////////////////////////////////////////////////////////////////////////
  285. template <typename Buffering, typename Counting, typename Tracking>
  286. struct output_iterator_base : Buffering, Counting, Tracking
  287. {
  288. typedef Buffering buffering_policy;
  289. typedef Counting counting_policy;
  290. typedef Tracking tracking_policy;
  291. output_iterator_base() {}
  292. output_iterator_base(output_iterator_base const& rhs)
  293. : buffering_policy(rhs), counting_policy(rhs), tracking_policy(rhs)
  294. {}
  295. template <typename T>
  296. bool output(T const& value)
  297. {
  298. this->counting_policy::output(value);
  299. this->tracking_policy::output(value);
  300. return this->buffering_policy::output(value);
  301. }
  302. };
  303. template <typename Buffering, typename Counting, typename Tracking>
  304. struct disabling_output_iterator : Buffering, Counting, Tracking
  305. {
  306. typedef Buffering buffering_policy;
  307. typedef Counting counting_policy;
  308. typedef Tracking tracking_policy;
  309. disabling_output_iterator() : do_output(true) {}
  310. disabling_output_iterator(disabling_output_iterator const& rhs)
  311. : buffering_policy(rhs), counting_policy(rhs), tracking_policy(rhs)
  312. , do_output(rhs.do_output)
  313. {}
  314. template <typename T>
  315. bool output(T const& value)
  316. {
  317. if (!do_output)
  318. return false;
  319. this->counting_policy::output(value);
  320. this->tracking_policy::output(value);
  321. return this->buffering_policy::output(value);
  322. }
  323. bool do_output;
  324. };
  325. ///////////////////////////////////////////////////////////////////////////
  326. template <typename OutputIterator, typename Properties, typename Derived>
  327. struct make_output_iterator
  328. {
  329. // get the most derived type of this class
  330. typedef typename mpl::if_<
  331. traits::not_is_unused<Derived>, Derived
  332. , output_iterator<OutputIterator, Properties, Derived>
  333. >::type most_derived_type;
  334. static const generator_properties::enum_type properties = static_cast<generator_properties::enum_type>(Properties::value);
  335. typedef typename mpl::if_c<
  336. (properties & generator_properties::tracking) ? true : false
  337. , position_policy, no_position_policy
  338. >::type tracking_type;
  339. typedef typename mpl::if_c<
  340. (properties & generator_properties::buffering) ? true : false
  341. , buffering_policy, no_buffering_policy
  342. >::type buffering_type;
  343. typedef typename mpl::if_c<
  344. (properties & generator_properties::counting) ? true : false
  345. , counting_policy<most_derived_type>, no_counting_policy
  346. >::type counting_type;
  347. typedef typename mpl::if_c<
  348. (properties & generator_properties::disabling) ? true : false
  349. , disabling_output_iterator<buffering_type, counting_type, tracking_type>
  350. , output_iterator_base<buffering_type, counting_type, tracking_type>
  351. >::type type;
  352. };
  353. ///////////////////////////////////////////////////////////////////////////
  354. // Karma uses an output iterator wrapper for all output operations. This
  355. // is necessary to avoid the dreaded 'scanner business' problem, i.e. the
  356. // dependency of rules and grammars on the used output iterator.
  357. //
  358. // By default the user supplied output iterator is wrapped inside an
  359. // instance of this internal output_iterator class.
  360. //
  361. // This output_iterator class normally just forwards to the embedded user
  362. // supplied iterator. But it is possible to enable additional functionality
  363. // on demand, such as counting, buffering, and position tracking.
  364. ///////////////////////////////////////////////////////////////////////////
  365. template <typename OutputIterator, typename Properties, typename Derived>
  366. class output_iterator
  367. : public make_output_iterator<OutputIterator, Properties, Derived>::type
  368. {
  369. private:
  370. // base iterator type
  371. typedef typename make_output_iterator<
  372. OutputIterator, Properties, Derived>::type base_iterator;
  373. public:
  374. typedef std::output_iterator_tag iterator_category;
  375. typedef void value_type;
  376. typedef void difference_type;
  377. typedef void pointer;
  378. typedef void reference;
  379. explicit output_iterator(OutputIterator& sink_)
  380. : sink(&sink_)
  381. {}
  382. output_iterator(output_iterator const& rhs)
  383. : base_iterator(rhs), sink(rhs.sink)
  384. {}
  385. output_iterator& operator*() { return *this; }
  386. output_iterator& operator++()
  387. {
  388. if (!this->base_iterator::has_buffer())
  389. ++(*sink); // increment only if not buffering
  390. return *this;
  391. }
  392. output_iterator operator++(int)
  393. {
  394. if (!this->base_iterator::has_buffer()) {
  395. output_iterator t(*this);
  396. ++(*sink);
  397. return t;
  398. }
  399. return *this;
  400. }
  401. #if defined(BOOST_MSVC)
  402. // 'argument' : conversion from '...' to '...', possible loss of data
  403. #pragma warning (push)
  404. #pragma warning (disable: 4244)
  405. #endif
  406. template <typename T>
  407. void operator=(T const& value)
  408. {
  409. if (this->base_iterator::output(value))
  410. *(*sink) = value;
  411. }
  412. #if defined(BOOST_MSVC)
  413. #pragma warning (pop)
  414. #endif
  415. // plain output iterators are considered to be good all the time
  416. bool good() const { return true; }
  417. // allow to access underlying output iterator
  418. OutputIterator& base() { return *sink; }
  419. protected:
  420. // this is the wrapped user supplied output iterator
  421. OutputIterator* sink;
  422. };
  423. ///////////////////////////////////////////////////////////////////////////
  424. template <typename T, typename Elem, typename Traits, typename Properties>
  425. class output_iterator<karma::ostream_iterator<T, Elem, Traits>, Properties>
  426. : public output_iterator<karma::ostream_iterator<T, Elem, Traits>, Properties
  427. , output_iterator<karma::ostream_iterator<T, Elem, Traits>, Properties> >
  428. {
  429. private:
  430. typedef output_iterator<karma::ostream_iterator<T, Elem, Traits>, Properties
  431. , output_iterator<karma::ostream_iterator<T, Elem, Traits>, Properties>
  432. > base_type;
  433. typedef karma::ostream_iterator<T, Elem, Traits> base_iterator_type;
  434. typedef std::basic_ostream<Elem, Traits> ostream_type;
  435. public:
  436. output_iterator(base_iterator_type& sink)
  437. : base_type(sink) {}
  438. ostream_type& get_ostream() { return (*this->sink).get_ostream(); }
  439. ostream_type const& get_ostream() const { return (*this->sink).get_ostream(); }
  440. // expose good bit of underlying stream object
  441. bool good() const { return (*this->sink).get_ostream().good(); }
  442. };
  443. ///////////////////////////////////////////////////////////////////////////
  444. // Helper class for exception safe enabling of character counting in the
  445. // output iterator
  446. ///////////////////////////////////////////////////////////////////////////
  447. template <typename OutputIterator>
  448. struct enable_counting
  449. {
  450. enable_counting(OutputIterator& sink_, std::size_t count = 0)
  451. : count_data(sink_, count) {}
  452. // get number of characters counted since last enable
  453. std::size_t count() const
  454. {
  455. return count_data.get_count();
  456. }
  457. private:
  458. counting_sink<OutputIterator> count_data; // for counting
  459. };
  460. template <typename OutputIterator>
  461. struct disable_counting
  462. {
  463. disable_counting(OutputIterator& sink_)
  464. : count_data(sink_, 0, false) {}
  465. private:
  466. counting_sink<OutputIterator> count_data;
  467. };
  468. ///////////////////////////////////////////////////////////////////////////
  469. // Helper class for exception safe enabling of character buffering in the
  470. // output iterator
  471. ///////////////////////////////////////////////////////////////////////////
  472. template <typename OutputIterator>
  473. struct enable_buffering
  474. {
  475. enable_buffering(OutputIterator& sink_
  476. , std::size_t width = std::size_t(-1))
  477. : sink(sink_), prev_buffer(NULL), enabled(false)
  478. {
  479. buffer_data.enable(width);
  480. prev_buffer = sink.chain_buffering(&buffer_data);
  481. enabled = true;
  482. }
  483. ~enable_buffering()
  484. {
  485. disable();
  486. }
  487. // reset buffer chain to initial state
  488. void disable()
  489. {
  490. if (enabled) {
  491. BOOST_VERIFY(&buffer_data == sink.chain_buffering(prev_buffer));
  492. enabled = false;
  493. }
  494. }
  495. // copy to the underlying sink whatever is in the local buffer
  496. bool buffer_copy(std::size_t maxwidth = std::size_t(-1)
  497. , bool disable_ = true)
  498. {
  499. if (disable_)
  500. disable();
  501. return buffer_data.copy(sink, maxwidth) && sink.good();
  502. }
  503. // return number of characters stored in the buffer
  504. std::size_t buffer_size() const
  505. {
  506. return buffer_data.buffer_size();
  507. }
  508. // copy to the remaining characters to the specified sink
  509. template <typename RestIterator>
  510. bool buffer_copy_rest(RestIterator& sink, std::size_t start_at = 0) const
  511. {
  512. return buffer_data.copy_rest(sink, start_at);
  513. }
  514. // copy the contents to the given output iterator
  515. template <typename OutputIterator_>
  516. bool buffer_copy_to(OutputIterator_& sink
  517. , std::size_t maxwidth = std::size_t(-1)) const
  518. {
  519. return buffer_data.copy(sink, maxwidth);
  520. }
  521. private:
  522. OutputIterator& sink;
  523. buffer_sink buffer_data; // for buffering
  524. buffer_sink* prev_buffer; // previous buffer in chain
  525. bool enabled;
  526. };
  527. ///////////////////////////////////////////////////////////////////////////
  528. // Helper class for exception safe disabling of output
  529. ///////////////////////////////////////////////////////////////////////////
  530. template <typename OutputIterator>
  531. struct disable_output
  532. {
  533. disable_output(OutputIterator& sink_)
  534. : sink(sink_), prev_do_output(sink.do_output)
  535. {
  536. sink.do_output = false;
  537. }
  538. ~disable_output()
  539. {
  540. sink.do_output = prev_do_output;
  541. }
  542. OutputIterator& sink;
  543. bool prev_do_output;
  544. };
  545. ///////////////////////////////////////////////////////////////////////////
  546. template <typename Sink>
  547. bool sink_is_good(Sink const&)
  548. {
  549. return true; // the general case is always good
  550. }
  551. template <typename OutputIterator, typename Derived>
  552. bool sink_is_good(output_iterator<OutputIterator, Derived> const& sink)
  553. {
  554. return sink.good(); // our own output iterators are handled separately
  555. }
  556. }}}}
  557. #endif