Skip to content

Commit 20378c5

Browse files
committed
new fqname works
1 parent 559e7a9 commit 20378c5

File tree

5 files changed

+171
-46
lines changed

5 files changed

+171
-46
lines changed

src/parser/parse_fqname.cpp

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,33 +6,34 @@ namespace hk {
66

77
[[nodiscard]] static parse_result<fqname> parse_fqname(token_iterator& it, parse_context& ctx, bool absolute)
88
{
9+
using namespace std::literals;
10+
911
// Lookahead is maximum 8, dots followed by identifier.
1012
constexpr auto max_num_prefix_dots = 7uz;
1113

1214
auto const first = it->begin();
1315

14-
auto r = fqname{};
16+
auto r = std::string{};
1517

1618
auto num_prefix_dots = 0uz;
1719
if (absolute) {
18-
r.set_prefix(1);
20+
r = '.';
1921

2022
} else {
2123
for (; num_prefix_dots != max_num_prefix_dots; ++num_prefix_dots) {
2224
if (it[num_prefix_dots] != '.') {
2325
break;
2426
}
27+
r += '.';
2528
}
2629
if (num_prefix_dots == max_num_prefix_dots) {
2730
return tokens_did_not_match;
2831
}
29-
30-
r.set_prefix(num_prefix_dots);
3132
}
3233

3334
if (it[num_prefix_dots] == token::identifier) {
3435
if (auto id = it->identifier_value()) {
35-
r.append_component(*id);
36+
r += *id;
3637
it += num_prefix_dots + 1;
3738
} else {
3839
ctx.add((it + num_prefix_dots)->begin(), (it + num_prefix_dots)->end(), hkc_error::insecure_identifier, "identifier `{}`: {}", it->string_view(), id.error());
@@ -43,11 +44,12 @@ namespace hk {
4344
}
4445

4546
while (*it == ".") {
47+
r += '.';
4648
++it;
4749

4850
if (*it == token::identifier) {
4951
if (auto id = it->identifier_value()) {
50-
r.append_component(*id);
52+
r += *id;
5153
++it;
5254
} else {
5355
ctx.add(it->begin(), it->end(), hkc_error::insecure_identifier, "identifier `{}`: {}", it->string_view(), id.error());
@@ -58,7 +60,7 @@ namespace hk {
5860
}
5961
}
6062

61-
return r;
63+
return fqname{std::move(r)};
6264
}
6365

6466
[[nodiscard]] parse_result<fqname> parse_absolute_fqname(token_iterator& it, parse_context &ctx)

src/tokenizer/tokenizer.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11

22
#include "tokenizer.hpp"
33
#include "token_parsers.hpp"
4-
#include "utility/module.hpp"
54
#include "utility/fixed_fifo.hpp"
65
#include <gsl/gsl>
76
#include <cassert>

src/tokenizer/tokenizer.hpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
#include "token.hpp"
55
#include "line_table.hpp"
66
#include "char_category.hpp"
7-
#include "utility/module.hpp"
87
#include "utility/generator.hpp"
98
#include <concepts>
109
#include <string>

src/utility/fqname.hpp

Lines changed: 115 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -45,21 +45,16 @@ class fqname {
4545

4646
constexpr const_iterator(char const* first) noexcept :
4747
_first(first),
48-
_last(fixup_last(first))
48+
_last(fixup_last(first)) {}
4949

50-
[[nodiscard]] constexpr bool operator==(const_iterator const& rhs) noexcept
50+
[[nodiscard]] constexpr friend bool operator==(const_iterator const& lhs, const_iterator const& rhs) noexcept
5151
{
52-
return _first == rhs._first;
52+
return lhs._first == rhs._first;
5353
}
5454

55-
[[nodiscard]] constexpr bool operator==(std::default_sentinel_t) noexcept
55+
[[nodiscard]] constexpr friend bool operator==(const_iterator const& lhs, std::default_sentinel_t) noexcept
5656
{
57-
return _first == nullptr or *_first == '\0';
58-
}
59-
60-
[[nodiscard]] constexpr std::strong_ordering operator<=>(const_iterator const& rhs) noexcept
61-
{
62-
return _first <=> rhs._first;
57+
return lhs._first == nullptr or *lhs._first == '\0';
6358
}
6459

6560
constexpr const_iterator& operator++()
@@ -118,75 +113,158 @@ class fqname {
118113
constexpr fqname& operator=(fqname const&) = default;
119114
constexpr fqname& operator=(fqname&&) = default;
120115

116+
constexpr fqname(std::string_view other) : _str(other) {}
117+
constexpr fqname(std::string other) : _str(std::move(other)) {}
118+
constexpr fqname(char const *other) : _str(other) {}
119+
120+
[[nodiscard]] constexpr friend bool operator==(fqname const& lhs, fqname const& rhs) noexcept
121+
{
122+
return std::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
123+
}
124+
125+
[[nodiscard]] constexpr friend std::strong_ordering operator<=>(fqname const& lhs, fqname const& rhs) noexcept
126+
{
127+
return std::lexicographical_compare_three_way(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
128+
}
129+
121130
[[nodiscard]] constexpr std::string const& string() const noexcept
122131
{
123132
return _str;
124133
}
125134

126-
[[nodiscard]] const_iterator begin() const noexcept
135+
[[nodiscard]] constexpr size_t prefix() const noexcept
136+
{
137+
if (auto const i = _str.find_first_not_of('.'); i != _str.npos) {
138+
return i;
139+
} else {
140+
return _str.size();
141+
}
142+
}
143+
144+
[[nodiscard]] constexpr bool is_absolute() const noexcept
145+
{
146+
return prefix() == 1;
147+
}
148+
149+
[[nodiscard]] constexpr bool is_relative() const noexcept
150+
{
151+
return not is_absolute();
152+
}
153+
154+
[[nodiscard]] constexpr const_iterator begin() const noexcept
127155
{
128156
return const_iterator{_str.c_str()};
129157
}
130158

131-
[[nodiscard]] const_iterator end() const noexcept
159+
[[nodiscard]] constexpr const_iterator end() const noexcept
132160
{
133161
return const_iterator{_str.c_str() + _str.size()};
134162
}
135163

136-
bool pop_component()
164+
/** Pop the last component.
165+
*
166+
* Removes the last component, or:
167+
* - if empty, the result is: ..
168+
* - if absolute, the result is: .
169+
* - if there are only dots, add one more dot.
170+
*/
171+
constexpr void pop_component()
137172
{
173+
using namespace std::literals;
174+
138175
if (_str.empty()) {
139-
return false;
176+
_str = ".."s;
177+
} else if (auto const p = prefix(); p == _str.size()) {
178+
if (p != 1) {
179+
_str += '.';
180+
}
181+
} else {
182+
if (auto const i = _str.rfind('.'); i == _str.npos) {
183+
_str.clear();
184+
} else {
185+
_str.erase(i);
186+
}
140187
}
188+
}
189+
190+
constexpr fqname& add_component(std::string_view component)
191+
{
192+
assert(component.find('.') != component.npos);
193+
194+
if (component.empty()) {
195+
_str += '.';
141196

142-
if (auto const i = _str.rfind('.'); i == _str.npos) {
143-
_str.clear();
144-
return true;
145197
} else {
146-
_str.erase(i);
147-
return true;
198+
if (not _str.empty()) {
199+
_str += '.';
200+
}
201+
_str += component;
148202
}
203+
return *this;
149204
}
150205

151-
fqname& operator/=(std::string_view component)
206+
constexpr fqname& operator/=(fqname const& rhs)
152207
{
153-
assert(component.empty() or (component.first() != '.' and component.last() != '.'));
208+
if (rhs.is_absolute()) {
209+
*this = rhs;
210+
return *this;
211+
}
154212

155-
if (not _str.empty()) {
156-
_str += '.';
213+
for (auto component : rhs) {
214+
if (component.empty()) {
215+
pop_component();
216+
} else {
217+
add_component(component);
218+
}
157219
}
158-
_str += component;
159220
return *this;
160221
}
161222

162-
[[nodiscard]] fqname operator/(std::string_view component)
223+
constexpr fqname operator/(fqname const& rhs)
163224
{
164225
auto tmp = *this;
165-
tmp /= component;
226+
tmp /= rhs;
166227
return tmp;
167228
}
168229

169-
fqname& operator/=(fqname const& other)
230+
constexpr fqname& operator/=(std::string_view rhs)
170231
{
171-
if (other.is_absolute()) {
172-
*this = other;
173-
return *this;
174-
}
232+
return *this /= fqname{rhs};
233+
}
234+
235+
constexpr fqname operator/(std::string_view rhs)
236+
{
237+
return *this / fqname{rhs};
238+
}
175239

176-
auto leading = true;
177-
for (auto component : other) {
240+
/** Generate a lexically normal path.
241+
*
242+
*/
243+
constexpr fqname lexically_normal() const
244+
{
245+
auto r = fqname{};
246+
r._str.reserve(_str.size());
247+
248+
auto is_prefix = true;
249+
for (auto component: *this) {
178250
if (component.empty()) {
179-
assert(leading);
180-
pop_component();
251+
if (is_prefix) {
252+
r.add_component(component);
253+
} else {
254+
r.pop_component();
255+
}
181256
} else {
182-
leading = false;
183-
*this /= component;
257+
r.add_component(component);
258+
is_prefix = false;
184259
}
185260
}
261+
262+
return r;
186263
}
187264

188265
private:
189266
std::string _str = {};
267+
190268
};
191269

192270
} // namespace hk

src/utility/strings.hpp

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33

44
#include <string_view>
55
#include <string>
6+
#include <cstring>
7+
#include <bit>
8+
#include <cstddef>
69
#include <vector>
710

811
namespace hk {
@@ -15,4 +18,48 @@ namespace hk {
1518
*/
1619
[[nodiscard]] std::vector<std::string> split(std::string_view str, char delimiter);
1720

21+
/** Count the length of the prefix of specific characters.
22+
*
23+
* This uses an fast algorithm
24+
*
25+
* @tparam C The character to look for
26+
* @param str The string to check the prefix off.
27+
* @return The number of @a C character at the start of the string.
28+
*/
29+
template<char C>
30+
[[nodiscard]] constexpr size_t prefix_count(std::string_view str)
31+
{
32+
constexpr auto dots = []{
33+
auto r = 0uz;
34+
for (auto i = 0uz; i != sizeof(r); ++i) {
35+
r <<= 8;
36+
r |= C;
37+
}
38+
return r;
39+
}();
40+
41+
auto const fast_size = (str.size() / sizeof(size_t)) * sizeof(size_t);
42+
auto i = 0uz;
43+
for (; i != fast_size; i += sizeof(size_t)) {
44+
size_t value = 0uz;
45+
std::memcpy(&value, str.data() + i, sizeof(value));
46+
if (std::endian::native == std::endian::little) {
47+
value = std::byteswap(value);
48+
}
49+
50+
value ^= dots;
51+
if (value != 0) {
52+
return i + std::countl_zero(value) / 8;
53+
}
54+
}
55+
56+
for (; i != str.size(); ++i) {
57+
if (str[i] != C) {
58+
return i;
59+
}
60+
}
61+
62+
return i;
63+
}
64+
1865
} // namespace hk

0 commit comments

Comments
 (0)