Skip to content

Commit e73f2cc

Browse files
committed
feat: introduce Scalar and StructLike interfaces for Transform evaluation
1 parent a5bcd45 commit e73f2cc

File tree

1 file changed

+278
-0
lines changed

1 file changed

+278
-0
lines changed

src/iceberg/struct_like.h

Lines changed: 278 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,278 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
#pragma once
21+
22+
#include <string>
23+
#include <vector>
24+
25+
#include "iceberg/iceberg_export.h"
26+
#include "iceberg/result.h"
27+
#include "iceberg/type.h"
28+
29+
namespace iceberg {
30+
31+
class Scalar;
32+
class StructScalar;
33+
class ArrayScalar;
34+
class ScalarVisitor;
35+
class StructLike;
36+
class StructLikeVisitor;
37+
/**
38+
* @brief Base class representing a generic scalar value.
39+
*/
40+
class ICEBERG_EXPORT Scalar {
41+
public:
42+
virtual ~Scalar() = default;
43+
44+
/**
45+
* @brief Checks if the scalar represents a null value.
46+
* @return true if the value is null, false otherwise.
47+
*/
48+
virtual bool IsNull() const = 0;
49+
50+
/**
51+
* @brief Casts the scalar to a specific derived type.
52+
* @tparam T The target derived Scalar type.
53+
* @return Reference to the casted value.
54+
* @throws std::bad_cast if the cast fails.
55+
*/
56+
template <typename T>
57+
const T& as() const {
58+
auto ptr = dynamic_cast<const T*>(this);
59+
if (!ptr) throw std::bad_cast();
60+
return *ptr;
61+
}
62+
63+
/**
64+
* @brief Creates a deep copy of the scalar.
65+
* @return A shared pointer to the cloned scalar.
66+
*/
67+
virtual std::shared_ptr<Scalar> clone() const = 0;
68+
69+
/**
70+
* @brief Accepts a visitor for dispatching based on scalar type.
71+
* @param visitor The visitor to accept.
72+
*/
73+
virtual void accept(ScalarVisitor& visitor) const = 0;
74+
};
75+
76+
/**
77+
* @brief Visitor interface for Scalar, supporting type-dispatched operations.
78+
*/
79+
class ICEBERG_EXPORT ScalarVisitor {
80+
public:
81+
virtual ~ScalarVisitor() = default;
82+
83+
/// Visit methods for primitive types
84+
virtual void visit(int32_t value) = 0;
85+
virtual void visit(int64_t value) = 0;
86+
virtual void visit(float value) = 0;
87+
virtual void visit(double value) = 0;
88+
virtual void visit(bool value) = 0;
89+
virtual void visit(const std::string& value) = 0;
90+
91+
/**
92+
* @brief Called when visiting a null scalar.
93+
*/
94+
virtual void visitNull() = 0;
95+
96+
/// Visit methods for complex types
97+
virtual void visitStruct(const StructScalar& value) = 0;
98+
virtual void visitArray(const ArrayScalar& value) = 0;
99+
};
100+
101+
/**
102+
* @brief Represents a scalar that holds a primitive value.
103+
* @tparam T The type of the primitive value.
104+
*/
105+
template <typename T>
106+
class ICEBERG_EXPORT PrimitiveScalar : public Scalar {
107+
public:
108+
/**
109+
* @brief Constructs a PrimitiveScalar from an optional value.
110+
* @param value The optional primitive value.
111+
*/
112+
explicit PrimitiveScalar(std::optional<T> value) : value_(std::move(value)) {}
113+
114+
bool IsNull() const override { return !value_.has_value(); }
115+
116+
/**
117+
* @brief Gets the actual value held by the scalar.
118+
* @return Reference to the value.
119+
* @note Behavior is undefined if the scalar is null.
120+
*/
121+
const T& value() const { return *value_; }
122+
123+
/**
124+
* @brief (Deprecated) Type-specific accessor for raw value.
125+
* @tparam U Must match T.
126+
* @return Reference to the value if types match.
127+
* @throws std::bad_cast if U does not match T.
128+
*/
129+
template <typename U>
130+
const U& as() const {
131+
if constexpr (std::is_same_v<T, U>) return *value_;
132+
throw std::bad_cast();
133+
}
134+
135+
std::shared_ptr<Scalar> clone() const override {
136+
return std::make_shared<PrimitiveScalar<T>>(value_);
137+
}
138+
139+
void accept(ScalarVisitor& visitor) const override {
140+
if (IsNull()) {
141+
visitor.visitNull();
142+
} else {
143+
visitor.visit(*value_);
144+
}
145+
}
146+
147+
private:
148+
std::optional<T> value_;
149+
};
150+
151+
// Aliases for common primitive scalar types
152+
using Int32Scalar = PrimitiveScalar<int32_t>;
153+
using Int64Scalar = PrimitiveScalar<int64_t>;
154+
using DoubleScalar = PrimitiveScalar<double>;
155+
using StringScalar = PrimitiveScalar<std::string>;
156+
using BoolScalar = PrimitiveScalar<bool>;
157+
158+
/**
159+
* @brief Base class for scalars that contain a vector of child Scalars.
160+
* @tparam Derived The concrete subclass type (CRTP).
161+
*/
162+
template <typename Derived>
163+
class VectorScalarBase : public Scalar {
164+
public:
165+
/**
166+
* @brief Constructs a VectorScalarBase.
167+
* @param values Child scalar values.
168+
* @param is_null Whether the entire scalar is null.
169+
*/
170+
explicit VectorScalarBase(std::vector<std::shared_ptr<Scalar>> values,
171+
bool is_null = false)
172+
: values_(std::move(values)), is_null_(is_null) {}
173+
174+
/**
175+
* @brief Gets the child scalar values.
176+
* @return Vector of shared pointers to child Scalars.
177+
*/
178+
const std::vector<std::shared_ptr<Scalar>>& value() const { return values_; }
179+
180+
bool IsNull() const override { return is_null_; }
181+
182+
std::shared_ptr<Scalar> clone() const override {
183+
std::vector<std::shared_ptr<Scalar>> cloned;
184+
for (const auto& v : values_) {
185+
cloned.push_back(v->clone());
186+
}
187+
return std::make_shared<Derived>(std::move(cloned), is_null_);
188+
}
189+
190+
protected:
191+
std::vector<std::shared_ptr<Scalar>> values_;
192+
bool is_null_;
193+
};
194+
195+
/**
196+
* @brief Represents a struct-like scalar (tuple of fields).
197+
*/
198+
class StructScalar : public VectorScalarBase<StructScalar> {
199+
public:
200+
using VectorScalarBase::VectorScalarBase;
201+
202+
void accept(ScalarVisitor& visitor) const override {
203+
if (IsNull()) {
204+
visitor.visitNull();
205+
} else {
206+
visitor.visitStruct(*this);
207+
}
208+
}
209+
};
210+
211+
/**
212+
* @brief Represents an array-like scalar (list of values).
213+
*/
214+
class ArrayScalar : public VectorScalarBase<ArrayScalar> {
215+
public:
216+
using VectorScalarBase::VectorScalarBase;
217+
218+
void accept(ScalarVisitor& visitor) const override {
219+
if (IsNull()) {
220+
visitor.visitNull();
221+
} else {
222+
visitor.visitArray(*this);
223+
}
224+
}
225+
};
226+
227+
/**
228+
* @brief Abstract interface for structured field access.
229+
*/
230+
class ICEBERG_EXPORT StructLike {
231+
public:
232+
virtual ~StructLike() = default;
233+
234+
/**
235+
* @brief Gets the type of the structure.
236+
* @return Reference to the StructType.
237+
*/
238+
virtual const StructType& struct_type() const = 0;
239+
240+
/**
241+
* @brief Gets the number of fields.
242+
* @return Number of fields.
243+
*/
244+
virtual int32_t size() const = 0;
245+
246+
/**
247+
* @brief Gets the value of a field by position.
248+
* @param pos The zero-based index of the field.
249+
* @return Reference to the scalar value.
250+
*/
251+
virtual const Scalar& get(int32_t pos) const = 0;
252+
253+
/**
254+
* @brief Sets the value of a field by position.
255+
* @param pos The zero-based index of the field.
256+
* @param value The scalar to assign.
257+
* @return Status indicating success or failure.
258+
*/
259+
virtual Status set(int32_t pos, std::shared_ptr<Scalar> value) = 0;
260+
};
261+
262+
/**
263+
* @brief Visitor interface for traversing StructLike fields.
264+
*/
265+
class ICEBERG_EXPORT StructLikeVisitor {
266+
public:
267+
virtual ~StructLikeVisitor() = default;
268+
269+
/**
270+
* @brief Visits a single field of a StructLike object.
271+
* @param pos The index of the field.
272+
* @param type The type of the field.
273+
* @param value The scalar value of the field.
274+
*/
275+
virtual void visitField(int pos, const Type& type, const Scalar& value) = 0;
276+
};
277+
278+
} // namespace iceberg

0 commit comments

Comments
 (0)