2020
2121#include < format>
2222#include < functional>
23- #include < map>
2423#include < string>
24+ #include < unordered_map>
2525
2626namespace iceberg {
2727
28+ // Default conversion functions
29+ template <typename U>
30+ std::string defaultToString (const U& val) {
31+ if constexpr ((std::is_signed_v<U> && std::is_integral_v<U>) ||
32+ std::is_floating_point_v<U>) {
33+ return std::to_string (val);
34+ } else if constexpr (std::is_same_v<U, bool >) {
35+ return val ? " true" : " false" ;
36+ } else if constexpr (std::is_same_v<U, std::string> ||
37+ std::is_same_v<U, std::string_view>) {
38+ return val;
39+ } else {
40+ throw std::runtime_error (
41+ std::format (" Explicit toStr() is required for {}" , typeid (U).name ()));
42+ }
43+ }
44+
45+ template <typename U>
46+ U defaultFromString (const std::string& val) {
47+ if constexpr (std::is_same_v<U, std::string>) {
48+ return val;
49+ } else if constexpr (std::is_same_v<U, bool >) {
50+ return val == " true" ;
51+ } else if constexpr (std::is_signed_v<U> && std::is_integral_v<U>) {
52+ return static_cast <U>(std::stoll (val));
53+ } else if constexpr (std::is_floating_point_v<U>) {
54+ return static_cast <U>(std::stod (val));
55+ } else {
56+ throw std::runtime_error (
57+ std::format (" Explicit toT() is required for {}" , typeid (U).name ()));
58+ }
59+ }
60+
2861template <class ConcreteConfig >
2962class ConfigBase {
3063 public:
3164 template <typename T>
3265 class Entry {
33- Entry (
34- std::string key, const T& val,
35- std::function<std::string(const T&)> toStr =
36- [](const T& val) {
37- if constexpr ((std::is_signed_v<T> && std::is_integral_v<T>) ||
38- std::is_floating_point_v<T>) {
39- return std::to_string (val);
40- } else if constexpr (std::is_same_v<T, bool >) {
41- return val ? " true" : " false" ;
42- } else if constexpr (std::is_same_v<T, std::string> ||
43- std::is_same_v<T, std::string_view>) {
44- return val;
45- } else {
46- throw std::runtime_error (
47- std::format (" Explicit toStr() is required for {}" , typeid (T).name ()));
48- }
49- },
50- std::function<T(const std::string&)> toT = [](const std::string& val) -> T {
51- if constexpr (std::is_same_v<T, std::string>) {
52- return val;
53- } else if constexpr (std::is_same_v<T, bool >) {
54- return val == " true" ;
55- } else if constexpr (std::is_signed_v<T> && std::is_integral_v<T>) {
56- return static_cast <T>(std::stoll (val));
57- } else if constexpr (std::is_floating_point_v<T>) {
58- return static_cast <T>(std::stod (val));
59- } else {
60- throw std::runtime_error (
61- std::format (" Explicit toT() is required for {}" , typeid (T).name ()));
62- }
63- })
64- : key_{std::move (key)}, default_{val}, toStr_{toStr}, toT_{toT} {}
66+ public:
67+ Entry (std::string key, const T& val,
68+ std::function<std::string(const T&)> to_str = defaultToString<T>,
69+ std::function<T(const std::string&)> from_str = defaultFromString<T>)
70+ : key_{std::move (key)}, default_{val}, to_str_{to_str}, from_str_{from_str} {}
6571
72+ private:
6673 const std::string key_;
6774 const T default_;
68- const std::function<std::string(const T&)> toStr_ ;
69- const std::function<T(const std::string&)> toT_ ;
75+ const std::function<std::string(const T&)> to_str_ ;
76+ const std::function<T(const std::string&)> from_str_ ;
7077
7178 friend ConfigBase;
7279 friend ConcreteConfig;
7380
7481 public:
7582 const std::string& key () const { return key_; }
7683
77- T value () const { return default_; }
84+ const T& value () const { return default_; }
7885 };
7986
8087 template <typename T>
8188 ConfigBase& set (const Entry<T>& entry, const T& val) {
82- configs_[entry.key_ ] = entry.toStr_ (val);
89+ configs_[entry.key_ ] = entry.to_str_ (val);
8390 return *this ;
8491 }
8592
@@ -96,19 +103,14 @@ class ConfigBase {
96103
97104 template <typename T>
98105 T get (const Entry<T>& entry) const {
99- try {
100- auto iter = configs_.find (entry.key_ );
101- return iter != configs_.cend () ? entry.toT_ (iter->second ) : entry.default_ ;
102- } catch (std::exception& e) {
103- throw std::runtime_error (
104- std::format (" Failed to get config {} with error: {}" , entry.key_ , e.what ()));
105- }
106+ auto iter = configs_.find (entry.key_ );
107+ return iter != configs_.cend () ? entry.from_str_ (iter->second ) : entry.default_ ;
106108 }
107109
108- std::map <std::string, std::string> const & configs () const { return configs_; }
110+ std::unordered_map <std::string, std::string> const & configs () const { return configs_; }
109111
110112 protected:
111- std::map <std::string, std::string> configs_;
113+ std::unordered_map <std::string, std::string> configs_;
112114};
113115
114116} // namespace iceberg
0 commit comments