public inbox for libstdc++-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc(refs/users/aoliva/heads/testme)] [libstdc++] encode __time_get_state in tm
@ 2023-02-17 5:00 Alexandre Oliva
0 siblings, 0 replies; only message in thread
From: Alexandre Oliva @ 2023-02-17 5:00 UTC (permalink / raw)
To: gcc-cvs, libstdc++-cvs
https://gcc.gnu.org/g:674ed3d302857f2ae3c669c1d36877bfde602953
commit 674ed3d302857f2ae3c669c1d36877bfde602953
Author: Alexandre Oliva <oliva@adacore.com>
Date: Fri Feb 17 01:59:08 2023 -0300
[libstdc++] encode __time_get_state in tm
On platforms that fail the ptrtomemfn-cast-to-pfn hack, such as
arm-*-vxworks*, time_get fails with %I and %p because the state is not
preserved across do_get calls.
This patch introduces an alternate hack, that encodes the state in
unused bits of struct tm before calling do_get, extracts them in
do_get, does the processing, and encodes it back, so that get extracts
it.
The finalizer is adjusted for idempotence, because both do_get and get
may call it.
for libstdc++-v3/ChangeLog
* include/bits/locale_facets_nonio.h (__time_get_state): Add
_M_state_tm, _M_save_to and _M_restore_from.
* include/bits/locale_facets_nonio.tcc (time_get::get): Drop
do_get-overriding hack. Use state unconditionally, and encode
it in tm around do_get.
(time_get::do_get): Extract state from tm, and encode it back,
around parsing and finalizing.
* src/c++98/locale_facets.cc
(__time_get_state::_M_finalize_state): Make tm_hour and
tm_year idempotent.
Change-Id: I6fff27a23fb3da7921756069957d5672d25e6a6f
TN: W127-053
Diff:
---
libstdc++-v3/include/bits/locale_facets_nonio.h | 80 +++++++++++++++++++++++
libstdc++-v3/include/bits/locale_facets_nonio.tcc | 43 ++----------
libstdc++-v3/src/c++98/locale_facets.cc | 8 ++-
3 files changed, 93 insertions(+), 38 deletions(-)
diff --git a/libstdc++-v3/include/bits/locale_facets_nonio.h b/libstdc++-v3/include/bits/locale_facets_nonio.h
index 372cf042950..711bede1584 100644
--- a/libstdc++-v3/include/bits/locale_facets_nonio.h
+++ b/libstdc++-v3/include/bits/locale_facets_nonio.h
@@ -361,6 +361,86 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
void
_M_finalize_state(tm* __tm);
+ private:
+ void
+ _M_state_tm(tm* __tm, bool __totm)
+ {
+ // Check we don't invade the in-range tm bits, even if int is
+ // 16-bits wide.
+#define _M_min_shift_tm_sec 6
+#define _M_min_shift_tm_min 6
+#define _M_min_shift_tm_hour 5
+#define _M_min_shift_tm_mday 5
+#define _M_min_shift_tm_mon 4
+#define _M_min_shift_tm_year 16 // 14, but signed, so avoid it.
+#define _M_min_shift_tm_wday 3
+#define _M_min_shift_tm_yday 9
+#define _M_min_shift_tm_isdst 1
+ // Represent __STF in __WDT bits of __TMF up to the __MSB bit.
+ // In __MSB, 0 stands for the most significant bit of __TMF,
+ // 1 the bit next to it, and so on.
+#define _M_time_get_state_bitfield_inout(__tmf, __msb, __wdt, __stf) \
+ do \
+ { \
+ const unsigned __shift = (sizeof (__tm->__tmf) * __CHAR_BIT__ \
+ - (__msb) - (__wdt)); \
+ static char __attribute__ ((__unused__)) \
+ __check_parms_##__tmf[(__msb) >= 0 && (__wdt) > 0 \
+ && __shift >= (_M_min_shift_##__tmf \
+ + (sizeof (__tm->__tmf) \
+ * __CHAR_BIT__) - 16) \
+ ? 1 : -1]; \
+ const unsigned __mask = ((1 << (__wdt)) - 1) << __shift; \
+ if (!__totm) \
+ this->__stf = (__tm->__tmf & __mask) >> __shift; \
+ __tm->__tmf &= ~__mask; \
+ if (__totm) \
+ __tm->__tmf |= ((unsigned)this->__stf << __shift) & __mask; \
+ } \
+ while (0)
+
+ _M_time_get_state_bitfield_inout (tm_hour, 0, 1, _M_have_I);
+ _M_time_get_state_bitfield_inout (tm_wday, 0, 1, _M_have_wday);
+ _M_time_get_state_bitfield_inout (tm_yday, 0, 1, _M_have_yday);
+ _M_time_get_state_bitfield_inout (tm_mon, 0, 1, _M_have_mon);
+ _M_time_get_state_bitfield_inout (tm_mday, 0, 1, _M_have_mday);
+ _M_time_get_state_bitfield_inout (tm_yday, 1, 1, _M_have_uweek);
+ _M_time_get_state_bitfield_inout (tm_yday, 2, 1, _M_have_wweek);
+ _M_time_get_state_bitfield_inout (tm_isdst, 0, 1, _M_have_century);
+ _M_time_get_state_bitfield_inout (tm_hour, 1, 1, _M_is_pm);
+ _M_time_get_state_bitfield_inout (tm_isdst, 1, 1, _M_want_century);
+ _M_time_get_state_bitfield_inout (tm_yday, 3, 1, _M_want_xday);
+ // _M_pad1
+ _M_time_get_state_bitfield_inout (tm_wday, 1, 6, _M_week_no);
+ // _M_pad2
+ _M_time_get_state_bitfield_inout (tm_mon, 1, 8, _M_century);
+ // _M_pad3
+
+#undef _M_min_shift_tm_hour
+#undef _M_min_shift_tm_sec
+#undef _M_min_shift_tm_min
+#undef _M_min_shift_tm_hour
+#undef _M_min_shift_tm_mday
+#undef _M_min_shift_tm_mon
+#undef _M_min_shift_tm_year
+#undef _M_min_shift_tm_wday
+#undef _M_min_shift_tm_yday
+#undef _M_min_shift_tm_isdst
+#undef _M_time_get_state_bitfield_inout
+ }
+ public:
+ // Encode *THIS into scratch bits of __TM.
+ void
+ _M_save_to(tm* __tm) {
+ _M_state_tm (__tm, true);
+ }
+
+ // Decode and zero out scratch bits of __TM back into *THIS.
+ void
+ _M_restore_from(tm* __tm) {
+ _M_state_tm (__tm, false);
+ }
+
unsigned int _M_have_I : 1;
unsigned int _M_have_wday : 1;
unsigned int _M_have_yday : 1;
diff --git a/libstdc++-v3/include/bits/locale_facets_nonio.tcc b/libstdc++-v3/include/bits/locale_facets_nonio.tcc
index b19f4425300..47d243ce84d 100644
--- a/libstdc++-v3/include/bits/locale_facets_nonio.tcc
+++ b/libstdc++-v3/include/bits/locale_facets_nonio.tcc
@@ -1464,21 +1464,8 @@ _GLIBCXX_END_NAMESPACE_LDBL_OR_CXX11
const locale& __loc = __io._M_getloc();
ctype<_CharT> const& __ctype = use_facet<ctype<_CharT> >(__loc);
__err = ios_base::goodbit;
- bool __use_state = false;
-#if __GNUC__ >= 5 && !defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wpmf-conversions"
- // Nasty hack. The C++ standard mandates that get invokes the do_get
- // virtual method, but unfortunately at least without an ABI change
- // for the facets we can't keep state across the different do_get
- // calls. So e.g. if __fmt is "%p %I:%M:%S", we can't handle it
- // properly, because we first handle the %p am/pm specifier and only
- // later the 12-hour format specifier.
- if ((void*)(this->*(&time_get::do_get)) == (void*)(&time_get::do_get))
- __use_state = true;
-#pragma GCC diagnostic pop
-#endif
__time_get_state __state = __time_get_state();
+ __state._M_save_to (__tm);
while (__fmt != __fmtend &&
__err == ios_base::goodbit)
{
@@ -1510,26 +1497,8 @@ _GLIBCXX_END_NAMESPACE_LDBL_OR_CXX11
__err = ios_base::failbit;
break;
}
- if (__use_state)
- {
- char_type __new_fmt[4];
- __new_fmt[0] = __fmt_start[0];
- __new_fmt[1] = __fmt_start[1];
- if (__mod)
- {
- __new_fmt[2] = __fmt_start[2];
- __new_fmt[3] = char_type();
- }
- else
- __new_fmt[2] = char_type();
- __s = _M_extract_via_format(__s, __end, __io, __err, __tm,
- __new_fmt, __state);
- if (__s == __end)
- __err |= ios_base::eofbit;
- }
- else
- __s = this->do_get(__s, __end, __io, __err, __tm, __format,
- __mod);
+ __s = this->do_get(__s, __end, __io, __err, __tm,
+ __format, __mod);
++__fmt;
}
else if (__ctype.is(ctype_base::space, *__fmt))
@@ -1556,8 +1525,8 @@ _GLIBCXX_END_NAMESPACE_LDBL_OR_CXX11
break;
}
}
- if (__use_state)
- __state._M_finalize_state(__tm);
+ __state._M_restore_from (__tm);
+ __state._M_finalize_state(__tm);
return __s;
}
@@ -1588,9 +1557,11 @@ _GLIBCXX_END_NAMESPACE_LDBL_OR_CXX11
}
__time_get_state __state = __time_get_state();
+ __state._M_restore_from (__tm);
__beg = _M_extract_via_format(__beg, __end, __io, __err, __tm, __fmt,
__state);
__state._M_finalize_state(__tm);
+ __state._M_save_to (__tm);
if (__beg == __end)
__err |= ios_base::eofbit;
return __beg;
diff --git a/libstdc++-v3/src/c++98/locale_facets.cc b/libstdc++-v3/src/c++98/locale_facets.cc
index c0bb7fd181d..28c34b5f379 100644
--- a/libstdc++-v3/src/c++98/locale_facets.cc
+++ b/libstdc++-v3/src/c++98/locale_facets.cc
@@ -181,12 +181,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__time_get_state::
_M_finalize_state(tm* tm)
{
- if (_M_have_I && _M_is_pm)
+ if (_M_have_I && _M_is_pm && (unsigned) tm->tm_hour < 12)
tm->tm_hour += 12;
if (_M_have_century)
{
if (_M_want_century)
- tm->tm_year = tm->tm_year % 100;
+ {
+ tm->tm_year = tm->tm_year % 100;
+ if (tm->tm_year < 0)
+ tm->tm_year += 100;
+ }
else
tm->tm_year = 0;
tm->tm_year += (_M_century - 19) * 100;
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2023-02-17 5:00 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-02-17 5:00 [gcc(refs/users/aoliva/heads/testme)] [libstdc++] encode __time_get_state in tm Alexandre Oliva
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).