From ba017a73e63eea36f81bb7dfd4173bde770f1665 Mon Sep 17 00:00:00 2001 From: Yuanhong Zhao Date: Fri, 30 Jul 2021 13:46:59 -0700 Subject: [PATCH 1/2] Fixes subtract_with_carry_engine io --- stl/inc/random | 60 +++++++++++++++- tests/libcxx/expected_results.txt | 13 ---- tests/libcxx/skipped_tests.txt | 13 ---- tests/std/test.lst | 1 + tests/std/tests/GH_000442_rand_swc_io/env.lst | 4 ++ .../std/tests/GH_000442_rand_swc_io/test.cpp | 72 +++++++++++++++++++ 6 files changed, 134 insertions(+), 29 deletions(-) create mode 100644 tests/std/tests/GH_000442_rand_swc_io/env.lst create mode 100644 tests/std/tests/GH_000442_rand_swc_io/test.cpp diff --git a/stl/inc/random b/stl/inc/random index 350d5ff6df8..d047214bc40 100644 --- a/stl/inc/random +++ b/stl/inc/random @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include #include @@ -685,6 +685,12 @@ public: return _Ostr; } + template + basic_ostream<_Elem, _Traits>& _WriteFull(basic_ostream<_Elem, _Traits>& _Ostr) const { // write state to _Ostr + _Swc_Traits::_WriteFull(_Ostr, *this, _Carry); + return _Ostr; + } + protected: template void _Seed(_Gen& _Gx, bool _Readcy, true_type) { // reset sequence from numeric value @@ -828,14 +834,24 @@ struct _Swc_traits { // traits for subtract_with_carry generator int _Kx = _Get_wc(); for (size_t _Ix = 0; _Ix < _Nw; ++_Ix) { - for (int _Jx = 1; _Jx <= _Kx; ++_Jx) { // unpack into _Kx words - unsigned int _Word = static_cast(_Buf._At(_Ix) >> ((_Kx - _Jx) * 32)); + for (int _Jx = 0; _Jx < _Kx; ++_Jx) { // unpack into _Kx words + const unsigned int _Word = static_cast(_Buf._At(_Ix) >> (_Jx * 32)); _Ostr << _Word << ' '; } } _Ostr << _Cy; } + + template + static void _WriteFull( + basic_ostream<_Elem, _Traits>& _Ostr, const _Circ_buf<_Ty, _Nw>& _Buf, _Cy_t _Cy) { // write state to _Ostr + for (size_t _Ix = 0; _Ix < _Nw; ++_Ix) { + _Ostr << _Buf._At(_Ix) << ' '; + } + + _Ostr << _Cy; + } }; // CLASS TEMPLATE subtract_with_carry @@ -922,6 +938,44 @@ public: _NODISCARD static constexpr _Ty(max)() { return _Mx - 1; } + + template + friend basic_ostream<_Elem, _Traits>& operator<<( + basic_ostream<_Elem, _Traits>& _Ostr, const subtract_with_carry_engine& _Eng) { + const auto _Save_flags = _Ostr.flags(ios_base::dec | ios_base::left); + const auto _Save_fill = _Ostr.fill(' '); + _Eng._WriteFull(_Ostr); + _Ostr.flags(_Save_flags); + _Ostr.fill(_Save_fill); + return _Ostr; + } + + template + friend basic_istream<_Elem, _Traits>& operator>>( + basic_istream<_Elem, _Traits>& _Istr, subtract_with_carry_engine& _Eng) { + constexpr auto _Nx = subtract_with_carry_engine::long_lag; + subtract_with_carry_engine::result_type _Buffer[_Nx]; + typename subtract_with_carry_engine::_Mybase::_Traits::_Cy_t _Carry_buf; + const auto _Save_flags = _Istr.flags(ios_base::dec | ios_base::skipws); + for (size_t _Ix = 0; _Ix < _Nx; ++_Ix) { + _Istr >> _Buffer[_Ix]; + } + + _Istr >> _Carry_buf; + if (_Istr) { + for (size_t _Ix = 0; _Ix < _Nx; ++_Ix) { + _Eng._Ax[_Ix] = _Buffer[_Ix]; + } + + _Eng._Carry = _Carry_buf; + _Eng._Idx = _Nx; + } else { + _Istr.setstate(ios_base::failbit); + } + + _Istr.flags(_Save_flags); + return _Istr; + } }; #if _HAS_TR1_NAMESPACE diff --git a/tests/libcxx/expected_results.txt b/tests/libcxx/expected_results.txt index 5f8bd0d8eb3..f4bf0a499dc 100644 --- a/tests/libcxx/expected_results.txt +++ b/tests/libcxx/expected_results.txt @@ -779,19 +779,6 @@ std/input.output/iostream.format/ext.manip/get_money.pass.cpp FAIL std/input.output/iostream.format/ext.manip/put_money.pass.cpp FAIL std/input.output/iostreams.base/ios/basic.ios.members/copyfmt.pass.cpp FAIL -# Not yet analyzed, likely STL bugs. Assertion failed: os.str() == a -std/numerics/rand/rand.adapt/rand.adapt.disc/ctor_result_type.pass.cpp FAIL -std/numerics/rand/rand.adapt/rand.adapt.disc/ctor_sseq.pass.cpp FAIL -std/numerics/rand/rand.adapt/rand.adapt.ibits/ctor_result_type.pass.cpp FAIL -std/numerics/rand/rand.adapt/rand.adapt.ibits/ctor_sseq.pass.cpp FAIL -std/numerics/rand/rand.eng/rand.eng.sub/ctor_result_type.pass.cpp FAIL -std/numerics/rand/rand.eng/rand.eng.sub/ctor_sseq.pass.cpp FAIL - -# Not yet analyzed, likely STL bugs. Assertion failed: e1 == e2 -std/numerics/rand/rand.adapt/rand.adapt.disc/io.pass.cpp FAIL -std/numerics/rand/rand.adapt/rand.adapt.ibits/io.pass.cpp FAIL -std/numerics/rand/rand.eng/rand.eng.sub/io.pass.cpp FAIL - # Likely STL bug: Looks like we shouldn't be using assignment. std/thread/futures/futures.promise/set_rvalue.pass.cpp FAIL diff --git a/tests/libcxx/skipped_tests.txt b/tests/libcxx/skipped_tests.txt index 547fd8444f4..7beabe9a686 100644 --- a/tests/libcxx/skipped_tests.txt +++ b/tests/libcxx/skipped_tests.txt @@ -779,19 +779,6 @@ input.output\iostream.format\ext.manip\get_money.pass.cpp input.output\iostream.format\ext.manip\put_money.pass.cpp input.output\iostreams.base\ios\basic.ios.members\copyfmt.pass.cpp -# Not yet analyzed, likely STL bugs. Assertion failed: os.str() == a -numerics\rand\rand.adapt\rand.adapt.disc\ctor_result_type.pass.cpp -numerics\rand\rand.adapt\rand.adapt.disc\ctor_sseq.pass.cpp -numerics\rand\rand.adapt\rand.adapt.ibits\ctor_result_type.pass.cpp -numerics\rand\rand.adapt\rand.adapt.ibits\ctor_sseq.pass.cpp -numerics\rand\rand.eng\rand.eng.sub\ctor_result_type.pass.cpp -numerics\rand\rand.eng\rand.eng.sub\ctor_sseq.pass.cpp - -# Not yet analyzed, likely STL bugs. Assertion failed: e1 == e2 -numerics\rand\rand.adapt\rand.adapt.disc\io.pass.cpp -numerics\rand\rand.adapt\rand.adapt.ibits\io.pass.cpp -numerics\rand\rand.eng\rand.eng.sub\io.pass.cpp - # Likely STL bug: Looks like we shouldn't be using assignment. thread\futures\futures.promise\set_rvalue.pass.cpp diff --git a/tests/std/test.lst b/tests/std/test.lst index 3fb435eca19..c540a7f6add 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -155,6 +155,7 @@ tests\Dev11_1140665_unique_ptr_array_conversions tests\Dev11_1150223_shared_mutex tests\Dev11_1158803_regex_thread_safety tests\Dev11_1180290_filesystem_error_code +tests\GH_000442_rand_swc_io tests\GH_000457_system_error_message tests\GH_000545_include_compare tests\GH_000625_vector_bool_optimization diff --git a/tests/std/tests/GH_000442_rand_swc_io/env.lst b/tests/std/tests/GH_000442_rand_swc_io/env.lst new file mode 100644 index 00000000000..19f025bd0e6 --- /dev/null +++ b/tests/std/tests/GH_000442_rand_swc_io/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\usual_matrix.lst diff --git a/tests/std/tests/GH_000442_rand_swc_io/test.cpp b/tests/std/tests/GH_000442_rand_swc_io/test.cpp new file mode 100644 index 00000000000..9241c55264c --- /dev/null +++ b/tests/std/tests/GH_000442_rand_swc_io/test.cpp @@ -0,0 +1,72 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include + +using namespace std; + +void check_state(const string& state_str) { + // Check word-by-word in case of whitespace differences. + constexpr static const char* state_ref[] = { + "10880375256626", + "126660097854724", + "33643165434010", + "78293780235492", + "179418984296008", + "96783156950859", + "238199764491708", + "34339434557790", + "155299155394531", + "29014415493780", + "209265474179052", + "263777435457028", + "0", + }; + constexpr auto state_size = sizeof(state_ref) / sizeof(state_ref[0]); + stringstream sstr(state_str); + + size_t idx = 0; + string word; + while (sstr && idx < state_size) { + sstr >> word; + assert(word == state_ref[idx]); + ++idx; + } + + assert(sstr.rdstate() == ios_base::eofbit && idx == state_size); +} + +void check(stringstream& sstr) { + ranlux48_base eng1; + ranlux48_base eng2; + sstr << eng1; + check_state(sstr.str()); + sstr >> eng2; + assert(eng1 == eng2); +} + +int main() { + { + stringstream sstr; + sstr << hex; + check(sstr); + } + + { + stringstream sstr; + sstr.unsetf(ios_base::skipws); + check(sstr); + } + + { + stringstream sstr; + sstr.fill('.'); + sstr.width(40); + check(sstr); + } + + return 0; +} From 524e6393424f600cc7ad4ae1fa0b451ad66de2ea Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Mon, 27 Sep 2021 18:47:04 -0700 Subject: [PATCH 2/2] Code review feedback. --- stl/inc/random | 14 +++++++------- tests/std/test.lst | 2 +- .../env.lst | 0 .../test.cpp | 16 ++++++++++++---- 4 files changed, 20 insertions(+), 12 deletions(-) rename tests/std/tests/{GH_000442_rand_swc_io => GH_000442_random_subtract_with_carry_engine_io}/env.lst (100%) rename tests/std/tests/{GH_000442_rand_swc_io => GH_000442_random_subtract_with_carry_engine_io}/test.cpp (68%) diff --git a/stl/inc/random b/stl/inc/random index 6a20c8ff425..254042b1656 100644 --- a/stl/inc/random +++ b/stl/inc/random @@ -675,8 +675,8 @@ public: } template - basic_ostream<_Elem, _Traits>& _WriteFull(basic_ostream<_Elem, _Traits>& _Ostr) const { // write state to _Ostr - _Swc_Traits::_WriteFull(_Ostr, *this, _Carry); + basic_ostream<_Elem, _Traits>& _Write_full(basic_ostream<_Elem, _Traits>& _Ostr) const { // write state to _Ostr + _Swc_Traits::_Write_full(_Ostr, *this, _Carry); return _Ostr; } @@ -832,7 +832,7 @@ struct _Swc_traits { // traits for subtract_with_carry generator } template - static void _WriteFull( + static void _Write_full( basic_ostream<_Elem, _Traits>& _Ostr, const _Circ_buf<_Ty, _Nw>& _Buf, _Cy_t _Cy) { // write state to _Ostr for (size_t _Ix = 0; _Ix < _Nw; ++_Ix) { _Ostr << _Buf._At(_Ix) << ' '; @@ -930,7 +930,7 @@ public: basic_ostream<_Elem, _Traits>& _Ostr, const subtract_with_carry_engine& _Eng) { const auto _Save_flags = _Ostr.flags(ios_base::dec | ios_base::left); const auto _Save_fill = _Ostr.fill(' '); - _Eng._WriteFull(_Ostr); + _Eng._Write_full(_Ostr); _Ostr.flags(_Save_flags); _Ostr.fill(_Save_fill); return _Ostr; @@ -939,9 +939,9 @@ public: template friend basic_istream<_Elem, _Traits>& operator>>( basic_istream<_Elem, _Traits>& _Istr, subtract_with_carry_engine& _Eng) { - constexpr auto _Nx = subtract_with_carry_engine::long_lag; - subtract_with_carry_engine::result_type _Buffer[_Nx]; - typename subtract_with_carry_engine::_Mybase::_Traits::_Cy_t _Carry_buf; + constexpr auto _Nx = long_lag; + result_type _Buffer[_Nx]; + typename _Mybase::_Traits::_Cy_t _Carry_buf; const auto _Save_flags = _Istr.flags(ios_base::dec | ios_base::skipws); for (size_t _Ix = 0; _Ix < _Nx; ++_Ix) { _Istr >> _Buffer[_Ix]; diff --git a/tests/std/test.lst b/tests/std/test.lst index c01cf11b07d..06d667b39f6 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -161,7 +161,7 @@ tests\GH_000431_equal_memcmp_is_safe tests\GH_000431_iter_copy_move_cat tests\GH_000431_lex_compare_family tests\GH_000431_lex_compare_memcmp_classify -tests\GH_000442_rand_swc_io +tests\GH_000442_random_subtract_with_carry_engine_io tests\GH_000457_system_error_message tests\GH_000545_include_compare tests\GH_000625_vector_bool_optimization diff --git a/tests/std/tests/GH_000442_rand_swc_io/env.lst b/tests/std/tests/GH_000442_random_subtract_with_carry_engine_io/env.lst similarity index 100% rename from tests/std/tests/GH_000442_rand_swc_io/env.lst rename to tests/std/tests/GH_000442_random_subtract_with_carry_engine_io/env.lst diff --git a/tests/std/tests/GH_000442_rand_swc_io/test.cpp b/tests/std/tests/GH_000442_random_subtract_with_carry_engine_io/test.cpp similarity index 68% rename from tests/std/tests/GH_000442_rand_swc_io/test.cpp rename to tests/std/tests/GH_000442_random_subtract_with_carry_engine_io/test.cpp index 9241c55264c..25bd64ff20d 100644 --- a/tests/std/tests/GH_000442_rand_swc_io/test.cpp +++ b/tests/std/tests/GH_000442_random_subtract_with_carry_engine_io/test.cpp @@ -2,15 +2,16 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #include +#include #include #include #include - +#include using namespace std; void check_state(const string& state_str) { // Check word-by-word in case of whitespace differences. - constexpr static const char* state_ref[] = { + static constexpr const char* state_ref[] = { "10880375256626", "126660097854724", "33643165434010", @@ -25,7 +26,7 @@ void check_state(const string& state_str) { "263777435457028", "0", }; - constexpr auto state_size = sizeof(state_ref) / sizeof(state_ref[0]); + constexpr auto state_size = size(state_ref); stringstream sstr(state_str); size_t idx = 0; @@ -36,16 +37,23 @@ void check_state(const string& state_str) { ++idx; } - assert(sstr.rdstate() == ios_base::eofbit && idx == state_size); + assert(sstr.rdstate() == ios_base::eofbit); + assert(idx == state_size); } void check(stringstream& sstr) { + // N4892 [tab:rand.req.eng]: "Postconditions: The os.fmtflags and fill character are unchanged." + // and "Postconditions: The is.fmtflags are unchanged." + const auto old_flags = sstr.flags(); + const auto old_fill = sstr.fill(); ranlux48_base eng1; ranlux48_base eng2; sstr << eng1; check_state(sstr.str()); sstr >> eng2; assert(eng1 == eng2); + assert(sstr.flags() == old_flags); + assert(sstr.fill() == old_fill); } int main() {