Skip to content
Merged
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
41 changes: 37 additions & 4 deletions include/tvm/ffi/extra/structural_visit.h
Original file line number Diff line number Diff line change
Expand Up @@ -487,9 +487,31 @@ enum class WalkOrder : int32_t {

namespace details {

/// \cond Doxygen_Suppress
// Return from the current raw or same-T Expected visit function if Result stops traversal.
// The rvalue-only proxy lets the enclosing return type select the representation.
/*!
* \brief Return from a visit hook if \p Result stops traversal.
*
* Propagates an ``Error`` or a ``VisitInterrupt`` out of the enclosing function
* and otherwise falls through. Works from a raw ``TVMFFIAny`` hook and from a
* typed ``Expected`` helper alike; the rvalue-only proxy lets the return type
* select the representation.
*
* A registered ``__s_visit__`` hook is one line per traversed field followed by
* the terminal return. A field skipped on purpose is guarded by a condition and
* carries a ``// skips:`` note saying why.
*
* \code{.cpp}
* TVMFFIAny FooVisit(StructuralVisitorObj* visitor, AnyView value) noexcept {
* const FooNode* self =
* details::AnyUnsafe::RawObjectPtrFromAnyViewAfterCheck<const FooNode>(value);
* TVM_FFI_S_VISIT_MAYBE_EARLY_RETURN(visitor->VisitExpected(self->a));
* TVM_FFI_S_VISIT_MAYBE_EARLY_RETURN(visitor->VisitExpected(self->b));
* TVM_FFI_S_VISIT_RETURN_NONE();
* }
* \endcode
*
* \param Result An expression yielding the descent result to inspect.
* \sa TVM_FFI_S_VISIT_RETURN_NONE
*/
#define TVM_FFI_S_VISIT_MAYBE_EARLY_RETURN(Result) \
do { \
auto&& tvm_ffi_res_ = (Result); \
Expand All @@ -498,7 +520,18 @@ namespace details {
return ::tvm::ffi::details::MaybeReturnHelper(::std::move(tvm_ffi_res_)); \
} \
} while (0)
/// \endcond

/*!
* \brief Return the completed result -- no interrupt -- from a visit hook.
*
* Terminal statement of a hook that traversed every field it intends to. Works
* from a raw ``TVMFFIAny`` hook and a typed ``Expected`` helper alike.
*
* \sa TVM_FFI_S_VISIT_MAYBE_EARLY_RETURN
*/
#define TVM_FFI_S_VISIT_RETURN_NONE() \
return ::tvm::ffi::details::MaybeReturnHelper( \
::tvm::ffi::Expected<::tvm::ffi::Optional<::tvm::ffi::VisitInterrupt>>(::std::nullopt))

} // namespace details

Expand Down
4 changes: 2 additions & 2 deletions src/ffi/extra/structural_visit.cc
Original file line number Diff line number Diff line change
Expand Up @@ -115,15 +115,15 @@ TVMFFIAny VisitSeqContainer(StructuralVisitorObj* visitor, const SeqBaseObj* sel
for (const Any& item : *self) {
TVM_FFI_S_VISIT_MAYBE_EARLY_RETURN(visitor->VisitExpected(item));
}
return ExpectedUnsafe::MoveToTVMFFIAny(Expected<Optional<VisitInterrupt>>(std::nullopt));
TVM_FFI_S_VISIT_RETURN_NONE();
}

/*! \brief Visit values in a map container while treating keys as structural anchors. */
TVMFFIAny VisitMapContainer(StructuralVisitorObj* visitor, const MapBaseObj* self) noexcept {
for (const auto& kv : *self) {
TVM_FFI_S_VISIT_MAYBE_EARLY_RETURN(visitor->VisitExpected(kv.second));
}
return ExpectedUnsafe::MoveToTVMFFIAny(Expected<Optional<VisitInterrupt>>(std::nullopt));
TVM_FFI_S_VISIT_RETURN_NONE();
}

/*! \brief Structural visit hook for ArrayObj. */
Expand Down