regex_automaton.h 10.5 KB
Newer Older
1 2
// class template regex -*- C++ -*-

3
// Copyright (C) 2013-2019 Free Software Foundation, Inc.
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
//
// This file is part of the GNU ISO C++ Library.  This library is free
// software; you can redistribute it and/or modify it under the
// terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3, or (at your option)
// any later version.

// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// Under Section 7 of GPL version 3, you are granted additional
// permissions described in the GCC Runtime Library Exception, version
// 3.1, as published by the Free Software Foundation.

// You should have received a copy of the GNU General Public License and
// a copy of the GCC Runtime Library Exception along with this program;
// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
// <http://www.gnu.org/licenses/>.

/**
 *  @file bits/regex_automaton.h
 *  This is an internal header file, included by other library headers.
 *  Do not attempt to use it directly. @headername{regex}
 */

31 32 33 34 35
// This macro defines the maximal state number a NFA can have.
#ifndef _GLIBCXX_REGEX_STATE_LIMIT
#define _GLIBCXX_REGEX_STATE_LIMIT 100000
#endif

36 37 38 39
namespace std _GLIBCXX_VISIBILITY(default)
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION

40 41
namespace __detail
{
42 43 44 45 46 47
  /**
   *  @defgroup regex-detail Base and Implementation Classes
   *  @ingroup regex
   *  @{
   */

48
  typedef long _StateIdT;
49 50 51 52 53 54 55
  static const _StateIdT _S_invalid_state_id  = -1;

  template<typename _CharT>
    using _Matcher = std::function<bool (_CharT)>;

  /// Operation codes that define the type of transitions within the base NFA
  /// that represents the regular expression.
56
  enum _Opcode : int
57
  {
58 59
      _S_opcode_unknown,
      _S_opcode_alternative,
60
      _S_opcode_repeat,
61 62 63
      _S_opcode_backref,
      _S_opcode_line_begin_assertion,
      _S_opcode_line_end_assertion,
64
      _S_opcode_word_boundary,
65 66 67 68 69 70
      _S_opcode_subexpr_lookahead,
      _S_opcode_subexpr_begin,
      _S_opcode_subexpr_end,
      _S_opcode_dummy,
      _S_opcode_match,
      _S_opcode_accept,
71 72
  };

73 74
  struct _State_base
  {
75
  protected:
76
    _Opcode      _M_opcode;           // type of outgoing transition
77 78

  public:
79 80
    _StateIdT    _M_next;             // outgoing transition
    union // Since they are mutually exclusive.
81
    {
82 83 84
      size_t _M_subexpr;        // for _S_opcode_subexpr_*
      size_t _M_backref_index;  // for _S_opcode_backref
      struct
85
      {
86 87
	// for _S_opcode_alternative, _S_opcode_repeat and
	// _S_opcode_subexpr_lookahead
88 89 90 91
	_StateIdT  _M_alt;
	// for _S_opcode_word_boundary or _S_opcode_subexpr_lookahead or
	// quantifiers (ungreedy if set true)
	bool       _M_neg;
92
      };
93 94
      // For _S_opcode_match
      __gnu_cxx::__aligned_membuf<_Matcher<char>> _M_matcher_storage;
95
    };
96

97
  protected:
98 99 100 101 102
    explicit _State_base(_Opcode __opcode)
    : _M_opcode(__opcode), _M_next(_S_invalid_state_id)
    { }

