Program Listing for File enum_def.h#
↰ Return to documentation for file (tvm/ffi/reflection/enum_def.h)
/*
* 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.
*/
#ifndef TVM_FFI_REFLECTION_ENUM_DEF_H_
#define TVM_FFI_REFLECTION_ENUM_DEF_H_
#include <tvm/ffi/any.h>
#include <tvm/ffi/c_api.h>
#include <tvm/ffi/container/dict.h>
#include <tvm/ffi/container/list.h>
#include <tvm/ffi/enum.h>
#include <tvm/ffi/error.h>
#include <tvm/ffi/memory.h>
#include <tvm/ffi/object.h>
#include <tvm/ffi/reflection/accessor.h>
#include <tvm/ffi/reflection/registry.h>
#include <tvm/ffi/string.h>
#include <cstdint>
#include <type_traits>
#include <utility>
namespace tvm {
namespace ffi {
namespace reflection {
template <typename EnumClsObj, typename = std::enable_if_t<std::is_base_of_v<EnumObj, EnumClsObj>>>
class EnumDef : public ReflectionDefBase {
public:
explicit EnumDef(const char* str_index) : type_index_(EnumClsObj::_GetOrAllocRuntimeTypeIndex()) {
static_assert(!std::is_base_of_v<IntEnumObj, EnumClsObj>,
"IntEnum registration requires an explicit integer index");
EnumState state = EnsureState();
Register(state, static_cast<int64_t>(state->entries.size()), String(str_index));
}
EnumDef(const char* str_index, int64_t int_index)
: type_index_(EnumClsObj::_GetOrAllocRuntimeTypeIndex()) {
static_assert(std::is_base_of_v<IntEnumObj, EnumClsObj>,
"Explicit integer indices are reserved for IntEnum");
Register(EnsureState(), int_index, String(str_index));
}
template <typename T>
EnumDef& set_attr(const char* attr_name, T value) {
Dict<String, Dict<ObjectRef, Any>> attrs = EnsureState()->attrs;
String key(attr_name);
Dict<ObjectRef, Any> column = attrs.Get(key).value_or(Dict<ObjectRef, Any>());
attrs.Set(key, column);
column.Set(instance_, Any(std::move(value)));
return *this;
}
private:
void Register(const EnumState& state, int64_t int_index, String str_index) {
List<ObjectRef> entries = state->entries;
Dict<Any, ObjectRef> indexes = state->indexes;
Any int_key(int_index);
Any str_key(str_index);
if (indexes.count(int_key) || indexes.count(str_key)) {
TVM_FFI_THROW(ValueError) << "Duplicate enum index for type `" << EnumClsObj::_type_key
<< "`";
}
ObjectPtr<EnumClsObj> obj = make_object<EnumClsObj>();
::tvm::ffi::details::ObjectUnsafe::GetHeader(obj.get())->type_index = type_index_;
obj->_int_index = int_index;
obj->_str_index = std::move(str_index);
instance_ = Enum(ObjectPtr<EnumObj>(std::move(obj)));
entries.push_back(instance_);
indexes.Set(int_key, instance_);
indexes.Set(str_key, instance_);
}
EnumState EnsureState() {
int32_t state_type_index = EnumStateObj::_GetOrAllocRuntimeTypeIndex();
TypeAttrColumn column(type_attr::kEnumState);
if (AnyView value = column[type_index_]; value != nullptr) {
if (value.type_index() != state_type_index) {
TVM_FFI_THROW(TypeError) << "Expected `" << EnumStateObj::_type_key
<< "` in enum state column, but got `" << value.GetTypeKey()
<< "`";
}
// Avoid cast<EnumState> here because it reads the same deferred inline type index.
TVMFFIAny value_any = value.CopyToTVMFFIAny();
return ::tvm::ffi::details::ObjectUnsafe::ObjectRefFromObjectPtr<EnumState>(
::tvm::ffi::details::ObjectUnsafe::ObjectPtrFromUnowned<Object>(value_any.v_obj));
}
ObjectPtr<EnumStateObj> state_obj = make_object<EnumStateObj>();
// GCC runs attribute constructors before dynamic initialization of inline type indices.
// Set the header explicitly so the state is not packed as `None` during static init.
::tvm::ffi::details::ObjectUnsafe::GetHeader(state_obj.get())->type_index = state_type_index;
EnumState state(std::move(state_obj));
constexpr TVMFFIByteArray name = AsByteArray(type_attr::kEnumState);
TVMFFIAny value_any = AnyView(state).CopyToTVMFFIAny();
TVM_FFI_CHECK_SAFE_CALL(TVMFFITypeRegisterAttr(type_index_, &name, &value_any));
return state;
}
int32_t type_index_;
Enum instance_;
};
} // namespace reflection
} // namespace ffi
} // namespace tvm
#endif // TVM_FFI_REFLECTION_ENUM_DEF_H_