
The implementation of std::basic_streambuf used private member variables to manipulate the get and the put areas. Using public API functions is equivalent but leads to code that is easier to understand, since the public API functions are known more widely than our internal member variables. Using the public API functions removes the need to map the internal member variables back to get/put area manipulation functions in one's head. Finally, it also makes it easier to find subtle issues by instrumenting accessor functions, which is impossible if the class uses the member variables directly.
406 lines
12 KiB
C++
406 lines
12 KiB
C++
// -*- C++ -*-
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef _LIBCPP_STREAMBUF
|
|
#define _LIBCPP_STREAMBUF
|
|
|
|
/*
|
|
streambuf synopsis
|
|
|
|
namespace std
|
|
{
|
|
|
|
template <class charT, class traits = char_traits<charT> >
|
|
class basic_streambuf
|
|
{
|
|
public:
|
|
// types:
|
|
typedef charT char_type;
|
|
typedef traits traits_type;
|
|
typedef typename traits_type::int_type int_type;
|
|
typedef typename traits_type::pos_type pos_type;
|
|
typedef typename traits_type::off_type off_type;
|
|
|
|
virtual ~basic_streambuf();
|
|
|
|
// 27.6.2.2.1 locales:
|
|
locale pubimbue(const locale& loc);
|
|
locale getloc() const;
|
|
|
|
// 27.6.2.2.2 buffer and positioning:
|
|
basic_streambuf* pubsetbuf(char_type* s, streamsize n);
|
|
pos_type pubseekoff(off_type off, ios_base::seekdir way,
|
|
ios_base::openmode which = ios_base::in | ios_base::out);
|
|
pos_type pubseekpos(pos_type sp,
|
|
ios_base::openmode which = ios_base::in | ios_base::out);
|
|
int pubsync();
|
|
|
|
// Get and put areas:
|
|
// 27.6.2.2.3 Get area:
|
|
streamsize in_avail();
|
|
int_type snextc();
|
|
int_type sbumpc();
|
|
int_type sgetc();
|
|
streamsize sgetn(char_type* s, streamsize n);
|
|
|
|
// 27.6.2.2.4 Putback:
|
|
int_type sputbackc(char_type c);
|
|
int_type sungetc();
|
|
|
|
// 27.6.2.2.5 Put area:
|
|
int_type sputc(char_type c);
|
|
streamsize sputn(const char_type* s, streamsize n);
|
|
|
|
protected:
|
|
basic_streambuf();
|
|
basic_streambuf(const basic_streambuf& rhs);
|
|
basic_streambuf& operator=(const basic_streambuf& rhs);
|
|
void swap(basic_streambuf& rhs);
|
|
|
|
// 27.6.2.3.2 Get area:
|
|
char_type* eback() const;
|
|
char_type* gptr() const;
|
|
char_type* egptr() const;
|
|
void gbump(int n);
|
|
void setg(char_type* gbeg, char_type* gnext, char_type* gend);
|
|
|
|
// 27.6.2.3.3 Put area:
|
|
char_type* pbase() const;
|
|
char_type* pptr() const;
|
|
char_type* epptr() const;
|
|
void pbump(int n);
|
|
void setp(char_type* pbeg, char_type* pend);
|
|
|
|
// 27.6.2.4 virtual functions:
|
|
// 27.6.2.4.1 Locales:
|
|
virtual void imbue(const locale& loc);
|
|
|
|
// 27.6.2.4.2 Buffer management and positioning:
|
|
virtual basic_streambuf* setbuf(char_type* s, streamsize n);
|
|
virtual pos_type seekoff(off_type off, ios_base::seekdir way,
|
|
ios_base::openmode which = ios_base::in | ios_base::out);
|
|
virtual pos_type seekpos(pos_type sp,
|
|
ios_base::openmode which = ios_base::in | ios_base::out);
|
|
virtual int sync();
|
|
|
|
// 27.6.2.4.3 Get area:
|
|
virtual streamsize showmanyc();
|
|
virtual streamsize xsgetn(char_type* s, streamsize n);
|
|
virtual int_type underflow();
|
|
virtual int_type uflow();
|
|
|
|
// 27.6.2.4.4 Putback:
|
|
virtual int_type pbackfail(int_type c = traits_type::eof());
|
|
|
|
// 27.6.2.4.5 Put area:
|
|
virtual streamsize xsputn(const char_type* s, streamsize n);
|
|
virtual int_type overflow (int_type c = traits_type::eof());
|
|
};
|
|
|
|
} // std
|
|
|
|
*/
|
|
|
|
#if __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS)
|
|
# include <__cxx03/streambuf>
|
|
#else
|
|
# include <__config>
|
|
|
|
# if _LIBCPP_HAS_LOCALIZATION
|
|
|
|
# include <__assert>
|
|
# include <__fwd/streambuf.h>
|
|
# include <__locale>
|
|
# include <__type_traits/is_same.h>
|
|
# include <__utility/is_valid_range.h>
|
|
# include <climits>
|
|
# include <ios>
|
|
# include <iosfwd>
|
|
# include <version>
|
|
|
|
# if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
|
# pragma GCC system_header
|
|
# endif
|
|
|
|
_LIBCPP_PUSH_MACROS
|
|
# include <__undef_macros>
|
|
|
|
_LIBCPP_BEGIN_NAMESPACE_STD
|
|
|
|
template <class _CharT, class _Traits>
|
|
class basic_streambuf {
|
|
public:
|
|
// types:
|
|
typedef _CharT char_type;
|
|
typedef _Traits traits_type;
|
|
typedef typename traits_type::int_type int_type;
|
|
typedef typename traits_type::pos_type pos_type;
|
|
typedef typename traits_type::off_type off_type;
|
|
|
|
static_assert(is_same<_CharT, typename traits_type::char_type>::value,
|
|
"traits_type::char_type must be the same type as CharT");
|
|
|
|
virtual ~basic_streambuf() {}
|
|
|
|
// 27.6.2.2.1 locales:
|
|
inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 locale pubimbue(const locale& __loc) {
|
|
imbue(__loc);
|
|
locale __r = __loc_;
|
|
__loc_ = __loc;
|
|
return __r;
|
|
}
|
|
|
|
inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 locale getloc() const { return __loc_; }
|
|
|
|
// 27.6.2.2.2 buffer and positioning:
|
|
inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 basic_streambuf* pubsetbuf(char_type* __s, streamsize __n) {
|
|
return setbuf(__s, __n);
|
|
}
|
|
|
|
inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 pos_type
|
|
pubseekoff(off_type __off, ios_base::seekdir __way, ios_base::openmode __which = ios_base::in | ios_base::out) {
|
|
return seekoff(__off, __way, __which);
|
|
}
|
|
|
|
inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 pos_type
|
|
pubseekpos(pos_type __sp, ios_base::openmode __which = ios_base::in | ios_base::out) {
|
|
return seekpos(__sp, __which);
|
|
}
|
|
|
|
inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 int pubsync() { return sync(); }
|
|
|
|
// Get and put areas:
|
|
// 27.6.2.2.3 Get area:
|
|
inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 streamsize in_avail() {
|
|
if (gptr() < egptr())
|
|
return static_cast<streamsize>(egptr() - gptr());
|
|
return showmanyc();
|
|
}
|
|
|
|
inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 int_type snextc() {
|
|
if (sbumpc() == traits_type::eof())
|
|
return traits_type::eof();
|
|
return sgetc();
|
|
}
|
|
|
|
inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 int_type sbumpc() {
|
|
if (gptr() == egptr())
|
|
return uflow();
|
|
int_type __c = traits_type::to_int_type(*gptr());
|
|
this->gbump(1);
|
|
return __c;
|
|
}
|
|
|
|
inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 int_type sgetc() {
|
|
if (gptr() == egptr())
|
|
return underflow();
|
|
return traits_type::to_int_type(*gptr());
|
|
}
|
|
|
|
inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 streamsize sgetn(char_type* __s, streamsize __n) { return xsgetn(__s, __n); }
|
|
|
|
// 27.6.2.2.4 Putback:
|
|
inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 int_type sputbackc(char_type __c) {
|
|
if (eback() == gptr() || !traits_type::eq(__c, *(gptr() - 1)))
|
|
return pbackfail(traits_type::to_int_type(__c));
|
|
this->gbump(-1);
|
|
return traits_type::to_int_type(*gptr());
|
|
}
|
|
|
|
inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 int_type sungetc() {
|
|
if (eback() == gptr())
|
|
return pbackfail();
|
|
this->gbump(-1);
|
|
return traits_type::to_int_type(*gptr());
|
|
}
|
|
|
|
// 27.6.2.2.5 Put area:
|
|
inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 int_type sputc(char_type __c) {
|
|
if (pptr() == epptr())
|
|
return overflow(traits_type::to_int_type(__c));
|
|
*pptr() = __c;
|
|
this->pbump(1);
|
|
return traits_type::to_int_type(__c);
|
|
}
|
|
|
|
inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 streamsize sputn(const char_type* __s, streamsize __n) {
|
|
return xsputn(__s, __n);
|
|
}
|
|
|
|
protected:
|
|
basic_streambuf() {}
|
|
basic_streambuf(const basic_streambuf& __sb)
|
|
: __loc_(__sb.__loc_),
|
|
__binp_(__sb.__binp_),
|
|
__ninp_(__sb.__ninp_),
|
|
__einp_(__sb.__einp_),
|
|
__bout_(__sb.__bout_),
|
|
__nout_(__sb.__nout_),
|
|
__eout_(__sb.__eout_) {}
|
|
|
|
basic_streambuf& operator=(const basic_streambuf& __sb) {
|
|
__loc_ = __sb.__loc_;
|
|
__binp_ = __sb.__binp_;
|
|
__ninp_ = __sb.__ninp_;
|
|
__einp_ = __sb.__einp_;
|
|
__bout_ = __sb.__bout_;
|
|
__nout_ = __sb.__nout_;
|
|
__eout_ = __sb.__eout_;
|
|
return *this;
|
|
}
|
|
|
|
void swap(basic_streambuf& __sb) {
|
|
std::swap(__loc_, __sb.__loc_);
|
|
std::swap(__binp_, __sb.__binp_);
|
|
std::swap(__ninp_, __sb.__ninp_);
|
|
std::swap(__einp_, __sb.__einp_);
|
|
std::swap(__bout_, __sb.__bout_);
|
|
std::swap(__nout_, __sb.__nout_);
|
|
std::swap(__eout_, __sb.__eout_);
|
|
}
|
|
|
|
// 27.6.2.3.2 Get area:
|
|
_LIBCPP_HIDE_FROM_ABI char_type* eback() const { return __binp_; }
|
|
_LIBCPP_HIDE_FROM_ABI char_type* gptr() const { return __ninp_; }
|
|
_LIBCPP_HIDE_FROM_ABI char_type* egptr() const { return __einp_; }
|
|
|
|
inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 void gbump(int __n) { __ninp_ += __n; }
|
|
|
|
// gbump takes an int, so it might not be able to represent the offset we want to add.
|
|
_LIBCPP_HIDE_FROM_ABI void __gbump_ptrdiff(ptrdiff_t __n) { __ninp_ += __n; }
|
|
|
|
inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 void setg(char_type* __gbeg, char_type* __gnext, char_type* __gend) {
|
|
_LIBCPP_ASSERT_VALID_INPUT_RANGE(std::__is_valid_range(__gbeg, __gnext), "[gbeg, gnext) must be a valid range");
|
|
_LIBCPP_ASSERT_VALID_INPUT_RANGE(std::__is_valid_range(__gbeg, __gend), "[gbeg, gend) must be a valid range");
|
|
_LIBCPP_ASSERT_VALID_INPUT_RANGE(std::__is_valid_range(__gnext, __gend), "[gnext, gend) must be a valid range");
|
|
__binp_ = __gbeg;
|
|
__ninp_ = __gnext;
|
|
__einp_ = __gend;
|
|
}
|
|
|
|
// 27.6.2.3.3 Put area:
|
|
_LIBCPP_HIDE_FROM_ABI char_type* pbase() const { return __bout_; }
|
|
_LIBCPP_HIDE_FROM_ABI char_type* pptr() const { return __nout_; }
|
|
_LIBCPP_HIDE_FROM_ABI char_type* epptr() const { return __eout_; }
|
|
|
|
inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 void pbump(int __n) { __nout_ += __n; }
|
|
|
|
_LIBCPP_HIDE_FROM_ABI void __pbump(streamsize __n) { __nout_ += __n; }
|
|
|
|
inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 void setp(char_type* __pbeg, char_type* __pend) {
|
|
_LIBCPP_ASSERT_VALID_INPUT_RANGE(std::__is_valid_range(__pbeg, __pend), "[pbeg, pend) must be a valid range");
|
|
__bout_ = __nout_ = __pbeg;
|
|
__eout_ = __pend;
|
|
}
|
|
|
|
// 27.6.2.4 virtual functions:
|
|
// 27.6.2.4.1 Locales:
|
|
virtual void imbue(const locale&) {}
|
|
|
|
// 27.6.2.4.2 Buffer management and positioning:
|
|
virtual basic_streambuf* setbuf(char_type*, streamsize) { return this; }
|
|
virtual pos_type seekoff(off_type, ios_base::seekdir, ios_base::openmode = ios_base::in | ios_base::out) {
|
|
return pos_type(off_type(-1));
|
|
}
|
|
virtual pos_type seekpos(pos_type, ios_base::openmode = ios_base::in | ios_base::out) {
|
|
return pos_type(off_type(-1));
|
|
}
|
|
virtual int sync() { return 0; }
|
|
|
|
// 27.6.2.4.3 Get area:
|
|
virtual streamsize showmanyc() { return 0; }
|
|
|
|
virtual streamsize xsgetn(char_type* __s, streamsize __n) {
|
|
int_type __c;
|
|
streamsize __i = 0;
|
|
while (__i < __n) {
|
|
if (gptr() < egptr()) {
|
|
const streamsize __len = std::min(static_cast<streamsize>(INT_MAX), std::min(egptr() - gptr(), __n - __i));
|
|
traits_type::copy(__s, gptr(), __len);
|
|
__s += __len;
|
|
__i += __len;
|
|
this->gbump(__len);
|
|
} else if ((__c = uflow()) != traits_type::eof()) {
|
|
*__s = traits_type::to_char_type(__c);
|
|
++__s;
|
|
++__i;
|
|
} else
|
|
break;
|
|
}
|
|
return __i;
|
|
}
|
|
|
|
virtual int_type underflow() { return traits_type::eof(); }
|
|
virtual int_type uflow() {
|
|
if (underflow() == traits_type::eof())
|
|
return traits_type::eof();
|
|
int_type __c = traits_type::to_int_type(*gptr());
|
|
this->gbump(1);
|
|
return __c;
|
|
}
|
|
|
|
// 27.6.2.4.4 Putback:
|
|
virtual int_type pbackfail(int_type = traits_type::eof()) { return traits_type::eof(); }
|
|
|
|
// 27.6.2.4.5 Put area:
|
|
virtual streamsize xsputn(const char_type* __s, streamsize __n) {
|
|
streamsize __i = 0;
|
|
while (__i < __n) {
|
|
if (pptr() >= epptr()) {
|
|
if (overflow(traits_type::to_int_type(*__s)) == traits_type::eof())
|
|
break;
|
|
++__s;
|
|
++__i;
|
|
} else {
|
|
streamsize __chunk_size = std::min(epptr() - pptr(), __n - __i);
|
|
traits_type::copy(pptr(), __s, __chunk_size);
|
|
__pbump(__chunk_size);
|
|
__s += __chunk_size;
|
|
__i += __chunk_size;
|
|
}
|
|
}
|
|
return __i;
|
|
}
|
|
|
|
virtual int_type overflow(int_type = traits_type::eof()) { return traits_type::eof(); }
|
|
|
|
private:
|
|
locale __loc_;
|
|
char_type* __binp_ = nullptr;
|
|
char_type* __ninp_ = nullptr;
|
|
char_type* __einp_ = nullptr;
|
|
char_type* __bout_ = nullptr;
|
|
char_type* __nout_ = nullptr;
|
|
char_type* __eout_ = nullptr;
|
|
|
|
template <class _CharT2, class _Traits2, class _Allocator>
|
|
_LIBCPP_HIDE_FROM_ABI friend basic_istream<_CharT2, _Traits2>&
|
|
getline(basic_istream<_CharT2, _Traits2>&, basic_string<_CharT2, _Traits2, _Allocator>&, _CharT2);
|
|
};
|
|
|
|
extern template class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS basic_streambuf<char>;
|
|
|
|
# if _LIBCPP_HAS_WIDE_CHARACTERS
|
|
extern template class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS basic_streambuf<wchar_t>;
|
|
# endif
|
|
|
|
_LIBCPP_END_NAMESPACE_STD
|
|
|
|
_LIBCPP_POP_MACROS
|
|
|
|
# endif // _LIBCPP_HAS_LOCALIZATION
|
|
|
|
# if !defined(_LIBCPP_REMOVE_TRANSITIVE_INCLUDES) && _LIBCPP_STD_VER <= 20
|
|
# include <cstdint>
|
|
# include <optional>
|
|
# endif
|
|
#endif // __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS)
|
|
|
|
#endif // _LIBCPP_STREAMBUF
|