99 template <
typename T,
typename Enable =
void>
108 template <
typename T>
109 struct ConfigTypeTagOf<T, std::enable_if_t<std::is_integral_v<T> && !std::is_same_v<T, bool>>>
114 template <
typename T>
120 template <
typename T>
126 template <
typename T, std::
size_t N>
139 template <
typename T>
150 template <
typename T,
typename =
void>
153 template <
typename T>
156 decltype(static_cast<int>(T::RowsAtCompileTime)),
157 decltype(static_cast<int>(T::ColsAtCompileTime))>> : std::true_type {};
160 template <
typename T>
199 std::optional<double>
min;
200 std::optional<double>
max;
225 return {std::move(key), std::move(value)};
231 return {std::move(vals)};
260 template <
typename Tag,
typename... Rest>
263 applyTag(meta, std::forward<Tag>(tag));
264 applyTags(meta, std::forward<Rest>(rest)...);
271 template <
typename T,
typename V>
272 std::function<nlohmann::ordered_json()>
276 auto typeTag = meta.typeTag;
277 auto minimum = meta.minimum;
278 auto maximum = meta.maximum;
279 auto enumVals = meta.enumValues;
280 auto auxInfo = meta.auxInfo;
282 return [member, desc, typeTag, minimum, maximum, enumVals, auxInfo]() -> nlohmann::ordered_json
284 nlohmann::ordered_json s;
289 s[
"default"] = nlohmann::ordered_json(defaults.*member);
290 s[
"description"] = desc;
291 if (minimum.has_value())
292 s[
"minimum"] = minimum.value();
293 if (maximum.has_value())
294 s[
"maximum"] = maximum.value();
295 if (!enumVals.empty())
296 s[
"enum"] = enumVals;
297 for (
const auto &kv : auxInfo)
298 s[
"x-" + kv.first] = kv.second;
308 template <
typename T,
typename V>
309 std::function<void(
const nlohmann::ordered_json &,
const char *)>
318 return [minimum, maximum](
const nlohmann::ordered_json &val,
const char *fieldName)
321 if (!val.is_number())
323 double v = val.get<
double>();
324 if (minimum.has_value() &&
v < minimum.value())
326 throw std::runtime_error(
327 fmt::format(
"Config field '{}': value {} is below minimum {}",
328 fieldName,
v, minimum.value()));
330 if (maximum.has_value() &&
v > maximum.value())
332 throw std::runtime_error(
333 fmt::format(
"Config field '{}': value {} is above maximum {}",
334 fieldName,
v, maximum.value()));
349 template <
typename T>
364 template <
typename V,
typename... Tags>
365 void field(V T::*member, const char *jsonKey, const char *desc, Tags &&...tags)
376 auto rangeChecker = detail::makeRangeChecker<T, V>(meta);
378 meta.
readField = [member, jsonKey, rangeChecker](
const nlohmann::ordered_json &j,
void *obj)
380 const auto &val = j.at(jsonKey);
382 rangeChecker(val, jsonKey);
383 static_cast<T *
>(obj)->*member = val.template get<V>();
385 meta.
writeField = [member, jsonKey](nlohmann::ordered_json &j,
const void *obj)
387 j[jsonKey] =
static_cast<const T *
>(obj)->*member;
389 meta.
schemaEntry = detail::makeSchemaEntry<T>(member, desc, meta);
397 template <
typename V,
typename... Tags>
398 void field_alias(V T::*member, const char *jsonKey, const char *desc, Tags &&...tags)
400 field(member, jsonKey, desc, std::forward<Tags>(tags)...);
407 template <
typename S,
typename... Tags>
408 void field_section(
S T::*member, const char *jsonKey, const char *desc, Tags &&...tags)
414 meta.
readField = [member, jsonKey](
const nlohmann::ordered_json &j,
void *obj)
418 from_json(j.at(jsonKey),
static_cast<T *
>(obj)->*member);
420 meta.
writeField = [member, jsonKey](nlohmann::ordered_json &j,
const void *obj)
422 j[jsonKey] =
static_cast<const T *
>(obj)->*member;
426 S::_dnds_ensure_registered();
436 template <
typename S,
typename... Tags>
437 void field_array_of(std::vector<S> T::*member, const char *jsonKey, const char *desc, Tags &&...tags)
443 meta.
readField = [member, jsonKey](
const nlohmann::ordered_json &j,
void *obj)
445 static_cast<T *
>(obj)->*member = j.at(jsonKey).template get<std::vector<S>>();
447 meta.
writeField = [member, jsonKey](nlohmann::ordered_json &j,
const void *obj)
449 j[jsonKey] =
static_cast<const T *
>(obj)->*member;
451 meta.
schemaEntry = [desc]() -> nlohmann::ordered_json
453 nlohmann::ordered_json s;
455 s[
"description"] = desc;
456 S::_dnds_ensure_registered();
467 template <
typename S,
typename... Tags>
468 void field_map_of(std::map<std::string, S> T::*member, const char *jsonKey, const char *desc, Tags &&...tags)
474 meta.
readField = [member, jsonKey](
const nlohmann::ordered_json &j,
void *obj)
476 static_cast<T *
>(obj)->*member =
477 j.at(jsonKey).template get<std::map<std::string, S>>();
479 meta.
writeField = [member, jsonKey](nlohmann::ordered_json &j,
const void *obj)
481 j[jsonKey] =
static_cast<const T *
>(obj)->*member;
483 meta.
schemaEntry = [desc]() -> nlohmann::ordered_json
485 nlohmann::ordered_json s;
486 s[
"type"] =
"object";
487 s[
"description"] = desc;
488 S::_dnds_ensure_registered();
499 template <
typename... Tags>
500 void field_json(nlohmann::ordered_json T::*member, const char *jsonKey, const char *desc, Tags &&...tags)
506 meta.
readField = [member, jsonKey](
const nlohmann::ordered_json &j,
void *obj)
508 static_cast<T *
>(obj)->*member = j.at(jsonKey);
510 meta.
writeField = [member, jsonKey](nlohmann::ordered_json &j,
const void *obj)
512 j[jsonKey] =
static_cast<const T *
>(obj)->*member;
514 meta.
schemaEntry = [desc]() -> nlohmann::ordered_json
516 nlohmann::ordered_json s;
517 s[
"description"] = desc;
538 template <
typename FSchema,
typename... Tags>
540 const char *jsonKey, const char *desc,
541 FSchema &&schemaFn, Tags &&...tags)
547 meta.
readField = [member, jsonKey](
const nlohmann::ordered_json &j,
void *obj)
549 static_cast<T *
>(obj)->*member = j.at(jsonKey);
551 meta.
writeField = [member, jsonKey](nlohmann::ordered_json &j,
const void *obj)
553 j[jsonKey] =
static_cast<const T *
>(obj)->*member;
555 meta.
schemaEntry = [fn = std::forward<FSchema>(schemaFn)]() -> nlohmann::ordered_json
567 template <
typename F>
568 auto check(F &&f) ->
decltype(f(std::declval<const T &>()), void())
571 [fn = std::forward<F>(f)](
const void *obj) ->
CheckResult
573 return fn(*
static_cast<const T *
>(obj));
580 template <
typename F>
581 void check(
const char *msg, F &&pred)
584 [
message = std::string(msg), fn = std::forward<F>(pred)](
const void *obj) ->
CheckResult
586 bool ok = fn(*
static_cast<const T *
>(obj));
595 template <
typename F>
596 auto check_ctx(F &&f) ->
decltype(f(std::declval<const T &>(), std::declval<const ConfigContext &>()), void())
601 return fn(*
static_cast<const T *
>(obj), ctx);
609 template <
typename F>
633#define DNDS_FIELD(name_, desc_, ...) \
634 config.field(&T::name_, #name_, desc_, ##__VA_ARGS__)
662#define DNDS_DECLARE_CONFIG(Type_) \
664 static void _dnds_ensure_registered() \
666 static bool done = false; \
669 ::DNDS::ConfigSectionBuilder<Type_> config; \
670 _dnds_do_register(config); \
672 friend void to_json(nlohmann::ordered_json &j, const Type_ &t) \
674 Type_::_dnds_ensure_registered(); \
675 ::DNDS::ConfigRegistry<Type_>::writeToJson(j, t); \
677 friend void from_json(const nlohmann::ordered_json &j, Type_ &t) \
679 Type_::_dnds_ensure_registered(); \
680 ::DNDS::ConfigRegistry<Type_>::readFromJson(j, t); \
682 static nlohmann::ordered_json schema(const std::string &desc = "") \
684 Type_::_dnds_ensure_registered(); \
685 return ::DNDS::ConfigRegistry<Type_>::emitSchema(desc); \
687 std::vector<::DNDS::CheckResult> validate() const \
689 Type_::_dnds_ensure_registered(); \
690 return ::DNDS::ConfigRegistry<Type_>::validate(*this); \
692 std::vector<::DNDS::CheckResult> validateWithContext( \
693 const ::DNDS::ConfigContext &ctx) const \
695 Type_::_dnds_ensure_registered(); \
696 return ::DNDS::ConfigRegistry<Type_>::validateWithContext(*this, ctx); \
698 static void validateKeys(const nlohmann::ordered_json &j) \
700 Type_::_dnds_ensure_registered(); \
701 ::DNDS::ConfigRegistry<Type_>::validateKeys(j); \
703 static void _dnds_do_register(::DNDS::ConfigSectionBuilder<Type_> &config)
Per-type configuration field registry with JSON serialization, JSON Schema (draft-07) emission,...
static bool registerField(FieldMeta meta)
Register a single field's metadata.
static bool registerCheck(CrossFieldCheck check)
Register a cross-field validation check (no runtime context needed).
static bool registerContextualCheck(ContextualCheck check)
Register a cross-field validation check that needs runtime context.
static nlohmann::ordered_json emitSchema(const std::string §ionDescription="")
Emit a JSON Schema (draft-07) object describing all registered fields.
static void registerPostReadHook(std::function< void(T &)> hook)
Register a post-read hook called after all fields are deserialized. Useful for recomputing derived qu...
Builder object passed to the user's registration function.
void field_map_of(std::map< std::string, S > T::*member, const char *jsonKey, const char *desc, Tags &&...tags)
Register a std::map<std::string, S> field.
void field_json(nlohmann::ordered_json T::*member, const char *jsonKey, const char *desc, Tags &&...tags)
Register an opaque nlohmann::ordered_json field.
void field(V T::*member, const char *jsonKey, const char *desc, Tags &&...tags)
Register a field with pointer-to-member.
auto check(F &&f) -> decltype(f(std::declval< const T & >()), void())
Register a context-free cross-field check.
void field_json_schema(nlohmann::ordered_json T::*member, const char *jsonKey, const char *desc, FSchema &&schemaFn, Tags &&...tags)
Register an opaque nlohmann::ordered_json field with a user-supplied schema generator.
void check(const char *msg, F &&pred)
Register a context-free cross-field check with a message string.
void field_section(S T::*member, const char *jsonKey, const char *desc, Tags &&...tags)
Register a nested sub-section. The sub-section type must itself use DNDS_DECLARE_CONFIG.
void field_array_of(std::vector< S > T::*member, const char *jsonKey, const char *desc, Tags &&...tags)
Register a std::vector<S> field (array of sub-objects).
void post_read(F &&f)
Register a post-read hook for recomputing derived quantities.
auto check_ctx(F &&f) -> decltype(f(std::declval< const T & >(), std::declval< const ConfigContext & >()), void())
Register a context-aware cross-field check.
void field_alias(V T::*member, const char *jsonKey, const char *desc, Tags &&...tags)
Register a field whose JSON key differs from the C++ member name.
EnumValuesTag enum_values(std::vector< std::string > vals)
Create an enum allowed-values tag.
InfoTag info(std::string key, std::string value)
Create an auxiliary info tag.
RangeTag range(double min)
Create a minimum-only range constraint.
std::function< void(const nlohmann::ordered_json &, const char *)> makeRangeChecker(const FieldMeta &meta)
Build a runtime range-check closure.
void applyTags(FieldMeta &)
void applyTag(FieldMeta &meta, const Config::RangeTag &tag)
std::function< nlohmann::ordered_json()> makeSchemaEntry(V T::*member, const char *desc, const FieldMeta &meta)
Build the schemaEntry closure from a fully-tagged FieldMeta.
the host side operators are provided as implemented
ConfigTypeTag
Enumerates the JSON Schema type associated with a config field.
void from_json(const nlohmann::ordered_json &j, host_device_vector< real > &v)
std::string schemaTypeString(ConfigTypeTag tag)
message(STATUS "here!!!! ${DNDS_Euler_Models_List}") foreach(item IN LISTS DNDS_Euler_Models_List) string(REPLACE "
Result of a single validation check.
Runtime context supplied to context-aware validation checks.
static constexpr ConfigTypeTag value
Explicit enum allowed-values tag.
std::vector< std::string > values
Auxiliary info tag (emitted as "x-<key>" in schema).
Numeric range constraint. Enforced at parse time in readFromJson and emitted in schema.
std::optional< double > max
std::optional< double > min
Eigen::Matrix< real, 5, 1 > v