19#include <system_error>
32namespace metadata_detail
34namespace dt = presentation::data_table_detail;
38 if constexpr (std::same_as<T, std::string>)
39 return std::string(
text);
40 else if constexpr (std::same_as<T, bool>)
42 if (
text ==
"true" ||
text ==
"1")
return true;
43 if (
text ==
"false" ||
text ==
"0")
return false;
44 throw std::invalid_argument(
"expected true, false, 1 or 0");
46 else if constexpr (dt::integer<T>)
49 auto [end, error] = std::from_chars(
text.data(),
text.data() +
text.size(),
value);
50 if (error == std::errc::result_out_of_range)
throw std::out_of_range(
"integer out of range");
52 throw std::invalid_argument(
"expected a complete integer literal");
55 else if constexpr (dt::half_integer<T>)
56 return T::parse(
text);
58 return parse_real<T>(
text);
68 template <presentation::DataTableValue T>
74 [[nodiscard]] std::type_index
type()
const {
return storage_->type(); }
75 [[nodiscard]]
bool missing()
const {
return !storage_->scalar().has_value(); }
78 return storage_->text(format, machine);
82 template <
typename T> [[nodiscard]] T
const&
get()
const {
return std::any_cast<T const&>(storage_->value()); }
87 template <presentation::DataTableValue T> [[nodiscard]] T
as()
const
89 namespace dt = metadata_detail::dt;
90 if (
auto p = std::any_cast<T>(&storage_->value()))
return *
p;
93 if (this->
missing())
return std::nullopt;
94 return this->as<typename dt::optional_traits<T>::value_type>();
98 if (this->
missing())
throw std::invalid_argument(
"missing value for a non-optional field");
99 auto const& scalar = storage_->scalar();
100 if (
auto p = std::any_cast<T>(&scalar))
return *
p;
101 if constexpr (dt::runtime_real<T>)
102 throw std::invalid_argument(
"conversion to mpreal requires explicit Precision");
105 if (
auto p = std::any_cast<std::string>(&scalar))
return metadata_detail::parse<T>(*
p);
106 std::optional<T> result;
107 auto try_type = [&]<
typename U>() {
111 if (
auto p = std::any_cast<U>(&scalar))
117 if constexpr (dt::runtime_real<U>)
123 throw std::out_of_range(
"real conversion overflow");
133 throw std::out_of_range(
"real conversion overflow");
136 auto converted = dt::convert<T>(*
p);
137 result = std::move(converted);
140 [&]<
typename... U>(std::tuple<U...>*) {
141 (try_type.template operator()<U>(), ...);
143 std::tuple<
signed char,
unsigned char,
short,
unsigned short,
int,
unsigned int,
long,
unsigned long,
146#if UNI20_HAS_FLOAT128
147 try_type.template operator()<uni20::float128>();
150 try_type.template operator()<
mpreal>();
152 if (!result)
throw std::invalid_argument(
"incompatible metadata scalar types");
153 return std::move(*result);
163 template <presentation::DataTableValue T>
164 requires metadata_detail::dt::runtime_real<metadata_detail::dt::value_type<T>>
167 namespace dt = metadata_detail::dt;
170 if (this->
missing())
return std::nullopt;
171 return this->as<mpreal>(precision);
175 if (this->
missing())
throw std::invalid_argument(
"missing value for a non-optional field");
176 auto const& scalar = storage_->scalar();
177 if (
auto p = std::any_cast<mpreal>(&scalar))
return p->at(precision);
178 if (
auto p = std::any_cast<std::string>(&scalar))
return parse_real<mpreal>(*
p, precision);
179 std::optional<mpreal> result;
180 auto try_type = [&]<
typename U>() {
181 if constexpr (presentation::DataTableValue<U>)
182 if (
auto p = std::any_cast<U>(&scalar)) result.emplace(*
p, precision);
184 [&]<
typename... U>(std::tuple<U...>*) {
185 (try_type.template operator()<U>(), ...);
186 }(
static_cast<std::tuple<
signed char,
unsigned char,
short,
unsigned short,
int,
unsigned int,
long,
187 unsigned long,
long long,
unsigned long long,
float,
double,
long double>*>(
nullptr));
188#if UNI20_HAS_FLOAT128
189 try_type.template operator()<uni20::float128>();
191 if (!result)
throw std::invalid_argument(
"incompatible metadata scalar types");
192 return std::move(*result);
200 virtual ~interface() =
default;
201 virtual std::type_index type()
const = 0;
202 virtual std::any
const&
value()
const = 0;
203 virtual std::any
const& scalar()
const = 0;
206 template <
typename T>
struct model final : interface
208 explicit model(T value) : value_(
std::move(
value))
210 auto const& v = std::any_cast<T const&>(value_);
211 if constexpr (metadata_detail::dt::optional_traits<T>::optional)
213 if (v) this->set_scalar(*v);
218 std::type_index type()
const override {
return typeid(T); }
219 std::any
const&
value()
const override {
return value_; }
220 std::any
const& scalar()
const override {
return scalar_; }
223 return metadata_detail::dt::cell_text(std::any_cast<T const&>(value_), format, machine);
227 template <
typename V>
void set_scalar(V
const& value)
229 if constexpr (metadata_detail::dt::half_integer<V>)
230 scalar_ = basic_half_int<std::intmax_t>(value);
235 static std::string copy_text(
char const*
text)
237 if (!
text)
throw std::invalid_argument(
"null metadata text");
240 std::shared_ptr<interface const> storage_;
258 return "explicit input";
260 return "command line";
262 return "option file";
266 return "environment";
270 throw std::invalid_argument(
"invalid configuration source");
288 std::optional<value_origin>
origin = std::nullopt;
308 void group(std::string
id, std::string label = {})
310 metadata_detail::dt::validate_identifier(
id);
311 if (std::ranges::any_of(groups_, [&](
auto const& g) {
return g.id == id; }))
312 throw std::invalid_argument(
"duplicate metadata group: " +
id);
313 if (label.empty()) label = id;
314 groups_.push_back({std::move(
id), std::move(label)});
318 metadata_detail::dt::validate_identifier(
id);
319 if (this->
find(
id))
throw std::invalid_argument(
"duplicate metadata field: " +
id);
321 if (found == groups_.end())
throw std::invalid_argument(
"unknown metadata group: " +
group);
322 if (options.label.empty()) options.label = id;
323 found->fields.push_back({std::move(
id), std::move(
value), std::move(options)});
327 for (
auto&
group : groups_)
328 for (
auto& field :
group.fields)
331 if (field.value.type() !=
value.type())
throw std::invalid_argument(
"metadata replacement changes type");
332 field.value = std::move(
value);
335 throw std::invalid_argument(
"unknown metadata field: " +
id);
339 for (
auto const&
group : groups_)
340 for (
auto const& field :
group.fields)
341 if (field.id ==
id)
return &field;
344 [[nodiscard]] std::vector<metadata_group>
const&
groups()
const {
return groups_; }
348 auto combined = *
this;
352 for (
auto const& field :
group.fields)
353 combined.add(
group.id, field.id, field.value, field.options);
355 *
this = std::move(combined);
361 for (
auto const& [
id, key] : keys)
362 if (!this->
find(id)) throw
std::invalid_argument(
"unknown metadata export field: " + id);
364 for (
auto const&
group : groups_)
365 for (auto const& field :
group.fields)
367 auto key = keys.contains(field.id) ? keys.at(field.id) : field.id;
368 if (!result.emplace(key, field.value.text(field.options.display,
true)).second)
369 throw std::invalid_argument(
"duplicate metadata export key: " + key);
375 std::vector<metadata_group> groups_;
Exact arithmetic or an explicit binary working precision.
Definition core/precision.hpp:13
static constexpr Precision bits(bit_count_type count)
Select a positive binary significand size.
Definition core/precision.hpp:21
Signed value type that stores multiples of one half exactly.
Definition half_int.hpp:34
Owning exact rational or finite-precision MPFR real, with eager arithmetic.
Definition mpreal.hpp:74
bool empty() const noexcept
Return whether this document has no spans.
Definition presentation.cpp:1182
Concept for real scalar types (float, double, etc.).
Definition scalar_concepts.hpp:69
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
Typed result tables with deferred presentation and numerical export.
presentation::styled_text text
Definition display.cpp:141
constexpr bool isfinite(I const &x) noexcept
Returns whether an integer scalar is finite.
Definition math.hpp:121
Defines basic_half_int<T>, a signed integer type with half-integer resolution.
Scalar math helper utilities.
Definition display.cpp:16
Definition data_table.cpp:8
std::map< std::string, std::string > table_metadata
Application metadata is owned text, independent of numerical rows.
Definition data_table.hpp:314
Definition async/async.hpp:26
configuration_source
Definition metadata.hpp:244
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
Project-level numeric limits customization point.
Definition numeric_limits.hpp:16
Column display settings. These never change stored values or default export precision.
Definition data_table.hpp:198
Definition data_table.hpp:33
Identifies the winning source, without retaining discarded candidates.
Definition metadata.hpp:275
std::string location
Definition metadata.hpp:277
configuration_source source
Definition metadata.hpp:276
std::string key
Definition metadata.hpp:278