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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
|
/*
* This source code is released into the public domain.
*/
module;
#include <cstdlib>
#include <expected>
#include <format>
#include <iosfwd>
#include <string>
#include <ucl.h>
export module nihil.ucl:string;
import nihil;
import :object;
import :type;
namespace nihil::ucl {
export struct string final : object {
using contained_type = std::string_view;
inline static constexpr object_type ucl_type = object_type::string;
// string is a container of char
using value_type = char const;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
using reference = value_type &;
using pointer = value_type *;
using iterator = pointer;
/*
* Create a new empty string. Throws std::system_error on failure.
*/
string();
/*
* Create a string from a value. Throws std::system_error on failure.
*/
explicit string(std::string_view);
/*
* Create a string from a C literal. Throws std::system_error
* on failure.
*/
explicit string(char const *);
/*
* Create a string from a contiguous range. The range's value type
* must be char. Throws std::system_error on failure.
*/
template<std::ranges::contiguous_range Range>
requires (!std::same_as<std::string_view, Range> &&
std::same_as<char, std::ranges::range_value_t<Range>>)
explicit string(Range &&range)
: string(std::string_view(std::ranges::begin(range),
std::ranges::end(range)))
{}
/*
* Create a string from a non-contiguous range. This requires a
* temporary value due to limitations of the UCL C API.
*/
template<std::ranges::range Range>
requires (!std::ranges::contiguous_range<Range> &&
std::same_as<char, std::ranges::range_value_t<Range>>)
explicit string(Range &&range)
: string(std::string(std::from_range, range))
{}
/*
* Create a string from an iterator pair. The iterator's value type
* must be char. If the iterator pair is not contiguous, the value
* will be copied to a temporary first.
*
* Throws std::system_error on failure.
*/
template<std::input_iterator Iterator>
requires (std::same_as<char, std::iter_value_t<Iterator>>)
string(Iterator first, Iterator last)
: string(std::ranges::subrange(first, last))
{}
/*
* Create a new string from a UCL object. Throws type_mismatch
* on failure.
*/
string(ref_t, ::ucl_object_t const *uobj);
string(noref_t, ::ucl_object_t *uobj);
// Return the value of this string.
[[nodiscard]] auto value(this string const &self) -> contained_type;
// Return the size of this string.
[[nodiscard]] auto size(this string const &self) -> size_type;
// Test if this string is empty.
[[nodiscard]] auto empty(this string const &self) -> bool;
// Access this string's data
[[nodiscard]] auto data(this string const &self) -> pointer;
// Iterator access
[[nodiscard]] auto begin(this string const &self) -> iterator;
[[nodiscard]] auto end(this string const &self) -> iterator;
};
/*
* String constructors. These return an error instead of throwing.
*/
// Empty string
export [[nodiscard]] auto
make_string() -> std::expected<string, error>;
// From string_view
export [[nodiscard]] auto
make_string(std::string_view) -> std::expected<string, error>;
// From C literal
export [[nodiscard]] auto
make_string(char const *) -> std::expected<string, error>;
// From contiguous range
export template<std::ranges::contiguous_range Range>
requires (!std::same_as<std::string_view, Range> &&
std::same_as<char, std::ranges::range_value_t<Range>>)
[[nodiscard]] auto make_string(Range &&range)
{
return make_string(std::string_view(range));
}
// From non-contiguous range
export template<std::ranges::range Range>
requires (!std::ranges::contiguous_range<Range> &&
std::same_as<char, std::ranges::range_value_t<Range>>)
[[nodiscard]] auto make_string(Range &&range)
{
return make_string(std::string(std::from_range, range));
}
// From iterator pair
export template<std::input_iterator Iterator>
requires (std::same_as<char, std::iter_value_t<Iterator>>)
[[nodiscard]] auto make_string(Iterator first, Iterator last)
{
return make_string(std::ranges::subrange(first, last));
}
/*
* Comparison operators.
*/
export [[nodiscard]] auto operator== (string const &a, string const &b) -> bool;
export [[nodiscard]] auto operator<=> (string const &a, string const &b)
-> std::strong_ordering;
/*
* For convenience, allow comparison with C++ strings without having to
* construct a temporary UCL object.
*/
export [[nodiscard]] auto operator==(string const &lhs,
std::string_view rhs) -> bool;
export [[nodiscard]] auto operator==(string const &lhs,
std::string const &rhs) -> bool;
export [[nodiscard]] auto operator==(string const &lhs,
char const *rhs) -> bool;
export [[nodiscard]] auto operator<=>(string const &lhs,
std::string_view rhs)
-> std::strong_ordering;
export [[nodiscard]] auto operator<=>(string const &lhs,
std::string const &rhs)
-> std::strong_ordering;
export [[nodiscard]] auto operator<=>(string const &lhs,
char const *rhs)
-> std::strong_ordering;
/*
* Print a string to a stream.
*/
export auto operator<<(std::ostream &, string const &) -> std::ostream &;
/*
* Literal operator.
*/
inline namespace literals {
export constexpr auto operator""_ucl (char const *s, std::size_t n)
-> string
{
return string(std::string_view(s, n));
}
} // namespace nihil::ucl::literals
} // namespace nihil::ucl
namespace nihil { inline namespace literals {
export using namespace ::nihil::ucl::literals;
}} // namespace nihil::literals
/*
* std::formatter for a string. This provides the same format operations
* as std::formatter<std::string_view>.
*/
export template<>
struct std::formatter<nihil::ucl::string, char>
{
std::formatter<std::string_view> base_formatter;
template<class ParseContext>
constexpr ParseContext::iterator parse(ParseContext& ctx)
{
return base_formatter.parse(ctx);
}
template<class FmtContext>
FmtContext::iterator format(nihil::ucl::string const &o,
FmtContext& ctx) const
{
return base_formatter.format(o.value(), ctx);
}
};
|