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

STEllAR-GROUP / hpx / #862

10 Jan 2023 05:30PM UTC coverage: 86.582% (-0.05%) from 86.634%
#862

push

StellarBot
Merge #6130

6130: Remove the mutex lock in the critical path of get_partitioner. r=hkaiser a=JiakunYan

Remove the mutex lock in the critical path of hpx::resource::detail::get_partitioner.

The protected variable `partitioner_ref` is only set once during initialization.

Co-authored-by: Jiakun Yan <jiakunyan1998@gmail.com>

6 of 6 new or added lines in 1 file covered. (100.0%)

174767 of 201851 relevant lines covered (86.58%)

2069816.07 hits per line

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

64.63
/libs/core/ini/src/ini.cpp
1
//  Copyright (c) 2005-2007 Andre Merzky
2
//  Copyright (c) 2005-2022 Hartmut Kaiser
3
//  Copyright (c)      2011 Bryce Lelbach
4
//
5
//  SPDX-License-Identifier: BSL-1.0
6
//  Distributed under the Boost Software License, Version 1.0. (See accompanying
7
//  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
8

9
#include <hpx/config.hpp>
10

11
// System Header Files
12
#include <cerrno>
13
#include <cstddef>
14
#include <cstdint>
15
#include <cstdio>
16
#include <cstdlib>
17
#include <cstring>
18
#include <fstream>
19
#include <iostream>
20
#include <list>
21
#include <mutex>
22
#include <regex>
23
#include <string>
24
#include <type_traits>
25
#include <utility>
26
#include <vector>
27

28
#include <hpx/assert.hpp>
29
#include <hpx/ini/ini.hpp>
30
#include <hpx/modules/errors.hpp>
31
#include <hpx/serialization/map.hpp>
32
#include <hpx/serialization/serialize.hpp>
33
#include <hpx/string_util/classification.hpp>
34
#include <hpx/string_util/split.hpp>
35
#include <hpx/thread_support/unlock_guard.hpp>
36

37
#ifdef __APPLE__
38
#include <crt_externs.h>
39
#define environ (*_NSGetEnviron())
40
#elif !defined(HPX_WINDOWS)
41
extern char** environ;
42
#endif
43

