RESTinio
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 
19 namespace restinio
20 {
21 
22 namespace router
23 {
24 
25 namespace pcre2_details
26 {
27 
28 //
29 // match_results_t
30 //
31 
32 //! A wrapper class for working with pcre match results.
33 template < typename Traits >
35 {
37  {
39  }
40 
42  {
43  if( nullptr != m_match_data )
45  }
46 
47  match_results_t( const match_results_t & ) = delete;
48  match_results_t( match_results_t && ) = delete;
49  match_results_t & operator = ( const match_results_t & ) = delete;
50  match_results_t & operator = ( 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 
63  };
64 
65  matched_item_descriptor_t
66  operator [] ( std::size_t i ) const
67  {
69 
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 };
79 };
80 
81 //
82 // regex_t
83 //
84 
85 //! A wrapper for using pcre regexes in express_router.
86 class 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 *
124  pcre2_regex() const
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(
152  RESTINIO_FMT_FORMAT_STRING(
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.
167 template < std::size_t Max_Capture_Groups = 20, int Compile_Options = 0, int Match_Options = 0 >
169 {
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.
180 template < typename Traits = pcre2_traits_t<> >
182 {
183  using compiled_regex_t = pcre2_details::regex_t;
184  using match_results_t = pcre2_details::match_results_t< Traits >;
185  using matched_item_descriptor_t = typename match_results_t::matched_item_descriptor_t;
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
252  submatch_begin_pos( const matched_item_descriptor_t & m )
253  {
254  return static_cast< std::size_t >( m.m_begin );
255  }
256 
257  //! Get the end of a submatch.
258  static auto
259  submatch_end_pos( const matched_item_descriptor_t & m )
260  {
261  return static_cast< std::size_t >( m.m_end );
262  }
263 };
264 
265 } /* namespace router */
266 
267 } /* namespace restinio */
static constexpr std::size_t max_capture_groups()
regex_t & operator=(const regex_t &)=delete
match_results_t(const match_results_t &)=delete
void compile(string_view_t r, int options)
match_results_t & operator=(match_results_t &&)=delete
match_results_t & operator=(const match_results_t &)=delete
std::enable_if< std::is_same< Parameter_Container, query_string_params_t >::value||std::is_same< Parameter_Container, router::route_params_t >::value, std::optional< Value_Type > >::type opt_value(const Parameter_Container &params, string_view_t key)
Gets the value of a parameter specified by key wrapped in std::optional<Value_Type> if parameter exis...
Definition: value_or.hpp:64
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.
matched_item_descriptor_t operator[](std::size_t i) const
static constexpr std::size_t max_capture_groups
regex_t & operator=(regex_t &&rw) noexcept
static auto compile_regex(string_view_t r, bool is_case_sensative)
Create compiled regex object for a given route.
A wrapper class for working with pcre match results.
Regex engine implementation for PCRE2.
static auto submatch_end_pos(const matched_item_descriptor_t &m)
Get the end of a submatch.