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

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


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);
>+  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.


>+
>+  TESTHEAD("check broken format");
>+  iss.str("2014-04-14 01:09:35");
>+  format = "%";
>+  ret = tget.get(istreambuf_iterator<char>(iss), end, iss, err, &time,
>+                 format.data(), format.data()+format.size());
>+  VERIFY(err == ios_base::failbit);
>+
>+  TESTHEAD("check single format letter version");
>+  iss.str("2020");
>+  ret = tget.get(istreambuf_iterator<char>(iss), end, iss, err, &time, 'Y');
>+  VERIFY(err == ios_base::goodbit);
>+  VERIFY(time.tm_year == 120);
>+  VERIFY(ret == end);

Shouldn't this set err == eofbit too?

The 1.cc tests seem like they can never pass.



More information about the Libstdc++ mailing list