Skip to content

Instantly share code, notes, and snippets.

@elbeno
Last active August 21, 2016 15:52
Show Gist options
  • Save elbeno/451cddadfcfd0d17c91c3a39e83dd4d6 to your computer and use it in GitHub Desktop.
Save elbeno/451cddadfcfd0d17c91c3a39e83dd4d6 to your computer and use it in GitHub Desktop.
Join algorithm
#include <algorithm>
#include <cstddef>
#include <iterator>
#include <type_traits>
#include <utility>
using namespace std;
template <typename InputIt, typename OutputIt,
typename FwdIt, typename F>
inline
OutputIt join(InputIt first, InputIt last,
OutputIt dest,
FwdIt d_first, FwdIt d_last,
F&& f)
{
if (first == last) return dest;
decltype(auto) r = f(*first++);
dest = std::move(std::begin(r), std::end(r), dest);
while (first != last)
{
dest = std::copy(d_first, d_last, dest);
r = f(*first++);
dest = std::move(std::begin(r), std::end(r), dest);
}
return dest;
}
template <typename InputIt, typename OutputIt, typename T, typename F>
inline
OutputIt join(InputIt first, InputIt last,
OutputIt dest,
const T& delimiter,
F&& f,
std::enable_if_t<std::is_assignable<decltype(*dest), T>::value>* = nullptr)
{
// if the delimiter can be assigned directly to the output, do that. example:
// f produces strings, and delimiter is a char.
return join(first, last, dest,
&delimiter, &delimiter + 1,
std::forward<F>(f));
}
template <typename InputIt, typename OutputIt, typename T, typename F>
inline
OutputIt join(InputIt first, InputIt last,
OutputIt dest,
const T& delimiter,
F&& f,
std::enable_if_t<!std::is_assignable<decltype(*dest), T>::value>* = nullptr)
{
// if the delimiter can't be assigned to the output, we assume it's a range of
// values that can be. example: f produces strings, and delimiter is a string.
return join(first, last, dest,
std::begin(delimiter), std::end(delimiter),
std::forward<F>(f));
}
template <typename InputIt, typename OutputIt, typename F, size_t N>
inline
OutputIt join(InputIt first, InputIt last,
OutputIt dest,
const char(&delimiter)[N],
F&& f)
{
// for const char array literals, they are null-terminated: we don't want the
// null character.
return join(first, last, dest,
&delimiter[0], &delimiter[N-1],
std::forward<F>(f));
}
template <typename InputIt, typename OutputIt, typename T>
inline
OutputIt join(InputIt first, InputIt last,
OutputIt dest,
const T& delimiter)
{
// if a function is not supplied, assume the identity function
return join(first, last, dest, delimiter,
[] (auto&& x) { return std::forward<decltype(x)>(x); });
}
#include <iostream>
#include <string>
#include <vector>
int main(void)
{
{
vector<int> v = { 1,2,3,4,5 };
string s;
auto it = join(std::cbegin(v), std::cend(v), back_inserter(s), ",",
[] (int i) { return to_string(i); });
cout << s << endl;
}
{
vector<string> v = { "foo","bar","baz","quux" };
string s;
auto it = join(std::make_move_iterator(std::begin(v)),
std::make_move_iterator(std::end(v)),
back_inserter(s), ",");
cout << s << endl;
}
{
vector<string> v = { "foo","bar","baz","quux" };
string s;
auto it = join(std::begin(v), std::end(v), back_inserter(s), ",");
cout << s << endl;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment