Last active
August 21, 2016 15:52
-
-
Save elbeno/451cddadfcfd0d17c91c3a39e83dd4d6 to your computer and use it in GitHub Desktop.
Join algorithm
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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