RESTinio
pcre_regex_engine.hpp
Go to the documentation of this file.
1/*
2 restinio
3*/
4
9#pragma once
10
11#include <pcre.h>
12
14
16
17namespace restinio
18{
19
20namespace router
21{
22
23namespace pcre_details
24{
25
26
27//
28// match_results_t
29//
30
32template < typename Traits >
33struct match_results_t final
34{
36 {
38 int begin,
39 int end )
40 : m_begin{ begin }
41 , m_end{ end }
42 {}
43
45 int m_end;
46 };
47
49 operator [] ( std::size_t i ) const
50 {
51 if( m_submatches[ 2 * i ] >= 0 )
52 {
53 // Submatch has non-empty value.
55 m_submatches[ 2 * i ],
56 m_submatches[ 1 + 2 * i ] };
57 }
58
59 // This submatch group is empty.
60 return matched_item_descriptor_t{ 0, 0 };
61 }
62
63 std::size_t size() const { return m_size; }
64
65 std::size_t m_size{ 0 };
66 std::array< int, 3 * Traits::max_capture_groups > m_submatches;
67};
68
69//
70// regex_t
71//
72
74class regex_t final
75{
76 public:
77 regex_t() = default;
78 regex_t( string_view_t r, int options )
79 {
80 compile( r, options );
81 }
82
83 regex_t( const regex_t & ) = delete;
84 regex_t & operator = ( const regex_t & ) = delete;
85
86 regex_t( regex_t && rw ) noexcept
87 : m_route_regex{ rw.m_route_regex }
88 {
89 rw.m_route_regex = nullptr;
90 }
91
92 regex_t & operator = ( regex_t && rw ) noexcept
93 {
94 if( this != &rw )
95 {
96 m_route_regex = rw.m_route_regex;
97 rw.m_route_regex = nullptr;
98 }
99
100 return *this;
101 }
102
104 {
105 if( nullptr != m_route_regex )
106 {
107 pcre_free( m_route_regex );
108 }
109 }
110
111 const pcre *
113 {
114 return m_route_regex;
115 }
116
117 private:
118 pcre * m_route_regex{ nullptr };
119
120 void
121 compile( string_view_t r, int options )
122 {
123 const char* compile_error;
124 int eoffset;
125
126 // We need zero-terminated string.
127 const std::string route{ r.data(), r.size() };
128
129 m_route_regex = pcre_compile( route.c_str(), options, &compile_error, &eoffset, nullptr );
130
131 if( nullptr == m_route_regex )
132 {
133 throw exception_t{
134 fmt::format(
135 "unable to compile regex \"{}\": {}",
136 route,
137 compile_error ) };
138 }
139 }
140};
141
142} /* namespace pcre_details */
143
144//
145// pcre_traits_t
146//
147
149template < std::size_t Max_Capture_Groups = 20, int Compile_Options = 0, int Match_Options = 0 >
151{
152 static constexpr std::size_t max_capture_groups = Max_Capture_Groups;
153 static constexpr int compile_options = Compile_Options;
154 static constexpr int match_options = Match_Options;
155};
156
157//
158// pcre_regex_engine_t
159//
160
162template < typename Traits = pcre_traits_t<> >
164{
168
169 // Max itemes that can be captured be pcre engine.
170 static constexpr std::size_t
172 {
173 return Traits::max_capture_groups;
174 }
175
177 static auto
182 bool is_case_sensative )
183 {
184 int options = Traits::compile_options;
185
186 if( !is_case_sensative )
187 {
188 options |= PCRE_CASELESS;
189 }
190
191 return compiled_regex_t{ r, options };
192 }
193
195 static auto
197 string_view_t target_path,
198 const compiled_regex_t & r,
199 match_results_t & match_results )
200 {
201 const int rc =
202 pcre_exec(
203 r.pcre_regex(),
204 nullptr,
205 target_path.data(),
206 static_cast< int >( target_path.size() ),
207 0, // startoffset
208 Traits::match_options,
209 match_results.m_submatches.data(),
210 static_cast< int >( match_results.m_submatches.size() ) );
211
212 if( rc > 0 )
213 {
214 match_results.m_size = static_cast<std::size_t>(rc);
215 return true;
216 }
217 else if( rc == 0 )
218 {
219 // This should not happen,
220 // because the number of groups is checked when creating route matcher.
221 throw exception_t{ "unexpected: not enough submatch vector size" };
222 }
223 if( PCRE_ERROR_NOMATCH != rc )
224 {
225 throw exception_t{ fmt::format("pcre error: {}", rc ) };
226 }
227 // else PCRE_ERROR_NOMATCH -- no match for this route
228
229 return false;
230 }
231
233 static auto
235 {
236 return static_cast< std::size_t >( m.m_begin );
237 }
238
240 static auto
242 {
243 return static_cast< std::size_t >( m.m_end );
244 }
245};
246
247} /* namespace router */
248
249} /* namespace restinio */
Exception class for all exceptions thrown by RESTinio.
Definition: exception.hpp:26
A wrapper for using pcre regexes in express_router.
regex_t & operator=(const regex_t &)=delete
void compile(string_view_t r, int options)
regex_t(string_view_t r, int options)
A special wrapper around fmtlib include files.
nonstd::string_view string_view_t
Definition: string_view.hpp:19
A wrapper class for working with pcre match results.
matched_item_descriptor_t operator[](std::size_t i) const
std::array< int, 3 *Traits::max_capture_groups > m_submatches
Regex engine implementation for PCRE.
static constexpr std::size_t max_capture_groups()
static auto compile_regex(string_view_t r, bool is_case_sensative)
Create compiled regex object for a given route.
typename match_results_t::matched_item_descriptor_t matched_item_descriptor_t
static auto submatch_begin_pos(const matched_item_descriptor_t &m)
Get the beginning of a submatch.
static auto try_match(string_view_t target_path, const compiled_regex_t &r, match_results_t &match_results)
Wrapper function for matching logic invokation.
static auto submatch_end_pos(const matched_item_descriptor_t &m)
Get the end of a submatch.
static constexpr std::size_t max_capture_groups