1// Streams based on std::span -*- C++ -*- 2 3// Copyright The GNU Toolchain Authors. 4// 5// This file is part of the GNU ISO C++ Library. This library is free 6// software; you can redistribute it and/or modify it under the 7// terms of the GNU General Public License as published by the 8// Free Software Foundation; either version 3, or (at your option) 9// any later version. 10 11// This library is distributed in the hope that it will be useful, 12// but WITHOUT ANY WARRANTY; without even the implied warranty of 13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14// GNU General Public License for more details. 15 16// Under Section 7 of GPL version 3, you are granted additional 17// permissions described in the GCC Runtime Library Exception, version 18// 3.1, as published by the Free Software Foundation. 19 20// You should have received a copy of the GNU General Public License and 21// a copy of the GCC Runtime Library Exception along with this program; 22// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 23// <http://www.gnu.org/licenses/>. 24 25/** @file spanstream 26 * This is a Standard C++ Library header. 27 */ 28 29#ifndef _GLIBCXX_SPANSTREAM 30#define _GLIBCXX_SPANSTREAM 1 31 32#pragma GCC system_header 33 34#if __cplusplus > 202002L 35#include <span> 36#include <streambuf> 37#include <istream> 38#include <ostream> 39#include <bits/ranges_base.h> 40 41#if __cpp_lib_span 42namespace std _GLIBCXX_VISIBILITY(default) 43{ 44_GLIBCXX_BEGIN_NAMESPACE_VERSION 45 46#define __cpp_lib_spanstream 202106L 47 48template<typename _CharT, typename _Traits> 49 class basic_spanbuf 50 : public basic_streambuf<_CharT, _Traits> 51 { 52 using __streambuf_type = basic_streambuf<_CharT, _Traits>; 53 54 public: 55 using char_type = _CharT; 56 using int_type = typename _Traits::int_type; 57 using pos_type = typename _Traits::pos_type; 58 using off_type = typename _Traits::off_type; 59 using traits_type = _Traits; 60 61 // [spanbuf.ctor], constructors 62 basic_spanbuf() : basic_spanbuf(ios_base::in | ios_base::out) 63 { } 64 65 explicit 66 basic_spanbuf(ios_base::openmode __which) 67 : __streambuf_type(), _M_mode(__which) 68 { } 69 70 explicit 71 basic_spanbuf(std::span<_CharT> __s, 72 ios_base::openmode __which = ios_base::in | ios_base::out) 73 : __streambuf_type(), _M_mode(__which) 74 { span(__s); } 75 76 basic_spanbuf(const basic_spanbuf&) = delete; 77 78 /** Move constructor. 79 * 80 * Transfers the buffer and pointers into the get and put areas from 81 * `__rhs` to `*this`. 82 * 83 * In this implementation `rhs` is left unchanged, 84 * but that is not guaranteed by the standard. 85 */ 86 basic_spanbuf(basic_spanbuf&& __rhs) 87 : __streambuf_type(__rhs), _M_mode(__rhs._M_mode), _M_buf(__rhs._M_buf) 88 { } 89 90 // [spanbuf.assign], assignment and swap 91 basic_spanbuf& operator=(const basic_spanbuf&) = delete; 92 93 basic_spanbuf& 94 operator=(basic_spanbuf&& __rhs) 95 { 96 basic_spanbuf(std::move(__rhs)).swap(*this); 97 return *this; 98 } 99 100 void 101 swap(basic_spanbuf& __rhs) 102 { 103 __streambuf_type::swap(__rhs); 104 std::swap(_M_mode, __rhs._M_mode); 105 std::swap(_M_buf, __rhs._M_buf); 106 } 107 108 // [spanbuf.members], member functions 109 std::span<_CharT> 110 span() const noexcept 111 { 112 if (_M_mode & ios_base::out) 113 return {this->pbase(), this->pptr()}; 114 else 115 return _M_buf; 116 } 117 118 void 119 span(std::span<_CharT> __s) noexcept 120 { 121 _M_buf = __s; 122 if (_M_mode & ios_base::out) 123 { 124 this->setp(__s.data(), __s.data() + __s.size()); 125 if (_M_mode & ios_base::ate) 126 this->pbump(__s.size()); 127 } 128 if (_M_mode & ios_base::in) 129 this->setg(__s.data(), __s.data(), __s.data() + __s.size()); 130 } 131 132 protected: 133 // [spanbuf.virtuals], overridden virtual functions 134 basic_streambuf<_CharT, _Traits>* 135 setbuf(_CharT* __s, streamsize __n) override 136 { 137 span({__s, __n}); 138 return this; 139 } 140 141 pos_type 142 seekoff(off_type __off, ios_base::seekdir __way, 143 ios_base::openmode __which = ios_base::in | ios_base::out) override 144 { 145 pos_type __ret = pos_type(off_type(-1)); 146 147 if (__way == ios_base::beg) 148 { 149 if (0 <= __off && __off <= _M_buf.size()) 150 { 151 if (__which & ios_base::in) 152 this->setg(this->eback(), this->eback() + __off, this->egptr()); 153 154 if (__which & ios_base::out) 155 { 156 this->setp(this->pbase(), this->epptr()); 157 this->pbump(__off); 158 } 159 160 __ret = pos_type(__off); 161 } 162 } 163 else 164 { 165 off_type __base; 166 __which &= (ios_base::in|ios_base::out); 167 168 if (__which == ios_base::out) 169 __base = this->pptr() - this->pbase(); 170 else if (__way == ios_base::cur) 171 { 172 if (__which == ios_base::in) 173 __base = this->gptr() - this->eback(); 174 else 175 return __ret; 176 } 177 else if (__way == ios_base::end) 178 __base = _M_buf.size(); 179 180 if (__builtin_add_overflow(__base, __off, &__off)) 181 return __ret; 182 183 if (__off < 0 || __off > _M_buf.size()) 184 return __ret; 185 186 if (__which & ios_base::in) 187 this->setg(this->eback(), this->eback() + __off, this->egptr()); 188 189 if (__which & ios_base::out) 190 { 191 this->setp(this->pbase(), this->epptr()); 192 this->pbump(__off); 193 } 194 195 __ret = pos_type(__off); 196 197 } 198 return __ret; 199 } 200 201 pos_type 202 seekpos(pos_type __sp, 203 ios_base::openmode __which = ios_base::in | ios_base::out) override 204 { return seekoff(off_type(__sp), ios_base::beg, __which); } 205 206 private: 207 208 ios_base::openmode _M_mode; 209 std::span<_CharT> _M_buf; 210 }; 211 212template<typename _CharT, typename _Traits> 213 inline void 214 swap(basic_spanbuf<_CharT, _Traits>& __x, 215 basic_spanbuf<_CharT, _Traits>& __y) 216 { __x.swap(__y); } 217 218using spanbuf = basic_spanbuf<char>; 219using wspanbuf = basic_spanbuf<wchar_t>; 220 221template<typename _CharT, typename _Traits> 222 class basic_ispanstream 223 : public basic_istream<_CharT, _Traits> 224 { 225 using __istream_type = basic_istream<_CharT, _Traits>; 226 227 public: 228 using char_type = _CharT; 229 using int_type = typename _Traits::int_type; 230 using pos_type = typename _Traits::pos_type; 231 using off_type = typename _Traits::off_type; 232 using traits_type = _Traits; 233 234 // [ispanstream.ctor], constructors 235 explicit 236 basic_ispanstream(std::span<_CharT> __s, 237 ios_base::openmode __which = ios_base::in) 238 : __istream_type(std::__addressof(_M_sb)), 239 _M_sb(__s, __which | ios_base::in) 240 { } 241 242 basic_ispanstream(const basic_ispanstream&) = delete; 243 244 basic_ispanstream(basic_ispanstream&& __rhs) 245 : __istream_type(std::move(__rhs)), _M_sb(std::move(__rhs._M_sb)) 246 { 247 __istream_type::set_rdbuf(std::addressof(_M_sb)); 248 } 249 250 template<typename _Ros> 251 requires ranges::borrowed_range<_Ros> 252 && (!convertible_to<_Ros, std::span<_CharT>>) 253 && convertible_to<_Ros, std::span<const _CharT>> 254 explicit 255 basic_ispanstream(_Ros&& __s) 256 : __istream_type(std::__addressof(_M_sb)), 257 _M_sb(ios_base::in) 258 { 259 std::span<const _CharT> __sp(std::forward<_Ros>(__s)); 260 _M_sb.span({const_cast<_CharT*>(__sp.data()), __sp.size()}); 261 } 262 263 // [ispanstream.assign], assignment and swap 264 basic_ispanstream& operator=(const basic_ispanstream&) = delete; 265 basic_ispanstream& operator=(basic_ispanstream&& __rhs) = default; 266 267 void 268 swap(basic_ispanstream& __rhs) 269 { 270 __istream_type::swap(__rhs); 271 _M_sb.swap(__rhs._M_sb); 272 } 273 274 // [ispanstream.members], member functions 275 basic_spanbuf<_CharT, _Traits>* 276 rdbuf() const noexcept 277 { 278 return const_cast<basic_spanbuf<_CharT, _Traits>*>(std::__addressof(_M_sb)); 279 } 280 281 std::span<const _CharT> 282 span() const noexcept 283 { return _M_sb.span(); } 284 285 void 286 span(std::span<_CharT> __s) noexcept 287 { return _M_sb.span(__s); } 288 289 template<typename _Ros> 290 requires ranges::borrowed_range<_Ros> 291 && (!convertible_to<_Ros, std::span<_CharT>>) 292 && convertible_to<_Ros, std::span<const _CharT>> 293 void 294 span(_Ros&& __s) noexcept 295 { 296 std::span<const _CharT> __sp(std::forward<_Ros>(__s)); 297 _M_sb.span({const_cast<_CharT*>(__sp.data()), __sp.size()}); 298 } 299 300 private: 301 basic_spanbuf<_CharT, _Traits> _M_sb; 302 }; 303 304template<typename _CharT, typename _Traits> 305 inline void 306 swap(basic_ispanstream<_CharT, _Traits>& __x, 307 basic_ispanstream<_CharT, _Traits>& __y) 308 { __x.swap(__y); } 309 310using ispanstream = basic_ispanstream<char>; 311using wispanstream = basic_ispanstream<wchar_t>; 312 313template<typename _CharT, typename _Traits> 314 class basic_ospanstream 315 : public basic_ostream<_CharT, _Traits> 316 { 317 using __ostream_type = basic_ostream<_CharT, _Traits>; 318 319 public: 320 using char_type = _CharT; 321 using int_type = typename _Traits::int_type; 322 using pos_type = typename _Traits::pos_type; 323 using off_type = typename _Traits::off_type; 324 using traits_type = _Traits; 325 326 // [ospanstream.ctor], constructors 327 explicit 328 basic_ospanstream(std::span<_CharT> __s, 329 ios_base::openmode __which = ios_base::out) 330 : __ostream_type(std::__addressof(_M_sb)), 331 _M_sb(__s, __which | ios_base::in) 332 { } 333 334 basic_ospanstream(const basic_ospanstream&) = delete; 335 336 basic_ospanstream(basic_ospanstream&& __rhs) 337 : __ostream_type(std::move(__rhs)), _M_sb(std::move(__rhs._M_sb)) 338 { 339 __ostream_type::set_rdbuf(std::addressof(_M_sb)); 340 } 341 342 // [ospanstream.assign], assignment and swap 343 basic_ospanstream& operator=(const basic_ospanstream&) = delete; 344 basic_ospanstream& operator=(basic_ospanstream&& __rhs) = default; 345 346 void 347 swap(basic_ospanstream& __rhs) 348 { 349 __ostream_type::swap(__rhs); 350 _M_sb.swap(__rhs._M_sb); 351 } 352 353 // [ospanstream.members], member functions 354 basic_spanbuf<_CharT, _Traits>* 355 rdbuf() const noexcept 356 { 357 return const_cast<basic_spanbuf<_CharT, _Traits>*>(std::__addressof(_M_sb)); 358 } 359 360 std::span<_CharT> 361 span() const noexcept 362 { return _M_sb.span(); } 363 364 void 365 span(std::span<_CharT> __s) noexcept 366 { return _M_sb.span(__s); } 367 368 private: 369 basic_spanbuf<_CharT, _Traits> _M_sb; 370 }; 371 372template<typename _CharT, typename _Traits> 373 inline void 374 swap(basic_ospanstream<_CharT, _Traits>& __x, 375 basic_ospanstream<_CharT, _Traits>& __y) 376 { __x.swap(__y); } 377 378using ospanstream = basic_ospanstream<char>; 379using wospanstream = basic_ospanstream<wchar_t>; 380 381template<typename _CharT, typename _Traits> 382 class basic_spanstream 383 : public basic_iostream<_CharT, _Traits> 384 { 385 using __iostream_type = basic_iostream<_CharT, _Traits>; 386 387 public: 388 using char_type = _CharT; 389 using int_type = typename _Traits::int_type; 390 using pos_type = typename _Traits::pos_type; 391 using off_type = typename _Traits::off_type; 392 using traits_type = _Traits; 393 394 // [spanstream.ctor], constructors 395 explicit 396 basic_spanstream(std::span<_CharT> __s, 397 ios_base::openmode __which = ios_base::out | ios_base::in) 398 : __iostream_type(std::__addressof(_M_sb)), 399 _M_sb(__s, __which) 400 { } 401 402 basic_spanstream(const basic_spanstream&) = delete; 403 404 basic_spanstream(basic_spanstream&& __rhs) 405 : __iostream_type(std::move(__rhs)), _M_sb(std::move(__rhs._M_sb)) 406 { 407 __iostream_type::set_rdbuf(std::addressof(_M_sb)); 408 } 409 410 // [spanstream.assign], assignment and swap 411 basic_spanstream& operator=(const basic_spanstream&) = delete; 412 basic_spanstream& operator=(basic_spanstream&& __rhs) = default; 413 414 void 415 swap(basic_spanstream& __rhs) 416 { 417 __iostream_type::swap(__rhs); 418 _M_sb.swap(__rhs._M_sb); 419 } 420 421 // [spanstream.members], members 422 basic_spanbuf<_CharT, _Traits>* 423 rdbuf() const noexcept 424 { 425 return const_cast<basic_spanbuf<_CharT, _Traits>*>(std::__addressof(_M_sb)); 426 } 427 428 std::span<_CharT> 429 span() const noexcept 430 { return _M_sb.span(); } 431 432 void 433 span(std::span<_CharT> __s) noexcept 434 { return _M_sb.span(__s); } 435 436 private: 437 basic_spanbuf<_CharT, _Traits> _M_sb; 438 }; 439 440template<typename _CharT, typename _Traits> 441 inline void 442 swap(basic_spanstream<_CharT, _Traits>& __x, 443 basic_spanstream<_CharT, _Traits>& __y) 444 { __x.swap(__y); } 445 446using spanstream = basic_spanstream<char>; 447using wspanstream = basic_spanstream<wchar_t>; 448 449_GLIBCXX_END_NAMESPACE_VERSION 450} // namespace std 451#endif // __cpp_lib_span 452#endif // C++23 453#endif // _GLIBCXX_SPANSTREAM 454