char_type
fill() const
{
- if (!_M_fill_init)
- {
- _M_fill = this->widen(' ');
- _M_fill_init = true;
- }
+ if (__builtin_expect(!_M_fill_init, false))
+ return this->widen(' ');
return _M_fill;
}
char_type
fill(char_type __ch)
{
- char_type __old = this->fill();
+ char_type __old = _M_fill;
_M_fill = __ch;
+ _M_fill_init = true;
return __old;
}
// return without throwing an exception. Unfortunately,
// ctype<char_type> is not necessarily a required facet, so
// streams with char_type != [char, wchar_t] will not have it by
- // default. Because of this, the correct value for _M_fill is
- // constructed on the first call of fill(). That way,
+ // default. If the ctype<char_type> facet is available now,
+ // _M_fill is set here, but otherwise no fill character will be
+ // cached and a call to fill() will check for the facet again later
+ // (and will throw if the facet is still not present). This way
// unformatted input and output with non-required basic_ios
// instantiations is possible even without imbuing the expected
// ctype<char_type> facet.
- _M_fill = _CharT();
- _M_fill_init = false;
+ if (_M_ctype)
+ {
+ _M_fill = _M_ctype->widen(' ');
+ _M_fill_init = true;
+ }
+ else
+ _M_fill_init = false;
_M_tie = 0;
_M_exception = goodbit;
--- /dev/null
+// { dg-do run }
+
+#include <ios>
+#include <locale>
+#include <streambuf>
+#include <testsuite_hooks.h>
+
+typedef char C;
+
+struct tabby_mctype : std::ctype<C>
+{
+ C do_widen(char c) const { return c == ' ' ? '\t' : c; }
+
+ const char*
+ do_widen(const char* lo, const char* hi, C* to) const
+ {
+ while (lo != hi)
+ *to++ = do_widen(*lo++);
+ return hi;
+ }
+};
+
+void
+test01()
+{
+ std::basic_ios<C> out(0);
+ std::locale loc(std::locale(), new tabby_mctype);
+ out.imbue(loc);
+ VERIFY( out.fill() == ' ' ); // Imbuing a new locale doesn't affect fill().
+ out.fill('*');
+ VERIFY( out.fill() == '*' ); // This will be cached now.
+ out.imbue(std::locale());
+ VERIFY( out.fill() == '*' ); // Imbuing a new locale doesn't affect fill().
+}
+
+void
+test02()
+{
+ std::locale loc(std::locale(), new tabby_mctype);
+ std::locale::global(loc);
+ std::basic_ios<C> out(0);
+ VERIFY( out.fill() == '\t' );
+ out.imbue(std::locale::classic());
+ VERIFY( out.fill() == '\t' ); // Imbuing a new locale doesn't affect fill().
+ out.fill('*');
+ VERIFY( out.fill() == '*' ); // This will be cached now.
+ out.imbue(std::locale());
+ VERIFY( out.fill() == '*' ); // Imbuing a new locale doesn't affect fill().
+}
+
+void
+test03()
+{
+ // This function tests a libstdc++ extension: if no ctype<char_type> facet
+ // is present when the stream is initialized, a fill character will not be
+ // cached. Calling fill() will obtain a fill character from the locale each
+ // time it's called.
+ typedef signed char C2;
+ std::basic_ios<C2> out(0);
+#if __cpp_exceptions
+ try {
+ (void) out.fill(); // No ctype<signed char> in the locale.
+ VERIFY( false );
+ } catch (...) {
+ }
+#endif
+ out.fill('*');
+ VERIFY( out.fill() == '*' ); // This will be cached now.
+ out.imbue(std::locale());
+ VERIFY( out.fill() == '*' ); // Imbuing a new locale doesn't affect fill().
+}
+
+int main()
+{
+ test01();
+ test02();
+ test03();
+}
--- /dev/null
+// { dg-do run }
+
+#include <ios>
+#include <locale>
+#include <streambuf>
+#include <testsuite_hooks.h>
+
+typedef wchar_t C;
+
+struct tabby_mctype : std::ctype<C>
+{
+ C do_widen(char c) const { return c == ' ' ? L'\t' : c; }
+
+ const char*
+ do_widen(const char* lo, const char* hi, C* to) const
+ {
+ while (lo != hi)
+ *to++ = do_widen(*lo++);
+ return hi;
+ }
+};
+
+void
+test01()
+{
+ std::basic_ios<C> out(0);
+ std::locale loc(std::locale(), new tabby_mctype);
+ out.imbue(loc);
+ VERIFY( out.fill() == L' ' ); // Imbuing a new locale doesn't affect fill().
+ out.fill(L'*');
+ VERIFY( out.fill() == L'*' ); // This will be cached now.
+ out.imbue(std::locale());
+ VERIFY( out.fill() == L'*' ); // Imbuing a new locale doesn't affect fill().
+}
+
+void
+test02()
+{
+ std::locale loc(std::locale(), new tabby_mctype);
+ std::locale::global(loc);
+ std::basic_ios<C> out(0);
+ VERIFY( out.fill() == L'\t' );
+ out.imbue(std::locale::classic());
+ VERIFY( out.fill() == L'\t' ); // Imbuing a new locale doesn't affect fill().
+ out.fill(L'*');
+ VERIFY( out.fill() == L'*' ); // This will be cached now.
+ out.imbue(std::locale());
+ VERIFY( out.fill() == L'*' ); // Imbuing a new locale doesn't affect fill().
+}
+
+int main()
+{
+ test01();
+ test02();
+}