Skip to content

Commit ea86234

Browse files
committed
fix
Signed-off-by: Mikhail Kot <mikhail@spiraldb.com>
1 parent fcc9abe commit ea86234

11 files changed

Lines changed: 923 additions & 587 deletions

File tree

lang/cpp/include/vortex/scalar.hpp

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,27 @@ class Scalar {
2626
bool is_null() const;
2727
DataType dtype() const;
2828

29+
/**
30+
* Read scalar's value.
31+
*
32+
* Supported types are bool, primitives, std::string_view, and BinaryView.
33+
*
34+
* std::string_view/BinaryView's returned borrow from scalar and stay valid
35+
* while scalar is valud.
36+
*
37+
* Throws if scalar type does not match T or value is Null.
38+
*/
39+
template <element_type T>
40+
T get() const;
41+
42+
/**
43+
* Read a decimal scalar's unscaled value.
44+
* int8/16/32/64_t are supported.
45+
* Throws if scalar is not a decimal, is Null, or value does not fit in T.
46+
*/
47+
template <primitive_type T>
48+
T get_decimal() const;
49+
2950
private:
3051
friend struct detail::Access;
3152
explicit Scalar(vx_scalar *owned) : handle_(owned) {
@@ -40,6 +61,58 @@ class Scalar {
4061
std::unique_ptr<vx_scalar, Deleter> handle_;
4162
};
4263

64+
template <element_type T>
65+
T Scalar::get() const {
66+
vx_scalar *h = handle_.get();
67+
if constexpr (std::is_same_v<T, bool>) {
68+
return vx_scalar_get_bool(h);
69+
} else if constexpr (std::is_same_v<T, std::string_view>) {
70+
vx_view v = vx_scalar_get_utf8(h);
71+
return std::string_view(v.ptr, v.len);
72+
} else if constexpr (std::is_same_v<T, BinaryView>) {
73+
vx_view v = vx_scalar_get_binary(h);
74+
return BinaryView(reinterpret_cast<const std::byte *>(v.ptr), v.len);
75+
} else if constexpr (std::is_same_v<T, uint8_t>) {
76+
return vx_scalar_get_u8(h);
77+
} else if constexpr (std::is_same_v<T, uint16_t>) {
78+
return vx_scalar_get_u16(h);
79+
} else if constexpr (std::is_same_v<T, uint32_t>) {
80+
return vx_scalar_get_u32(h);
81+
} else if constexpr (std::is_same_v<T, uint64_t>) {
82+
return vx_scalar_get_u64(h);
83+
} else if constexpr (std::is_same_v<T, int8_t>) {
84+
return vx_scalar_get_i8(h);
85+
} else if constexpr (std::is_same_v<T, int16_t>) {
86+
return vx_scalar_get_i16(h);
87+
} else if constexpr (std::is_same_v<T, int32_t>) {
88+
return vx_scalar_get_i32(h);
89+
} else if constexpr (std::is_same_v<T, int64_t>) {
90+
return vx_scalar_get_i64(h);
91+
} else if constexpr (std::is_same_v<T, float>) {
92+
return vx_scalar_get_f32(h);
93+
} else if constexpr (std::is_same_v<T, double>) {
94+
return vx_scalar_get_f64(h);
95+
} else {
96+
static_assert(false, "f16 scalar get is not supported");
97+
}
98+
}
99+
100+
template <primitive_type T>
101+
T Scalar::get_decimal() const {
102+
vx_scalar *h = handle_.get();
103+
if constexpr (std::is_same_v<T, int8_t>) {
104+
return vx_scalar_get_decimal_i8(h);
105+
} else if constexpr (std::is_same_v<T, int16_t>) {
106+
return vx_scalar_get_decimal_i16(h);
107+
} else if constexpr (std::is_same_v<T, int32_t>) {
108+
return vx_scalar_get_decimal_i32(h);
109+
} else if constexpr (std::is_same_v<T, int64_t>) {
110+
return vx_scalar_get_decimal_i64(h);
111+
} else {
112+
static_assert(false, "unsupported decimal scalar get type");
113+
}
114+
}
115+
43116
namespace detail {
44117
vx_scalar *make_bool(bool value, bool nullable);
45118
vx_scalar *make_primitive(vx_ptype ptype, const void *value, bool nullable);

lang/cpp/src/array.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,11 @@ BytesView Array::bytes(const Session &session) const {
325325
}
326326

327327
bool PrimitiveView<bool>::value(size_t i) const {
328+
if (i >= size_) {
329+
throw VortexException("index " + std::to_string(i) + " out of bounds for view of size " +
330+
std::to_string(size_),
331+
ErrorCode::OutOfBounds);
332+
}
328333
return vx_array_get_bool(Access::c_ptr(canonical_), i);
329334
}
330335

lang/cpp/tests/expression.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ TEST_CASE("Operator overloading", "[expr]") {
8585
REQUIRE(bits.value(1));
8686
REQUIRE(bits.value(2));
8787
REQUIRE_FALSE(bits.value(3));
88+
REQUIRE_THROWS_AS(bits.value(data.size()), VortexException);
8889
}
8990

9091
TEST_CASE("Apply error", "[expr]") {

lang/cpp/tests/scalar.cpp

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ using namespace std::string_view_literals;
1010

1111
namespace {
1212
using enum vortex::PType;
13+
using scalar::decimal;
14+
using scalar::of;
1315

1416
TEST_CASE("Boolean scalar", "[scalar]") {
1517
Scalar s = scalar::of(true);
@@ -29,7 +31,7 @@ TEST_CASE("Integer scalars", "[scalar]") {
2931
}
3032

3133
TEST_CASE("Float scalars", "[scalar]") {
32-
REQUIRE(scalar::of(1.5F).dtype().primitive_type() == F32);
34+
REQUIRE(scalar::of(1.5f).dtype().primitive_type() == F32);
3335
REQUIRE(scalar::of(1.5).dtype().primitive_type() == F64);
3436
REQUIRE(scalar::of(float16_t {0x3C00}).dtype().primitive_type() == F16);
3537
}
@@ -87,6 +89,32 @@ TEST_CASE("Decimal scalars", "[scalar]") {
8789
REQUIRE(d64.dtype().decimal_scale() == 3);
8890
}
8991

92+
TEST_CASE("Primitive getters", "[scalar]") {
93+
REQUIRE(of<uint64_t>(1ULL << 40).get<uint64_t>() == (1ULL << 40));
94+
REQUIRE(of<int32_t>(-7).get<int32_t>() == -7);
95+
REQUIRE(of(2.5).get<double>() == 2.5);
96+
REQUIRE(of(true).get<bool>());
97+
}
98+
99+
TEST_CASE("String getters", "[scalar]") {
100+
Scalar s = of("hello"sv);
101+
REQUIRE(s.get<std::string_view>() == "hello"sv);
102+
103+
const std::byte bytes[] = {std::byte {1}, std::byte {2}, std::byte {0}, std::byte {4}};
104+
Scalar b = of(std::span<const std::byte> {bytes});
105+
BinaryView view = b.get<BinaryView>();
106+
REQUIRE(view.size() == 4);
107+
REQUIRE(view[0] == std::byte {1});
108+
REQUIRE(view[3] == std::byte {4});
109+
}
110+
111+
TEST_CASE("Decimal getters", "[scalar]") {
112+
REQUIRE(decimal<int8_t>(56, 5, 2).get_decimal<int8_t>() == 56);
113+
REQUIRE(decimal<int16_t>(1234, 5, 2).get_decimal<int16_t>() == 1234);
114+
REQUIRE(decimal<int32_t>(5678, 6, 2).get_decimal<int32_t>() == 5678);
115+
REQUIRE(decimal<int64_t>(99999, 12, 3).get_decimal<int64_t>() == 99999);
116+
}
117+
90118
TEST_CASE("Copy scalar", "[scalar]") {
91119
Scalar a = scalar::of<int64_t>(42);
92120
Scalar b = a;

0 commit comments

Comments
 (0)