diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 3bfa38e8d39..67878c1caf3 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,11 @@ +2002-05-24 Phil Edwards + + libstdc++/6282 + * include/std/std_bitset.h (_Base_biteset<0>): New specialization. + (operator>>): If nothing was extracted, don't fail in the + zero-length case. + * testsuite/23_containers/bitset_ctor.cc (test02): New test. + 2002-05-24 Benjamin Kosnik PR libstdc++/6701 diff --git a/libstdc++-v3/include/std/std_bitset.h b/libstdc++-v3/include/std/std_bitset.h index 0945c90f5fc..fe60b01f347 100644 --- a/libstdc++-v3/include/std/std_bitset.h +++ b/libstdc++-v3/include/std/std_bitset.h @@ -61,7 +61,7 @@ #define _GLIBCPP_BITSET_BITS_PER_WORD (CHAR_BIT*sizeof(unsigned long)) #define _GLIBCPP_BITSET_WORDS(__n) \ - ((__n) < 1 ? 1 : ((__n) + _GLIBCPP_BITSET_BITS_PER_WORD - 1)/_GLIBCPP_BITSET_BITS_PER_WORD) + ((__n) < 1 ? 0 : ((__n) + _GLIBCPP_BITSET_BITS_PER_WORD - 1)/_GLIBCPP_BITSET_BITS_PER_WORD) namespace std { @@ -463,6 +463,101 @@ namespace std _M_do_find_next(size_t __prev, size_t __not_found) const; }; + + /** + * @if maint + * Base class, specialization for no storage (zero-length %bitset). + * + * See documentation for bitset. + * @endif + */ + template<> + struct _Base_bitset<0> + { + typedef unsigned long _WordT; + + _Base_bitset() {} + _Base_bitset(unsigned long) {} + + static size_t + _S_whichword(size_t __pos ) + { return __pos / _GLIBCPP_BITSET_BITS_PER_WORD; } + + static size_t + _S_whichbyte(size_t __pos ) + { return (__pos % _GLIBCPP_BITSET_BITS_PER_WORD) / CHAR_BIT; } + + static size_t + _S_whichbit(size_t __pos ) + { return __pos % _GLIBCPP_BITSET_BITS_PER_WORD; } + + static _WordT + _S_maskbit(size_t __pos ) + { return (static_cast<_WordT>(1)) << _S_whichbit(__pos); } + + // This would normally give access to the data. The bounds-checking + // in the bitset class will prevent the user from getting this far, + // but (1) it must still return an lvalue to compile, and (2) the + // user might call _Unchecked_set directly, in which case this /needs/ + // to fail. Let's not penalize zero-length users unless they actually + // make an unchecked call; all the memory ugliness is therefore + // localized to this single should-never-get-this-far function. + _WordT& + _M_getword(size_t) const + { __throw_out_of_range("bitset -- zero-length"); return *new _WordT; } + + _WordT + _M_hiword() const { return 0; } + + void + _M_do_and(const _Base_bitset<0>&) { } + + void + _M_do_or(const _Base_bitset<0>&) { } + + void + _M_do_xor(const _Base_bitset<0>&) { } + + void + _M_do_left_shift(size_t) { } + + void + _M_do_right_shift(size_t) { } + + void + _M_do_flip() { } + + void + _M_do_set() { } + + void + _M_do_reset() { } + + // Are all empty bitsets equal to each other? Are they equal to + // themselves? How to compare a thing which has no state? What is + // the sound of one zero-length bitset clapping? + bool + _M_is_equal(const _Base_bitset<0>&) const { return true; } + + bool + _M_is_any() const { return false; } + + size_t + _M_do_count() const { return 0; } + + unsigned long + _M_do_to_ulong() const { return 0; } + + // Normally "not found" is the size, but that could also be + // misinterpreted as an index in this corner case. Oh well. + size_t + _M_do_find_first(size_t) const { return 0; } + + size_t + _M_do_find_next(size_t, size_t) const { return 0; } + }; + + // Helper class to zero out the unused high-order bits in the highest word. template struct _Sanitize @@ -1115,7 +1210,7 @@ namespace std } } - if (__tmp.empty()) + if (__tmp.empty() && !_Nb) __is.setstate(ios_base::failbit); else __x._M_copy_from_string(__tmp, static_cast(0), _Nb); diff --git a/libstdc++-v3/testsuite/23_containers/bitset_ctor.cc b/libstdc++-v3/testsuite/23_containers/bitset_ctor.cc index c568e22af56..8dae3add5ea 100644 --- a/libstdc++-v3/testsuite/23_containers/bitset_ctor.cc +++ b/libstdc++-v3/testsuite/23_containers/bitset_ctor.cc @@ -81,9 +81,46 @@ bool test01(void) return test; } +// boundary condition: a zero-sized set +// libstdc++/6282 +bool test02(void) +{ + using std::char_traits; using std::allocator; + bool test = true; + + std::bitset<0> z1; + VERIFY( z1.any() == false ); + + std::bitset<0> z2(12345); + VERIFY( z2.any() == false ); + + std::bitset<0> z3(std::string("10101010101")); + VERIFY( z3.any() == false ); + + try { + z1.set(0); + VERIFY( false ); + } + catch(std::out_of_range& fail) { + VERIFY( true ); + } + catch(...) { + VERIFY( false ); + } + + VERIFY( z1.to_ulong() == 0 ); + VERIFY( ( z1.to_string,allocator >().empty() ) ); + +#ifdef DEBUG_ASSERT + assert(test); +#endif + return test; +} + int main() { test01(); + test02(); return 0; }