Skip to content

Commit 1548832

Browse files
yuanhongzhaoStephanTLavavej
authored andcommitted
<random>: Fixes subtract_with_carry_engine io (microsoft#2088)
Co-authored-by: Stephan T. Lavavej <[email protected]>
1 parent 5d3a3a8 commit 1548832

File tree

6 files changed

+142
-29
lines changed

6 files changed

+142
-29
lines changed

stl/inc/random

+57-3
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
#include <algorithm>
1313
#include <cmath>
1414
#include <cstdint>
15-
#include <iosfwd>
15+
#include <ios>
1616
#include <vector>
1717
#include <xbit_ops.h>
1818
#include <xstring>
@@ -674,6 +674,12 @@ public:
674674
return _Ostr;
675675
}
676676

677+
template <class _Elem, class _Traits>
678+
basic_ostream<_Elem, _Traits>& _Write_full(basic_ostream<_Elem, _Traits>& _Ostr) const { // write state to _Ostr
679+
_Swc_Traits::_Write_full(_Ostr, *this, _Carry);
680+
return _Ostr;
681+
}
682+
677683
protected:
678684
template <class _Gen>
679685
void _Seed(_Gen& _Gx, bool _Readcy, true_type) { // reset sequence from numeric value
@@ -816,14 +822,24 @@ struct _Swc_traits { // traits for subtract_with_carry generator
816822
int _Kx = _Get_wc();
817823

818824
for (size_t _Ix = 0; _Ix < _Nw; ++_Ix) {
819-
for (int _Jx = 1; _Jx <= _Kx; ++_Jx) { // unpack into _Kx words
820-
unsigned int _Word = static_cast<unsigned int>(_Buf._At(_Ix) >> ((_Kx - _Jx) * 32));
825+
for (int _Jx = 0; _Jx < _Kx; ++_Jx) { // unpack into _Kx words
826+
const unsigned int _Word = static_cast<unsigned int>(_Buf._At(_Ix) >> (_Jx * 32));
821827
_Ostr << _Word << ' ';
822828
}
823829
}
824830

825831
_Ostr << _Cy;
826832
}
833+
834+
template <class _Elem, class _Traits>
835+
static void _Write_full(
836+
basic_ostream<_Elem, _Traits>& _Ostr, const _Circ_buf<_Ty, _Nw>& _Buf, _Cy_t _Cy) { // write state to _Ostr
837+
for (size_t _Ix = 0; _Ix < _Nw; ++_Ix) {
838+
_Ostr << _Buf._At(_Ix) << ' ';
839+
}
840+
841+
_Ostr << _Cy;
842+
}
827843
};
828844

829845
template <class _Ty, _Ty _Mx, size_t _Sx, size_t _Rx>
@@ -908,6 +924,44 @@ public:
908924
_NODISCARD static constexpr _Ty(max)() {
909925
return _Mx - 1;
910926
}
927+
928+
template <class _Elem, class _Traits>
929+
friend basic_ostream<_Elem, _Traits>& operator<<(
930+
basic_ostream<_Elem, _Traits>& _Ostr, const subtract_with_carry_engine& _Eng) {
931+
const auto _Save_flags = _Ostr.flags(ios_base::dec | ios_base::left);
932+
const auto _Save_fill = _Ostr.fill(' ');
933+
_Eng._Write_full(_Ostr);
934+
_Ostr.flags(_Save_flags);
935+
_Ostr.fill(_Save_fill);
936+
return _Ostr;
937+
}
938+
939+
template <class _Elem, class _Traits>
940+
friend basic_istream<_Elem, _Traits>& operator>>(
941+
basic_istream<_Elem, _Traits>& _Istr, subtract_with_carry_engine& _Eng) {
942+
constexpr auto _Nx = long_lag;
943+
result_type _Buffer[_Nx];
944+
typename _Mybase::_Traits::_Cy_t _Carry_buf;
945+
const auto _Save_flags = _Istr.flags(ios_base::dec | ios_base::skipws);
946+
for (size_t _Ix = 0; _Ix < _Nx; ++_Ix) {
947+
_Istr >> _Buffer[_Ix];
948+
}
949+
950+
_Istr >> _Carry_buf;
951+
if (_Istr) {
952+
for (size_t _Ix = 0; _Ix < _Nx; ++_Ix) {
953+
_Eng._Ax[_Ix] = _Buffer[_Ix];
954+
}
955+
956+
_Eng._Carry = _Carry_buf;
957+
_Eng._Idx = _Nx;
958+
} else {
959+
_Istr.setstate(ios_base::failbit);
960+
}
961+
962+
_Istr.flags(_Save_flags);
963+
return _Istr;
964+
}
911965
};
912966

913967
#if _HAS_TR1_NAMESPACE

tests/libcxx/expected_results.txt

-13
Original file line numberDiff line numberDiff line change
@@ -779,19 +779,6 @@ std/input.output/iostream.format/ext.manip/get_money.pass.cpp FAIL
779779
std/input.output/iostream.format/ext.manip/put_money.pass.cpp FAIL
780780
std/input.output/iostreams.base/ios/basic.ios.members/copyfmt.pass.cpp FAIL
781781

