Shamrock 2025.10.0
Astrophysical Code
Loading...
Searching...
No Matches
ImplVariant.hpp
Go to the documentation of this file.
1// -------------------------------------------------------//
2//
3// SHAMROCK code for hydrodynamics
4// Copyright (c) 2021-2026 Timothée David--Cléris <tim.shamrock@proton.me>
5// SPDX-License-Identifier: CeCILL Free Software License Agreement v2.1
6// Shamrock is licensed under the CeCILL 2.1 License, see LICENSE for more information
7//
8// -------------------------------------------------------//
9
10#pragma once
11
37
41#include <fmt/ranges.h>
42#include <nlohmann/json.hpp>
43#include <string_view>
44#include <concepts>
45#include <functional>
46#include <optional>
47#include <string>
48#include <utility>
49#include <variant>
50#include <vector>
51
52namespace shamalgs {
53
83 template<class Alt>
86 static inline nlohmann::json to_json(const Alt &) { return nlohmann::json::object(); }
88 static inline Alt from_json(const nlohmann::json &) { return Alt{}; }
89 };
90
110 template<class Alt>
111 concept HasCustomDefaults = requires {
112 { Alt::variant_custom_defaults() } -> std::convertible_to<std::vector<Alt>>;
113 };
114
115 // Forward declaration: defined below, needed by impl_variant_alts::default_config_list()
116 template<class Variant>
117 inline std::string variant_to_config_string(const Variant &v);
118
119 namespace details {
122 template<class Alt>
123 inline std::vector<Alt> alt_default_list() {
124 if constexpr (HasCustomDefaults<Alt>) {
125 return Alt::variant_custom_defaults();
126 } else {
127 return {Alt{}};
128 }
129 }
130
132 template<class Variant>
134
135 template<class... Alts>
136 struct impl_variant_alts<std::variant<Alts...>> {
137 static inline std::vector<std::string> default_type_names() {
138 return {std::string(Alts::variant_type_name)...};
139 }
140
144 static inline std::vector<std::string> default_config_list() {
145 std::vector<std::string> out;
146 auto add_alt = [&]<class Alt>() {
147 for (auto &alt : alt_default_list<Alt>()) {
148 out.push_back(
149 variant_to_config_string<std::variant<Alts...>>(
150 std::variant<Alts...>{std::move(alt)}));
151 }
152 };
153 (add_alt.template operator()<Alts>(), ...);
154 return out;
155 }
156
157 static inline std::variant<Alts...> from_config_string(std::string_view s) {
158 nlohmann::json j = nlohmann::json::parse(s);
159 std::string name = j.at("implementation").get<std::string>();
160 nlohmann::json params = j.value("parameters", nlohmann::json::object());
161
162 std::optional<std::variant<Alts...>> result;
163 (void) ((name == Alts::variant_type_name
164 ? (result
165 = std::variant<Alts...>{ImplVariantParams<Alts>::from_json(params)},
166 true)
167 : false)
168 || ...);
169
170 if (!result) {
172 "invalid implementation : {}, possible implementations : {}",
173 name,
174 default_type_names()));
175 }
176 return *result;
177 }
178 };
179 } // namespace details
180
182 template<class Variant>
183 inline std::string variant_to_config_string(const Variant &v) {
184 return std::visit(
185 [](const auto &alt) {
186 using Alt = std::decay_t<decltype(alt)>;
187 nlohmann::json j;
188 j["implementation"] = std::string(Alt::variant_type_name);
189 j["parameters"] = ImplVariantParams<Alt>::to_json(alt);
190 return j.dump();
191 },
192 v);
193 }
194
196 template<class Variant>
197 inline Variant variant_from_config_string(std::string_view s) {
199 }
200
202 template<class Variant>
203 inline std::vector<std::string> variant_default_type_names() {
205 }
206
212 public:
213 virtual ~IImplVariant() = default;
214
217 virtual std::string get_current_config() const = 0;
218
220 virtual std::vector<std::string> get_default_config_list() const = 0;
221
223 virtual void set(std::string_view config_json) = 0;
224
226 virtual bool is_set() const = 0;
227
229 virtual void autoselect(const sham::DeviceScheduler_ptr &sched) = 0;
230 };
231
264 template<class... Alts>
266 public:
267 using Variant = std::variant<Alts...>;
268
271 = std::function<void(const sham::DeviceScheduler_ptr &, ImplVariantGlobal &)>;
272
274 explicit ImplVariantGlobal(AutoselectFn fn) : autoselect_fn(std::move(fn)) {}
275
277 inline bool is_set() const override { return current.has_value(); }
278
279 /// Select the algorithm's default implementation for the device behind `sched`
280 inline void autoselect(const sham::DeviceScheduler_ptr &sched) override {
281 autoselect_fn(sched, *this);
282 }
283
285 inline const Variant &get() const { return *current; }
286
288 /// null if no implementation has been selected yet (see is_set())
289 inline std::string get_current_config() const override {
290 if (!is_set()) {
291 return nlohmann::json(nullptr).dump();
292 }
294 }
295
298 /// contribute one entry per instance in their variant_custom_defaults() list.
299 inline std::vector<std::string> get_default_config_list() const override {
301 }
302
304 inline void set(Variant v) { current = std::move(v); }
305
306 /// Select an implementation from a {"implementation": ..., "parameters": ...} json string
307 inline void set(std::string_view config_json) override {
308 current = variant_from_config_string<Variant>(config_json);
309 }
310
311 private:
312 std::optional<Variant> current;
313 AutoselectFn autoselect_fn;
314 };
315
316} // namespace shamalgs
std::vector< Alt > alt_default_list()
Non-template virtual interface exposed by ImplVariantGlobal, for code that needs to hold or pass arou...
virtual std::vector< std::string > get_default_config_list() const =0
List the available implementations as config json strings, one per alternative.
virtual void autoselect(const sham::DeviceScheduler_ptr &sched)=0
Select the algorithm's default implementation for the device behind sched.
virtual bool is_set() const =0
Whether an implementation has been selected yet.
virtual void set(std::string_view config_json)=0
Select an implementation from a {"implementation": ..., "parameters": ...} json string.
virtual std::string get_current_config() const =0
std::vector< std::string > get_default_config_list() const override
void autoselect(const sham::DeviceScheduler_ptr &sched) override
Select the algorithm's default implementation for the device behind sched.
void set(Variant v)
Directly select an alternative (e.g. to seed a default at the call site).
ImplVariantGlobal(AutoselectFn fn)
Construct an unset selector, whose default implementation is picked by fn.
bool is_set() const override
Whether an implementation has been selected yet.
std::string get_current_config() const override
const Variant & get() const
Get the currently selected implementation. Requires is_set().
std::function< void(const sham::DeviceScheduler_ptr &, ImplVariantGlobal &)> AutoselectFn
Callable selecting the default implementation, by calling set() on the selector.
Detects whether Alt opts into exposing more than one default instance of itself (e....
This header file contains utility functions related to exception handling in the code.
Core formatting functions: format, vformat, and format_printf.
Namespace for internal details of the logs module.
namespace to contain everything implemented by shamalgs
Definition algorithm.hpp:21
std::string variant_to_config_string(const Variant &v)
Serialize the currently active alternative of a variant to a single config json string.
std::vector< std::string > variant_default_type_names()
List the variant_type_name of every alternative of a variant, with no params.
Variant variant_from_config_string(std::string_view s)
Parse a variant back from a config string produced by variant_to_config_string.
ExcptTypes make_except_with_loc(std::string message, SourceLocation loc=SourceLocation{})
Create an exception with a message and a location.
Customization point controlling how an alternative's fields (if any) are serialized to / parsed from ...
static Alt from_json(const nlohmann::json &)
Parse the alternative's fields back (default: no fields, ignored).
static nlohmann::json to_json(const Alt &)
Serialize the alternative's fields (default: no fields, empty object).
Partial specialization target: extracts the Alts... pack out of std::variant<Alts....