From 493fafb213b55967647225b42a895f32058d8392 Mon Sep 17 00:00:00 2001 From: tosh Date: Wed, 17 Apr 2013 19:48:30 +0200 Subject: [PATCH] adds optional LogStream for cpp iostream-style logging --- interface/src/LogStream.h | 106 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 interface/src/LogStream.h diff --git a/interface/src/LogStream.h b/interface/src/LogStream.h new file mode 100644 index 0000000000..88e5d4fff0 --- /dev/null +++ b/interface/src/LogStream.h @@ -0,0 +1,106 @@ +// +// LogStream.h +// interface +// +// Created by Tobias Schwinger on 4/17/13. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// + +#ifndef __interface__LogStream__ +#define __interface__LogStream__ + +#include + +#include "Log.h" + +// +// Makes the logging facility accessible as a C++ stream. +// +// Example: +// +// // somewhere central - ideally one per thread (else pass 'true' as +// // second constructor argument and compromise some efficiency) +// LogStream lOut(printLog); +// +// // elsewhere: +// lOut << "Hello there!" << std::endl; +// +class LogStream { + std::ostringstream _objOutStream; + Log& _refLog; + bool _flgThreadSafe; +public: + inline LogStream(Log& log, bool threadSafe = false); + + class StreamRef; friend class StreamRef; + + template< typename T > friend inline LogStream::StreamRef const operator<<(LogStream&, T const&); + +private: + // don't + LogStream(LogStream const&); // = delete; + LogStream& operator=(LogStream const&); // = delete; + + inline void ostreamBegin(); + inline void ostreamEnd(); +}; + +inline LogStream::LogStream(Log& log, bool threadSafe) : + _objOutStream(std::ios_base::out), _refLog(log), _flgThreadSafe(threadSafe) { } + +inline void LogStream::ostreamBegin() { + + if (_flgThreadSafe) { + // the user wants to share this LogStream among threads, + // so lock the global log here, already + pthread_mutex_lock(& _refLog._mtx); + } + _objOutStream.str(""); +} + +inline void LogStream::ostreamEnd() { + + if (! _flgThreadSafe) { + // haven't locked, so far (we have memory for each thread) + pthread_mutex_lock(& _refLog._mtx); + } + _refLog.addMessage(_objOutStream.str().c_str()); + pthread_mutex_unlock(& _refLog._mtx); +} + + +// +// The Log::StreamRef class makes operator<< work. It... +// +class LogStream::StreamRef { + mutable LogStream* _ptrLogStream; + typedef std::ostream& (*manipulator)(std::ostream&); + + friend class LogStream; + + template< typename T > friend inline LogStream::StreamRef const operator<<(LogStream&, T const&); + StreamRef(LogStream* log) : _ptrLogStream(log) { } +public: + // ...forwards << operator calls to stringstream... + template< typename T > StreamRef const operator<<(T const& x) const { _ptrLogStream->_objOutStream << x; return *this; } + // ...has to dance around to make manipulators (such as std::hex, std::endl) work... + StreamRef const operator<<(manipulator x) const { _ptrLogStream->_objOutStream << x; return *this; } + // ...informs the logger that a stream has ended when it has the responsibility... + ~StreamRef() { if (_ptrLogStream != 0l) { _ptrLogStream->ostreamEnd(); } } + // ...which is passed on upon copy. + StreamRef(StreamRef const& other) : _ptrLogStream(other._ptrLogStream) { other._ptrLogStream = 0l; } + +private: + // don't + StreamRef& operator=(StreamRef const&); // = delete; +}; + +template< typename T > inline LogStream::StreamRef const operator<<(LogStream& s, T const& x) { + + s.ostreamBegin(); + s._objOutStream << x; + return LogStream::StreamRef(& s); // calls streamEnd at the end of the stream expression +} + + +#endif