99 template <
typename T,
typename Enable =
void>
116 template <
typename T>
117 struct ConfigTypeTagOf<T, std::enable_if_t<std::is_integral_v<T> && !std::is_same_v<T, bool>>>
122 template <
typename T>
128 template <
typename T>
134 template <
typename T, std::
size_t N>
147 template <
typename T>
158 template <
typename T,
typename =
void>
163 template <
typename T>
166 decltype(static_cast<int>(T::RowsAtCompileTime)),
167 decltype(static_cast<int>(T::ColsAtCompileTime))>> : std::true_type
172 template <
typename T>
226 std::optional<double>
min;
227 std::optional<double>
max;
252 return {std::move(key), std::move(value)};
258 return {std::move(vals)};
287 template <
typename Tag,
typename... Rest>
290 applyTag(meta, std::forward<Tag>(tag));
291 applyTags(meta, std::forward<Rest>(rest)...);
298 template <
typename T,
typename V>
299 std::function<nlohmann::ordered_json()>
303 auto typeTag = meta.typeTag;
304 auto minimum = meta.minimum;
305 auto maximum = meta.maximum;
306 auto enumVals = meta.enumValues;
307 auto auxInfo = meta.auxInfo;
309 return [member, desc, typeTag, minimum, maximum, enumVals, auxInfo]() -> nlohmann::ordered_json
311 nlohmann::ordered_json s;
316 s[
"default"] = nlohmann::ordered_json(defaults.*member);
317 s[
"description"] = desc;
318 if (minimum.has_value())
319 s[
"minimum"] = minimum.value();
320 if (maximum.has_value())
321 s[
"maximum"] = maximum.value();
322 if (!enumVals.empty())
323 s[
"enum"] = enumVals;
324 for (
const auto &kv : auxInfo)
325 s[
"x-" + kv.first] = kv.second;
335 template <
typename T,
typename V>
336 std::function<void(
const nlohmann::ordered_json &,
const char *)>
345 return [minimum, maximum](
const nlohmann::ordered_json &val,
const char *fieldName)
348 if (!val.is_number())
350 double v = val.get<
double>();
351 if (minimum.has_value() &&
v < minimum.value())
353 throw std::runtime_error(
354 fmt::format(
"Config field '{}': value {} is below minimum {}",
355 fieldName,
v, minimum.value()));
357 if (maximum.has_value() &&
v > maximum.value())
359 throw std::runtime_error(
360 fmt::format(
"Config field '{}': value {} is above maximum {}",
361 fieldName,
v, maximum.value()));
376 template <
typename T>
391 template <
typename V,
typename... Tags>
392 void field(V T::*member, const char *jsonKey, const char *desc, Tags &&...tags)
403 auto rangeChecker = detail::makeRangeChecker<T, V>(meta);
405 meta.
readField = [member, jsonKey, rangeChecker](
const nlohmann::ordered_json &
j,
void *obj)
407 const auto &val =
j.at(jsonKey);
409 rangeChecker(val, jsonKey);
410 static_cast<T *
>(obj)->*member = val.template get<V>();
412 meta.
writeField = [member, jsonKey](nlohmann::ordered_json &
j,
const void *obj)
414 j[jsonKey] =
static_cast<const T *
>(obj)->*member;
416 meta.
schemaEntry = detail::makeSchemaEntry<T>(member, desc, meta);
424 template <
typename V,
typename... Tags>
425 void field_alias(V T::*member, const char *jsonKey, const char *desc, Tags &&...tags)
427 field(member, jsonKey, desc, std::forward<Tags>(tags)...);
434 template <
typename S,
typename... Tags>
435 void field_section(
S T::*member, const char *jsonKey, const char *desc, Tags &&...tags)
441 meta.
readField = [member, jsonKey](
const nlohmann::ordered_json &
j,
void *obj)
445 from_json(
j.at(jsonKey),
static_cast<T *
>(obj)->*member);
447 meta.
writeField = [member, jsonKey](nlohmann::ordered_json &
j,
const void *obj)
449 j[jsonKey] =
static_cast<const T *
>(obj)->*member;
453 S::_dnds_ensure_registered();
463 template <
typename S,
typename... Tags>
464 void field_array_of(std::vector<S> T::*member, const char *jsonKey, const char *desc, Tags &&...tags)
470 meta.
readField = [member, jsonKey](
const nlohmann::ordered_json &
j,
void *obj)
472 static_cast<T *
>(obj)->*member =
j.at(jsonKey).template get<std::vector<S>>();
474 meta.
writeField = [member, jsonKey](nlohmann::ordered_json &
j,
const void *obj)
476 j[jsonKey] =
static_cast<const T *
>(obj)->*member;
478 meta.
schemaEntry = [desc]() -> nlohmann::ordered_json
480 nlohmann::ordered_json s;
482 s[
"description"] = desc;
483 S::_dnds_ensure_registered();
494 template <
typename S,
typename... Tags>
495 void field_map_of(std::map<std::string, S> T::*member, const char *jsonKey, const char *desc, Tags &&...tags)
501 meta.
readField = [member, jsonKey](
const nlohmann::ordered_json &
j,
void *obj)
503 static_cast<T *
>(obj)->*member =
504 j.at(jsonKey).template get<std::map<std::string, S>>();
506 meta.
writeField = [member, jsonKey](nlohmann::ordered_json &
j,
const void *obj)
508 j[jsonKey] =
static_cast<const T *
>(obj)->*member;
510 meta.
schemaEntry = [desc]() -> nlohmann::ordered_json
512 nlohmann::ordered_json s;
513 s[
"type"] =
"object";
514 s[
"description"] = desc;
515 S::_dnds_ensure_registered();
526 template <
typename... Tags>
527 void field_json(nlohmann::ordered_json T::*member, const char *jsonKey, const char *desc, Tags &&...tags)
533 meta.
readField = [member, jsonKey](
const nlohmann::ordered_json &
j,
void *obj)
535 static_cast<T *
>(obj)->*member =
j.at(jsonKey);
537 meta.
writeField = [member, jsonKey](nlohmann::ordered_json &
j,
const void *obj)
539 j[jsonKey] =
static_cast<const T *
>(obj)->*member;
541 meta.
schemaEntry = [desc]() -> nlohmann::ordered_json
543 nlohmann::ordered_json s;
544 s[
"description"] = desc;
565 template <
typename FSchema,
typename... Tags>
567 const char *jsonKey, const char *desc,
568 FSchema &&schemaFn, Tags &&...tags)
574 meta.
readField = [member, jsonKey](
const nlohmann::ordered_json &
j,
void *obj)
576 static_cast<T *
>(obj)->*member =
j.at(jsonKey);
578 meta.
writeField = [member, jsonKey](nlohmann::ordered_json &
j,
const void *obj)
580 j[jsonKey] =
static_cast<const T *
>(obj)->*member;
582 meta.
schemaEntry = [fn = std::forward<FSchema>(schemaFn)]() -> nlohmann::ordered_json
594 template <
typename F>
595 auto check(F &&f) ->
decltype(f(std::declval<const T &>()), void())
598 [fn = std::forward<F>(f)](
const void *obj) ->
CheckResult
600 return fn(*
static_cast<const T *
>(obj));
607 template <
typename F>
608 void check(
const char *msg, F &&pred)
611 [
message = std::string(msg), fn = std::forward<F>(pred)](
const void *obj) ->
CheckResult
613 bool ok = fn(*
static_cast<const T *
>(obj));
622 template <
typename F>
623 auto check_ctx(F &&f) ->
decltype(f(std::declval<const T &>(), std::declval<const ConfigContext &>()), void())
628 return fn(*
static_cast<const T *
>(obj), ctx);
636 template <
typename F>
660#define DNDS_FIELD(name_, desc_, ...) \
661 config.field(&T::name_, #name_, desc_, ##__VA_ARGS__)
692#define DNDS_DECLARE_CONFIG(Type_) \
694 static void _dnds_ensure_registered() \
696 static bool done = false; \
700 ::DNDS::ConfigSectionBuilder<Type_> config; \
701 _dnds_do_register(config); \
703 friend void to_json(nlohmann::ordered_json &j, const Type_ &t) \
705 Type_::_dnds_ensure_registered(); \
706 ::DNDS::ConfigRegistry<Type_>::writeToJson(j, t); \
708 friend void from_json(const nlohmann::ordered_json &j, Type_ &t) \
710 Type_::_dnds_ensure_registered(); \
711 ::DNDS::ConfigRegistry<Type_>::readFromJson(j, t); \
713 static nlohmann::ordered_json schema(const std::string &desc = "") \
715 Type_::_dnds_ensure_registered(); \
716 return ::DNDS::ConfigRegistry<Type_>::emitSchema(desc); \
718 std::vector<::DNDS::CheckResult> validate() const \
720 Type_::_dnds_ensure_registered(); \
721 return ::DNDS::ConfigRegistry<Type_>::validate(*this); \
723 std::vector<::DNDS::CheckResult> validateWithContext( \
724 const ::DNDS::ConfigContext &ctx) const \
726 Type_::_dnds_ensure_registered(); \
727 return ::DNDS::ConfigRegistry<Type_>::validateWithContext(*this, ctx); \
729 static void validateKeys(const nlohmann::ordered_json &j) \
731 Type_::_dnds_ensure_registered(); \
732 ::DNDS::ConfigRegistry<Type_>::validateKeys(j); \
734 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