Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / libcxx / src / std_stream.h
blob37b4ffd1b4f6c518abc042a626bfb7f3033d68ab
1 // -*- C++ -*-
2 //===----------------------------------------------------------------------===//
3 //
4 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5 // See https://llvm.org/LICENSE.txt for license information.
6 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //
8 //===----------------------------------------------------------------------===//
10 #ifndef _LIBCPP_STD_STREAM_H
11 #define _LIBCPP_STD_STREAM_H
13 #include <__config>
14 #include <__locale>
15 #include <cstdio>
16 #include <istream>
17 #include <ostream>
19 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
20 # pragma GCC system_header
21 #endif
23 _LIBCPP_PUSH_MACROS
24 #include <__undef_macros>
27 _LIBCPP_BEGIN_NAMESPACE_STD
29 static const int __limit = 8;
31 // __stdinbuf
33 template <class _CharT>
34 class _LIBCPP_HIDDEN __stdinbuf
35 : public basic_streambuf<_CharT, char_traits<_CharT> >
37 public:
38 typedef _CharT char_type;
39 typedef char_traits<char_type> traits_type;
40 typedef typename traits_type::int_type int_type;
41 typedef typename traits_type::pos_type pos_type;
42 typedef typename traits_type::off_type off_type;
43 typedef typename traits_type::state_type state_type;
45 __stdinbuf(FILE* __fp, state_type* __st);
47 protected:
48 virtual int_type underflow();
49 virtual int_type uflow();
50 virtual int_type pbackfail(int_type __c = traits_type::eof());
51 virtual void imbue(const locale& __loc);
53 private:
55 FILE* __file_;
56 const codecvt<char_type, char, state_type>* __cv_;
57 state_type* __st_;
58 int __encoding_;
59 int_type __last_consumed_;
60 bool __last_consumed_is_next_;
61 bool __always_noconv_;
63 #if defined(_LIBCPP_WIN32API)
64 static constexpr bool __is_win32api_wide_char = !is_same_v<_CharT, char>;
65 #else
66 static constexpr bool __is_win32api_wide_char = false;
67 #endif
69 __stdinbuf(const __stdinbuf&);
70 __stdinbuf& operator=(const __stdinbuf&);
72 int_type __getchar(bool __consume);
75 template <class _CharT>
76 __stdinbuf<_CharT>::__stdinbuf(FILE* __fp, state_type* __st)
77 : __file_(__fp),
78 __st_(__st),
79 __last_consumed_(traits_type::eof()),
80 __last_consumed_is_next_(false)
82 imbue(this->getloc());
83 // On Windows, in wchar_t mode, ignore the codecvt from the locale by
84 // default and assume noconv; this passes wchar_t through unmodified from
85 // getwc. If the user sets a custom locale with imbue(), that gets honored,
86 // the IO is done with getc() and converted with the provided codecvt.
87 if constexpr (__is_win32api_wide_char)
88 __always_noconv_ = true;
91 template <class _CharT>
92 void
93 __stdinbuf<_CharT>::imbue(const locale& __loc)
95 __cv_ = &use_facet<codecvt<char_type, char, state_type> >(__loc);
96 __encoding_ = __cv_->encoding();
97 __always_noconv_ = __cv_->always_noconv();
98 if (__encoding_ > __limit)
99 __throw_runtime_error("unsupported locale for standard input");
102 template <class _CharT>
103 typename __stdinbuf<_CharT>::int_type
104 __stdinbuf<_CharT>::underflow()
106 return __getchar(false);
109 template <class _CharT>
110 typename __stdinbuf<_CharT>::int_type
111 __stdinbuf<_CharT>::uflow()
113 return __getchar(true);
116 inline bool __do_getc(FILE *__fp, char *__pbuf) {
117 int __c = getc(__fp);
118 if (__c == EOF)
119 return false;
120 *__pbuf = static_cast<char>(__c);
121 return true;
123 #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
124 inline bool __do_getc(FILE *__fp, wchar_t *__pbuf) {
125 wint_t __c = getwc(__fp);
126 if (__c == WEOF)
127 return false;
128 *__pbuf = static_cast<wchar_t>(__c);
129 return true;
131 #endif
133 inline bool __do_ungetc(int __c, FILE *__fp, char __dummy) {
134 if (ungetc(__c, __fp) == EOF)
135 return false;
136 return true;
138 #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
139 inline bool __do_ungetc(std::wint_t __c, FILE *__fp, wchar_t __dummy) {
140 if (ungetwc(__c, __fp) == WEOF)
141 return false;
142 return true;
144 #endif
146 template <class _CharT>
147 typename __stdinbuf<_CharT>::int_type
148 __stdinbuf<_CharT>::__getchar(bool __consume)
150 if (__last_consumed_is_next_)
152 int_type __result = __last_consumed_;
153 if (__consume)
155 __last_consumed_ = traits_type::eof();
156 __last_consumed_is_next_ = false;
158 return __result;
160 if (__always_noconv_) {
161 char_type __1buf;
162 if (!__do_getc(__file_, &__1buf))
163 return traits_type::eof();
164 if (!__consume)
166 if (!__do_ungetc(traits_type::to_int_type(__1buf), __file_, __1buf))
167 return traits_type::eof();
169 else
170 __last_consumed_ = traits_type::to_int_type(__1buf);
171 return traits_type::to_int_type(__1buf);
174 char __extbuf[__limit];
175 int __nread = _VSTD::max(1, __encoding_);
176 for (int __i = 0; __i < __nread; ++__i)
178 int __c = getc(__file_);
179 if (__c == EOF)
180 return traits_type::eof();
181 __extbuf[__i] = static_cast<char>(__c);
183 char_type __1buf;
184 const char* __enxt;
185 char_type* __inxt;
186 codecvt_base::result __r;
189 state_type __sv_st = *__st_;
190 __r = __cv_->in(*__st_, __extbuf, __extbuf + __nread, __enxt,
191 &__1buf, &__1buf + 1, __inxt);
192 switch (__r)
194 case _VSTD::codecvt_base::ok:
195 break;
196 case codecvt_base::partial:
197 *__st_ = __sv_st;
198 if (__nread == sizeof(__extbuf))
199 return traits_type::eof();
201 int __c = getc(__file_);
202 if (__c == EOF)
203 return traits_type::eof();
204 __extbuf[__nread] = static_cast<char>(__c);
206 ++__nread;
207 break;
208 case codecvt_base::error:
209 return traits_type::eof();
210 case _VSTD::codecvt_base::noconv:
211 __1buf = static_cast<char_type>(__extbuf[0]);
212 break;
214 } while (__r == _VSTD::codecvt_base::partial);
215 if (!__consume)
217 for (int __i = __nread; __i > 0;)
219 if (ungetc(traits_type::to_int_type(__extbuf[--__i]), __file_) == EOF)
220 return traits_type::eof();
223 else
224 __last_consumed_ = traits_type::to_int_type(__1buf);
225 return traits_type::to_int_type(__1buf);
228 template <class _CharT>
229 typename __stdinbuf<_CharT>::int_type
230 __stdinbuf<_CharT>::pbackfail(int_type __c)
232 if (traits_type::eq_int_type(__c, traits_type::eof()))
234 if (!__last_consumed_is_next_)
236 __c = __last_consumed_;
237 __last_consumed_is_next_ = !traits_type::eq_int_type(__last_consumed_,
238 traits_type::eof());
240 return __c;
242 if (__always_noconv_ && __last_consumed_is_next_) {
243 if (!__do_ungetc(__last_consumed_, __file_,
244 traits_type::to_char_type(__last_consumed_)))
245 return traits_type::eof();
246 } else if (__last_consumed_is_next_) {
247 char __extbuf[__limit];
248 char* __enxt;
249 const char_type __ci = traits_type::to_char_type(__last_consumed_);
250 const char_type* __inxt;
251 switch (__cv_->out(*__st_, &__ci, &__ci + 1, __inxt,
252 __extbuf, __extbuf + sizeof(__extbuf), __enxt))
254 case _VSTD::codecvt_base::ok:
255 break;
256 case _VSTD::codecvt_base::noconv:
257 __extbuf[0] = static_cast<char>(__last_consumed_);
258 __enxt = __extbuf + 1;
259 break;
260 case codecvt_base::partial:
261 case codecvt_base::error:
262 return traits_type::eof();
264 while (__enxt > __extbuf)
265 if (ungetc(*--__enxt, __file_) == EOF)
266 return traits_type::eof();
268 __last_consumed_ = __c;
269 __last_consumed_is_next_ = true;
270 return __c;
273 // __stdoutbuf
275 template <class _CharT>
276 class _LIBCPP_HIDDEN __stdoutbuf
277 : public basic_streambuf<_CharT, char_traits<_CharT> >
279 public:
280 typedef _CharT char_type;
281 typedef char_traits<char_type> traits_type;
282 typedef typename traits_type::int_type int_type;
283 typedef typename traits_type::pos_type pos_type;
284 typedef typename traits_type::off_type off_type;
285 typedef typename traits_type::state_type state_type;
287 __stdoutbuf(FILE* __fp, state_type* __st);
289 protected:
290 virtual int_type overflow (int_type __c = traits_type::eof());
291 virtual streamsize xsputn(const char_type* __s, streamsize __n);
292 virtual int sync();
293 virtual void imbue(const locale& __loc);
295 private:
296 FILE* __file_;
297 const codecvt<char_type, char, state_type>* __cv_;
298 state_type* __st_;
299 bool __always_noconv_;
301 #if defined(_LIBCPP_WIN32API)
302 static constexpr bool __is_win32api_wide_char = !is_same_v<_CharT, char>;
303 #else
304 static constexpr bool __is_win32api_wide_char = false;
305 #endif
307 __stdoutbuf(const __stdoutbuf&);
308 __stdoutbuf& operator=(const __stdoutbuf&);
311 template <class _CharT>
312 __stdoutbuf<_CharT>::__stdoutbuf(FILE* __fp, state_type* __st)
313 : __file_(__fp),
314 __cv_(&use_facet<codecvt<char_type, char, state_type> >(this->getloc())),
315 __st_(__st),
316 __always_noconv_(__cv_->always_noconv())
318 // On Windows, in wchar_t mode, ignore the codecvt from the locale by
319 // default and assume noconv; this passes wchar_t through unmodified to
320 // fputwc, which handles it correctly depending on the actual mode of the
321 // output stream. If the user sets a custom locale with imbue(), that
322 // gets honored.
323 if constexpr (__is_win32api_wide_char)
324 __always_noconv_ = true;
327 inline bool __do_fputc(char __c, FILE* __fp) {
328 if (fwrite(&__c, sizeof(__c), 1, __fp) != 1)
329 return false;
330 return true;
332 #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
333 inline bool __do_fputc(wchar_t __c, FILE* __fp) {
334 // fputwc works regardless of wide/narrow mode of stdout, while
335 // fwrite of wchar_t only works if the stream actually has been set
336 // into wide mode.
337 if (fputwc(__c, __fp) == WEOF)
338 return false;
339 return true;
341 #endif
343 template <class _CharT>
344 typename __stdoutbuf<_CharT>::int_type
345 __stdoutbuf<_CharT>::overflow(int_type __c)
347 char __extbuf[__limit];
348 char_type __1buf;
349 if (!traits_type::eq_int_type(__c, traits_type::eof()))
351 __1buf = traits_type::to_char_type(__c);
352 if (__always_noconv_)
354 if (!__do_fputc(__1buf, __file_))
355 return traits_type::eof();
357 else
359 char* __extbe = __extbuf;
360 codecvt_base::result __r;
361 char_type* pbase = &__1buf;
362 char_type* pptr = pbase + 1;
365 const char_type* __e;
366 __r = __cv_->out(*__st_, pbase, pptr, __e,
367 __extbuf,
368 __extbuf + sizeof(__extbuf),
369 __extbe);
370 if (__e == pbase)
371 return traits_type::eof();
372 if (__r == codecvt_base::noconv)
374 if (fwrite(pbase, 1, 1, __file_) != 1)
375 return traits_type::eof();
377 else if (__r == codecvt_base::ok || __r == codecvt_base::partial)
379 size_t __nmemb = static_cast<size_t>(__extbe - __extbuf);
380 if (fwrite(__extbuf, 1, __nmemb, __file_) != __nmemb)
381 return traits_type::eof();
382 if (__r == codecvt_base::partial)
384 pbase = const_cast<char_type*>(__e);
387 else
388 return traits_type::eof();
389 } while (__r == codecvt_base::partial);
392 return traits_type::not_eof(__c);
395 template <class _CharT>
396 streamsize
397 __stdoutbuf<_CharT>::xsputn(const char_type* __s, streamsize __n)
399 // For wchar_t on Windows, don't call fwrite(), but write characters one
400 // at a time with fputwc(); that works both when stdout is in the default
401 // mode and when it is set to Unicode mode.
402 if (__always_noconv_ && !__is_win32api_wide_char)
403 return fwrite(__s, sizeof(char_type), __n, __file_);
404 streamsize __i = 0;
405 for (; __i < __n; ++__i, ++__s)
406 if (overflow(traits_type::to_int_type(*__s)) == traits_type::eof())
407 break;
408 return __i;
411 template <class _CharT>
413 __stdoutbuf<_CharT>::sync()
415 char __extbuf[__limit];
416 codecvt_base::result __r;
419 char* __extbe;
420 __r = __cv_->unshift(*__st_, __extbuf,
421 __extbuf + sizeof(__extbuf),
422 __extbe);
423 size_t __nmemb = static_cast<size_t>(__extbe - __extbuf);
424 if (fwrite(__extbuf, 1, __nmemb, __file_) != __nmemb)
425 return -1;
426 } while (__r == codecvt_base::partial);
427 if (__r == codecvt_base::error)
428 return -1;
429 if (fflush(__file_))
430 return -1;
431 return 0;
434 template <class _CharT>
435 void
436 __stdoutbuf<_CharT>::imbue(const locale& __loc)
438 sync();
439 __cv_ = &use_facet<codecvt<char_type, char, state_type> >(__loc);
440 __always_noconv_ = __cv_->always_noconv();
443 _LIBCPP_END_NAMESPACE_STD
445 _LIBCPP_POP_MACROS
447 #endif // _LIBCPP_STD_STREAM_H