RESTinio
Loading...
Searching...
No Matches
pcre2_regex_engine.hpp
Go to the documentation of this file.
1/*
2 restinio
3*/
4
5/*!
6 Regex engine for using std::regex.
7*/
8
9#pragma once
10
11#include <array>
12
13#include <pcre2.h>
14
15#include <restinio/impl/include_fmtlib.hpp>
16
17#include <restinio/exception.hpp>
18
19namespace restinio
20{
21
22namespace router
23{
24
26{
27
28//
29// match_results_t
30//
31
32//! A wrapper class for working with pcre match results.
33template < typename Traits >
34struct match_results_t final
35{
37 {
38 m_match_data = pcre2_match_data_create( Traits::max_capture_groups, nullptr );
39 }
40
42 {
43 if( nullptr != m_match_data )
44 pcre2_match_data_free( m_match_data );
45 }
46
47 match_results_t( const match_results_t & ) = delete;
49 match_results_t & operator = ( const match_results_t & ) = delete;
51
52 struct matched_item_descriptor_t final
53 {
55 PCRE2_SIZE begin,
56 PCRE2_SIZE end )
57 : m_begin{ begin }
58 , m_end{ end }
59 {}
60
61 PCRE2_SIZE m_begin;
62 PCRE2_SIZE m_end;
63 };
64
65 matched_item_descriptor_t
66 operator [] ( std::size_t i ) const
67 {
68 PCRE2_SIZE * submatches = pcre2_get_ovector_pointer( m_match_data );
69
70 return matched_item_descriptor_t{
71 submatches[ 2 * i ],
72 submatches[ 1 + 2 * i ] };
73 }
74
75 std::size_t size() const { return m_size; }
76
77 std::size_t m_size{ 0 };
78 pcre2_match_data * m_match_data;
79};
80
81//
82// regex_t
83//
84
85//! A wrapper for using pcre regexes in express_router.
86class regex_t final
87{
88 public:
89 regex_t() = default;
90 regex_t( string_view_t r, int options )
91 {
92 compile( r, options );
93 }
94
95 regex_t( const regex_t & ) = delete;
96 regex_t & operator = ( const regex_t & ) = delete;
97
98 regex_t( regex_t && rw ) noexcept
100 {
101 rw.m_route_regex = nullptr;
102 }
103
104 regex_t & operator = ( regex_t && rw ) noexcept
105 {
106 if( this != &rw )
107 {
108 m_route_regex = rw.m_route_regex;
109 rw.m_route_regex = nullptr;
110 }
111
112 return *this;
113 }
114
116 {
117 if( nullptr != m_route_regex )
118 {
119 pcre2_code_free( m_route_regex );
120 }
121 }
122
123 const pcre2_code *
125 {
126 return m_route_regex;
127 }
128
129 private:
130 pcre2_code * m_route_regex{ nullptr };
131
132 void
133 compile( string_view_t r, int options )
134 {
135 PCRE2_SIZE erroroffset;
136 int errorcode;
137
138 m_route_regex = pcre2_compile(
139 reinterpret_cast< const unsigned char*>( r.data() ),
140 r.size(),
141 static_cast<unsigned int>(options),
142 &errorcode,
143 &erroroffset,
144 nullptr );
145
146 if( nullptr == m_route_regex )
147 {
148 std::array< unsigned char, 256 > buffer;
149 (void)pcre2_get_error_message( errorcode, buffer.data(), buffer.size() );
150 throw exception_t{
151 fmt::format(
153 "unable to compile regex \"{}\": {}" ),
154 fmtlib_tools::streamed( r ),
155 reinterpret_cast< const char * >( buffer.data() ) ) };
156 }
157 }
158};
159
160} /* namespace pcre2_details */
161
162//
163// pcre_traits_t
164//
165
166//! PCRE traits.
167template < std::size_t Max_Capture_Groups = 20, int Compile_Options = 0, int Match_Options = 0 >
169{
170 static constexpr std::size_t max_capture_groups = Max_Capture_Groups;
171 static constexpr int compile_options = Compile_Options;
172 static constexpr int match_options = Match_Options;
173};
174
175//
176// pcre2_regex_engine_t
177//
178
179//! Regex engine implementation for PCRE2.
180template < typename Traits = pcre2_traits_t<> >
182{
186
187 // Max itemes that can be captured be pcre engine.
188 static constexpr std::size_t
190 {
191 return Traits::max_capture_groups;
192 }
193
194 //! Create compiled regex object for a given route.
195 static auto
197 //! Regular expression (the pattern).
198 string_view_t r,
199 //! Option for case sensativity.
200 bool is_case_sensative )
201 {
202 int options = Traits::compile_options;
203
204 if( !is_case_sensative )
205 {
206 options |= PCRE2_CASELESS;
207 }
208
209 return compiled_regex_t{ r, options };
210 }
211
212 //! Wrapper function for matching logic invokation.
213 static auto
215 string_view_t target_path,
216 const compiled_regex_t & r,
217 match_results_t & match_results )
218 {
219 const int rc =
220 pcre2_match(
221 r.pcre2_regex(),
222 reinterpret_cast< const unsigned char* >( target_path.data() ),
223 target_path.size(),
224 0, // startoffset
225 Traits::match_options,
226 match_results.m_match_data,
227 nullptr );
228
229 if( rc > 0 )
230 {
231 match_results.m_size = static_cast<std::size_t>(rc);
232 return true;
233 }
234 else if( rc == 0 )
235 {
236 // This should not happen,
237 // because the number of groups is checked when creating route matcher.
238 throw exception_t{ "unexpected: not enough submatch vector size" };
239 }
240 if( PCRE2_ERROR_NOMATCH != rc )
241 {
242 throw exception_t{
243 fmt::format( RESTINIO_FMT_FORMAT_STRING( "pcre2 error: {}" ), rc ) };
244 }
245 // else PCRE2_ERROR_NOMATCH -- no match for this route
246
247 return false;
248 }
249
250 //! Get the beginning of a submatch.
251 static auto
253 {
254 return static_cast< std::size_t >( m.m_begin );
255 }
256
257 //! Get the end of a submatch.
258 static auto
260 {
261 return static_cast< std::size_t >( m.m_end );
262 }
263};
264
265} /* namespace router */
266
267} /* namespace restinio */
Exception class for all exceptions thrown by RESTinio.
Definition exception.hpp:26
exception_t(const char *err)
Definition exception.hpp:29
regex_t & operator=(regex_t &&rw) noexcept
regex_t & operator=(const regex_t &)=delete
void compile(string_view_t r, int options)
#define RESTINIO_FMT_FORMAT_STRING(s)
match_results_t & operator=(const match_results_t &)=delete
match_results_t & operator=(match_results_t &&)=delete
match_results_t(const match_results_t &)=delete
matched_item_descriptor_t operator[](std::size_t i) const
Regex engine implementation for PCRE2.
pcre2_details::match_results_t< Traits > match_results_t
static auto submatch_end_pos(const matched_item_descriptor_t &m)
Get the end 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.
typename match_results_t::matched_item_descriptor_t matched_item_descriptor_t
static auto compile_regex(string_view_t r, bool is_case_sensative)
Create compiled regex object for a given route.
static auto submatch_begin_pos(const matched_item_descriptor_t &m)
Get the beginning of a submatch.
static constexpr std::size_t max_capture_groups()
static constexpr std::size_t max_capture_groups