  public:
103 104 105 106 107 108 109 110
    bool
    _M_has_alt()
    {
      return _M_opcode == _S_opcode_alternative
	|| _M_opcode == _S_opcode_repeat
	|| _M_opcode == _S_opcode_subexpr_lookahead;
    }

111
#ifdef _GLIBCXX_DEBUG
112 113
    std::ostream&
    _M_print(std::ostream& ostr) const;
114

115 116 117
    // Prints graphviz dot commands for state.
    std::ostream&
    _M_dot(std::ostream& __ostr, _StateIdT __id) const;
118
#endif
119
  };
120

121
  template<typename _Char_type>
122
    struct _State : _State_base
123
    {
124 125 126 127 128 129 130 131 132 133 134 135 136 137
      typedef _Matcher<_Char_type> _MatcherT;
      static_assert(sizeof(_MatcherT) == sizeof(_Matcher<char>),
		    "std::function<bool(T)> has the same size as "
		    "std::function<bool(char)>");
      static_assert(alignof(_MatcherT) == alignof(_Matcher<char>),
		    "std::function<bool(T)> has the same alignment as "
		    "std::function<bool(char)>");

      explicit
      _State(_Opcode __opcode) : _State_base(__opcode)
      {
	if (_M_opcode() == _S_opcode_match)
	  new (this->_M_matcher_storage._M_addr()) _MatcherT();
      }
138

139 140 141 142 143 144
      _State(const _State& __rhs) : _State_base(__rhs)
      {
	if (__rhs._M_opcode() == _S_opcode_match)
	  new (this->_M_matcher_storage._M_addr())
	    _MatcherT(__rhs._M_get_matcher());
      }
145

146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
      _State(_State&& __rhs) : _State_base(__rhs)
      {
	if (__rhs._M_opcode() == _S_opcode_match)
	  new (this->_M_matcher_storage._M_addr())
	    _MatcherT(std::move(__rhs._M_get_matcher()));
      }

      _State&
      operator=(const _State&) = delete;

      ~_State()
      {
	if (_M_opcode() == _S_opcode_match)
	  _M_get_matcher().~_MatcherT();
      }

      // Since correct ctor and dtor rely on _M_opcode, it's better not to
      // change it over time.
      _Opcode
      _M_opcode() const
      { return _State_base::_M_opcode; }

      bool
      _M_matches(_Char_type __char) const
      { return _M_get_matcher()(__char); }

      _MatcherT&
      _M_get_matcher()
      { return *static_cast<_MatcherT*>(this->_M_matcher_storage._M_addr()); }

      const _MatcherT&
      _M_get_matcher() const
      {
	return *static_cast<const _MatcherT*>(
	    this->_M_matcher_storage._M_addr());
      }
182
    };
183

184 185 186 187 188 189 190 191
  struct _NFA_base
  {
    typedef size_t                              _SizeT;
    typedef regex_constants::syntax_option_type _FlagT;

    explicit
    _NFA_base(_FlagT __f)
    : _M_flags(__f), _M_start_state(0), _M_subexpr_count(0),
192
    _M_has_backref(false)
193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212
    { }

    _NFA_base(_NFA_base&&) = default;

  protected:
    ~_NFA_base() = default;

  public:
    _FlagT
    _M_options() const
    { return _M_flags; }

    _StateIdT
    _M_start() const
    { return _M_start_state; }

