add octa::FunctionMakeDefaultConstructible, use in MapRange and FilterRange

This turns any callable object into a primitive default constructible type.
That is, for regular function objects, the type represents the object type
itself, for function pointers, the type represents the function pointer,
for simple lambdas the type represents a function pointer they map to
(only when the lambda doesn't capture) and for closures it represents
the right octa::Function type.
master
Daniel Kolesa 2015-06-07 18:06:29 +01:00
parent f4ca222dbd
commit 548de69102
2 changed files with 56 additions and 59 deletions

View File

@ -412,70 +412,13 @@ T foldr(R range, T init, F func) {
return init;
}
namespace detail {
template<typename F>
struct HofLambdaTypes: HofLambdaTypes<decltype(&F::operator())> {};
template<typename C, typename R, typename A>
struct HofLambdaTypes<R (C::*)(A) const> {
typedef R Result;
typedef A Arg;
};
template<typename F>
using HofLambdaRet = typename HofLambdaTypes<F>::Result;
template<typename F>
using HofLambdaArg = typename HofLambdaTypes<F>::Arg;
template<typename F>
struct HofFuncTest {
template<typename FF>
static char test(HofLambdaRet<FF> (*)(HofLambdaArg<FF>));
template<typename FF>
static int test(...);
static constexpr bool value = (sizeof(test<F>(octa::declval<F>())) == 1);
};
template<typename F, bool = HofFuncTest<F>::value>
struct HofFuncTypeObjBase {
typedef octa::Function<HofLambdaRet<F>(HofLambdaArg<F>)> Type;
};
template<typename F>
struct HofFuncTypeObjBase<F, true> {
typedef HofLambdaRet<F> (*Type)(HofLambdaArg<F>);
};
template<typename F, bool = octa::IsDefaultConstructible<F>::value &&
octa::IsMoveConstructible<F>::value
> struct HofFuncTypeObj {
typedef typename HofFuncTypeObjBase<F>::Type Type;
};
template<typename F>
struct HofFuncTypeObj<F, true> {
typedef F Type;
};
template<typename F, bool = octa::IsClass<F>::value>
struct HofFuncType {
typedef F Type;
};
template<typename F>
struct HofFuncType<F, true> {
typedef typename HofFuncTypeObj<F>::Type Type;
};
}
template<typename T, typename F, typename R>
struct MapRange: InputRange<
MapRange<T, F, R>, octa::RangeCategory<T>, R, R, octa::RangeSize<T>
> {
private:
T p_range;
typename octa::detail::HofFuncType<F>::Type p_func;
typename octa::FunctionMakeDefaultConstructible<F> p_func;
public:
MapRange(): p_range(), p_func() {}
@ -567,7 +510,7 @@ struct FilterRange: InputRange<
> {
private:
T p_range;
typename octa::detail::HofFuncType<F>::Type p_pred;
typename octa::FunctionMakeDefaultConstructible<F> p_pred;
void advance_valid() {
while (!p_range.empty() && !p_pred(front())) p_range.pop_front();

View File

@ -735,6 +735,60 @@ bool operator!=(nullptr_t, const Function<T> &rhs) { return rhs; }
template<typename T>
bool operator!=(const Function<T> &lhs, nullptr_t) { return lhs; }
namespace detail {
template<typename F>
struct DcLambdaTypes: DcLambdaTypes<decltype(&F::operator())> {};
template<typename C, typename R, typename ...A>
struct DcLambdaTypes<R (C::*)(A...) const> {
typedef R (*Ptr)(A...);
typedef octa::Function<R(A...)> Obj;
};
template<typename F>
struct DcFuncTest {
template<typename FF>
static char test(typename DcLambdaTypes<FF>::Ptr);
template<typename FF>
static int test(...);
static constexpr bool value = (sizeof(test<F>(octa::declval<F>())) == 1);
};
template<typename F, bool = DcFuncTest<F>::value>
struct DcFuncTypeObjBase {
typedef typename DcLambdaTypes<F>::Obj Type;
};
template<typename F>
struct DcFuncTypeObjBase<F, true> {
typedef typename DcLambdaTypes<F>::Ptr Type;
};
template<typename F, bool = octa::IsDefaultConstructible<F>::value &&
octa::IsMoveConstructible<F>::value
> struct DcFuncTypeObj {
typedef typename DcFuncTypeObjBase<F>::Type Type;
};
template<typename F>
struct DcFuncTypeObj<F, true> {
typedef F Type;
};
template<typename F, bool = octa::IsClass<F>::value>
struct DcFuncType {
typedef F Type;
};
template<typename F>
struct DcFuncType<F, true> {
typedef typename DcFuncTypeObj<F>::Type Type;
};
}
template<typename F> using FunctionMakeDefaultConstructible
= typename octa::detail::DcFuncType<F>::Type;
} /* namespace octa */
#endif