blob: 05fb60568b193babe5c3364cacb8171327920e25 [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BASE_TASK_SCHEDULER_TASK_TRAITS_DETAILS_H_
#define BASE_TASK_SCHEDULER_TASK_TRAITS_DETAILS_H_
#include <type_traits>
#include <utility>
namespace base {
namespace internal {
// HasArgOfType<CheckedType, ArgTypes...>::value is true iff a type in ArgTypes
// matches CheckedType.
template <class...>
struct HasArgOfType : std::false_type {};
template <class CheckedType, class FirstArgType, class... ArgTypes>
struct HasArgOfType<CheckedType, FirstArgType, ArgTypes...>
: std::conditional<std::is_same<CheckedType, FirstArgType>::value,
std::true_type,
HasArgOfType<CheckedType, ArgTypes...>>::type {};
// When the following call is made:
// GetValueFromArgListImpl(CallFirstTag(), GetterType(), args...);
// If |args| is empty, the compiler selects the first overload. This overload
// returns getter.GetDefaultValue(). If |args| is not empty, the compiler
// prefers using the second overload because the type of the first argument
// matches exactly. This overload returns getter.GetValueFromArg(first_arg),
// where |first_arg| is the first element in |args|. If
// getter.GetValueFromArg(first_arg) isn't defined, the compiler uses the third
// overload instead. This overload discards the first argument in |args| and
// makes a recursive call to GetValueFromArgListImpl() with CallFirstTag() as
// first argument.
// Tag dispatching.
struct CallSecondTag {};
struct CallFirstTag : CallSecondTag {};
// Overload 1: Default value.
template <class GetterType>
constexpr typename GetterType::ValueType GetValueFromArgListImpl(
CallFirstTag,
GetterType getter) {
return getter.GetDefaultValue();
}
// Overload 2: Get value from first argument. Check that no argument in |args|
// has the same type as |first_arg|.
template <class GetterType,
class FirstArgType,
class... ArgTypes,
class TestGetValueFromArgDefined =
decltype(std::declval<GetterType>().GetValueFromArg(
std::declval<FirstArgType>()))>
constexpr typename GetterType::ValueType GetValueFromArgListImpl(
CallFirstTag,
GetterType getter,
const FirstArgType& first_arg,
const ArgTypes&... args) {
static_assert(!HasArgOfType<FirstArgType, ArgTypes...>::value,
"Multiple arguments of the same type were provided to the "
"constructor of TaskTraits.");
return getter.GetValueFromArg(first_arg);
}
// Overload 3: Discard first argument.
template <class GetterType, class FirstArgType, class... ArgTypes>
constexpr typename GetterType::ValueType GetValueFromArgListImpl(
CallSecondTag,
GetterType getter,
const FirstArgType&,
const ArgTypes&... args) {
return GetValueFromArgListImpl(CallFirstTag(), getter, args...);
}
// If there is an argument |arg_of_type| of type Getter::ArgType in |args|,
// returns getter.GetValueFromArg(arg_of_type). If there are more than one
// argument of type Getter::ArgType in |args|, generates a compile-time error.
// Otherwise, returns getter.GetDefaultValue().
//
// |getter| must provide:
//
// ValueType:
// The return type of GetValueFromArgListImpl().
//
// ArgType:
// The type of the argument from which GetValueFromArgListImpl() derives its
// return value.
//
// ValueType GetValueFromArg(ArgType):
// Converts an argument of type ArgType into a value returned by
// GetValueFromArgListImpl().
//
// ValueType GetDefaultValue():
// Returns the value returned by GetValueFromArgListImpl() if none of its
// arguments is of type ArgType.
template <class GetterType, class... ArgTypes>
constexpr typename GetterType::ValueType GetValueFromArgList(
GetterType getter,
const ArgTypes&... args) {
return GetValueFromArgListImpl(CallFirstTag(), getter, args...);
}
template <typename ArgType>
struct BooleanArgGetter {
using ValueType = bool;
constexpr ValueType GetValueFromArg(ArgType) const { return true; }
constexpr ValueType GetDefaultValue() const { return false; }
};
template <typename ArgType, ArgType DefaultValue>
struct EnumArgGetter {
using ValueType = ArgType;
constexpr ValueType GetValueFromArg(ArgType arg) const { return arg; }
constexpr ValueType GetDefaultValue() const { return DefaultValue; }
};
// Allows instantiation of multiple types in one statement. Used to prevent
// instantiation of the constructor of TaskTraits with inappropriate argument
// types.
template <class...>
struct InitTypes {};
} // namespace internal
} // namespace base
#endif // BASE_TASK_SCHEDULER_TASK_TRAITS_DETAILS_H_