New C++ API#8741
Conversation
Signed-off-by: Mikhail Kot <mikhail@spiraldb.com>
Merging this PR will not alter performance
|
|
Please can we add the tests along side the code. |
Signed-off-by: Mikhail Kot <mikhail@spiraldb.com>
|
| Location | Candidate |
|---|---|
lang/cpp/include/vortex/common.hpp:18 / src/f16.cpp:12 |
float16_t::operator float() const noexcept |
lang/cpp/include/vortex/common.hpp:50 |
detail::to_ptype<T>() noexcept |
lang/cpp/include/vortex/estimate.hpp:21 |
explicit Estimate(vx_estimate raw) noexcept |
lang/cpp/include/vortex/array.hpp:144 / src/array.cpp:191 |
Array::nullable() const noexcept |
lang/cpp/include/vortex/scan.hpp:36 |
PullRange::iterator::operator*() const noexcept |
lang/cpp/include/vortex/scan.hpp:46 |
PullRange::iterator::operator==(std::default_sentinel_t) const noexcept |
lang/cpp/include/vortex/scan.hpp:55 |
PullRange(Source&) noexcept |
lang/cpp/include/vortex/scan.hpp:60 |
PullRange::end() noexcept |
lang/cpp/include/vortex/scan.hpp:112 |
Partition::batches() & noexcept |
lang/cpp/include/vortex/scan.hpp:223 |
Scan::partitions() & noexcept |
For PullRange's default iterator constructor, noexcept is also appropriate.
Its constructor taking std::optional<Item> can be conditional:
iterator(Source* src, std::optional<Item> first)
noexcept(std::is_nothrow_move_constructible_v<std::optional<Item>>);The private raw-handle adopting constructors are also safe to annotate, for
consistency:
Array(const vx_array*)DataType(const vx_dtype*)Expression(const vx_expression*)Scalar(vx_scalar*)Writer(vx_array_sink*)DataSource(const vx_data_source*, Session)Partition(vx_partition*, Session)ArrowStream(Session, ArrowArrayStream)- all four view constructors
Scan(vx_scan*, Estimate, Session) is the exception: it uses
std::make_unique<std::mutex>(), so it can allocate and must remain potentially
throwing.
Candidates that need an FFI contract decision first
These are non-allocating in the current implementation, but call Rust functions
declared extern "C-unwind":
Array::is_primitive(PType) constScalar::is_null() constValiditycopy constructor and copy assignment
They could become noexcept only if the FFI contract explicitly guarantees that
valid wrapper inputs cannot panic or unwind. Otherwise, leave them
unannotated.
Things that look like accessors but should not be noexcept
| Function | Why |
|---|---|
Array::size() |
vx_array_len dereferences through a panic-on-null FFI helper; a moved-from Array has a null handle. |
Array::has_dtype() |
A valid internal Union or Variant dtype can panic while converting to the FFI dtype variant. |
DataType::variant() |
Same Union/Variant conversion panic path. |
DataType::nullable() |
Uses a panic-on-null FFI helper on a moved-from object. |
DataSource::row_count() |
FFI dereferences a null handle and dispatches through a data-source trait. |
DataType::primitive_type() |
Panics for non-primitive dtypes. |
decimal_precision() / decimal_scale() |
Panic for non-decimal dtypes. |
fixed_size_list_size() |
Panic for a non-fixed-size-list dtype. |
PrimitiveView<bool>::value() |
Panics on an out-of-bounds index. |
Array::dtype(), DataSource::dtype(), Scalar::dtype() |
Their FFI implementations allocate owning wrapper handles. |
| Copy constructors and assignments of owning wrapper types | FFI cloning allocates wrapper storage and moved-from values can produce null-handle panic paths. |
dtype::*, scalar::of, expression constructors/operators |
FFI allocation paths, and several have error or panic routes. |
begin() / operator++() on PullRange |
They call next() / next_partition(), which can throw VortexException. |
The destructors written without noexcept, such as ~Validity(),
~ValidityBits(), and ~ArrowStream(), are already implicitly
noexcept(true) in this design. Adding the spelling would be documentation
only.
Recommendation
Make the high-confidence annotations now, but first fix the FFI panic paths
before treating the remaining accessors as no-fail. In particular, moved-from
wrapper behavior needs an explicit policy: either guard null handles and
return or throw normally, or document every non-move operation as invalid after
move. The former gives a much better basis for adding noexcept to simple
predicates and accessors.
|
+1, I've removed noexcept everywhere except move constructors and free functions. |
|
Almost there! 🤝 |
Add new C++ API code.
Tests and examples will be added in the next PR