Compile-time calculation of data lookup tables
by Len Popp
Acknowledgements
- Ashley Roll - https://github.com/AshleyRoll/cppcon21/blob/main/code/table_gen_1.cpp
- Jason Turner - https://tinyurl.com/constexpr2021
Compile-time calculation of data lookup tables
by Len Popp
Acknowledgements
// DataTable - Compile-time calculation of data lookup tables | |
// by Len Popp | |
// Ref: | |
// https://github.com/AshleyRoll/cppcon21/blob/main/code/table_gen_1.cpp - Ashley Roll | |
// https://tinyurl.com/constexpr2021 - Jason Turner | |
#include <array> | |
#include <algorithm> | |
#include <ranges> | |
// DataTable - Class template for static tables of pre-calculated data | |
// The table contains NUM_VALUES values of type VALUE_T. | |
// Each value is calculated by function FUNC_CALC1 which has this signature: | |
// VALUE_T FUNC_CALC1(std::size_t index, std::size_t numValues) | |
// Access to the data is read-only. | |
template<typename VALUE_T, std::size_t NUM_VALUES, VALUE_T FUNC_CALC1(std::size_t index, std::size_t numValues)> | |
class DataTable | |
{ | |
public: | |
// Constructor uses FUNC_CALC1 to fill dataArray | |
constexpr DataTable() | |
{ | |
for (std::size_t index = 0; index < NUM_VALUES; ++index) { | |
dataArray[index] = FUNC_CALC1(index, NUM_VALUES); | |
} | |
} | |
constexpr std::size_t size() const { return NUM_VALUES; } | |
constexpr const auto& getArray() const { return dataArray; } | |
constexpr const VALUE_T& operator[](std::size_t index) const { return dataArray[index]; } | |
private: | |
// dataArray is a fixed-size array of values that is initialized at compile time | |
VALUE_T dataArray[NUM_VALUES]; | |
}; |
// MakeDataTable - Compile-time calculation of data lookup tables | |
// by Len Popp | |
#include "DataTable.h" | |
#include <cmath> | |
#include <numbers> | |
#include <iostream> | |
// Example: SquareTable - A simple table calculated by a lambda | |
static constexpr DataTable<uint16_t, 10, | |
[](const std::size_t index, const std::size_t /*numValues*/) { | |
return static_cast<uint16_t>(index * index); | |
}> | |
SquareTable; | |
// Example: SineTable - A table of sine values converted to positive integers | |
// One extra entry is included (513 instead of 512) to help with interpolation. | |
// NOTE: This isn't supposed to work, but GCC declares most functions in <cmath> | |
// to be constexpr, which is non-standard but very useful! | |
#if defined(__GNUC__) | |
template<typename VALUE_T> | |
constexpr VALUE_T sineCalc(std::size_t index, std::size_t numValues) | |
{ | |
constexpr VALUE_T half = std::numeric_limits<VALUE_T>::max() / 2; | |
double phase = 2 * std::numbers::pi / (numValues-1) * index; | |
double sine = (std::sin(phase) + 1) * half; | |
return static_cast<VALUE_T>(std::round(sine)); | |
} | |
static constexpr DataTable<uint16_t, 512+1, sineCalc> SineTable; | |
#endif | |
int main() | |
{ | |
for (auto n : SquareTable.getArray()) { | |
std::cout << n << ' '; | |
} | |
std::cout << '\n'; | |
#if defined(__GNUC__) | |
for (auto n : SineTable.getArray()) { | |
std::cout << n << ' '; | |
} | |
std::cout << '\n'; | |
#endif | |
} |