Warum Daten verwenden, wenn wir eine Binärsuche zur Kompilierzeit mit Vorlagenerweiterung berechnen können?
Synopsis: Dieser Code generiert eine benutzerdefinierte lower_bound-Implementierung für jede Indexsequenz.
Voraussetzungen: Jeder Index muss im Tupel in aufsteigender Reihenfolge erscheinen.
Ergebnisse: bei Clang 3.9.1 wird kein Eingabearray generiert. Der Compiler vergleicht lediglich jede Grenze in der effizientesten Reihenfolge. GCC entscheidet ein Array zu erstellen und effektiv implementieren lower_bound selbst (wow!)
Code:
#include <utility>
#include <tuple>
// turn values into types
template<std::size_t I> using index = std::integral_constant<std::size_t, I>;
// termination case
template<class T, class Tuple, std::size_t it>
std::size_t iteration(T value, Tuple&&, index<it>, index<0>)
{
return it;
}
// end of search 'else' path which will not be taken but there must
// be code available at compile time
template<class T, class Tuple, std::size_t first, std::size_t count, std::enable_if_t<(first >= count)>* = nullptr>
std::size_t iteration(T value, Tuple&& tuple, index<first>, index<count>)
{
return count-1;
}
// normal iteration of the lower_bound loop
template<class T, class Tuple, std::size_t first, std::size_t count, std::enable_if_t<(first < count)>* = nullptr>
std::size_t iteration(T value, Tuple&& tuple, index<first>, index<count>)
{
constexpr auto step = count/2;
constexpr auto it = first + step;
if(std::get<it>(tuple) < value)
{
return iteration(value, std::forward<Tuple>(tuple), index<it>(), index<step + 1>());
}
else {
return iteration(value, std::forward<Tuple>(tuple), index<first>(), index<step>());
}
}
// expand out a lower-bound algorithm from a tuple of bounds
template<class Tuple, class T>
constexpr std::size_t tuple_lower_bound(Tuple&& tuple, const T& value)
{
constexpr auto count = index<std::tuple_size<std::decay_t<Tuple>>::value>();
constexpr auto first = index<0>();
return iteration(value, std::forward<Tuple>(tuple), first, count);
}
int GetScalingFactor(int input)
{
static constexpr auto indexes = std::make_tuple(13107, 19660, 26214, 32767, 39321, 45874, 52428, 58981);
static constexpr std::array<int, std::tuple_size<std::decay_t<decltype(indexes)>>::value + 1> factors =
{{
72816, 81918, 93621, 109225, 131070, 163837, 218450, 327675, 0
}};
auto i = tuple_lower_bound(indexes, input + 1);
return factors[i];
}
int main()
{
extern int get_input();
auto s1 = GetScalingFactor(get_input());
return s1;
}
* Warum * können Sie nicht verwenden Division oder Modulo? Ganzzahlige Division ist normalerweise sehr schnell. –
'std :: lower_bound' könnte eine gute Alternative sein. – Jarod42
Erfahren Sie mehr über binäre Suche? –