Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP - [libc++][spanstream] P0448R4: A strstream replacement using span<charT> as buffer #83541

Draft
wants to merge 86 commits into
base: main
Choose a base branch
from

Conversation

@Zingam Zingam added the libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi. label Mar 1, 2024
@llvmbot
Copy link
Collaborator

llvmbot commented Mar 1, 2024

@llvm/pr-subscribers-libcxx

Author: Hristo Hristov (H-G-Hristov)

Changes

Implements: P0448R https://wg21.link/P0448R4


Patch is 84.49 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/83541.diff

38 Files Affected:

  • (modified) libcxx/docs/FeatureTestMacroTable.rst (+1-1)
  • (modified) libcxx/docs/ReleaseNotes/19.rst (+1)
  • (modified) libcxx/docs/Status/Cxx23Papers.csv (+1-1)
  • (modified) libcxx/include/CMakeLists.txt (+2)
  • (added) libcxx/include/__fwd/spanstream.h (+48)
  • (modified) libcxx/include/__std_clang_module (+3)
  • (modified) libcxx/include/iosfwd (+20)
  • (modified) libcxx/include/libcxx.imp (+1)
  • (modified) libcxx/include/module.modulemap.in (+12-7)
  • (added) libcxx/include/spanstream (+435)
  • (modified) libcxx/include/version (+1-1)
  • (modified) libcxx/modules/std.compat.cppm.in (-3)
  • (modified) libcxx/modules/std.cppm.in (+3-3)
  • (added) libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/move.pass.cpp (+81)
  • (added) libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/ros.pass.cpp (+60)
  • (added) libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/span.mode.pass.cpp (+136)
  • (added) libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.general/lit.local.cfg (+3)
  • (added) libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.general/nothing_to_do.pass.cpp (+15)
  • (added) libcxx/test/std/input.output/span.streams/ispanstream/types.compile.pass.cpp (+79)
  • (added) libcxx/test/std/input.output/span.streams/macros.h (+18)
  • (added) libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.general/lit.local.cfg (+3)
  • (added) libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.general/nothing_to_do.pass.cpp (+15)
  • (added) libcxx/test/std/input.output/span.streams/ospanstream/types.compile.pass.cpp (+79)
  • (added) libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/default.pass.cpp (+46)
  • (added) libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/mode.pass.cpp (+101)
  • (added) libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/move.pass.cpp (+242)
  • (added) libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/span.mode.pass.cpp (+187)
  • (added) libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.general/lit.local.cfg (+3)
  • (added) libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.general/nothing_to_do.pass.cpp (+15)
  • (added) libcxx/test/std/input.output/span.streams/spanbuf/types.compile.pass.cpp (+79)
  • (added) libcxx/test/std/input.output/span.streams/spanstream/spanstream.general/lit.local.cfg (+3)
  • (added) libcxx/test/std/input.output/span.streams/spanstream/spanstream.general/nothing_to_do.pass.cpp (+15)
  • (added) libcxx/test/std/input.output/span.streams/spanstream/types.compile.pass.cpp (+79)
  • (added) libcxx/test/std/input.output/span.streams/types.h (+73)
  • (added) libcxx/test/std/language.support/support.limits/support.limits.general/spanstream.version.compile.pass.cpp (+68)
  • (modified) libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp (+10-22)
  • (modified) libcxx/utils/generate_feature_test_macro_components.py (-1)
  • (modified) libcxx/utils/libcxx/header_information.py (+2-1)
diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst
index 468226c0c2dddf..1c39df01b3f0ee 100644
--- a/libcxx/docs/FeatureTestMacroTable.rst
+++ b/libcxx/docs/FeatureTestMacroTable.rst
@@ -370,7 +370,7 @@ Status
     --------------------------------------------------- -----------------
     ``__cpp_lib_reference_from_temporary``              *unimplemented*
     --------------------------------------------------- -----------------
-    ``__cpp_lib_spanstream``                            *unimplemented*
+    ``__cpp_lib_spanstream``                            ``202106L``
     --------------------------------------------------- -----------------
     ``__cpp_lib_stacktrace``                            *unimplemented*
     --------------------------------------------------- -----------------
