-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathconfig.hh
109 lines (96 loc) · 3.06 KB
/
config.hh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
// Copyright (c) 2022 Mikael Simonsson <https://mikaelsimonsson.com>.
// SPDX-License-Identifier: BSL-1.0
// # Config file parser
#pragma once
#include "snn-core/strcore.hh"
#include "snn-core/vec.hh"
#include "snn-core/ascii/trim.hh"
#include "snn-core/file/read.hh"
#include "snn-core/pair/common.hh"
#include "snn-core/range/contiguous.hh"
#include "snn-core/range/view/reverse.hh"
#include "snn-core/string/range/split.hh"
namespace snn::file
{
// ## Classes
// ### config
class config final
{
public:
config(const transient<null_term<const char*>> path)
: v_{container::reserve, 10}
{
parse_(path);
}
explicit operator bool() const noexcept
{
return !v_.is_empty();
}
// get<String>
template <constructible_from<const str&> String>
[[nodiscard]] String get(const transient<cstrview> key, const String def = String{}) const
{
for (const auto& kv : range::view::reverse{v_.range()})
{
if (kv.key == key.get())
{
return kv.value;
}
}
return def;
}
// get<Int>
template <strict_integral Int>
[[nodiscard]] Int get(const transient<cstrview> key, const Int def = 0) const
{
for (const auto& kv : range::view::reverse{v_.range()})
{
if (kv.key == key.get())
{
const auto p = kv.value.template to_prefix<Int>();
if (p.count == kv.value.size())
{
return p.value;
}
break;
}
}
return def;
}
template <any_strcore Str>
[[nodiscard]] Str to() const
{
Str s{container::reserve, v_.count() * 30}; // Only an estimate.
for (const auto& kv : v_)
{
s << kv.key << ": " << kv.value << '\n';
}
return s;
}
private:
vec<pair::key_value<str>> v_;
void parse_(const transient<null_term<const char*>> path)
{
auto contents = file::read<strbuf>(path).value();
for (cstrview line : string::range::split{contents, '\n'})
{
ascii::trim_inplace(line);
if (line && !line.has_front('#'))
{
const usize space_pos = line.find(' ').value_or_npos();
if (space_pos != constant::npos)
{
cstrview key = line.view(0, space_pos);
cstrview value = line.view(space_pos);
ascii::trim_inplace(key);
ascii::trim_inplace(value);
if (key && value)
{
v_.append_inplace(key, value);
}
}
}
}
}
};
}