Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
Taepper committed Nov 19, 2024
1 parent 4b6bf77 commit cd7cf31
Show file tree
Hide file tree
Showing 37 changed files with 718 additions and 908 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ find_package(re2 REQUIRED)
# Includes
# ---------------------------------------------------------------------------

include_directories(
include_directories(SYSTEM
${CMAKE_SOURCE_DIR}/include
)

Expand Down
6 changes: 5 additions & 1 deletion include/config/config_metadata.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,11 @@ class ConfigSpecification {

std::string helpText() const;

std::optional<ConfigValueSpecification> getValueSpecification(const ConfigKeyPath& key) const;
std::optional<ConfigValueSpecification> getValueSpecification(const ConfigKeyPath& key
) const;

std::optional<ConfigValueSpecification> getValueSpecificationStrict(const ConfigKeyPath& key
) const;
};

} // namespace silo::config
6 changes: 1 addition & 5 deletions include/config/config_source_interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -145,15 +145,11 @@ class VerifiedConfigSource {

[[nodiscard]] std::optional<uint32_t> getUint32(const ConfigKeyPath& config_key_path) const;

[[nodiscard]] std::optional<uint32_t> getUint16(const ConfigKeyPath& config_key_path) const;
[[nodiscard]] std::optional<uint16_t> getUint16(const ConfigKeyPath& config_key_path) const;

[[nodiscard]] std::optional<double> getFloat(const ConfigKeyPath& config_key_path) const;

[[nodiscard]] std::optional<bool> getBool(const ConfigKeyPath& config_key_path) const;

[[nodiscard]] bool hasProperty(const ConfigKeyPath& config_key_path) const {
return getString(config_key_path).has_value();
}
};

} // namespace silo::config
71 changes: 58 additions & 13 deletions include/config/config_value.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ namespace silo::config {

class ConfigKeyPath {
public:
std::vector<std::string> path;
std::vector<std::vector<std::string>> path;

friend bool operator==(const ConfigKeyPath& lhs, const ConfigKeyPath& rhs) {
return lhs.path == rhs.path;
Expand Down Expand Up @@ -44,9 +44,30 @@ constexpr std::string_view configValueTypeToString(ConfigValueType type) {
}
}

class ConfigValueSpecification;

class ConfigValue {
friend class ConfigValueSpecification;

ConfigValue(
std::variant<std::string, std::filesystem::path, int32_t, uint32_t, uint16_t, bool> value
)
: value(value) {}

public:
std::variant<std::string, std::filesystem::path, int32_t, uint32_t, bool> value;
std::variant<std::string, std::filesystem::path, int32_t, uint32_t, uint16_t, bool> value;

static ConfigValue fromString(const std::string& value) { return ConfigValue{value}; }

static ConfigValue fromPath(const std::filesystem::path& value) { return ConfigValue{value}; }

static ConfigValue fromInt32(int32_t value) { return ConfigValue{value}; }

static ConfigValue fromUint32(uint32_t value) { return ConfigValue{value}; }

static ConfigValue fromUint16(uint16_t value) { return ConfigValue{value}; }

static ConfigValue fromBool(bool value) { return ConfigValue{value}; }

ConfigValueType getValueType() const {
return std::visit(
Expand Down Expand Up @@ -94,31 +115,55 @@ class ConfigValue {
};

class ConfigValueSpecification {
ConfigValueSpecification() = default;

public:
ConfigKeyPath key;
ConfigValueType type;
std::optional<ConfigValue> default_value;
/// Help as shown for --help, excluding the other info above.
/// If type is bool, the command line option does not take an argument but
/// is the constant "true", which will be added to the help text
std::string_view help_text;

/// If true, the command line option does not take an argument but
/// is the constant "true".
[[nodiscard]] bool isBool() const;

ConfigValue getValueFromString(std::string value_string) const;

ConfigValue createValue(
std::variant<std::string, std::filesystem::path, int32_t, uint32_t, uint16_t, bool> value
) const;

static ConfigValueSpecification createWithoutDefault(
ConfigKeyPath key,
ConfigValueType value_type,
std::string_view help_text
){
ConfigValueSpecification value_specification;
value_specification.key = key;
value_specification.type = value_type;
value_specification.help_text = help_text;
return value_specification;
}

/// No need for the value_type. It is implicitly defined by the default. Prevents misspecification.
static ConfigValueSpecification createWithDefault(
ConfigKeyPath key,
ConfigValue default_value,
std::string_view help_text
){
ConfigValueSpecification value_specification;
value_specification.key = key;
value_specification.type = default_value.getValueType();
value_specification.default_value = default_value;
value_specification.help_text = help_text;
return value_specification;
}
};

} // namespace silo::config

namespace std {
template <>
struct hash<silo::config::ConfigKeyPath> {
std::size_t operator()(const silo::config::ConfigKeyPath& key) const {
std::size_t seed = 0; // Initialize seed for the hash
for (const auto& segment : key.path) {
boost::hash_combine(seed, segment); // Combine each segment's hash
}
return seed; // Return the final combined hash
}
std::size_t operator()(const silo::config::ConfigKeyPath& key) const;
};
} // namespace std
4 changes: 1 addition & 3 deletions include/config/overwrite_from_interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,7 @@ class OverwriteFrom {
/// .to_vec_reverse() and wrap in ConfigKeyPath). Throws
/// `silo::config::ConfigException` for config value parse errors
/// (subclass as ConfigValueParseError?).
virtual void overwriteFrom(
const VerifiedConfigSource& config_source
) = 0;
virtual void overwriteFrom(const VerifiedConfigSource& config_source) = 0;

virtual ~OverwriteFrom() = default;
};
Expand Down
2 changes: 1 addition & 1 deletion include/config/source/environment_variables.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class EnvironmentVariables : public RawConfigSource {

static std::string configKeyPathToString(const ConfigKeyPath& key_path);

static ConfigKeyPath stringToConfigKeyPath(const std::string& key_path_string);
static ConfigKeyPath stringToConfigKeyPath(const std::string& key_path_string); // TODO check whether AmbiguousKeyPath can be used
};

} // namespace silo::config
46 changes: 1 addition & 45 deletions include/config/toplevel_interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,6 @@

#include "config/config_metadata.h"
#include "config/overwrite_from_interface.h"
#include "config/source/command_line_arguments.h"
#include "config/source/environment_variables.h"
#include "config/source/yaml_file.h"
#include "silo/common/cons_list.h"
#include "silo/common/overloaded.h"

Expand All @@ -30,48 +27,7 @@ template <typename C /* : Default + OverwriteFrom + ToplevelConfig + Debug */>
std::optional<C> rawGetConfig(
std::span<const std::string> cmd,
const ConfigSpecification& config_specification
) {
auto env_source =
EnvironmentVariables::decodeEnvironmentVariables().verify(config_specification);
auto cmd_source = CommandLineArguments{cmd}.verify(config_specification);

const ConsList<std::string> no_parents{};

C config;

// First, only check command line arguments, for "--help"; avoid
// potential errors from env processing, and we don't have the
// path to the config file yet. Since we're only interested in the
// help option, there's no need to read config_struct first, OK?
config = {};
config.overwriteFrom(no_parents, cmd_source);
if (config.asksForHelp()) {
return std::nullopt;
}

// Then process env and cmd, to get to the config file
// path. Re-initialize since env must be processed for cmd.
config = {};
config.overwriteFrom(no_parents, env_source);
config.overwriteFrom(no_parents, cmd_source);
// Would anyone request help via SILO_ENV=true? Well, allow it:
if (config.asksForHelp()) {
return std::nullopt;
}

auto config_path = config.configPath();
if (config_path.has_value()) {
auto file_source = YamlFile::readFile(*config_path).verify(config_specification);
// Now read again with the file first:
config = {};
config.overwriteFrom(no_parents, file_source);
config.overwriteFrom(no_parents, env_source);
config.overwriteFrom(no_parents, cmd_source);
// (The config file might specify --help, too, but we ignore
// that.)
}
return std::optional{config};
}
);

/// In case of error, returns the exit code that the caller should
/// pass to exit(): 0 if the user gave --help, 1 in case of erroneous
Expand Down
15 changes: 15 additions & 0 deletions include/silo/common/fmt_formatters.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

#include <fmt/format.h>
#include <chrono>
#include <nlohmann/json.hpp>

template <typename T>
struct [[maybe_unused]] fmt::formatter<std::optional<T>> : fmt::formatter<std::string> {
Expand Down Expand Up @@ -43,3 +44,17 @@ struct [[maybe_unused]] fmt::formatter<
return fmt::format_to(ctx.out(), "{}", silo::common::toIsoString(val));
}
};

namespace fmt {

template <>
struct formatter<nlohmann::json> {
constexpr auto parse(format_parse_context& ctx) -> decltype(ctx.begin()) { return ctx.end(); }

template <typename FormatContext>
auto format(const nlohmann::json& json, FormatContext& ctx) -> decltype(ctx.out()) {
return fmt::format_to(ctx.out(), "{}", json.dump());
}
};

} // namespace fmt
Loading

0 comments on commit cd7cf31

Please sign in to comment.