aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHåvard Pettersen <havardpe@oath.com>2020-06-13 15:08:51 +0000
committerHåvard Pettersen <havardpe@oath.com>2020-06-13 15:08:51 +0000
commitc9c54cbc1f20ed5f54bc63035fe7881604c795ff (patch)
treefeccbfb366083d0b9558faa4b898b61d8eb61cad
parent24a8b542e20c8758f2d5973fc21e979b80247dae (diff)
auto-detect actual type typify results
-rw-r--r--eval/src/vespa/eval/eval/aggr.h6
-rw-r--r--vespalib/src/vespa/vespalib/util/typify.h40
2 files changed, 30 insertions, 16 deletions
diff --git a/eval/src/vespa/eval/eval/aggr.h b/eval/src/vespa/eval/eval/aggr.h
index e7431c2c23b..169f0b1d2af 100644
--- a/eval/src/vespa/eval/eval/aggr.h
+++ b/eval/src/vespa/eval/eval/aggr.h
@@ -2,6 +2,7 @@
#pragma once
+#include <vespa/vespalib/util/typify.h>
#include <vespa/vespalib/stllike/string.h>
#include <vector>
#include <map>
@@ -120,10 +121,7 @@ public:
} // namespave vespalib::eval::aggr
struct TypifyAggr {
- template <template<typename> typename A> struct Result {
- static constexpr bool is_type = false;
- template <typename T> using templ = A<T>;
- };
+ template <template<typename> typename TT> using Result = TypifyResultSimpleTemplate<TT>;
template <typename F> static decltype(auto) resolve(Aggr aggr, F &&f) {
switch (aggr) {
case Aggr::AVG: return f(Result<aggr::Avg>());
diff --git a/vespalib/src/vespa/vespalib/util/typify.h b/vespalib/src/vespa/vespalib/util/typify.h
index a2a24baca41..afedb4219a5 100644
--- a/vespalib/src/vespa/vespalib/util/typify.h
+++ b/vespalib/src/vespa/vespalib/util/typify.h
@@ -10,27 +10,40 @@ namespace vespalib {
//-----------------------------------------------------------------------------
/**
- * Typification result for values resolving into actual types.
+ * Typification result for values resolving into actual types. Using
+ * this exact template is not required, but the result type must have
+ * the name 'type' for the auto-unwrapping performed by typify_invoke
+ * to work.
**/
template <typename T> struct TypifyResultType {
- static constexpr bool is_type = true;
using type = T;
};
/**
- * Typification result for values resolving into compile-time values
- * which are also types as long as they are kept inside their result
- * wrappers.
+ * Typification result for values resolving into non-types. Using this
+ * exact template is not required, but is supplied for
+ * convenience. The resolved compile-time value should be called
+ * 'value' for consistency across typifiers.
**/
template <typename T, T VALUE> struct TypifyResultValue {
- static constexpr bool is_type = false;
static constexpr T value = VALUE;
};
/**
+ * Typification result for values resolving into simple templates
+ * (templated on one type). Using this exact template is not required,
+ * but is supplied as convenience and example. The resolved template
+ * should be called 'templ' for consistency across typifiers.
+ **/
+template <template<typename> typename TT> struct TypifyResultSimpleTemplate {
+ template <typename T> using templ = TT<T>;
+};
+
+/**
* A Typifier is able to take a run-time value and resolve it into a
- * type. The resolve result is passed to the specified function in the
- * form of a thin result wrapper.
+ * type, non-type constant value or a template. The resolve result is
+ * passed to the specified function in the form of a thin result
+ * wrapper.
**/
struct TypifyBool {
template <bool VALUE> using Result = TypifyResultValue<bool, VALUE>;
@@ -58,6 +71,8 @@ template <size_t N, typename Typifier, typename Target, typename ...Rs> struct T
static_assert(sizeof...(Rs) == N);
return Target::template invoke<Rs...>();
}
+ template <class, class = std::void_t<>> struct has_type : std::false_type {};
+ template <class T> struct has_type<T, std::void_t<typename T::type>> : std::true_type {};
template <typename T, typename ...Args> static decltype(auto) select(T &&value, Args &&...args) {
if constexpr (N == sizeof...(Rs)) {
return Target::template invoke<Rs...>(std::forward<T>(value), std::forward<Args>(args)...);
@@ -65,7 +80,8 @@ template <size_t N, typename Typifier, typename Target, typename ...Rs> struct T
return Typifier::resolve(value, [&](auto t)->decltype(auto)
{
using X = decltype(t);
- if constexpr (X::is_type) {
+ constexpr bool x_has_type = has_type<X>::value;
+ if constexpr (x_has_type) {
return TypifyInvokeImpl<N, Typifier, Target, Rs..., typename X::type>::select(std::forward<Args>(args)...);
} else {
return TypifyInvokeImpl<N, Typifier, Target, Rs..., X>::select(std::forward<Args>(args)...);
@@ -82,9 +98,9 @@ template <size_t N, typename Typifier, typename Target, typename ...Rs> struct T
* the typification results from the N first parameters as template
* parameters. Note that typification results that are types are
* unwrapped before being used as template parameters while
- * typification results that are compile-time values are kept in their
- * wrappers when passed as template parameters. Please refer to the
- * unit test for examples.
+ * typification results that are non-types or templates are kept in
+ * their wrappers when passed as template parameters. Please refer to
+ * the unit test for examples.
**/
template <size_t N, typename Typifier, typename Target, typename ...Args> decltype(auto) typify_invoke(Args && ...args) {
static_assert(N > 0);