diff options
Diffstat (limited to 'libstdc++-v3/include/bits')
-rw-r--r-- | libstdc++-v3/include/bits/hashtable.h | 146 | ||||
-rw-r--r-- | libstdc++-v3/include/bits/ios_base.h | 8 | ||||
-rw-r--r-- | libstdc++-v3/include/bits/parse_numbers.h | 339 | ||||
-rw-r--r-- | libstdc++-v3/include/bits/regex.tcc | 2 | ||||
-rw-r--r-- | libstdc++-v3/include/bits/regex_automaton.tcc | 4 | ||||
-rw-r--r-- | libstdc++-v3/include/bits/regex_compiler.h | 43 | ||||
-rw-r--r-- | libstdc++-v3/include/bits/regex_compiler.tcc | 36 | ||||
-rw-r--r-- | libstdc++-v3/include/bits/regex_executor.h | 99 | ||||
-rw-r--r-- | libstdc++-v3/include/bits/regex_executor.tcc | 168 | ||||
-rw-r--r-- | libstdc++-v3/include/bits/regex_scanner.tcc | 11 | ||||
-rw-r--r-- | libstdc++-v3/include/bits/uses_allocator.h | 31 |
11 files changed, 437 insertions, 450 deletions
diff --git a/libstdc++-v3/include/bits/hashtable.h b/libstdc++-v3/include/bits/hashtable.h index 22e17d29d7b..9b6394c4e49 100644 --- a/libstdc++-v3/include/bits/hashtable.h +++ b/libstdc++-v3/include/bits/hashtable.h @@ -316,14 +316,49 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION size_type _M_element_count; _RehashPolicy _M_rehash_policy; + // A single bucket used when only need for 1 bucket. Especially + // interesting in move semantic to leave hashtable with only 1 buckets + // which is not allocated so that we can have those operations noexcept + // qualified. + // Note that we can't leave hashtable with 0 bucket without adding + // numerous checks in the code to avoid 0 modulus. + __bucket_type _M_single_bucket; + + bool + _M_uses_single_bucket(__bucket_type* __bkts) const + { return __builtin_expect(_M_buckets == &_M_single_bucket, false); } + + bool + _M_uses_single_bucket() const + { return _M_uses_single_bucket(_M_buckets); } + __hashtable_alloc& _M_base_alloc() { return *this; } - using __hashtable_alloc::_M_deallocate_buckets; + __bucket_type* + _M_allocate_buckets(size_type __n) + { + if (__builtin_expect(__n == 1, false)) + { + _M_single_bucket = nullptr; + return &_M_single_bucket; + } + + return __hashtable_alloc::_M_allocate_buckets(__n); + } + + void + _M_deallocate_buckets(__bucket_type* __bkts, size_type __n) + { + if (_M_uses_single_bucket(__bkts)) + return; + + __hashtable_alloc::_M_deallocate_buckets(__bkts, __n); + } void _M_deallocate_buckets() - { this->_M_deallocate_buckets(_M_buckets, _M_bucket_count); } + { _M_deallocate_buckets(_M_buckets, _M_bucket_count); } // Gets bucket begin, deals with the fact that non-empty buckets contain // their before begin node. @@ -703,11 +738,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION size_type erase(const key_type& __k) - { - if (__builtin_expect(_M_bucket_count == 0, false)) - return 0; - return _M_erase(__unique_keys(), __k); - } + { return _M_erase(__unique_keys(), __k); } iterator erase(const_iterator, const_iterator); @@ -768,7 +799,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _M_rehash_policy() { _M_bucket_count = _M_rehash_policy._M_next_bkt(__bucket_hint); - _M_buckets = this->_M_allocate_buckets(_M_bucket_count); + _M_buckets = _M_allocate_buckets(_M_bucket_count); } template<typename _Key, typename _Value, @@ -796,7 +827,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION std::max(_M_rehash_policy._M_bkt_for_elements(__nb_elems), __bucket_hint)); - _M_buckets = this->_M_allocate_buckets(_M_bucket_count); + _M_buckets = _M_allocate_buckets(_M_bucket_count); __try { for (; __f != __l; ++__f) @@ -833,9 +864,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { // Replacement allocator cannot free existing storage. this->_M_deallocate_nodes(_M_begin()); - if (__builtin_expect(_M_bucket_count != 0, true)) - _M_deallocate_buckets(); - _M_reset(); + _M_before_begin._M_nxt = nullptr; + _M_deallocate_buckets(); + _M_buckets = nullptr; std::__alloc_on_copy(__this_alloc, __that_alloc); __hashtable_base::operator=(__ht); _M_bucket_count = __ht._M_bucket_count; @@ -867,7 +898,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION if (_M_bucket_count != __ht._M_bucket_count) { __former_buckets = _M_buckets; - _M_buckets = this->_M_allocate_buckets(__ht._M_bucket_count); + _M_buckets = _M_allocate_buckets(__ht._M_bucket_count); _M_bucket_count = __ht._M_bucket_count; } else @@ -885,8 +916,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION [&__roan](const __node_type* __n) { return __roan(__n->_M_v()); }); if (__former_buckets) - this->_M_deallocate_buckets(__former_buckets, - __former_bucket_count); + _M_deallocate_buckets(__former_buckets, __former_bucket_count); } __catch(...) { @@ -917,7 +947,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { __bucket_type* __buckets = nullptr; if (!_M_buckets) - _M_buckets = __buckets = this->_M_allocate_buckets(_M_bucket_count); + _M_buckets = __buckets = _M_allocate_buckets(_M_bucket_count); __try { @@ -964,8 +994,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _M_reset() noexcept { _M_rehash_policy._M_reset(); - _M_bucket_count = 0; - _M_buckets = nullptr; + _M_bucket_count = 1; + _M_single_bucket = nullptr; + _M_buckets = &_M_single_bucket; _M_before_begin._M_nxt = nullptr; _M_element_count = 0; } @@ -980,12 +1011,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _M_move_assign(_Hashtable&& __ht, std::true_type) { this->_M_deallocate_nodes(_M_begin()); - if (__builtin_expect(_M_bucket_count != 0, true)) - _M_deallocate_buckets(); - + _M_deallocate_buckets(); __hashtable_base::operator=(std::move(__ht)); _M_rehash_policy = __ht._M_rehash_policy; - _M_buckets = __ht._M_buckets; + if (!__ht._M_uses_single_bucket()) + _M_buckets = __ht._M_buckets; + else + { + _M_buckets = &_M_single_bucket; + _M_single_bucket = __ht._M_single_bucket; + } _M_bucket_count = __ht._M_bucket_count; _M_before_begin._M_nxt = __ht._M_before_begin._M_nxt; _M_element_count = __ht._M_element_count; @@ -1019,7 +1054,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION if (_M_bucket_count != __ht._M_bucket_count) { __former_buckets = _M_buckets; - _M_buckets = this->_M_allocate_buckets(__ht._M_bucket_count); + _M_buckets = _M_allocate_buckets(__ht._M_bucket_count); _M_bucket_count = __ht._M_bucket_count; } else @@ -1093,10 +1128,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _M_element_count(__ht._M_element_count), _M_rehash_policy(__ht._M_rehash_policy) { + // Update, if necessary, buckets if __ht is using its single bucket. + if (__ht._M_uses_single_bucket()) + { + _M_buckets = &_M_single_bucket; + _M_single_bucket = __ht._M_single_bucket; + } + // Update, if necessary, bucket pointing to before begin that hasn't // moved. if (_M_begin()) _M_buckets[_M_bucket_index(_M_begin())] = &_M_before_begin; + __ht._M_reset(); } @@ -1139,7 +1182,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { if (__ht._M_node_allocator() == this->_M_node_allocator()) { - _M_buckets = __ht._M_buckets; + if (__ht._M_uses_single_bucket()) + { + _M_buckets = &_M_single_bucket; + _M_single_bucket = __ht._M_single_bucket; + } + else + _M_buckets = __ht._M_buckets; + _M_before_begin._M_nxt = __ht._M_before_begin._M_nxt; // Update, if necessary, bucket pointing to before begin that hasn't // moved. @@ -1189,15 +1239,34 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION std::__alloc_on_swap(this->_M_node_allocator(), __x._M_node_allocator()); std::swap(_M_rehash_policy, __x._M_rehash_policy); - std::swap(_M_buckets, __x._M_buckets); + + // Deal properly with potentially moved instances. + if (this->_M_uses_single_bucket()) + { + if (!__x._M_uses_single_bucket()) + { + _M_buckets = __x._M_buckets; + __x._M_buckets = &__x._M_single_bucket; + } + } + else if (__x._M_uses_single_bucket()) + { + __x._M_buckets = _M_buckets; + _M_buckets = &_M_single_bucket; + } + else + std::swap(_M_buckets, __x._M_buckets); + std::swap(_M_bucket_count, __x._M_bucket_count); std::swap(_M_before_begin._M_nxt, __x._M_before_begin._M_nxt); std::swap(_M_element_count, __x._M_element_count); + std::swap(_M_single_bucket, __x._M_single_bucket); // Fix buckets containing the _M_before_begin pointers that can't be // swapped. if (_M_begin()) _M_buckets[_M_bucket_index(_M_begin())] = &_M_before_begin; + if (__x._M_begin()) __x._M_buckets[__x._M_bucket_index(__x._M_begin())] = &__x._M_before_begin; @@ -1230,9 +1299,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _H1, _H2, _Hash, _RehashPolicy, _Traits>:: find(const key_type& __k) { - if (__builtin_expect(_M_bucket_count == 0, false)) - return end(); - __hash_code __code = this->_M_hash_code(__k); std::size_t __n = _M_bucket_index(__k, __code); __node_type* __p = _M_find_node(__n, __k, __code); @@ -1250,9 +1316,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _H1, _H2, _Hash, _RehashPolicy, _Traits>:: find(const key_type& __k) const { - if (__builtin_expect(_M_bucket_count == 0, false)) - return end(); - __hash_code __code = this->_M_hash_code(__k); std::size_t __n = _M_bucket_index(__k, __code); __node_type* __p = _M_find_node(__n, __k, __code); @@ -1270,9 +1333,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _H1, _H2, _Hash, _RehashPolicy, _Traits>:: count(const key_type& __k) const { - if (__builtin_expect(_M_bucket_count == 0, false)) - return 0; - __hash_code __code = this->_M_hash_code(__k); std::size_t __n = _M_bucket_index(__k, __code); __node_type* __p = _M_bucket_begin(__n); @@ -1287,7 +1347,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION else if (__result) // All equivalent values are next to each other, if we // found a non-equivalent value after an equivalent one it - // means that we won't find any more equivalent values. + // means that we won't find any new equivalent value. break; if (!__p->_M_nxt || _M_bucket_index(__p->_M_next()) != __n) break; @@ -1311,9 +1371,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _H1, _H2, _Hash, _RehashPolicy, _Traits>:: equal_range(const key_type& __k) { - if (__builtin_expect(_M_bucket_count == 0, false)) - return std::make_pair(end(), end()); - __hash_code __code = this->_M_hash_code(__k); std::size_t __n = _M_bucket_index(__k, __code); __node_type* __p = _M_find_node(__n, __k, __code); @@ -1347,9 +1404,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _H1, _H2, _Hash, _RehashPolicy, _Traits>:: equal_range(const key_type& __k) const { - if (__builtin_expect(_M_bucket_count == 0, false)) - return std::make_pair(end(), end()); - __hash_code __code = this->_M_hash_code(__k); std::size_t __n = _M_bucket_index(__k, __code); __node_type* __p = _M_find_node(__n, __k, __code); @@ -1944,7 +1998,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _H1, _H2, _Hash, _RehashPolicy, _Traits>:: _M_rehash_aux(size_type __n, std::true_type) { - __bucket_type* __new_buckets = this->_M_allocate_buckets(__n); + __bucket_type* __new_buckets = _M_allocate_buckets(__n); __node_type* __p = _M_begin(); _M_before_begin._M_nxt = nullptr; std::size_t __bbegin_bkt = 0; @@ -1969,8 +2023,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __p = __next; } - if (__builtin_expect(_M_bucket_count != 0, true)) - _M_deallocate_buckets(); + _M_deallocate_buckets(); _M_bucket_count = __n; _M_buckets = __new_buckets; } @@ -1986,7 +2039,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _H1, _H2, _Hash, _RehashPolicy, _Traits>:: _M_rehash_aux(size_type __n, std::false_type) { - __bucket_type* __new_buckets = this->_M_allocate_buckets(__n); + __bucket_type* __new_buckets = _M_allocate_buckets(__n); __node_type* __p = _M_begin(); _M_before_begin._M_nxt = nullptr; @@ -2060,8 +2113,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __new_buckets[__next_bkt] = __prev_p; } - if (__builtin_expect(_M_bucket_count != 0, true)) - _M_deallocate_buckets(); + _M_deallocate_buckets(); _M_bucket_count = __n; _M_buckets = __new_buckets; } diff --git a/libstdc++-v3/include/bits/ios_base.h b/libstdc++-v3/include/bits/ios_base.h index ae856de7b45..59c506696f5 100644 --- a/libstdc++-v3/include/bits/ios_base.h +++ b/libstdc++-v3/include/bits/ios_base.h @@ -780,6 +780,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION protected: ios_base() throw (); +#if __cplusplus < 201103L // _GLIBCXX_RESOLVE_LIB_DEFECTS // 50. Copy constructor and assignment operator of ios_base private: @@ -787,6 +788,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ios_base& operator=(const ios_base&); +#else + public: + ios_base(const ios_base&) = delete; + + ios_base& + operator=(const ios_base&) = delete; +#endif }; // [27.4.5.1] fmtflags manipulators diff --git a/libstdc++-v3/include/bits/parse_numbers.h b/libstdc++-v3/include/bits/parse_numbers.h index 91a127c4ebe..a29d1272255 100644 --- a/libstdc++-v3/include/bits/parse_numbers.h +++ b/libstdc++-v3/include/bits/parse_numbers.h @@ -27,8 +27,8 @@ * Do not attempt to use it directly. @headername{chrono} */ -#ifndef _PARSE_NUMBERS_H -#define _PARSE_NUMBERS_H 1 +#ifndef _GLIBCXX_PARSE_NUMBERS_H +#define _GLIBCXX_PARSE_NUMBERS_H 1 #pragma GCC system_header @@ -36,289 +36,182 @@ #if __cplusplus > 201103L +#include <limits> + namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION -namespace __parse_int { - +namespace __parse_int +{ template<unsigned _Base, char _Dig> struct _Digit; template<unsigned _Base> - struct _Digit<_Base, '0'> + struct _Digit<_Base, '0'> : integral_constant<unsigned, 0> { - static constexpr bool valid{true}; - static constexpr unsigned value{0}; + using __valid = true_type; }; template<unsigned _Base> - struct _Digit<_Base, '1'> + struct _Digit<_Base, '1'> : integral_constant<unsigned, 1> { - static constexpr bool valid{true}; - static constexpr unsigned value{1}; + using __valid = true_type; }; - template<unsigned _Base> - struct _Digit<_Base, '2'> + template<unsigned _Base, unsigned _Val> + struct _Digit_impl : integral_constant<unsigned, _Val> { - static_assert(_Base > 2, "invalid digit"); - static constexpr bool valid{true}; - static constexpr unsigned value{2}; + static_assert(_Base > _Val, "invalid digit"); + using __valid = true_type; }; template<unsigned _Base> - struct _Digit<_Base, '3'> - { - static_assert(_Base > 3, "invalid digit"); - static constexpr bool valid{true}; - static constexpr unsigned value{3}; - }; + struct _Digit<_Base, '2'> : _Digit_impl<_Base, 2> + { }; template<unsigned _Base> - struct _Digit<_Base, '4'> - { - static_assert(_Base > 4, "invalid digit"); - static constexpr bool valid{true}; - static constexpr unsigned value{4}; - }; + struct _Digit<_Base, '3'> : _Digit_impl<_Base, 3> + { }; template<unsigned _Base> - struct _Digit<_Base, '5'> - { - static_assert(_Base > 5, "invalid digit"); - static constexpr bool valid{true}; - static constexpr unsigned value{5}; - }; + struct _Digit<_Base, '4'> : _Digit_impl<_Base, 4> + { }; template<unsigned _Base> - struct _Digit<_Base, '6'> - { - static_assert(_Base > 6, "invalid digit"); - static constexpr bool valid{true}; - static constexpr unsigned value{6}; - }; + struct _Digit<_Base, '5'> : _Digit_impl<_Base, 5> + { }; template<unsigned _Base> - struct _Digit<_Base, '7'> - { - static_assert(_Base > 7, "invalid digit"); - static constexpr bool valid{true}; - static constexpr unsigned value{7}; - }; + struct _Digit<_Base, '6'> : _Digit_impl<_Base, 6> + { }; template<unsigned _Base> - struct _Digit<_Base, '8'> - { - static_assert(_Base > 8, "invalid digit"); - static constexpr bool valid{true}; - static constexpr unsigned value{8}; - }; + struct _Digit<_Base, '7'> : _Digit_impl<_Base, 7> + { }; template<unsigned _Base> - struct _Digit<_Base, '9'> - { - static_assert(_Base > 9, "invalid digit"); - static constexpr bool valid{true}; - static constexpr unsigned value{9}; - }; + struct _Digit<_Base, '8'> : _Digit_impl<_Base, 8> + { }; template<unsigned _Base> - struct _Digit<_Base, 'a'> - { - static_assert(_Base > 0xa, "invalid digit"); - static constexpr bool valid{true}; - static constexpr unsigned value{0xa}; - }; + struct _Digit<_Base, '9'> : _Digit_impl<_Base, 9> + { }; template<unsigned _Base> - struct _Digit<_Base, 'A'> - { - static_assert(_Base > 0xa, "invalid digit"); - static constexpr bool valid{true}; - static constexpr unsigned value{0xa}; - }; + struct _Digit<_Base, 'a'> : _Digit_impl<_Base, 0xa> + { }; template<unsigned _Base> - struct _Digit<_Base, 'b'> - { - static_assert(_Base > 0xb, "invalid digit"); - static constexpr bool valid{true}; - static constexpr unsigned value{0xb}; - }; + struct _Digit<_Base, 'A'> : _Digit_impl<_Base, 0xa> + { }; template<unsigned _Base> - struct _Digit<_Base, 'B'> - { - static_assert(_Base > 0xb, "invalid digit"); - static constexpr bool valid{true}; - static constexpr unsigned value{0xb}; - }; + struct _Digit<_Base, 'b'> : _Digit_impl<_Base, 0xb> + { }; template<unsigned _Base> - struct _Digit<_Base, 'c'> - { - static_assert(_Base > 0xc, "invalid digit"); - static constexpr bool valid{true}; - static constexpr unsigned value{0xc}; - }; + struct _Digit<_Base, 'B'> : _Digit_impl<_Base, 0xb> + { }; template<unsigned _Base> - struct _Digit<_Base, 'C'> - { - static_assert(_Base > 0xc, "invalid digit"); - static constexpr bool valid{true}; - static constexpr unsigned value{0xc}; - }; + struct _Digit<_Base, 'c'> : _Digit_impl<_Base, 0xc> + { }; template<unsigned _Base> - struct _Digit<_Base, 'd'> - { - static_assert(_Base > 0xd, "invalid digit"); - static constexpr bool valid{true}; - static constexpr unsigned value{0xd}; - }; + struct _Digit<_Base, 'C'> : _Digit_impl<_Base, 0xc> + { }; template<unsigned _Base> - struct _Digit<_Base, 'D'> - { - static_assert(_Base > 0xd, "invalid digit"); - static constexpr bool valid{true}; - static constexpr unsigned value{0xd}; - }; + struct _Digit<_Base, 'd'> : _Digit_impl<_Base, 0xd> + { }; template<unsigned _Base> - struct _Digit<_Base, 'e'> - { - static_assert(_Base > 0xe, "invalid digit"); - static constexpr bool valid{true}; - static constexpr unsigned value{0xe}; - }; + struct _Digit<_Base, 'D'> : _Digit_impl<_Base, 0xd> + { }; template<unsigned _Base> - struct _Digit<_Base, 'E'> - { - static_assert(_Base > 0xe, "invalid digit"); - static constexpr bool valid{true}; - static constexpr unsigned value{0xe}; - }; + struct _Digit<_Base, 'e'> : _Digit_impl<_Base, 0xe> + { }; template<unsigned _Base> - struct _Digit<_Base, 'f'> - { - static_assert(_Base > 0xf, "invalid digit"); - static constexpr bool valid{true}; - static constexpr unsigned value{0xf}; - }; + struct _Digit<_Base, 'E'> : _Digit_impl<_Base, 0xe> + { }; template<unsigned _Base> - struct _Digit<_Base, 'F'> - { - static_assert(_Base > 0xf, "invalid digit"); - static constexpr bool valid{true}; - static constexpr unsigned value{0xf}; - }; + struct _Digit<_Base, 'f'> : _Digit_impl<_Base, 0xf> + { }; - // Digit separator template<unsigned _Base> - struct _Digit<_Base, '\''> - { - static constexpr bool valid{false}; - static constexpr unsigned value{0}; - }; - - -//------------------------------------------------------------------------------ - - template<unsigned _Base, char _Dig, char... _Digs> - struct _Digits_help - { - static constexpr unsigned - value{_Digit<_Base, _Dig>::valid ? - 1U + _Digits_help<_Base, _Digs...>::value : - _Digits_help<_Base, _Digs...>::value}; - }; - - template<unsigned _Base, char _Dig> - struct _Digits_help<_Base, _Dig> - { - static constexpr unsigned value{_Digit<_Base, _Dig>::valid ? 1U : 0U}; - }; - - template<unsigned _Base, char... _Digs> - struct _Digits - { - static constexpr unsigned value{_Digits_help<_Base, _Digs...>::value}; - }; + struct _Digit<_Base, 'F'> : _Digit_impl<_Base, 0xf> + { }; + // Digit separator template<unsigned _Base> - struct _Digits<_Base> + struct _Digit<_Base, '\''> : integral_constant<unsigned, 0> { - static constexpr unsigned value{0U}; + using __valid = false_type; }; //------------------------------------------------------------------------------ + template<unsigned long long _Val> + using __ull_constant = integral_constant<unsigned long long, _Val>; + template<unsigned _Base, char _Dig, char... _Digs> struct _Power_help { - static constexpr unsigned - value{_Digit<_Base, _Dig>::valid ? - _Base * _Power_help<_Base, _Digs...>::value : - _Power_help<_Base, _Digs...>::value}; + using __next = typename _Power_help<_Base, _Digs...>::type; + using __valid_digit = typename _Digit<_Base, _Dig>::__valid; + using type + = __ull_constant<__next::value * (__valid_digit{} ? _Base : 1ULL)>; }; template<unsigned _Base, char _Dig> struct _Power_help<_Base, _Dig> { - static constexpr unsigned value{_Digit<_Base, _Dig>::valid ? 1U : 0U}; + using __valid_digit = typename _Digit<_Base, _Dig>::__valid; + using type = __ull_constant<__valid_digit::value>; }; template<unsigned _Base, char... _Digs> - struct _Power - { - static constexpr unsigned value{_Power_help<_Base, _Digs...>::value}; - }; + struct _Power : _Power_help<_Base, _Digs...>::type + { }; template<unsigned _Base> - struct _Power<_Base> - { - static constexpr unsigned value{0U}; - }; + struct _Power<_Base> : __ull_constant<0> + { }; //------------------------------------------------------------------------------ - template<unsigned _Base, unsigned _Pow, char _Dig, char... _Digs> + template<unsigned _Base, unsigned long long _Pow, char _Dig, char... _Digs> struct _Number_help { - static constexpr unsigned - value{_Digit<_Base, _Dig>::valid ? - _Pow * _Digit<_Base, _Dig>::value - + _Number_help<_Base, _Pow / _Base, _Digs...>::value : - _Number_help<_Base, _Pow, _Digs...>::value}; + using __digit = _Digit<_Base, _Dig>; + using __valid_digit = typename __digit::__valid; + using __next = _Number_help<_Base, + _Pow / (_Base * __valid_digit::value), + _Digs...>; + using type = __ull_constant<_Pow * __digit::value + __next::type::value>; + static_assert((type::value / _Pow) == __digit::value, "overflow"); }; - template<unsigned _Base, unsigned _Pow, char _Dig> + template<unsigned _Base, unsigned long long _Pow, char _Dig> struct _Number_help<_Base, _Pow, _Dig> { //static_assert(_Pow == 1U, "power should be one"); - static constexpr unsigned - value{_Digit<_Base, _Dig>::valid ? _Digit<_Base, _Dig>::value : 0U}; + using type = __ull_constant<_Digit<_Base, _Dig>::value>; }; template<unsigned _Base, char... _Digs> struct _Number - { - static constexpr unsigned - value{_Number_help<_Base, _Power<_Base, _Digs...>::value, - _Digs...>::value}; - }; + : _Number_help<_Base, _Power<_Base, _Digs...>::value, _Digs...>::type + { }; template<unsigned _Base> struct _Number<_Base> - { - static constexpr unsigned value{0U}; - }; + : __ull_constant<0> + { }; //------------------------------------------------------------------------------ // This _Parse_int is the same 'level' as the old _Base_dispatch. @@ -328,84 +221,62 @@ namespace __parse_int { template<char... _Digs> struct _Parse_int<'0', 'b', _Digs...> - { - static constexpr unsigned long long - value{_Number<2U, _Digs...>::value}; - }; + : _Number<2U, _Digs...>::type + { }; template<char... _Digs> struct _Parse_int<'0', 'B', _Digs...> - { - static constexpr unsigned long long - value{_Number<2U, _Digs...>::value}; - }; + : _Number<2U, _Digs...>::type + { }; template<char... _Digs> struct _Parse_int<'0', 'x', _Digs...> - { - static constexpr unsigned long long - value{_Number<16U, _Digs...>::value}; - }; + : _Number<16U, _Digs...>::type + { }; template<char... _Digs> struct _Parse_int<'0', 'X', _Digs...> - { - static constexpr unsigned long long - value{_Number<16U, _Digs...>::value}; - }; + : _Number<16U, _Digs...>::type + { }; template<char... _Digs> struct _Parse_int<'0', _Digs...> - { - static constexpr unsigned long long - value{_Number<8U, _Digs...>::value}; - }; + : _Number<8U, _Digs...>::type + { }; template<char... _Digs> struct _Parse_int - { - static constexpr unsigned long long - value{_Number<10U, _Digs...>::value}; - }; + : _Number<10U, _Digs...>::type + { }; } // namespace __parse_int -namespace __select_int { - +namespace __select_int +{ template<unsigned long long _Val, typename... _Ints> struct _Select_int_base; template<unsigned long long _Val, typename _IntType, typename... _Ints> struct _Select_int_base<_Val, _IntType, _Ints...> - : integral_constant - < - typename conditional - < - _Val <= static_cast<unsigned long long> - (std::numeric_limits<_IntType>::max()), - _IntType, - typename _Select_int_base<_Val, _Ints...>::value_type - >::type, - _Val - > + : conditional_t<(_Val <= std::numeric_limits<_IntType>::max()), + integral_constant<_IntType, _Val>, + _Select_int_base<_Val, _Ints...>> { }; template<unsigned long long _Val> - struct _Select_int_base<_Val> : integral_constant<unsigned long long, _Val> + struct _Select_int_base<_Val> { }; template<char... _Digs> - struct _Select_int - : _Select_int_base< + using _Select_int = typename _Select_int_base< __parse_int::_Parse_int<_Digs...>::value, unsigned char, unsigned short, unsigned int, unsigned long, unsigned long long - > - { }; + >::type; } // namespace __select_int @@ -414,4 +285,4 @@ _GLIBCXX_END_NAMESPACE_VERSION #endif // __cplusplus > 201103L -#endif // _PARSE_NUMBERS_H +#endif // _GLIBCXX_PARSE_NUMBERS_H diff --git a/libstdc++-v3/include/bits/regex.tcc b/libstdc++-v3/include/bits/regex.tcc index 0d737a0b74b..a81f51750dc 100644 --- a/libstdc++-v3/include/bits/regex.tcc +++ b/libstdc++-v3/include/bits/regex.tcc @@ -32,7 +32,7 @@ // If _GLIBCXX_REGEX_USE_THOMPSON_NFA is defined, the thompson NFA // algorithm will be used. This algorithm is not enabled by default, // and cannot be used if the regex contains back-references, but has better -// (polynomial instead of exponential) worst case performace. +// (polynomial instead of exponential) worst case performance. // See __regex_algo_impl below. namespace std _GLIBCXX_VISIBILITY(default) diff --git a/libstdc++-v3/include/bits/regex_automaton.tcc b/libstdc++-v3/include/bits/regex_automaton.tcc index e0ac3f94ceb..1c6cfdd1b9f 100644 --- a/libstdc++-v3/include/bits/regex_automaton.tcc +++ b/libstdc++-v3/include/bits/regex_automaton.tcc @@ -35,7 +35,7 @@ namespace __detail _GLIBCXX_BEGIN_NAMESPACE_VERSION #ifdef _GLIBCXX_DEBUG - std::ostream& + inline std::ostream& _State_base::_M_print(std::ostream& ostr) const { switch (_M_opcode) @@ -67,7 +67,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } // Prints graphviz dot commands for state. - std::ostream& + inline std::ostream& _State_base::_M_dot(std::ostream& __ostr, _StateIdT __id) const { switch (_M_opcode) diff --git a/libstdc++-v3/include/bits/regex_compiler.h b/libstdc++-v3/include/bits/regex_compiler.h index d7e21624e37..ca116de53af 100644 --- a/libstdc++-v3/include/bits/regex_compiler.h +++ b/libstdc++-v3/include/bits/regex_compiler.h @@ -43,7 +43,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION struct _BracketMatcher; /** - * @brief Builds an NFA from an input iterator interval. + * @brief Builds an NFA from an input iterator range. * * The %_TraitsT type should fulfill requirements [28.3]. */ @@ -329,7 +329,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION operator()(_CharT __ch) const { _GLIBCXX_DEBUG_ASSERT(_M_is_ready); - return _M_apply(__ch, _IsChar()); + return _M_apply(__ch, _UseCache()); } void @@ -369,15 +369,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #endif } + // __neg should be true for \D, \S and \W only. void - _M_add_character_class(const _StringT& __s) + _M_add_character_class(const _StringT& __s, bool __neg) { auto __mask = _M_traits.lookup_classname(__s.data(), __s.data() + __s.size(), __icase); if (__mask == 0) __throw_regex_error(regex_constants::error_ctype); - _M_class_set |= __mask; + if (!__neg) + _M_class_set |= __mask; + else + _M_neg_class_set.push_back(__mask); #ifdef _GLIBCXX_DEBUG _M_is_ready = false; #endif @@ -387,7 +391,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _M_make_range(_CharT __l, _CharT __r) { _M_range_set.push_back(make_pair(_M_translator._M_transform(__l), - _M_translator._M_transform(__r))); + _M_translator._M_transform(__r))); #ifdef _GLIBCXX_DEBUG _M_is_ready = false; #endif @@ -396,21 +400,28 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION void _M_ready() { - _M_make_cache(_IsChar()); + std::sort(_M_char_set.begin(), _M_char_set.end()); + auto __end = std::unique(_M_char_set.begin(), _M_char_set.end()); + _M_char_set.erase(__end, _M_char_set.end()); + _M_make_cache(_UseCache()); #ifdef _GLIBCXX_DEBUG _M_is_ready = true; #endif } private: - typedef typename is_same<_CharT, char>::type _IsChar; + // Currently we only use the cache for char + typedef typename std::is_same<_CharT, char>::type _UseCache; + + static constexpr size_t + _S_cache_size() { return 1ul << (sizeof(_CharT) * __CHAR_BIT__); } + struct _Dummy { }; - typedef typename conditional<_IsChar::value, - std::bitset<1 << (8 * sizeof(_CharT))>, - _Dummy>::type _CacheT; - typedef typename make_unsigned<_CharT>::type _UnsignedCharT; + typedef typename std::conditional<_UseCache::value, + std::bitset<_S_cache_size()>, + _Dummy>::type _CacheT; + typedef typename std::make_unsigned<_CharT>::type _UnsignedCharT; - private: bool _M_apply(_CharT __ch, false_type) const; @@ -421,9 +432,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION void _M_make_cache(true_type) { - for (size_t __i = 0; __i < _M_cache.size(); __i++) - _M_cache[static_cast<_UnsignedCharT>(__i)] = - _M_apply(__i, false_type()); + for (unsigned __i = 0; __i < _M_cache.size(); __i++) + _M_cache[__i] = _M_apply(static_cast<_CharT>(__i), false_type()); } void @@ -431,14 +441,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { } private: - _CacheT _M_cache; std::vector<_CharT> _M_char_set; std::vector<_StringT> _M_equiv_set; std::vector<pair<_StrTransT, _StrTransT>> _M_range_set; + std::vector<_CharClassT> _M_neg_class_set; _CharClassT _M_class_set; _TransT _M_translator; const _TraitsT& _M_traits; bool _M_is_non_matching; + _CacheT _M_cache; #ifdef _GLIBCXX_DEBUG bool _M_is_ready; #endif diff --git a/libstdc++-v3/include/bits/regex_compiler.tcc b/libstdc++-v3/include/bits/regex_compiler.tcc index 3cf9e457ccd..0df10cc1a8b 100644 --- a/libstdc++-v3/include/bits/regex_compiler.tcc +++ b/libstdc++-v3/include/bits/regex_compiler.tcc @@ -37,9 +37,9 @@ // When compiling, states are *chained* instead of tree- or graph-constructed. // It's more like structured programs: there's if statement and loop statement. // -// For alternative structure(say "a|b"), aka "if statement", two branchs should -// be constructed. However, these two shall merge to an "end_tag" at the end of -// this operator: +// For alternative structure (say "a|b"), aka "if statement", two branches +// should be constructed. However, these two shall merge to an "end_tag" at +// the end of this operator: // // branch1 // / \ @@ -151,7 +151,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION else if (_M_match_token(_ScannerT::_S_token_line_end)) _M_stack.push(_StateSeqT(_M_nfa, _M_nfa._M_insert_line_end())); else if (_M_match_token(_ScannerT::_S_token_word_bound)) - // _M_value[0] == 'n' means it's negtive, say "not word boundary". + // _M_value[0] == 'n' means it's negative, say "not word boundary". _M_stack.push(_StateSeqT(_M_nfa, _M_nfa. _M_insert_word_bound(_M_value[0] == 'n'))); else if (_M_match_token(_ScannerT::_S_token_subexpr_lookahead_begin)) @@ -256,7 +256,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION auto __end = _M_nfa._M_insert_dummy(); // _M_alt is the "match more" branch, and _M_next is the // "match less" one. Switch _M_alt and _M_next of all created - // nodes. This is a hacking but IMO works well. + // nodes. This is a hack but IMO works well. std::stack<_StateIdT> __stack; for (long __i = 0; __i < __n; ++__i) { @@ -397,7 +397,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _GLIBCXX_DEBUG_ASSERT(_M_value.size() == 1); _BracketMatcher<_TraitsT, __icase, __collate> __matcher (_M_ctype.is(_CtypeT::upper, _M_value[0]), _M_traits); - __matcher._M_add_character_class(_M_value); + __matcher._M_add_character_class(_M_value, false); __matcher._M_ready(); _M_stack.push(_StateSeqT(_M_nfa, _M_nfa._M_insert_matcher(std::move(__matcher)))); @@ -428,7 +428,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION else if (_M_match_token(_ScannerT::_S_token_equiv_class_name)) __matcher._M_add_equivalence_class(_M_value); else if (_M_match_token(_ScannerT::_S_token_char_class_name)) - __matcher._M_add_character_class(_M_value); + __matcher._M_add_character_class(_M_value, false); else if (_M_try_char()) // [a { auto __ch = _M_value[0]; @@ -451,6 +451,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } __matcher._M_add_char(__ch); } + else if (_M_match_token(_ScannerT::_S_token_quoted_class)) + __matcher._M_add_character_class(_M_value, + _M_ctype.is(_CtypeT::upper, + _M_value[0])); else __throw_regex_error(regex_constants::error_brack); } @@ -507,12 +511,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _BracketMatcher<_TraitsT, __icase, __collate>:: _M_apply(_CharT __ch, false_type) const { - bool __ret = false; - if (std::find(_M_char_set.begin(), _M_char_set.end(), - _M_translator._M_translate(__ch)) - != _M_char_set.end()) - __ret = true; - else + bool __ret = std::binary_search(_M_char_set.begin(), _M_char_set.end(), + _M_translator._M_translate(__ch)); + if (!__ret) { auto __s = _M_translator._M_transform(__ch); for (auto& __it : _M_range_set) @@ -527,6 +528,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _M_traits.transform_primary(&__ch, &__ch+1)) != _M_equiv_set.end()) __ret = true; + else + { + for (auto& __it : _M_neg_class_set) + if (!_M_traits.isctype(__ch, __it)) + { + __ret = true; + break; + } + } } if (_M_is_non_matching) return !__ret; diff --git a/libstdc++-v3/include/bits/regex_executor.h b/libstdc++-v3/include/bits/regex_executor.h index c110b88a3f4..1991c0007a1 100644 --- a/libstdc++-v3/include/bits/regex_executor.h +++ b/libstdc++-v3/include/bits/regex_executor.h @@ -42,8 +42,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION */ /** - * @brief Takes a regex and an input string in and - * do the matching. + * @brief Takes a regex and an input string and does the matching. * * The %_Executor class has two modes: DFS mode and BFS mode, controlled * by the template parameter %__dfs_mode. @@ -52,6 +51,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION bool __dfs_mode> class _Executor { + using __search_mode = integral_constant<bool, __dfs_mode>; + using __dfs = true_type; + using __bfs = false_type; + + enum class _Match_mode : unsigned char { _Exact, _Prefix }; + public: typedef typename iterator_traits<_BiIter>::value_type _CharT; typedef basic_regex<_CharT, _TraitsT> _RegexT; @@ -71,24 +76,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _M_re(__re), _M_nfa(*__re._M_automaton), _M_results(__results), - _M_match_queue(__dfs_mode ? nullptr - : new vector<pair<_StateIdT, _ResultsVec>>()), _M_rep_count(_M_nfa.size()), - _M_visited(__dfs_mode ? nullptr : new vector<bool>(_M_nfa.size())), + _M_states(_M_nfa._M_start(), _M_nfa.size()), _M_flags((__flags & regex_constants::match_prev_avail) ? (__flags & ~regex_constants::match_not_bol & ~regex_constants::match_not_bow) - : __flags), - _M_start_state(_M_nfa._M_start()) + : __flags) { } - // Set matched when string exactly match the pattern. + // Set matched when string exactly matches the pattern. bool _M_match() { _M_current = _M_begin; - return _M_main<true>(); + return _M_main(_Match_mode::_Exact); } // Set matched when some prefix of the string matches the pattern. @@ -96,24 +98,28 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _M_search_from_first() { _M_current = _M_begin; - return _M_main<false>(); + return _M_main(_Match_mode::_Prefix); } bool _M_search(); private: - template<bool __match_mode> - void - _M_rep_once_more(_StateIdT); + void + _M_rep_once_more(_Match_mode __match_mode, _StateIdT); - template<bool __match_mode> - void - _M_dfs(_StateIdT __start); + void + _M_dfs(_Match_mode __match_mode, _StateIdT __start); - template<bool __match_mode> - bool - _M_main(); + bool + _M_main(_Match_mode __match_mode) + { return _M_main_dispatch(__match_mode, __search_mode{}); } + + bool + _M_main_dispatch(_Match_mode __match_mode, __dfs); + + bool + _M_main_dispatch(_Match_mode __match_mode, __bfs); bool _M_is_word(_CharT __ch) const @@ -144,6 +150,53 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION bool _M_lookahead(_State<_TraitsT> __state); + // Holds additional information used in BFS-mode. + template<typename _SearchMode, typename _ResultsVec> + struct _State_info; + + template<typename _ResultsVec> + struct _State_info<__bfs, _ResultsVec> + { + explicit + _State_info(_StateIdT __start, size_t __n) + : _M_start(__start), _M_visited_states(new bool[__n]()) + { } + + bool _M_visited(_StateIdT __i) + { + if (_M_visited_states[__i]) + return true; + _M_visited_states[__i] = true; + return false; + } + + void _M_queue(_StateIdT __i, const _ResultsVec& __res) + { _M_match_queue.emplace_back(__i, __res); } + + // Saves states that need to be considered for the next character. + vector<pair<_StateIdT, _ResultsVec>> _M_match_queue; + // Indicates which states are already visited. + unique_ptr<bool[]> _M_visited_states; + // To record current solution. + _StateIdT _M_start; + }; + + template<typename _ResultsVec> + struct _State_info<__dfs, _ResultsVec> + { + explicit + _State_info(_StateIdT __start, size_t) : _M_start(__start) + { } + + // Dummy implementations for DFS mode. + bool _M_visited(_StateIdT) const { return false; } + void _M_queue(_StateIdT, const _ResultsVec&) { } + + // To record current solution. + _StateIdT _M_start; + }; + + public: _ResultsVec _M_cur_results; _BiIter _M_current; @@ -152,15 +205,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION const _RegexT& _M_re; const _NFAT& _M_nfa; _ResultsVec& _M_results; - // Used in BFS, saving states that need to be considered for the next - // character. - unique_ptr<vector<pair<_StateIdT, _ResultsVec>>> _M_match_queue; - // Used in BFS, indicating that which state is already visited. vector<pair<_BiIter, int>> _M_rep_count; - unique_ptr<vector<bool>> _M_visited; + _State_info<__search_mode, _ResultsVec> _M_states; _FlagT _M_flags; - // To record current solution. - _StateIdT _M_start_state; // Do we have a solution so far? bool _M_has_sol; }; diff --git a/libstdc++-v3/include/bits/regex_executor.tcc b/libstdc++-v3/include/bits/regex_executor.tcc index 7f8993382c8..aefa8f47137 100644 --- a/libstdc++-v3/include/bits/regex_executor.tcc +++ b/libstdc++-v3/include/bits/regex_executor.tcc @@ -35,7 +35,7 @@ namespace __detail _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _BiIter, typename _Alloc, typename _TraitsT, - bool __dfs_mode> + bool __dfs_mode> bool _Executor<_BiIter, _Alloc, _TraitsT, __dfs_mode>:: _M_search() { @@ -45,7 +45,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION do { _M_current = __cur; - if (_M_main<false>()) + if (_M_main(_Match_mode::_Prefix)) return true; } // Continue when __cur == _M_end @@ -53,8 +53,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return false; } - // This function operates in different modes, DFS mode or BFS mode, indicated - // by template parameter __dfs_mode. See _M_main for details. + // The _M_main function operates in different modes, DFS mode or BFS mode, + // indicated by template parameter __dfs_mode, and dispatches to one of the + // _M_main_dispatch overloads. // // ------------------------------------------------------------ // @@ -62,12 +63,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // // It applies a Depth-First-Search (aka backtracking) on given NFA and input // string. - // At the very beginning the executor stands in the start state, then it tries - // every possible state transition in current state recursively. Some state - // transitions consume input string, say, a single-char-matcher or a + // At the very beginning the executor stands in the start state, then it + // tries every possible state transition in current state recursively. Some + // state transitions consume input string, say, a single-char-matcher or a // back-reference matcher; some don't, like assertion or other anchor nodes. - // When the input is exhausted and/or the current state is an accepting state, - // the whole executor returns true. + // When the input is exhausted and/or the current state is an accepting + // state, the whole executor returns true. // // TODO: This approach is exponentially slow for certain input. // Try to compile the NFA to a DFA. @@ -75,6 +76,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // Time complexity: \Omega(match_length), O(2^(_M_nfa.size())) // Space complexity: \theta(match_results.size() + match_length) // + template<typename _BiIter, typename _Alloc, typename _TraitsT, + bool __dfs_mode> + bool _Executor<_BiIter, _Alloc, _TraitsT, __dfs_mode>:: + _M_main_dispatch(_Match_mode __match_mode, __dfs) + { + _M_has_sol = false; + _M_cur_results = _M_results; + _M_dfs(__match_mode, _M_states._M_start); + return _M_has_sol; + } + // ------------------------------------------------------------ // // BFS mode: @@ -84,11 +96,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // // It first computes epsilon closure (states that can be achieved without // consuming characters) for every state that's still matching, - // using the same DFS algorithm, but doesn't re-enter states (find a true in - // _M_visited), nor follows _S_opcode_match. + // using the same DFS algorithm, but doesn't re-enter states (using + // _M_states._M_visited to check), nor follow _S_opcode_match. // - // Then apply DFS using every _S_opcode_match (in _M_match_queue) as the start - // state. + // Then apply DFS using every _S_opcode_match (in _M_states._M_match_queue) + // as the start state. // // It significantly reduces potential duplicate states, so has a better // upper bound; but it requires more overhead. @@ -98,60 +110,45 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // Space complexity: \Omega(_M_nfa.size() + match_results.size()) // O(_M_nfa.size() * match_results.size()) template<typename _BiIter, typename _Alloc, typename _TraitsT, - bool __dfs_mode> - template<bool __match_mode> + bool __dfs_mode> bool _Executor<_BiIter, _Alloc, _TraitsT, __dfs_mode>:: - _M_main() + _M_main_dispatch(_Match_mode __match_mode, __bfs) { - if (__dfs_mode) + _M_states._M_queue(_M_states._M_start, _M_results); + bool __ret = false; + while (1) { _M_has_sol = false; - _M_cur_results = _M_results; - _M_dfs<__match_mode>(_M_start_state); - return _M_has_sol; - } - else - { - _M_match_queue->push_back(make_pair(_M_start_state, _M_results)); - bool __ret = false; - while (1) + if (_M_states._M_match_queue.empty()) + break; + std::fill_n(_M_states._M_visited_states.get(), _M_nfa.size(), false); + auto __old_queue = std::move(_M_states._M_match_queue); + for (auto& __task : __old_queue) { - _M_has_sol = false; - if (_M_match_queue->empty()) - break; - _M_visited->assign(_M_visited->size(), false); - auto _M_old_queue = std::move(*_M_match_queue); - for (auto __task : _M_old_queue) - { - _M_cur_results = __task.second; - _M_dfs<__match_mode>(__task.first); - } - if (!__match_mode) - __ret |= _M_has_sol; - if (_M_current == _M_end) - break; - ++_M_current; + _M_cur_results = std::move(__task.second); + _M_dfs(__match_mode, __task.first); } - if (__match_mode) - __ret = _M_has_sol; - return __ret; + if (__match_mode == _Match_mode::_Prefix) + __ret |= _M_has_sol; + if (_M_current == _M_end) + break; + ++_M_current; } + if (__match_mode == _Match_mode::_Exact) + __ret = _M_has_sol; + return __ret; } // Return whether now match the given sub-NFA. template<typename _BiIter, typename _Alloc, typename _TraitsT, - bool __dfs_mode> + bool __dfs_mode> bool _Executor<_BiIter, _Alloc, _TraitsT, __dfs_mode>:: _M_lookahead(_State<_TraitsT> __state) { _ResultsVec __what(_M_cur_results.size()); - auto __sub = std::unique_ptr<_Executor>(new _Executor(_M_current, - _M_end, - __what, - _M_re, - _M_flags)); - __sub->_M_start_state = __state._M_alt; - if (__sub->_M_search_from_first()) + _Executor __sub(_M_current, _M_end, __what, _M_re, _M_flags); + __sub._M_states._M_start = __state._M_alt; + if (__sub._M_search_from_first()) { for (size_t __i = 0; __i < __what.size(); __i++) if (__what[__i].matched) @@ -169,9 +166,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // we need to spare one more time for potential group capture. template<typename _BiIter, typename _Alloc, typename _TraitsT, bool __dfs_mode> - template<bool __match_mode> void _Executor<_BiIter, _Alloc, _TraitsT, __dfs_mode>:: - _M_rep_once_more(_StateIdT __i) + _M_rep_once_more(_Match_mode __match_mode, _StateIdT __i) { const auto& __state = _M_nfa[__i]; auto& __rep_count = _M_rep_count[__i]; @@ -180,7 +176,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION auto __back = __rep_count; __rep_count.first = _M_current; __rep_count.second = 1; - _M_dfs<__match_mode>(__state._M_alt); + _M_dfs(__match_mode, __state._M_alt); __rep_count = __back; } else @@ -188,24 +184,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION if (__rep_count.second < 2) { __rep_count.second++; - _M_dfs<__match_mode>(__state._M_alt); + _M_dfs(__match_mode, __state._M_alt); __rep_count.second--; } } }; template<typename _BiIter, typename _Alloc, typename _TraitsT, - bool __dfs_mode> - template<bool __match_mode> + bool __dfs_mode> void _Executor<_BiIter, _Alloc, _TraitsT, __dfs_mode>:: - _M_dfs(_StateIdT __i) + _M_dfs(_Match_mode __match_mode, _StateIdT __i) { - if (!__dfs_mode) - { - if ((*_M_visited)[__i]) - return; - (*_M_visited)[__i] = true; - } + if (_M_states._M_visited(__i)) + return; const auto& __state = _M_nfa[__i]; // Every change on _M_cur_results and _M_current will be rolled back after @@ -221,33 +212,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // Greedy. if (!__state._M_neg) { - _M_rep_once_more<__match_mode>(__i); + _M_rep_once_more(__match_mode, __i); // If it's DFS executor and already accepted, we're done. if (!__dfs_mode || !_M_has_sol) - _M_dfs<__match_mode>(__state._M_next); + _M_dfs(__match_mode, __state._M_next); } else // Non-greedy mode { if (__dfs_mode) { // vice-versa. - _M_dfs<__match_mode>(__state._M_next); + _M_dfs(__match_mode, __state._M_next); if (!_M_has_sol) - _M_rep_once_more<__match_mode>(__i); + _M_rep_once_more(__match_mode, __i); } else { // DON'T attempt anything, because there's already another - // state with higher priority accepted. This state cannot be - // better by attempting its next node. + // state with higher priority accepted. This state cannot + // be better by attempting its next node. if (!_M_has_sol) { - _M_dfs<__match_mode>(__state._M_next); + _M_dfs(__match_mode, __state._M_next); // DON'T attempt anything if it's already accepted. An // accepted state *must* be better than a solution that // matches a non-greedy quantifier one more time. if (!_M_has_sol) - _M_rep_once_more<__match_mode>(__i); + _M_rep_once_more(__match_mode, __i); } } } @@ -258,7 +249,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION auto& __res = _M_cur_results[__state._M_subexpr]; auto __back = __res.first; __res.first = _M_current; - _M_dfs<__match_mode>(__state._M_next); + _M_dfs(__match_mode, __state._M_next); __res.first = __back; } break; @@ -268,27 +259,27 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION auto __back = __res; __res.second = _M_current; __res.matched = true; - _M_dfs<__match_mode>(__state._M_next); + _M_dfs(__match_mode, __state._M_next); __res = __back; } break; case _S_opcode_line_begin_assertion: if (_M_at_begin()) - _M_dfs<__match_mode>(__state._M_next); + _M_dfs(__match_mode, __state._M_next); break; case _S_opcode_line_end_assertion: if (_M_at_end()) - _M_dfs<__match_mode>(__state._M_next); + _M_dfs(__match_mode, __state._M_next); break; case _S_opcode_word_boundary: if (_M_word_boundary(__state) == !__state._M_neg) - _M_dfs<__match_mode>(__state._M_next); + _M_dfs(__match_mode, __state._M_next); break; // Here __state._M_alt offers a single start node for a sub-NFA. // We recursively invoke our algorithm to match the sub-NFA. case _S_opcode_subexpr_lookahead: if (_M_lookahead(__state) == !__state._M_neg) - _M_dfs<__match_mode>(__state._M_next); + _M_dfs(__match_mode, __state._M_next); break; case _S_opcode_match: if (__dfs_mode) @@ -296,14 +287,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION if (_M_current != _M_end && __state._M_matches(*_M_current)) { ++_M_current; - _M_dfs<__match_mode>(__state._M_next); + _M_dfs(__match_mode, __state._M_next); --_M_current; } } else if (__state._M_matches(*_M_current)) - _M_match_queue->push_back(make_pair(__state._M_next, - _M_cur_results)); + _M_states._M_queue(__state._M_next, _M_cur_results); break; // First fetch the matched result from _M_cur_results as __submatch; // then compare it with @@ -328,11 +318,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { auto __backup = _M_current; _M_current = __last; - _M_dfs<__match_mode>(__state._M_next); + _M_dfs(__match_mode, __state._M_next); _M_current = __backup; } else - _M_dfs<__match_mode>(__state._M_next); + _M_dfs(__match_mode, __state._M_next); } } break; @@ -340,7 +330,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION if (__dfs_mode) { _GLIBCXX_DEBUG_ASSERT(!_M_has_sol); - if (__match_mode) + if (__match_mode == _Match_mode::_Exact) _M_has_sol = _M_current == _M_end; else _M_has_sol = true; @@ -355,7 +345,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION if (_M_current == _M_begin && (_M_flags & regex_constants::match_not_null)) break; - if (!__match_mode || _M_current == _M_end) + if (__match_mode == _Match_mode::_Prefix || _M_current == _M_end) if (!_M_has_sol) { _M_has_sol = true; @@ -364,9 +354,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } break; case _S_opcode_alternative: - _M_dfs<__match_mode>(__state._M_alt); + _M_dfs(__match_mode, __state._M_alt); if (!__dfs_mode || !_M_has_sol) - _M_dfs<__match_mode>(__state._M_next); + _M_dfs(__match_mode, __state._M_next); break; default: _GLIBCXX_DEBUG_ASSERT(false); @@ -375,7 +365,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // Return whether now is at some word boundary. template<typename _BiIter, typename _Alloc, typename _TraitsT, - bool __dfs_mode> + bool __dfs_mode> bool _Executor<_BiIter, _Alloc, _TraitsT, __dfs_mode>:: _M_word_boundary(_State<_TraitsT> __state) const { diff --git a/libstdc++-v3/include/bits/regex_scanner.tcc b/libstdc++-v3/include/bits/regex_scanner.tcc index f501ff6c2cb..818e47b5670 100644 --- a/libstdc++-v3/include/bits/regex_scanner.tcc +++ b/libstdc++-v3/include/bits/regex_scanner.tcc @@ -227,14 +227,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } } // In POSIX, when encountering "[]" or "[^]", the ']' is interpreted - // literally. So "[]]" or "[^]]" is valid regex. See the testcases + // literally. So "[]]" and "[^]]" are valid regexes. See the testcases // `*/empty_range.cc`. else if (__c == ']' && (_M_is_ecma() || !_M_at_bracket_start)) { _M_token = _S_token_bracket_end; _M_state = _S_state_normal; } - // ECMAScirpt and awk permmits escaping in bracket. + // ECMAScript and awk permits escaping in bracket. else if (__c == '\\' && (_M_is_ecma() || _M_is_awk())) (this->*_M_eat_escape)(); else @@ -344,7 +344,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } _M_token = _S_token_hex_num; } - // ECMAScript recongnizes multi-digit back-references. + // ECMAScript recognizes multi-digit back-references. else if (_M_ctype.is(_CtypeT::digit, __c)) { _M_value.assign(1, __c); @@ -392,6 +392,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION else { #ifdef __STRICT_ANSI__ + // POSIX says it is undefined to escape ordinary characters __throw_regex_error(regex_constants::error_escape); #else _M_token = _S_token_ord_char; @@ -435,8 +436,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __throw_regex_error(regex_constants::error_escape); } - // Eats a character class or throwns an exception. - // __ch cound be ':', '.' or '=', _M_current is the char after ']' when + // Eats a character class or throws an exception. + // __ch could be ':', '.' or '=', _M_current is the char after ']' when // returning. template<typename _CharT> void diff --git a/libstdc++-v3/include/bits/uses_allocator.h b/libstdc++-v3/include/bits/uses_allocator.h index 10131c0a967..7281508fc06 100644 --- a/libstdc++-v3/include/bits/uses_allocator.h +++ b/libstdc++-v3/include/bits/uses_allocator.h @@ -45,35 +45,33 @@ _GLIBCXX_HAS_NESTED_TYPE(allocator_type) template<typename _Tp, typename _Alloc, bool = __has_allocator_type<_Tp>::value> struct __uses_allocator_helper - : public false_type { }; + : false_type { }; template<typename _Tp, typename _Alloc> struct __uses_allocator_helper<_Tp, _Alloc, true> - : public integral_constant<bool, is_convertible<_Alloc, - typename _Tp::allocator_type>::value> + : is_convertible<_Alloc, typename _Tp::allocator_type>::type { }; /// [allocator.uses.trait] template<typename _Tp, typename _Alloc> struct uses_allocator - : public integral_constant<bool, - __uses_allocator_helper<_Tp, _Alloc>::value> + : __uses_allocator_helper<_Tp, _Alloc>::type { }; - template<typename _Tp, typename _Alloc, typename... _Args> - struct __uses_allocator_arg - : is_constructible<_Tp, _Alloc, _Args...> - { static_assert( uses_allocator<_Tp, _Alloc>::value, "uses allocator" ); }; - struct __uses_alloc_base { }; + struct __uses_alloc0 : __uses_alloc_base - { struct _Anything { _Anything(...) { } } _M_a; }; + { + struct _Sink { void operator=(const void*) { } } _M_a; + }; + template<typename _Alloc> struct __uses_alloc1 : __uses_alloc_base { const _Alloc* _M_a; }; + template<typename _Alloc> struct __uses_alloc2 : __uses_alloc_base { const _Alloc* _M_a; }; - template<bool, typename _Alloc, typename... _Args> + template<bool, typename _Tp, typename _Alloc, typename... _Args> struct __uses_alloc; template<typename _Tp, typename _Alloc, typename... _Args> @@ -89,15 +87,14 @@ _GLIBCXX_HAS_NESTED_TYPE(allocator_type) : __uses_alloc0 { }; template<typename _Tp, typename _Alloc, typename... _Args> - struct __uses_alloc_impl - : __uses_alloc<uses_allocator<_Tp, _Alloc>::value, _Tp, _Alloc, _Args...> - { }; + using __uses_alloc_t = + __uses_alloc<uses_allocator<_Tp, _Alloc>::value, _Tp, _Alloc, _Args...>; template<typename _Tp, typename _Alloc, typename... _Args> - __uses_alloc_impl<_Tp, _Alloc, _Args...> + inline __uses_alloc_t<_Tp, _Alloc, _Args...> __use_alloc(const _Alloc& __a) { - __uses_alloc_impl<_Tp, _Alloc, _Args...> __ret; + __uses_alloc_t<_Tp, _Alloc, _Args...> __ret; __ret._M_a = &__a; return __ret; } |