/*
|
* Copyright (C) 2018 The Android Open Source Project
|
*
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
* you may not use this file except in compliance with the License.
|
* You may obtain a copy of the License at
|
*
|
* http://www.apache.org/licenses/LICENSE-2.0
|
*
|
* Unless required by applicable law or agreed to in writing, software
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* See the License for the specific language governing permissions and
|
* limitations under the License.
|
*/
|
|
#ifndef IORAP_COMMON_TYPE_H
|
#define IORAP_COMMON_TYPE_H
|
|
#include <cstdint>
|
#include <tuple>
|
|
namespace iorap {
|
namespace introspect {
|
|
/*
|
* Simple types-as-value abstractions.
|
*
|
* Allow types to be passed as regular function parameters instead of using 'template' type
|
* parameters.
|
*
|
* This enables the following, more concise, pattern:
|
* ----------------------------
|
*
|
* Traditional metaprogramming with template parameters:
|
*
|
* template <typename ... Args>
|
* struct get_num_params {
|
* static constexpr size_t value = sizeof...(Args);
|
* };
|
*
|
* typename get_num_params<decltype("hello"), decltype("world")>::value == 2
|
* typename get_num_params<decltype(int), decltype(int), decltype(int), decltype(int)>::value == 4
|
*
|
* Alternative metaprogramming with values:
|
*
|
* constexpr auto get_num_params = [](auto&&... val) { return sizeof...(val); };
|
*
|
* get_num_params("hello", "world") == 2
|
* get_num_params(0,0,0,0) == 4
|
*/
|
|
/*
|
* A fully instantiated type wrapper.
|
*
|
* basic_type<T> is intended for overloading functions between different basic_types.
|
* type_c<T> is intended for instantiating new type wrappers as a short-hand (and not requiring
|
* typename).
|
*
|
* For basic_type<T> in particular it allows one to overload on basic_type<T> to handle specific
|
* types, and there's no requirement that T be constexpr, be default constructible, and no
|
* template specializations is necessary.
|
*
|
* void foo(basic_type<int>) {
|
* printf("int");
|
* }
|
*
|
* template <typename T>
|
* void foo(basic_type<T>) {
|
* printf("everything else");
|
* }
|
*
|
* as opposed to this verbosity
|
*
|
* template <typename T>
|
* struct foo {
|
* void operator() {
|
* printf("everything else");
|
* }
|
* };
|
*
|
* template <>
|
* struct foo<int> {
|
* void operator() {
|
* printf("int");
|
* }
|
* };
|
*
|
* OR this super-hack which works in rare situations
|
*
|
* void foo(int) {
|
* printf("int");
|
* }
|
*
|
* template <typename T>
|
* void foo(T&&) {
|
* printf("everything else")
|
* }
|
*
|
* Note that invoking the last foo(T&&) is particularly challenging. declval<T> fails at compilation
|
* with a static_assert, so a real value has to be constructed that is immediately discarded.
|
*/
|
template <typename T>
|
struct basic_type {
|
using type = T;
|
};
|
|
template <typename T>
|
struct type_impl {
|
struct _ : basic_type<T> { };
|
};
|
|
template <typename T>
|
using type = basic_type<T>; // typename type_impl<T>::_; // subclass of basic_type<T>
|
// TODO: why doesn't using type_impl::_ work with ADL?
|
|
template <typename T>
|
using type_t = type<T>;
|
|
template <typename T>
|
constexpr auto type_c = type<T>{};
|
|
template <auto X>
|
struct value_constant {
|
static constexpr auto value = X;
|
};
|
|
template <int X>
|
constexpr auto int_c = value_constant<X>{};
|
|
template <typename T>
|
constexpr bool dependent_false_v = false;
|
|
// Emit a static_assert(false) if the else branch in an 'if constexpr' is taken.
|
// Needs a type as the first parameter.
|
#define STATIC_FAIL(T, msg) static_assert(::iorap::introspect::dependent_false_v<T>, msg)
|
// Emit a static_assert(false) if an else branch in an 'if constexpr' is taken, used with
|
// (e.g. auto) values instead of types.
|
#define STATIC_FAIL_DT(var, msg) STATIC_FAIL(decltype(var), msg)
|
|
template <size_t i, typename Tuple, typename F>
|
static constexpr void for_each_impl(Tuple&& t, F&& f) {
|
if constexpr (i == std::tuple_size<std::decay_t<Tuple>>::value) {
|
return;
|
} else {
|
f(std::get<i>(std::forward<Tuple>(t)));
|
for_each_impl<i+1>(std::forward<Tuple>(t), std::forward<F>(f));
|
}
|
}
|
|
// for each Tuple<a1,a2,...,aN> invoke { f(a1); f(a2); ... ; f(aN); }
|
template <typename Tuple, typename F>
|
static constexpr void for_each(Tuple&& t, F&& f) {
|
return for_each_impl<0u>(std::forward<Tuple>(t), std::forward<F>(f));
|
}
|
|
// Perfect forwarding for structured binding.
|
//
|
// Example:
|
// auto&& [a,b] = whatever;
|
// return aliasing_forward<T>(a);
|
template <typename T, typename U>
|
constexpr decltype(auto) aliasing_forward(U&& val) noexcept {
|
if constexpr (std::is_lvalue_reference_v<T>) {
|
return val;
|
} else {
|
return std::move(val);
|
}
|
}
|
|
|
} // namespace introspect
|
} // namespace iorap
|
|
#endif // IORAP_COMMON_TYPE_H
|