44
///////////////////////////////////////////////////////////////////////////////
45
namespace hpx::util {
46

47
    ///////////////////////////////////////////////////////////////////////////////
48
    // example ini line: line # comment
49
    inline constexpr char const pattern_comment[] = "^([^#]*)(#.*)$";
50
    ///////////////////////////////////////////////////////////////////////////////
51

52
    namespace detail {
53

54
        ///////////////////////////////////////////////////////////////////////////
55
        inline std::string trim_whitespace(std::string const& s)
2,487,831✔
56
        {
57
            typedef std::string::size_type size_type;
58

59
            size_type first = s.find_first_not_of(" \t\r\n");
2,487,831✔
60
            if (std::string::npos == first)
2,487,831✔
61
                return (std::string());
4,165✔
62

63
            size_type last = s.find_last_not_of(" \t\r\n");
2,483,666✔
64
            return s.substr(first, last - first + 1);
2,483,666✔
65
        }
2,487,831✔
66

67
        // MSVC: using std::string::replace triggers ASAN reports
68
        std::string replace_substr(std::string const& str,
300,045✔
69
            std::size_t start_pos, std::size_t oldlen, char const* newstr)
70
        {
71
            std::string result(str.substr(0, start_pos));
300,045✔
72
            result += newstr;
300,045✔
73
            result += str.substr(start_pos + oldlen);
300,045✔
74
            return result;
300,045✔
75
        }
300,045✔
76

77
        std::string replace_substr(std::string const& str,
292,707✔
78
            std::size_t start_pos, std::size_t oldlen,
79
            std::string const& newstr)
80
        {
81
            return replace_substr(str, start_pos, oldlen, newstr.c_str());
292,707✔
82
        }
83
    }    // namespace detail
84

85
    ///////////////////////////////////////////////////////////////////////////////
86
    section::section() noexcept
515,651✔
87
      : root_(this_())
515,651✔
88
    {
89
    }
515,651✔
90

91
    section::section(std::string const& filename, section* root)
×
92
      : root_(nullptr != root ? root : this_())
×
93
      , name_(filename)
×
94
    {
95
        read(filename);
×
96
    }
×
97

98
    section::section(section const& in)
808,942✔
99
      : root_(this_())
404,471✔
100
      , name_(in.get_name())
404,471✔
101
      , parent_name_(in.get_parent_name())
404,471✔
102
    {
103
        entry_map const& e = in.get_entries();
404,471✔
104
        entry_map::const_iterator end = e.end();
404,471✔
105
        for (entry_map::const_iterator i = e.begin(); i != end; ++i)
2,273,420✔
106
            add_entry(i->first, i->second);
1,868,949✔
107

108
        section_map s = in.get_sections();
404,471✔
109
        section_map::iterator send = s.end();
404,471✔
110
        for (section_map::iterator si = s.begin(); si != send; ++si)
607,915✔
111
            add_section(si->first, si->second, get_root());
203,444✔
112
    }
404,471✔
113

114
    section& section::operator=(section const& rhs)
1,805✔
115
    {
116
        if (this != &rhs)
1,805✔
117
        {
118
            std::unique_lock<mutex_type> l(mtx_);
1,805✔
119

120
            root_ = this;
1,805✔
121
            parent_name_ = rhs.get_parent_name();
1,805✔
122
            name_ = rhs.get_name();
1,805✔
123

124
            entry_map const& e = rhs.get_entries();
1,805✔
125
            entry_map::const_iterator end = e.end();
1,805✔
126
            for (entry_map::const_iterator i = e.begin(); i != end; ++i)
5,297✔
127
                add_entry(l, i->first, i->first, i->second);
3,492✔
128

129
            section_map s = rhs.get_sections();
1,805✔
130
            section_map::iterator send = s.end();
1,805✔
131
            for (section_map::iterator si = s.begin(); si != send; ++si)
5,474✔
132
                add_section(l, si->first, si->second, get_root());
3,669✔
133
        }
1,805✔
134
        return *this;
1,805✔
135
    }
×
136

137
    section& section::clone_from(section const& rhs, section* root)
456,734✔
138
    {
139
        if (this != &rhs)
456,734✔
140
        {
141
            std::unique_lock<mutex_type> l(mtx_);
456,734✔
142

143
            root_ = root ? root : this;
456,734✔
144
            parent_name_ = rhs.get_parent_name();
456,734✔
145
            name_ = rhs.get_name();
456,734✔
146

147
            entry_map const& e = rhs.get_entries();
456,734✔
148
            entry_map::const_iterator end = e.end();
456,734✔
149
            for (entry_map::const_iterator i = e.begin(); i != end; ++i)
2,325,683✔
150
                add_entry(l, i->first, i->first, i->second);
1,868,949✔
151

152
            section_map s = rhs.get_sections();
456,734✔
153
            section_map::iterator send = s.end();
456,734✔
154
            for (section_map::iterator si = s.begin(); si != send; ++si)
651,049✔
155
                add_section(l, si->first, si->second, get_root());
194,315✔
156
        }
456,734✔
157
        return *this;
456,734✔
158
    }
×
159

160
    void section::read(std::string const& filename)
×
161
    {
162
#if defined(__AIX__) && defined(__GNUC__)
163
        // NEVER ask why... seems to be some weird stdlib initialization problem
164
        // If you don't call getline() here the while(getline...) loop below will
165
        // crash with a bad_cast exception. Stupid AIX...
166
        std::string l1;
167
        std::ifstream i1;
168
        i1.open(filename.c_str(), std::ios::in);
169
        std::getline(i1, l1);
170
        i1.close();
171
#endif
172

173
        // build ini - open file and parse each line
174
        std::ifstream input(filename.c_str(), std::ios::in);
×
175
        if (!input.is_open())
×
176
            line_msg("Cannot open file: ", filename);
×
177

178
        // read file
179
        std::string line;
×
180
        std::vector<std::string> lines;
×
181
        while (std::getline(input, line))
×
182
            lines.push_back(line);
×
183

184
        // parse file
185
        parse(filename, lines, false);
×
186
    }
×
187

188
    bool force_entry(std::string& str)
922,300✔
189
    {
190
        std::string::size_type p = str.find_last_of('!');
922,300✔
191
        if (p != std::string::npos &&
922,300✔
192
            str.find_first_not_of(" \t", p + 1) == std::string::npos)
24,981✔
193
        {
194
            str = str.substr(0, p);    // remove forcing modifier ('!')
24,981✔
195
            return true;
24,981✔
196
        }
197
        return false;
897,319✔
198
    }
922,300✔
199

200
    // parse file
201
    void section::parse(std::string const& sourcename,
19,265✔
202
        std::vector<std::string> const& lines, bool verify_existing,
203
        bool weed_out_comments, bool replace_existing)
204
    {
205
        int linenum = 0;
19,265✔
206
        section* current = this;
19,265✔
207

208
        std::regex regex_comment(pattern_comment, std::regex_constants::icase);
19,265✔
209

210
        std::vector<std::string>::const_iterator end = lines.end();
19,265✔
211
        for (std::vector<std::string>::const_iterator it = lines.begin();
1,114,988✔
212
             it != end; ++it)
1,114,988✔
213
        {
214
            ++linenum;
1,095,723✔
215

216
            // remove trailing new lines and white spaces
217
            std::string line(detail::trim_whitespace(*it));
1,095,723✔
218

219
            // skip if empty line
220
            if (line.empty())
1,095,723✔
221
                continue;
2,986✔
222

223
            // weed out comments
224
            if (weed_out_comments)
1,092,737✔
225
            {
226
                std::smatch what_comment;
594✔
227
                if (std::regex_match(line, what_comment, regex_comment))
594✔
228
                {
229
                    HPX_ASSERT(3 == what_comment.size());
×
230

231
                    line = detail::trim_whitespace(what_comment[1]);
×
232
                    if (line.empty())
×
233
                        continue;
×
234
                }
×
235
            }
594✔
236
            // no comments anymore: line is either section, key=val,
237
            // or garbage/empty
238

239
            // Check if we have a section.
240
            // Example: [sec.ssec]
241
            if (line.front() == '[' && line.back() == ']')
1,092,737✔
242
            {
243
                current = this;    // start adding sections at the root
170,437✔
244

245
                // got the section name. It might be hierarchical, so split it up, and
246
                // for each elem, check if we have it.  If not, create it, and add
247
                std::string sec_name(line.substr(1, line.size() - 2));
170,437✔
248
                std::string::size_type pos = 0;
170,437✔
249
                for (std::string::size_type pos1 = sec_name.find_first_of('.');
459,715✔
250
                     std::string::npos != pos1;
459,715✔
251
                     pos1 = sec_name.find_first_of('.', pos = pos1 + 1))
289,278✔
252
                {
253
                    current = current->add_section_if_new(
289,278✔
254
                        sec_name.substr(pos, pos1 - pos));
289,278✔
255
                }
289,278✔
256

257
                current = current->add_section_if_new(sec_name.substr(pos));
170,437✔
258
                continue;
259
            }
170,437✔
260

261
            // Check if we have a key=val entry...
262
            std::string::size_type assign_pos = line.find('=');
922,300✔
263
            if (assign_pos != std::string::npos)
922,300✔
264
            {
265
                std::string sec_key =
266
                    detail::trim_whitespace(line.substr(0, assign_pos));
922,300✔
267

268
                section* s = current;    // save the section we're in
922,300✔
269
                current = this;          // start adding sections at the root
922,300✔
270

271
                std::string::size_type pos = 0;
922,300✔
272

273
                // Check if we have a qualified key name
274
                // Example: hpx.commandline.allow_unknown
275
                for (std::string::size_type dot_pos =
1,074,369✔
276
                         sec_key.find_first_of('.');
922,300✔
277
                     std::string::npos != dot_pos;
1,074,369✔
278
                     dot_pos = sec_key.find_first_of('.', pos = dot_pos + 1))
152,069✔
279
                {
280
                    current = current->add_section_if_new(
152,069✔
281
                        sec_key.substr(pos, dot_pos - pos));
152,069✔
282
                }
152,069✔
283

284
                // if we don't have section qualifiers, restore current...
285
                if (current == this)
922,300✔
286
                {
287
                    current = s;
832,705✔
288
                }
832,705✔
289

290
                std::string key = sec_key.substr(pos);
922,300✔
291

292
                // add key/val to this section
293
                std::unique_lock<mutex_type> l(current->mtx_);
922,300✔
294

295
                if (!force_entry(key) && verify_existing &&
986,914✔
296
                    !current->has_entry(l, key))
64,614✔
297
                {
298
                    line_msg("Attempt to initialize unknown entry: ",
×
299
                        sourcename, linenum, line);
×
300
                }
×
301

302
                if (replace_existing || !current->has_entry(l, key))
922,300✔
303
                {
304
                    std::string value = detail::trim_whitespace(line.substr(
469,808✔
305
                        assign_pos + 1, line.size() - assign_pos - 1));
469,808✔
306
                    current->add_entry(l, key, key, value);
469,808✔
307
                }
469,808✔
308

309
                // restore the old section
310
                current = s;
922,300✔
311
            }
922,300✔
312
            else
313
            {
314
                // Hmm, is not a section, is not an entry, is not empty - must be
315
                // an error!
316
                line_msg("Cannot parse line at: ", sourcename, linenum, line);
×
317
            }
318
        }
1,095,723✔
319
    }
19,265✔
320

321
    ///////////////////////////////////////////////////////////////////////////////
322
    void section::add_section(std::unique_lock<mutex_type>& /* l */,
456,734✔
323
        std::string const& sec_name, section& sec, section* root)
324
    {
325
        // setting name and root
326
        sec.name_ = sec_name;
456,734✔
327
        sec.parent_name_ = get_full_name();
456,734✔
328

329
        section& newsec = sections_[sec_name];
456,734✔
330
        newsec.clone_from(sec, (nullptr != root) ? root : get_root());
456,734✔
331
    }
456,734✔
332

333
    ///////////////////////////////////////////////////////////////////////////
334
    section* section::add_section_if_new(
613,550✔
335
        std::unique_lock<mutex_type>& l, std::string const& sec_name)
336
    {
337
        // do we know this one?
338
        if (!has_section(l, sec_name))
613,550✔
339
        {
340
            // no - add it!
341
            section sec;
55,306✔
342
            add_section(l, sec_name, sec, get_root());
55,306✔
343
        }
55,306✔
344

345
        return get_section(l, sec_name);
613,550✔
346
    }
×
347

348
    bool section::has_section(
740,051✔
349
        std::unique_lock<mutex_type>& l, std::string const& sec_name) const
350
    {
351
        std::string::size_type i = sec_name.find('.');
740,051✔
352
        if (i != std::string::npos)
740,051✔
353
        {
354
            std::string cor_sec_name = sec_name.substr(0, i);
75,046✔
355

356
            section_map::const_iterator it = sections_.find(cor_sec_name);
75,046✔
357
            if (it != sections_.end())
75,046✔
358
            {
359
                std::string sub_sec_name = sec_name.substr(i + 1);
75,046✔
360
                hpx::unlock_guard<std::unique_lock<mutex_type>> ul(l);
75,046✔
361
                return (*it).second.has_section(sub_sec_name);
75,046✔
362
            }
75,046✔
363
            return false;
×
364
        }
75,046✔
365
        return sections_.find(sec_name) != sections_.end();
665,005✔
366
    }
740,051✔
367

368
    section* section::get_section(
674,118✔
369
        std::unique_lock<mutex_type>& l, std::string const& sec_name)
370
    {
371
        std::string::size_type i = sec_name.find('.');
674,118✔
372
        if (i != std::string::npos)
674,118✔
373
        {
374
            std::string cor_sec_name = sec_name.substr(0, i);
39,494✔
375
            section_map::iterator it = sections_.find(cor_sec_name);
39,494✔
376
            if (it != sections_.end())
39,494✔
377
            {
378
                std::string sub_sec_name = sec_name.substr(i + 1);
39,494✔
379
                hpx::unlock_guard<std::unique_lock<mutex_type>> ul(l);
39,494✔
380
                return (*it).second.get_section(sub_sec_name);
39,494✔
381
            }
39,494✔
382

383
            std::string name(get_name());
×
384
            if (name.empty())
×
385
                name = "<root>";
×
386

387
            HPX_THROW_EXCEPTION(hpx::error::bad_parameter,
×
388
                "section::get_section", "No such section ({}) in section: {}",
389
                sec_name, name);
390
            return nullptr;
391
        }
39,494✔
392

393
        section_map::iterator it = sections_.find(sec_name);
634,624✔
394
        if (it != sections_.end())
634,624✔
395
            return &((*it).second);
634,624✔
396

397
        HPX_THROW_EXCEPTION(hpx::error::bad_parameter, "section::get_section",
×
398
            "No such section ({}) in section: {}", sec_name, get_name());
399
        return nullptr;
400
    }
674,118✔
401

402
    section const* section::get_section(
162,267✔
403
        std::unique_lock<mutex_type>& l, std::string const& sec_name) const
404
    {
405
        std::string::size_type i = sec_name.find('.');
162,267✔
406
        if (i != std::string::npos)
162,267✔
407
        {
408
            std::string cor_sec_name = sec_name.substr(0, i);
88,364✔
409
            section_map::const_iterator it = sections_.find(cor_sec_name);
88,364✔
410
            if (it != sections_.end())
88,364✔
411
            {
412
                std::string sub_sec_name = sec_name.substr(i + 1);
88,364✔
413
                hpx::unlock_guard<std::unique_lock<mutex_type>> ul(l);
88,364✔
414
                return (*it).second.get_section(sub_sec_name);
88,364✔
415
            }
88,364✔
416

417
            std::string name(get_name());
×
418
            if (name.empty())
×
419
                name = "<root>";
×
420

421
            HPX_THROW_EXCEPTION(hpx::error::bad_parameter,
×
422
                "section::get_section", "No such section ({}) in section: {}",
423
                sec_name, name);
424
            return nullptr;
425
        }
88,364✔
426

427
        section_map::const_iterator it = sections_.find(sec_name);
73,903✔
428
        if (it != sections_.end())
73,903✔
429
            return &((*it).second);
73,903✔
430

431
        HPX_THROW_EXCEPTION(hpx::error::bad_parameter, "section::get_section",
×
432
            "No such section ({}) in section: {}", sec_name, get_name());
433
        return nullptr;
434
    }
162,267✔
435

436
    void section::add_entry(std::unique_lock<mutex_type>& l,
470,587✔
437
        std::string const& fullkey, std::string const& key, std::string val)
438
    {
439
        // first expand the full property name in the value (avoids infinite recursion)
440
        expand_only(
470,587✔
441
            l, val, std::string::size_type(-1), get_full_name() + "." + key);
470,587✔
442

443
        std::string::size_type i = key.find_last_of('.');
470,587✔
444
        if (i != std::string::npos)
470,587✔
445
        {
446
            section* current = root_;
20✔
447

448
            // make sure all sections in key exist
449
            std::string sec_name = key.substr(0, i);
20✔
450

451
            std::string::size_type pos = 0;
20✔
452
            for (std::string::size_type pos1 = sec_name.find_first_of('.');
44✔
453
                 std::string::npos != pos1;
44✔
454
                 pos1 = sec_name.find_first_of('.', pos = pos1 + 1))
24✔
455
            {
456
                current = current->add_section_if_new(
24✔
457
                    l, sec_name.substr(pos, pos1 - pos));
24✔
458
            }
24✔
459

460
            current = current->add_section_if_new(l, sec_name.substr(pos));
20✔
461

462
            // now add this entry to the section
463
            current->add_entry(l, fullkey, key.substr(i + 1), val);
20✔
464
        }
20✔
465
        else
466
        {
467
            entry_map::iterator it = entries_.find(key);
470,567✔
468
            if (it != entries_.end())
470,567✔
469
            {
470
                auto& e = it->second;
215,814✔
471
                e.first = HPX_MOVE(val);
215,814✔
472
                if (!e.second.empty())
215,814✔
473
                {
474
                    std::string value = e.first;
2✔
475
                    entry_changed_func f = e.second;
2✔
476

477
                    hpx::unlock_guard<std::unique_lock<mutex_type>> ul(l);
2✔
478
                    f(fullkey, value);
2✔
479
                }
2✔
480
            }
215,814✔
481
            else
482
            {
483
                // just add this entry to the section
484
                entries_[key] = entry_type(val, entry_changed_func());
254,753✔
485
            }
486
        }
487
    }
470,587✔
488

489
    void section::add_entry(std::unique_lock<mutex_type>& l,
3,741,390✔
490
        std::string const& fullkey, std::string const& key,
491
        entry_type const& val)
492
    {
493
        std::string::size_type i = key.find_last_of('.');
3,741,390✔
494
        if (i != std::string::npos)
3,741,390✔
495
        {
496
            section* current = root_;
×
497

498
            // make sure all sections in key exist
499
            std::string sec_name = key.substr(0, i);
×
500

501
            std::string::size_type pos = 0;
×
502
            for (std::string::size_type pos1 = sec_name.find_first_of('.');
×
503
                 std::string::npos != pos1;
×
504
                 pos1 = sec_name.find_first_of('.', pos = pos1 + 1))
×
505
            {
506
                current = current->add_section_if_new(
×
507
                    l, sec_name.substr(pos, pos1 - pos));
×
508
            }
×
509

510
            current = current->add_section_if_new(l, sec_name.substr(pos));
×
511

512
            // now add this entry to the section
513
            current->add_entry(l, fullkey, key.substr(i + 1), val);
×
514
        }
×
515
        else
516
        {
517
            entry_map::iterator it = entries_.find(key);
3,741,390✔
518
            if (it != entries_.end())
3,741,390✔
519
            {
520
                auto& second = it->second;
×
521
                second = val;
×
522
                if (!second.second.empty())
×
523
                {
524
                    std::string value = second.first;
×
525
                    entry_changed_func f = second.second;
×
526

527
                    hpx::unlock_guard<std::unique_lock<mutex_type>> ul(l);
×
528
                    f(fullkey, value);
×
529
                }
×
530
            }
×
531
            else
532
            {
533
                // just add this entry to the section
534
                std::pair<entry_map::iterator, bool> p =
535
                    entries_.emplace(key, val);
3,741,390✔
536
                HPX_ASSERT(p.second);
3,741,390✔
537

538
                auto& second = p.first->second;
3,741,390✔
539
                if (!second.second.empty())
3,741,390✔
540
                {
541
                    std::string key = p.first->first;
×
542
                    std::string value = second.first;
×
543
                    entry_changed_func f = second.second;
×
544

545
                    hpx::unlock_guard<std::unique_lock<mutex_type>> ul(l);
×
546
                    f(key, value);
×
547
                }
×
548
            }
549
        }
550
    }
3,741,390✔
551

552
    ///////////////////////////////////////////////////////////////////////////////
553
    template <typename F1, typename F2>
554
    class compose_callback_impl
34✔
555
    {
556
    public:
557
        template <typename A1, typename A2>
558
        compose_callback_impl(A1&& f1, A2&& f2)
10✔
559
          : f1_(HPX_FORWARD(A1, f1))
10✔
560
          , f2_(HPX_FORWARD(A2, f2))
10✔
561
        {
562
        }
10✔
563

564
        void operator()(std::string const& k, std::string const& v) const
×
565
        {
566
            f1_(k, v);
×
567
            f2_(k, v);
×
568
        }
×
569

570
    private:
571
        F1 f1_;
572
        F2 f2_;
573
    };
574

575
    template <typename F1, typename F2>
576
    static HPX_FORCEINLINE
577
        hpx::function<void(std::string const&, std::string const&)>
578
        compose_callback(F1&& f1, F2&& f2)
574✔
579
    {
580
        if (!f1)
574✔
581
            return HPX_FORWARD(F2, f2);
×
582
        else if (!f2)
574✔
583
            return HPX_FORWARD(F1, f1);
564✔
584

585
        // otherwise create a combined callback
586
        using result_type =
587
            compose_callback_impl<std::decay_t<F1>, std::decay_t<F2>>;
588
        return result_type(HPX_FORWARD(F1, f1), HPX_FORWARD(F2, f2));
10✔
589
    }
574✔
590

591
    void section::add_notification_callback(std::unique_lock<mutex_type>& l,
1,148✔
592
        std::string const& key, entry_changed_func const& callback)
593
    {
594
        std::string::size_type i = key.find_last_of('.');
1,148✔
595
        if (i != std::string::npos)
1,148✔
596
        {
597
            section* current = root_;
574✔
598

599
            // make sure all sections in key exist
600
            std::string sec_name = key.substr(0, i);
574✔
601

602
            std::string::size_type pos = 0;
574✔
603
            for (std::string::size_type pos1 = sec_name.find_first_of('.');
1,722✔
604
                 std::string::npos != pos1;
1,722✔
605
                 pos1 = sec_name.find_first_of('.', pos = pos1 + 1))
1,148✔
606
            {
607
                current = current->add_section_if_new(
1,148✔
608
                    l, sec_name.substr(pos, pos1 - pos));
1,148✔
609
            }
1,148✔
610

611
            current = current->add_section_if_new(l, sec_name.substr(pos));
574✔
612

613
            // now add this entry to the section
614
            current->add_notification_callback(l, key.substr(i + 1), callback);
574✔
615
        }
574✔
616
        else
617
        {
618
            // just add this entry to the section
619
            entry_map::iterator it = entries_.find(key);
574✔
620
            if (it != entries_.end())
574✔
621
            {
622
                it->second.second =
574✔
623
                    compose_callback(callback, it->second.second);
574✔
624
            }
574✔
625
            else
626
            {
627
                entries_[key] = entry_type("", callback);
×
628
            }
629
        }
630
    }
1,148✔
631

632
    bool section::has_entry(
739,544✔
633
        std::unique_lock<mutex_type>& l, std::string const& key) const
634
    {
635
        std::string::size_type i = key.find('.');
739,544✔
636
        if (i != std::string::npos)
739,544✔
637
        {
638
            std::string sub_sec = key.substr(0, i);
1✔
639
            if (has_section(l, sub_sec))
1✔
640
            {
641
                std::string sub_key = key.substr(i + 1, key.size() - i);
1✔
642
                section_map::const_iterator cit = sections_.find(sub_sec);
1✔
643
                HPX_ASSERT(cit != sections_.end());
1✔
644
                hpx::unlock_guard<std::unique_lock<mutex_type>> ul(l);
1✔
645
                return (*cit).second.has_entry(sub_key);    //-V783
1✔
646
            }
1✔
647
            return false;
×
648
        }
1✔
649
        return entries_.find(key) != entries_.end();
739,543✔
650
    }
739,544✔
651

652
    std::string section::get_entry(
71,499✔
653
        std::unique_lock<mutex_type>& l, std::string const& key) const
654
    {
655
        std::string::size_type i = key.find('.');
71,499✔
656
        if (i != std::string::npos)
71,499✔
657
        {
658
            std::string sub_sec = key.substr(0, i);
14,553✔
659
            if (has_section(l, sub_sec))
14,553✔
660
            {
661
                std::string sub_key = key.substr(i + 1, key.size() - i);
14,553✔
662
                section_map::const_iterator cit = sections_.find(sub_sec);
14,553✔
663
                HPX_ASSERT(cit != sections_.end());
14,553✔
664
                hpx::unlock_guard<std::unique_lock<mutex_type>> ul(l);
14,553✔
665
                return (*cit).second.get_entry(sub_key);    //-V783
14,553✔
666
            }
14,553✔
667

668
            HPX_THROW_EXCEPTION(hpx::error::bad_parameter, "section::get_entry",
×
669
                "No such key ({}) in section: {}", key, get_name());
670
            return "";
671
        }
14,553✔
672

673
        if (entries_.find(key) != entries_.end())
56,946✔
674
        {
675
            entry_map::const_iterator cit = entries_.find(key);
56,946✔
676
            HPX_ASSERT(cit != entries_.end());
56,946✔
677
            return expand(l, (*cit).second.first);    //-V783
56,946✔
678
        }
679

680
        HPX_THROW_EXCEPTION(hpx::error::bad_parameter, "section::get_entry",
×
681
            "No such section ({}) in section: {}", key, get_name());
682
        return "";
683
    }
71,499✔
684

685
    std::string section::get_entry(std::unique_lock<mutex_type>& l,
339,833✔
686
        std::string const& key, std::string const& default_val) const
687
    {
688
        typedef std::vector<std::string> string_vector;
689

690
        string_vector split_key;
339,830✔
691
        hpx::string_util::split(
339,830✔
692
            split_key, key, hpx::string_util::is_any_of("."));
339,830✔
693

694
        std::string sk = split_key.back();
339,829✔
695
        split_key.pop_back();
339,829✔
696

697
        section const* cur_section = this;
339,829✔
698
        for (string_vector::const_iterator iter = split_key.begin(),
1,009,912✔
699
                                           end = split_key.end();
339,829✔
700
             iter != end; ++iter)
670,083✔
701
        {
702
            section_map::const_iterator next =
703
                cur_section->sections_.find(*iter);
333,289✔
704
            if (cur_section->sections_.end() == next)
333,291✔
705
                return expand(l, default_val);
3,036✔
706
            cur_section = &next->second;
330,254✔
707
        }
330,254✔
708

709
        entry_map::const_iterator entry = cur_section->entries_.find(sk);
336,794✔
710
        if (cur_section->entries_.end() == entry)
336,793✔
711
            return expand(l, default_val);
36,852✔
712

713
        return expand(l, entry->second.first);
299,941✔
714
    }
339,827✔
715

716
    inline void indent(int ind, std::ostream& strm)
×
717
    {
718
        for (int i = 0; i < ind; ++i)
×
719
            strm << "  ";
×
720
    }
×
721

722
    void section::dump(int ind) const
×
723
    {
724
        return dump(ind, std::cout);
×
725
    }
726

727
    void section::dump(int ind, std::ostream& strm) const
×
728
    {
729
        std::unique_lock<mutex_type> l(mtx_);
×
730

731
        bool header = false;
×
732
        if (0 == ind)
×
733
            header = true;
×
734

735
        ++ind;
×
736
        if (header)
×
737
        {
738
            if (get_root() == this)
×
739
            {
740
                strm << "============================\n";
×
741
            }
×
742
            else
743
            {
744
                strm << "============================[\n"
×
745
                     << get_name() << "\n"
×
746
                     << "]\n";
×
747
            }
748
        }
×
749

750
        entry_map::const_iterator eend = entries_.end();
×
751
        for (entry_map::const_iterator i = entries_.begin(); i != eend; ++i)
×
752
        {
753
            indent(ind, strm);
×
754

755
            auto& second = i->second;
×
756
            std::string const expansion = expand(l, second.first);
×
757

758
            // Check if the expanded entry is different from the actual entry.
759
            if (expansion != second.first)
×
760
            {
761
                // If the expansion is different from the real entry, then print
762
                // it out.
763
                strm << "'" << i->first << "' : '" << second.first << "' -> '"
×
764
                     << expansion << "'\n";
×
765
            }
×
766
            else
767
            {
768
                strm << "'" << i->first << "' : '" << second.first << "'\n";
×
769
            }
770
        }
×
771

772
        section_map::const_iterator send = sections_.end();
×
773
        for (section_map::const_iterator i = sections_.begin(); i != send; ++i)
×
774
        {
775
            indent(ind, strm);
×
776
            strm << "[" << i->first << "]\n";
×
777
            (*i).second.dump(ind, strm);
×
778
        }
×
779

780
        if (header)
×
781
            strm << "============================\n";
×
782

783
        strm << std::flush;
×
784
    }
×
785

786
    void section::merge(std::string const& filename)
×
787
    {
788
        section tmp(filename, root_);
×
789
        merge(tmp);
×
790
    }
×
791

792
    void section::merge(section& second)
×
793
    {
794
        std::unique_lock<mutex_type> l(mtx_);
×
795

796
        // merge entries: keep own entries, and add other entries
797
        entry_map const& s_entries = second.get_entries();
×
798
        entry_map::const_iterator end = s_entries.end();
×
799
        for (entry_map::const_iterator i = s_entries.begin(); i != end; ++i)
×
800
            entries_[i->first] = i->second;
×
801

802
        // merge subsection known in first section
803
        section_map::iterator send = sections_.end();
×
804
        for (section_map::iterator i = sections_.begin(); i != send; ++i)
×
805
        {
806
            // is there something to merge with?
807
            if (second.has_section(l, i->first))
×
808
                i->second.merge(second.sections_[i->first]);
×
809
        }
×
810

811
        // merge subsection known in second section
812
        section_map s = second.get_sections();
×
813
        section_map::iterator secend = s.end();
×
814
        for (section_map::iterator i = s.begin(); i != secend; ++i)
×
815
        {
816
            // if THIS knows the section, we already merged it above
817
            if (!has_section(l, i->first))
×
818
            {
819
                // it is not known here, so we can't merge, but have to add it.
820
                add_section(l, i->first, i->second, get_root());
×
821
            }
×
822
        }
×
823
    }
×
824

825
    /////////////////////////////////////////////////////////////////////////////////
826
    void section::line_msg(std::string msg, std::string const& file, int lnum,
×
827
        std::string const& line)
828
    {
829
        msg += " " + file;
×
830
        if (lnum > 0)
×
831
            msg += ": line " + std::to_string(lnum);
×
832
        if (!line.empty())
×
833
            msg += " (offending entry: " + line + ")";
×
834

835
        HPX_THROW_EXCEPTION(hpx::error::no_success, "section::line_msg", msg);
×
836
    }
×
837

838
    ///////////////////////////////////////////////////////////////////////////////
839
    // find the matching closing brace starting from 'begin', escaped braces will
840
    // be un-escaped
841
    inline std::string::size_type find_next(char const* ch, std::string& value,
866,228✔
842
        std::string::size_type begin = static_cast<std::string::size_type>(-1))
843
    {
844
        std::string::size_type end = value.find_first_of(ch, begin + 1);
866,228✔
845
        while (end != std::string::npos)
866,228✔
846
        {
847
            if (end != 0 && value[end - 1] != '\\')
675,649✔
848
                break;
675,649✔
849
            value = detail::replace_substr(value, end - 1, 2, ch);
×
850
            end = value.find_first_of(ch, end);
×
851
        }
852
        return end;
866,228✔
853
    }
854

855
    ///////////////////////////////////////////////////////////////////////////////
856
    void section::expand(std::unique_lock<mutex_type>& l, std::string& value,
446,948✔
857
        std::string::size_type begin) const
858
    {
859
        std::string::size_type p = value.find_first_of('$', begin + 1);
446,948✔
860
        while (p != std::string::npos && value.size() - 1 != p)
526,472✔
861
        {
862
            if ('[' == value[p + 1])
79,524✔
863
                expand_bracket(l, value, p);
50,172✔
864
            else if ('{' == value[p + 1])
29,352✔
865
                expand_brace(l, value, p);
×
866
            p = value.find_first_of('$', p + 1);
79,524✔
867
        }
868
    }
446,948✔
869

870
    void section::expand_bracket(std::unique_lock<mutex_type>& l,
50,172✔
871
        std::string& value, std::string::size_type begin) const
872
    {
873
        // expand all keys embedded inside this key
874
        expand(l, value, begin);
50,172✔
875

876
        // now expand the key itself
877
        std::string::size_type end = find_next("]", value, begin + 1);
50,172✔
878
        if (end != std::string::npos)
50,172✔
879
        {
880
            std::string to_expand = value.substr(begin + 2, end - begin - 2);
50,172✔
881
            std::string::size_type colon = find_next(":", to_expand);
50,172✔
882
            if (colon == std::string::npos)
50,172✔
883
            {
884
                value = detail::replace_substr(value, begin, end - begin + 1,
50,172✔
885
                    root_->get_entry(l, to_expand, std::string()));
50,172✔
886
            }
50,172✔
887
            else
888
            {
889
                value = detail::replace_substr(value, begin, end - begin + 1,
×
890
                    root_->get_entry(l, to_expand.substr(0, colon),
×
891
                        to_expand.substr(colon + 1)));
×
892
            }
893
        }
50,172✔
894
    }
50,172✔
895

896
    void section::expand_brace(std::unique_lock<mutex_type>& l,
×
897
        std::string& value, std::string::size_type begin) const
898
    {
899
        // expand all keys embedded inside this key
900
        expand(l, value, begin);
×
901

902
        // now expand the key itself
903
        std::string::size_type end = find_next("}", value, begin + 1);
×
904
        if (end != std::string::npos)
×
905
        {
906
            std::string to_expand = value.substr(begin + 2, end - begin - 2);
×
907
            std::string::size_type colon = find_next(":", to_expand);
×
908
            if (colon == std::string::npos)
×
909
            {
910
                char* env = getenv(to_expand.c_str());
×
911
                value = detail::replace_substr(
×
912
                    value, begin, end - begin + 1, nullptr != env ? env : "");
×
913
            }
×
914
            else
915
            {
916
                char* env = getenv(to_expand.substr(0, colon).c_str());
×
917
                value = detail::replace_substr(value, begin, end - begin + 1,
×
918
                    nullptr != env ? std::string(env) :
×
919
                                     to_expand.substr(colon + 1));
×
920
            }
921
        }
×
922
    }
×
923

924
    std::string section::expand(
396,774✔
925
        std::unique_lock<mutex_type>& l, std::string value) const
926
    {
927
        expand(l, value, std::string::size_type(-1));
396,774✔
928
        return value;
396,774✔
929
    }
930

931
    ///////////////////////////////////////////////////////////////////////////////
932
    void section::expand_only(std::unique_lock<mutex_type>& l,
853,529✔
933
        std::string& value, std::string::size_type begin,
934
        std::string const& expand_this) const
935
    {
936
        std::string::size_type p = value.find_first_of('$', begin + 1);
853,529✔
937
        while (p != std::string::npos && value.size() - 1 != p)
1,469,799✔
938
        {
939
            if ('[' == value[p + 1])
616,270✔
940
                expand_bracket_only(l, value, p, expand_this);
133,069✔
941
            else if ('{' == value[p + 1])
483,201✔
942
                expand_brace_only(l, value, p, expand_this);
249,873✔
943
            p = value.find_first_of('$', p + 1);
616,270✔
944
        }
945
    }
853,529✔
946

947
    void section::expand_bracket_only(std::unique_lock<mutex_type>& l,
133,069✔
948
        std::string& value, std::string::size_type begin,
949
        std::string const& expand_this) const
950
    {
951
        // expand all keys embedded inside this key
952
        expand_only(l, value, begin, expand_this);
133,069✔
953

954
        // now expand the key itself
955
        std::string::size_type end = find_next("]", value, begin + 1);
133,069✔
956
        if (end != std::string::npos)
133,069✔
957
        {
958
            std::string to_expand = value.substr(begin + 2, end - begin - 2);
133,069✔
959
            std::string::size_type colon = find_next(":", to_expand);
133,069✔
960
            if (colon == std::string::npos)
133,069✔
961
            {
962
                if (to_expand == expand_this)
133,069✔
963
                {
964
                    value =
×
965
                        detail::replace_substr(value, begin, end - begin + 1,
×
966
                            root_->get_entry(l, to_expand, std::string()));
×
967
                }
×
968
            }
133,069✔
969
            else if (to_expand.substr(0, colon) == expand_this)
×
970
            {
971
                value = detail::replace_substr(value, begin, end - begin + 1,
×
972
                    root_->get_entry(l, to_expand.substr(0, colon),
×
973
                        to_expand.substr(colon + 1)));
×
974
            }
×
975
        }
133,069✔
976
    }
133,069✔
977

978
    void section::expand_brace_only(std::unique_lock<mutex_type>& l,
249,873✔
979
        std::string& value, std::string::size_type begin,
980
        std::string const& expand_this) const
981
    {
982
        // expand all keys embedded inside this key
983
        expand_only(l, value, begin, expand_this);
249,873✔
984

985
        // now expand the key itself
986
        std::string::size_type end = find_next("}", value, begin + 1);
249,873✔
987
        if (end != std::string::npos)
249,873✔
988
        {
989
            std::string to_expand = value.substr(begin + 2, end - begin - 2);
249,873✔
990
            std::string::size_type colon = find_next(":", to_expand);
249,873✔
991
            if (colon == std::string::npos)
249,873✔
992
            {
993
                char* env = getenv(to_expand.c_str());
7,338✔
994
                value = detail::replace_substr(
7,338✔
995
                    value, begin, end - begin + 1, nullptr != env ? env : "");
7,338✔
996
            }
7,338✔
997
            else
998
            {
999
                char* env = getenv(to_expand.substr(0, colon).c_str());
242,535✔
1000
                value = detail::replace_substr(value, begin, end - begin + 1,
485,070✔
1001
                    nullptr != env ? std::string(env) :
485,067✔
1002
                                     to_expand.substr(colon + 1));
242,532✔
1003
            }
1004
        }
249,873✔
1005
    }
249,873✔
1006

1007
    std::string section::expand_only(std::unique_lock<mutex_type>& l,
×
1008
        std::string value, std::string const& expand_this) const
1009
    {
1010
        expand_only(l, value, std::string::size_type(-1), expand_this);
×
1011
        return value;
×
1012
    }
1013

1014
    ///////////////////////////////////////////////////////////////////////////////
1015
    template <typename Archive>
1016
    void section::save(Archive& ar, unsigned int const /* version */) const
×
1017
    {
1018
        ar << name_;
×
1019
        ar << parent_name_;
×
1020

1021
        std::uint64_t size = entries_.size();
×
1022
        ar << size;
×
1023
        for (auto const& val : entries_)
×
1024
        {
1025
            ar << val.first;
×
1026
        }
1027

1028
        ar << sections_;
×
1029
    }
×
1030

1031
    template <typename Archive>
1032
    void section::load(Archive& ar, unsigned int const /* version */)
×
1033
    {
1034
        ar >> name_;
×
1035
        ar >> parent_name_;
×
1036

1037
        std::uint64_t size;
1038
        ar >> size;    //-V128
×
1039

1040
        entries_.clear();
×
1041
        for (std::size_t i = 0; i < size; ++i)
×
1042
        {
1043
            using value_type = typename entry_map::value_type;
1044

1045
            value_type v;
×
1046
            ar >> const_cast<std::string&>(v.first);
×
1047
            entries_.insert(entries_.end(), HPX_MOVE(v));
×
1048
        }
×
1049

1050
        ar >> sections_;
×
1051

1052
        set_root(this, true);    // make this the current root
×
1053
    }
×
1054

1055
    // explicit instantiation for the correct archive types
1056
    template HPX_CORE_EXPORT void section::save(
1057
        serialization::output_archive&, unsigned int const version) const;
1058

1059
    template HPX_CORE_EXPORT void section::load(
1060
        serialization::input_archive&, unsigned int const version);
1061
}    // namespace hpx::util
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

© 2026 Coveralls, Inc