782-
# Not yet analyzed, likely STL bugs. Assertion failed: os.str() == a
783-
std/numerics/rand/rand.adapt/rand.adapt.disc/ctor_result_type.pass.cpp FAIL
784-
std/numerics/rand/rand.adapt/rand.adapt.disc/ctor_sseq.pass.cpp FAIL
785-
std/numerics/rand/rand.adapt/rand.adapt.ibits/ctor_result_type.pass.cpp FAIL
786-
std/numerics/rand/rand.adapt/rand.adapt.ibits/ctor_sseq.pass.cpp FAIL
787-
std/numerics/rand/rand.eng/rand.eng.sub/ctor_result_type.pass.cpp FAIL
788-
std/numerics/rand/rand.eng/rand.eng.sub/ctor_sseq.pass.cpp FAIL
789-
790-
# Not yet analyzed, likely STL bugs. Assertion failed: e1 == e2
791-
std/numerics/rand/rand.adapt/rand.adapt.disc/io.pass.cpp FAIL
792-
std/numerics/rand/rand.adapt/rand.adapt.ibits/io.pass.cpp FAIL
793-
std/numerics/rand/rand.eng/rand.eng.sub/io.pass.cpp FAIL
794-
795782
# Likely STL bug: Looks like we shouldn't be using assignment.
796783
std/thread/futures/futures.promise/set_rvalue.pass.cpp FAIL
797784

tests/libcxx/skipped_tests.txt

-13
Original file line numberDiff line numberDiff line change
@@ -779,19 +779,6 @@ input.output\iostream.format\ext.manip\get_money.pass.cpp
779779
input.output\iostream.format\ext.manip\put_money.pass.cpp
780780
input.output\iostreams.base\ios\basic.ios.members\copyfmt.pass.cpp
781781

782-
# Not yet analyzed, likely STL bugs. Assertion failed: os.str() == a
783-
numerics\rand\rand.adapt\rand.adapt.disc\ctor_result_type.pass.cpp
784-
numerics\rand\rand.adapt\rand.adapt.disc\ctor_sseq.pass.cpp
785-
numerics\rand\rand.adapt\rand.adapt.ibits\ctor_result_type.pass.cpp
786-
numerics\rand\rand.adapt\rand.adapt.ibits\ctor_sseq.pass.cpp
787-
numerics\rand\rand.eng\rand.eng.sub\ctor_result_type.pass.cpp
788-
numerics\rand\rand.eng\rand.eng.sub\ctor_sseq.pass.cpp
789-
790-
# Not yet analyzed, likely STL bugs. Assertion failed: e1 == e2
791-
numerics\rand\rand.adapt\rand.adapt.disc\io.pass.cpp
792-
numerics\rand\rand.adapt\rand.adapt.ibits\io.pass.cpp
793-
numerics\rand\rand.eng\rand.eng.sub\io.pass.cpp
794-
795782
# Likely STL bug: Looks like we shouldn't be using assignment.
796783
thread\futures\futures.promise\set_rvalue.pass.cpp
797784

tests/std/test.lst

+1
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@ tests\GH_000431_equal_memcmp_is_safe
161161
tests\GH_000431_iter_copy_move_cat
162162
tests\GH_000431_lex_compare_family
163163
tests\GH_000431_lex_compare_memcmp_classify
164+
tests\GH_000442_random_subtract_with_carry_engine_io
164165
tests\GH_000457_system_error_message
165166
tests\GH_000545_include_compare
166167
tests\GH_000625_vector_bool_optimization
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Copyright (c) Microsoft Corporation.
2+
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
3+
4+
RUNALL_INCLUDE ..\usual_matrix.lst
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
3+
4+
#include <cassert>
5+
#include <cstddef>
6+
#include <ios>
7+
#include <random>
8+
#include <sstream>
9+
#include <string>
10+
using namespace std;
11+
12+
void check_state(const string& state_str) {
13+
// Check word-by-word in case of whitespace differences.
14+
static constexpr const char* state_ref[] = {
15+
"10880375256626",
16+
"126660097854724",
17+
"33643165434010",
18+
"78293780235492",
19+
"179418984296008",
20+
"96783156950859",
21+
"238199764491708",
22+
"34339434557790",
23+
"155299155394531",
24+
"29014415493780",
25+
"209265474179052",
26+
"263777435457028",
27+
"0",
28+
};
29+
constexpr auto state_size = size(state_ref);
30+
stringstream sstr(state_str);
31+
32+
size_t idx = 0;
33+
string word;
34+
while (sstr && idx < state_size) {
35+
sstr >> word;
36+
assert(word == state_ref[idx]);
37+
++idx;
38+
}
39+
40+
assert(sstr.rdstate() == ios_base::eofbit);
41+
assert(idx == state_size);
42+
}
43+
44+
void check(stringstream& sstr) {
45+
// N4892 [tab:rand.req.eng]: "Postconditions: The os.fmtflags and fill character are unchanged."
46+
// and "Postconditions: The is.fmtflags are unchanged."
47+
const auto old_flags = sstr.flags();
48+
const auto old_fill = sstr.fill();
49+
ranlux48_base eng1;
50+
ranlux48_base eng2;
51+
sstr << eng1;
52+
check_state(sstr.str());
53+
sstr >> eng2;
54+
assert(eng1 == eng2);
55+
assert(sstr.flags() == old_flags);
56+
assert(sstr.fill() == old_fill);
57+
}
58+
59+
int main() {
60+
{
61+
stringstream sstr;
62+
sstr << hex;
63+
check(sstr);
64+
}
65+
66+
{
67+
stringstream sstr;
68+
sstr.unsetf(ios_base::skipws);
69+
check(sstr);
70+
}
71+
72+
{
73+
stringstream sstr;
74+
sstr.fill('.');
75+
sstr.width(40);
76+
check(sstr);
77+
}
78+
79+
return 0;
80+
}

0 commit comments

Comments
 (0)