Uni20
Asynchronous tensor and runtime library.
Loading...
Searching...
No Matches
common/configuration.hpp
Go to the documentation of this file.
1
5#pragma once
6#include "metadata.hpp"
7#include <algorithm>
8#include <cstdlib>
9#include <exception>
10#include <functional>
11#include <map>
12#include <memory>
13#include <optional>
14#include <set>
15#include <stdexcept>
16#include <string>
17#include <utility>
18#include <vector>
19
20namespace uni20
21{
22namespace cli
23{
24class configuration;
25}
26using attribute_map = std::map<std::string, metadata_value>;
27
31template <typename T>
34 !presentation::data_table_detail::runtime_real<presentation::data_table_detail::value_type<T>>;
35
41
44 public:
45 configuration_binding& attribute(std::string repository, std::string key)
46 {
47 attribute_ = std::pair{std::move(repository), std::move(key)};
48 return *this;
49 }
51 {
52 environment_ = std::move(name);
53 return *this;
54 }
55 configuration_binding& file(std::string key)
56 {
57 file_ = std::move(key);
58 return *this;
59 }
61 {
62 required_ = value;
63 return *this;
64 }
67 {
68 default_.reset();
69 return *this;
70 }
72 {
73 metadata_ = std::move(options);
74 return *this;
75 }
77 template <presentation::DataTableValue T, typename F> configuration_binding& check(F&& check)
78 {
79 checks_.push_back([fn = std::forward<F>(check)](metadata_value const& v) { fn(v.get<T>()); });
80 return *this;
81 }
82 [[nodiscard]] std::string const& id() const { return id_; }
83 [[nodiscard]] std::optional<std::string> const& file_key() const { return file_; }
84
85 private:
86 friend class configuration;
87 friend class cli::configuration;
88 std::string id_;
89 std::optional<metadata_value> default_;
90 std::optional<std::pair<std::string, std::string>> attribute_;
91 std::optional<std::string> environment_;
92 std::optional<std::string> file_;
93 bool required_ = false;
94 metadata_field_options metadata_;
95 std::function<metadata_value(metadata_value const&, value_origin const&)> convert_;
96 std::vector<std::function<void(metadata_value const&)>> checks_;
97};
98
104 public:
105 using environment_reader = std::function<std::optional<std::string>(std::string const&)>;
106 explicit configuration(environment_reader reader = [](std::string const& name) -> std::optional<std::string> {
107 if (auto p = std::getenv(name.c_str())) return std::string(p);
108 return std::nullopt;
109 })
110 : environment_(std::move(reader))
111 {}
112
113 template <ConfigurationValue T> configuration_binding& add(std::string id, T initial)
114 {
115 auto& binding = this->add<T>(std::move(id));
116 binding.default_ = metadata_value(std::move(initial));
117 return binding;
118 }
119 template <ConfigurationValue T> configuration_binding& add(std::string id)
120 {
121 metadata_detail::dt::validate_identifier(id);
122 if (bindings_.contains(id)) throw std::invalid_argument("duplicate configuration field: " + id);
123 auto binding = std::make_unique<configuration_binding>();
124 binding->id_ = id;
125 binding->convert_ = [](metadata_value const& value, value_origin const&) {
126 return metadata_value(value.as<T>());
127 };
128 auto* result = binding.get();
129 bindings_.emplace(id, std::move(binding));
130 order_.push_back(std::move(id));
131 return *result;
132 }
133
134 void set(std::string const& id, metadata_value value)
135 {
136 (void)this->binding(id);
137 explicit_.insert_or_assign(id, std::move(value));
138 cli_.erase(id);
139 }
140 void attributes(std::string repository, attribute_map values)
141 {
142 attributes_.insert_or_assign(std::move(repository), std::move(values));
143 }
144
146 void option_file(std::string path, attribute_map values)
147 {
148 for (auto const& [key, value] : values)
149 {
150 auto count = std::ranges::count_if(bindings_, [&](auto const& item) { return item.second->file_ == key; });
151 if (count != 1) throw std::invalid_argument("unknown or ambiguous option-file key: " + key);
152 }
153 file_path_ = std::move(path);
154 file_ = std::move(values);
155 }
156 [[nodiscard]] configuration_binding const& binding(std::string const& id) const
157 {
158 auto found = bindings_.find(id);
159 if (found == bindings_.end()) throw std::invalid_argument("unknown configuration field: " + id);
160 return *found->second;
161 }
162 [[nodiscard]] configuration_binding& binding(std::string const& id)
163 {
164 return const_cast<configuration_binding&>(std::as_const(*this).binding(id));
165 }
166 [[nodiscard]] std::optional<resolved_value> resolve(std::string const& id) const
167 {
168 auto const& b = this->binding(id);
169 std::optional<resolved_value> selected;
170 auto take = [&](attribute_map const& map, std::string const& key, value_origin origin) {
171 if (selected) return;
172 if (auto it = map.find(key); it != map.end()) selected.emplace(it->second, std::move(origin));
173 };
174 take(explicit_, id,
176 if (b.file_) take(file_, *b.file_, {configuration_source::option_file, file_path_, *b.file_});
177 if (b.attribute_)
178 {
179 auto const& [repository, key] = *b.attribute_;
180 if (auto it = attributes_.find(repository); it != attributes_.end())
181 take(it->second, key, {configuration_source::attribute, repository, key});
182 }
183 if (!selected && b.environment_)
184 if (auto value = environment_(*b.environment_))
185 selected.emplace(metadata_value(std::move(*value)),
186 value_origin{configuration_source::environment, {}, *b.environment_});
187 if (!selected && b.default_)
188 selected.emplace(*b.default_, value_origin{configuration_source::application_default, {}, id});
189 if (!selected)
190 {
191 if (b.required_) throw std::invalid_argument("missing required configuration field: " + id);
192 return std::nullopt;
193 }
194 try
195 {
196 selected->value = b.convert_(selected->value, selected->origin);
197 for (auto const& check : b.checks_)
198 check(selected->value);
199 }
200 catch (std::exception const& e)
201 {
202 throw std::invalid_argument("configuration field '" + id + "' from " +
203 std::string(to_string(selected->origin.source)) + " '" + selected->origin.location +
204 "' key '" + selected->origin.key + "': " + e.what());
205 }
206 return selected;
207 }
209 template <ConfigurationValue T> [[nodiscard]] T get(std::string const& id) const
210 {
211 auto result = this->resolve(id);
212 if (!result) throw std::invalid_argument("configuration field has no value: " + id);
213 return result->value.as<T>();
214 }
215 [[nodiscard]] metadata_document snapshot(std::string group = "configuration") const
216 {
217 metadata_document document;
218 document.group(group, "Configuration");
219 for (auto const& id : order_)
220 if (auto value = this->resolve(id))
221 {
222 auto options = this->binding(id).metadata_;
223 options.origin = value->origin;
224 document.add(group, id, std::move(value->value), std::move(options));
225 }
226 return document;
227 }
229 void copy_attributes(attribute_map& output, std::map<std::string, std::string> const& keys) const
230 {
231 attribute_map additions;
232 for (auto const& [id, key] : keys)
233 {
234 auto value = this->resolve(id);
235 if (!value) throw std::invalid_argument("no value for output attribute: " + id);
236 if (!additions.emplace(key, std::move(value->value)).second)
237 throw std::invalid_argument("duplicate output attribute: " + key);
238 }
239 for (auto& [key, value] : additions)
240 output.insert_or_assign(key, std::move(value));
241 }
242
243 private:
244 friend class cli::configuration;
245 environment_reader environment_;
246 std::map<std::string, std::unique_ptr<configuration_binding>> bindings_;
247 std::vector<std::string> order_;
248 attribute_map explicit_;
249 std::set<std::string> cli_;
250 attribute_map file_;
251 std::string file_path_;
252 std::map<std::string, attribute_map> attributes_;
253};
254} // namespace uni20
Collect CLI input first, then resolve declared fallback sources after loading input attributes.
Definition cli/configuration.hpp:25
A single declared scalar, with application-selected fallback sources.
Definition common/configuration.hpp:43
configuration_binding & metadata(metadata_field_options options)
Definition common/configuration.hpp:71
configuration_binding & attribute(std::string repository, std::string key)
Definition common/configuration.hpp:45
configuration_binding & required(bool value=true)
Definition common/configuration.hpp:60
configuration_binding & file(std::string key)
Definition common/configuration.hpp:55
configuration_binding & environment(std::string name)
Definition common/configuration.hpp:50
configuration_binding & check(F &&check)
Validate the final native value, after source selection and conversion.
Definition common/configuration.hpp:77
std::optional< std::string > const & file_key() const
Definition common/configuration.hpp:83
std::string const & id() const
Definition common/configuration.hpp:82
configuration_binding & without_default()
Require an actual source instead of treating the initialized variable as a fallback.
Definition common/configuration.hpp:66
Parser-independent configuration with CLI/API > file > attribute > environment > default precedence.
Definition common/configuration.hpp:103
std::optional< resolved_value > resolve(std::string const &id) const
Definition common/configuration.hpp:166
metadata_document snapshot(std::string group="configuration") const
Definition common/configuration.hpp:215
void set(std::string const &id, metadata_value value)
Definition common/configuration.hpp:134
void attributes(std::string repository, attribute_map values)
Definition common/configuration.hpp:140
configuration_binding & add(std::string id)
Definition common/configuration.hpp:119
configuration_binding & add(std::string id, T initial)
Definition common/configuration.hpp:113
std::function< std::optional< std::string >(std::string const &)> environment_reader
Definition common/configuration.hpp:105
void copy_attributes(attribute_map &output, std::map< std::string, std::string > const &keys) const
Copy only explicitly selected resolved fields to output-object attributes.
Definition common/configuration.hpp:229
T get(std::string const &id) const
Resolve and convert a value without choosing a runtime precision.
Definition common/configuration.hpp:209
configuration(environment_reader reader=[](std::string const &name) -> std::optional< std::string > { if(auto p=std::getenv(name.c_str())) return std::string(p);return std::nullopt;})
Definition common/configuration.hpp:106
configuration_binding const & binding(std::string const &id) const
Definition common/configuration.hpp:156
configuration_binding & binding(std::string const &id)
Definition common/configuration.hpp:162
void option_file(std::string path, attribute_map values)
Supply one already parsed option file; reject undeclared or ambiguous keys before use.
Definition common/configuration.hpp:146
Ordered, uniquely identified metadata. Copies are independent snapshots.
Definition metadata.hpp:306
void group(std::string id, std::string label={})
Definition metadata.hpp:308
void add(std::string const &group, std::string id, metadata_value value, metadata_field_options options={})
Definition metadata.hpp:316
An immutable owned value that retains its native scalar and optional type.
Definition metadata.hpp:66
T const & get() const
Access the exact declared type; a mismatch throws std::bad_any_cast.
Definition metadata.hpp:82
Binding values whose textual conversion needs no runtime precision choice.
Definition common/configuration.hpp:32
Types retained directly by data tables, without numerical narrowing or text conversion.
Definition data_table.hpp:189
locale_t value
Definition data_table.cpp:49
Owned native scalar metadata, independent of parsers and output streams.
Definition qnum.hpp:403
void check(cublasStatus_t status, std::string_view operation, int device, std::source_location where)
Raise unless a cuBLAS call returned CUBLAS_STATUS_SUCCESS.
Definition cublas_error.cpp:52
Definition data_table.cpp:8
Definition async/async.hpp:26
std::map< std::string, metadata_value > attribute_map
Definition common/configuration.hpp:26
auto to_string(basic_half_int< T > value) -> std::string
Format a half-integer as an integer or decimal .5.
Definition half_int.hpp:477
Definition metadata.hpp:282
Definition common/configuration.hpp:37
metadata_value value
Definition common/configuration.hpp:38
value_origin origin
Definition common/configuration.hpp:39
Identifies the winning source, without retaining discarded candidates.
Definition metadata.hpp:275