Toolbox snapshot
The Reactive C++ Toolbox
Loading...
Searching...
No Matches
Config.hpp
Go to the documentation of this file.
1// The Reactive C++ Toolbox.
2// Copyright (C) 2013-2019 Swirly Cloud Limited
3// Copyright (C) 2022 Reactive Markets Limited
4//
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16
17#ifndef TOOLBOX_UTIL_CONFIG_HPP
18#define TOOLBOX_UTIL_CONFIG_HPP
19
21
22#pragma GCC diagnostic push
23#pragma GCC diagnostic ignored "-Wstrict-aliasing"
24#include <boost/container/flat_map.hpp>
25#pragma GCC diagnostic pop
26
27#include <map>
28
29namespace toolbox {
30inline namespace util {
31
32template <typename FnT>
33std::istream& parse_section(std::istream& is, FnT fn, std::string* name = nullptr)
34{
35 std::string line;
36 while (std::getline(is, line)) {
37
38 trim(line);
39
40 // Ignore empty lines and comments.
41
42 if (line.empty() || line[0] == '#') {
43 continue;
44 }
45
46 if (line.front() == '[' && line.back() == ']') {
47 if (name) {
48 name->assign(line, 1, line.size() - 2);
49 trim(*name);
50 }
51 return is;
52 }
53
54 auto [key, val] = split_pair(line, '=');
55 rtrim(key);
56 ltrim(val);
57
58 fn(key, val);
59 }
60 if (name) {
61 name->clear();
62 }
63 return is;
64}
65
68 public:
71
72 // Copy.
73 Config(const Config&);
75
76 // Move.
77 Config(Config&&) noexcept;
78 Config& operator=(Config&&) noexcept;
79
81 const std::string& get(const std::string& key) const;
82 const char* get(const std::string& key, const char* dfl) const noexcept;
83 const char* get(const std::string& key, std::nullptr_t) const noexcept
84 {
85 return get(key, static_cast<const char*>(nullptr));
86 }
88 template <typename ValueT>
89 ValueT get(const std::string& key) const
90 {
91 const auto it{map_.find(key)};
92 if (it != map_.end()) {
93 if constexpr (std::is_same_v<ValueT, std::string_view>) {
94 // Explicitly allow conversion to std::string_view in this case,
95 // because we know that the argument is not a temporary.
96 return std::string_view{it->second};
97 } else if constexpr (std::is_enum_v<ValueT>) {
98 return ValueT{from_string<std::underlying_type_t<ValueT>>(it->second)};
99 } else {
100 return from_string<ValueT>(it->second);
101 }
102 }
103 if (!parent_) {
104 throw std::runtime_error{std::string{"missing config key: "} + key};
105 }
106 return parent_->get<ValueT>(key);
107 }
108 template <typename ValueT>
109 ValueT get(const std::string& key, ValueT dfl) const noexcept
110 {
111 const auto it{map_.find(key)};
112 if (it != map_.end()) {
113 if constexpr (std::is_same_v<ValueT, std::string_view>) {
114 // Explicitly allow conversion to std::string_view in this case,
115 // because we know that the argument is not a temporary.
116 return std::string_view{it->second};
117 } else if constexpr (std::is_enum_v<ValueT>) {
118 return ValueT{from_string<std::underlying_type_t<ValueT>>(it->second)};
119 } else {
120 return from_string<ValueT>(it->second);
121 }
122 }
123 return parent_ ? parent_->get<ValueT>(key, dfl) : dfl;
124 }
125 std::size_t size() const noexcept { return map_.size(); }
126 void clear() noexcept { map_.clear(); }
127 std::istream& read_section(std::istream& is) { return read_section(is, nullptr); }
128 std::istream& read_section(std::istream&& is) { return read_section(is); }
129 std::istream& read_section(std::istream& is, std::string& next)
130 {
131 return read_section(is, &next);
132 }
133 std::istream& read_section(std::istream&& is, std::string& next)
134 {
135 return read_section(is, next);
136 }
137 void set(std::string key, std::string val)
138 {
139 map_.insert_or_assign(std::move(key), std::move(val));
140 }
141 void set_parent(Config& parent) noexcept { parent_ = &parent; }
142
143 private:
144 std::istream& read_section(std::istream& is, std::string* next);
145 std::map<std::string, std::string> map_;
146 Config* parent_{nullptr};
147};
148
150 public:
153
154 // Copy.
155 MultiConfig(const MultiConfig&) = delete;
157
158 // Move.
160 MultiConfig& operator=(MultiConfig&&) noexcept;
161
162 void clear() noexcept;
163 void read(std::istream& is);
164 void read(std::istream&& is) { read(is); }
165
166 const Config& root() const noexcept { return root_; }
167 const Config& section(const std::string& name) const noexcept
168 {
169 auto it = map_.find(name);
170 return it != map_.end() ? it->second : root_;
171 }
172 const Config& section(std::string_view name) const noexcept
173 {
174 return section(std::string{name});
175 }
176
177 private:
178 Config root_;
179 // Map of named sections.
180 std::map<std::string, Config> map_;
181};
182
183} // namespace util
184} // namespace toolbox
185
186#endif // TOOLBOX_UTIL_CONFIG_HPP
#define TOOLBOX_API
Definition Config.h:39
Simple config reader with environment variable substitution.
Definition Config.hpp:67
void clear() noexcept
Definition Config.hpp:126
Config & operator=(const Config &)
ValueT get(const std::string &key, ValueT dfl) const noexcept
Definition Config.hpp:109
std::size_t size() const noexcept
Definition Config.hpp:125
Config(const Config &)
Config(Config &&) noexcept
std::istream & read_section(std::istream &&is, std::string &next)
Definition Config.hpp:133
std::istream & read_section(std::istream &&is)
Definition Config.hpp:128
std::istream & read_section(std::istream &is)
Definition Config.hpp:127
void set_parent(Config &parent) noexcept
Definition Config.hpp:141
void set(std::string key, std::string val)
Definition Config.hpp:137
ValueT get(const std::string &key) const
Throws std::runtime_error if key does not exist.
Definition Config.hpp:89
std::istream & read_section(std::istream &is, std::string &next)
Definition Config.hpp:129
MultiConfig & operator=(const MultiConfig &)=delete
const Config & section(const std::string &name) const noexcept
Definition Config.hpp:167
const Config & root() const noexcept
Definition Config.hpp:166
MultiConfig(const MultiConfig &)=delete
MultiConfig(MultiConfig &&) noexcept
const Config & section(std::string_view name) const noexcept
Definition Config.hpp:172
void read(std::istream &&is)
Definition Config.hpp:164
STL namespace.
pair< string_view, string_view > split_pair(string_view s, char delim) noexcept
Definition String.cpp:51
void rtrim(string_view &s) noexcept
Definition String.cpp:39
void trim(std::string_view &s) noexcept
Definition String.hpp:84
void ltrim(string_view &s) noexcept
Definition String.cpp:27
std::istream & parse_section(std::istream &is, FnT fn, std::string *name=nullptr)
Definition Config.hpp:33
constexpr const auto & get(const detail::Struct< detail::Member< TagsT, ValuesT >... > &s, TagT tag={})
Definition Struct.hpp:110
constexpr auto bind() noexcept
Definition Slot.hpp:92