blob: e856d73d6d62997b5d21131e0c70d5827f6d02d5 [file] [log] [blame]
/*
* 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