| /** |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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_EQUALS_ANY_CONSTANT_HPP_ |
| #define QUICKSTEP_UTILITY_EQUALS_ANY_CONSTANT_HPP_ |
| |
| #include <type_traits> |
| |
| namespace quickstep { |
| |
| /** \addtogroup Utility |
| * @{ |
| */ |
| |
| /** |
| * @brief EqualsAnyConstant is an overloaded family of function templates that |
| * simply see if a runtime 'check' value is equal to any number of |
| * compile-time constants (which are given as template parameters). |
| * @note Obviously there are a number of ways to accomplish such a simple task. |
| * Each of them has some problems, however: |
| * 1. A series of if/else statements - very verbose and pontentially |
| * slow for a large number of constants (although GCC and Clang are |
| * smart enough to collapse this down into a jump table at -O3). |
| * 2. A switch statement - potentially faster than if/else statements, |
| * because the compiler will convert it to a jump table if there are |
| * more than a few cases. Still verbose, though. |
| * 3. Looping over an array of constants. Less verbose (particularly if |
| * using a standard-library template from <algorithm> like |
| * std::find), but just as slow if not worse than the if/else |
| * statements. |
| * The approach here is to have the concise invocations of |
| * EqualsAnyConstant expand out to switch statements for reasonable |
| * numbers of constants (currently 8 or less). This gives us the |
| * efficiency of option #2 with conciseness even better than option #3. |
| * For larger numbers of constants, a variadic template is included that |
| * will (at compile time, not run time) recursively expand into switch |
| * statements that each cover up to 8 constants a piece (a smart compiler |
| * will even collapse them down into a single jump table; GCC and Clang |
| * do, at the very least). |
| **/ |
| template <typename T> |
| inline bool EqualsAnyConstant(const T check) { |
| return false; |
| } |
| |
| template <typename T, T c1> |
| inline bool EqualsAnyConstant(const T check) { |
| return check == c1; |
| } |
| |
| template <typename T, T c1, T c2> |
| inline bool EqualsAnyConstant(const T check) { |
| switch (check) { |
| case c1: |
| case c2: |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| template <typename T, T c1, T c2, T c3> |
| inline bool EqualsAnyConstant(const T check) { |
| switch (check) { |
| case c1: |
| case c2: |
| case c3: |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| |
| template <typename T, T c1, T c2, T c3, T c4> |
| inline bool EqualsAnyConstant(const T check) { |
| switch (check) { |
| case c1: |
| case c2: |
| case c3: |
| case c4: |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| template <typename T, T c1, T c2, T c3, T c4, T c5> |
| inline bool EqualsAnyConstant(const T check) { |
| switch (check) { |
| case c1: |
| case c2: |
| case c3: |
| case c4: |
| case c5: |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| template <typename T, T c1, T c2, T c3, T c4, T c5, T c6> |
| inline bool EqualsAnyConstant(const T check) { |
| switch (check) { |
| case c1: |
| case c2: |
| case c3: |
| case c4: |
| case c5: |
| case c6: |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| template <typename T, T c1, T c2, T c3, T c4, T c5, T c6, T c7> |
| inline bool EqualsAnyConstant(const T check) { |
| switch (check) { |
| case c1: |
| case c2: |
| case c3: |
| case c4: |
| case c5: |
| case c6: |
| case c7: |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| template <typename T, T c1, T c2, T c3, T c4, T c5, T c6, T c7, T c8, T ...tail_constants> |
| bool EqualsAnyConstant(const T check) { |
| switch (check) { |
| case c1: |
| case c2: |
| case c3: |
| case c4: |
| case c5: |
| case c6: |
| case c7: |
| case c8: |
| return true; |
| default: |
| return EqualsAnyConstant<T, tail_constants...>(check); |
| } |
| } |
| |
| /** |
| * @brief Helper macro for EqualsAnyConstant that adds a little bit of |
| * syntactic sugar to deduce the type of the checked expression. |
| **/ |
| #define QUICKSTEP_EQUALS_ANY_CONSTANT(check, ...) \ |
| (EqualsAnyConstant< \ |
| typename std::remove_reference<typename std::remove_cv<decltype(check)>::type>::type, \ |
| __VA_ARGS__ >(check)) |
| |
| /** @} */ |
| |
| } // namespace quickstep |
| |
| #endif // QUICKSTEP_UTILITY_EQUALS_ANY_CONSTANT_HPP_ |