[PATCH 1/3] libstdc++: Add time_get::get support.

Jonathan Wakely jwakely@redhat.com
Sat Dec 20 13:43:00 GMT 2014


On 20/12/14 13:07 +0000, Jonathan Wakely wrote:
>On 15/04/14 23:19 +0200, Rüdiger Sonderfeld wrote:
>>This patch adds support for std::time_get::get and std::time_get::do_get
>>[locale.time.get].  Currently do_get is not virtual because this caused
>>segfault errors for me.
>
>Hi Rüdiger, I'm trying to apply this patch and the tests don't work.
>
>There also seem to be some problems in the new functions.
>
>>* libstdc++-v3/include/bits/locale_facets_nonio.h (time_get::get):
>> (time_get::do_get):  New method (C++11).
>>* libstdc++-v3/include/bits/locale_facets_nonio.tcc (time_get::get):
>> (time_get::do_get):  New method (C++11).
>>* libstdc++-v3/testsuite/22_locale/time_get/get/char/1.cc: New file.
>>* libstdc++-v3/testsuite/22_locale/time_get/get/char/2.cc: New file.
>>---
>>libstdc++-v3/include/bits/locale_facets_nonio.h    |  73 ++++++++++++
>>libstdc++-v3/include/bits/locale_facets_nonio.tcc  | 102 ++++++++++++++++
>>.../testsuite/22_locale/time_get/get/char/1.cc     | 129 ++++++++++++++++++++
>>.../testsuite/22_locale/time_get/get/char/2.cc     | 103 ++++++++++++++++
>>.../testsuite/22_locale/time_get/get/wchar_t/1.cc  | 130 +++++++++++++++++++++
>>.../testsuite/22_locale/time_get/get/wchar_t/2.cc  | 104 +++++++++++++++++
>>6 files changed, 641 insertions(+)
>>create mode 100644 libstdc++-v3/testsuite/22_locale/time_get/get/char/1.cc
>>create mode 100644 libstdc++-v3/testsuite/22_locale/time_get/get/char/2.cc
>>create mode 100644 libstdc++-v3/testsuite/22_locale/time_get/get/wchar_t/1.cc
>>create mode 100644 libstdc++-v3/testsuite/22_locale/time_get/get/wchar_t/2.cc
>>
>>diff --git a/libstdc++-v3/include/bits/locale_facets_nonio.tcc b/libstdc++-v3/include/bits/locale_facets_nonio.tcc
>>index 41d944d..93466b6 100644
>>--- a/libstdc++-v3/include/bits/locale_facets_nonio.tcc
>>+++ b/libstdc++-v3/include/bits/locale_facets_nonio.tcc
>>@@ -1137,6 +1137,108 @@ _GLIBCXX_END_NAMESPACE_LDBL
>>      return __beg;
>>    }
>>
>>+#if __cplusplus >= 201103L
>>+  template<typename _CharT, typename _InIter>
>>+    inline
>>+    _InIter
>>+    time_get<_CharT, _InIter>::
>>+    get(iter_type __s, iter_type __end, ios_base& __io,
>>+        ios_base::iostate& __err, tm* __tm, const char_type *__fmt,
>>+        const char_type *__fmtend) const
>>+    {
>>+      const locale& __loc = __io._M_getloc();
>>+      ctype<_CharT> const& __ctype = use_facet<ctype<_CharT> >(__loc);
>>+      __err = ios_base::goodbit;
>>+      while (__fmt != __fmtend &&
>>+             __err == ios_base::goodbit)
>>+        {
>>+          if (__s == __end)
>>+            {
>>+              __err = ios_base::eofbit | ios_base::failbit;
>>+              break;
>>+            }
>>+          else if (__ctype.narrow(*__fmt, 0) == '%')
>>+            {
>>+              char __format;
>>+              char __mod = 0;
>>+              if (++__fmt == __fmtend)
>>+                {
>>+                  __err = ios_base::failbit;
>>+                  break;
>>+                }
>>+              const char __c = __ctype.narrow(*__fmt, 0);
>>+              if (__c != 'E' && __c != 'O')
>>+                __format = __c;
>>+              else if (++__fmt != __fmtend)
>>+                {
>>+                  __mod = __c;
>>+                  __format = __ctype.narrow(*__fmt, 0);
>>+                }
>>+              else
>>+                {
>>+                  __err = ios_base::failbit;
>>+                  break;
>>+                }
>>+              __s = this->do_get(__s, __end, __io, __err, __tm, __format, __mod);
>>+              ++__fmt;
>>+            }
>>+          else if (__ctype.is(ctype_base::space, *__fmt))
>>+            {
>>+              ++__fmt;
>>+              while (__fmt != __fmtend &&
>>+                     __ctype.is(ctype_base::space, *__fmt))
>>+                ++__fmt;
>>+
>>+              while (__s != __end &&
>>+                     __ctype.is(ctype_base::space, *__s))
>>+                ++__s;
>>+            }
>>+          // TODO real case-insensitive comparison
>>+          else if (__ctype.tolower(*__s) == __ctype.tolower(*__fmt) ||
>>+                   __ctype.toupper(*__s) == __ctype.toupper(*__fmt))
>>+            {
>>+              ++__s;
>>+              ++__fmt;
>>+            }
>>+          else
>>+            {
>>+              __err = ios_base::failbit;
>>+              break;
>>+            }
>>+        }
>>+      return __s;
>>+    }
>>+
>>+  template<typename _CharT, typename _InIter>
>>+    inline
>>+    _InIter
>>+    time_get<_CharT, _InIter>::
>>+    do_get(iter_type __beg, iter_type __end, ios_base& __io,
>>+           ios_base::iostate& __err, tm* __tm,
>>+           char __format, char __mod) const
>>+    {
>>+      const locale& __loc = __io._M_getloc();
>>+      ctype<_CharT> const& __ctype = use_facet<ctype<_CharT> >(__loc);
>
>Shouldn't this set err = goodbit before doing anything?
>
> "Effects: The function starts by evaluating err = ios_base::goodbit."
>
>>+      char_type __fmt[4];
>>+      __fmt[0] = __ctype.widen('%');
>>+      if (!__mod)
>>+        {
>>+          __fmt[1] = __format;
>>+          __fmt[2] = char_type();
>>+        }
>>+      else
>>+        {
>>+          __fmt[1] = __mod;
>>+          __fmt[2] = __format;
>>+          __fmt[3] = char_type();
>>+        }
>>+
>>+      return _M_extract_via_format(__beg, __end, __io, __err, __tm, __fmt);
>
>It also doesn't seem to meet this requirement:
>
> "When s == end evaluates to true after reading a character the
> function evaluates err |= ios_base::eofbit.
>
>>+    }
>>+
>>+#endif // __cplusplus >= 201103L
>>+
>>  template<typename _CharT, typename _OutIter>
>>    _OutIter
>>    time_put<_CharT, _OutIter>::
>>diff --git a/libstdc++-v3/testsuite/22_locale/time_get/get/char/1.cc b/libstdc++-v3/testsuite/22_locale/time_get/get/char/1.cc
>>new file mode 100644
>>index 0000000..1ad7822
>>--- /dev/null
>>+++ b/libstdc++-v3/testsuite/22_locale/time_get/get/char/1.cc
>>@@ -0,0 +1,129 @@
>>+// { dg-options " -std=gnu++11 " }
>>+
>>+// 2014-04-14 Rüdiger Sonderfeld  <ruediger@c-plusplus.de>
>>+
>>+// Copyright (C) 2014 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
>>+// <http://www.gnu.org/licenses/>.
>>+
>>+// 22.4.5.1.1 (C++11) time_get members [locale.time.get.members]
>>+
>>+#include <locale>
>>+#include <sstream>
>>+#include <iterator>
>>+#include <testsuite_hooks.h>
>>+
>>+#ifndef _GLIBCXX_ASSERT
>>+#  include <iostream>
>>+#  define PRINT(x) cout << #x << ": " << x << endl
>>+#  define TESTHEAD(x) cout << x << endl
>>+#else
>>+#  define PRINT(x) do {} while(false)
>>+#  define TESTHEAD(x) do {} while(false)
>>+#endif
>>+
>>+void test01()
>>+{
>>+  using namespace std;
>>+  bool test __attribute__((unused)) = true;
>>+
>>+  locale loc_c = locale::classic();
>>+
>>+  istringstream iss;
>>+  iss.imbue(loc_c);
>>+  const time_get<char>& tget = use_facet<time_get<char>>(iss.getloc());
>>+  const istreambuf_iterator<char> end;
>>+
>>+  tm time;
>>+  ios_base::iostate err;
>>+
>>+  // check regular operations with format string
>>+  TESTHEAD("regular operations");
>>+  iss.str("d 2014-04-14 01:09:35");
>>+  string format = "d %Y-%m-%d %H:%M:%S";
>>+  auto ret = tget.get(istreambuf_iterator<char>(iss), end, iss, err, &time,
>>+                      format.data(), format.data()+format.size());
>>+  PRINT(err);
>>+  VERIFY(err == ios_base::goodbit);
>
>libc++ sets eofbit here.
>
>>+  VERIFY(ret == end);
>>+  PRINT(time.tm_year);
>>+  VERIFY(time.tm_year == 114);
>>+  PRINT(time.tm_mon);
>>+  VERIFY(time.tm_mon == 3);
>>+  PRINT(time.tm_mday);
>>+  VERIFY(time.tm_mday == 14);
>>+  PRINT(time.tm_hour);
>>+  VERIFY(time.tm_hour == 1);
>>+  PRINT(time.tm_min);
>>+  VERIFY(time.tm_min == 9);
>>+  PRINT(time.tm_sec);
>>+  VERIFY(time.tm_sec == 35);
>>+
>>+  TESTHEAD("check eof");
>>+  iss.str("2020");
>>+  ret = tget.get(istreambuf_iterator<char>(iss), end, iss, err, &time,
>>+                 format.data(), format.data()+format.size());
>>+  VERIFY(err == ios_base::eofbit | ios_base::failbit);

And this is always true, because == has higher precedence than |

>>+  VERIFY(ret == end);
>
>How can this test pass?
>
>Is there a format = "%Y" missing?
>
>You cannot parse "2020" using the format "d %Y-%m-%d %H:%M:%S" so it
>should not reach EOF and should not set ret = end.



More information about the Libstdc++ mailing list