259 lines · cpp
1//===----------------------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include <__assert>10#include <__utility/unreachable.h>11#include <algorithm>12#include <climits>13#include <cstdlib>14#include <cstring>15#include <strstream>16 17_LIBCPP_PUSH_MACROS18#include <__undef_macros>19 20_LIBCPP_BEGIN_NAMESPACE_STD21 22strstreambuf::strstreambuf(streamsize __alsize)23 : __strmode_(__dynamic), __alsize_(__alsize), __palloc_(nullptr), __pfree_(nullptr) {}24 25strstreambuf::strstreambuf(void* (*__palloc)(size_t), void (*__pfree)(void*))26 : __strmode_(__dynamic), __alsize_(__default_alsize), __palloc_(__palloc), __pfree_(__pfree) {}27 28void strstreambuf::__init(char* __gnext, streamsize __n, char* __pbeg) {29 if (__n == 0)30 __n = static_cast<streamsize>(strlen(__gnext));31 else if (__n < 0)32 __n = INT_MAX;33 if (__pbeg == nullptr)34 setg(__gnext, __gnext, __gnext + __n);35 else {36 setg(__gnext, __gnext, __pbeg);37 setp(__pbeg, __pbeg + __n);38 }39}40 41strstreambuf::strstreambuf(char* __gnext, streamsize __n, char* __pbeg)42 : __strmode_(), __alsize_(__default_alsize), __palloc_(nullptr), __pfree_(nullptr) {43 __init(__gnext, __n, __pbeg);44}45 46strstreambuf::strstreambuf(const char* __gnext, streamsize __n)47 : __strmode_(__constant), __alsize_(__default_alsize), __palloc_(nullptr), __pfree_(nullptr) {48 __init(const_cast<char*>(__gnext), __n, nullptr);49}50 51strstreambuf::strstreambuf(signed char* __gnext, streamsize __n, signed char* __pbeg)52 : __strmode_(), __alsize_(__default_alsize), __palloc_(nullptr), __pfree_(nullptr) {53 __init(const_cast<char*>(reinterpret_cast<const char*>(__gnext)), __n, reinterpret_cast<char*>(__pbeg));54}55 56strstreambuf::strstreambuf(const signed char* __gnext, streamsize __n)57 : __strmode_(__constant), __alsize_(__default_alsize), __palloc_(nullptr), __pfree_(nullptr) {58 __init(const_cast<char*>(reinterpret_cast<const char*>(__gnext)), __n, nullptr);59}60 61strstreambuf::strstreambuf(unsigned char* __gnext, streamsize __n, unsigned char* __pbeg)62 : __strmode_(), __alsize_(__default_alsize), __palloc_(nullptr), __pfree_(nullptr) {63 __init(const_cast<char*>(reinterpret_cast<const char*>(__gnext)), __n, reinterpret_cast<char*>(__pbeg));64}65 66strstreambuf::strstreambuf(const unsigned char* __gnext, streamsize __n)67 : __strmode_(__constant), __alsize_(__default_alsize), __palloc_(nullptr), __pfree_(nullptr) {68 __init(const_cast<char*>(reinterpret_cast<const char*>(__gnext)), __n, nullptr);69}70 71strstreambuf::~strstreambuf() {72 if (eback() && (__strmode_ & __allocated) != 0 && (__strmode_ & __frozen) == 0) {73 if (__pfree_)74 __pfree_(eback());75 else76 delete[] eback();77 }78}79 80void strstreambuf::swap(strstreambuf& __rhs) {81 streambuf::swap(__rhs);82 std::swap(__strmode_, __rhs.__strmode_);83 std::swap(__alsize_, __rhs.__alsize_);84 std::swap(__palloc_, __rhs.__palloc_);85 std::swap(__pfree_, __rhs.__pfree_);86}87 88void strstreambuf::freeze(bool __freezefl) {89 if (__strmode_ & __dynamic) {90 if (__freezefl)91 __strmode_ |= __frozen;92 else93 __strmode_ &= ~__frozen;94 }95}96 97char* strstreambuf::str() {98 if (__strmode_ & __dynamic)99 __strmode_ |= __frozen;100 return eback();101}102 103int strstreambuf::pcount() const { return static_cast<int>(pptr() - pbase()); }104 105strstreambuf::int_type strstreambuf::overflow(int_type __c) {106 if (__c == EOF)107 return int_type(0);108 if (pptr() == epptr()) {109 if ((__strmode_ & __dynamic) == 0 || (__strmode_ & __frozen) != 0)110 return int_type(EOF);111 size_t old_size = static_cast<size_t>((epptr() ? epptr() : egptr()) - eback());112 size_t new_size = max<size_t>(static_cast<size_t>(__alsize_), 2 * old_size);113 if (new_size == 0)114 new_size = __default_alsize;115 char* buf = nullptr;116 if (__palloc_)117 buf = static_cast<char*>(__palloc_(new_size));118 else119 buf = new char[new_size];120 if (buf == nullptr)121 return int_type(EOF);122 if (old_size != 0) {123 _LIBCPP_ASSERT_INTERNAL(eback(), "strstreambuf::overflow reallocating but the get area is a null pointer");124 memcpy(buf, eback(), static_cast<size_t>(old_size));125 }126 ptrdiff_t ninp = gptr() - eback();127 ptrdiff_t einp = egptr() - eback();128 ptrdiff_t nout = pptr() - pbase();129 if (__strmode_ & __allocated) {130 if (__pfree_)131 __pfree_(eback());132 else133 delete[] eback();134 }135 setg(buf, buf + ninp, buf + einp);136 setp(buf + einp, buf + new_size);137 __pbump(nout);138 __strmode_ |= __allocated;139 }140 *pptr() = static_cast<char>(__c);141 pbump(1);142 return int_type(static_cast<unsigned char>(__c));143}144 145strstreambuf::int_type strstreambuf::pbackfail(int_type __c) {146 if (eback() == gptr())147 return EOF;148 if (__c == EOF) {149 gbump(-1);150 return int_type(0);151 }152 if (__strmode_ & __constant) {153 if (gptr()[-1] == static_cast<char>(__c)) {154 gbump(-1);155 return __c;156 }157 return EOF;158 }159 gbump(-1);160 *gptr() = static_cast<char>(__c);161 return __c;162}163 164strstreambuf::int_type strstreambuf::underflow() {165 if (gptr() == egptr()) {166 if (egptr() >= pptr())167 return EOF;168 setg(eback(), gptr(), pptr());169 }170 return int_type(static_cast<unsigned char>(*gptr()));171}172 173strstreambuf::pos_type strstreambuf::seekoff(off_type __off, ios_base::seekdir __way, ios_base::openmode __which) {174 bool pos_in = (__which & ios::in) != 0;175 bool pos_out = (__which & ios::out) != 0;176 switch (__way) {177 case ios::beg:178 case ios::end:179 if (!pos_in && !pos_out)180 return pos_type(off_type(-1));181 break;182 case ios::cur:183 if (pos_in == pos_out)184 return pos_type(off_type(-1));185 break;186 }187 188 if (pos_in && gptr() == nullptr)189 return pos_type(off_type(-1));190 if (pos_out && pptr() == nullptr)191 return pos_type(off_type(-1));192 193 off_type newoff;194 char* seekhigh = epptr() ? epptr() : egptr();195 switch (__way) {196 case ios::beg:197 newoff = 0;198 break;199 case ios::cur:200 newoff = (pos_in ? gptr() : pptr()) - eback();201 break;202 case ios::end:203 newoff = seekhigh - eback();204 break;205 default:206 __libcpp_unreachable();207 }208 newoff += __off;209 if (newoff < 0 || newoff > seekhigh - eback())210 return pos_type(off_type(-1));211 212 char* newpos = eback() + newoff;213 if (pos_in)214 setg(eback(), newpos, std::max(newpos, egptr()));215 if (pos_out) {216 // min(pbase, newpos), newpos, epptr()217 __off = epptr() - newpos;218 setp(min(pbase(), newpos), epptr());219 __pbump((epptr() - pbase()) - __off);220 }221 return pos_type(newoff);222}223 224strstreambuf::pos_type strstreambuf::seekpos(pos_type __sp, ios_base::openmode __which) {225 bool pos_in = (__which & ios::in) != 0;226 bool pos_out = (__which & ios::out) != 0;227 if (!pos_in && !pos_out)228 return pos_type(off_type(-1));229 230 if ((pos_in && gptr() == nullptr) || (pos_out && pptr() == nullptr))231 return pos_type(off_type(-1));232 233 off_type newoff = __sp;234 char* seekhigh = epptr() ? epptr() : egptr();235 if (newoff < 0 || newoff > seekhigh - eback())236 return pos_type(off_type(-1));237 238 char* newpos = eback() + newoff;239 if (pos_in)240 setg(eback(), newpos, std::max(newpos, egptr()));241 if (pos_out) {242 // min(pbase, newpos), newpos, epptr()243 off_type temp = epptr() - newpos;244 setp(min(pbase(), newpos), epptr());245 __pbump((epptr() - pbase()) - temp);246 }247 return pos_type(newoff);248}249 250istrstream::~istrstream() {}251 252ostrstream::~ostrstream() {}253 254strstream::~strstream() {}255 256_LIBCPP_END_NAMESPACE_STD257 258_LIBCPP_POP_MACROS259