NBEngine/include/SmartStreams.hpp
2025-12-12 02:19:45 -06:00

162 lines
4.3 KiB
C++

#pragma once
#ifndef _NB_SMARTSTREAM
#define _NB_SMARTSTREAM
#include <ostream>
#include <type_traits>
#include <unordered_map>
#include <utility>
#include <vector>
namespace nb {
typedef std::pair<unsigned int, std::string> SmartFormat;
template <typename T=const char*>
struct SmartText {
T msg;
SmartFormat fmt;
};
typedef std::string (*SmartTextFormatter)(std::string, std::string);
typedef std::unordered_map<unsigned int, SmartTextFormatter> SmartFormatMap;
template <typename ST>
class SmartOStreamBase {
public:
virtual void process(const SmartText<const char*>&) = 0;
static const SmartFormatMap Formatters;
protected:
SmartOStreamBase(ST& stream) : _ostream{&stream} {}
ST* _ostream;
};
template<typename ST, typename Derived>
class SmartOStreamBaseImpl;
template<typename ST, typename Derived = void>
class SmartOStream;
template<typename ST, typename STD, typename Derived>
class SmartOStreamBaseImpl<SmartOStream<ST, STD>, Derived> : public SmartOStreamBase<SmartOStream<ST, STD>>{
public:
using StreamType = SmartOStream<ST, STD>;
using Base = SmartOStreamBase<StreamType>;
using Base::process;
using Base::Formatters;
protected:
using Base::Base;
};
template<typename C, typename T, typename Derived>
class SmartOStreamBaseImpl<std::basic_ostream<C, T>, Derived> : public SmartOStreamBase<std::basic_ostream<C, T>> {
public:
using StreamType = std::basic_ostream<C, T>;
using Base = SmartOStreamBase<StreamType>;
using Base::process;
using Base::Formatters;
protected:
using Base::Base;
};
template<typename StreamType, typename Derived>
class SmartOStream : public SmartOStreamBaseImpl<StreamType, Derived> {
template <typename ST, typename D, typename U>
friend SmartOStream<ST, D>& operator<<(SmartOStream<ST, D>&, const U&);
public:
using Base = SmartOStreamBaseImpl<StreamType, Derived>;
SmartOStream(StreamType& stream) : Base(stream) {}
StreamType* getStream() const { return _ostream; }
template <typename X>
void process(const X& val) {
*_ostream << val;
}
template <typename Msg>
void process(const SmartText<Msg>& msg) {
using D = typename std::conditional<std::is_void<Derived>::value, SmartOStream<StreamType, void>, Derived>::type;
try {
*_ostream << D::Formatters.at(msg.fmt.first)(
static_cast<D*>(this)->process(static_cast<Msg>(msg.msg)),
msg.fmt.second
);
} catch (const std::out_of_range& e) {
*_ostream << D::Formatters.at(0)(
static_cast<D*>(this)->process(static_cast<Msg>(msg.msg)),
msg.fmt.second
);
}
}
virtual void process(const SmartText<const char*>&);
static const SmartFormatMap Formatters;
protected:
using Base::_ostream;
static std::string defaultFormatter(std::string msg, std::string fmt) {
return msg;
}
};
template<typename ST, typename D>
const SmartFormatMap SmartOStream<ST, D>::Formatters = {
{0, defaultFormatter}
};
template <typename ST, typename D, typename U>
SmartOStream<ST, D>& operator<<(SmartOStream<ST, D>& stream, const U& msg) {
using Derived = typename std::conditional<std::is_void<D>::value, SmartOStream<ST, void>, D>::type;
static_cast<Derived*>(&stream)->process(msg);
return stream;
}
template<typename ST, typename D>
void SmartOStream<ST, D>::process(const SmartText<const char*>& msg) {
using Derived = typename std::conditional<std::is_void<D>::value, SmartOStream<ST, void>, D>::type;
std::string msg_str(msg.msg);
try {
*_ostream << Derived::Formatters.at(msg.fmt.first)(msg_str, msg.fmt.second);
} catch (const std::out_of_range& e) {
*_ostream << Derived::Formatters.at(0)(msg_str, msg.fmt.second);
}
}
template<typename ST, typename D>
class SmartTerminal : public SmartOStream<ST, SmartTerminal<ST, D>> {
using Base = SmartOStream<ST, SmartTerminal<ST, D>>;
public:
using Base::Base;
static const SmartFormatMap Formatters;
enum FormatterCodes : unsigned int {
DEFAULT = 0,
COLOR,
CLEAR,
BOLD,
};
protected:
};
template<typename ST, typename D>
const SmartFormatMap SmartTerminal<ST, D>::Formatters = {
{SmartTerminal<ST, D>::DEFAULT, SmartOStream<ST, D>::defaultFormatter}
};
}
#endif // _NB_SMARTSTREAM