diff --git a/libcxx/docs/ReleaseNotes/19.rst b/libcxx/docs/ReleaseNotes/19.rst
index 78c6bb87a5a402..536960b4681298 100644
--- a/libcxx/docs/ReleaseNotes/19.rst
+++ b/libcxx/docs/ReleaseNotes/19.rst
@@ -41,6 +41,7 @@ Implemented Papers
 - P2637R3 - Member ``visit``
 - P2652R2 - Disallow User Specialization of ``allocator_traits``
 - P2819R2 - Add ``tuple`` protocol to ``complex``
+- P0448R4 - A ``strstream`` replacement using ``span<charT>`` as buffer
 
 
 Improvements and New Features
diff --git a/libcxx/docs/Status/Cxx23Papers.csv b/libcxx/docs/Status/Cxx23Papers.csv
index eb415ed8c031fa..084c101ece9392 100644
--- a/libcxx/docs/Status/Cxx23Papers.csv
+++ b/libcxx/docs/Status/Cxx23Papers.csv
@@ -12,7 +12,7 @@
 "`P2259R1 <https://wg21.link/P2259R1>`__","LWG","Repairing input range adaptors and counted_iterator","February 2021","","","|ranges|"
 "","","","","","",""
 "`P0401R6 <https://wg21.link/P0401R6>`__","LWG","Providing size feedback in the Allocator interface","June 2021","|Complete|","15.0"
