libcruft-util/iterator/infix.hpp

140 lines
4.0 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:
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<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 {
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 (val._container))
>;
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 (ContainerT const &_container, const CharT *_delimiter = ", ")
{
return detail::infix_t<ContainerT const&,CharT> { _container, _delimiter };
}
template <typename ContainerT, typename CharT = char>
auto
make_infix (ContainerT &&_container, const CharT *_delimiter = ", ")
{
return detail::infix_t<std::remove_reference_t<ContainerT>,CharT> {
std::forward<ContainerT> (_container),
_delimiter
};
}
template <typename ValueT, size_t CountV, typename CharT>
auto
make_infix (const ValueT (&val)[CountV], CharT const *delimiter = ", ")
{
return make_infix (cruft::view {val}, delimiter);
}
template <typename ValueT, size_t CountV, typename CharT>
auto
make_infix (ValueT (&val)[CountV], CharT const *delimiter = ", ")
{
return make_infix (cruft::view {val}, delimiter);
}
}