forked from OctaForge/libostd
SFINAE friendly ToString and expansion of any tuple-like type in format
This commit is contained in:
parent
a77f983015
commit
82a8ea3902
|
@ -14,6 +14,7 @@
|
|||
#include "octa/algorithm.hh"
|
||||
#include "octa/string.hh"
|
||||
#include "octa/utility.hh"
|
||||
#include "octa/internal/tuple.hh"
|
||||
|
||||
namespace octa {
|
||||
|
||||
|
@ -458,21 +459,46 @@ namespace detail {
|
|||
template<typename T>
|
||||
using FmtRangeTest = decltype(test_fmt_range<T>(0));
|
||||
|
||||
template<Size I>
|
||||
struct FmtTupleUnpacker {
|
||||
template<typename R, typename T, typename ...A>
|
||||
static inline Ptrdiff unpack(R &writer, Size &fmtn, bool esc,
|
||||
const char *fmt, const T &item,
|
||||
const A &...args) {
|
||||
return FmtTupleUnpacker<I - 1>::unpack(writer, fmtn, esc, fmt,
|
||||
item, get<I - 1>(item), args...);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct FmtTupleUnpacker<0> {
|
||||
template<typename R, typename T, typename ...A>
|
||||
static inline Ptrdiff unpack(R &writer, Size &fmtn, bool esc,
|
||||
const char *fmt, const T &,
|
||||
const A &...args) {
|
||||
return format_impl(writer, fmtn, esc, fmt, args...);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename R, typename T>
|
||||
inline Ptrdiff format_ritem(R &writer, Size &fmtn, bool esc, bool,
|
||||
const char *fmt, const T &item) {
|
||||
const char *fmt, const T &item,
|
||||
EnableIf<!IsTupleLike<T>::value, bool>
|
||||
= true) {
|
||||
return format_impl(writer, fmtn, esc, fmt, item);
|
||||
}
|
||||
|
||||
template<typename R, typename T, typename U>
|
||||
template<typename R, typename T>
|
||||
inline Ptrdiff format_ritem(R &writer, Size &fmtn, bool esc,
|
||||
bool expandval, const char *fmt,
|
||||
const Pair<T, U> &pair) {
|
||||
const T &item,
|
||||
EnableIf<IsTupleLike<T>::value, bool>
|
||||
= true) {
|
||||
if (expandval) {
|
||||
return format_impl(writer, fmtn, esc, fmt, pair.first,
|
||||
pair.second);
|
||||
return FmtTupleUnpacker<TupleSize<T>::value>::unpack(writer,
|
||||
fmtn, esc, fmt, item);
|
||||
}
|
||||
return format_impl(writer, fmtn, esc, fmt, pair);
|
||||
return format_impl(writer, fmtn, esc, fmt, item);
|
||||
}
|
||||
|
||||
template<typename R, typename T>
|
||||
|
@ -515,9 +541,8 @@ namespace detail {
|
|||
return -1;
|
||||
}
|
||||
|
||||
template<typename T,
|
||||
typename = decltype(octa::to_string(declval<T>()))
|
||||
> static True test_fmt_tostr(int);
|
||||
template<typename T>
|
||||
static True test_fmt_tostr(decltype(octa::to_string(declval<T>())) *);
|
||||
template<typename> static False test_fmt_tostr(...);
|
||||
|
||||
template<typename T>
|
||||
|
@ -756,7 +781,8 @@ namespace detail {
|
|||
/* generic failure case */
|
||||
template<typename R, typename T>
|
||||
Ptrdiff write(R &, bool, const T &, EnableIf<
|
||||
!IsArithmetic<T>::value && !FmtTostrTest<T>::value, bool
|
||||
!IsArithmetic<T>::value && !FmtTostrTest<T>::value &&
|
||||
!FmtTofmtTest<T, FmtWriteRange<R>>::value, bool
|
||||
> = true) {
|
||||
assert(false && "value cannot be formatted");
|
||||
return -1;
|
||||
|
|
|
@ -485,24 +485,24 @@ namespace detail {
|
|||
template<typename U> static int test(...);
|
||||
static constexpr bool value = (sizeof(test<T>(0)) == sizeof(char));
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
static True test_iterable(decltype(octa::iter(declval<T>())) *);
|
||||
template<typename> static False test_iterable(...);
|
||||
|
||||
template<typename T>
|
||||
using IterableTest = decltype(test_iterable<T>(0));
|
||||
}
|
||||
|
||||
template<typename T> struct ToString {
|
||||
template<typename T, typename = void>
|
||||
struct ToString;
|
||||
|
||||
template<typename T>
|
||||
struct ToString<T, EnableIf<detail::IterableTest<T>::value>> {
|
||||
using Argument = T;
|
||||
using Result = String;
|
||||
|
||||
template<typename U>
|
||||
static String to_str(const U &v,
|
||||
EnableIf<detail::ToStringTest<U>::value, bool> = true
|
||||
) {
|
||||
return v.to_string();
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
static String to_str(const U &v,
|
||||
EnableIf<!detail::ToStringTest<U>::value &&
|
||||
!IsScalar<U>::value, bool> = true
|
||||
) {
|
||||
String operator()(const T &v) const {
|
||||
String ret("{");
|
||||
ret += concat(octa::iter(v), ", ", ToString<
|
||||
RemoveCv<RemoveReference<
|
||||
|
@ -512,20 +512,34 @@ template<typename T> struct ToString {
|
|||
ret += "}";
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename U>
|
||||
static String to_str(const U &v,
|
||||
EnableIf<!detail::ToStringTest<U>::value &&
|
||||
IsScalar<U>::value, bool> = true
|
||||
) {
|
||||
return ToString<U>()(v);
|
||||
}
|
||||
template<typename T>
|
||||
struct ToString<T, EnableIf<IsScalar<T>::value>> {
|
||||
using Argument = T;
|
||||
using Result = String;
|
||||
|
||||
String operator()(const T &v) const {
|
||||
return to_str(v);
|
||||
return ToString<T>()(v);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct ToString<T, EnableIf<detail::ToStringTest<T>::value>> {
|
||||
using Argument = T;
|
||||
using Result = String;
|
||||
|
||||
String operator()(const T &v) const {
|
||||
return v.to_string();
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T> struct ToString<const T, EnableIf<
|
||||
!detail::IterableTest<T>::value &&
|
||||
!detail::ToStringTest<T>::value &&
|
||||
!IsScalar<T>::value
|
||||
>>: ToString<T> {};
|
||||
|
||||
namespace detail {
|
||||
template<typename T>
|
||||
void str_printf(Vector<char> *s, const char *fmt, T v) {
|
||||
|
@ -637,10 +651,8 @@ template<typename T, typename U> struct ToString<Pair<T, U>> {
|
|||
}
|
||||
};
|
||||
|
||||
template<typename T> struct ToString<const T>: ToString<T> {};
|
||||
|
||||
template<typename T, typename = decltype(ToString<T>()(declval<T>()))>
|
||||
String to_string(const T &v) {
|
||||
template<typename T>
|
||||
typename ToString<T>::Result to_string(const T &v) {
|
||||
return ToString<T>()(v);
|
||||
}
|
||||
|
||||
|
|
|
@ -277,10 +277,10 @@ class Tuple {
|
|||
friend TupleElement<I, Tuple<T...>> &get(Tuple<T...> &);
|
||||
|
||||
template<Size I, typename ...T>
|
||||
friend TupleElement<I, Tuple<T...>> &get(const Tuple<T...> &);
|
||||
friend const TupleElement<I, Tuple<T...>> &get(const Tuple<T...> &);
|
||||
|
||||
template<Size I, typename ...T>
|
||||
friend TupleElement<I, Tuple<T...>> &get(Tuple<T...> &&);
|
||||
friend TupleElement<I, Tuple<T...>> &&get(Tuple<T...> &&);
|
||||
|
||||
public:
|
||||
template<bool D = true, typename = EnableIf<
|
||||
|
|
Loading…
Reference in a new issue