-"`P0448R4 <https://wg21.link/P0448R4>`__","LWG","A strstream replacement using span<charT> as buffer","June 2021","",""
+"`P0448R4 <https://wg21.link/P0448R4>`__","LWG","A ``strstream`` replacement using ``span<charT>`` as buffer","June 2021","|Partial|","19.0"
 "`P1132R8 <https://wg21.link/P1132R8>`__","LWG","out_ptr - a scalable output pointer abstraction","June 2021","",""
 "`P1328R1 <https://wg21.link/P1328R1>`__","LWG","Making std::type_info::operator== constexpr","June 2021","|Complete|","17.0"
 "`P1425R4 <https://wg21.link/P1425R4>`__","LWG","Iterators pair constructors for stack and queue","June 2021","|Complete|","14.0","|ranges|"
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index cafd8c6e00d968..024d4e0a6f523d 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -439,6 +439,7 @@ set(files
   __fwd/ostream.h
   __fwd/pair.h
   __fwd/span.h
+  __fwd/spanstream.h
   __fwd/sstream.h
   __fwd/streambuf.h
   __fwd/string.h
@@ -986,6 +987,7 @@ set(files
   shared_mutex
   source_location
   span
+  spanstream
   sstream
   stack
   stdatomic.h
diff --git a/libcxx/include/__fwd/spanstream.h b/libcxx/include/__fwd/spanstream.h
new file mode 100644
index 00000000000000..f5ff2ad2c9cfc6
--- /dev/null
+++ b/libcxx/include/__fwd/spanstream.h
@@ -0,0 +1,48 @@
+//===----------------------------------------------------------------------===//
+//
+// 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___FWD_SPANSTREAM_H
+#define _LIBCPP___FWD_SPANSTREAM_H
+
+#include <__config>
+#include <__fwd/string.h>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+#if _LIBCPP_STD_VER >= 23
+
+template <class _CharT, class _Traits = char_traits<_CharT>>
+class _LIBCPP_TEMPLATE_VIS basic_spanbuf;
+template <class _CharT, class _Traits = char_traits<_CharT>>
+class _LIBCPP_TEMPLATE_VIS basic_ispanstream;
+template <class _CharT, class _Traits = char_traits<_CharT>>
+class _LIBCPP_TEMPLATE_VIS basic_ospanstream;
+template <class _CharT, class _Traits = char_traits<_CharT>>
+class _LIBCPP_TEMPLATE_VIS basic_spanstream;
+
+using spanbuf     = basic_spanbuf<char>;
+using ispanstream = basic_ispanstream<char>;
+using ospanstream = basic_ospanstream<char>;
+using spanstream  = basic_spanstream<char>;
+
+#  ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+using wspanbuf     = basic_spanbuf<wchar_t>;
+using wispanstream = basic_ispanstream<wchar_t>;
+using wospanstream = basic_ospanstream<wchar_t>;
+using wspanstream  = basic_spanstream<wchar_t>;
+#  endif
+
+#endif // _LIBCPP_STD_VER >= 23
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___FWD_SPANSTREAM_H
diff --git a/libcxx/include/__std_clang_module b/libcxx/include/__std_clang_module
index 18d6ce6b46c1f6..f7cefc697c316f 100644
--- a/libcxx/include/__std_clang_module
+++ b/libcxx/include/__std_clang_module
@@ -163,6 +163,9 @@
 #include <source_location>
 #include <span>
 #if !defined(_LIBCPP_HAS_NO_LOCALIZATION)
+#  include <spanstream>
+#endif
+#if !defined(_LIBCPP_HAS_NO_LOCALIZATION)
 #  include <sstream>
 #endif
 #include <stack>
diff --git a/libcxx/include/iosfwd b/libcxx/include/iosfwd
index e28998d004156d..c760284f0dee88 100644
--- a/libcxx/include/iosfwd
+++ b/libcxx/include/iosfwd
@@ -42,6 +42,15 @@ template <class charT, class traits = char_traits<charT>, class Allocator = allo
 template <class charT, class traits = char_traits<charT>, class Allocator = allocator<charT> >
     class basic_stringstream;
 
+  template<class charT, class traits = char_traits<charT>>
+    class basic_spanbuf;                                                             // Since C++23
+  template<class charT, class traits = char_traits<charT>>
+    class basic_ispanstream;                                                         // Since C++23
+  template<class charT, class traits = char_traits<charT>>
+    class basic_ospanstream;                                                         // Since C++23
+  template<class charT, class traits = char_traits<charT>>
+    class basic_spanstream;                                                          // Since C++23
+
 template <class charT, class traits = char_traits<charT> > class basic_filebuf;
 template <class charT, class traits = char_traits<charT> > class basic_ifstream;
 template <class charT, class traits = char_traits<charT> > class basic_ofstream;
@@ -63,6 +72,11 @@ typedef basic_istringstream<char>    istringstream;
 typedef basic_ostringstream<char>    ostringstream;
 typedef basic_stringstream<char>     stringstream;
 
+using spanbuf     = basic_spanbuf<char>;                                             // Since C++23
+using ispanstream = basic_ispanstream<char>;                                         // Since C++23
+using ospanstream = basic_ospanstream<char>;                                         // Since C++23
+using spanstream  = basic_spanstream<char>;                                          // Since C++23
+
 typedef basic_filebuf<char>          filebuf;
 typedef basic_ifstream<char>         ifstream;
 typedef basic_ofstream<char>         ofstream;
@@ -78,6 +92,11 @@ typedef basic_istringstream<wchar_t> wistringstream;
 typedef basic_ostringstream<wchar_t> wostringstream;
 typedef basic_stringstream<wchar_t>  wstringstream;
 
+using wspanbuf     = basic_spanbuf<wchar_t>;                                         // Since C++23
+using wispanstream = basic_ispanstream<wchar_t>;                                     // Since C++23
+using wospanstream = basic_ospanstream<wchar_t>;                                     // Since C++23
+using wspanstream  = basic_spanstream<wchar_t>;                                      // Since C++23
+
 typedef basic_filebuf<wchar_t>       wfilebuf;
 typedef basic_ifstream<wchar_t>      wifstream;
 typedef basic_ofstream<wchar_t>      wofstream;
@@ -112,6 +131,7 @@ using wosyncstream = basic_osyncstream<wchar_t>;  // C++20
 #include <__fwd/ios.h>
 #include <__fwd/istream.h>
 #include <__fwd/ostream.h>
+#include <__fwd/spanstream.h>
 #include <__fwd/sstream.h>
 #include <__fwd/streambuf.h>
 #include <__fwd/string.h>
diff --git a/libcxx/include/libcxx.imp b/libcxx/include/libcxx.imp
index 22fbea99b848bb..c25f0bbd215031 100644
--- a/libcxx/include/libcxx.imp
+++ b/libcxx/include/libcxx.imp
@@ -434,6 +434,7 @@
   { include: [ "<__fwd/ostream.h>", "private", "<ostream>", "public" ] },
   { include: [ "<__fwd/pair.h>", "private", "<utility>", "public" ] },
   { include: [ "<__fwd/span.h>", "private", "<span>", "public" ] },
+  { include: [ "<__fwd/spanstream.h>", "private", "<spanstream>", "public" ] },
   { include: [ "<__fwd/sstream.h>", "private", "<sstream>", "public" ] },
   { include: [ "<__fwd/streambuf.h>", "private", "<streambuf>", "public" ] },
   { include: [ "<__fwd/string.h>", "private", "<string>", "public" ] },
diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index 219906aa9a5668..00d877960a4cc4 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -233,6 +233,10 @@ module std_span [system] {
   export std_version
   export std_private_span_span_fwd
 }
+module std_spanstream [system] {
+  header "spanstream"
+  export *
+}
 module std_sstream [system] {
   header "sstream"
   export *
@@ -1388,14 +1392,15 @@ module std_private_functional_unary_function             [system] { header "__fu
 module std_private_functional_unary_negate               [system] { header "__functional/unary_negate.h" }
 module std_private_functional_weak_result_type           [system] { header "__functional/weak_result_type.h" }
 
-module std_private_ios_fpos [system] { header "__ios/fpos.h" }
+module std_private_ios_fpos                         [system] { header "__ios/fpos.h" }
 
-module std_private_iosfwd_fstream_fwd   [system] { header "__fwd/fstream.h" }
-module std_private_iosfwd_ios_fwd       [system] { header "__fwd/ios.h" }
-module std_private_iosfwd_istream_fwd   [system] { header "__fwd/istream.h" }
-module std_private_iosfwd_ostream_fwd   [system] { header "__fwd/ostream.h" }
-module std_private_iosfwd_sstream_fwd   [system] { header "__fwd/sstream.h" }
-module std_private_iosfwd_streambuf_fwd [system] { header "__fwd/streambuf.h" }
+module std_private_iosfwd_fstream_fwd               [system] { header "__fwd/fstream.h" }
+module std_private_iosfwd_ios_fwd                   [system] { header "__fwd/ios.h" }
+module std_private_iosfwd_istream_fwd               [system] { header "__fwd/istream.h" }
+module std_private_iosfwd_ostream_fwd               [system] { header "__fwd/ostream.h" }
+module std_private_iosfwd_spanstream_fwd            [system] { header "__fwd/spanstream.h" }
+module std_private_iosfwd_sstream_fwd               [system] { header "__fwd/sstream.h" }
+module std_private_iosfwd_streambuf_fwd             [system] { header "__fwd/streambuf.h" }
 
 module std_private_iterator_access                  [system] { header "__iterator/access.h" }
 module std_private_iterator_advance                 [system] { header "__iterator/advance.h" }
diff --git a/libcxx/include/spanstream b/libcxx/include/spanstream
new file mode 100644
index 00000000000000..16bbf04d81c559
--- /dev/null
+++ b/libcxx/include/spanstream
@@ -0,0 +1,435 @@
+// -*- 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_SPANSTREAM
+#define _LIBCPP_SPANSTREAM
+
+// clang-format off
+
+/*
+  Span-based streams [span.streams]
+
+  template<class charT, class traits = char_traits<charT>>
+    class basic_spanbuf;
+
+  template<class charT, class traits>
+    void swap(basic_spanbuf<charT, traits>& x, basic_spanbuf<charT, traits>& y);
+
+  using spanbuf = basic_spanbuf<char>;
+  using wspanbuf = basic_spanbuf<wchar_t>;
+
+  template<class charT, class traits = char_traits<charT>>
+    class basic_ispanstream;
+
+  template<class charT, class traits>
+    void swap(basic_ispanstream<charT, traits>& x, basic_ispanstream<charT, traits>& y);
+
+  using ispanstream = basic_ispanstream<char>;
+  using wispanstream = basic_ispanstream<wchar_t>;
+
+  template<class charT, class traits = char_traits<charT>>
+    class basic_ospanstream;
+
+  template<class charT, class traits>
+    void swap(basic_ospanstream<charT, traits>& x, basic_ospanstream<charT, traits>& y);
+
+  using ospanstream = basic_ospanstream<char>;
+  using wospanstream = basic_ospanstream<wchar_t>;
+
+  template<class charT, class traits = char_traits<charT>>
+    class basic_spanstream;
+
+  template<class charT, class traits>
+    void swap(basic_spanstream<charT, traits>& x, basic_spanstream<charT, traits>& y);
+
+  using spanstream = basic_spanstream<char>;
+  using wspanstream = basic_spanstream<wchar_t>;
+*/
+
+// clang-format on
+
+#include <__assert> // all public C++ headers provide the assertion handler
+#include <__availability>
+#include <__config>
+#include <__fwd/spanstream.h>
+#include <__memory/addressof.h>
+#include <__ranges/concepts.h>
+#include <__utility/cmp.h>
+#include <__utility/forward.h>
+#include <__utility/move.h>
+#include <__utility/swap.h>
+#include <iostream>
+#include <span>
+#include <streambuf>
+#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
+
+#if _LIBCPP_STD_VER >= 23
+
+// Class template basic_spanbuf [spanbuf]
+
+template <class _CharT, class _Traits>
+class _LIBCPP_TEMPLATE_VIS basic_spanbuf : public basic_streambuf<_CharT, _Traits> {
+public:
+  using char_type   = _CharT;
+  using int_type    = typename _Traits::int_type;
+  using pos_type    = typename _Traits::pos_type;
+  using off_type    = typename _Traits::off_type;
+  using traits_type = _Traits;
+
+  // [spanbuf.cons], constructors
+
+  _LIBCPP_HIDE_FROM_ABI basic_spanbuf() : basic_spanbuf(ios_base::in | ios_base::out) {}
+
+  _LIBCPP_HIDE_FROM_ABI explicit basic_spanbuf(ios_base::openmode __which)
+      : basic_spanbuf(std::span<_CharT>(), __which) {}
+
+  _LIBCPP_HIDE_FROM_ABI explicit basic_spanbuf(std::span<_CharT> __s,
+                                               ios_base::openmode __which = ios_base::in | ios_base::out)
+      : basic_streambuf<_CharT, _Traits>{}, __mode_{__which}, __buf_{__s} {
+    this->span(__s);
+  }
+
+  basic_spanbuf(const basic_spanbuf&) = delete;
+
+  _LIBCPP_HIDE_FROM_ABI basic_spanbuf(basic_spanbuf&& __rhs)
+      : basic_streambuf<_CharT, _Traits>{std::move(__rhs)},
+        __mode_{std::move(__rhs.__mode_)},
+        __buf_{std::move(__rhs.__buf_)} {}
+
+  // [spanbuf.assign], assignment and swap
+
+  basic_spanbuf& operator=(const basic_spanbuf&) = delete;
+
+  _LIBCPP_HIDE_FROM_ABI basic_spanbuf& operator=(basic_spanbuf&& __rhs) {
+    basic_spanbuf __tmp{std::move(__rhs)};
+    this->swap(__tmp);
+    return *this;
+  }
+
+  _LIBCPP_HIDE_FROM_ABI void swap(basic_spanbuf& __rhs) {
+    basic_streambuf<_CharT, _Traits>::swap(__rhs);
+    std::swap(__mode_, __rhs.__mode_);
+    std::swap(__buf_, __rhs.__buf_);
+  }
+
+  // [spanbuf.members], member functions
+
+  _LIBCPP_HIDE_FROM_ABI std::span<_CharT> span() const noexcept {
+    if (__mode_ & ios_base::out) {
+      return std::span<_CharT>(this->pbase(), this->pptr());
+    }
+    return __buf_;
+  }
+
+  _LIBCPP_HIDE_FROM_ABI void span(std::span<_CharT> __s) noexcept {
+    __buf_ = __s;
+
+    if (__mode_ & ios_base::out) {
+      this->setp(__s.data(), __s.data() + __s.size());
+      if (__mode_ & ios_base::ate) {
+        this->pbump(__s.size());
+      }
+    }
+
+    if (__mode_ & ios_base::in) {
+      this->setg(__s.data(), __s.data(), __s.data() + __s.size());
+    }
+  }
+
+protected:
+  // [spanbuf.virtuals], overridden virtual functions
+
+  _LIBCPP_HIDE_FROM_ABI basic_streambuf<_CharT, _Traits>* setbuf(_CharT* __s, streamsize __n) override {
+    this->span(std::span<_CharT>(__s, __n));
+    return this;
+  }
+
+  _LIBCPP_HIDE_FROM_ABI pos_type
+  seekoff(off_type __off, ios_base::seekdir __way, ios_base::openmode __which = ios_base::in | ios_base::out) override {
+    const pos_type __error(off_type(-1));
+
+    if ((__which & ios_base::in) && (__which & ios_base::out) && (ios_base::cur == __way))
+      return __error;
+
+    off_type __baseoff = [this, __way, __which] {
+      switch (__way) {
+      case ios_base::beg:
+        return off_type(0);
+
+      case ios_base::cur:
+        if (__which & ios_base::out)
+          return off_type(this->pptr() - this->pbase());
+        return off_type(this->gptr() - this->eback());
+
+      case ios_base::end:
+        if ((__which & ios_base::out) && !(__which & ios_base::in))
+          return off_type(this->pptr() - this->pbase());
+        return off_type(__buf_.size());
+      }
+    }();
+
+    off_type __newoff;
+    if (__builtin_add_overflow(__baseoff, __off, &__newoff) || (__newoff < off_type(0)) ||
+        (std::cmp_greater(__newoff, __buf_.size())))
+      return __error;
+
+    if (__which & ios_base::in) {
+      if ((this->gptr() == nullptr) && (__newoff != off_type(0)))
+        return __error;
+      this->setg(this->eback(), this->eback() + __newoff, this->egptr());
+    }
+
+    if (__which & ios_base::out) {
+      if ((this->pptr() == nullptr) && (__newoff != off_type(0)))
+        return __error;
+      this->setp(this->pbase(), this->epptr());
+      this->pbump(__newoff);
+    }
+
+    return pos_type(__newoff);
+  }
+
+  _LIBCPP_HIDE_FROM_ABI pos_type seekpos(pos_type __sp,
+                                         ios_base::openmode __which = ios_base::in | ios_base::out) override {
+    return seekoff(off_type(__sp), ios_base::beg, __which);
+  }
+
+private:
+  ios_base::openmode __mode_; // exposition only
+  std::span<_CharT> __buf_;   // exposition only
+};
+
+template <class _CharT, class _Traits>
+_LIBCPP_HIDE_FROM_ABI void swap(basic_spanbuf<_CharT, _Traits>& __x, basic_spanbuf<_CharT, _Traits>& __y) {
+  __x.swap(__y);
+}
+
+using std::spanbuf;
+#  ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+using std::wspanbuf;
+#  endif
+
+// Class template basic_ispanstream [ispanstream]
+
+template <class _CharT, class _Traits>
+class _LIBCPP_TEMPLATE_VIS basic_ispanstream : public basic_istream<_CharT, _Traits> {
+public:
+  using char_type   = _CharT;
+  using int_type    = typename _Traits::int_type;
+  using pos_type    = typename _Traits::pos_type;
+  using off_type    = typename _Traits::off_type;
+  using traits_type = _Traits;
+
+  // [ispanstream.cons], constructors
+
+  _LIBCPP_HIDE_FROM_ABI explicit basic_ispanstream(std::span<_CharT> __s, ios_base::openmode __which = ios_base::in)
+      : basic_istream<_CharT, _Traits>(std::addressof(__sb_)),
+        __sb_(basic_spanbuf<_CharT, _Traits>(__s, __which | ios_base::in)) {}
+
+  basic_ispanstream(const basic_ispanstream&) = delete;
+
+  _LIBCPP_HIDE_FROM_ABI basic_ispanstream(basic_ispanstream&& __rhs)
+      : basic_istream<_CharT, _Traits>(std::move(__rhs)), __sb_(std::move(__rhs.__sb_)) {
+    basic_istream<_CharT, _Traits>::set_rdbuf(std::addressof(__sb_));
+  }
+
+  template <ranges::borrowed_range _ROSeq>
+    requires(!convertible_to<_ROSeq, std::span<_CharT>>) && convertible_to<_ROSeq, std::span<const _CharT>>
+  _LIBCPP_HIDE_FROM_ABI explicit basic_ispanstream(_ROSeq&& __s)
+      : basic_istream<_CharT, _Traits>(std::addressof(__sb_)) {
+    std::span<const _CharT> __sp(std::forward<_ROSeq>(__s));
+    this->span(std::span<_CharT>(std::span<_CharT>(const_cast<_CharT*>(__sp.data()), __sp.size())));
+  }
+
+  basic_ispanstream& operator=(const basic_ispanstream&) = delete;
+
+  _LIBCPP_HIDE_FROM_ABI basic_ispanstream& operator=(basic_ispanstream&& __rhs) {
+    basic_ispanstream __tmp{std::move(__rhs)};
+    this->swap(__tmp);
+    return *this;
+  }
+
+  // [ispanstream.swap], swap
+
+  _LIBCPP_HIDE_FROM_ABI void swap(basic_ispanstream& __rhs) {
+    basic_istream<_CharT, _Traits>::swap(__rhs);
+    __sb_.swap(__rhs.__sb_);
+  }
+
+  // [ispanstream.members], member functions
+
+  _LIBCPP...
[truncated]

@H-G-Hristov H-G-Hristov force-pushed the hgh/libcxx/P0448R4-spanstream-A-strstream-replacement-using-span-charT-as-buffer branch from 8b95319 to ebd7cc2 Compare March 1, 2024 08:52
Copy link

github-actions bot commented Mar 1, 2024

✅ With the latest revision this PR passed the Python code formatter.

@H-G-Hristov H-G-Hristov force-pushed the hgh/libcxx/P0448R4-spanstream-A-strstream-replacement-using-span-charT-as-buffer branch 6 times, most recently from 23c95e8 to 1aec5c1 Compare March 5, 2024 15:25
Copy link

github-actions bot commented Mar 5, 2024

✅ With the latest revision this PR passed the C/C++ code formatter.

@H-G-Hristov H-G-Hristov force-pushed the hgh/libcxx/P0448R4-spanstream-A-strstream-replacement-using-span-charT-as-buffer branch 2 times, most recently from b17f653 to b078864 Compare March 11, 2024 06:48
Comment on lines 112 to 116
_LIBCPP_HIDE_FROM_ABI basic_spanbuf(basic_spanbuf&& __rhs)
: basic_streambuf<_CharT, _Traits>{std::move(__rhs)},
__mode_{std::move(__rhs.__mode_)},
__buf_{std::move(__rhs.__buf_)} {}
// __buf_{std::exchange(__rhs.__buf_, {})} {}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alternative implementation with std::exchange, which sets an empty span (data() == nullptr):

Suggested change
_LIBCPP_HIDE_FROM_ABI basic_spanbuf(basic_spanbuf&& __rhs)
: basic_streambuf<_CharT, _Traits>{std::move(__rhs)},
__mode_{std::move(__rhs.__mode_)},
__buf_{std::move(__rhs.__buf_)} {}
// __buf_{std::exchange(__rhs.__buf_, {})} {}
_LIBCPP_HIDE_FROM_ABI basic_spanbuf(basic_spanbuf&& __rhs)
: basic_streambuf<_CharT, _Traits>{std::move(__rhs)},
__mode_{std::move(__rhs.__mode_)},
__buf_{std::exchange(__rhs.__buf_, {})} {}

@H-G-Hristov H-G-Hristov force-pushed the hgh/libcxx/P0448R4-spanstream-A-strstream-replacement-using-span-charT-as-buffer branch 6 times, most recently from ebc2a90 to 72b462d Compare March 17, 2024 12:10
@H-G-Hristov H-G-Hristov force-pushed the hgh/libcxx/P0448R4-spanstream-A-strstream-replacement-using-span-charT-as-buffer branch from 72b462d to 37e3bcd Compare July 19, 2024 16:08
@H-G-Hristov H-G-Hristov force-pushed the hgh/libcxx/P0448R4-spanstream-A-strstream-replacement-using-span-charT-as-buffer branch from 04fa4d4 to dd2bae6 Compare July 29, 2024 16:10
@Zingam Zingam linked an issue Aug 21, 2024 that may be closed by this pull request
@H-G-Hristov H-G-Hristov force-pushed the hgh/libcxx/P0448R4-spanstream-A-strstream-replacement-using-span-charT-as-buffer branch 6 times, most recently from 3a123c2 to 44a3e5c Compare October 12, 2024 17:35
@H-G-Hristov H-G-Hristov force-pushed the hgh/libcxx/P0448R4-spanstream-A-strstream-replacement-using-span-charT-as-buffer branch from 44a3e5c to e31a530 Compare October 15, 2024 18:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

P0448R4: A strstream replacement using span<charT> as buffer
3 participants