• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

STEllAR-GROUP / hpx / #882

31 Aug 2023 07:44PM UTC coverage: 41.798% (-44.7%) from 86.546%
#882

push

19442 of 46514 relevant lines covered (41.8%)

126375.38 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

57.5
/libs/core/program_options/src/variables_map.cpp
1
//  Copyright Vladimir Prus 2002-2004.
2
//
3
//  SPDX-License-Identifier: BSL-1.0
4
//  Distributed under the Boost Software License, Version 1.0. (See accompanying
5
//  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6

7
#include <hpx/program_options/config.hpp>
8
#include <hpx/assert.hpp>
9
#include <hpx/modules/datastructures.hpp>
10
#include <hpx/program_options/options_description.hpp>
11
#include <hpx/program_options/parsers.hpp>
12
#include <hpx/program_options/value_semantic.hpp>
13
#include <hpx/program_options/variables_map.hpp>
14

15
#include <cstddef>
16
#include <map>
17
#include <memory>
18
#include <set>
19
#include <string>
20
#include <vector>
21

22
namespace hpx::program_options {
23

24
    // First, performs semantic actions for 'oa'. Then, stores in 'm' all
25
    // options that are defined in 'desc'.
26
    HPX_CORE_EXPORT
27
    void store(parsed_options const& options, variables_map& xm, bool utf8)
194✔
28
    {
29
        // TODO: what if we have different definition for the same option name
30
        // during different calls 'store'.
31
        HPX_ASSERT(options.description);
32
        options_description const& desc = *options.description;
194✔
33

34
        // We need to access map's operator[], not the overridden version
35
        // variables_map. Ehmm.. messy.
36
        std::map<std::string, variable_value>& m = xm;
194✔
37

38
        std::set<std::string> new_final;
39

40
        // Declared once, to please Intel in VC++ mode;
41
        std::size_t i;
42

43
        // Declared here so can be used to provide context for exceptions
44
        std::string option_name;
45
        std::string original_token;
46

47
        try
48
        {
49
            // First, convert/store all given options
50
            for (i = 0; i < options.options.size(); ++i)
698✔
51
            {
52
                auto const& opts = options.options[i];
53
                option_name = opts.string_key;
504✔
54
                // Skip positional options without name
55
                if (option_name.empty())
504✔
56
                    continue;
21✔
57

58
                // Ignore unregistered option. The 'unregistered' field can be
59
                // true only if user has explicitly asked to allow unregistered
60
                // options. We can't store them to variables map (lacking any
61
                // information about paring), so just ignore them.
62
                if (opts.unregistered)
485✔
63
                    continue;
2✔
64

65
                // If option has final value, skip this assignment
66
                if (xm.m_final.count(option_name))
×
67
                    continue;
×
68

69
                original_token = !opts.original_tokens.empty() ?
483✔
70
                    opts.original_tokens[0] :
71
                    "";
72
                option_description const& d =
73
                    desc.find(option_name, false, false, false);
483✔
74

75
                variable_value& v = m[option_name];
483✔
76
                if (v.defaulted())
483✔
77
                {
78
                    // Explicit assignment here erases defaulted value
79
                    v = variable_value();
×
80
                }
81

82
                auto const& semantic = d.semantic();
483✔
83
                semantic->parse(v.value(), opts.value, utf8);
483✔
84

85
                v.m_value_semantic = semantic;
86

87
                // The option is not composing, and the value is explicitly
88
                // provided. Ignore values of this option for subsequent calls
89
                // to 'store'. We store this to a temporary set, so that several
90
                // assignment inside *this* 'store' call are allowed.
91
                if (!semantic->is_composing())
483✔
92
                    new_final.insert(option_name);
93
            }
94
        }
95
        catch (error_with_option_name& e)
×
96
        {
97
            // add context and rethrow
98
            e.add_context(
99
                option_name, original_token, options.m_options_prefix);
×
100
            throw;
×
101
        }
×
102

103
        xm.m_final.insert(new_final.begin(), new_final.end());
194✔
104

105
        // Second, apply default values and store required options.
106
        std::vector<std::shared_ptr<option_description>> const& all =
107
            desc.options();
194✔
108
        for (i = 0; i < all.size(); ++i)
9,237✔
109
        {
110
            option_description const& d = *all[i];
111
            std::string key = d.key("");
18,086✔
112
            // FIXME: this logic relies on knowledge of option_description
113
            // internals. The 'key' is empty if options description contains
114
            // '*'. In that case, default value makes no sense at all.
115
            if (key.empty())
9,043✔
116
            {
117
                continue;
118
            }
119
            if (m.count(key) == 0)
120
            {
121
                hpx::any_nonser def;
122
                if (d.semantic()->apply_default(def))
17,180✔
123
                {
124
                    m[key] = variable_value(def, true);
325✔
125
                    m[key].m_value_semantic = d.semantic();
650✔
126
                }
127
            }
128

129
            // add empty value if this is an required option
130
            if (d.semantic()->is_required())
18,086✔
131
            {
132
                // For option names specified in multiple ways, e.g. on the
133
                // command line, config file etc, the following precedence rules
134
                // apply: "--"  >  ("-" or "/")  >  ""
135
                // Precedence is set conveniently by a single call to length()
136
                std::string canonical_name =
137
                    d.canonical_display_name(options.m_options_prefix);
×
138
                if (canonical_name.length() > xm.m_required[key].length())
×
139
                    xm.m_required[key] = HPX_MOVE(canonical_name);
×
140
            }
141
        }
142
    }
194✔
143

144
    void store(wparsed_options const& options, variables_map& m)
×
145
    {
146
        store(options.utf8_encoded_options, m, true);
×
147
    }
×
148

149
    void notify(variables_map& vm)
194✔
150
    {
151
        vm.notify();
194✔
152
    }
194✔
153

154
    abstract_variables_map::abstract_variables_map()
194✔
155
      : m_next(nullptr)
194✔
156
    {
157
    }
194✔
158

159
    abstract_variables_map::abstract_variables_map(
×
160
        abstract_variables_map const* next)
×
161
      : m_next(next)
×
162
    {
163
    }
×
164

165
    variable_value const& abstract_variables_map::operator[](
440✔
166
        std::string const& name) const
167
    {
168
        variable_value const& v = get(name);
440✔
169
        if (v.empty() && m_next)
440✔
170
        {
171
            return (*m_next)[name];
×
172
        }
173

174
        if (v.defaulted() && m_next)
440✔
175
        {
176
            if (variable_value const& v2 = (*m_next)[name];
×
177
                !v2.empty() && !v2.defaulted())
×
178
            {
179
                return v2;
180
            }
181
            return v;
182
        }
183
        return v;
184
    }
185

186
    void abstract_variables_map::next(abstract_variables_map* next)
×
187
    {
188
        m_next = next;
×
189
    }
×
190

191
    variables_map::variables_map() = default;
194✔
192

193
    variables_map::variables_map(abstract_variables_map const* next)
×
194
      : abstract_variables_map(next)
×
195
    {
196
    }
×
197

198
    void variables_map::clear()
×
199
    {
200
        std::map<std::string, variable_value>::clear();
201
        m_final.clear();
202
        m_required.clear();
203
    }
×
204

205
    variable_value const& variables_map::get(std::string const& name) const
440✔
206
    {
207
        if (auto const i = this->find(name); i == this->end())
440✔
208
        {
209
            static variable_value empty;
×
210
            return empty;
×
211
        }
212
        else
213
        {
214
            return i->second;
440✔
215
        }
216
    }
217

218
    void variables_map::notify()
194✔
219
    {
220
        // This checks if all required options occur
221
        for (auto const& r : m_required)
194✔
222
        {
223
            std::string const& opt = r.first;
×
224
            std::string const& display_opt = r.second;
×
225
            if (auto iter = find(opt); iter == end() || iter->second.empty())
×
226
            {
227
                throw required_option(display_opt);
×
228
            }
229
        }
230

231
        // Lastly, run notify actions.
232
        for (auto& k : *this)
972✔
233
        {
234
            /* Users might wish to use variables_map to store their own values
235
               that are not parsed, and therefore will not have value_semantics
236
               defined. Do not crash on such values. In multi-module programs,
237
               one module might add custom values, and the 'notify' function
238
               will be called after that, so we check that value_semantics is
239
               not NULL. See:
240
                   https://svn.boost.org/trac/boost/ticket/2782
241
            */
242
            if (k.second.m_value_semantic)
778✔
243
                k.second.m_value_semantic->notify(k.second.value());
778✔
244
        }
245
    }
194✔
246
}    // namespace hpx::program_options
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc