diff --git a/include/log/Log.h b/include/log/Log.h index 7f23356..bcf9e37 100644 --- a/include/log/Log.h +++ b/include/log/Log.h @@ -48,9 +48,26 @@ class Log final std::unordered_map writers; class StreamHelper; + class DummyStreamHelper; + class StreamHelperImpl; + + using VerboseStreamReturnType = +#ifdef LU_LOG_DISABLE_VERBOSE + DummyStreamHelper; +#else + StreamHelper; +#endif + + using DebugStreamReturnType = +#ifdef LU_LOG_DISABLE_VERBOSE + DummyStreamHelper; +#else + StreamHelper; +#endif public: // constructors + Log() = delete; Log(const Log&) = default; explicit Log(const std::string& logName, LogLevel outputLevel = LogLevel::All); @@ -108,10 +125,10 @@ class Log final * If LU_LOG_DISABLE_VERBOSE is defined then the verbose methods are no-ops. * If LU_LOG_DISABLE_DEBUG is defined then the debug methods are no-ops. */ - StreamHelper verbose(const std::string& tag); + VerboseStreamReturnType verbose(const std::string& tag); void verbose(const std::string& tag, const std::string& msg); void verbosef(const std::string& tag, const char* fmt, ...); - StreamHelper debug(const std::string& tag); + DebugStreamReturnType debug(const std::string& tag); void debug(const std::string& tag, const std::string& msg); void debugf(const std::string& tag, const char* fmt, ...); StreamHelper info(const std::string& tag); @@ -150,15 +167,14 @@ class Log final * Creates a LogMessage from the provided parameters and forwards that * message to the writers of this log. */ - void dispatch(LogLevel level, const std::string& tag, const std::string& msg); - - - class StreamHelperImpl; + void dispatch(LogLevel level, const std::string& tag, const std::string& msg); /** - * Helper class that allows logs to accept stream input. Input is - * accumulated in a stringstream and dispatched back to the log when the - * helper is destroyed. + * Helper class that allows logs to accept stream input. Uses a variant of + * the pimpl idiom with shared pointers so that this object may be copied + * but final writing only occurs when the implementation is destroyed. + * Necessary because returning by value requires an accessible copy + * constructor. */ class StreamHelper final { @@ -169,7 +185,7 @@ class Log final using Manipulator = std::ostream& (*)(std::ostream&); // constructors - StreamHelper() = default; + StreamHelper() = delete; StreamHelper(Log& log, LogLevel level, const std::string& tag); StreamHelper(const StreamHelper&) = default; // operators @@ -187,7 +203,32 @@ class Log final StreamHelper& operator<<(Manipulator manip); }; - class StreamHelperImpl + /** + * This helper class does nothing. Used to allow verbose and debug methods + * to be disabled via a preprocessor define. + */ + class DummyStreamHelper + { + public: + using Manipulator = std::ostream& (*)(std::ostream&); + + // constructors + DummyStreamHelper() = default; + DummyStreamHelper(const DummyStreamHelper&) = default; + // operators + DummyStreamHelper& operator=(const DummyStreamHelper&) = delete; + + template + DummyStreamHelper& operator<<(const T& arg); + DummyStreamHelper& operator<<(Manipulator manip); + }; + + /** + * Implementation of the stream helper. Accumulates the log message in a + * stringstream and dispatches the message back to the log when this + * helper is destroyed. + */ + class StreamHelperImpl final { private: Log& log; @@ -215,11 +256,14 @@ using WeakLogPtr = WeakPtr; * Definitions ****************************************************************************/ -inline Log::StreamHelper Log::verbose(const std::string& tag) +// These functions are inlined so that the disable macros perform correctly +// even if we're compiled as a static lib. + +inline Log::VerboseStreamReturnType Log::verbose(const std::string& tag) { #ifdef LU_LOG_DISABLE_VERBOSE LU_UNUSED(tag); - return StreamHelper(); + return DummyStreamHelper(); #else return stream(LogLevel::Verbose, tag); #endif @@ -248,11 +292,11 @@ inline void Log::verbosef(const std::string& tag, const char* fmt, ...) #endif } -inline Log::StreamHelper Log::debug(const std::string& tag) +inline Log::DebugStreamReturnType Log::debug(const std::string& tag) { #ifdef LU_LOG_DISABLE_DEBUG LU_UNUSED(tag); - return StreamHelper(); + return DummyStreamHelper(); #else return stream(LogLevel::Debug, tag); #endif @@ -284,10 +328,14 @@ inline void Log::debugf(const std::string& tag, const char* fmt, ...) template Log::StreamHelper& Log::StreamHelper::operator<<(const T& arg) { - if (impl) - { - impl->os << arg; - } + impl->os << arg; + return *this; +} + +template +Log::DummyStreamHelper& Log::DummyStreamHelper::operator<<(const T& arg) +{ + LU_UNUSED(arg); return *this; } diff --git a/src/log/Log.cpp b/src/log/Log.cpp index f9a1d52..23f9d78 100644 --- a/src/log/Log.cpp +++ b/src/log/Log.cpp @@ -24,6 +24,8 @@ #include "log/Log.h" #include +// The printf style log functions use a fixed size stack buffer to process the +// format string. static const int PRINTF_BUFFER_SIZE = 256; namespace util @@ -228,10 +230,14 @@ Log::StreamHelper::StreamHelper(Log& log, LogLevel level, Log::StreamHelper& Log::StreamHelper::operator<<( Log::StreamHelper::Manipulator manip) { - if (impl) - { - manip(impl->os); - } + manip(impl->os); + return *this; +} + + +Log::DummyStreamHelper& Log::DummyStreamHelper::operator<<(Manipulator manip) +{ + LU_UNUSED(manip); return *this; }