2 * Copyright (c) 2014-2017, Andrzej Rybczak <electricityispower@gmail.com>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the copyright holder nor the names of its
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
26 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 #ifndef NCMPCPP_UTILITY_OPTION_PARSER_H
34 #define NCMPCPP_UTILITY_OPTION_PARSER_H
36 #include <boost/algorithm/string/trim.hpp>
37 #include <boost/tokenizer.hpp>
38 #include <boost/lexical_cast.hpp>
41 #include <unordered_map>
43 [[noreturn
]] inline void invalid_value(const std::string
&v
)
45 throw std::runtime_error("invalid value: " + v
);
48 template <typename DestT
>
49 DestT
verbose_lexical_cast(const std::string
&v
)
52 return boost::lexical_cast
<DestT
>(v
);
53 } catch (boost::bad_lexical_cast
&) {
58 template <typename ValueT
, typename ConvertT
>
59 std::vector
<ValueT
> list_of(const std::string
&v
, ConvertT convert
)
61 std::vector
<ValueT
> result
;
62 boost::tokenizer
<boost::escaped_list_separator
<char>> elems(v
);
63 for (auto &value
: elems
)
64 result
.push_back(convert(boost::trim_copy(value
)));
66 throw std::runtime_error("empty list");
70 template <typename ValueT
>
71 std::vector
<ValueT
> list_of(const std::string
&v
)
73 return list_of
<ValueT
>(v
, verbose_lexical_cast
<ValueT
>);
76 bool yes_no(const std::string
&v
);
78 ////////////////////////////////////////////////////////////////////////////////
82 template <typename DestT
>
85 template <typename MapT
>
86 worker(DestT
*dest
, MapT
&&map
)
87 : m_dest(dest
), m_map(std::forward
<MapT
>(map
)), m_dest_set(false)
90 void operator()(std::string value
)
93 throw std::runtime_error("option already set");
94 assign
<DestT
, void>::apply(m_dest
, m_map
, value
);
99 template <typename ValueT
, typename VoidT
>
101 static void apply(ValueT
*dest
,
102 std::function
<DestT(std::string
)> &map
,
103 std::string
&value
) {
104 *dest
= map(std::move(value
));
107 template <typename VoidT
>
108 struct assign
<void, VoidT
> {
109 static void apply(void *,
110 std::function
<void(std::string
)> &map
,
111 std::string
&value
) {
112 map(std::move(value
));
117 std::function
<DestT(std::string
)> m_map
;
122 template <typename StringT
, typename SetterT
>
123 parser(StringT
&&default_
, SetterT
&&setter_
)
125 , m_default_value(std::forward
<StringT
>(default_
))
126 , m_worker(std::forward
<SetterT
>(setter_
))
134 void parse(std::string v
)
136 m_worker(std::move(v
));
140 void parse_default() const
143 m_worker(m_default_value
);
148 std::string m_default_value
;
149 std::function
<void(std::string
)> m_worker
;
152 std::unordered_map
<std::string
, parser
> m_parsers
;
155 template <typename DestT
, typename MapT
>
156 void add(std::string option
, DestT
*dest
, std::string default_
, MapT
&&map
)
158 assert(m_parsers
.count(option
) == 0);
163 worker
<DestT
>(dest
, std::forward
<MapT
>(map
))));
166 template <typename DestT
>
167 void add(std::string option
, DestT
*dest
, std::string default_
)
169 add(std::move(option
), dest
, std::move(default_
), verbose_lexical_cast
<DestT
>);
172 bool run(std::istream
&is
, bool warn_on_errors
);
173 bool initialize_undefined(bool warn_on_errors
);
176 #endif // NCMPCPP_UTILITY_OPTION_PARSER_H