#pragma once #ifndef _NB_SMARTSTREAM #define _NB_SMARTSTREAM #include #include #include #include #include namespace nb { typedef std::pair SmartTextKV; //template struct SmartText { std::string msg; SmartTextKV kv = {0, ""}; }; typedef std::string (*SmartTextFormatter)(std::string, std::string); typedef std::unordered_map SmartFormatMap; template class SmartOStreamBaseImpl; template class SmartOStream; template class SmartOStreamBaseImpl { public: virtual void process(const SmartText&) = 0; static const SmartFormatMap Formatters; using StreamType = SmartOStream; protected: SmartOStreamBaseImpl(StreamType& stream) : _ostream(&stream) {} StreamType* _ostream; }; template class SmartOStreamBaseImpl, Derived> { public: virtual void process(const SmartText&) = 0; static const SmartFormatMap Formatters; using StreamType = std::basic_ostream; protected: SmartOStreamBaseImpl(StreamType& stream) : _ostream(&stream) {} StreamType* _ostream; }; template class SmartOStream : public SmartOStreamBaseImpl { template friend SmartOStream& operator<<(SmartOStream&, const U&); public: StreamType* getStream() const { return _ostream; } template void process(const X&); void process(const SmartText&); static const SmartFormatMap Formatters; using Base = SmartOStreamBaseImpl; protected: using Base::Base; using Base::_ostream; static std::string defaultFormatter(std::string msg, std::string fmt) { return msg; } }; template const SmartFormatMap SmartOStream::Formatters = { {0, defaultFormatter} }; template SmartOStream& operator<<(SmartOStream& stream, const U& msg) { static_cast(&stream)->process(msg); return stream; } template void SmartOStream::process(const SmartText& msg) { try { *_ostream << D::Formatters.at(msg.kv.first)(msg.msg, msg.kv.second); } catch (const std::out_of_range& e) { *_ostream << D::Formatters.at(0)(msg.msg, msg.kv.second); } } template template void SmartOStream::process(const X& msg) { *_ostream << msg; } } #endif // _NB_SMARTSTREAM