NBEngine/engine/NBCore/SmartStreams.hpp

124 lines
3.3 KiB
C++

#pragma once
#ifndef _NB_SMARTSTREAM
#define _NB_SMARTSTREAM
#include <array>
#include <iostream>
#include <memory>
#include <string>
#include <sstream>
#include <type_traits>
#include <utility>
#include <vector>
namespace nb {
template <typename StreamType, typename... Mixins>
class SmartStream;
template<typename Wrapper, typename U, typename Mix>
struct MixinHasProcess {
protected:
template <typename M>
static auto test(int)->decltype(
std::declval<M>().template process<Wrapper>(std::declval<const U&>()),
std::true_type{}
);
template <typename>
static std::false_type test(...);
public:
static const bool value = decltype(test<Mix>(0))::value;
};
template<typename Wrapper, typename U, typename... Mixins>
struct PackHasProcess;
template<typename Wrapper, typename U, typename Mix>
struct PackHasProcess<Wrapper, U, Mix> {
static const bool value = MixinHasProcess<Wrapper, U, Mix>::value;
using type = typename std::conditional<
value,
Mix,
void
>::type;
};
template<typename Wrapper, typename U, typename Mix1, typename... Mixins>
struct PackHasProcess<Wrapper, U, Mix1, Mixins...> {
protected:
static const bool base_value = MixinHasProcess<Wrapper, U, Mix1>::value;
public:
static const bool value = std::conditional<
base_value,
std::true_type,
typename PackHasProcess<Wrapper, U, Mixins...>::value
>::type::value;
using type = typename std::conditional<
base_value,
Mix1,
typename PackHasProcess<Wrapper, U, Mixins...>::type
>::type;
};
/* template <typename T, typename=void>
struct HasStreamType : std::false_type {};
template <typename T>
struct HasStreamType<T, > : std::false_type {}; */
template<typename ST, typename... Mixins>
class SmartStream : public Mixins... {
using StreamType = typename std::conditional<
decltype(std::declval<ST::StreamType>(), std::true_type{}),
ST::StreamType,
ST
>::type;
protected:
StreamType* const _stream;
public:
SmartStream(StreamType& stream) : _stream(&stream), Mixins(&stream)... {}
using Mixins::process...;
template <typename U, typename StreamFmt=SmartStream<StreamType, Mixins...>>
typename std::enable_if<PackHasProcess<SmartStream, U, Mixins...>::value, void>::type
toStream(const U& val, const StreamFmt* fmtas=nullptr) {
PackHasProcess<SmartStream, U, Mixins...>::type::template process<SmartStream>(val);
}
template <typename U, typename StreamFmt=SmartStream<StreamType, Mixins...>>
typename std::enable_if<!PackHasProcess<SmartStream, U, Mixins...>::value, void>::type
toStream(const U& val, const StreamFmt* fmtas=nullptr) {
*_stream << val;
}
template <typename U>
friend SmartStream& operator<<(SmartStream& stream, const U& val) {
stream.toStream(val);
return stream;
}
};
struct SmartText {
int x;
};
template <typename StreamType>
struct ANSIFormatter {
template <typename Wrapper>
void process(const SmartText& val, StreamType* fmtas = nullptr) {
static_cast<Wrapper*>(this)->toStream(val.x);
}
protected:
ANSIFormatter(StreamType* stream) : _stream(stream) {}
StreamType* const _stream;
};
}
#endif // _NB_SMARTSTREAM