27 #ifndef TVM_IR_CONFIG_SCHEMA_H_
28 #define TVM_IR_CONFIG_SCHEMA_H_
30 #include <tvm/ffi/container/map.h>
31 #include <tvm/ffi/function.h>
32 #include <tvm/ffi/reflection/registry.h>
36 #include <type_traits>
37 #include <unordered_map>
86 template <
typename T,
typename... Traits>
88 std::string skey(key);
89 if (key_to_index_.count(skey)) {
90 TVM_FFI_THROW(ValueError) <<
"Duplicate config option key: '" << key <<
"'";
92 key_to_index_[skey] = options_.size();
93 options_.push_back(MakeEntry<T>(key, std::forward<Traits>(traits)...));
102 ffi::TypedFunction<ffi::Any(ffi::Any)>
func;
126 for (
const auto& e : options_) {
127 auto it = config.find(e.key);
128 if (it != config.end()) {
129 result.Set(e.key, e.validator((*it).second));
130 }
else if (e.has_default) {
131 if (e.default_from_factory) {
134 result.Set(e.key, e.default_value);
141 if (error_on_unknown_) {
142 for (
const auto& kv : config) {
143 if (!key_to_index_.count(std::string(kv.first))) {
144 std::ostringstream os;
145 os <<
"Unknown config option '" << kv.first <<
"'. Known options: ";
147 for (
const auto& e : options_) {
148 if (!first) os <<
", ";
149 os <<
"'" << e.key <<
"'";
152 TVM_FFI_THROW(ValueError) << os.str();
158 if (canonicalizer_ !=
nullptr) {
159 result = canonicalizer_(result);
169 const std::vector<OptionEntry>&
ListOptions()
const {
return options_; }
172 bool HasOption(
const ffi::String& key)
const {
return key_to_index_.count(std::string(key)) > 0; }
175 template <
typename T>
176 static ffi::TypedFunction<ffi::Any(ffi::Any)> MakeValidator(
const ffi::String& key) {
177 return ffi::TypedFunction<ffi::Any(ffi::Any)>([key](ffi::Any val) -> ffi::Any {
178 auto opt = val.try_cast<T>();
179 if (!opt.has_value()) {
180 TVM_FFI_THROW(TypeError) <<
"Option '" << key <<
"': expected type '"
181 << ffi::TypeTraits<T>::TypeStr() <<
"' but got '"
182 << val.GetTypeKey() <<
"'";
184 return ffi::Any(opt.value());
188 template <
typename Trait>
189 static void ApplyTrait(OptionEntry* entry, ffi::reflection::FieldInfoBuilder* info,
191 using T = std::decay_t<Trait>;
192 if constexpr (std::is_same_v<T, AttrValidator>) {
193 entry->validator = std::move(trait.func);
194 }
else if constexpr (std::is_base_of_v<ffi::reflection::InfoTrait, T>) {
196 }
else if constexpr (std::is_same_v<T, const char*> || std::is_same_v<T, char*>) {
197 const char* doc = trait;
198 if (doc !=
nullptr && doc[0] !=
'\0') {
199 info->doc = TVMFFIByteArray{doc, std::char_traits<char>::length(doc)};
204 template <
typename T,
typename... Traits>
205 OptionEntry MakeEntry(
const ffi::String& key, Traits&&... traits) {
208 e.type_str = ffi::String(ffi::TypeTraits<T>::TypeStr());
209 e.validator = MakeValidator<T>(key);
212 ffi::reflection::FieldInfoBuilder info{};
214 info.default_value_or_factory = ffi::AnyView(
nullptr).CopyToTVMFFIAny();
215 info.doc = TVMFFIByteArray{
nullptr, 0};
216 (ApplyTrait(&e, &info, std::forward<Traits>(traits)), ...);
217 if (info.flags & kTVMFFIFieldFlagBitMaskHasDefault) {
218 e.has_default =
true;
219 e.default_from_factory = (info.flags & kTVMFFIFieldFlagBitMaskDefaultFromFactory) != 0;
220 e.default_value = ffi::AnyView::CopyFromTVMFFIAny(info.default_value_or_factory);
222 if (info.default_value_or_factory.type_index >= TVMFFITypeIndex::kTVMFFIStaticObjectBegin) {
223 ffi::details::ObjectUnsafe::DecRefObjectHandle(info.default_value_or_factory.v_obj);
230 std::vector<OptionEntry> options_;
232 std::unordered_map<std::string, size_t> key_to_index_;
236 bool error_on_unknown_ =
true;
Dynamic config schema for map-like options.
Definition: config_schema.h:53
bool HasOption(const ffi::String &key) const
Check if an option with the given key exists.
Definition: config_schema.h:172
ConfigMap Resolve(ConfigMap config) const
Default/validate, then canonicalize a config object.
Definition: config_schema.h:122
ffi::Map< ffi::String, ffi::Any > ConfigMap
Definition: config_schema.h:55
void set_error_on_unknown(bool value)
Set whether unknown keys trigger an error.
Definition: config_schema.h:107
ConfigSchema & def_option(const ffi::String &key, Traits &&... traits)
Declare a typed option.
Definition: config_schema.h:87
void set_canonicalizer(Canonicalizer f)
Set whole-object canonicalizer.
Definition: config_schema.h:98
ffi::TypedFunction< ConfigMap(ConfigMap)> Canonicalizer
Definition: config_schema.h:56
const std::vector< OptionEntry > & ListOptions() const
List declared options in declaration order.
Definition: config_schema.h:169
An object that builds and maintains block scope and StmtSref mapping for Dependence analysis.
Definition: analyzer.h:37
Trait to set a custom validator for a config option.
Definition: config_schema.h:101
ffi::TypedFunction< ffi::Any(ffi::Any)> func
Definition: config_schema.h:102
AttrValidator(ffi::TypedFunction< ffi::Any(ffi::Any)> f)
Definition: config_schema.h:103
Schema entry for one declared option.
Definition: config_schema.h:59
ffi::String key
Option key.
Definition: config_schema.h:61
bool default_from_factory
Whether the default is produced by a factory function.
Definition: config_schema.h:69
ffi::Any default_value
Default value, or factory function () -> Any when default_from_factory is true.
Definition: config_schema.h:71
ffi::String type_str
Type string for this option.
Definition: config_schema.h:63
bool has_default
Whether this option has a default value or factory.
Definition: config_schema.h:67
ffi::TypedFunction< ffi::Any(ffi::Any)> validator
Per-option validator/coercer (Any -> Any).
Definition: config_schema.h:65