140 lines
4.0 KiB
C++
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);
|
|
}
|
|
}
|