config.hpp
1 
6 #pragma once
7 
8 #include <any>
9 #include <cstddef>
10 #include <cstdint>
11 #include <functional>
12 #include <memory>
13 #include <mutex>
14 #include <stdexcept>
15 #include <string>
16 #include <string_view>
17 #include <unordered_map>
18 
19 #include <rapidsmpf/config_defaults.hpp>
20 #include <rapidsmpf/error.hpp>
21 #include <rapidsmpf/utils/string.hpp>
22 
23 namespace rapidsmpf::config {
24 
36 template <typename T>
37 using OptionFactory = std::function<T(std::string const&)>;
38 
45 class OptionValue {
46  public:
52  OptionValue() = default;
53 
59  OptionValue(std::string value_as_string)
60  : value_as_string_{std::move(value_as_string)} {}
61 
72  template <typename T>
73  explicit OptionValue(T value)
74  requires(!std::is_convertible_v<T, std::string_view>)
75  : value_{std::make_any<T>(std::move(value))} {}
76 
82  [[nodiscard]] std::any const& get_value() const {
83  return value_;
84  }
85 
93  [[nodiscard]] std::string const& get_value_as_string() const {
94  return value_as_string_;
95  }
96 
104  void set_value(std::any value) {
105  RAPIDSMPF_EXPECTS(
106  !value_.has_value(), "value already set", std::invalid_argument
107  );
108  value_ = std::move(value);
109  }
110 
111  private:
112  std::any value_{};
113  std::string value_as_string_{};
114  // TODO: add a collective policy.
115 };
116 
117 namespace detail {
118 
127  mutable std::mutex mutex;
128  std::unordered_map<std::string, OptionValue> options;
129 };
130 } // namespace detail
131 
144 class Options {
145  public:
153  Options(std::unordered_map<std::string, OptionValue> options = {});
154 
155 
163  Options(std::unordered_map<std::string, std::string> options_as_strings);
164 
178  bool insert_if_absent(std::string const& key, std::string_view option_as_string);
179 
190  std::size_t insert_if_absent(
191  std::unordered_map<std::string, std::string> options_as_strings
192  );
193 
218  template <typename T>
219  bool insert_if_absent(std::string const& key, T value)
220  requires(!std::is_convertible_v<T, std::string_view>)
221  {
222  std::lock_guard<std::mutex> lock(shared_->mutex);
223  auto [_, inserted] = shared_->options.try_emplace(
224  to_lower(trim(key)), OptionValue{std::move(value)}
225  );
226  return inserted;
227  }
228 
248  template <typename T>
249  T const& get(std::string const& key, OptionFactory<T> factory) {
250  auto& shared = *shared_;
251  std::lock_guard<std::mutex> lock(shared.mutex);
252  auto& option = shared.options[key];
253  if (!option.get_value().has_value()) {
254  // If the user did not supply a value and `DEFAULTS` contains one
255  // for `key`, pass that default to the factory. Otherwise, pass
256  // the empty string to the factory parser.
257  std::string const& stored = option.get_value_as_string();
258  auto it = DEFAULTS.find(key);
259  std::string const& effective =
260  (stored.empty() && it != DEFAULTS.end()) ? it->second : stored;
261  option.set_value(std::make_any<T>(factory(effective)));
262  }
263  try {
264  return std::any_cast<T const&>(option.get_value());
265  } catch (const std::bad_any_cast&) {
266  RAPIDSMPF_FAIL(
267  "accessing option with incompatible template type", std::invalid_argument
268  );
269  }
270  }
271 
284  [[nodiscard]] std::unordered_map<std::string, std::string> get_strings() const;
285 
286 
322  [[nodiscard]] std::vector<std::uint8_t> serialize() const;
323 
335  [[nodiscard]] static Options deserialize(std::vector<std::uint8_t> const& buffer);
336 
337  private:
338  std::shared_ptr<detail::SharedOptions> shared_;
339 };
340 
370  std::unordered_map<std::string, std::string>& output,
371  std::string const& key_regex = "RAPIDSMPF_(.*)"
372 );
373 
390 std::unordered_map<std::string, std::string> get_environment_variables(
391  std::string const& key_regex = "RAPIDSMPF_(.*)"
392 );
393 
394 } // namespace rapidsmpf::config
Configuration option value.
Definition: config.hpp:45
OptionValue(std::string value_as_string)
Constructs OptionValue from a string representation.
Definition: config.hpp:59
std::any const & get_value() const
Retrieves the stored value.
Definition: config.hpp:82
std::string const & get_value_as_string() const
Retrieves the string representation of the value.
Definition: config.hpp:93
OptionValue()=default
Default constructor.
void set_value(std::any value)
Sets the value if it has not been set already.
Definition: config.hpp:104
OptionValue(T value) requires(!std
Constructs OptionValue from a typed value.
Definition: config.hpp:73
Manages configuration options for RapidsMPF operations.
Definition: config.hpp:144
bool insert_if_absent(std::string const &key, T value) requires(!std
Inserts an option only if it is not already present.
Definition: config.hpp:219
static Options deserialize(std::vector< std::uint8_t > const &buffer)
Deserializes a binary buffer into an Options object.
T const & get(std::string const &key, OptionFactory< T > factory)
Retrieves a configuration option by key.
Definition: config.hpp:249
std::vector< std::uint8_t > serialize() const
Serializes the options into a binary buffer.
Options(std::unordered_map< std::string, OptionValue > options={})
Constructs an Options instance from option values.
std::unordered_map< std::string, std::string > get_strings() const
Retrieves all option values as strings.
Options(std::unordered_map< std::string, std::string > options_as_strings)
Constructs an Options instance from option values as strings.
std::size_t insert_if_absent(std::unordered_map< std::string, std::string > options_as_strings)
Inserts multiple options if they are not already present.
bool insert_if_absent(std::string const &key, std::string_view option_as_string)
Inserts an option only if it is not already present.
const std::unordered_map< std::string, std::string > DEFAULTS
String-form default values for config options.
std::function< T(std::string const &)> OptionFactory
Type alias for a factory function that constructs options from strings.
Definition: config.hpp:37
void get_environment_variables(std::unordered_map< std::string, std::string > &output, std::string const &key_regex="RAPIDSMPF_(.*)")
Populates a map with environment variables matching a given regular expression.
std::string to_lower(std::string_view text)
Converts the specified string to lowercase.
std::string trim(std::string_view text)
Trims whitespace from both ends of the specified string.
Internal shared collection for the Options class.
Definition: config.hpp:126
std::mutex mutex
Shared mutex, must be use to guard options.
Definition: config.hpp:127
std::unordered_map< std::string, OptionValue > options
Shared options.
Definition: config.hpp:128