    _SizeT
    _M_sub_count() const
    { return _M_subexpr_count; }

213
    _GLIBCXX_STD_C::vector<size_t> _M_paren_stack;
214 215 216 217 218 219
    _FlagT                    _M_flags;
    _StateIdT                 _M_start_state;
    _SizeT                    _M_subexpr_count;
    bool                      _M_has_backref;
  };

220
  template<typename _TraitsT>
221
    struct _NFA
222
    : _NFA_base, _GLIBCXX_STD_C::vector<_State<typename _TraitsT::char_type>>
223
    {
224 225 226
      typedef typename _TraitsT::char_type	_Char_type;
      typedef _State<_Char_type>		_StateT;
      typedef _Matcher<_Char_type>		_MatcherT;
227

228 229 230
      _NFA(const typename _TraitsT::locale_type& __loc, _FlagT __flags)
      : _NFA_base(__flags)
      { _M_traits.imbue(__loc); }
231

232 233 234
      // for performance reasons _NFA objects should only be moved not copied
      _NFA(const _NFA&) = delete;
      _NFA(_NFA&&) = default;
235 236 237 238

      _StateIdT
      _M_insert_accept()
      {
239 240
	auto __ret = _M_insert_state(_StateT(_S_opcode_accept));
	return __ret;
241 242 243
      }

      _StateIdT
244 245
      _M_insert_alt(_StateIdT __next, _StateIdT __alt,
		    bool __neg __attribute__((__unused__)))
246
      {
247 248 249
	_StateT __tmp(_S_opcode_alternative);
	// It labels every quantifier to make greedy comparison easier in BFS
	// approach.
250 251 252 253 254 255 256 257 258 259 260
	__tmp._M_next = __next;
	__tmp._M_alt = __alt;
	return _M_insert_state(std::move(__tmp));
      }

      _StateIdT
      _M_insert_repeat(_StateIdT __next, _StateIdT __alt, bool __neg)
      {
	_StateT __tmp(_S_opcode_repeat);
	// It labels every quantifier to make greedy comparison easier in BFS
	// approach.
261 262 263
	__tmp._M_next = __next;
	__tmp._M_alt = __alt;
	__tmp._M_neg = __neg;
264
	return _M_insert_state(std::move(__tmp));
265 266 267 268 269
      }

      _StateIdT
      _M_insert_matcher(_MatcherT __m)
      {
270
	_StateT __tmp(_S_opcode_match);
271
	__tmp._M_get_matcher() = std::move(__m);
272
	return _M_insert_state(std::move(__tmp));
273 274 275 276 277
      }

      _StateIdT
      _M_insert_subexpr_begin()
      {
278 279
	auto __id = this->_M_subexpr_count++;
	this->_M_paren_stack.push_back(__id);
280 281
	_StateT __tmp(_S_opcode_subexpr_begin);
	__tmp._M_subexpr = __id;
282
	return _M_insert_state(std::move(__tmp));
283 284 285 286 287
      }

      _StateIdT
      _M_insert_subexpr_end()
      {
288
	_StateT __tmp(_S_opcode_subexpr_end);
289 290 291
	__tmp._M_subexpr = this->_M_paren_stack.back();
	this->_M_paren_stack.pop_back();
	return _M_insert_state(std::move(__tmp));
292 293
      }

294
      _StateIdT
295
      _M_insert_backref(size_t __index);
296

297
      _StateIdT
298 299 300 301 302 303 304 305 306
      _M_insert_line_begin()
      { return _M_insert_state(_StateT(_S_opcode_line_begin_assertion)); }

      _StateIdT
      _M_insert_line_end()
      { return _M_insert_state(_StateT(_S_opcode_line_end_assertion)); }

      _StateIdT
      _M_insert_word_bound(bool __neg)
307
      {
308
	_StateT __tmp(_S_opcode_word_boundary);
309
	__tmp._M_neg = __neg;
310
	return _M_insert_state(std::move(__tmp));
311 312 313
      }

      _StateIdT
314 315 316 317 318
      _M_insert_lookahead(_StateIdT __alt, bool __neg)
      {
	_StateT __tmp(_S_opcode_subexpr_lookahead);
	__tmp._M_alt = __alt;
	__tmp._M_neg = __neg;
319
	return _M_insert_state(std::move(__tmp));
320 321 322 323 324 325 326
      }

      _StateIdT
      _M_insert_dummy()
      { return _M_insert_state(_StateT(_S_opcode_dummy)); }

      _StateIdT
327 328
      _M_insert_state(_StateT __s)
      {
329
	this->push_back(std::move(__s));
330
	if (this->size() > _GLIBCXX_REGEX_STATE_LIMIT)
331 332 333 334 335
	  __throw_regex_error(
	    regex_constants::error_space,
	    "Number of NFA states exceeds limit. Please use shorter regex "
	    "string, or use smaller brace expression, or make "
	    "_GLIBCXX_REGEX_STATE_LIMIT larger.");
336
	return this->size() - 1;
337 338 339 340 341 342
      }

      // Eliminate dummy node in this NFA to make it compact.
      void
      _M_eliminate_dummy();

343 344 345 346
#ifdef _GLIBCXX_DEBUG
      std::ostream&
      _M_dot(std::ostream& __ostr) const;
#endif
347 348
    public:
      _TraitsT                  _M_traits;
349 350 351 352 353
    };

  /// Describes a sequence of one or more %_State, its current start
  /// and end(s).  This structure contains fragments of an NFA during
  /// construction.
354
  template<typename _TraitsT>
355 356 357
    class _StateSeq
    {
    public:
358
      typedef _NFA<_TraitsT> _RegexT;
359

360 361
    public:
      _StateSeq(_RegexT& __nfa, _StateIdT __s)
362
      : _M_nfa(__nfa), _M_start(__s), _M_end(__s)
363 364
      { }

365 366
      _StateSeq(_RegexT& __nfa, _StateIdT __s, _StateIdT __end)
      : _M_nfa(__nfa), _M_start(__s), _M_end(__end)
367 368
      { }

369
      // Append a state on *this and change *this to the new sequence.
370
      void
371 372 373 374 375
      _M_append(_StateIdT __id)
      {
	_M_nfa[_M_end]._M_next = __id;
	_M_end = __id;
      }
376

377
      // Append a sequence on *this and change *this to the new sequence.
378
      void
379 380 381 382 383
      _M_append(const _StateSeq& __s)
      {
	_M_nfa[_M_end]._M_next = __s._M_start;
	_M_end = __s._M_end;
      }
384 385

      // Clones an entire sequence.
386
      _StateSeq
387 388
      _M_clone();

389
    public:
390 391
      _RegexT&  _M_nfa;
      _StateIdT _M_start;
392
      _StateIdT _M_end;
393 394 395 396
    };

 //@} regex-detail
} // namespace __detail
397 398

_GLIBCXX_END_NAMESPACE_VERSION
399 400 401
} // namespace std

#include <bits/regex_automaton.tcc>