/* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Copyright 2010-2018 Danny Robson */ #pragma once #include "../view.hpp" namespace cruft::iterator { /////////////////////////////////////////////////////////////////////////// /// an output iterator that inserts a delimiter between successive /// assignments /// /// very useful for outputting comma seperated lists to an ostream, eg: /// /// std::copy ( /// std::cbegin (container), /// std::cend (container), /// cruft::infix_iterator (os, ", ") /// ); template < typename ValueT, class CharT = char, class Traits = std::char_traits > class infix_iterator { public: using iterator_category = std::output_iterator_tag; using value_type = void; using difference_type = void; using reference = void; using pointer = void; using char_type = CharT; using traits_type = Traits; using ostream_type = std::basic_ostream; infix_iterator (ostream_type& _output, const CharT *_delimiter): m_output (_output), m_delimiter (_delimiter) { ; } infix_iterator& operator= (ValueT const &value) { if (!m_first) m_output << m_delimiter; m_output << value; m_first = false; return *this; } infix_iterator& operator* (void) { return *this; } infix_iterator& operator++ (void) { return *this; } infix_iterator& operator++ (int) { return *this; } private: bool m_first = true; ostream_type &m_output; const CharT *m_delimiter; }; namespace detail { template struct infix_t { ContainerT _container; const CharT *_delimiter; }; template std::ostream& operator<< (std::ostream &os, const infix_t &val) { using iterator_type = std::decay_t< decltype(std::begin (val._container)) >; using value_type = typename std::iterator_traits::value_type; std::copy ( std::cbegin (val._container), std::cend (val._container), infix_iterator (os, val._delimiter) ); return os; } } /// a helper function that returns an object that will use a /// cruft::infix_iterator to output a container's values to an ostream with /// the given delimiter. /// /// reduces boilerplate code required to output lists of things /// /// std::cout << cruft::make_infix (container) << '\n'; template auto make_infix (ContainerT const &_container, const CharT *_delimiter = ", ") { return detail::infix_t { _container, _delimiter }; } template auto make_infix (ContainerT &&_container, const CharT *_delimiter = ", ") { return detail::infix_t,CharT> { std::forward (_container), _delimiter }; } template auto make_infix (const ValueT (&val)[CountV], CharT const *delimiter = ", ") { return make_infix (cruft::view {val}, delimiter); } template auto make_infix (ValueT (&val)[CountV], CharT const *delimiter = ", ") { return make_infix (cruft::view {val}, delimiter); } }