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 | |
| } |