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/algorithm.hh"
|
||||||
#include "octa/string.hh"
|
#include "octa/string.hh"
|
||||||
#include "octa/utility.hh"
|
#include "octa/utility.hh"
|
||||||
|
#include "octa/internal/tuple.hh"
|
||||||
|
|
||||||
namespace octa {
|
namespace octa {
|
||||||
|
|
||||||
|
@ -458,21 +459,46 @@ namespace detail {
|
||||||
template<typename T>
|
template<typename T>
|
||||||
using FmtRangeTest = decltype(test_fmt_range<T>(0));
|
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>
|
template<typename R, typename T>
|
||||||
inline Ptrdiff format_ritem(R &writer, Size &fmtn, bool esc, bool,
|
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);
|
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,
|
inline Ptrdiff format_ritem(R &writer, Size &fmtn, bool esc,
|
||||||
bool expandval, const char *fmt,
|
bool expandval, const char *fmt,
|
||||||
const Pair<T, U> &pair) {
|
const T &item,
|
||||||
|
EnableIf<IsTupleLike<T>::value, bool>
|
||||||
|
= true) {
|
||||||
if (expandval) {
|
if (expandval) {
|
||||||
return format_impl(writer, fmtn, esc, fmt, pair.first,
|
return FmtTupleUnpacker<TupleSize<T>::value>::unpack(writer,
|
||||||
pair.second);
|
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>
|
template<typename R, typename T>
|
||||||
|
@ -515,9 +541,8 @@ namespace detail {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T,
|
template<typename T>
|
||||||
typename = decltype(octa::to_string(declval<T>()))
|
static True test_fmt_tostr(decltype(octa::to_string(declval<T>())) *);
|
||||||
> static True test_fmt_tostr(int);
|
|
||||||
template<typename> static False test_fmt_tostr(...);
|
template<typename> static False test_fmt_tostr(...);
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
@ -756,7 +781,8 @@ namespace detail {
|
||||||
/* generic failure case */
|
/* generic failure case */
|
||||||
template<typename R, typename T>
|
template<typename R, typename T>
|
||||||
Ptrdiff write(R &, bool, const T &, EnableIf<
|
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) {
|
> = true) {
|
||||||
assert(false && "value cannot be formatted");
|
assert(false && "value cannot be formatted");
|
||||||
return -1;
|
return -1;
|
||||||
|
|
|
@ -485,24 +485,24 @@ namespace detail {
|
||||||
template<typename U> static int test(...);
|
template<typename U> static int test(...);
|
||||||
static constexpr bool value = (sizeof(test<T>(0)) == sizeof(char));
|
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 Argument = T;
|
||||||
using Result = String;
|
using Result = String;
|
||||||
|
|
||||||
template<typename U>
|
String operator()(const T &v) const {
|
||||||
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 ret("{");
|
String ret("{");
|
||||||
ret += concat(octa::iter(v), ", ", ToString<
|
ret += concat(octa::iter(v), ", ", ToString<
|
||||||
RemoveCv<RemoveReference<
|
RemoveCv<RemoveReference<
|
||||||
|
@ -512,20 +512,34 @@ template<typename T> struct ToString {
|
||||||
ret += "}";
|
ret += "}";
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
template<typename U>
|
template<typename T>
|
||||||
static String to_str(const U &v,
|
struct ToString<T, EnableIf<IsScalar<T>::value>> {
|
||||||
EnableIf<!detail::ToStringTest<U>::value &&
|
using Argument = T;
|
||||||
IsScalar<U>::value, bool> = true
|
using Result = String;
|
||||||
) {
|
|
||||||
return ToString<U>()(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
String operator()(const T &v) const {
|
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 {
|
namespace detail {
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void str_printf(Vector<char> *s, const char *fmt, T v) {
|
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 ToString<T>::Result to_string(const T &v) {
|
||||||
template<typename T, typename = decltype(ToString<T>()(declval<T>()))>
|
|
||||||
String to_string(const T &v) {
|
|
||||||
return ToString<T>()(v);
|
return ToString<T>()(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -277,10 +277,10 @@ class Tuple {
|
||||||
friend TupleElement<I, Tuple<T...>> &get(Tuple<T...> &);
|
friend TupleElement<I, Tuple<T...>> &get(Tuple<T...> &);
|
||||||
|
|
||||||
template<Size I, typename ...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>
|
template<Size I, typename ...T>
|
||||||
friend TupleElement<I, Tuple<T...>> &get(Tuple<T...> &&);
|
friend TupleElement<I, Tuple<T...>> &&get(Tuple<T...> &&);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
template<bool D = true, typename = EnableIf<
|
template<bool D = true, typename = EnableIf<
|
||||||
|
|
Loading…
Reference in a new issue