-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathmatches.hh
157 lines (120 loc) · 3.99 KB
/
matches.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
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
// Copyright (c) 2022 Mikael Simonsson <https://mikaelsimonsson.com>.
// SPDX-License-Identifier: BSL-1.0
// # Matches
#pragma once
#include "snn-core/array_view.hh"
#include "snn-core/optional.hh"
#include "snn-core/math/common.hh"
#include "snn-core/pcre/core.hh"
#include "snn-core/pcre/error.hh"
#include "snn-core/pcre/match_view.hh"
namespace snn::pcre
{
// ## Classes
// ### matches
class matches final
{
public:
// #### Types
using trivially_relocatable_type = matches;
// #### Constructor
explicit matches(const not_null<pcre2_code_8*> code, const cstrview subject) noexcept
: match_data_{::pcre2_match_data_create_from_pattern_8(code.get(), nullptr)},
subject_{subject}
{
}
// #### Non-copyable
matches(const matches&) = delete;
matches& operator=(const matches&) = delete;
// #### Movable
matches(matches&& other) noexcept
: match_data_{std::exchange(other.match_data_, nullptr)},
subject_{std::exchange(other.subject_, cstrview{})},
count_{std::exchange(other.count_, 0)},
error_number_{std::exchange(other.error_number_, 0)}
{
}
matches& operator=(matches&& other) noexcept
{
std::swap(match_data_, other.match_data_);
std::swap(subject_, other.subject_);
std::swap(count_, other.count_);
std::swap(error_number_, other.error_number_);
return *this;
}
// #### Destructor
~matches()
{
::pcre2_match_data_free_8(match_data_); // Does nothing if nullptr.
}
// #### Explicit conversion operators
explicit operator bool() const noexcept
{
return !is_empty();
}
// #### Single element access
[[nodiscard]] optional<match_view> at(const usize pos) const noexcept
{
if (pos < count())
{
return at(pos, promise::within_bounds);
}
return nullopt;
}
[[nodiscard]] match_view at(const usize pos, promise::within_bounds_t) const noexcept
{
snn_assert(pos < count());
const usize* const ovector = ::pcre2_get_ovector_pointer_8(match_data_);
const usize index = pos * 2;
SNN_DIAGNOSTIC_PUSH
SNN_DIAGNOSTIC_IGNORE_UNSAFE_BUFFER_USAGE
const usize start_pos = ovector[index];
const usize end_pos = ovector[index + 1];
SNN_DIAGNOSTIC_POP
// Do not assume that the end position is greater than the start position (pcre2demo.c).
return match_view{subject_, math::min(start_pos, end_pos),
math::abs_diff(start_pos, end_pos)};
}
// #### Count
[[nodiscard]] u32 count() const noexcept
{
return count_;
}
[[nodiscard]] bool is_empty() const noexcept
{
return count_ == 0;
}
// #### Status
[[nodiscard]] int error_number() const noexcept
{
return error_number_;
}
[[nodiscard]] bool is_valid() const noexcept
{
return match_data_ != nullptr;
}
// #### Data
[[nodiscard]] not_null<pcre2_match_data_8*> data(promise::is_valid_t) const noexcept
{
snn_assert(is_valid());
return not_null{match_data_};
}
// #### Setters
void set_count(const u32 c) noexcept
{
if (is_valid())
{
count_ = math::min(c, ::pcre2_get_ovector_count_8(match_data_));
}
}
void set_error_number(const int n) noexcept
{
error_number_ = n;
}
private:
pcre2_match_data_8* match_data_;
cstrview subject_;
u32 count_{0};
int error_number_{0};
};
}