Re: [PR] feat: add `__copy__`, `__deepcopy__`, and `__replace__` for FFI objects [tvm-ffi]

2026-02-13 Thread via GitHub


junrushao merged PR #438:
URL: https://github.com/apache/tvm-ffi/pull/438


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


-
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]



Re: [PR] feat: add `__copy__`, `__deepcopy__`, and `__replace__` for FFI objects [tvm-ffi]

2026-02-13 Thread via GitHub


tqchen commented on code in PR #438:
URL: https://github.com/apache/tvm-ffi/pull/438#discussion_r2806752339


##
include/tvm/ffi/reflection/registry.h:
##
@@ -460,6 +460,9 @@ struct init {
   }
 };
 
+/*! \brief Method name used for shallow copy registration. */
+inline constexpr const char* kShallowCopyMethodName = "__ffi_shallow_copy__";

Review Comment:
   kInitMethodName is member of ObjectDef, for consistency maybe make it also 
member? 
   
   Alterntaively, consider group these constants into struct or namespace like 
`struct StaticTypeKey {`. Maybe TypeAttrName or `reflection::type_attr::`



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


-
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]



Re: [PR] feat: add `__copy__`, `__deepcopy__`, and `__replace__` for FFI objects [tvm-ffi]

2026-02-13 Thread via GitHub


tqchen commented on code in PR #438:
URL: https://github.com/apache/tvm-ffi/pull/438#discussion_r2806747880


##
src/ffi/extra/deep_copy.cc:
##
@@ -0,0 +1,162 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+/*
+ * \file src/ffi/extra/deep_copy.cc
+ *
+ * \brief Reflection-based deep copy utilities.
+ */
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+#include 
+
+namespace tvm {
+namespace ffi {
+
+/*!
+ * \brief Deep copier with memoization.
+ *
+ * - Arrays / Maps: Resolve() recurses to rebuild with resolved children.
+ * - Copyable objects: shallow-copied immediately into copy_map_ (so cyclic
+ *   back-references resolve), then queued for field resolution.
+ * - The queue is drained iteratively by Run(), bounding recursion depth
+ *   to container nesting rather than object-graph depth.
+ * - Shared references are preserved: the same original maps to the same copy.
+ */
+class ObjectDeepCopier {
+ public:
+  explicit ObjectDeepCopier(reflection::TypeAttrColumn* column) : 
column_(column) {}
+
+  Any Run(const Any& value) {
+if (value.type_index() < TypeIndex::kTVMFFIStaticObjectBegin) return value;
+Any result = Resolve(value);
+// NOLINTNEXTLINE(modernize-loop-convert): queue grows during iteration
+for (size_t i = 0; i < resolve_queue_.size(); ++i) {
+  ResolveFields(resolve_queue_[i]);
+}
+return result;
+  }
+
+ private:
+  /*! \brief Resolve a value: pass through primitives, copy/rebuild objects. */
+  Any Resolve(const Any& value) {
+if (value.type_index() < TypeIndex::kTVMFFIStaticObjectBegin) {
+  return value;
+}
+const Object* obj = value.as();
+if (auto it = copy_map_.find(obj); it != copy_map_.end()) {
+  return it->second;
+}
+int32_t ti = obj->type_index();
+// Strings and bytes are immutable — return as-is.
+if (ti == TypeIndex::kTVMFFIStr || ti == TypeIndex::kTVMFFIBytes) {

Review Comment:
   this also applies to kTVMFFIShape which is immutable and can return as it is



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


-
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]



Re: [PR] feat: add `__copy__`, `__deepcopy__`, and `__replace__` for FFI objects [tvm-ffi]

2026-02-11 Thread via GitHub


gemini-code-assist[bot] commented on code in PR #438:
URL: https://github.com/apache/tvm-ffi/pull/438#discussion_r2792040790


##
include/tvm/ffi/extra/deep_copy.h:
##
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+/*!
+ * \file tvm/ffi/extra/deep_copy.h
+ * \brief Reflection-based object copy utilities
+ */
+#ifndef TVM_FFI_EXTRA_DEEP_COPY_H_
+#define TVM_FFI_EXTRA_DEEP_COPY_H_
+
+#include 
+#include 
+
+namespace tvm {
+namespace ffi {
+
+/**
+ * \brief Deep copy an ffi::Any value.
+ *
+ * Recursively copies the value and all reachable objects in its object graph.
+ * Copy-constructible types with `ObjectDef` registration automatically 
support deep copy.
+ * Primitive types, strings, and bytes are returned as-is (they are immutable).
+ * Arrays and Maps are recursively deep copied.
+ * Objects without copy support are kept as shared references.

Review Comment:
   ![high](https://www.gstatic.com/codereviewagent/high-priority.svg)
   
   The documentation states that objects without copy support are kept as 
shared references. However, the implementation in `src/ffi/extra/deep_copy.cc` 
throws an error if an object is not copy-constructible. This is a significant 
discrepancy. The implementation's behavior of throwing an error seems more 
appropriate for a deep copy operation, as silently falling back to a shallow 
copy could lead to unexpected behavior. Please update the documentation to 
reflect that an error is thrown for non-copyable objects.
   
   ```c
* Objects that are not copy-constructible will cause a runtime error.
   ```



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


-
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]



Re: [PR] feat: add `__copy__`, `__deepcopy__`, and `__replace__` for FFI objects [tvm-ffi]

2026-02-11 Thread via GitHub


junrushao commented on PR #438:
URL: https://github.com/apache/tvm-ffi/pull/438#issuecomment-3883040511

   /gemini review


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


-
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]



Re: [PR] feat: add `__copy__`, `__deepcopy__`, and `__replace__` for FFI objects [tvm-ffi]

2026-02-11 Thread via GitHub


junrushao commented on PR #438:
URL: https://github.com/apache/tvm-ffi/pull/438#issuecomment-3882928238

   Updated per discussion with TQ. @tqchen please re-review 


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


-
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]



Re: [PR] feat: add `__copy__`, `__deepcopy__`, and `__replace__` for FFI objects [tvm-ffi]

2026-02-10 Thread via GitHub


junrushao commented on code in PR #438:
URL: https://github.com/apache/tvm-ffi/pull/438#discussion_r2791512956


##
include/tvm/ffi/extra/copy.h:
##
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+/*!
+ * \file tvm/ffi/extra/copy.h
+ * \brief Reflection-based object copy utilities
+ */
+#ifndef TVM_FFI_EXTRA_COPY_H_
+#define TVM_FFI_EXTRA_COPY_H_
+
+#include 
+#include 
+
+namespace tvm {
+namespace ffi {
+
+/**
+ * \brief Deep copy an ffi::Any value.
+ *
+ * Recursively copies the value and all reachable objects in its object graph.
+ * Objects must have copy support enabled via `refl::enable_copy()` to be deep 
copied.
+ * Primitive types, strings, and bytes are returned as-is (they are immutable).
+ * Arrays and Maps are recursively deep copied.
+ * Objects without copy support are kept as shared references.
+ *
+ * \param value The value to deep copy.
+ * \return The deep copied value.
+ */
+TVM_FFI_EXTRA_CXX_API Any DeepCopyValue(const Any& value);

Review Comment:
   good idea!



##
include/tvm/ffi/extra/copy.h:
##
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+/*!
+ * \file tvm/ffi/extra/copy.h
+ * \brief Reflection-based object copy utilities
+ */
+#ifndef TVM_FFI_EXTRA_COPY_H_
+#define TVM_FFI_EXTRA_COPY_H_

Review Comment:
   updated



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


-
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]



Re: [PR] feat: add `__copy__`, `__deepcopy__`, and `__replace__` for FFI objects [tvm-ffi]

2026-02-10 Thread via GitHub


junrushao commented on code in PR #438:
URL: https://github.com/apache/tvm-ffi/pull/438#discussion_r2791488179


##
include/tvm/ffi/reflection/registry.h:
##
@@ -460,6 +460,49 @@ struct init {
   }
 };
 
+/*!
+ * \brief Helper class to enable copy support for object types.
+ *
+ * This helper is used with `ObjectDef::def()` to register 
`__ffi_shallow_copy__`
+ * as an instance method. This enables `__copy__`, `__deepcopy__`, and 
`__replace__`
+ * in Python via the `copy` module.
+ *
+ * The shallow copy uses the C++ copy constructor of the object type:
+ * `make_object(*self)`.
+ *
+ * Example usage:
+ *
+ * \code{.cpp}
+ * refl::ObjectDef()
+ * .def(refl::enable_copy())
+ * .def(refl::init());
+ * \endcode
+ *
+ * \note The object type must have a copy constructor.
+ */
+struct enable_copy {

Review Comment:
   alternatively, let's enable copy by default for all object types which are 
copy_constructible



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


-
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]



Re: [PR] feat: add `__copy__`, `__deepcopy__`, and `__replace__` for FFI objects [tvm-ffi]

2026-02-09 Thread via GitHub


junrushao commented on PR #438:
URL: https://github.com/apache/tvm-ffi/pull/438#issuecomment-3874675284

   Still - implication of cyclic reference and CoW containers (Array, Map) 
makes it pretty challenging to have an absolutely correct implementation of 
`__deepcopy__`. Converting it to draft.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


-
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]



Re: [PR] feat: add `__copy__`, `__deepcopy__`, and `__replace__` for FFI objects [tvm-ffi]

2026-02-09 Thread via GitHub


tqchen commented on code in PR #438:
URL: https://github.com/apache/tvm-ffi/pull/438#discussion_r2784035440


##
include/tvm/ffi/reflection/registry.h:
##
@@ -460,6 +460,49 @@ struct init {
   }
 };
 
+/*!
+ * \brief Helper class to enable copy support for object types.
+ *
+ * This helper is used with `ObjectDef::def()` to register 
`__ffi_shallow_copy__`
+ * as an instance method. This enables `__copy__`, `__deepcopy__`, and 
`__replace__`
+ * in Python via the `copy` module.
+ *
+ * The shallow copy uses the C++ copy constructor of the object type:
+ * `make_object(*self)`.
+ *
+ * Example usage:
+ *
+ * \code{.cpp}
+ * refl::ObjectDef()
+ * .def(refl::enable_copy())
+ * .def(refl::init());
+ * \endcode
+ *
+ * \note The object type must have a copy constructor.
+ */
+struct enable_copy {

Review Comment:
   yes, i understand, seems the confusion part is that it enables a shallow 
copy API that was required for deep copy?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


-
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]



Re: [PR] feat: add `__copy__`, `__deepcopy__`, and `__replace__` for FFI objects [tvm-ffi]

2026-02-09 Thread via GitHub


junrushao commented on code in PR #438:
URL: https://github.com/apache/tvm-ffi/pull/438#discussion_r2783983437


##
include/tvm/ffi/reflection/registry.h:
##
@@ -460,6 +460,49 @@ struct init {
   }
 };
 
+/*!
+ * \brief Helper class to enable copy support for object types.
+ *
+ * This helper is used with `ObjectDef::def()` to register 
`__ffi_shallow_copy__`
+ * as an instance method. This enables `__copy__`, `__deepcopy__`, and 
`__replace__`
+ * in Python via the `copy` module.
+ *
+ * The shallow copy uses the C++ copy constructor of the object type:
+ * `make_object(*self)`.
+ *
+ * Example usage:
+ *
+ * \code{.cpp}
+ * refl::ObjectDef()
+ * .def(refl::enable_copy())
+ * .def(refl::init());
+ * \endcode
+ *
+ * \note The object type must have a copy constructor.
+ */
+struct enable_copy {

Review Comment:
   No it's for shallow copy



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


-
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]



Re: [PR] feat: add `__copy__`, `__deepcopy__`, and `__replace__` for FFI objects [tvm-ffi]

2026-02-09 Thread via GitHub


tqchen commented on code in PR #438:
URL: https://github.com/apache/tvm-ffi/pull/438#discussion_r2782403728


##
include/tvm/ffi/extra/copy.h:
##
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+/*!
+ * \file tvm/ffi/extra/copy.h
+ * \brief Reflection-based object copy utilities
+ */
+#ifndef TVM_FFI_EXTRA_COPY_H_
+#define TVM_FFI_EXTRA_COPY_H_
+
+#include 
+#include 
+
+namespace tvm {
+namespace ffi {
+
+/**
+ * \brief Deep copy an ffi::Any value.
+ *
+ * Recursively copies the value and all reachable objects in its object graph.
+ * Objects must have copy support enabled via `refl::enable_copy()` to be deep 
copied.
+ * Primitive types, strings, and bytes are returned as-is (they are immutable).
+ * Arrays and Maps are recursively deep copied.
+ * Objects without copy support are kept as shared references.
+ *
+ * \param value The value to deep copy.
+ * \return The deep copied value.
+ */
+TVM_FFI_EXTRA_CXX_API Any DeepCopyValue(const Any& value);

Review Comment:
   I feel DeepCopy as an API name is fine here



##
include/tvm/ffi/extra/copy.h:
##
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+/*!
+ * \file tvm/ffi/extra/copy.h
+ * \brief Reflection-based object copy utilities
+ */
+#ifndef TVM_FFI_EXTRA_COPY_H_
+#define TVM_FFI_EXTRA_COPY_H_

Review Comment:
   deep_copy.h?



##
include/tvm/ffi/reflection/registry.h:
##
@@ -460,6 +460,49 @@ struct init {
   }
 };
 
+/*!
+ * \brief Helper class to enable copy support for object types.
+ *
+ * This helper is used with `ObjectDef::def()` to register 
`__ffi_shallow_copy__`
+ * as an instance method. This enables `__copy__`, `__deepcopy__`, and 
`__replace__`
+ * in Python via the `copy` module.
+ *
+ * The shallow copy uses the C++ copy constructor of the object type:
+ * `make_object(*self)`.
+ *
+ * Example usage:
+ *
+ * \code{.cpp}
+ * refl::ObjectDef()
+ * .def(refl::enable_copy())
+ * .def(refl::init());
+ * \endcode
+ *
+ * \note The object type must have a copy constructor.
+ */
+struct enable_copy {

Review Comment:
   should it be enable_deep_copy to be explicit?



##
src/ffi/extra/copy.cc:
##
@@ -0,0 +1,268 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+/*
+ * \file src/ffi/extra/copy.cc
+ *
+ * \brief Reflection-based deep copy utilities.
+ */
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+#include 
+#include 
+
+namespace tvm {
+namespace ffi {
+
+/*!
+ * \brief Deep copier that recursively copies objects using shallow copy + 
field replacement.
+ *
+ * Algorithm:
+ * Phase 1: Walk t

Re: [PR] feat: add `__copy__`, `__deepcopy__`, and `__replace__` for FFI objects [tvm-ffi]

2026-02-08 Thread via GitHub


gemini-code-assist[bot] commented on code in PR #438:
URL: https://github.com/apache/tvm-ffi/pull/438#discussion_r2780989838


##
include/tvm/ffi/reflection/registry.h:
##
@@ -587,6 +630,42 @@ class ObjectDef : public ReflectionDefBase {
 return *this;
   }
 
+  /*!
+   * \brief Enable copy support for this object type.
+   *
+   * Registers `__ffi_shallow_copy__` as an instance method that performs a 
shallow
+   * copy via the C++ copy constructor: `make_object(*self)`.
+   * Also registers it as a type attribute so that the generic deep copy 
function
+   * can look it up by type index.
+   *
+   * \param ec An instance of `enable_copy`.
+   * \param extra Optional additional metadata such as docstring.
+   *
+   * \return Reference to this `ObjectDef` for method chaining.
+   *
+   * Example:
+   *
+   * \code{.cpp}
+   * refl::ObjectDef()
+   * .def(refl::enable_copy())
+   * .def(refl::init());
+   * \endcode
+   */
+  template 
+  TVM_FFI_INLINE ObjectDef& def([[maybe_unused]] enable_copy ec, Extra&&... 
extra) {
+// Register __ffi_shallow_copy__ as an instance method
+RegisterMethod(kShallowCopyMethodName, false, &enable_copy::template 
shallow_copy,
+   std::forward(extra)...);
+// Also register as a type attribute for generic deep copy lookup
+Function copy_fn = GetMethod(std::string(type_key_) + "." + 
kShallowCopyMethodName,
+ &enable_copy::template shallow_copy);
+TVMFFIByteArray attr_name = {kShallowCopyMethodName,
+ 
std::char_traits::length(kShallowCopyMethodName)};
+TVMFFIAny attr_value = AnyView(copy_fn).CopyToTVMFFIAny();
+TVM_FFI_CHECK_SAFE_CALL(TVMFFITypeRegisterAttr(type_index_, &attr_name, 
&attr_value));
+return *this;
+  }

Review Comment:
   ![medium](https://www.gstatic.com/codereviewagent/medium-priority.svg)
   
   The current implementation creates the `Function` object for the shallow 
copy method twice: once within `RegisterMethod` on line 657 and again 
explicitly via `GetMethod` on line 660. This is slightly inefficient as it 
involves redundant work during type registration.
   
   You can avoid this by retrieving the method that was just registered using 
`TVMFFITypeGetMethod` and then using that to register the type attribute. This 
makes the code more efficient and avoids the redundant object creation.
   
   ```c
 TVM_FFI_INLINE ObjectDef& def([[maybe_unused]] enable_copy ec, Extra&&... 
extra) {
   // Register __ffi_shallow_copy__ as an instance method
   RegisterMethod(kShallowCopyMethodName, false, &enable_copy::template 
shallow_copy,
  std::forward(extra)...);
   // Also register as a type attribute for generic deep copy lookup
   TVMFFIMethodInfo method_info;
   TVMFFIByteArray method_name = {kShallowCopyMethodName,
  
std::char_traits::length(kShallowCopyMethodName)};
   TVM_FFI_CHECK_SAFE_CALL(TVMFFITypeGetMethod(type_index_, &method_name, 
&method_info));
   TVM_FFI_CHECK_SAFE_CALL(TVMFFITypeRegisterAttr(type_index_, 
&method_name, &method_info.method));
   return *this;
 }
   ```



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


-
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]



Re: [PR] feat: add `__copy__`, `__deepcopy__`, and `__replace__` for FFI objects [tvm-ffi]

2026-02-08 Thread via GitHub


junrushao commented on PR #438:
URL: https://github.com/apache/tvm-ffi/pull/438#issuecomment-3869773464

   /gemini review


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


-
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]



Re: [PR] feat: add `__copy__`, `__deepcopy__`, and `__replace__` for FFI objects [tvm-ffi]

2026-02-08 Thread via GitHub


gemini-code-assist[bot] commented on code in PR #438:
URL: https://github.com/apache/tvm-ffi/pull/438#discussion_r2780848789


##
src/ffi/extra/copy.cc:
##
@@ -0,0 +1,293 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+/*
+ * \file src/ffi/extra/copy.cc
+ *
+ * \brief Reflection-based deep copy utilities.
+ */
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+#include 
+#include 
+#include 
+
+namespace tvm {
+namespace ffi {
+
+/*!
+ * \brief Deep copier that recursively copies objects using shallow copy + 
field replacement.
+ *
+ * Algorithm:
+ * Phase 1: Walk the entire object graph (objects, arrays, maps) using an 
explicit
+ *  stack, collecting all reachable nodes in topological order 
(post-order DFS).
+ *  An unordered_set deduplicates nodes, preserving shared references.
+ * Phase 2: In two sub-passes:
+ *  (a) Create shallow copies of all copyable objects first, so that
+ *  back-references in cyclic object graphs resolve correctly.
+ *  (b) Create deep-copied arrays/maps with resolved elements, and
+ *  resolve fields of copyable objects with previously copied 
values.
+ *
+ * Primitive types, strings, bytes, and functions are immutable and returned 
as-is.
+ * Arrays and Maps are recursively copied (their elements are replaced with 
copies).
+ * Shared references (including shared containers) are preserved in the copy 
graph.
+ * Objects without enable_copy() are kept as shared references.
+ */
+class ObjectDeepCopier {
+ public:
+  static Any DeepCopy(const Any& root) {
+ObjectDeepCopier copier;
+// Phase 1: Collect all reachable nodes in topological order
+copier.CollectNodes(root);
+// Phase 2: Copy nodes in topological order
+copier.CopyNodesInOrder();
+// Phase 3: Resolve the root value with copies
+return copier.ResolveValue(root);
+  }
+
+ private:
+  struct DFSFrame {
+const Object* obj;
+bool children_pushed;
+  };
+
+  // The type attribute column for looking up per-type shallow copy functions
+  static reflection::TypeAttrColumn& ShallowCopyColumn() {
+static reflection::TypeAttrColumn column("__ffi_shallow_copy__");
+return column;
+  }
+
+  // Map from original object pointer to its copy
+  std::unordered_map copy_map_;
+  // Topological order of nodes to copy (post-order, leaves first)
+  std::vector topo_order_;
+  // Set of visited object pointers for deduplication
+  std::unordered_set visited_;
+  // Original Any values keyed by Object pointer (for typed container access)
+  std::unordered_map originals_;
+
+  /*!
+   * \brief Extract the Object pointer from an Any value.
+   * \return The Object pointer, or nullptr if the value is not an 
object/array/map.
+   */
+  static const Object* AsObjectPtr(const Any& value) {
+int32_t ti = value.type_index();
+if (ti == TypeIndex::kTVMFFIArray || ti == TypeIndex::kTVMFFIMap ||
+ti >= TypeIndex::kTVMFFIStaticObjectBegin) {
+  return details::AnyUnsafe::CopyFromAnyViewAfterCheck(value);
+}
+return nullptr;
+  }
+
+  /*!
+   * \brief Phase 1: Walk the object graph iteratively, collecting all 
reachable nodes
+   *(objects, arrays, maps) in topological order (post-order DFS).
+   */
+  void CollectNodes(const Any& root) {
+const Object* root_obj = AsObjectPtr(root);
+if (root_obj == nullptr) return;
+originals_.emplace(root_obj, root);
+
+std::stack stack;
+stack.push({root_obj, false});
+
+while (!stack.empty()) {
+  DFSFrame& frame = stack.top();
+
+  if (frame.children_pushed) {
+// All children processed, add this node in post-order
+topo_order_.push_back(frame.obj);
+stack.pop();
+continue;
+  }
+
+  frame.children_pushed = true;
+
+  // Dedup at process time (not push time) to ensure correct topological 
order
+  // when multiple parents share the same child node.
+  if (!visited_.insert(frame.obj).second) {
+stack.pop();
+continue;
+  }
+
+  int32_t ti = frame.obj->type_index();
+
+  if (ti == TypeIndex::kTVMFFIArray) {
+// Push array elements

Re: [PR] feat: add `__copy__`, `__deepcopy__`, and `__replace__` for FFI objects [tvm-ffi]

2026-02-08 Thread via GitHub


gemini-code-assist[bot] commented on code in PR #438:
URL: https://github.com/apache/tvm-ffi/pull/438#discussion_r2780848789


##
src/ffi/extra/copy.cc:
##
@@ -0,0 +1,293 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+/*
+ * \file src/ffi/extra/copy.cc
+ *
+ * \brief Reflection-based deep copy utilities.
+ */
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+#include 
+#include 
+#include 
+
+namespace tvm {
+namespace ffi {
+
+/*!
+ * \brief Deep copier that recursively copies objects using shallow copy + 
field replacement.
+ *
+ * Algorithm:
+ * Phase 1: Walk the entire object graph (objects, arrays, maps) using an 
explicit
+ *  stack, collecting all reachable nodes in topological order 
(post-order DFS).
+ *  An unordered_set deduplicates nodes, preserving shared references.
+ * Phase 2: In two sub-passes:
+ *  (a) Create shallow copies of all copyable objects first, so that
+ *  back-references in cyclic object graphs resolve correctly.
+ *  (b) Create deep-copied arrays/maps with resolved elements, and
+ *  resolve fields of copyable objects with previously copied 
values.
+ *
+ * Primitive types, strings, bytes, and functions are immutable and returned 
as-is.
+ * Arrays and Maps are recursively copied (their elements are replaced with 
copies).
+ * Shared references (including shared containers) are preserved in the copy 
graph.
+ * Objects without enable_copy() are kept as shared references.
+ */
+class ObjectDeepCopier {
+ public:
+  static Any DeepCopy(const Any& root) {
+ObjectDeepCopier copier;
+// Phase 1: Collect all reachable nodes in topological order
+copier.CollectNodes(root);
+// Phase 2: Copy nodes in topological order
+copier.CopyNodesInOrder();
+// Phase 3: Resolve the root value with copies
+return copier.ResolveValue(root);
+  }
+
+ private:
+  struct DFSFrame {
+const Object* obj;
+bool children_pushed;
+  };
+
+  // The type attribute column for looking up per-type shallow copy functions
+  static reflection::TypeAttrColumn& ShallowCopyColumn() {
+static reflection::TypeAttrColumn column("__ffi_shallow_copy__");
+return column;
+  }
+
+  // Map from original object pointer to its copy
+  std::unordered_map copy_map_;
+  // Topological order of nodes to copy (post-order, leaves first)
+  std::vector topo_order_;
+  // Set of visited object pointers for deduplication
+  std::unordered_set visited_;
+  // Original Any values keyed by Object pointer (for typed container access)
+  std::unordered_map originals_;
+
+  /*!
+   * \brief Extract the Object pointer from an Any value.
+   * \return The Object pointer, or nullptr if the value is not an 
object/array/map.
+   */
+  static const Object* AsObjectPtr(const Any& value) {
+int32_t ti = value.type_index();
+if (ti == TypeIndex::kTVMFFIArray || ti == TypeIndex::kTVMFFIMap ||
+ti >= TypeIndex::kTVMFFIStaticObjectBegin) {
+  return details::AnyUnsafe::CopyFromAnyViewAfterCheck(value);
+}
+return nullptr;
+  }
+
+  /*!
+   * \brief Phase 1: Walk the object graph iteratively, collecting all 
reachable nodes
+   *(objects, arrays, maps) in topological order (post-order DFS).
+   */
+  void CollectNodes(const Any& root) {
+const Object* root_obj = AsObjectPtr(root);
+if (root_obj == nullptr) return;
+originals_.emplace(root_obj, root);
+
+std::stack stack;
+stack.push({root_obj, false});
+
+while (!stack.empty()) {
+  DFSFrame& frame = stack.top();
+
+  if (frame.children_pushed) {
+// All children processed, add this node in post-order
+topo_order_.push_back(frame.obj);
+stack.pop();
+continue;
+  }
+
+  frame.children_pushed = true;
+
+  // Dedup at process time (not push time) to ensure correct topological 
order
+  // when multiple parents share the same child node.
+  if (!visited_.insert(frame.obj).second) {
+stack.pop();
+continue;
+  }
+
+  int32_t ti = frame.obj->type_index();
+
+  if (ti == TypeIndex::kTVMFFIArray) {
+// Push array elements

Re: [PR] feat: add `__copy__`, `__deepcopy__`, and `__replace__` for FFI objects [tvm-ffi]

2026-02-08 Thread via GitHub


gemini-code-assist[bot] commented on code in PR #438:
URL: https://github.com/apache/tvm-ffi/pull/438#discussion_r2780848777


##
src/ffi/extra/copy.cc:
##
@@ -0,0 +1,293 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+/*
+ * \file src/ffi/extra/copy.cc
+ *
+ * \brief Reflection-based deep copy utilities.
+ */
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+#include 
+#include 
+#include 
+
+namespace tvm {
+namespace ffi {
+
+/*!
+ * \brief Deep copier that recursively copies objects using shallow copy + 
field replacement.
+ *
+ * Algorithm:
+ * Phase 1: Walk the entire object graph (objects, arrays, maps) using an 
explicit
+ *  stack, collecting all reachable nodes in topological order 
(post-order DFS).
+ *  An unordered_set deduplicates nodes, preserving shared references.
+ * Phase 2: In two sub-passes:
+ *  (a) Create shallow copies of all copyable objects first, so that
+ *  back-references in cyclic object graphs resolve correctly.
+ *  (b) Create deep-copied arrays/maps with resolved elements, and
+ *  resolve fields of copyable objects with previously copied 
values.

Review Comment:
   ![medium](https://www.gstatic.com/codereviewagent/medium-priority.svg)
   
   The documentation for Phase 2 of the deep copy algorithm mentions two 
sub-passes, but the implementation in `CopyNodesInOrder` actually uses three 
distinct sub-passes. The comment within `CopyNodesInOrder` correctly describes 
these three passes. To improve clarity and consistency, the main class-level 
documentation should be updated to reflect the three-pass approach.
   
   ```suggestion
* Phase 2: In three sub-passes:
*  (a) Create shallow copies of all copyable objects. This allows
*  back-references in cyclic graphs to be resolved correctly.
*  (b) Create deep copies of arrays and maps. Their elements are
*  resolved to their copied versions from sub-pass (a).
*  (c) Resolve fields of the shallow-copied objects from (a) to 
point
*  to their deep-copied versions from (a) and (b).
   ```



##
src/ffi/extra/copy.cc:
##
@@ -0,0 +1,293 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+/*
+ * \file src/ffi/extra/copy.cc
+ *
+ * \brief Reflection-based deep copy utilities.
+ */
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+#include 
+#include 
+#include 
+
+namespace tvm {
+namespace ffi {
+
+/*!
+ * \brief Deep copier that recursively copies objects using shallow copy + 
field replacement.
+ *
+ * Algorithm:
+ * Phase 1: Walk the entire object graph (objects, arrays, maps) using an 
explicit
+ *  stack, collecting all reachable nodes in topological order 
(post-order DFS).
+ *  An unordered_set deduplicates nodes, preserving shared references.
+ * Phase 2: In two sub-passes:
+ *  (a) Create shallow copies of all copyable objects first, so that
+ *  back-references in cyclic object graphs resolve correctly.
+ *  (b) Create deep-copied arrays/maps with resolved elements, and
+ *  resolve fields of copyable objects with previously copied 
values.
+ *
+ * Primitive types, strings, bytes, and functions are immutable and returned 
as-is.
+ * Arrays and Maps are recursi

Re: [PR] feat: add `__copy__`, `__deepcopy__`, and `__replace__` for FFI objects [tvm-ffi]

2026-02-08 Thread via GitHub


junrushao commented on PR #438:
URL: https://github.com/apache/tvm-ffi/pull/438#issuecomment-3869613919

   /gemini review


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


-
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]



Re: [PR] feat: add `__copy__`, `__deepcopy__`, and `__replace__` for FFI objects [tvm-ffi]

2026-02-08 Thread via GitHub


junrushao commented on code in PR #438:
URL: https://github.com/apache/tvm-ffi/pull/438#discussion_r2780822687


##
python/tvm_ffi/registry.py:
##
@@ -335,25 +335,97 @@ def _add_class_attrs(type_cls: type, type_info: TypeInfo) 
-> type:
 if not hasattr(type_cls, name):  # skip already defined attributes
 setattr(type_cls, name, field.as_property(type_cls))
 has_c_init = False
+has_shallow_copy = False
 for method in type_info.methods:
 name = method.name
 if name == "__ffi_init__":
 name = "__c_ffi_init__"
 has_c_init = True
-if not hasattr(type_cls, name):
+if name == "__ffi_shallow_copy__":
+has_shallow_copy = True
+# Always override: shallow copy is type-specific and must not be 
inherited
+setattr(type_cls, name, method.as_callable(type_cls))
+elif not hasattr(type_cls, name):
 setattr(type_cls, name, method.as_callable(type_cls))
 if "__init__" not in type_cls.__dict__:
 if has_c_init:
 setattr(type_cls, "__init__", getattr(type_cls, "__ffi_init__"))
 elif not issubclass(type_cls, core.PyNativeObject):
 setattr(type_cls, "__init__", __init__invalid)
+_setup_copy_methods(type_cls, has_shallow_copy)
 return type_cls
 
 
+def _setup_copy_methods(type_cls: type, has_shallow_copy: bool) -> None:
+"""Set up __copy__, __deepcopy__, __replace__ based on copy support."""
+if has_shallow_copy:
+if "__copy__" not in type_cls.__dict__:
+setattr(type_cls, "__copy__", _copy_supported)
+if "__deepcopy__" not in type_cls.__dict__:
+setattr(type_cls, "__deepcopy__", _deepcopy_supported)
+if "__replace__" not in type_cls.__dict__:
+setattr(type_cls, "__replace__", _replace_supported)
+else:
+if "__copy__" not in type_cls.__dict__:
+setattr(type_cls, "__copy__", _copy_unsupported)
+if "__deepcopy__" not in type_cls.__dict__:
+setattr(type_cls, "__deepcopy__", _deepcopy_unsupported)
+if "__replace__" not in type_cls.__dict__:
+setattr(type_cls, "__replace__", _replace_unsupported)
+
+
 def __init__invalid(self: Any, *args: Any, **kwargs: Any) -> None:
 raise RuntimeError("The __init__ method of this class is not implemented.")
 
 
+def _copy_supported(self: Any) -> Any:
+return self.__ffi_shallow_copy__()
+
+
+def _deepcopy_supported(self: Any, memo: Any = None) -> Any:
+return _get_deep_copy_func()(self)
+
+
+def _replace_supported(self: Any, **kwargs: Any) -> Any:
+import copy  # noqa: PLC0415
+
+obj = copy.copy(self)
+for key, value in kwargs.items():
+setattr(obj, key, value)
+return obj
+
+
+def _copy_unsupported(self: Any) -> Any:
+raise TypeError(
+f"Type `{type(self).__name__}` does not support copy. "
+f"Enable it with refl::enable_copy() in the C++ type registration."
+)
+
+
+def _deepcopy_unsupported(self: Any, memo: Any = None) -> Any:
+raise TypeError(
+f"Type `{type(self).__name__}` does not support deepcopy. "
+f"Enable it with refl::enable_copy() in the C++ type registration."
+)
+
+
+def _replace_unsupported(self: Any, **kwargs: Any) -> Any:
+raise TypeError(
+f"Type `{type(self).__name__}` does not support replace. "
+f"Enable it with refl::enable_copy() in the C++ type registration."
+)
+
+
+def _get_deep_copy_func() -> core.Function:
+global _deep_copy_func_cache  # noqa: PLW0603
+if _deep_copy_func_cache is None:
+_deep_copy_func_cache = get_global_func("ffi.DeepCopy")
+return _deep_copy_func_cache
+
+
+_deep_copy_func_cache: core.Function | None = None

Review Comment:
   probably don't need this - just call `get_global_func` every time



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


-
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]



Re: [PR] feat: add `__copy__`, `__deepcopy__`, and `__replace__` for FFI objects [tvm-ffi]

2026-02-08 Thread via GitHub


gemini-code-assist[bot] commented on code in PR #438:
URL: https://github.com/apache/tvm-ffi/pull/438#discussion_r2780743716


##
src/ffi/extra/copy.cc:
##
@@ -0,0 +1,275 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+/*
+ * \file src/ffi/extra/copy.cc
+ *
+ * \brief Reflection-based deep copy utilities.
+ */
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+#include 
+#include 
+#include 
+
+namespace tvm {
+namespace ffi {
+
+/*!
+ * \brief Deep copier that recursively copies objects using shallow copy + 
field replacement.
+ *
+ * Algorithm:
+ * Phase 1: Walk the entire object graph (objects, arrays, maps) using an 
explicit
+ *  stack, collecting all reachable nodes in topological order 
(post-order DFS).
+ *  An unordered_set deduplicates nodes, preserving shared references.
+ * Phase 2: In two sub-passes:
+ *  (a) Create shallow copies of all copyable objects first, so that
+ *  back-references in cyclic object graphs resolve correctly.
+ *  (b) Create deep-copied arrays/maps with resolved elements, and
+ *  resolve fields of copyable objects with previously copied 
values.
+ *
+ * Primitive types, strings, bytes, and functions are immutable and returned 
as-is.
+ * Arrays and Maps are recursively copied (their elements are replaced with 
copies).
+ * Shared references (including shared containers) are preserved in the copy 
graph.
+ * Objects without enable_copy() are kept as shared references.
+ */
+class ObjectDeepCopier {
+ public:
+  static Any DeepCopy(const Any& root) {
+ObjectDeepCopier copier;
+// Phase 1: Collect all reachable nodes in topological order
+copier.CollectNodes(root);
+// Phase 2: Copy nodes in topological order
+copier.CopyNodesInOrder();
+// Phase 3: Resolve the root value with copies
+return copier.ResolveValue(root);
+  }
+
+ private:
+  struct DFSFrame {
+const Object* obj;
+bool children_pushed;
+  };
+
+  // The type attribute column for looking up per-type shallow copy functions
+  static reflection::TypeAttrColumn& ShallowCopyColumn() {
+static reflection::TypeAttrColumn column("__ffi_shallow_copy__");
+return column;
+  }
+
+  // Map from original object pointer to its copy
+  std::unordered_map copy_map_;
+  // Topological order of nodes to copy (post-order, leaves first)
+  std::vector topo_order_;
+  // Set of visited object pointers for deduplication
+  std::unordered_set visited_;
+  // Original Any values keyed by Object pointer (for typed container access)
+  std::unordered_map originals_;
+
+  /*!
+   * \brief Extract the Object pointer from an Any value.
+   * \return The Object pointer, or nullptr if the value is not an 
object/array/map.
+   */
+  static const Object* AsObjectPtr(const Any& value) {
+int32_t ti = value.type_index();
+if (ti == TypeIndex::kTVMFFIArray || ti == TypeIndex::kTVMFFIMap ||
+ti >= TypeIndex::kTVMFFIStaticObjectBegin) {
+  return details::AnyUnsafe::CopyFromAnyViewAfterCheck(value);
+}
+return nullptr;
+  }
+
+  /*!
+   * \brief Phase 1: Walk the object graph iteratively, collecting all 
reachable nodes
+   *(objects, arrays, maps) in topological order (post-order DFS).
+   */
+  void CollectNodes(const Any& root) {
+const Object* root_obj = AsObjectPtr(root);
+if (root_obj == nullptr) return;
+originals_.emplace(root_obj, root);
+
+std::stack stack;
+stack.push({root_obj, false});
+
+while (!stack.empty()) {
+  DFSFrame& frame = stack.top();
+
+  if (frame.children_pushed) {
+// All children processed, add this node in post-order
+topo_order_.push_back(frame.obj);
+stack.pop();
+continue;
+  }
+
+  frame.children_pushed = true;
+
+  // Dedup at process time (not push time) to ensure correct topological 
order
+  // when multiple parents share the same child node.
+  if (!visited_.insert(frame.obj).second) {
+stack.pop();
+continue;
+  }
+
+  int32_t ti = frame.obj->type_index();
+
+  if (ti == TypeIndex::kTVMFFIArray) {
+// Push array elements

Re: [PR] feat: add `__copy__`, `__deepcopy__`, and `__replace__` for FFI objects [tvm-ffi]

2026-02-08 Thread via GitHub


junrushao commented on PR #438:
URL: https://github.com/apache/tvm-ffi/pull/438#issuecomment-3869480545

   /gemini review


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


-
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]



Re: [PR] feat: add `__copy__`, `__deepcopy__`, and `__replace__` for FFI objects [tvm-ffi]

2026-02-08 Thread via GitHub


gemini-code-assist[bot] commented on code in PR #438:
URL: https://github.com/apache/tvm-ffi/pull/438#discussion_r2780540797


##
src/ffi/extra/copy.cc:
##
@@ -0,0 +1,287 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+/*
+ * \file src/ffi/extra/copy.cc
+ *
+ * \brief Reflection-based deep copy utilities.
+ */
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+#include 
+#include 
+#include 
+
+namespace tvm {
+namespace ffi {
+
+/*!
+ * \brief Deep copier that recursively copies objects using shallow copy + 
field replacement.
+ *
+ * Algorithm:
+ * Phase 1: Walk the object graph using an explicit stack, collecting all 
reachable
+ *  objects in topological order (post-order DFS). An unordered_set is 
used
+ *  for deduplication.
+ * Phase 2: In topological order (leaves first), create shallow copies of each 
object
+ *  and replace their fields with previously copied values.
+ *
+ * Primitive types, strings, bytes, and functions are immutable and returned 
as-is.
+ * Arrays and Maps are recursively copied (their elements are replaced with 
copies).
+ * Objects without enable_copy() are kept as shared references.
+ */
+class ObjectDeepCopier {
+ public:
+  static Any DeepCopy(const Any& root) {
+ObjectDeepCopier copier;
+// Phase 1: Collect all copyable objects in topological order
+copier.CollectObjects(root);
+// Phase 2: Copy objects in topological order (leaves first)
+copier.CopyObjectsInOrder();
+// Phase 3: Resolve the root value with copies
+return copier.Resolve(root);
+  }
+
+ private:
+  struct DFSFrame {
+const Object* obj;
+bool children_pushed;
+  };
+
+  // The type attribute column for looking up per-type shallow copy functions
+  static reflection::TypeAttrColumn& ShallowCopyColumn() {
+static reflection::TypeAttrColumn column("__ffi_shallow_copy__");
+return column;
+  }
+
+  // Map from original object pointer to its shallow copy
+  std::unordered_map copy_map_;
+  // Topological order of objects to copy (post-order, leaves first)
+  std::vector topo_order_;
+  // Set of visited object pointers for deduplication
+  std::unordered_set visited_;
+
+  /*!
+   * \brief Phase 1: Walk the object graph, collecting copyable objects
+   *in topological order (post-order DFS).
+   */
+  void CollectObjects(const Any& root) { WalkValue(root); }
+
+  /*!
+   * \brief Recursively walk through Any values to find all objects.
+   */
+  void WalkValue(const Any& value) {
+switch (value.type_index()) {
+  case TypeIndex::kTVMFFIArray: {
+Array arr = 
details::AnyUnsafe::CopyFromAnyViewAfterCheck>(value);
+for (const Any& elem : arr) {
+  WalkValue(elem);
+}
+break;
+  }
+  case TypeIndex::kTVMFFIMap: {
+Map m = 
details::AnyUnsafe::CopyFromAnyViewAfterCheck>(value);
+for (const auto& [k, v] : m) {
+  WalkValue(k);
+  WalkValue(v);
+}
+break;
+  }
+  default: {
+if (value.type_index() >= TypeIndex::kTVMFFIStaticObjectBegin) {
+  const Object* obj = 
details::AnyUnsafe::CopyFromAnyViewAfterCheck(value);
+  if (obj != nullptr && visited_.find(obj) == visited_.end()) {
+CollectObjectDFS(obj);
+  }
+}
+break;
+  }
+}
+  }

Review Comment:
   ![medium](https://www.gstatic.com/codereviewagent/medium-priority.svg)
   
   The traversal of containers (`Array`, `Map`) in `WalkValue`, 
`PushFieldChildren`, and `Resolve` is recursive. This could lead to a stack 
overflow for deeply nested containers (e.g., an `Array` of `Array`s).
   
   Since `CollectObjectDFS` already uses an iterative approach with an explicit 
stack to handle deep object graphs, I recommend applying a similar iterative 
pattern for container traversal here. This would make the deep copy mechanism 
fully robust against stack overflows for any object graph structure.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: disc

Re: [PR] feat: add `__copy__`, `__deepcopy__`, and `__replace__` for FFI objects [tvm-ffi]

2026-02-08 Thread via GitHub


gemini-code-assist[bot] commented on PR #438:
URL: https://github.com/apache/tvm-ffi/pull/438#issuecomment-3869233311

   ## Summary of Changes
   
   Hello @junrushao, I'm Gemini Code Assist[^1]! I'm currently reviewing this 
pull request and will post my feedback shortly. In the meantime, here's a 
summary to help you and other reviewers quickly get up to speed!
   
   This pull request significantly enhances the interoperability between C++ 
FFI objects and Python by introducing robust copying mechanisms. It allows 
users to perform shallow and deep copies, as well as field-based replacements, 
on C++-backed objects directly from Python, aligning their behavior with 
standard Python objects. This change improves the usability and flexibility of 
FFI objects within Python workflows.
   
   ### Highlights
   
   * **C++ Reflection API Enhancement**: Introduced `refl::enable_copy()` in 
the C++ reflection API to register a `__ffi_shallow_copy__` method, allowing 
C++ objects to define their shallow copy behavior using their copy constructor.
   * **Deep Copy Mechanism**: Developed `ObjectDeepCopier` in C++ 
(`src/ffi/extra/copy.cc`) which performs a two-phase deep copy: first, it walks 
the object graph using DFS to collect objects in topological order, then it 
creates shallow copies and replaces fields with previously copied values.
   * **Python Integration for Copy Operations**: Wired up Python's `__copy__`, 
`__deepcopy__`, and `__replace__` methods for FFI objects, ensuring proper copy 
semantics for both `@register_object` and `@c_class` types. Types without 
`enable_copy()` will now raise a `TypeError` when these methods are called.
   
   🧠 **New Feature in Public Preview:** You can now enable **Memory** to help 
**Gemini Code Assist** learn from your team's feedback. This makes future code 
reviews more consistent and personalized to your project's style. **Click 
[here](https://codeassist.google/code-review/login) to enable Memory in your 
admin console.**
   
   
   Changelog
   
   * **.pre-commit-config.yaml**
   * Updated the `ty check` pre-commit hook to include 
`--error-on-warning`, enforcing stricter type checking.
   * **CMakeLists.txt**
   * Added `src/ffi/extra/copy.cc` to the build system, incorporating the 
new C++ copy utilities.
   * **include/tvm/ffi/extra/copy.h**
   * Introduced the `DeepCopyValue` function declaration, providing a C++ 
API for deep copying `ffi::Any` values.
   * **include/tvm/ffi/reflection/registry.h**
   * Defined `refl::enable_copy` helper struct to facilitate registration 
of `__ffi_shallow_copy__` methods for C++ object types.
   * Extended `ObjectDef` to include a `def(enable_copy)` method, allowing 
types to easily opt-in to copy support.
   * **python/tvm_ffi/dataclasses/c_class.py**
   * Modified the `@c_class` decorator to call `_setup_copy_methods`, 
enabling Python copy methods for C++ classes.
   * **python/tvm_ffi/registry.py**
   * Implemented `_setup_copy_methods` to dynamically add `__copy__`, 
`__deepcopy__`, and `__replace__` to FFI object types based on the presence of 
`__ffi_shallow_copy__`.
   * Added helper functions (`_copy_supported`, `_deepcopy_supported`, 
`_replace_supported`, and their `_unsupported` counterparts) to handle the 
Python-side implementation and error reporting for copy operations.
   * Introduced `_get_deep_copy_func` and `_deep_copy_func_cache` for 
efficient lookup of the C++ deep copy function.
   * **src/ffi/extra/copy.cc**
   * Implemented the `ObjectDeepCopier` class, which performs a two-phase 
deep copy: graph traversal (DFS) to collect objects in topological order, 
followed by shallow copying and field replacement.
   * Provided the `DeepCopyValue` function, exposed as `ffi.DeepCopy` to 
the FFI, which leverages `ObjectDeepCopier`.
   * **src/ffi/testing/testing.cc**
   * Updated test object definitions (`TestIntPairObj`, `TestObjectBase`, 
`TestObjectDerived`, `SchemaAllTypesObj`) to use `refl::enable_copy()`, making 
them copyable for testing purposes.
   * **tests/python/test_copy.py**
   * Added a new test file with 17 tests covering various aspects of 
`copy.copy()`, `copy.deepcopy()`, and `__replace__` for FFI objects, including 
basic fields, new object identity, mutable fields, mutation isolation, derived 
type preservation, nested objects, shared references, and error handling for 
unsupported types.
   
   
   
   
   
   Activity
   
   * A new C++ implementation for deep copying FFI objects has been introduced.
   * Python's `copy` module functionality (`__copy__`, `__deepcopy__`, 
`__replace__`) has been integrated with FFI objects.
   * Comprehensive test cases have been added to validate the new copy 
mechanisms across various scenarios.
   * The build system and pre-commit hooks were updated to support the new C++ 
files and enforce stricter code quality.
   
   
   
   
   Using Gemini Code Assist
   
   
   The full guide for Gemini C