Last active
December 30, 2015 06:38
-
-
Save tell/dc1c26fd2585f516e183 to your computer and use it in GitHub Desktop.
join in C++
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
*.o | |
test_* | |
*.log |
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
/* -*- 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 : */ |
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
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) $< |
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 <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