Last active
November 7, 2015 11:04
-
-
Save Redchards/bff347eb0be067bc1222 to your computer and use it in GitHub Desktop.
Extremly simple logging system, using expression templates (inspired by a lightning talk of Marc Eaddy)
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
#pragma once | |
#include <map> | |
#include <iostream> | |
#include <string> | |
#include <utility> | |
// A very simple logging system, shamelessly inspired by : | |
// https://github.com/CppCon/CppCon2014/blob/master/Lightning%20Talks/Cheap,%20Simple,%20and%20Safe%20Logging%20Using%20Expression%20Templates/Cheap,%20Simple,%20and%20Safe%20Logging%20Using%20Expression%20Templates%20-%20Marc%20Eaddy.pdf | |
typedef uint16_t flag_type; | |
enum class LogLevel : flag_type | |
{ | |
info = 0, | |
warning, | |
error, | |
fatal | |
}; | |
static std::map<LogLevel, std::string> LogLevelName { | |
{LogLevel::info, "Info"}, | |
{LogLevel::warning, "Warning"}, | |
{LogLevel::error, "Error"}, | |
{LogLevel::fatal, "Fatal"} | |
}; | |
template<typename List> | |
struct LogData { | |
typedef List type; | |
List list; | |
}; | |
struct DummyLogData {}; | |
template<LogLevel level> | |
class LogBase | |
{ | |
public: | |
LogBase(std::ostream& os) : os_(os) {}; | |
~LogBase() = default; | |
protected: | |
std::ostream& os_; | |
}; | |
template<> | |
class LogBase<LogLevel::fatal> | |
{ | |
public: | |
LogBase(std::ostream& os) : os_(os){} | |
~LogBase() | |
{ | |
std::terminate(); | |
} | |
protected: | |
std::ostream& os_; | |
}; | |
template<LogLevel level> | |
class LogIntermediate : public LogBase<level> | |
{ | |
static std::ostream& DefaultOstream; | |
public: | |
LogIntermediate(const char* file, size_t line, std::ostream& os = DefaultOstream) : LogBase<level>(os) | |
{ | |
this->os_ << "(" << file << ":" << line << ") " << LogLevelName[level] << " : "; | |
}; | |
~LogIntermediate() {}; | |
template<typename TLogData> | |
void operator<<(TLogData&& data) | |
{ | |
write(std::forward<TLogData::type>(data.list)); | |
} | |
private: | |
template<typename TLogDataPair> | |
void write(TLogDataPair&& pair) | |
{ | |
write(std::forward<typename TLogDataPair::first_type>(pair.first)); | |
this->os_ << std::forward<typename TLogDataPair::second_type>(pair.second); | |
} | |
void write(DummyLogData&&) {} | |
}; | |
template<LogLevel level> | |
std::ostream& LogIntermediate<level>::DefaultOstream = std::cout; | |
#define LOG(level, data) LogIntermediate<level>(__FILE__, __LINE__) << (LogData<DummyLogData>() << data) | |
#define LOGTO(level, out, data) LogIntermediate<level(__FILE__, __LINE__, out) << (LogData<DummyLogData>() << data) | |
template<typename T, typename U> | |
LogData<std::pair<T&&, U&&>> operator<<(LogData<T>&& orig, U&& input) | |
{ | |
return {{ std::forward<T>(orig.list), std::forward<U>(input) }}; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment