| /* |
| * 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. |
| */ |
| #include <gtest/gtest.h> |
| #include <tvm/ffi/container/map.h> |
| #include <tvm/ffi/object.h> |
| #include <tvm/ffi/reflection/access_path.h> |
| #include <tvm/ffi/reflection/accessor.h> |
| #include <tvm/ffi/reflection/creator.h> |
| #include <tvm/ffi/reflection/overload.h> |
| #include <tvm/ffi/reflection/registry.h> |
| #include <tvm/ffi/string.h> |
| |
| namespace { |
| |
| using namespace tvm::ffi; |
| |
| struct TestOverloadObj : public Object { |
| explicit TestOverloadObj(int32_t x) : type(Type::INT) {} |
| explicit TestOverloadObj(float y) : type(Type::FLOAT) {} |
| |
| static int AddOneInt(int x) { return x + 1; } |
| static float AddOneFloat(float x) { return x + 1.0f; } |
| |
| template <typename T> |
| auto Holds(T) const { |
| if constexpr (std::is_same_v<T, int32_t>) { |
| return type == Type::INT; |
| } else if constexpr (std::is_same_v<T, float>) { |
| return type == Type::FLOAT; |
| } else { |
| static_assert(sizeof(T) == 0, "Unsupported type"); |
| } |
| } |
| |
| enum class Type { INT, FLOAT } type; |
| TVM_FFI_DECLARE_OBJECT_INFO("test.TestOverloadObj", TestOverloadObj, Object); |
| }; |
| |
| TVM_FFI_STATIC_INIT_BLOCK() { |
| namespace refl = tvm::ffi::reflection; |
| refl::OverloadObjectDef<TestOverloadObj>() |
| .def(refl::init<int32_t>()) |
| .def(refl::init<float>()) |
| .def("hold_same_type", &TestOverloadObj::Holds<int32_t>) |
| .def("hold_same_type", &TestOverloadObj::Holds<float>) |
| .def_static("add_one_static", &TestOverloadObj::AddOneInt) |
| .def_static("add_one_static", &TestOverloadObj::AddOneFloat); |
| } |
| |
| TEST(Reflection, CallOverloadedInitMethod) { |
| Function init_method = reflection::GetMethod("test.TestOverloadObj", "__ffi_init__"); |
| Any obj_a = init_method(10); // choose the int constructor |
| EXPECT_TRUE(obj_a.as<TestOverloadObj>() != nullptr); |
| EXPECT_EQ(obj_a.as<TestOverloadObj>()->type, TestOverloadObj::Type::INT); |
| Any obj_b = init_method(3.14f); // choose the float constructor |
| EXPECT_TRUE(obj_b.as<TestOverloadObj>() != nullptr); |
| EXPECT_EQ(obj_b.as<TestOverloadObj>()->type, TestOverloadObj::Type::FLOAT); |
| } |
| |
| TEST(Reflection, CallOverloadedMethod) { |
| Function init_method = reflection::GetMethod("test.TestOverloadObj", "__ffi_init__"); |
| Function hold_same_type = reflection::GetMethod("test.TestOverloadObj", "hold_same_type"); |
| Any obj_a = init_method(10); // choose the int constructor |
| Any res_a = hold_same_type(obj_a, 20); |
| EXPECT_EQ(res_a.as<bool>(), true); |
| Any res_b = hold_same_type(obj_a, 3.14f); |
| EXPECT_EQ(res_b.as<bool>(), false); |
| } |
| |
| TEST(Reflection, CallOverloadedStaticMethod) { |
| Function add_one = reflection::GetMethod("test.TestOverloadObj", "add_one_static"); |
| Any res_a = add_one(20); |
| EXPECT_EQ(res_a.as<int>(), 21); |
| Any res_b = add_one(1.0f); |
| static_assert(1.0f + 1.0f == 2.0f); |
| EXPECT_EQ(res_b.as<float>(), 2.0f); |
| } |
| |
| } // namespace |