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 __glibcxx_assert(__n >= 0); 138 this->span(std::span<_CharT>(__s, __n)); 139 return this; 140 } 141 142 pos_type 143 seekoff(off_type __off, ios_base::seekdir __way, 144 ios_base::openmode __which = ios_base::in | ios_base::out) override 145 { 146 pos_type __ret = pos_type(off_type(-1)); 147 148 if (__way == ios_base::beg) 149 { 150 if (0 <= __off && __off <= _M_buf.size()) 151 { 152 if (__which & ios_base::in) 153 this->setg(this->eback(), this->eback() + __off, this->egptr()); 154 155 if (__which & ios_base::out) 156 { 157 this->setp(this->pbase(), this->epptr()); 158 this->pbump(__off); 159 } 160 161 __ret = pos_type(__off); 162 } 163 } 164 else 165 { 166 off_type __base; 167 __which &= (ios_base::in|ios_base::out); 168 169 if (__which == ios_base::out) 170 __base = this->pptr() - this->pbase(); 171 else if (__way == ios_base::cur) 172 { 173 if (__which == ios_base::in) 174 __base = this->gptr() - this->eback(); 175 else 176 return __ret; 177 } 178 else if (__way == ios_base::end) 179 __base = _M_buf.size(); 180 181 if (__builtin_add_overflow(__base, __off, &__off)) 182 return __ret; 183 184 if (__off < 0 || __off > _M_buf.size()) 185 return __ret; 186 187 if (__which & ios_base::in) 188 this->setg(this->eback(), this->eback() + __off, this->egptr()); 189 190 if (__which & ios_base::out) 191 { 192 this->setp(this->pbase(), this->epptr()); 193 this->pbump(__off); 194 } 195 196 __ret = pos_type(__off); 197 198 } 199 return __ret; 200 } 201 202 pos_type 203 seekpos(pos_type __sp, 204 ios_base::openmode __which = ios_base::in | ios_base::out) override 205 { return seekoff(off_type(__sp), ios_base::beg, __which); } 206 207 private: 208 209 ios_base::openmode _M_mode; 210 std::span<_CharT> _M_buf; 211 }; 212 213template<typename _CharT, typename _Traits> 214 inline void 215 swap(basic_spanbuf<_CharT, _Traits>& __x, 216 basic_spanbuf<_CharT, _Traits>& __y) 217 { __x.swap(__y); } 218 219using spanbuf = basic_spanbuf<char>; 220using wspanbuf = basic_spanbuf<wchar_t>; 221 222template<typename _CharT, typename _Traits> 223 class basic_ispanstream 224 : public basic_istream<_CharT, _Traits> 225 { 226 using __istream_type = basic_istream<_CharT, _Traits>; 227 228 public: 229 using char_type = _CharT; 230 using int_type = typename _Traits::int_type; 231 using pos_type = typename _Traits::pos_type; 232 using off_type = typename _Traits::off_type; 233 using traits_type = _Traits; 234 235 // [ispanstream.ctor], constructors 236 explicit 237 basic_ispanstream(std::span<_CharT> __s, 238 ios_base::openmode __which = ios_base::in) 239 : __istream_type(std::__addressof(_M_sb)), 240 _M_sb(__s, __which | ios_base::in) 241 { } 242 243 basic_ispanstream(const basic_ispanstream&) = delete; 244 245 basic_ispanstream(basic_ispanstream&& __rhs) 246 : __istream_type(std::move(__rhs)), _M_sb(std::move(__rhs._M_sb)) 247 { 248 __istream_type::set_rdbuf(std::addressof(_M_sb)); 249 } 250 251 template<typename _Ros> 252 requires ranges::borrowed_range<_Ros> 253 && (!convertible_to<_Ros, std::span<_CharT>>) 254 && convertible_to<_Ros, std::span<const _CharT>> 255 explicit 256 basic_ispanstream(_Ros&& __s) 257 : __istream_type(std::__addressof(_M_sb)), 258 _M_sb(ios_base::in) 259 { 260 std::span<const _CharT> __sp(std::forward<_Ros>(__s)); 261 _M_sb.span({const_cast<_CharT*>(__sp.data()), __sp.size()}); 262 } 263 264 // [ispanstream.assign], assignment and swap 265 basic_ispanstream& operator=(const basic_ispanstream&) = delete; 266 basic_ispanstream& operator=(basic_ispanstream&& __rhs) = default; 267 268 void 269 swap(basic_ispanstream& __rhs) 270 { 271 __istream_type::swap(__rhs); 272 _M_sb.swap(__rhs._M_sb); 273 } 274 275 // [ispanstream.members], member functions 276 basic_spanbuf<_CharT, _Traits>* 277 rdbuf() const noexcept 278 { 279 return const_cast<basic_spanbuf<_CharT, _Traits>*>(std::__addressof(_M_sb)); 280 } 281 282 std::span<const _CharT> 283 span() const noexcept 284 { return _M_sb.span(); } 285 286 void 287 span(std::span<_CharT> __s) noexcept 288 { return _M_sb.span(__s); } 289 290 template<typename _Ros> 291 requires ranges::borrowed_range<_Ros> 292 && (!convertible_to<_Ros, std::span<_CharT>>) 293 && convertible_to<_Ros, std::span<const _CharT>> 294 void 295 span(_Ros&& __s) noexcept 296 { 297 std::span<const _CharT> __sp(std::forward<_Ros>(__s)); 298 _M_sb.span({const_cast<_CharT*>(__sp.data()), __sp.size()}); 299 } 300 301 private: 302 basic_spanbuf<_CharT, _Traits> _M_sb; 303 }; 304 305template<typename _CharT, typename _Traits> 306 inline void 307 swap(basic_ispanstream<_CharT, _Traits>& __x, 308 basic_ispanstream<_CharT, _Traits>& __y) 309 { __x.swap(__y); } 310 311using ispanstream = basic_ispanstream<char>; 312using wispanstream = basic_ispanstream<wchar_t>; 313 314template<typename _CharT, typename _Traits> 315 class basic_ospanstream 316 : public basic_ostream<_CharT, _Traits> 317 { 318 using __ostream_type = basic_ostream<_CharT, _Traits>; 319 320 public: 321 using char_type = _CharT; 322 using int_type = typename _Traits::int_type; 323 using pos_type = typename _Traits::pos_type; 324 using off_type = typename _Traits::off_type; 325 using traits_type = _Traits; 326 327 // [ospanstream.ctor], constructors 328 explicit 329 basic_ospanstream(std::span<_CharT> __s, 330 ios_base::openmode __which = ios_base::out) 331 : __ostream_type(std::__addressof(_M_sb)), 332 _M_sb(__s, __which | ios_base::in) 333 { } 334 335 basic_ospanstream(const basic_ospanstream&) = delete; 336 337 basic_ospanstream(basic_ospanstream&& __rhs) 338 : __ostream_type(std::move(__rhs)), _M_sb(std::move(__rhs._M_sb)) 339 { 340 __ostream_type::set_rdbuf(std::addressof(_M_sb)); 341 } 342 343 // [ospanstream.assign], assignment and swap 344 basic_ospanstream& operator=(const basic_ospanstream&) = delete; 345 basic_ospanstream& operator=(basic_ospanstream&& __rhs) = default; 346 347 void 348 swap(basic_ospanstream& __rhs) 349 { 350 __ostream_type::swap(__rhs); 351 _M_sb.swap(__rhs._M_sb); 352 } 353 354 // [ospanstream.members], member functions 355 basic_spanbuf<_CharT, _Traits>* 356 rdbuf() const noexcept 357 { 358 return const_cast<basic_spanbuf<_CharT, _Traits>*>(std::__addressof(_M_sb)); 359 } 360 361 std::span<_CharT> 362 span() const noexcept 363 { return _M_sb.span(); } 364 365 void 366 span(std::span<_CharT> __s) noexcept 367 { return _M_sb.span(__s); } 368 369 private: 370 basic_spanbuf<_CharT, _Traits> _M_sb; 371 }; 372 373template<typename _CharT, typename _Traits> 374 inline void 375 swap(basic_ospanstream<_CharT, _Traits>& __x, 376 basic_ospanstream<_CharT, _Traits>& __y) 377 { __x.swap(__y); } 378 379using ospanstream = basic_ospanstream<char>; 380using wospanstream = basic_ospanstream<wchar_t>; 381 382template<typename _CharT, typename _Traits> 383 class basic_spanstream 384 : public basic_iostream<_CharT, _Traits> 385 { 386 using __iostream_type = basic_iostream<_CharT, _Traits>; 387 388 public: 389 using char_type = _CharT; 390 using int_type = typename _Traits::int_type; 391 using pos_type = typename _Traits::pos_type; 392 using off_type = typename _Traits::off_type; 393 using traits_type = _Traits; 394 395 // [spanstream.ctor], constructors 396 explicit 397 basic_spanstream(std::span<_CharT> __s, 398 ios_base::openmode __which = ios_base::out | ios_base::in) 399 : __iostream_type(std::__addressof(_M_sb)), 400 _M_sb(__s, __which) 401 { } 402 403 basic_spanstream(const basic_spanstream&) = delete; 404 405 basic_spanstream(basic_spanstream&& __rhs) 406 : __iostream_type(std::move(__rhs)), _M_sb(std::move(__rhs._M_sb)) 407 { 408 __iostream_type::set_rdbuf(std::addressof(_M_sb)); 409 } 410 411 // [spanstream.assign], assignment and swap 412 basic_spanstream& operator=(const basic_spanstream&) = delete; 413 basic_spanstream& operator=(basic_spanstream&& __rhs) = default; 414 415 void 416 swap(basic_spanstream& __rhs) 417 { 418 __iostream_type::swap(__rhs); 419 _M_sb.swap(__rhs._M_sb); 420 } 421 422 // [spanstream.members], members 423 basic_spanbuf<_CharT, _Traits>* 424 rdbuf() const noexcept 425 { 426 return const_cast<basic_spanbuf<_CharT, _Traits>*>(std::__addressof(_M_sb)); 427 } 428 429 std::span<_CharT> 430 span() const noexcept 431 { return _M_sb.span(); } 432 433 void 434 span(std::span<_CharT> __s) noexcept 435 { return _M_sb.span(__s); } 436 437 private: 438 basic_spanbuf<_CharT, _Traits> _M_sb; 439 }; 440 441template<typename _CharT, typename _Traits> 442 inline void 443 swap(basic_spanstream<_CharT, _Traits>& __x, 444 basic_spanstream<_CharT, _Traits>& __y) 445 { __x.swap(__y); } 446 447using spanstream = basic_spanstream<char>; 448using wspanstream = basic_spanstream<wchar_t>; 449 450_GLIBCXX_END_NAMESPACE_VERSION 451} // namespace std 452#endif // __cpp_lib_span 453#endif // C++23 454#endif // _GLIBCXX_SPANSTREAM 455