Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 16 additions & 10 deletions src/pantab/numeric_gen.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,22 @@
#include <array>
#include <cstddef>
#include <utility>
#include <variant>

// The Tableau Hyper API requires Numeric to be templated at compile time
// but the values are only known at runtime. This solution is adopted from
// https://stackoverflow.com/questions/78888913/creating-cartesian-product-from-integer-range-template-argument/78889229?noredirect=1#comment139097273_78889229
template <std::size_t N> constexpr auto to_integral_variant(std::size_t n) {
return [&]<std::size_t... Is>(std::index_sequence<Is...>) {
using ResType = std::variant<std::integral_constant<std::size_t, Is>...>;
std::array<ResType, N> all{
ResType{std::integral_constant<std::size_t, Is>{}}...};
return all[n];
}(std::make_index_sequence<N>());
// but the values are only known at runtime. This dispatches a runtime index
// n ∈ [0, N) to a compile-time integral_constant, calling f with it.
//
// Uses a function pointer table for O(1) dispatch. This replaces the previous
// std::variant + std::visit approach which was extremely slow to compile due
// to the cartesian product of two N-element variant visit dispatch tables.
template <std::size_t N, typename F>
constexpr void integral_dispatch(std::size_t n, F &&f) {
[&]<std::size_t... Is>(std::index_sequence<Is...>) {
using FnPtr = void (*)(F &);
const std::array<FnPtr, N> table{
{static_cast<FnPtr>([](F &fn) {
fn(std::integral_constant<std::size_t, Is>{});
})...}};
table[n](f);
}(std::make_index_sequence<N>{});
Comment on lines +15 to +23
}
20 changes: 10 additions & 10 deletions src/pantab/reader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
#include "numeric_gen.hpp"

#include <span>
#include <variant>
#include <vector>

#include <hyperapi/hyperapi.hpp>
Expand Down Expand Up @@ -296,18 +295,19 @@ class DecimalReadHelper : public ReadHelper {
throw nb::value_error("Numeric scale may not exceed 38!");
}

const auto decimal_string = std::visit(
[&value](auto P, auto S) -> std::string {
const auto decimal_string = [&]() -> std::string {
std::string result;
integral_dispatch<PrecisionLimit>(precision_, [&](auto P) {
integral_dispatch<PrecisionLimit>(scale_, [&](auto S) {
if constexpr (S() <= P()) {
const auto decimal_value = value.get<hyperapi::Numeric<P(), S()>>();
auto value_string = decimal_value.toString();
std::erase(value_string, '.');
return value_string;
result = decimal_value.toString();
std::erase(result, '.');
}
throw "unreachable";
},
to_integral_variant<PrecisionLimit>(precision_),
to_integral_variant<PrecisionLimit>(scale_));
});
});
return result;
}();
Comment on lines +298 to +310

const struct ArrowStringView sv {
decimal_string.data(), static_cast<int64_t>(decimal_string.size())
Expand Down
39 changes: 15 additions & 24 deletions src/pantab/writer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
#include <set>
#include <span>
#include <utility>
#include <variant>

static auto GetHyperTypeFromArrowSchema(struct ArrowSchema *schema,
ArrowError *error)
Expand Down Expand Up @@ -429,17 +428,13 @@ class DecimalInsertHelper : public InsertHelper {
}

if (CheckNull(idx)) {
std::visit(
[&](auto P, auto S) {
if constexpr (S() <= P()) {
InsertNull<hyperapi::Numeric<P(), S()>>();
return;
} else {
throw "unreachable";
}
},
to_integral_variant<PrecisionLimit>(precision_),
to_integral_variant<PrecisionLimit>(scale_));
integral_dispatch<PrecisionLimit>(precision_, [&](auto P) {
integral_dispatch<PrecisionLimit>(scale_, [&](auto S) {
if constexpr (S() <= P()) {
InsertNull<hyperapi::Numeric<P(), S()>>();
}
});
});
Comment on lines +431 to +437
return;
}

Expand Down Expand Up @@ -475,18 +470,14 @@ class DecimalInsertHelper : public InsertHelper {
}
}

std::visit(
[&](auto P, auto S) {
if constexpr (S() <= P()) {
const auto value = hyperapi::Numeric<P(), S()>{str};
InsertValue(std::move(value));
return;
} else {
throw "unreachable";
}
},
to_integral_variant<PrecisionLimit>(precision_),
to_integral_variant<PrecisionLimit>(scale_));
integral_dispatch<PrecisionLimit>(precision_, [&](auto P) {
integral_dispatch<PrecisionLimit>(scale_, [&](auto S) {
if constexpr (S() <= P()) {
const auto value = hyperapi::Numeric<P(), S()>{str};
InsertValue(std::move(value));
}
});
});
Comment on lines +473 to +480

ArrowBufferReset(&buffer);
}
Expand Down
Loading