#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 SmartOStreamBase { public: virtual void process(const SmartText&) = 0; static const SmartFormatMap Formatters; enum FormatterCodes : unsigned int; protected: SmartOStreamBase(ST& stream) : _ostream{&stream} {} ST* _ostream; }; template class SmartOStreamBaseImpl; template class SmartOStream; template class SmartOStreamBaseImpl, Derived> : public SmartOStreamBase>{ using Base = SmartOStreamBase>; public: using StreamType = SmartOStream; using Base::process; using Base::Formatters; protected: using Base::Base; }; template class SmartOStreamBaseImpl, Derived> : public SmartOStreamBase> { using Base = SmartOStreamBase>; public: using StreamType = std::basic_ostream; using Base::process; using Base::Formatters; protected: using Base::Base; }; template class SmartOStream : public SmartOStreamBaseImpl { template friend SmartOStream& operator<<(SmartOStream&, const U&); public: using Base = SmartOStreamBaseImpl; StreamType* getStream() const { return _ostream; } template void process(const X& val) { *_ostream << val; } void process(const SmartText&); static const SmartFormatMap Formatters; protected: using Base::Base; using Base::_ostream; static std::string defaultFormatter(std::string msg, std::string fmt) { return msg; } }; template enum SmartOStream::FormatterCodes : unsigned int { DEFAULT }; template const SmartFormatMap SmartOStream::Formatters = { {SmartOStream::FormatterCodes::DEFAULT, defaultFormatter} }; template SmartOStream& operator<<(SmartOStream& stream, const U& msg) { static_cast(&stream)->process(msg); return stream; } template SmartOStream& operator<<(SmartOStream& stream, const U& msg) { static_cast*>(&stream)->process(msg); return stream; } template void SmartOStream::process(const SmartText& msg) { using Derived = typename std::conditional::value, SmartOStream, D>::type; try { *_ostream << Derived::Formatters.at(msg.kv.first)(msg.msg, msg.kv.second); } catch (const std::out_of_range& e) { *_ostream << Derived::Formatters.at(0)(msg.msg, msg.kv.second); } } template class SmartTerminal : public SmartOStream> { using Base = SmartOStream>; public: using Base::Base; static const SmartFormatMap Formatters; enum FormatterCodes : unsigned int; protected: }; template enum SmartTerminal::FormatterCodes : unsigned int { DEFAULT, COLOR, BACKGROUND, BOLD, CLEAR }; { template const SmartTerminal::Formatters = { {SmartTerminal} }; } } #endif // _NB_SMARTSTREAM