#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; protected: SmartOStreamBase(ST& stream) : _ostream{&stream} {} ST* _ostream; }; template class SmartOStreamBaseImpl; template class SmartOStream; template class SmartOStreamBaseImpl, Derived> : public SmartOStreamBase>{ public: using StreamType = SmartOStream; using Base = SmartOStreamBase; using Base::process; using Base::Formatters; protected: using Base::Base; }; template class SmartOStreamBaseImpl, Derived> : public SmartOStreamBase> { public: using StreamType = std::basic_ostream; using Base = SmartOStreamBase; 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; SmartOStream(StreamType& stream) : Base(stream) {} StreamType* getStream() const { return _ostream; } template void process(const X& val) { *_ostream << val; } virtual void process(const SmartText&); static const SmartFormatMap Formatters; protected: 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) { using Derived = typename std::conditional::value, SmartOStream, D>::type; 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 { DEFAULT = 0, COLOR, CLEAR, BOLD, }; protected: }; template const SmartFormatMap SmartTerminal::Formatters = { {SmartTerminal::DEFAULT, SmartOStream::defaultFormatter} }; } #endif // _NB_SMARTSTREAM