124 lines
3.3 KiB
C++
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
|