libcruft-util/iterator/infix.hpp

118 lines
3.3 KiB
C++

/*
* 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 <danny@nerdcruft.net>
*/
#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<value_type> (os, ", ")
/// );
template <
typename ValueT,
class CharT = char,
class Traits = std::char_traits<CharT>
>
class infix_iterator : public std::iterator<std::output_iterator_tag, void, void, void, void> {
public:
using char_type = CharT;
using traits_type = Traits;
using ostream_type = std::basic_ostream<char_type, traits_type>;
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 <typename ContainerT, typename CharT>
struct infix_t {
const ContainerT &_container;
const CharT *_delimiter;
};
template <typename ContainerT, typename CharT>
std::ostream&
operator<< (std::ostream &os, const infix_t<ContainerT,CharT> &val)
{
using iterator_type = std::decay_t<
decltype(std::begin (std::declval<ContainerT> ()))
>;
using value_type = typename std::iterator_traits<iterator_type >::value_type;
std::copy (
std::cbegin (val._container),
std::cend (val._container),
infix_iterator<value_type> (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 <typename ContainerT, typename CharT = char>
auto
make_infix (const ContainerT &_container, const CharT *_delimiter = ", ")
{
return detail::infix_t<ContainerT,CharT> { _container, _delimiter };
}
template <typename ValueT, size_t CountV>
auto
make_infix (const ValueT (&val)[CountV])
{
return make_infix (cruft::view {val});
}
}