Seastar
High performance C++ framework for concurrent servers
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Modules Pages
program-options.hh
1/*
2 * This file is open source software, licensed to you under the terms
3 * of the Apache License, Version 2.0 (the "License"). See the NOTICE file
4 * distributed with this work for additional information regarding copyright
5 * ownership. You may not use this file except in compliance with the License.
6 *
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,
12 * software distributed under the License is distributed on an
13 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 * KIND, either express or implied. See the License for the
15 * specific language governing permissions and limitations
16 * under the License.
17 */
18/*
19 * Copyright (C) 2017 ScyllaDB
20 */
21
22#pragma once
23
24#include <seastar/core/format.hh>
25#include <seastar/core/sstring.hh>
26#include <seastar/util/modules.hh>
27
28#ifndef SEASTAR_MODULE
29#include <fmt/format.h>
30
31#include <boost/any.hpp>
32#include <boost/intrusive/list.hpp>
33
34#include <string>
35#include <unordered_map>
36#include <variant>
37#include <vector>
38#include <optional>
39#include <set>
40#include <memory>
41#endif
42
56
57namespace seastar {
58
59namespace program_options {
60
74class string_map final : private std::unordered_map<sstring, sstring> {
75private:
76 using base = std::unordered_map<sstring, sstring>;
77public:
78 using base::value_type;
79 using base::key_type;
80 using base::mapped_type;
81
82 using base::base;
83 using base::at;
84 using base::find;
85 using base::count;
86 using base::emplace;
87 using base::clear;
88 using base::operator[];
89 using base::begin;
90 using base::end;
91
92 friend bool operator==(const string_map&, const string_map&);
93 friend bool operator!=(const string_map&, const string_map&);
94};
95
96inline bool operator==(const string_map& lhs, const string_map& rhs) {
97 return static_cast<const string_map::base&>(lhs) == static_cast<const string_map::base&>(rhs);
98}
99
100inline bool operator!=(const string_map& lhs, const string_map& rhs) {
101 return !(lhs == rhs);
102}
103
107sstring get_or_default(const string_map&, const sstring& key, const sstring& def = sstring());
108
109std::istream& operator>>(std::istream& is, string_map&);
110std::ostream& operator<<(std::ostream& os, const string_map&);
111
113
114//
115// Required implementation hook for Boost.Program_options.
116//
117void validate(boost::any& out, const std::vector<std::string>& in, string_map*, int);
118
119using list_base_hook = boost::intrusive::list_base_hook<boost::intrusive::link_mode<boost::intrusive::auto_unlink>>;
120
121} // namespace program_options
122
123SEASTAR_MODULE_EXPORT_BEGIN
124enum class log_level;
125enum class logger_timestamp_style;
126enum class logger_ostream_type;
127namespace memory {
128 enum class alloc_failure_kind;
129}
130
131namespace program_options {
132
134
137
138class option_group;
139
144public:
151 virtual bool visit_group_start(const std::string& name, bool used) = 0;
156 virtual void visit_group_end() = 0;
157
165 virtual bool visit_value_metadata(const std::string& name, const std::string& description, bool used) = 0;
166
168 virtual void visit_value() = 0;
170 virtual void visit_value(const bool* default_val) = 0;
172 virtual void visit_value(const int* default_val) = 0;
174 virtual void visit_value(const unsigned* default_val) = 0;
176 virtual void visit_value(const float* default_val) = 0;
178 virtual void visit_value(const double* default_val) = 0;
180 virtual void visit_value(const std::string* default_val) = 0;
182 virtual void visit_value(const std::set<unsigned>* default_val) = 0;
184 virtual void visit_value(const log_level* default_val) = 0;
186 virtual void visit_value(const logger_timestamp_style* default_val) = 0;
188 virtual void visit_value(const logger_ostream_type* default_val) = 0;
190 virtual void visit_value(const memory::alloc_failure_kind* default_val) = 0;
192 virtual void visit_value(const std::unordered_map<sstring, log_level>* default_val) = 0;
193
195 virtual void visit_selection_value(const std::vector<std::string>& candidate_names, const std::size_t* default_candidate) = 0;
196};
197
202public:
209 virtual bool visit_group_start(const std::string& name, bool used) = 0;
214 virtual void visit_group_end() = 0;
215
223 virtual bool visit_value_metadata(const std::string& name, bool used) = 0;
224
226 virtual bool visit_value() = 0;
228 virtual bool visit_value(bool& val) = 0;
230 virtual bool visit_value(int& val) = 0;
232 virtual bool visit_value(unsigned& val) = 0;
234 virtual bool visit_value(float& val) = 0;
236 virtual bool visit_value(double& val) = 0;
238 virtual bool visit_value(std::string& val) = 0;
240 virtual bool visit_value(std::set<unsigned>& val) = 0;
242 virtual bool visit_value(log_level& val) = 0;
244 virtual bool visit_value(logger_timestamp_style& val) = 0;
246 virtual bool visit_value(logger_ostream_type& val) = 0;
250 virtual bool visit_value(std::unordered_map<sstring, log_level>& val) = 0;
251
253 virtual bool visit_selection_value(const std::vector<std::string>& candidate_names, std::size_t& selected_candidate) = 0;
254};
255
257struct unused {};
258
259class basic_value;
260
293class option_group : public list_base_hook {
294 friend class basic_value;
295
296public:
297 using value_list_type = boost::intrusive::list<
299 boost::intrusive::base_hook<list_base_hook>,
300 boost::intrusive::constant_time_size<false>>;
301
302 using option_group_list_type = boost::intrusive::list<
304 boost::intrusive::base_hook<list_base_hook>,
305 boost::intrusive::constant_time_size<false>>;
306
307private:
308 option_group* _parent;
309 bool _used = true;
310 std::string _name;
311 value_list_type _values;
312 option_group_list_type _subgroups;
313
314public:
320 explicit option_group(option_group* parent, std::string name);
326 explicit option_group(option_group* parent, std::string name, unused);
328 option_group(const option_group&) = delete;
329 virtual ~option_group() = default;
330
331 option_group& operator=(option_group&&) = delete;
332 option_group& operator=(const option_group&) = delete;
333
335 operator bool () const { return !_values.empty(); }
336 bool used() const { return _used; }
337 const std::string& name() const { return _name; }
338 const value_list_type& values() const { return _values; }
339 value_list_type& values() { return _values; }
340
367 void describe(options_descriptor& descriptor) const;
377 void mutate(options_mutator& mutator);
378};
379
383class basic_value : public list_base_hook {
384 friend class option_group;
385
386public:
387 option_group* _group;
388 bool _used = true;
389 std::string _name;
390 std::string _description;
391
392private:
393 virtual void do_describe(options_descriptor& descriptor) const = 0;
394 virtual void do_mutate(options_mutator& mutator) = 0;
395
396public:
397 basic_value(option_group& group, bool used, std::string name, std::string description);
399 basic_value(const basic_value&) = delete;
400 virtual ~basic_value() = default;
401
402 basic_value& operator=(basic_value&&) = delete;
403 basic_value& operator=(const basic_value&) = delete;
404
405 bool used() const { return _used; }
406 const std::string& name() const { return _name; }
407 const std::string& description() const { return _description; }
408
409 void describe(options_descriptor& descriptor) const;
410 void mutate(options_mutator& mutator);
411};
412
416template <typename T = std::monostate>
417class value : public basic_value {
418 std::optional<T> _value;
419 bool _defaulted = true;
420
421private:
422 virtual void do_describe(options_descriptor& descriptor) const override {
423 auto* val = _value ? &*_value : nullptr;
424 descriptor.visit_value(val);
425 }
426 virtual void do_mutate(options_mutator& mutator) override {
427 T val;
428 if (mutator.visit_value(val)) {
429 _value = std::move(val);
430 _defaulted = false;
431 }
432 }
433 void do_set_value(T value, bool defaulted) {
434 _value = std::move(value);
435 _defaulted = defaulted;
436 }
437
438public:
445 value(option_group& group, std::string name, std::optional<T> default_value, std::string description)
446 : basic_value(group, true, std::move(name), std::move(description))
447 , _value(std::move(default_value))
448 { }
450 value(option_group& group, std::string name, unused)
451 : basic_value(group, false, std::move(name), {})
452 { }
453 value(value&&) = default;
455 operator bool () const { return bool(_value); }
457 bool defaulted() const { return _defaulted; }
459 const T& get_value() const { return _value.value(); }
460 T& get_value() { return _value.value(); }
461 void set_default_value(T value) { do_set_value(std::move(value), true); }
462 void set_value(T value) { do_set_value(std::move(value), false); }
463};
464
468template <>
469class value<std::monostate> : public basic_value {
470 std::optional<bool> _set;
471
472private:
473 virtual void do_describe(options_descriptor& descriptor) const override {
474 descriptor.visit_value();
475 }
476 virtual void do_mutate(options_mutator& mutator) override {
477 bool is_set = mutator.visit_value();
478 if (_set.has_value()) {
479 // override the value only if it is not preset
480 if (is_set) {
481 _set = true;
482 }
483 } else {
484 _set = is_set;
485 }
486 }
487
488public:
494 value(option_group& group, std::string name, std::string description)
495 : basic_value(group, true, std::move(name), std::move(description))
496 { }
498 value(option_group& group, std::string name, unused)
499 : basic_value(group, false, std::move(name), {})
500 { }
502 operator bool () const { return _set ? _set.value() : false; }
503 void set_value() { _set = true; }
504 void unset_value() { _set = false; }
505};
506
517template <typename T = std::monostate>
519public:
520 using deleter = std::function<void(T*)>;
521 using value_handle = std::unique_ptr<T, deleter>;
522 struct candidate {
523 std::string name;
524 value_handle value;
525 std::unique_ptr<option_group> opts;
526 };
527 using candidates = std::vector<candidate>;
528
529private:
530 static constexpr size_t no_selected_candidate = -1;
531
532private:
533 candidates _candidates;
534 size_t _selected_candidate = no_selected_candidate;
535 bool _defaulted = true;
536
537public:
538 std::vector<std::string> get_candidate_names() const {
539 std::vector<std::string> candidate_names;
540 candidate_names.reserve(_candidates.size());
541 for (const auto& c : _candidates) {
542 candidate_names.push_back(c.name);
543 }
544 return candidate_names;
545 }
546private:
547 virtual void do_describe(options_descriptor& descriptor) const override {
548 descriptor.visit_selection_value(get_candidate_names(), _selected_candidate == no_selected_candidate ? nullptr : &_selected_candidate);
549 for (auto& c : _candidates) {
550 if (c.opts) {
551 c.opts->describe(descriptor);
552 }
553 }
554 }
555 virtual void do_mutate(options_mutator& mutator) override {
556 if (mutator.visit_selection_value(get_candidate_names(), _selected_candidate)) {
557 _defaulted = false;
558 }
559 if (_selected_candidate != no_selected_candidate) {
560 auto& c = _candidates.at(_selected_candidate);
561 if (c.opts) {
562 c.opts->mutate(mutator);
563 }
564 }
565 }
566 size_t find_candidate(const std::string& candidate_name) {
567 auto it = find_if(_candidates.begin(), _candidates.end(), [&] (const auto& candidate) {
568 return candidate.name == candidate_name;
569 });
570 if (it == _candidates.end()) {
571 throw std::invalid_argument(fmt::format("find_candidate(): failed to find candidate {}", candidate_name));
572 }
573 return it - _candidates.begin();
574 }
575
576 option_group* do_select_candidate(std::string candidate_name, bool defaulted) {
577 _selected_candidate = find_candidate(candidate_name);
578 _defaulted = defaulted;
579 return _candidates.at(_selected_candidate).opts.get();
580 }
581
582public:
590 selection_value(option_group& group, std::string name, candidates candidates, std::string default_candidate, std::string description)
591 : basic_value(group, true, std::move(name), std::move(description))
592 , _candidates(std::move(candidates))
593 , _selected_candidate(find_candidate(default_candidate))
594 { }
595 selection_value(option_group& group, std::string name, candidates candidates, std::string description)
596 : basic_value(group, true, std::move(name), std::move(description))
597 , _candidates(std::move(candidates))
598 { }
600 selection_value(option_group& group, std::string name, unused)
601 : basic_value(group, false, std::move(name), {})
602 { }
604 operator bool () const { return _selected_candidate != no_selected_candidate; }
606 bool defaulted() const { return _defaulted; }
608 const std::string& get_selected_candidate_name() const { return _candidates.at(_selected_candidate).name; }
610 const option_group* get_selected_candidate_opts() const { return _candidates.at(_selected_candidate).opts.get(); }
612 option_group* get_selected_candidate_opts() { return _candidates.at(_selected_candidate).opts.get(); }
613 T& get_selected_candidate() const { return *_candidates.at(_selected_candidate).value; }
617 option_group* select_candidate(std::string candidate_name) { return do_select_candidate(candidate_name, false); }
621 option_group* select_default_candidate(std::string candidate_name) { return do_select_candidate(candidate_name, true); }
622};
623
625
626}
627SEASTAR_MODULE_EXPORT_END
628
629}
Definition: program-options.hh:383
Definition: program-options.hh:293
void mutate(options_mutator &mutator)
option_group(option_group *parent, std::string name, unused)
void describe(options_descriptor &descriptor) const
option_group(option_group *parent, std::string name)
Definition: program-options.hh:143
virtual void visit_value(const std::set< unsigned > *default_val)=0
Visit a value (value), default_val is null when value has no default.
virtual void visit_value(const logger_ostream_type *default_val)=0
Visit a value (value), default_val is null when value has no default.
virtual void visit_value(const double *default_val)=0
Visit a value (value), default_val is null when value has no default.
virtual void visit_value(const std::unordered_map< sstring, log_level > *default_val)=0
Visit a value (value), default_val is null when value has no default.
virtual void visit_selection_value(const std::vector< std::string > &candidate_names, const std::size_t *default_candidate)=0
Visit a selection value (selection_value), default_candidate is null when there is no default candida...
virtual bool visit_value_metadata(const std::string &name, const std::string &description, bool used)=0
virtual void visit_value(const log_level *default_val)=0
Visit a value (value), default_val is null when value has no default.
virtual void visit_value(const float *default_val)=0
Visit a value (value), default_val is null when value has no default.
virtual void visit_value(const memory::alloc_failure_kind *default_val)=0
Visit a value (value), default_val is null when value has no default.
virtual void visit_value(const std::string *default_val)=0
Visit a value (value), default_val is null when value has no default.
virtual void visit_value(const unsigned *default_val)=0
Visit a value (value), default_val is null when value has no default.
virtual void visit_value(const int *default_val)=0
Visit a value (value), default_val is null when value has no default.
virtual bool visit_group_start(const std::string &name, bool used)=0
virtual void visit_value()=0
Visit a switch (value<std::monostate>).
virtual void visit_value(const logger_timestamp_style *default_val)=0
Visit a value (value), default_val is null when value has no default.
virtual void visit_value(const bool *default_val)=0
Visit a value (value), default_val is null when value has no default.
Definition: program-options.hh:201
virtual bool visit_value(std::set< unsigned > &val)=0
Visit and optionally mutate a value (value), should return true if value was mutated.
virtual bool visit_value(std::unordered_map< sstring, log_level > &val)=0
Visit and optionally mutate a value (value), should return true if value was mutated.
virtual bool visit_value_metadata(const std::string &name, bool used)=0
virtual bool visit_value(logger_ostream_type &val)=0
Visit and optionally mutate a value (value), should return true if value was mutated.
virtual bool visit_value()=0
Visit a switch (value<std::monostate>), switch is set to returned value.
virtual bool visit_value(double &val)=0
Visit and optionally mutate a value (value), should return true if value was mutated.
virtual bool visit_value(float &val)=0
Visit and optionally mutate a value (value), should return true if value was mutated.
virtual bool visit_group_start(const std::string &name, bool used)=0
virtual bool visit_value(unsigned &val)=0
Visit and optionally mutate a value (value), should return true if value was mutated.
virtual bool visit_selection_value(const std::vector< std::string > &candidate_names, std::size_t &selected_candidate)=0
Visit and optionally mutate a selection value (selection_value), should return true if value was muta...
virtual bool visit_value(memory::alloc_failure_kind &val)=0
Visit and optionally mutate a value (value), should return true if value was mutated.
virtual bool visit_value(logger_timestamp_style &val)=0
Visit and optionally mutate a value (value), should return true if value was mutated.
virtual bool visit_value(int &val)=0
Visit a value (value), default_val is null when value has no default.
virtual bool visit_value(std::string &val)=0
Visit and optionally mutate a value (value), should return true if value was mutated.
virtual bool visit_value(log_level &val)=0
Visit and optionally mutate a value (value), should return true if value was mutated.
virtual bool visit_value(bool &val)=0
Visit and optionally mutate a value (value), should return true if value was mutated.
Definition: program-options.hh:518
option_group * select_default_candidate(std::string candidate_name)
Definition: program-options.hh:621
selection_value(option_group &group, std::string name, unused)
Construct an unused value.
Definition: program-options.hh:600
option_group * get_selected_candidate_opts()
Get the options of the currently selected candidate (assumes there is one selected,...
Definition: program-options.hh:612
option_group * select_candidate(std::string candidate_name)
Definition: program-options.hh:617
bool defaulted() const
Is the currently selected candidate the default one?
Definition: program-options.hh:606
selection_value(option_group &group, std::string name, candidates candidates, std::string default_candidate, std::string description)
Definition: program-options.hh:590
const option_group * get_selected_candidate_opts() const
Get the options of the currently selected candidate (assumes there is one selected,...
Definition: program-options.hh:610
const std::string & get_selected_candidate_name() const
Get the name of the currently selected candidate (assumes there is one selected, see \operator bool()...
Definition: program-options.hh:608
Wrapper for command-line options with arbitrary string associations.
Definition: program-options.hh:74
value(option_group &group, std::string name, unused)
Construct an unused value.
Definition: program-options.hh:498
value(option_group &group, std::string name, std::string description)
Definition: program-options.hh:494
Definition: program-options.hh:417
value(option_group &group, std::string name, std::optional< T > default_value, std::string description)
Definition: program-options.hh:445
const T & get_value() const
Return the contained value, assumes there is one, see operator bool().
Definition: program-options.hh:459
bool defaulted() const
Does this value still contain a default-value?
Definition: program-options.hh:457
value(option_group &group, std::string name, unused)
Construct an unused value.
Definition: program-options.hh:450
log_level
log level used with
Definition: log.hh:55
A tag type used to construct unused option_group and basic_value objects.
Definition: program-options.hh:257
alloc_failure_kind
The kind of allocation failures to dump diagnostics report for.
Definition: memory_diagnostics.hh:41
Seastar API namespace.
Definition: abort_on_ebadf.hh:26
STL namespace.