Skip to content

Commit

Permalink
Use char_traits in streaming operator>> of bitset (#4970)
Browse files Browse the repository at this point in the history
Co-authored-by: Stephan T. Lavavej <stl@nuwen.net>
Co-authored-by: Casey Carter <cacarter@microsoft.com>
  • Loading branch information
3 people authored Sep 28, 2024
1 parent f8f9f7a commit 9bbdf43
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 11 deletions.
18 changes: 12 additions & 6 deletions stl/inc/bitset
Original file line number Diff line number Diff line change
Expand Up @@ -585,19 +585,25 @@ basic_istream<_Elem, _Tr>& operator>>(basic_istream<_Elem, _Tr>& _Istr, bitset<_
typename _Tr::int_type _Meta = _Istr.rdbuf()->sgetc();
for (size_t _Count = _Right.size(); 0 < _Count; _Meta = _Istr.rdbuf()->snextc(), (void) --_Count) {
// test _Meta
_Elem _Char;
if (_Tr::eq_int_type(_Tr::eof(), _Meta)) { // end of file, quit
_State |= _Istr_t::eofbit;
break;
} else if ((_Char = _Tr::to_char_type(_Meta)) != _Elem0 && _Char != _Elem1) {
}

const _Elem _Char = _Tr::to_char_type(_Meta);

if (!_Tr::eq(_Char, _Elem0) && !_Tr::eq(_Char, _Elem1)) {
break; // invalid element
} else if (_Str.max_size() <= _Str.size()) { // no room in string, give up (unlikely)
}

if (_Str.max_size() <= _Str.size()) { // no room in string, give up (unlikely)
_State |= _Istr_t::failbit;
break;
} else { // valid, append '0' or '1'
_Str.push_back('0' + (_Char == _Elem1));
_Changed = true;
}

// valid, append '0' or '1'
_Str.push_back('0' + _Tr::eq(_Char, _Elem1));
_Changed = true;
}
_CATCH_IO_(_Istr_t, _Istr)
}
Expand Down
30 changes: 25 additions & 5 deletions tests/std/tests/GH_004930_char_traits_user_specialization/test.cpp
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#include <bitset>
#include <cassert>
#include <cstddef>
#include <cstring>
#include <cwchar>
#include <ios>
#include <iosfwd>
#include <sstream>
#include <string>
#include <type_traits>

Expand All @@ -22,15 +24,13 @@

using namespace std;

enum odd_char : unsigned char {};

template <>
class std::char_traits<odd_char> {
template <class T>
class odd_char_traits {
private:
static constexpr unsigned char odd_mask = 0xF;

public:
using char_type = odd_char;
using char_type = T;
using int_type = int;
using off_type = streamoff;
using pos_type = streampos;
Expand Down Expand Up @@ -161,6 +161,13 @@ class std::char_traits<odd_char> {
}
};

enum odd_char : unsigned char {};

template <>
class char_traits<odd_char> : public odd_char_traits<odd_char> {};

// GH-4930 "<string>: basic_string<unicorn>::find_meow_of family
// with std::char_traits<unicorn> specialization are not supported"
CONSTEXPR20 bool test_gh_4930() {
constexpr odd_char s_init[]{static_cast<odd_char>(0x55), static_cast<odd_char>(0x44), static_cast<odd_char>(0x33),
static_cast<odd_char>(0x22), static_cast<odd_char>(0x11), static_cast<odd_char>(0)};
Expand Down Expand Up @@ -280,6 +287,19 @@ CONSTEXPR20 bool test_gh_4930() {
static_assert(test_gh_4930());
#endif // _HAS_CXX20

// GH-4956 "<bitset>: streaming operator >> does not use character traits"
void test_gh_4956() {
// bitset's stream extraction operator was using `!=` to compare characters instead of `traits::eq`
basic_string<char, odd_char_traits<char>> s("QQPPQ", 5);
basic_istringstream<char, odd_char_traits<char>> iss(s);

bitset<7> bs;
iss >> bs;

assert(bs.to_ulong() == 0b11001);
}

int main() {
assert(test_gh_4930());
test_gh_4956();
}

0 comments on commit 9bbdf43

Please sign in to comment.