Created
September 30, 2017 19:47
-
-
Save erickguan/82b821ed5948728097be421c52e9baaf to your computer and use it in GitHub Desktop.
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
#ifndef RANG_DOT_HPP | |
#define RANG_DOT_HPP | |
#if defined(__unix__) || defined(__unix) || defined(__linux__) | |
#define OS_LINUX | |
#elif defined(WIN32) || defined(_WIN32) || defined(_WIN64) | |
#define OS_WIN | |
#elif defined(__APPLE__) || defined(__MACH__) | |
#define OS_MAC | |
#else | |
#error Unknown Platform | |
#endif | |
#if defined(OS_LINUX) || defined(OS_MAC) | |
#include <cstring> | |
#include <unistd.h> | |
#elif defined(OS_WIN) | |
#include <VersionHelpers.h> | |
#include <io.h> | |
#include <windows.h> | |
#endif | |
#include <algorithm> | |
#include <cstdlib> | |
#include <ios> | |
#include <iostream> | |
#include <iterator> | |
#include <type_traits> | |
namespace rang { | |
enum class style { | |
reset = 0, | |
bold = 1, | |
dim = 2, | |
italic = 3, | |
underline = 4, | |
blink = 5, | |
rblink = 6, | |
reversed = 7, | |
conceal = 8, | |
crossed = 9 | |
}; | |
enum class fg { | |
black = 30, | |
red = 31, | |
green = 32, | |
yellow = 33, | |
blue = 34, | |
magenta = 35, | |
cyan = 36, | |
gray = 37, | |
reset = 39 | |
}; | |
enum class bg { | |
black = 40, | |
red = 41, | |
green = 42, | |
yellow = 43, | |
blue = 44, | |
magenta = 45, | |
cyan = 46, | |
gray = 47, | |
reset = 49 | |
}; | |
enum class fgB { | |
black = 90, | |
red = 91, | |
green = 92, | |
yellow = 93, | |
blue = 94, | |
magenta = 95, | |
cyan = 96, | |
gray = 97 | |
}; | |
enum class bgB { | |
black = 100, | |
red = 101, | |
green = 102, | |
yellow = 103, | |
blue = 104, | |
magenta = 105, | |
cyan = 106, | |
gray = 107 | |
}; | |
enum class control { autoColor = 0, forceColor = 1 }; | |
namespace rang_implementation { | |
inline std::streambuf const *&RANG_coutbuf() { | |
static std::streambuf const *pOutbuff = std::cout.rdbuf(); | |
return pOutbuff; | |
} | |
inline std::streambuf const *&RANG_cerrbuf() { | |
static std::streambuf const *pErrbuff = std::cerr.rdbuf(); | |
return pErrbuff; | |
} | |
inline std::streambuf const *&RANG_clogbuf() { | |
static std::streambuf const *pLogbuff = std::clog.rdbuf(); | |
return pLogbuff; | |
} | |
inline int getIword() { | |
static int i = std::ios_base::xalloc(); | |
return i; | |
} | |
inline bool supportsColor() { | |
#if defined(OS_LINUX) || defined(OS_MAC) | |
static constexpr const char *Terms[] = { | |
"ansi", "color", "console", "cygwin", "gnome", "konsole", "kterm", | |
"linux", "msys", "putty", "rxvt", "screen", "vt100", "xterm"}; | |
const char *env_p = std::getenv("TERM"); | |
if (env_p == nullptr) { | |
return false; | |
} | |
static const bool result = | |
std::any_of(std::begin(Terms), std::end(Terms), [&](const char *term) { | |
return std::strstr(env_p, term) != nullptr; | |
}); | |
#elif defined(OS_WIN) | |
static constexpr bool result = true; | |
#endif | |
return result; | |
} | |
inline bool isTerminal(const std::streambuf *osbuf) { | |
if (osbuf == RANG_coutbuf()) { | |
#if defined(OS_LINUX) || defined(OS_MAC) | |
return isatty(fileno(stdout)) ? true : false; | |
#elif defined(OS_WIN) | |
return _isatty(_fileno(stdout)) ? true : false; | |
#endif | |
} | |
if (osbuf == RANG_cerrbuf() || osbuf == RANG_clogbuf()) { | |
#if defined(OS_LINUX) || defined(OS_MAC) | |
return isatty(fileno(stderr)) ? true : false; | |
#elif defined(OS_WIN) | |
return _isatty(_fileno(stderr)) ? true : false; | |
#endif | |
} | |
return false; | |
} | |
template <typename T> | |
using enableStd = typename std::enable_if< | |
std::is_same<T, rang::style>::value || std::is_same<T, rang::fg>::value || | |
std::is_same<T, rang::bg>::value || std::is_same<T, rang::fgB>::value || | |
std::is_same<T, rang::bgB>::value, | |
std::ostream &>::type; | |
#ifdef OS_WIN | |
inline HANDLE getVersionDependentHandle() { | |
if (IsWindowsVersionOrGreater(10, 0, 0)) | |
return nullptr; | |
return GetStdHandle(STD_OUTPUT_HANDLE); | |
} | |
inline HANDLE getConsoleHandle() { | |
static HANDLE h = getVersionDependentHandle(); | |
return h; | |
} | |
inline WORD reverseRGB(WORD rgb) { | |
static const WORD rev[8] = {0, 4, 2, 6, 1, 5, 3, 7}; | |
return rev[rgb]; | |
} | |
inline void setWinAttribute(rang::bg col, WORD &state) { | |
state &= 0xFF0F; | |
state |= reverseRGB(static_cast<WORD>(col) - 40) << 4; | |
} | |
inline void setWinAttribute(rang::fg col, WORD &state) { | |
state &= 0xFFF0; | |
state |= reverseRGB(static_cast<WORD>(col) - 30); | |
} | |
inline void setWinAttribute(rang::bgB col, WORD &state) { | |
state &= 0xFF0F; | |
state |= (0x8 | reverseRGB(static_cast<WORD>(col) - 100)) << 4; | |
} | |
inline void setWinAttribute(rang::fgB col, WORD &state) { | |
state &= 0xFFF0; | |
state |= (0x8 | reverseRGB(static_cast<WORD>(col) - 90)); | |
} | |
inline void setWinAttribute(rang::style style, WORD &state) { | |
if (style == rang::style::reset) { | |
state = (FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED); | |
} | |
} | |
inline WORD ¤t_state() { | |
static WORD state = (FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED); | |
return state; | |
} | |
template <typename T> | |
inline enableStd<T> setColor(std::ostream &os, T const value) { | |
HANDLE h = getConsoleHandle(); | |
if (h && isTerminal(os.rdbuf())) { | |
setWinAttribute(value, current_state()); | |
SetConsoleTextAttribute(h, current_state()); | |
return os; | |
} | |
return os << "\033[" << static_cast<int>(value) << "m"; | |
} | |
#else | |
template <typename T> | |
inline enableStd<T> setColor(std::ostream &os, T const value) { | |
return os << "\033[" << static_cast<int>(value) << "m"; | |
} | |
#endif | |
template <typename T> | |
using enableControl = | |
typename std::enable_if<std::is_same<T, rang::control>::value, | |
std::ostream &>::type; | |
} // namespace rang_implementation | |
inline void init() { | |
rang_implementation::RANG_coutbuf(); | |
rang_implementation::RANG_cerrbuf(); | |
rang_implementation::RANG_clogbuf(); | |
} | |
template <typename T> | |
inline rang_implementation::enableStd<T> operator<<(std::ostream &os, | |
T const value) { | |
std::streambuf const *osbuf = os.rdbuf(); | |
return (os.iword(rang_implementation::getIword()) || | |
((rang_implementation::supportsColor()) && | |
(rang_implementation::isTerminal(osbuf)))) | |
? rang_implementation::setColor(os, value) | |
: os; | |
} | |
template <typename T> | |
inline rang_implementation::enableControl<T> operator<<(std::ostream &os, | |
T const value) { | |
if (value == rang::control::forceColor) { | |
os.iword(rang_implementation::getIword()) = 1; | |
} else if (value == rang::control::autoColor) { | |
os.iword(rang_implementation::getIword()) = 0; | |
} | |
return os; | |
} | |
} // namespace rang | |
#undef OS_LINUX | |
#undef OS_WIN | |
#undef OS_MAC | |
#endif /* ifndef RANG_DOT_HPP */ | |
#include <cstdlib> | |
#include <stack> | |
#include <iostream> | |
#include <typeinfo> | |
#include <string> | |
using namespace std; | |
class MyIterator; | |
class MyContainer { | |
public: | |
explicit MyContainer(); | |
MyIterator begin() const; | |
MyIterator end() const; | |
stack<int> vec; | |
}; | |
static bool gColor = false; | |
class MyIterator { | |
public: | |
explicit MyIterator(const MyContainer &c) | |
: m_container(const_cast<MyContainer &>(c)) | |
{ | |
color = gColor; | |
gColor = !gColor; | |
cout << (color ? rang::fg::red : rang::fg::green) << this << " constructed" << rang::style::reset << endl; | |
} | |
~MyIterator() | |
{ | |
cout << (color ? rang::fg::red : rang::fg::green) << this << " deconstructed" << rang::style::reset << endl; | |
} | |
// Required | |
bool operator!=(const MyIterator &other) | |
{ | |
cout << (color ? rang::fg::red : rang::fg::green) << this << " !=" << rang::style::reset << endl; | |
return !m_container.vec.empty(); | |
} | |
// Required | |
const MyIterator& operator++() | |
{ | |
cout << (color ? rang::fg::red : rang::fg::green) << this << " ++" << rang::style::reset << endl; | |
return *this; | |
} | |
// Required | |
int operator*() const | |
{ | |
auto top = m_container.vec.top(); | |
cout << (color ? rang::fg::red : rang::fg::green) << this << ' ' << top << rang::style::reset << endl; | |
m_container.vec.pop(); | |
return top; | |
} | |
private: | |
MyContainer& m_container; | |
bool color; | |
}; | |
MyContainer::MyContainer() | |
{ | |
vec.push(1); | |
vec.push(2); | |
vec.push(3); | |
} | |
MyIterator MyContainer::begin() const | |
{ | |
cout << "iter:begin" << endl; | |
return MyIterator(*this); | |
} | |
MyIterator MyContainer::end() const | |
{ | |
cout << "iter:end" << endl; | |
return MyIterator(*this); | |
} | |
int main() | |
{ | |
MyContainer c; | |
cout << "before iteration" << endl; | |
for (auto a : c) { | |
cout << "typeid: " << typeid(a).name() << " value " << a << endl; | |
} | |
cout << "after iteration" << endl; | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment