Skip to content

Instantly share code, notes, and snippets.

@tell
Last active December 30, 2015 06:38
Show Gist options
  • Save tell/dc1c26fd2585f516e183 to your computer and use it in GitHub Desktop.
Save tell/dc1c26fd2585f516e183 to your computer and use it in GitHub Desktop.
join in C++
*.o
test_*
*.log
/* -*- mode: c++ -*- */
#pragma once
#include <iterator>
#include <string>
#include <vector>
#include <sstream>
#include <cassert>
#ifndef NDEBUG
#define DEBUG_PRINT_FUNC() do { std::cerr << __PRETTY_FUNCTION__ << " (" << __FILE__ << ":" << __LINE__ << ")" << std::endl; } while (false)
#else
#define DEBUG_PRINT_FUNC() do {} while (false)
#endif
#if __cplusplus < 201103L && !defined(__APPLE__)
namespace std {
/*
* This function is equivalent to std::next in C++11.
*/
template<class T>
T next(T it, typename iterator_traits<T>::difference_type n = 1) {
advance(it, n);
return it;
}
} // namespace std
#endif
namespace sandpit {
namespace internal {
template<class T, class OUT = typename std::iterator_traits<T>::value_type>
class Join {
public:
typedef T iter_type;
typedef OUT out_value_type;
private:
const iter_type bi_;
const iter_type ei_;
const std::string sep_;
public:
Join(const iter_type& bi, const iter_type& ei, const std::string& sep)
: bi_(bi), ei_(ei), sep_(sep)
{}
friend std::ostream& operator<<(std::ostream& out, const Join& x) {
iter_type ci = x.bi_;
if (ci != x.ei_) {
for (; std::next(ci) != x.ei_; ci++) {
out << static_cast<out_value_type>(*ci) << x.sep_;
}
out << static_cast<out_value_type>(*ci);
}
return out;
}
operator std::string() const {
std::stringstream st;
st << *this;
return st.str();
}
};
template<class T>
struct tag {
typedef T type;
};
} // namespace internal
template<class T, class U = T>
inline internal::Join<const T*, U> join(const T* const x, const size_t n, const std::string& sep, const internal::tag<U> tag = internal::tag<U>()) {
DEBUG_PRINT_FUNC();
return internal::Join<const T*, U>(x, x + n, sep);
}
template<class T, size_t N, class U = T>
inline internal::Join<const T*, U> join(const T (&x)[N], const std::string& sep, class internal::tag<U> tag = internal::tag<U>()) {
DEBUG_PRINT_FUNC();
return internal::Join<const T*, U>(x, x + N, sep);
}
template<class T, size_t N, class U = T>
inline internal::Join<const T*, U> join(const T (&x)[N], const size_t n, const std::string& sep, class internal::tag<U> tag = internal::tag<U>()) {
DEBUG_PRINT_FUNC();
assert(n <= N);
return internal::Join<const T*, U>(x, x + n, sep);
}
template<class T>
inline internal::Join<const T*> join(const T* const x, const T* const y, const std::string& sep) {
DEBUG_PRINT_FUNC();
return internal::Join<const T*>(x, y, sep);
}
template<class T>
inline internal::Join<T> join(const T& bi, const T& ei, const std::string& sep) {
DEBUG_PRINT_FUNC();
return internal::Join<T>(bi, ei, sep);
}
template<class T>
inline internal::Join< typename std::vector<T>::const_iterator > join(const std::vector<T>& vec, const std::string& sep) {
DEBUG_PRINT_FUNC();
return internal::Join< typename std::vector<T>::const_iterator >(vec.begin(), vec.end(), sep);
}
template<class T>
inline internal::Join< typename std::vector<T>::const_iterator > join(const std::vector<T>& vec, const size_t n, const std::string& sep) {
DEBUG_PRINT_FUNC();
assert(n <= vec.size());
return internal::Join< typename std::vector<T>::const_iterator >(vec.begin(), vec.begin() + n, sep);
}
} // namespace sandpit
/* vim: set ff=unix fenc=utf-8 ft=cpp expandtab cindent cino=t0g0N-s : */
/* vim: set foldmethod=marker : */
CC = $(CXX)
.PHONY: all check clean
all: test_join test_join_c++11
check:
./test_join
clean:
$(RM) *~ .*~ *.o
test_join.o: test_join.cpp join.hpp
test_join_c++11.o: CPPFLAGS += -std=c++11
test_join_c++11.o: test_join.cpp join.hpp
$(COMPILE.cpp) $(OUTPUT_OPTION) $<
#include <iostream>
#include "join.hpp"
#define ASSERTEQ(x, y) \
do { \
if ((x) != (y)) { \
std::cerr << #x << " = " << x << std::endl \
<< #y << " = " << y << std::endl; \
assert((x) == (y)); } } while(0)
using namespace std;
using namespace sandpit;
int x[] = {0, 1, 2, 3};
const size_t xl = sizeof(x)/sizeof(x[0]);
void putstr(const string& str) {
cout << str << endl;
}
void test0() {
char y[] = {0, 1, 2, 3};
const string s = join<char, int>(y, 1, " ");
ASSERTEQ("0", s);
}
void test1() {
const string s = join(x, 1, " ");
ASSERTEQ("0", s);
}
void test2() {
const string s = join(x, " ");
ASSERTEQ("0 1 2 3", s);
}
void test3() {
const vector<int> y(x, x + xl);
const string s = join(y, ", ");
ASSERTEQ("0, 1, 2, 3", s);
}
void test4() {
const vector<int> y(x, x + xl);
const string s = join(y, 2, " ");
ASSERTEQ("0 1", s);
}
void test5() {
const vector<int> y(x, x + xl);
const string s = join(y.begin(), y.end(), " ");
ASSERTEQ("0 1 2 3", s);
}
void test6() {
const string s = join(x, x + 1, " ");
ASSERTEQ("0", s);
}
int main() {
test0();
test1();
test2();
test3();
test4();
test5();
test6();
}
/* vim: set ff=unix fenc=utf-8 ft=cpp expandtab cindent cino=g0 : */
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment