SFINAE friendly ToString and expansion of any tuple-like type in format

master
Daniel Kolesa 2015-07-11 17:26:41 +01:00
parent a77f983015
commit 82a8ea3902
3 changed files with 75 additions and 37 deletions

View File

@ -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;

View File

@ -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);
}

View File

@ -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<