config.hpp
1 
6 #pragma once
7 
8 #include <any>
9 #include <functional>
10 #include <memory>
11 #include <mutex>
12 #include <stdexcept>
13 #include <string>
14 #include <unordered_map>
15 
16 #include <rapidsmpf/error.hpp>
17 #include <rapidsmpf/utils/string.hpp>
18 
19 namespace rapidsmpf::config {
20 
32 template <typename T>
33 using OptionFactory = std::function<T(std::string const&)>;
34 
41 class OptionValue {
42  public:
48  OptionValue() = default;
49 
55  OptionValue(std::string value_as_string)
56  : value_as_string_{std::move(value_as_string)} {}
57 
68  template <typename T>
69  explicit OptionValue(T value)
70  requires(!std::is_convertible_v<T, std::string_view>)
71  : value_{std::make_any<T>(std::move(value))} {}
72 
78  [[nodiscard]] std::any const& get_value() const {
79  return value_;
80  }
81 
89  [[nodiscard]] std::string const& get_value_as_string() const {
90  return value_as_string_;
91  }
92 
100  void set_value(std::any value) {
101  RAPIDSMPF_EXPECTS(
102  !value_.has_value(), "value already set", std::invalid_argument
103  );
104  value_ = std::move(value);
105  }
106 
107  private:
108  std::any value_{};
109  std::string value_as_string_{};
110  // TODO: add a collective policy.
111 };
112 
113 namespace detail {
114 
123  mutable std::mutex mutex;
124  std::unordered_map<std::string, OptionValue> options;
125 };
126 } // namespace detail
127 
140 class Options {
141  public:
149  Options(std::unordered_map<std::string, OptionValue> options = {});
150 
151 
159  Options(std::unordered_map<std::string, std::string> options_as_strings);
160 
174  bool insert_if_absent(std::string const& key, std::string_view option_as_string);
175 
186  std::size_t insert_if_absent(
187  std::unordered_map<std::string, std::string> options_as_strings
188  );
189 
214  template <typename T>
215  bool insert_if_absent(std::string const& key, T value)
216  requires(!std::is_convertible_v<T, std::string_view>)
217  {
218  std::lock_guard<std::mutex> lock(shared_->mutex);
219  auto [_, inserted] = shared_->options.try_emplace(
220  to_lower(trim(key)), OptionValue{std::move(value)}
221  );
222  return inserted;
223  }
224 
244  template <typename T>
245  T const& get(std::string const& key, OptionFactory<T> factory) {
246  auto& shared = *shared_;
247  std::lock_guard<std::mutex> lock(shared.mutex);
248  auto& option = shared.options[key];
249  if (!option.get_value().has_value()) {
250  option.set_value(std::make_any<T>(factory(option.get_value_as_string())));
251  }
252  try {
253  return std::any_cast<T const&>(option.get_value());
254  } catch (const std::bad_any_cast&) {
255  RAPIDSMPF_FAIL(
256  "accessing option with incompatible template type", std::invalid_argument
257  );
258  }
259  }
260 
273  [[nodiscard]] std::unordered_map<std::string, std::string> get_strings() const;
274 
275 
311  [[nodiscard]] std::vector<std::uint8_t> serialize() const;
312 
324  [[nodiscard]] static Options deserialize(std::vector<std::uint8_t> const& buffer);
325 
326  private:
327  std::shared_ptr<detail::SharedOptions> shared_;
328 };
329 
359  std::unordered_map<std::string, std::string>& output,
360  std::string const& key_regex = "RAPIDSMPF_(.*)"
361 );
362 
379 std::unordered_map<std::string, std::string> get_environment_variables(
380  std::string const& key_regex = "RAPIDSMPF_(.*)"
381 );
382 
383 } // namespace rapidsmpf::config
Configuration option value.
Definition: config.hpp:41
OptionValue(std::string value_as_string)
Constructs OptionValue from a string representation.
Definition: config.hpp:55
std::any const & get_value() const
Retrieves the stored value.
Definition: config.hpp:78
std::string const & get_value_as_string() const
Retrieves the string representation of the value.
Definition: config.hpp:89
OptionValue()=default
Default constructor.
void set_value(std::any value)
Sets the value if it has not been set already.
Definition: config.hpp:100
OptionValue(T value) requires(!std
Constructs OptionValue from a typed value.
Definition: config.hpp:69
Manages configuration options for RapidsMPF operations.
Definition: config.hpp:140
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:215
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:245
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.
std::function< T(std::string const &)> OptionFactory
Type alias for a factory function that constructs options from strings.
Definition: config.hpp:33
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:122
std::mutex mutex
Shared mutex, must be use to guard options.
Definition: config.hpp:123
std::unordered_map< std::string, OptionValue > options
Shared options.
Definition: config.hpp:124