blob: 60022f551982b06e00f27e2345c2070d57e483bd [file] [log] [blame]
/**
* Copyright 2016, Quickstep Research Group, Computer Sciences Department,
* University of Wisconsin—Madison.
*
* 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 QUICKSTEP_UTILITY_TEMPLATE_UTIL_HPP_
#define QUICKSTEP_UTILITY_TEMPLATE_UTIL_HPP_
#include <cstddef>
#include <tuple>
#include <utility>
namespace quickstep {
/** \addtogroup Utility
* @{
*/
/**
* @brief Represents a compile-time sequence of integers.
*
* Sequence is defined here for C++11 compatibility. For C++14 and above,
* std::integer_sequence can be used to achieve the same functionality.
*
* TODO(jianqiao): directly use std::integer_sequence if having C++14 support.
*/
template<std::size_t ...>
struct Sequence {};
/**
* @brief The helper class for creating Sequence. MakeSequence<N>::type is
* equivalent to Sequence<1,2,...,N>.
*
* MakeSequence is defined here for C++11 compatibility. For C++14 and above,
* std::make_index_sequence can be used to achieve the same functionality.
*
* TODO(jianqiao): directly use std::make_index_sequence if having C++14 support.
*/
template<std::size_t N, std::size_t ...S>
struct MakeSequence : MakeSequence<N-1, N-1, S...> {};
template<std::size_t ...S>
struct MakeSequence<0, S...> {
typedef Sequence<S...> type;
};
/**
* @brief Final step of CreateBoolInstantiatedInstance. Now all bool_values are
* ready. Instantiate the template and create (i.e. new) an instance.
*/
template <template <bool ...> class T, class ReturnT,
bool ...bool_values, std::size_t ...i,
typename Tuple>
inline ReturnT* CreateBoolInstantiatedInstanceInner(Tuple &&args,
Sequence<i...> &&indices) {
return new T<bool_values...>(std::get<i>(std::forward<Tuple>(args))...);
}
/**
* @brief Edge case of the recursive CreateBoolInstantiatedInstance function
* when all bool variables have been branched and replaced with compile-time
* bool constants.
*/
template <template <bool ...> class T, class ReturnT,
bool ...bool_values,
typename Tuple>
inline ReturnT* CreateBoolInstantiatedInstance(Tuple &&args) {
// Note that the constructor arguments have been forwarded as a tuple (args).
// Here we generate a compile-time index sequence (i.e. typename MakeSequence<n_args>::type())
// for the tuple, so that the tuple can be unpacked as a sequence of constructor
// parameters in CreateBoolInstantiatedInstanceInner.
constexpr std::size_t n_args = std::tuple_size<Tuple>::value;
return CreateBoolInstantiatedInstanceInner<T, ReturnT, bool_values...>(
std::forward<Tuple>(args), typename MakeSequence<n_args>::type());
}
/**
* @brief A helper function for creating bool branched templates.
*
* The scenario for using this helper function is that, suppose we have a class
* where all template parameters are bools:
* --
* template <bool c1, bool c2, bool c3>
* class SomeClass : public BaseClass {
* // This simple function will be invoked in computationally-intensive loops.
* inline SomeType someSimpleFunction(...) {
* if (c1) {
* doSomeThing1();
* }
* if (c2) {
* doSomeThing2();
* }
* if (c3) {
* doSomeThing3();
* }
* }
* };
* --
* Typically, this bool-paramterized template is for performance consideration.
* That is, we would like to make a copy of code for each configuration of bool
* values, so that there will be no branchings in someSimpleFunction().
*
* The problem is that, to conditionally instantiate the template, given bool
* variables c1, c2, c3, we have to do something like this:
* --
* if (c1) {
* if (c2) {
* if (c3) {
* return new SomeClass<true, true, true>(some_args...);
* } else {
* return new SomeClass<true, true, false>(some_args...);
* }
* } else {
* if (c3) {
* return new SomeClass<true, false, true>(some_args...);
* } else {
* return new SomeClass<true, false, false>(some_args...);
* }
* } else {
* ...
* }
* --
* Then there will be power(2,N) branches if the template has N bool parameters,
* making it tedious to do the instantiating.
*
* Now, this helper function can achieve the branched instantiation in one
* statement as:
* --
* return CreateBoolInstantiatedInstance<SomeClass,BaseClass>(
* std::forward_as_tuple(some_args...), c1, c2, c3);
* --
*/
template <template <bool ...> class T, class ReturnT,
bool ...bool_values, typename ...Bools,
typename Tuple>
inline ReturnT* CreateBoolInstantiatedInstance(Tuple &&args,
const bool tparam,
const Bools ...rest_tparams) {
if (tparam) {
return CreateBoolInstantiatedInstance<T, ReturnT, bool_values..., true>(
std::forward<Tuple>(args), rest_tparams...);
} else {
return CreateBoolInstantiatedInstance<T, ReturnT, bool_values..., false>(
std::forward<Tuple>(args), rest_tparams...);
}
}
/** @} */
} // namespace quickstep
#endif // QUICKSTEP_UTILITY_TEMPLATE_UTIL_HPP_