From patchwork Sun Nov 27 00:27:09 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tim Shen X-Patchwork-Id: 699568 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3tR9cy3mrBz9t1B for ; Sun, 27 Nov 2016 11:27:44 +1100 (AEDT) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="MqkDblq7"; dkim-atps=neutral DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :mime-version:from:date:message-id:subject:to:content-type; q= dns; s=default; b=I3KRT8Ul0X64lV1rOgoB14qJ4b5GpJNZb7Wz2ZWFVu2okd wwuy7BXbmaYFXKOI/5cytXiXBKgRUkqhw79QMyHkZQ/r8JUbOapIQSQN30KVAuTt 0lyO7xqwnivW1cT6t7NN9bGw2OFqV1J5DEImmmCUcHiVPW3zG5ypozJxOy/0Y= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :mime-version:from:date:message-id:subject:to:content-type; s= default; bh=abek5ku0msjvyfRuYDvERMSOLoM=; b=MqkDblq7k7KK5o2KS9ah 25+UdXdRApRbbpNK9hmwNyb4W0e10juXWAq023ifuqEfpuoilDiq2HhOR7w4PTs1 Xm5Iln7ggNwUqJjPLIpTZsMKTK7/o5uL8Scam0Z5YmzPEPAoyFjcufBXS3ItAue0 wKY6us3BK7WNmBcKY9cTgiY= Received: (qmail 48162 invoked by alias); 27 Nov 2016 00:27:24 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 48135 invoked by uid 89); 27 Nov 2016 00:27:22 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-4.9 required=5.0 tests=AWL, BAYES_00, RCVD_IN_DNSWL_NONE, RP_MATCHES_RCVD, SPF_PASS autolearn=ham version=3.3.2 spammy=HTo:U*libstdc, tf, D*google.com, shen X-HELO: mail-ua0-f171.google.com Received: from mail-ua0-f171.google.com (HELO mail-ua0-f171.google.com) (209.85.217.171) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Sun, 27 Nov 2016 00:27:12 +0000 Received: by mail-ua0-f171.google.com with SMTP id 51so110024311uai.1 for ; Sat, 26 Nov 2016 16:27:12 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:from:date:message-id:subject:to; bh=cuTkNIVlE8OCt/ohJ6qSM3lnHNYQfKf1VBb6DOMV09Y=; b=iMvjkeEvtRyi4Bc0mgypJdNn6A7aNGDuYiIEM+aY11odHswHczei6tnbs/fJ2JrzDI BVm0rT3AKYs1oDeBi7xqMrOLUMPZGjriX6Z6s7Z8C+h5x/ZQB+DFR1+4Ag5XxNQ1vecb 559oMmnJx9QEGFTJO9WcnNzjTZ0uHj/N/t57Jg+zMMrU7uDGsiHqIS4fRUjw8zUl49NY prOnk3t79nBGpJc7DaNxVyzwawxSUXKilVOBPAkvlqloAr/az6xtZOgeg1J8NFnng0nc rj1HZcF88z4ML2jIcqQhAAkv8+HlNfzh9X0j15Ny89tx6o5c37hdG4oBDlLCAqA4Lj9Q tPhw== X-Gm-Message-State: AKaTC01ut4EQI6OM8oORMEWZnZD/tm6kmvqCuaICJs8qZnIFnYQeg9z4xdoSlFlUkUUrxYiCPAIK1LDwb2c66sfT X-Received: by 10.176.68.132 with SMTP id n4mr5951986uan.75.1480206430537; Sat, 26 Nov 2016 16:27:10 -0800 (PST) MIME-Version: 1.0 Received: by 10.103.31.69 with HTTP; Sat, 26 Nov 2016 16:27:09 -0800 (PST) From: Tim Shen Date: Sat, 26 Nov 2016 16:27:09 -0800 Message-ID: Subject: [PATCH] Partial solution to LWG 523 To: "libstdc++" , gcc-patches Also see discussions from libstdc++/71500. Bootstrapped and tested on x86_64-linux-gnu. Thanks! diff --git a/libstdc++-v3/include/bits/regex.h b/libstdc++-v3/include/bits/regex.h index aadf312..224d3db 100644 --- a/libstdc++-v3/include/bits/regex.h +++ b/libstdc++-v3/include/bits/regex.h @@ -762,7 +762,9 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 template basic_regex(_FwdIter __first, _FwdIter __last, locale_type __loc, flag_type __f) - : _M_flags(__f), _M_loc(std::move(__loc)), + : _M_flags((__f & (ECMAScript | basic | extended | awk | grep | egrep)) + ? __f : (__f | ECMAScript)), + _M_loc(std::move(__loc)), _M_automaton(__detail::__compile_nfa<_FwdIter, _Rx_traits>( std::move(__first), std::move(__last), _M_loc, _M_flags)) { } diff --git a/libstdc++-v3/include/bits/regex_compiler.h b/libstdc++-v3/include/bits/regex_compiler.h index 410d61b..964fb28 100644 --- a/libstdc++-v3/include/bits/regex_compiler.h +++ b/libstdc++-v3/include/bits/regex_compiler.h @@ -30,6 +30,15 @@ namespace std _GLIBCXX_VISIBILITY(default) { +_GLIBCXX_BEGIN_NAMESPACE_VERSION +_GLIBCXX_BEGIN_NAMESPACE_CXX11 + + template + class regex_traits; + +_GLIBCXX_END_NAMESPACE_CXX11 +_GLIBCXX_END_NAMESPACE_VERSION + namespace __detail { _GLIBCXX_BEGIN_NAMESPACE_VERSION @@ -207,17 +216,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // [28.13.14] template - class _RegexTranslator + class _RegexTranslatorBase { public: typedef typename _TraitsT::char_type _CharT; typedef typename _TraitsT::string_type _StringT; - typedef typename std::conditional<__collate, - _StringT, - _CharT>::type _StrTransT; + typedef _StringT _StrTransT; explicit - _RegexTranslator(const _TraitsT& __traits) + _RegexTranslatorBase(const _TraitsT& __traits) : _M_traits(__traits) { } @@ -235,23 +242,86 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _StrTransT _M_transform(_CharT __ch) const { - return _M_transform_impl(__ch, typename integral_constant::type()); + _StrTransT __str = _StrTransT(1, __ch); + return _M_traits.transform(__str.begin(), __str.end()); } - private: + // See LWG 523. It's not efficiently implementable when _TraitsT is not + // std::regex_traits<>, and __collate is true. See specializations for + // implementations of other cases. + bool + _M_match_range(const _StrTransT& __first, const _StrTransT& __last, + const _StrTransT& __s) const + { return __first <= __s && __s <= __last; } + + protected: + bool _M_in_range_icase(_CharT __first, _CharT __last, _CharT __ch) const + { + typedef std::ctype<_CharT> __ctype_type; + const auto& __fctyp = use_facet<__ctype_type>(this->_M_traits.getloc()); + auto __lower = __fctyp.tolower(__ch); + auto __upper = __fctyp.toupper(__ch); + return (__first <= __lower && __lower <= __last) + || (__first <= __upper && __upper <= __last); + } + + const _TraitsT& _M_traits; + }; + + template + class _RegexTranslator + : public _RegexTranslatorBase<_TraitsT, __icase, __collate> + { + public: + typedef _RegexTranslatorBase<_TraitsT, __icase, __collate> _Base; + using _Base::_Base; + }; + + template + class _RegexTranslator<_TraitsT, __icase, false> + : public _RegexTranslatorBase<_TraitsT, __icase, false> + { + public: + typedef _RegexTranslatorBase<_TraitsT, __icase, false> _Base; + typedef typename _Base::_CharT _CharT; + typedef _CharT _StrTransT; + + using _Base::_Base; + _StrTransT - _M_transform_impl(_CharT __ch, false_type) const + _M_transform(_CharT __ch) const { return __ch; } - _StrTransT - _M_transform_impl(_CharT __ch, true_type) const + bool + _M_match_range(_CharT __first, _CharT __last, _CharT __ch) const { - _StrTransT __str = _StrTransT(1, _M_translate(__ch)); - return _M_traits.transform(__str.begin(), __str.end()); + if (!__icase) + return __first <= __ch && __ch <= __last; + return this->_M_in_range_icase(__first, __last, __ch); } + }; - const _TraitsT& _M_traits; + template + class _RegexTranslator, true, true> + : public _RegexTranslatorBase, true, true> + { + public: + typedef _RegexTranslatorBase, true, true> + _Base; + typedef typename _Base::_CharT _CharT; + typedef typename _Base::_StrTransT _StrTransT; + + using _Base::_Base; + + bool + _M_match_range(const _StrTransT& __first, const _StrTransT& __last, + const _StrTransT& __str) const + { + __glibcxx_assert(__first.size() == 1); + __glibcxx_assert(__last.size() == 1); + __glibcxx_assert(__str.size() == 1); + return this->_M_in_range_icase(__first[0], __last[0], __str[0]); + } }; template @@ -272,6 +342,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _StrTransT _M_transform(_CharT __ch) const { return __ch; } + + bool + _M_match_range(_CharT __first, _CharT __last, _CharT __ch) const + { return __first <= __ch && __ch <= __last; } }; template diff --git a/libstdc++-v3/include/bits/regex_compiler.tcc b/libstdc++-v3/include/bits/regex_compiler.tcc index ef6ebdd..07e56d5 100644 --- a/libstdc++-v3/include/bits/regex_compiler.tcc +++ b/libstdc++-v3/include/bits/regex_compiler.tcc @@ -612,37 +612,26 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _BracketMatcher<_TraitsT, __icase, __collate>:: _M_apply(_CharT __ch, false_type) const { - 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) - if (__it.first <= __s && __s <= __it.second) - { - __ret = true; - break; - } - if (_M_traits.isctype(__ch, _M_class_set)) - __ret = true; - else if (std::find(_M_equiv_set.begin(), _M_equiv_set.end(), - _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; - else - return __ret; + return [this, __ch] + { + if (std::binary_search(_M_char_set.begin(), _M_char_set.end(), + _M_translator._M_translate(__ch))) + return true; + auto __s = _M_translator._M_transform(__ch); + for (auto& __it : _M_range_set) + if (_M_translator._M_match_range(__it.first, __it.second, __s)) + return true; + if (_M_traits.isctype(__ch, _M_class_set)) + return true; + if (std::find(_M_equiv_set.begin(), _M_equiv_set.end(), + _M_traits.transform_primary(&__ch, &__ch+1)) + != _M_equiv_set.end()) + return true; + for (auto& __it : _M_neg_class_set) + if (!_M_traits.isctype(__ch, __it)) + return true; + return false; + }() ^ _M_is_non_matching; } _GLIBCXX_END_NAMESPACE_VERSION diff --git a/libstdc++-v3/include/bits/shared_ptr_base.h b/libstdc++-v3/include/bits/shared_ptr_base.h index 953aa87..2fb70b7 100644 --- a/libstdc++-v3/include/bits/shared_ptr_base.h +++ b/libstdc++-v3/include/bits/shared_ptr_base.h @@ -1000,7 +1000,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION element_type& operator*() const noexcept { - __glibcxx_assert(_M_ptr != nullptr); + __glibcxx_assert(_M_get() != nullptr); return *_M_get(); } diff --git a/libstdc++-v3/testsuite/28_regex/traits/char/icase.cc b/libstdc++-v3/testsuite/28_regex/traits/char/icase.cc new file mode 100644 index 0000000..6b2d9ee --- /dev/null +++ b/libstdc++-v3/testsuite/28_regex/traits/char/icase.cc @@ -0,0 +1,75 @@ +// { dg_do run } +// { dg-do run { target c++11 } } + +// +// Copyright (C) 2016 Free Software Foundation, Inc. +// +// 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. +// +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// 28.7 Class template regex_traits [re.traits] + +#include +#include + +using namespace std; + +void +test01() +{ + { + regex re("[T-f]", regex::icase); + + VERIFY(regex_match("A", re)); + VERIFY(regex_match("F", re)); + VERIFY(regex_match("a", re)); + VERIFY(regex_match("f", re)); + + VERIFY(!regex_match("G", re)); + VERIFY(!regex_match("S", re)); + VERIFY(!regex_match("g", re)); + VERIFY(!regex_match("s", re)); + + VERIFY(regex_match("T", re)); + VERIFY(regex_match("Z", re)); + VERIFY(regex_match("t", re)); + VERIFY(regex_match("z", re)); + } + // icase works with std::regex_traits<>, because we know how it's implemented. + { + regex re("[T-f]", regex::icase | regex::collate); + + VERIFY(regex_match("A", re)); + VERIFY(regex_match("F", re)); + VERIFY(regex_match("a", re)); + VERIFY(regex_match("f", re)); + + VERIFY(!regex_match("G", re)); + VERIFY(!regex_match("S", re)); + VERIFY(!regex_match("g", re)); + VERIFY(!regex_match("s", re)); + + VERIFY(regex_match("T", re)); + VERIFY(regex_match("Z", re)); + VERIFY(regex_match("t", re)); + VERIFY(regex_match("z", re)); + } +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/28_regex/traits/char/user_defined.cc b/libstdc++-v3/testsuite/28_regex/traits/char/user_defined.cc index 4af0563..5888ce1 100644 --- a/libstdc++-v3/testsuite/28_regex/traits/char/user_defined.cc +++ b/libstdc++-v3/testsuite/28_regex/traits/char/user_defined.cc @@ -30,6 +30,9 @@ using namespace std; +bool called_transform = false; +bool called_nocase = false; + template class MyRegexTraits : public regex_traits @@ -40,14 +43,71 @@ template { return c+1; } + + CharT + translate_nocase(CharT c) const + { + called_nocase = true; + return regex_traits::translate_nocase(c); + } + + template + basic_string + transform(FwdIt begin, FwdIt end) const + { + called_transform = true; + return regex_traits::transform(begin, end); + } }; void test01() { - basic_regex> re("."); - VERIFY(!regex_match("\n", re)); - VERIFY(!regex_match("\r", re)); + { + basic_regex> re("."); + VERIFY(!regex_match("\n", re)); + VERIFY(!regex_match("\r", re)); + } + { + VERIFY(!called_transform); + basic_regex> re("[a]", regex::collate); + VERIFY(regex_match("a", re)); + VERIFY(exchange(called_transform, false)); + } + { + VERIFY(!called_nocase); + basic_regex> re("[a]", regex::icase); + VERIFY(regex_match("A", re)); + VERIFY(exchange(called_nocase, false)); + } + { + basic_regex> re("[T-f]", regex::icase); + VERIFY(regex_match("A", re)); + VERIFY(regex_match("F", re)); + VERIFY(regex_match("a", re)); + VERIFY(regex_match("f", re)); + + VERIFY(!regex_match("G", re)); + VERIFY(!regex_match("S", re)); + VERIFY(!regex_match("g", re)); + VERIFY(!regex_match("s", re)); + + VERIFY(regex_match("T", re)); + VERIFY(regex_match("Z", re)); + VERIFY(regex_match("t", re)); + VERIFY(regex_match("z", re)); + } + // icase doesn't participate with the presence of collate and user-defined traits. + { + basic_regex> re("[T-f]", regex::icase | regex::collate); + VERIFY(!regex_match("A", re)); + VERIFY(!regex_match("S", re)); + VERIFY(regex_match("T", re)); + VERIFY(regex_match("Z", re)); + VERIFY(regex_match("a", re)); + VERIFY(regex_match("f", re)); + VERIFY(!regex_match("g", re)); + } } int main()