[libcxx-commits] [libcxx] WIP - [libc++][spanstream] P0448R4: A `strstream` replacement using `span<charT>` as buffer (PR #83541)

Hristo Hristov via libcxx-commits libcxx-commits at lists.llvm.org
Fri Jul 19 09:16:30 PDT 2024


https://github.com/H-G-Hristov updated https://github.com/llvm/llvm-project/pull/83541

>From 51402f0343967e7b183c092a877e2b970fbff15a Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Tue, 27 Feb 2024 08:51:49 +0200
Subject: [PATCH 01/56] [libc++][spanstream] P0448R4: A `strstream` replacement
 using `span<charT>` as buffer

Implements: P0448R https://wg21.link/P0448R4
- https://eel.is/c++draft/span.streams
  - https://eel.is/c++draft/spanbuf
  - https://eel.is/c++draft/ispanstream
  - https://eel.is/c++draft/ospanstream
  - https://eel.is/c++draft/spanstream
---
 libcxx/docs/ReleaseNotes/19.rst               |   3 +-
 libcxx/docs/Status/Cxx23Papers.csv            |   2 +-
 libcxx/include/CMakeLists.txt                 |   1 +
 libcxx/include/__std_clang_module             |   3 +
 libcxx/include/module.modulemap               |   4 +
 libcxx/include/spanstream                     | 428 ++++++++++++++++++
 libcxx/include/version                        |   2 +-
 libcxx/modules/std.compat.cppm.in             |   3 -
 libcxx/modules/std.cppm.in                    |   6 +-
 .../ispanstream.general/lit.local.cfg         |   3 +
 .../nothing_to_do.pass.cpp                    |  15 +
 .../ispanstream/types.compile.pass.cpp        |  79 ++++
 .../ospanstream.general/lit.local.cfg         |   3 +
 .../nothing_to_do.pass.cpp                    |  15 +
 .../ospanstream/types.compile.pass.cpp        |  79 ++++
 .../spanbuf/spanbuf.cons/default.pass.cpp     |  45 ++
 .../spanbuf/spanbuf.general/lit.local.cfg     |   3 +
 .../spanbuf.general/nothing_to_do.pass.cpp    |  15 +
 .../spanbuf/types.compile.pass.cpp            |  79 ++++
 .../spanstream.general/lit.local.cfg          |   3 +
 .../spanstream.general/nothing_to_do.pass.cpp |  15 +
 .../spanstream/types.compile.pass.cpp         |  78 ++++
 .../spanstream.version.compile.pass.cpp       |  68 +++
 .../version.version.compile.pass.cpp          |  32 +-
 .../generate_feature_test_macro_components.py |   1 -
 libcxx/utils/libcxx/header_information.py     |   3 +-
 26 files changed, 955 insertions(+), 33 deletions(-)
 create mode 100644 libcxx/include/spanstream
 create mode 100644 libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.general/lit.local.cfg
 create mode 100644 libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.general/nothing_to_do.pass.cpp
 create mode 100644 libcxx/test/std/input.output/span.streams/ispanstream/types.compile.pass.cpp
 create mode 100644 libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.general/lit.local.cfg
 create mode 100644 libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.general/nothing_to_do.pass.cpp
 create mode 100644 libcxx/test/std/input.output/span.streams/ospanstream/types.compile.pass.cpp
 create mode 100644 libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/default.pass.cpp
 create mode 100644 libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.general/lit.local.cfg
 create mode 100644 libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.general/nothing_to_do.pass.cpp
 create mode 100644 libcxx/test/std/input.output/span.streams/spanbuf/types.compile.pass.cpp
 create mode 100644 libcxx/test/std/input.output/span.streams/spanstream/spanstream.general/lit.local.cfg
 create mode 100644 libcxx/test/std/input.output/span.streams/spanstream/spanstream.general/nothing_to_do.pass.cpp
 create mode 100644 libcxx/test/std/input.output/span.streams/spanstream/types.compile.pass.cpp
 create mode 100644 libcxx/test/std/language.support/support.limits/support.limits.general/spanstream.version.compile.pass.cpp

diff --git a/libcxx/docs/ReleaseNotes/19.rst b/libcxx/docs/ReleaseNotes/19.rst
index 784934eafe9f7..d797f9194ccbc 100644
--- a/libcxx/docs/ReleaseNotes/19.rst
+++ b/libcxx/docs/ReleaseNotes/19.rst
@@ -50,6 +50,7 @@ Implemented Papers
 - P2591R5 - Concatenation of strings and string views
 - P2968R2 - Make ``std::ignore`` a first-class object
 - P2997R1 - Removing the common reference requirement from the indirectly invocable concepts (as DR against C++20)
+- P0448R4 - A ``strstream`` replacement using ``span<charT>`` as buffer
 - P2302R4 - ``std::ranges::contains``
 - P1659R3 - ``std::ranges::starts_with`` and ``std::ranges::ends_with``
 - P3029R1 - Better ``mdspan``'s CTAD
@@ -73,7 +74,7 @@ Improvements and New Features
   up to 100x.
 
 - The ``std::set_intersection`` and ``std::ranges::set_intersection`` algorithms have been optimized to fast-forward over
-  contiguous ranges of non-matching values, reducing the number of comparisons from linear to 
+  contiguous ranges of non-matching values, reducing the number of comparisons from linear to
   logarithmic growth with the number of elements in best-case scenarios.
 
 - The ``_LIBCPP_ENABLE_CXX26_REMOVED_STRSTREAM`` macro has been added to make the declarations in ``<strstream>`` available.
diff --git a/libcxx/docs/Status/Cxx23Papers.csv b/libcxx/docs/Status/Cxx23Papers.csv
index 6dd6bdad07658..217787d65ced3 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","|Complete|","19.0"
 "`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 fa6736dc11e66..47331d61ba067 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -981,6 +981,7 @@ set(files
   shared_mutex
   source_location
   span
+  spanstream
   sstream
   stack
   stdatomic.h
diff --git a/libcxx/include/__std_clang_module b/libcxx/include/__std_clang_module
index 18d6ce6b46c1f..f7cefc697c316 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/module.modulemap b/libcxx/include/module.modulemap
index 43ab9c6987c84..105ea3b8812ff 100644
--- a/libcxx/include/module.modulemap
+++ b/libcxx/include/module.modulemap
@@ -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 *
diff --git a/libcxx/include/spanstream b/libcxx/include/spanstream
new file mode 100644
index 0000000000000..f25a04c2cb525
--- /dev/null
+++ b/libcxx/include/spanstream
@@ -0,0 +1,428 @@
+// -*- 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 <__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 = char_traits<_CharT>>
+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>
+void swap(basic_spanbuf<_CharT, _Traits>& __x, basic_spanbuf<_CharT, _Traits>& __y) {
+  __x.swap(__y);
+}
+
+using spanbuf = basic_spanbuf<char>;
+#  ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+using wspanbuf = basic_spanbuf<wchar_t>;
+#  endif
+
+// Class template basic_ispanstream [ispanstream]
+
+template <class _CharT, class _Traits = char_traits<_CharT>>
+class 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
+
+  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;
+
+  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>>
+  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;
+
+  basic_ispanstream& operator=(basic_ispanstream&& __rhs) {
+    basic_ispanstream __tmp{std::move(__rhs)};
+    this->swap(__tmp);
+    return *this;
+  }
+
+  // [ispanstream.swap], swap
+
+  void swap(basic_ispanstream& __rhs) {
+    basic_istream<_CharT, _Traits>::swap(__rhs);
+    __sb_.swap(__rhs.__sb_);
+  }
+
+  // [ispanstream.members], member functions
+
+  basic_spanbuf<_CharT, _Traits>* rdbuf() const noexcept {
+    return const_cast<basic_spanbuf<_CharT, _Traits>*>(std::addressof(__sb_));
+  }
+
+  std::span<const _CharT> span() const noexcept { return rdbuf()->span(); }
+
+  void span(std::span<_CharT> __s) noexcept { rdbuf()->span(__s); }
+
+  template <ranges::borrowed_range _ROSeq>
+    requires(!convertible_to<_ROSeq, std::span<_CharT>>) && convertible_to<_ROSeq, std::span<const _CharT>>
+  void span(_ROSeq&& __s) noexcept {
+    std::span<const _CharT> __sp(std::forward<_ROSeq>(__s));
+    this->span(std::span<_CharT>(const_cast<_CharT*>(__sp.data()), __sp.size()));
+  }
+
+private:
+  basic_spanbuf<_CharT, _Traits> __sb_; // exposition only
+};
+
+template <class _CharT, class _Traits>
+void swap(basic_ispanstream<_CharT, _Traits>& __x, basic_ispanstream<_CharT, _Traits>& __y) {
+  __x.swap(__y);
+}
+
+using ispanstream = basic_ispanstream<char>;
+#  ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+using wispanstream = basic_ispanstream<wchar_t>;
+#  endif
+
+// Class template basic_ospanstream [ospanstream]
+
+template <class _CharT, class _Traits = char_traits<_CharT>>
+class basic_ospanstream : public basic_ostream<_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;
+
+  // [ospanstream.cons], constructors
+
+  explicit basic_ospanstream(std::span<_CharT> __s, ios_base::openmode __which = ios_base::out)
+      : basic_ostream<_CharT, _Traits>(std::addressof(__sb_)),
+        __sb_(basic_spanbuf<_CharT, _Traits>(__s, __which | ios_base::out)) {}
+
+  basic_ospanstream(const basic_ospanstream&) = delete;
+
+  basic_ospanstream(basic_ospanstream&& __rhs) : basic_ospanstream(std::move(__rhs)), __sb_(std::move(__rhs.__sb_)) {
+    basic_ostream<_CharT, _Traits>::set_rdbuf(std::addressof(__sb_));
+  }
+
+  basic_ospanstream& operator=(const basic_ospanstream&) = delete;
+
+  basic_ospanstream& operator=(basic_ospanstream&& __rhs) {
+    basic_ospanstream __tmp{std::move(__rhs)};
+    this->swap(__tmp);
+    return *this;
+  }
+
+  // [ospanstream.swap], swap
+
+  void swap(basic_ospanstream& __rhs) {
+    basic_ostream<_CharT, _Traits>::swap(__rhs);
+    __sb_.swap(__rhs.__sb_);
+  }
+
+  // [ospanstream.members], member functions
+
+  basic_spanbuf<_CharT, _Traits>* rdbuf() const noexcept { return __sb_; }
+
+  std::span<_CharT> span() const noexcept { return __sb_.rdbuf()->span(); }
+
+  void span(std::span<_CharT> __s) noexcept { rdbuf()->span(__s); }
+
+private:
+  basic_spanbuf<_CharT, _Traits> __sb_; // exposition only
+};
+
+template <class _CharT, class _Traits>
+void swap(basic_ospanstream<_CharT, _Traits>& __x, basic_ospanstream<_CharT, _Traits>& __y) {
+  __x.swap(__y);
+}
+
+using ospanstream = basic_ospanstream<char>;
+#  ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+using wospanstream = basic_ospanstream<wchar_t>;
+#  endif
+
+template <class _CharT, class _Traits = char_traits<_CharT>>
+class basic_spanstream : public basic_iostream<_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;
+
+  // [spanstream.cons], constructors
+
+  explicit basic_spanstream(std::span<_CharT> __s, ios_base::openmode __which = ios_base::out | ios_base::in)
+      : basic_iostream<_CharT, _Traits>(std::addressof(__sb_)), __sb_(basic_spanbuf<_CharT, _Traits>(__s, __which)) {}
+
+  basic_spanstream(const basic_spanstream&) = delete;
+
+  basic_spanstream(basic_spanstream&& __rhs) : basic_spanstream(std::move(__rhs)), __sb_(__rhs.__sb_) {
+    basic_iostream<_CharT, _Traits>::set_rdbuf(std::addressof(__sb_));
+  }
+
+  basic_spanstream& operator=(const basic_spanstream&) = delete;
+
+  basic_spanstream& operator=(basic_spanstream&& __rhs) {
+    basic_spanstream __tmp{std::move(__rhs)};
+    this->swap(__tmp);
+    return *this;
+  }
+
+  // [spanstream.swap], swap
+
+  void swap(basic_spanstream& __rhs) {
+    basic_iostream<_CharT, _Traits>::swap(__rhs);
+    __sb_.swap(__rhs.__sb_);
+  }
+
+  // [spanstream.members], members
+
+  basic_spanbuf<_CharT, _Traits>* rdbuf() const noexcept { return __sb_; }
+
+  std::span<_CharT> span() const noexcept { return rdbuf()->span(); }
+
+  void span(std::span<_CharT> __s) noexcept { rdbuf()->span(__s); }
+
+private:
+  basic_spanbuf<_CharT, _Traits> __sb_; // exposition only
+};
+
+template <class _CharT, class _Traits>
+void swap(basic_spanstream<_CharT, _Traits>& __x, basic_spanstream<_CharT, _Traits>& __y) {
+  __x.swap(__y);
+}
+
+using spanstream = basic_spanstream<char>;
+#  ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+using wspanstream = basic_spanstream<wchar_t>;
+#  endif
+
+#endif // _LIBCPP_STD_VER >= 23
+
+_LIBCPP_END_NAMESPACE_STD
+
+_LIBCPP_POP_MACROS
+
+#if _LIBCPP_STD_VER <= 20 && !defined(_LIBCPP_REMOVE_TRANSITIVE_INCLUDES)
+#  include <type_traits>
+#endif
+
+#endif // _LIBCPP_SPANSTREAM
diff --git a/libcxx/include/version b/libcxx/include/version
index 68aa88a48fa8f..3a0815a02d6b0 100644
--- a/libcxx/include/version
+++ b/libcxx/include/version
@@ -492,7 +492,7 @@ __cpp_lib_void_t                                        201411L <type_traits>
 # define __cpp_lib_ranges_to_container                  202202L
 // # define __cpp_lib_ranges_zip                           202110L
 // # define __cpp_lib_reference_from_temporary             202202L
-// # define __cpp_lib_spanstream                           202106L
+# define __cpp_lib_spanstream                           202106L
 // # define __cpp_lib_stacktrace                           202011L
 # define __cpp_lib_stdatomic_h                          202011L
 # define __cpp_lib_string_contains                      202011L
diff --git a/libcxx/modules/std.compat.cppm.in b/libcxx/modules/std.compat.cppm.in
index 0f547a2dc8b71..c4f8afc191777 100644
--- a/libcxx/modules/std.compat.cppm.in
+++ b/libcxx/modules/std.compat.cppm.in
@@ -78,9 +78,6 @@ module;
 #  if __has_include(<rcu>)
 #    error "please update the header information for <rcu> in headers_not_available in utils/libcxx/header_information.py"
 #  endif // __has_include(<rcu>)
-#  if __has_include(<spanstream>)
-#    error "please update the header information for <spanstream> in headers_not_available in utils/libcxx/header_information.py"
-#  endif // __has_include(<spanstream>)
 #  if __has_include(<stacktrace>)
 #    error "please update the header information for <stacktrace> in headers_not_available in utils/libcxx/header_information.py"
 #  endif // __has_include(<stacktrace>)
diff --git a/libcxx/modules/std.cppm.in b/libcxx/modules/std.cppm.in
index ad8a639b7f71a..05b9bbc91e120 100644
--- a/libcxx/modules/std.cppm.in
+++ b/libcxx/modules/std.cppm.in
@@ -133,6 +133,9 @@ module;
 #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>
@@ -200,9 +203,6 @@ module;
 #  if __has_include(<rcu>)
 #    error "please update the header information for <rcu> in headers_not_available in utils/libcxx/header_information.py"
 #  endif // __has_include(<rcu>)
-#  if __has_include(<spanstream>)
-#    error "please update the header information for <spanstream> in headers_not_available in utils/libcxx/header_information.py"
-#  endif // __has_include(<spanstream>)
 #  if __has_include(<stacktrace>)
 #    error "please update the header information for <stacktrace> in headers_not_available in utils/libcxx/header_information.py"
 #  endif // __has_include(<stacktrace>)
diff --git a/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.general/lit.local.cfg b/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.general/lit.local.cfg
new file mode 100644
index 0000000000000..2cb10010c4507
--- /dev/null
+++ b/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.general/lit.local.cfg
@@ -0,0 +1,3 @@
+# All non-trivial uses of iostreams require localization support
+if "no-localization" in config.available_features:
+    config.unsupported = True
diff --git a/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.general/nothing_to_do.pass.cpp b/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.general/nothing_to_do.pass.cpp
new file mode 100644
index 0000000000000..4a307014fa0f7
--- /dev/null
+++ b/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.general/nothing_to_do.pass.cpp
@@ -0,0 +1,15 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <spanstream>
+
+// [ispanstream.general]
+
+int main(int, char**) { return 0; }
diff --git a/libcxx/test/std/input.output/span.streams/ispanstream/types.compile.pass.cpp b/libcxx/test/std/input.output/span.streams/ispanstream/types.compile.pass.cpp
new file mode 100644
index 0000000000000..773efffd61a39
--- /dev/null
+++ b/libcxx/test/std/input.output/span.streams/ispanstream/types.compile.pass.cpp
@@ -0,0 +1,79 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <spanstream>
+
+//   template<class charT, class traits = char_traits<charT>>
+//   class 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;
+
+//   using ispanstream = basic_ispanstream<char>;
+//   using wispanstream = basic_ispanstream<wchar_t>;
+
+#include <spanstream>
+#include <string>
+#include <type_traits>
+
+#include "test_macros.h"
+
+// Types
+
+static_assert(std::is_base_of_v<std::basic_istream<char>, std::ispanstream>);
+static_assert(std::is_same_v<std::ispanstream::char_type, char>);
+static_assert(std::is_same_v<std::ispanstream::int_type, std::char_traits<char>::int_type>);
+static_assert(std::is_same_v<std::ispanstream::pos_type, std::char_traits<char>::pos_type>);
+static_assert(std::is_same_v<std::ispanstream::off_type, std::char_traits<char>::off_type>);
+static_assert(std::is_same_v<std::ispanstream::traits_type, std::char_traits<char>>);
+
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+static_assert(std::is_base_of_v<std::basic_istream<wchar_t>, std::wispanstream>);
+static_assert(std::is_same_v<std::wispanstream::char_type, wchar_t>);
+static_assert(std::is_same_v<std::wispanstream::int_type, std::char_traits<wchar_t>::int_type>);
+static_assert(std::is_same_v<std::wispanstream::pos_type, std::char_traits<wchar_t>::pos_type>);
+static_assert(std::is_same_v<std::wispanstream::off_type, std::char_traits<wchar_t>::off_type>);
+static_assert(std::is_same_v<std::wispanstream::traits_type, std::char_traits<wchar_t>>);
+#endif
+
+// Copy properties
+
+static_assert(!std::is_copy_constructible_v<std::ispanstream>);
+static_assert(!std::is_copy_assignable_v<std::ispanstream>);
+
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+static_assert(!std::is_copy_constructible_v<std::wispanstream>);
+static_assert(!std::is_copy_assignable_v<std::wispanstream>);
+#endif
+
+// Move properties
+
+static_assert(!std::is_copy_constructible_v<std::ispanstream>);
+static_assert(!std::is_copy_assignable_v<std::ispanstream>);
+
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+static_assert(!std::is_copy_constructible_v<std::wispanstream>);
+static_assert(!std::is_copy_assignable_v<std::wispanstream>);
+#endif
+
+// Move properties
+
+static_assert(std::is_move_constructible_v<std::ispanstream>);
+static_assert(std::is_move_assignable_v<std::ispanstream>);
+
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+static_assert(std::is_move_constructible_v<std::wispanstream>);
+static_assert(std::is_move_assignable_v<std::wispanstream>);
+#endif
+
diff --git a/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.general/lit.local.cfg b/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.general/lit.local.cfg
new file mode 100644
index 0000000000000..2cb10010c4507
--- /dev/null
+++ b/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.general/lit.local.cfg
@@ -0,0 +1,3 @@
+# All non-trivial uses of iostreams require localization support
+if "no-localization" in config.available_features:
+    config.unsupported = True
diff --git a/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.general/nothing_to_do.pass.cpp b/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.general/nothing_to_do.pass.cpp
new file mode 100644
index 0000000000000..6f9497040a897
--- /dev/null
+++ b/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.general/nothing_to_do.pass.cpp
@@ -0,0 +1,15 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <spanstream>
+
+// [ospanstream.general]
+
+int main(int, char**) { return 0; }
diff --git a/libcxx/test/std/input.output/span.streams/ospanstream/types.compile.pass.cpp b/libcxx/test/std/input.output/span.streams/ospanstream/types.compile.pass.cpp
new file mode 100644
index 0000000000000..ab0cac0716840
--- /dev/null
+++ b/libcxx/test/std/input.output/span.streams/ospanstream/types.compile.pass.cpp
@@ -0,0 +1,79 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <spanstream>
+
+//   template<class charT, class traits = char_traits<charT>>
+//   class basic_ospanstream
+//     : public basic_ostream<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;
+
+//   using ospanstream = basic_ospanstream<char>;
+//   using wospanstream = basic_ospanstream<wchar_t>;
+
+#include <spanstream>
+#include <string>
+#include <type_traits>
+
+#include "test_macros.h"
+
+// Types
+
+static_assert(std::is_base_of_v<std::basic_ostream<char>, std::ospanstream>);
+static_assert(std::is_same_v<std::ospanstream::char_type, char>);
+static_assert(std::is_same_v<std::ospanstream::int_type, std::char_traits<char>::int_type>);
+static_assert(std::is_same_v<std::ospanstream::pos_type, std::char_traits<char>::pos_type>);
+static_assert(std::is_same_v<std::ospanstream::off_type, std::char_traits<char>::off_type>);
+static_assert(std::is_same_v<std::ospanstream::traits_type, std::char_traits<char>>);
+
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+static_assert(std::is_base_of_v<std::basic_ostream<wchar_t>, std::wospanstream>);
+static_assert(std::is_same_v<std::wospanstream::char_type, wchar_t>);
+static_assert(std::is_same_v<std::wospanstream::int_type, std::char_traits<wchar_t>::int_type>);
+static_assert(std::is_same_v<std::wospanstream::pos_type, std::char_traits<wchar_t>::pos_type>);
+static_assert(std::is_same_v<std::wospanstream::off_type, std::char_traits<wchar_t>::off_type>);
+static_assert(std::is_same_v<std::wospanstream::traits_type, std::char_traits<wchar_t>>);
+#endif
+
+// Copy properties
+
+static_assert(!std::is_copy_constructible_v<std::ospanstream>);
+static_assert(!std::is_copy_assignable_v<std::ospanstream>);
+
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+static_assert(!std::is_copy_constructible_v<std::wospanstream>);
+static_assert(!std::is_copy_assignable_v<std::wospanstream>);
+#endif
+
+// Move properties
+
+static_assert(!std::is_copy_constructible_v<std::ospanstream>);
+static_assert(!std::is_copy_assignable_v<std::ospanstream>);
+
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+static_assert(!std::is_copy_constructible_v<std::wospanstream>);
+static_assert(!std::is_copy_assignable_v<std::wospanstream>);
+#endif
+
+// Move properties
+
+static_assert(std::is_move_constructible_v<std::ospanstream>);
+static_assert(std::is_move_assignable_v<std::ospanstream>);
+
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+static_assert(std::is_move_constructible_v<std::wospanstream>);
+static_assert(std::is_move_assignable_v<std::wospanstream>);
+#endif
+
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/default.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/default.pass.cpp
new file mode 100644
index 0000000000000..4675c0e5fc299
--- /dev/null
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/default.pass.cpp
@@ -0,0 +1,45 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <spanstream>
+
+//   template<class charT, class traits = char_traits<charT>>
+//   class basic_spanbuf
+//     : public basic_streambuf<charT, traits> {
+
+//     // [spanbuf.cons], constructors
+//     basic_spanbuf();
+
+#include <cassert>
+#include <spanstream>
+
+#include "constexpr_char_traits.h"
+#include "test_macros.h"
+
+template <typename CharT, typename Traits = std::char_traits<CharT>>
+void test() {
+  using SpanBuf = std::basic_spanbuf<CharT, Traits>;
+
+  static_assert(std::default_initializable<SpanBuf>);
+
+  SpanBuf spBuf;
+  assert(spBuf.span().empty());
+}
+
+int main(int, char**) {
+  test<char>();
+  test<char, constexpr_char_traits<char>>();
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  test<wchar_t>();
+  test<wchar_t, constexpr_char_traits<wchar_t>>();
+#endif
+
+  return 0;
+}
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.general/lit.local.cfg b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.general/lit.local.cfg
new file mode 100644
index 0000000000000..2cb10010c4507
--- /dev/null
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.general/lit.local.cfg
@@ -0,0 +1,3 @@
+# All non-trivial uses of iostreams require localization support
+if "no-localization" in config.available_features:
+    config.unsupported = True
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.general/nothing_to_do.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.general/nothing_to_do.pass.cpp
new file mode 100644
index 0000000000000..fc746f4af7c76
--- /dev/null
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.general/nothing_to_do.pass.cpp
@@ -0,0 +1,15 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <spanstream>
+
+// [spanbuf.general]
+
+int main(int, char**) { return 0; }
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/types.compile.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/types.compile.pass.cpp
new file mode 100644
index 0000000000000..4585147ea8d2e
--- /dev/null
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/types.compile.pass.cpp
@@ -0,0 +1,79 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <spanstream>
+
+//   template<class charT, class traits = char_traits<charT>>
+//   class 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;
+
+//   using spanbuf = basic_spanbufchar>;
+//   using wspanbuf = basic_spanbuf<wchar_t>;
+
+#include <spanstream>
+#include <string>
+#include <type_traits>
+
+#include "test_macros.h"
+
+// Types
+
+static_assert(std::is_base_of_v<std::basic_streambuf<char>, std::spanbuf>);
+static_assert(std::is_same_v<std::spanbuf::char_type, char>);
+static_assert(std::is_same_v<std::spanbuf::int_type, std::char_traits<char>::int_type>);
+static_assert(std::is_same_v<std::spanbuf::pos_type, std::char_traits<char>::pos_type>);
+static_assert(std::is_same_v<std::spanbuf::off_type, std::char_traits<char>::off_type>);
+static_assert(std::is_same_v<std::spanbuf::traits_type, std::char_traits<char>>);
+
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+static_assert(std::is_base_of_v<std::basic_streambuf<wchar_t>, std::wspanbuf>);
+static_assert(std::is_same_v<std::wspanbuf::char_type, wchar_t>);
+static_assert(std::is_same_v<std::wspanbuf::int_type, std::char_traits<wchar_t>::int_type>);
+static_assert(std::is_same_v<std::wspanbuf::pos_type, std::char_traits<wchar_t>::pos_type>);
+static_assert(std::is_same_v<std::wspanbuf::off_type, std::char_traits<wchar_t>::off_type>);
+static_assert(std::is_same_v<std::wspanbuf::traits_type, std::char_traits<wchar_t>>);
+#endif
+
+// Copy properties
+
+static_assert(!std::is_copy_constructible_v<std::spanbuf>);
+static_assert(!std::is_copy_assignable_v<std::spanbuf>);
+
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+static_assert(!std::is_copy_constructible_v<std::wspanbuf>);
+static_assert(!std::is_copy_assignable_v<std::wspanbuf>);
+#endif
+
+// Move properties
+
+static_assert(!std::is_copy_constructible_v<std::spanbuf>);
+static_assert(!std::is_copy_assignable_v<std::spanbuf>);
+
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+static_assert(!std::is_copy_constructible_v<std::wspanbuf>);
+static_assert(!std::is_copy_assignable_v<std::wspanbuf>);
+#endif
+
+// Move properties
+
+static_assert(std::is_move_constructible_v<std::spanbuf>);
+static_assert(std::is_move_assignable_v<std::spanbuf>);
+
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+static_assert(std::is_move_constructible_v<std::wspanbuf>);
+static_assert(std::is_move_assignable_v<std::wspanbuf>);
+#endif
+
diff --git a/libcxx/test/std/input.output/span.streams/spanstream/spanstream.general/lit.local.cfg b/libcxx/test/std/input.output/span.streams/spanstream/spanstream.general/lit.local.cfg
new file mode 100644
index 0000000000000..2cb10010c4507
--- /dev/null
+++ b/libcxx/test/std/input.output/span.streams/spanstream/spanstream.general/lit.local.cfg
@@ -0,0 +1,3 @@
+# All non-trivial uses of iostreams require localization support
+if "no-localization" in config.available_features:
+    config.unsupported = True
diff --git a/libcxx/test/std/input.output/span.streams/spanstream/spanstream.general/nothing_to_do.pass.cpp b/libcxx/test/std/input.output/span.streams/spanstream/spanstream.general/nothing_to_do.pass.cpp
new file mode 100644
index 0000000000000..8677bb6d0906d
--- /dev/null
+++ b/libcxx/test/std/input.output/span.streams/spanstream/spanstream.general/nothing_to_do.pass.cpp
@@ -0,0 +1,15 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <spanstream>
+
+// [spanstream.general]
+
+int main(int, char**) { return 0; }
diff --git a/libcxx/test/std/input.output/span.streams/spanstream/types.compile.pass.cpp b/libcxx/test/std/input.output/span.streams/spanstream/types.compile.pass.cpp
new file mode 100644
index 0000000000000..4e90f259ccf48
--- /dev/null
+++ b/libcxx/test/std/input.output/span.streams/spanstream/types.compile.pass.cpp
@@ -0,0 +1,78 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <spanstream>
+
+//   template<class charT, class traits = char_traits<charT>>
+//   class basic_spanstream
+//     : public basic_iostream<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;
+
+//   using spanstream = basic_spanstream<char>;
+//   using wspanstream = basic_spanstream<wchar_t>;
+
+#include <spanstream>
+#include <string>
+#include <type_traits>
+
+#include "test_macros.h"
+
+// Types
+
+static_assert(std::is_base_of_v<std::basic_iostream<char>, std::spanstream>);
+static_assert(std::is_same_v<std::spanstream::char_type, char>);
+static_assert(std::is_same_v<std::spanstream::int_type, std::char_traits<char>::int_type>);
+static_assert(std::is_same_v<std::spanstream::pos_type, std::char_traits<char>::pos_type>);
+static_assert(std::is_same_v<std::spanstream::off_type, std::char_traits<char>::off_type>);
+static_assert(std::is_same_v<std::spanstream::traits_type, std::char_traits<char>>);
+
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+static_assert(std::is_base_of_v<std::basic_iostream<wchar_t>, std::wspanstream>);
+static_assert(std::is_same_v<std::wspanstream::char_type, wchar_t>);
+static_assert(std::is_same_v<std::wspanstream::int_type, std::char_traits<wchar_t>::int_type>);
+static_assert(std::is_same_v<std::wspanstream::pos_type, std::char_traits<wchar_t>::pos_type>);
+static_assert(std::is_same_v<std::wspanstream::off_type, std::char_traits<wchar_t>::off_type>);
+static_assert(std::is_same_v<std::wspanstream::traits_type, std::char_traits<wchar_t>>);
+#endif
+
+// Copy properties
+
+static_assert(!std::is_copy_constructible_v<std::spanstream>);
+static_assert(!std::is_copy_assignable_v<std::spanstream>);
+
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+static_assert(!std::is_copy_constructible_v<std::wspanstream>);
+static_assert(!std::is_copy_assignable_v<std::wspanstream>);
+#endif
+
+// Move properties
+
+static_assert(!std::is_copy_constructible_v<std::spanstream>);
+static_assert(!std::is_copy_assignable_v<std::spanstream>);
+
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+static_assert(!std::is_copy_constructible_v<std::wspanstream>);
+static_assert(!std::is_copy_assignable_v<std::wspanstream>);
+#endif
+
+// Move properties
+
+static_assert(std::is_move_constructible_v<std::spanstream>);
+static_assert(std::is_move_assignable_v<std::spanstream>);
+
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+static_assert(std::is_move_constructible_v<std::wspanstream>);
+static_assert(std::is_move_assignable_v<std::wspanstream>);
+#endif
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/spanstream.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/spanstream.version.compile.pass.cpp
new file mode 100644
index 0000000000000..8719352d4367e
--- /dev/null
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/spanstream.version.compile.pass.cpp
@@ -0,0 +1,68 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// WARNING: This test was generated by generate_feature_test_macro_components.py
+// and should not be edited manually.
+//
+// clang-format off
+
+// <spanstream>
+
+// Test the feature test macros defined by <spanstream>
+
+/*  Constant                Value
+    __cpp_lib_spanstream    202106L [C++23]
+*/
+
+#include <spanstream>
+#include "test_macros.h"
+
+#if TEST_STD_VER < 14
+
+# ifdef __cpp_lib_spanstream
+#   error "__cpp_lib_spanstream should not be defined before c++23"
+# endif
+
+#elif TEST_STD_VER == 14
+
+# ifdef __cpp_lib_spanstream
+#   error "__cpp_lib_spanstream should not be defined before c++23"
+# endif
+
+#elif TEST_STD_VER == 17
+
+# ifdef __cpp_lib_spanstream
+#   error "__cpp_lib_spanstream should not be defined before c++23"
+# endif
+
+#elif TEST_STD_VER == 20
+
+# ifdef __cpp_lib_spanstream
+#   error "__cpp_lib_spanstream should not be defined before c++23"
+# endif
+
+#elif TEST_STD_VER == 23
+
+# ifndef __cpp_lib_spanstream
+#   error "__cpp_lib_spanstream should be defined in c++23"
+# endif
+# if __cpp_lib_spanstream != 202106L
+#   error "__cpp_lib_spanstream should have the value 202106L in c++23"
+# endif
+
+#elif TEST_STD_VER > 23
+
+# ifndef __cpp_lib_spanstream
+#   error "__cpp_lib_spanstream should be defined in c++26"
+# endif
+# if __cpp_lib_spanstream != 202106L
+#   error "__cpp_lib_spanstream should have the value 202106L in c++26"
+# endif
+
+#endif // TEST_STD_VER > 23
+
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
index 945de95df67e1..7af28a068dfc3 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
@@ -5910,17 +5910,11 @@
 #   error "__cpp_lib_span_initializer_list should not be defined before c++26"
 # endif
 
-# if !defined(_LIBCPP_VERSION)
-#   ifndef __cpp_lib_spanstream
-#     error "__cpp_lib_spanstream should be defined in c++23"
-#   endif
-#   if __cpp_lib_spanstream != 202106L
-#     error "__cpp_lib_spanstream should have the value 202106L in c++23"
-#   endif
-# else // _LIBCPP_VERSION
-#   ifdef __cpp_lib_spanstream
-#     error "__cpp_lib_spanstream should not be defined because it is unimplemented in libc++!"
-#   endif
+# ifndef __cpp_lib_spanstream
+#   error "__cpp_lib_spanstream should be defined in c++23"
+# endif
+# if __cpp_lib_spanstream != 202106L
+#   error "__cpp_lib_spanstream should have the value 202106L in c++23"
 # endif
 
 # ifndef __cpp_lib_ssize
@@ -7805,17 +7799,11 @@
 #   error "__cpp_lib_span_initializer_list should have the value 202311L in c++26"
 # endif
 
-# if !defined(_LIBCPP_VERSION)
-#   ifndef __cpp_lib_spanstream
-#     error "__cpp_lib_spanstream should be defined in c++26"
-#   endif
-#   if __cpp_lib_spanstream != 202106L
-#     error "__cpp_lib_spanstream should have the value 202106L in c++26"
-#   endif
-# else // _LIBCPP_VERSION
-#   ifdef __cpp_lib_spanstream
-#     error "__cpp_lib_spanstream should not be defined because it is unimplemented in libc++!"
-#   endif
+# ifndef __cpp_lib_spanstream
+#   error "__cpp_lib_spanstream should be defined in c++26"
+# endif
+# if __cpp_lib_spanstream != 202106L
+#   error "__cpp_lib_spanstream should have the value 202106L in c++26"
 # endif
 
 # ifndef __cpp_lib_ssize
diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py
index a09beb29565ad..5fa3f0b6aef98 100755
--- a/libcxx/utils/generate_feature_test_macro_components.py
+++ b/libcxx/utils/generate_feature_test_macro_components.py
@@ -1217,7 +1217,6 @@ def add_version_header(tc):
             "name": "__cpp_lib_spanstream",
             "values": {"c++23": 202106},
             "headers": ["spanstream"],
-            "unimplemented": True,
         },
         {
             "name": "__cpp_lib_ssize",
diff --git a/libcxx/utils/libcxx/header_information.py b/libcxx/utils/libcxx/header_information.py
index 166c9a77c08e7..87fc42fc137b1 100644
--- a/libcxx/utils/libcxx/header_information.py
+++ b/libcxx/utils/libcxx/header_information.py
@@ -26,6 +26,7 @@
     "locale": "!defined(_LIBCPP_HAS_NO_LOCALIZATION)",
     "ostream": "!defined(_LIBCPP_HAS_NO_LOCALIZATION)",
     "regex": "!defined(_LIBCPP_HAS_NO_LOCALIZATION)",
+    "spanstream": "!defined(_LIBCPP_HAS_NO_LOCALIZATION)",
     "sstream": "!defined(_LIBCPP_HAS_NO_LOCALIZATION)",
     "streambuf": "!defined(_LIBCPP_HAS_NO_LOCALIZATION)",
     "strstream": "!defined(_LIBCPP_HAS_NO_LOCALIZATION)",
@@ -76,6 +77,7 @@
     "regex": "// UNSUPPORTED: no-localization",
     "semaphore": "// UNSUPPORTED: no-threads, c++03, c++11, c++14, c++17",
     "shared_mutex": "// UNSUPPORTED: no-threads, c++03, c++11",
+    "spanstream": "// UNSUPPORTED: no-localization",
     "sstream": "// UNSUPPORTED: no-localization",
     "stdatomic.h": "// UNSUPPORTED: no-threads, c++03, c++11, c++14, c++17, c++20",
     "stop_token": "// UNSUPPORTED: no-threads, c++03, c++11, c++14, c++17",
@@ -146,7 +148,6 @@
     "inplace_vector",
     "linalg",
     "rcu",
-    "spanstream",
     "stacktrace",
     "stdfloat",
     "text_encoding",

>From 03c0047d08f4af65fff38e37a636554a41237a2e Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Wed, 28 Feb 2024 18:30:36 +0200
Subject: [PATCH 02/56] Added forward declarations to `<iosfwd>`

---
 libcxx/include/CMakeLists.txt     |  1 +
 libcxx/include/__fwd/spanstream.h | 48 +++++++++++++++++++++++++++++++
 libcxx/include/iosfwd             | 20 +++++++++++++
 libcxx/include/module.modulemap   | 15 +++++-----
 libcxx/include/spanstream         | 15 +++++-----
 5 files changed, 85 insertions(+), 14 deletions(-)
 create mode 100644 libcxx/include/__fwd/spanstream.h

diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 47331d61ba067..99e5c19c16d62 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -426,6 +426,7 @@ set(files
   __fwd/pair.h
   __fwd/queue.h
   __fwd/span.h
+  __fwd/spanstream.h
   __fwd/sstream.h
   __fwd/stack.h
   __fwd/streambuf.h
diff --git a/libcxx/include/__fwd/spanstream.h b/libcxx/include/__fwd/spanstream.h
new file mode 100644
index 0000000000000..2afeaaecf7fb4
--- /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/iosfwd b/libcxx/include/iosfwd
index 051c73995e98b..47649f46d7487 100644
--- a/libcxx/include/iosfwd
+++ b/libcxx/include/iosfwd
@@ -41,6 +41,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;
@@ -62,6 +71,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;
@@ -77,6 +91,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;
@@ -111,6 +130,7 @@ using wosyncstream = basic_osyncstream<wchar_t>;  // C++20
 #include <__fwd/istream.h>
 #include <__fwd/memory.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/module.modulemap b/libcxx/include/module.modulemap
index 105ea3b8812ff..e04a444affbc2 100644
--- a/libcxx/include/module.modulemap
+++ b/libcxx/include/module.modulemap
@@ -1380,14 +1380,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
index f25a04c2cb525..ffaba85ef252c 100644
--- a/libcxx/include/spanstream
+++ b/libcxx/include/spanstream
@@ -57,6 +57,7 @@
 #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>
@@ -81,7 +82,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD
 
 // Class template basic_spanbuf [spanbuf]
 
-template <class _CharT, class _Traits = char_traits<_CharT>>
+template <class _CharT, class _Traits>
 class _LIBCPP_TEMPLATE_VIS basic_spanbuf : public basic_streambuf<_CharT, _Traits> {
 public:
   using char_type   = _CharT;
@@ -223,8 +224,8 @@ using wspanbuf = basic_spanbuf<wchar_t>;
 
 // Class template basic_ispanstream [ispanstream]
 
-template <class _CharT, class _Traits = char_traits<_CharT>>
-class basic_ispanstream : public basic_istream<_CharT, _Traits> {
+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;
@@ -300,8 +301,8 @@ using wispanstream = basic_ispanstream<wchar_t>;
 
 // Class template basic_ospanstream [ospanstream]
 
-template <class _CharT, class _Traits = char_traits<_CharT>>
-class basic_ospanstream : public basic_ostream<_CharT, _Traits> {
+template <class _CharT, class _Traits>
+class _LIBCPP_TEMPLATE_VIS basic_ospanstream : public basic_ostream<_CharT, _Traits> {
 public:
   using char_type   = _CharT;
   using int_type    = typename _Traits::int_type;
@@ -358,8 +359,8 @@ using ospanstream = basic_ospanstream<char>;
 using wospanstream = basic_ospanstream<wchar_t>;
 #  endif
 
-template <class _CharT, class _Traits = char_traits<_CharT>>
-class basic_spanstream : public basic_iostream<_CharT, _Traits> {
+template <class _CharT, class _Traits>
+class _LIBCPP_TEMPLATE_VIS basic_spanstream : public basic_iostream<_CharT, _Traits> {
 public:
   using char_type   = _CharT;
   using int_type    = typename _Traits::int_type;

>From c21b80a85369e5d97bb18a9a14f3e91468ef1346 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Wed, 28 Feb 2024 19:01:08 +0200
Subject: [PATCH 03/56] Tests: updated `types.compile.pass`

---
 .../ispanstream/types.compile.pass.cpp        | 67 +++++++++----------
 .../ospanstream/types.compile.pass.cpp        | 67 +++++++++----------
 .../spanbuf/types.compile.pass.cpp            | 67 +++++++++----------
 .../spanstream/types.compile.pass.cpp         | 66 +++++++++---------
 4 files changed, 132 insertions(+), 135 deletions(-)

diff --git a/libcxx/test/std/input.output/span.streams/ispanstream/types.compile.pass.cpp b/libcxx/test/std/input.output/span.streams/ispanstream/types.compile.pass.cpp
index 773efffd61a39..9615d270116ee 100644
--- a/libcxx/test/std/input.output/span.streams/ispanstream/types.compile.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/ispanstream/types.compile.pass.cpp
@@ -27,53 +27,52 @@
 #include <string>
 #include <type_traits>
 
+#include "constexpr_char_traits.h"
 #include "test_macros.h"
 
-// Types
+template <typename CharT, typename Traits = std::char_traits<CharT>>
+void test() {
+  using SpStream = std::basic_ispanstream<CharT, Traits>;
 
-static_assert(std::is_base_of_v<std::basic_istream<char>, std::ispanstream>);
-static_assert(std::is_same_v<std::ispanstream::char_type, char>);
-static_assert(std::is_same_v<std::ispanstream::int_type, std::char_traits<char>::int_type>);
-static_assert(std::is_same_v<std::ispanstream::pos_type, std::char_traits<char>::pos_type>);
-static_assert(std::is_same_v<std::ispanstream::off_type, std::char_traits<char>::off_type>);
-static_assert(std::is_same_v<std::ispanstream::traits_type, std::char_traits<char>>);
+  // Types
 
-#ifndef TEST_HAS_NO_WIDE_CHARACTERS
-static_assert(std::is_base_of_v<std::basic_istream<wchar_t>, std::wispanstream>);
-static_assert(std::is_same_v<std::wispanstream::char_type, wchar_t>);
-static_assert(std::is_same_v<std::wispanstream::int_type, std::char_traits<wchar_t>::int_type>);
-static_assert(std::is_same_v<std::wispanstream::pos_type, std::char_traits<wchar_t>::pos_type>);
-static_assert(std::is_same_v<std::wispanstream::off_type, std::char_traits<wchar_t>::off_type>);
-static_assert(std::is_same_v<std::wispanstream::traits_type, std::char_traits<wchar_t>>);
-#endif
+  static_assert(std::is_base_of_v<std::basic_istream<CharT, Traits>, SpStream>);
+  static_assert(std::is_same_v<typename SpStream::char_type, CharT>);
+  static_assert(std::is_same_v<typename SpStream::int_type, typename Traits::int_type>);
+  static_assert(std::is_same_v<typename SpStream::pos_type, typename Traits::pos_type>);
+  static_assert(std::is_same_v<typename SpStream::off_type, typename Traits::off_type>);
+  static_assert(std::is_same_v<typename SpStream::traits_type, Traits>);
 
-// Copy properties
+  // Copy properties
 
-static_assert(!std::is_copy_constructible_v<std::ispanstream>);
-static_assert(!std::is_copy_assignable_v<std::ispanstream>);
+  static_assert(!std::is_copy_constructible_v<SpStream>);
+  static_assert(!std::is_copy_assignable_v<SpStream>);
 
-#ifndef TEST_HAS_NO_WIDE_CHARACTERS
-static_assert(!std::is_copy_constructible_v<std::wispanstream>);
-static_assert(!std::is_copy_assignable_v<std::wispanstream>);
-#endif
+  // Move properties
 
-// Move properties
+  static_assert(!std::is_copy_constructible_v<SpStream>);
+  static_assert(!std::is_copy_assignable_v<SpStream>);
 
-static_assert(!std::is_copy_constructible_v<std::ispanstream>);
-static_assert(!std::is_copy_assignable_v<std::ispanstream>);
+  // Move properties
 
+  static_assert(std::is_move_constructible_v<SpStream>);
+  static_assert(std::is_move_assignable_v<SpStream>);
+}
+
+void test() {
+  test<char>();
+  test<char, constexpr_char_traits<char>>();
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
-static_assert(!std::is_copy_constructible_v<std::wispanstream>);
-static_assert(!std::is_copy_assignable_v<std::wispanstream>);
+  test<wchar_t>();
+  test<wchar_t, constexpr_char_traits<wchar_t>>();
 #endif
+}
 
-// Move properties
-
-static_assert(std::is_move_constructible_v<std::ispanstream>);
-static_assert(std::is_move_assignable_v<std::ispanstream>);
+// Aliases
 
+static_assert(std::is_base_of_v<std::basic_istream<char>, std::ispanstream>);
+static_assert(std::is_same_v<std::basic_ispanstream<char>, std::ispanstream>);
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
-static_assert(std::is_move_constructible_v<std::wispanstream>);
-static_assert(std::is_move_assignable_v<std::wispanstream>);
+static_assert(std::is_base_of_v<std::basic_istream<wchar_t>, std::wispanstream>);
+static_assert(std::is_same_v<std::basic_ispanstream<wchar_t>, std::wispanstream>);
 #endif
-
diff --git a/libcxx/test/std/input.output/span.streams/ospanstream/types.compile.pass.cpp b/libcxx/test/std/input.output/span.streams/ospanstream/types.compile.pass.cpp
index ab0cac0716840..e5a9e574eb39f 100644
--- a/libcxx/test/std/input.output/span.streams/ospanstream/types.compile.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/ospanstream/types.compile.pass.cpp
@@ -27,53 +27,52 @@
 #include <string>
 #include <type_traits>
 
+#include "constexpr_char_traits.h"
 #include "test_macros.h"
 
-// Types
+template <typename CharT, typename Traits = std::char_traits<CharT>>
+void test() {
+  using SpStream = std::basic_ospanstream<CharT, Traits>;
 
-static_assert(std::is_base_of_v<std::basic_ostream<char>, std::ospanstream>);
-static_assert(std::is_same_v<std::ospanstream::char_type, char>);
-static_assert(std::is_same_v<std::ospanstream::int_type, std::char_traits<char>::int_type>);
-static_assert(std::is_same_v<std::ospanstream::pos_type, std::char_traits<char>::pos_type>);
-static_assert(std::is_same_v<std::ospanstream::off_type, std::char_traits<char>::off_type>);
-static_assert(std::is_same_v<std::ospanstream::traits_type, std::char_traits<char>>);
+  // Types
 
-#ifndef TEST_HAS_NO_WIDE_CHARACTERS
-static_assert(std::is_base_of_v<std::basic_ostream<wchar_t>, std::wospanstream>);
-static_assert(std::is_same_v<std::wospanstream::char_type, wchar_t>);
-static_assert(std::is_same_v<std::wospanstream::int_type, std::char_traits<wchar_t>::int_type>);
-static_assert(std::is_same_v<std::wospanstream::pos_type, std::char_traits<wchar_t>::pos_type>);
-static_assert(std::is_same_v<std::wospanstream::off_type, std::char_traits<wchar_t>::off_type>);
-static_assert(std::is_same_v<std::wospanstream::traits_type, std::char_traits<wchar_t>>);
-#endif
+  static_assert(std::is_base_of_v<std::basic_ostream<CharT, Traits>, SpStream>);
+  static_assert(std::is_same_v<typename SpStream::char_type, CharT>);
+  static_assert(std::is_same_v<typename SpStream::int_type, typename Traits::int_type>);
+  static_assert(std::is_same_v<typename SpStream::pos_type, typename Traits::pos_type>);
+  static_assert(std::is_same_v<typename SpStream::off_type, typename Traits::off_type>);
+  static_assert(std::is_same_v<typename SpStream::traits_type, Traits>);
 
-// Copy properties
+  // Copy properties
 
-static_assert(!std::is_copy_constructible_v<std::ospanstream>);
-static_assert(!std::is_copy_assignable_v<std::ospanstream>);
+  static_assert(!std::is_copy_constructible_v<SpStream>);
+  static_assert(!std::is_copy_assignable_v<SpStream>);
 
-#ifndef TEST_HAS_NO_WIDE_CHARACTERS
-static_assert(!std::is_copy_constructible_v<std::wospanstream>);
-static_assert(!std::is_copy_assignable_v<std::wospanstream>);
-#endif
+  // Move properties
 
-// Move properties
+  static_assert(!std::is_copy_constructible_v<SpStream>);
+  static_assert(!std::is_copy_assignable_v<SpStream>);
 
-static_assert(!std::is_copy_constructible_v<std::ospanstream>);
-static_assert(!std::is_copy_assignable_v<std::ospanstream>);
+  // Move properties
 
+  static_assert(std::is_move_constructible_v<SpStream>);
+  static_assert(std::is_move_assignable_v<SpStream>);
+}
+
+void test() {
+  test<char>();
+  test<char, constexpr_char_traits<char>>();
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
-static_assert(!std::is_copy_constructible_v<std::wospanstream>);
-static_assert(!std::is_copy_assignable_v<std::wospanstream>);
+  test<wchar_t>();
+  test<wchar_t, constexpr_char_traits<wchar_t>>();
 #endif
+}
 
-// Move properties
-
-static_assert(std::is_move_constructible_v<std::ospanstream>);
-static_assert(std::is_move_assignable_v<std::ospanstream>);
+// Aliases
 
+static_assert(std::is_base_of_v<std::basic_ostream<char>, std::ospanstream>);
+static_assert(std::is_same_v<std::basic_ospanstream<char>, std::ospanstream>);
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
-static_assert(std::is_move_constructible_v<std::wospanstream>);
-static_assert(std::is_move_assignable_v<std::wospanstream>);
+static_assert(std::is_base_of_v<std::basic_ostream<wchar_t>, std::wospanstream>);
+static_assert(std::is_same_v<std::basic_ospanstream<wchar_t>, std::wospanstream>);
 #endif
-
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/types.compile.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/types.compile.pass.cpp
index 4585147ea8d2e..a8cc07ed524ea 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/types.compile.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/types.compile.pass.cpp
@@ -27,53 +27,52 @@
 #include <string>
 #include <type_traits>
 
+#include "constexpr_char_traits.h"
 #include "test_macros.h"
 
-// Types
+template <typename CharT, typename Traits = std::char_traits<CharT>>
+void test() {
+  using SpBuf = std::basic_spanbuf<CharT, Traits>;
 
-static_assert(std::is_base_of_v<std::basic_streambuf<char>, std::spanbuf>);
-static_assert(std::is_same_v<std::spanbuf::char_type, char>);
-static_assert(std::is_same_v<std::spanbuf::int_type, std::char_traits<char>::int_type>);
-static_assert(std::is_same_v<std::spanbuf::pos_type, std::char_traits<char>::pos_type>);
-static_assert(std::is_same_v<std::spanbuf::off_type, std::char_traits<char>::off_type>);
-static_assert(std::is_same_v<std::spanbuf::traits_type, std::char_traits<char>>);
+  // Types
 
-#ifndef TEST_HAS_NO_WIDE_CHARACTERS
-static_assert(std::is_base_of_v<std::basic_streambuf<wchar_t>, std::wspanbuf>);
-static_assert(std::is_same_v<std::wspanbuf::char_type, wchar_t>);
-static_assert(std::is_same_v<std::wspanbuf::int_type, std::char_traits<wchar_t>::int_type>);
-static_assert(std::is_same_v<std::wspanbuf::pos_type, std::char_traits<wchar_t>::pos_type>);
-static_assert(std::is_same_v<std::wspanbuf::off_type, std::char_traits<wchar_t>::off_type>);
-static_assert(std::is_same_v<std::wspanbuf::traits_type, std::char_traits<wchar_t>>);
-#endif
+  static_assert(std::is_base_of_v<std::basic_streambuf<CharT, Traits>, SpBuf>);
+  static_assert(std::is_same_v<typename SpBuf::char_type, CharT>);
+  static_assert(std::is_same_v<typename SpBuf::int_type, typename Traits::int_type>);
+  static_assert(std::is_same_v<typename SpBuf::pos_type, typename Traits::pos_type>);
+  static_assert(std::is_same_v<typename SpBuf::off_type, typename Traits::off_type>);
+  static_assert(std::is_same_v<typename SpBuf::traits_type, Traits>);
 
-// Copy properties
+  // Copy properties
 
-static_assert(!std::is_copy_constructible_v<std::spanbuf>);
-static_assert(!std::is_copy_assignable_v<std::spanbuf>);
+  static_assert(!std::is_copy_constructible_v<SpBuf>);
+  static_assert(!std::is_copy_assignable_v<SpBuf>);
 
-#ifndef TEST_HAS_NO_WIDE_CHARACTERS
-static_assert(!std::is_copy_constructible_v<std::wspanbuf>);
-static_assert(!std::is_copy_assignable_v<std::wspanbuf>);
-#endif
+  // Move properties
 
-// Move properties
+  static_assert(!std::is_copy_constructible_v<SpBuf>);
+  static_assert(!std::is_copy_assignable_v<SpBuf>);
 
-static_assert(!std::is_copy_constructible_v<std::spanbuf>);
-static_assert(!std::is_copy_assignable_v<std::spanbuf>);
+  // Move properties
 
+  static_assert(std::is_move_constructible_v<SpBuf>);
+  static_assert(std::is_move_assignable_v<SpBuf>);
+}
+
+void test() {
+  test<char>();
+  test<char, constexpr_char_traits<char>>();
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
-static_assert(!std::is_copy_constructible_v<std::wspanbuf>);
-static_assert(!std::is_copy_assignable_v<std::wspanbuf>);
+  test<wchar_t>();
+  test<wchar_t, constexpr_char_traits<wchar_t>>();
 #endif
+}
 
-// Move properties
-
-static_assert(std::is_move_constructible_v<std::spanbuf>);
-static_assert(std::is_move_assignable_v<std::spanbuf>);
+// Aliases
 
+static_assert(std::is_base_of_v<std::basic_streambuf<char>, std::spanbuf>);
+static_assert(std::is_same_v<std::basic_spanbuf<char>, std::spanbuf>);
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
-static_assert(std::is_move_constructible_v<std::wspanbuf>);
-static_assert(std::is_move_assignable_v<std::wspanbuf>);
+static_assert(std::is_base_of_v<std::basic_streambuf<wchar_t>, std::wspanbuf>);
+static_assert(std::is_same_v<std::basic_spanbuf<wchar_t>, std::wspanbuf>);
 #endif
-
diff --git a/libcxx/test/std/input.output/span.streams/spanstream/types.compile.pass.cpp b/libcxx/test/std/input.output/span.streams/spanstream/types.compile.pass.cpp
index 4e90f259ccf48..5714834be2ce1 100644
--- a/libcxx/test/std/input.output/span.streams/spanstream/types.compile.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanstream/types.compile.pass.cpp
@@ -27,52 +27,52 @@
 #include <string>
 #include <type_traits>
 
+#include "constexpr_char_traits.h"
 #include "test_macros.h"
 
-// Types
+template <typename CharT, typename Traits = std::char_traits<CharT>>
+void test() {
+  using SpStream = std::basic_spanstream<CharT, Traits>;
 
-static_assert(std::is_base_of_v<std::basic_iostream<char>, std::spanstream>);
-static_assert(std::is_same_v<std::spanstream::char_type, char>);
-static_assert(std::is_same_v<std::spanstream::int_type, std::char_traits<char>::int_type>);
-static_assert(std::is_same_v<std::spanstream::pos_type, std::char_traits<char>::pos_type>);
-static_assert(std::is_same_v<std::spanstream::off_type, std::char_traits<char>::off_type>);
-static_assert(std::is_same_v<std::spanstream::traits_type, std::char_traits<char>>);
+  // Types
 
-#ifndef TEST_HAS_NO_WIDE_CHARACTERS
-static_assert(std::is_base_of_v<std::basic_iostream<wchar_t>, std::wspanstream>);
-static_assert(std::is_same_v<std::wspanstream::char_type, wchar_t>);
-static_assert(std::is_same_v<std::wspanstream::int_type, std::char_traits<wchar_t>::int_type>);
-static_assert(std::is_same_v<std::wspanstream::pos_type, std::char_traits<wchar_t>::pos_type>);
-static_assert(std::is_same_v<std::wspanstream::off_type, std::char_traits<wchar_t>::off_type>);
-static_assert(std::is_same_v<std::wspanstream::traits_type, std::char_traits<wchar_t>>);
-#endif
+  static_assert(std::is_base_of_v<std::basic_iostream<CharT, Traits>, SpStream>);
+  static_assert(std::is_same_v<typename SpStream::char_type, CharT>);
+  static_assert(std::is_same_v<typename SpStream::int_type, typename Traits::int_type>);
+  static_assert(std::is_same_v<typename SpStream::pos_type, typename Traits::pos_type>);
+  static_assert(std::is_same_v<typename SpStream::off_type, typename Traits::off_type>);
+  static_assert(std::is_same_v<typename SpStream::traits_type, Traits>);
 
-// Copy properties
+  // Copy properties
 
-static_assert(!std::is_copy_constructible_v<std::spanstream>);
-static_assert(!std::is_copy_assignable_v<std::spanstream>);
+  static_assert(!std::is_copy_constructible_v<SpStream>);
+  static_assert(!std::is_copy_assignable_v<SpStream>);
 
-#ifndef TEST_HAS_NO_WIDE_CHARACTERS
-static_assert(!std::is_copy_constructible_v<std::wspanstream>);
-static_assert(!std::is_copy_assignable_v<std::wspanstream>);
-#endif
+  // Move properties
+
+  static_assert(!std::is_copy_constructible_v<SpStream>);
+  static_assert(!std::is_copy_assignable_v<SpStream>);
 
-// Move properties
+  // Move properties
 
-static_assert(!std::is_copy_constructible_v<std::spanstream>);
-static_assert(!std::is_copy_assignable_v<std::spanstream>);
+  static_assert(std::is_move_constructible_v<SpStream>);
+  static_assert(std::is_move_assignable_v<SpStream>);
+}
 
+void test() {
+  test<char>();
+  test<char, constexpr_char_traits<char>>();
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
-static_assert(!std::is_copy_constructible_v<std::wspanstream>);
-static_assert(!std::is_copy_assignable_v<std::wspanstream>);
+  test<wchar_t>();
+  test<wchar_t, constexpr_char_traits<wchar_t>>();
 #endif
+}
 
-// Move properties
-
-static_assert(std::is_move_constructible_v<std::spanstream>);
-static_assert(std::is_move_assignable_v<std::spanstream>);
+// Aliases
 
+static_assert(std::is_base_of_v<std::basic_iostream<char>, std::spanstream>);
+static_assert(std::is_same_v<std::basic_spanstream<char>, std::spanstream>);
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
-static_assert(std::is_move_constructible_v<std::wspanstream>);
-static_assert(std::is_move_assignable_v<std::wspanstream>);
+static_assert(std::is_base_of_v<std::basic_iostream<wchar_t>, std::wspanstream>);
+static_assert(std::is_same_v<std::basic_spanstream<wchar_t>, std::wspanstream>);
 #endif

>From 2a207f39cc6f82375a2dd69555f9d9bbb8ddb766 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Wed, 28 Feb 2024 19:38:58 +0200
Subject: [PATCH 04/56] Implementation: added `_LIBCPP_HIDE_FROM_ABI`

---
 libcxx/include/__fwd/spanstream.h |  8 ++--
 libcxx/include/spanstream         | 74 +++++++++++++++++--------------
 2 files changed, 44 insertions(+), 38 deletions(-)

diff --git a/libcxx/include/__fwd/spanstream.h b/libcxx/include/__fwd/spanstream.h
index 2afeaaecf7fb4..f5ff2ad2c9cfc 100644
--- a/libcxx/include/__fwd/spanstream.h
+++ b/libcxx/include/__fwd/spanstream.h
@@ -20,13 +20,13 @@ _LIBCPP_BEGIN_NAMESPACE_STD
 
 #if _LIBCPP_STD_VER >= 23
 
-template <class _CharT, class traits = char_traits<_CharT>>
+template <class _CharT, class _Traits = char_traits<_CharT>>
 class _LIBCPP_TEMPLATE_VIS basic_spanbuf;
-template <class _CharT, class traits = char_traits<_CharT>>
+template <class _CharT, class _Traits = char_traits<_CharT>>
 class _LIBCPP_TEMPLATE_VIS basic_ispanstream;
-template <class _CharT, class traits = char_traits<_CharT>>
+template <class _CharT, class _Traits = char_traits<_CharT>>
 class _LIBCPP_TEMPLATE_VIS basic_ospanstream;
-template <class _CharT, class traits = char_traits<_CharT>>
+template <class _CharT, class _Traits = char_traits<_CharT>>
 class _LIBCPP_TEMPLATE_VIS basic_spanstream;
 
 using spanbuf     = basic_spanbuf<char>;
diff --git a/libcxx/include/spanstream b/libcxx/include/spanstream
index ffaba85ef252c..16bbf04d81c55 100644
--- a/libcxx/include/spanstream
+++ b/libcxx/include/spanstream
@@ -105,6 +105,7 @@ public:
   }
 
   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_)},
@@ -113,6 +114,7 @@ public:
   // [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);
@@ -213,13 +215,13 @@ private:
 };
 
 template <class _CharT, class _Traits>
-void swap(basic_spanbuf<_CharT, _Traits>& __x, basic_spanbuf<_CharT, _Traits>& __y) {
+_LIBCPP_HIDE_FROM_ABI void swap(basic_spanbuf<_CharT, _Traits>& __x, basic_spanbuf<_CharT, _Traits>& __y) {
   __x.swap(__y);
 }
 
-using spanbuf = basic_spanbuf<char>;
+using std::spanbuf;
 #  ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
-using wspanbuf = basic_spanbuf<wchar_t>;
+using std::wspanbuf;
 #  endif
 
 // Class template basic_ispanstream [ispanstream]
@@ -235,27 +237,28 @@ public:
 
   // [ispanstream.cons], constructors
 
-  explicit basic_ispanstream(std::span<_CharT> __s, ios_base::openmode __which = ios_base::in)
+  _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;
 
-  basic_ispanstream(basic_ispanstream&& __rhs)
+  _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>>
-  explicit basic_ispanstream(_ROSeq&& __s) : basic_istream<_CharT, _Traits>(std::addressof(__sb_)) {
+  _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;
 
-  basic_ispanstream& operator=(basic_ispanstream&& __rhs) {
+  _LIBCPP_HIDE_FROM_ABI basic_ispanstream& operator=(basic_ispanstream&& __rhs) {
     basic_ispanstream __tmp{std::move(__rhs)};
     this->swap(__tmp);
     return *this;
@@ -263,24 +266,24 @@ public:
 
   // [ispanstream.swap], swap
 
-  void swap(basic_ispanstream& __rhs) {
+  _LIBCPP_HIDE_FROM_ABI void swap(basic_ispanstream& __rhs) {
     basic_istream<_CharT, _Traits>::swap(__rhs);
     __sb_.swap(__rhs.__sb_);
   }
 
   // [ispanstream.members], member functions
 
-  basic_spanbuf<_CharT, _Traits>* rdbuf() const noexcept {
+  _LIBCPP_HIDE_FROM_ABI basic_spanbuf<_CharT, _Traits>* rdbuf() const noexcept {
     return const_cast<basic_spanbuf<_CharT, _Traits>*>(std::addressof(__sb_));
   }
 
-  std::span<const _CharT> span() const noexcept { return rdbuf()->span(); }
+  _LIBCPP_HIDE_FROM_ABI std::span<const _CharT> span() const noexcept { return rdbuf()->span(); }
 
-  void span(std::span<_CharT> __s) noexcept { rdbuf()->span(__s); }
+  _LIBCPP_HIDE_FROM_ABI void span(std::span<_CharT> __s) noexcept { rdbuf()->span(__s); }
 
   template <ranges::borrowed_range _ROSeq>
     requires(!convertible_to<_ROSeq, std::span<_CharT>>) && convertible_to<_ROSeq, std::span<const _CharT>>
-  void span(_ROSeq&& __s) noexcept {
+  _LIBCPP_HIDE_FROM_ABI void span(_ROSeq&& __s) noexcept {
     std::span<const _CharT> __sp(std::forward<_ROSeq>(__s));
     this->span(std::span<_CharT>(const_cast<_CharT*>(__sp.data()), __sp.size()));
   }
@@ -290,13 +293,13 @@ private:
 };
 
 template <class _CharT, class _Traits>
-void swap(basic_ispanstream<_CharT, _Traits>& __x, basic_ispanstream<_CharT, _Traits>& __y) {
+_LIBCPP_HIDE_FROM_ABI void swap(basic_ispanstream<_CharT, _Traits>& __x, basic_ispanstream<_CharT, _Traits>& __y) {
   __x.swap(__y);
 }
 
-using ispanstream = basic_ispanstream<char>;
+using std::ispanstream;
 #  ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
-using wispanstream = basic_ispanstream<wchar_t>;
+using std::wispanstream;
 #  endif
 
 // Class template basic_ospanstream [ospanstream]
@@ -312,19 +315,20 @@ public:
 
   // [ospanstream.cons], constructors
 
-  explicit basic_ospanstream(std::span<_CharT> __s, ios_base::openmode __which = ios_base::out)
+  _LIBCPP_HIDE_FROM_ABI explicit basic_ospanstream(std::span<_CharT> __s, ios_base::openmode __which = ios_base::out)
       : basic_ostream<_CharT, _Traits>(std::addressof(__sb_)),
         __sb_(basic_spanbuf<_CharT, _Traits>(__s, __which | ios_base::out)) {}
 
   basic_ospanstream(const basic_ospanstream&) = delete;
 
-  basic_ospanstream(basic_ospanstream&& __rhs) : basic_ospanstream(std::move(__rhs)), __sb_(std::move(__rhs.__sb_)) {
+  _LIBCPP_HIDE_FROM_ABI basic_ospanstream(basic_ospanstream&& __rhs)
+      : basic_ospanstream(std::move(__rhs)), __sb_(std::move(__rhs.__sb_)) {
     basic_ostream<_CharT, _Traits>::set_rdbuf(std::addressof(__sb_));
   }
 
   basic_ospanstream& operator=(const basic_ospanstream&) = delete;
 
-  basic_ospanstream& operator=(basic_ospanstream&& __rhs) {
+  _LIBCPP_HIDE_FROM_ABI basic_ospanstream& operator=(basic_ospanstream&& __rhs) {
     basic_ospanstream __tmp{std::move(__rhs)};
     this->swap(__tmp);
     return *this;
@@ -332,31 +336,31 @@ public:
 
   // [ospanstream.swap], swap
 
-  void swap(basic_ospanstream& __rhs) {
+  _LIBCPP_HIDE_FROM_ABI void swap(basic_ospanstream& __rhs) {
     basic_ostream<_CharT, _Traits>::swap(__rhs);
     __sb_.swap(__rhs.__sb_);
   }
 
   // [ospanstream.members], member functions
 
-  basic_spanbuf<_CharT, _Traits>* rdbuf() const noexcept { return __sb_; }
+  _LIBCPP_HIDE_FROM_ABI basic_spanbuf<_CharT, _Traits>* rdbuf() const noexcept { return __sb_; }
 
-  std::span<_CharT> span() const noexcept { return __sb_.rdbuf()->span(); }
+  _LIBCPP_HIDE_FROM_ABI std::span<_CharT> span() const noexcept { return __sb_.rdbuf()->span(); }
 
-  void span(std::span<_CharT> __s) noexcept { rdbuf()->span(__s); }
+  _LIBCPP_HIDE_FROM_ABI void span(std::span<_CharT> __s) noexcept { rdbuf()->span(__s); }
 
 private:
   basic_spanbuf<_CharT, _Traits> __sb_; // exposition only
 };
 
 template <class _CharT, class _Traits>
-void swap(basic_ospanstream<_CharT, _Traits>& __x, basic_ospanstream<_CharT, _Traits>& __y) {
+_LIBCPP_HIDE_FROM_ABI void swap(basic_ospanstream<_CharT, _Traits>& __x, basic_ospanstream<_CharT, _Traits>& __y) {
   __x.swap(__y);
 }
 
-using ospanstream = basic_ospanstream<char>;
+using std::ospanstream;
 #  ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
-using wospanstream = basic_ospanstream<wchar_t>;
+using std::wospanstream;
 #  endif
 
 template <class _CharT, class _Traits>
@@ -370,18 +374,20 @@ public:
 
   // [spanstream.cons], constructors
 
-  explicit basic_spanstream(std::span<_CharT> __s, ios_base::openmode __which = ios_base::out | ios_base::in)
+  _LIBCPP_HIDE_FROM_ABI explicit basic_spanstream(std::span<_CharT> __s,
+                                                  ios_base::openmode __which = ios_base::out | ios_base::in)
       : basic_iostream<_CharT, _Traits>(std::addressof(__sb_)), __sb_(basic_spanbuf<_CharT, _Traits>(__s, __which)) {}
 
   basic_spanstream(const basic_spanstream&) = delete;
 
-  basic_spanstream(basic_spanstream&& __rhs) : basic_spanstream(std::move(__rhs)), __sb_(__rhs.__sb_) {
+  _LIBCPP_HIDE_FROM_ABI basic_spanstream(basic_spanstream&& __rhs)
+      : basic_spanstream(std::move(__rhs)), __sb_(__rhs.__sb_) {
     basic_iostream<_CharT, _Traits>::set_rdbuf(std::addressof(__sb_));
   }
 
   basic_spanstream& operator=(const basic_spanstream&) = delete;
 
-  basic_spanstream& operator=(basic_spanstream&& __rhs) {
+  _LIBCPP_HIDE_FROM_ABI basic_spanstream& operator=(basic_spanstream&& __rhs) {
     basic_spanstream __tmp{std::move(__rhs)};
     this->swap(__tmp);
     return *this;
@@ -396,24 +402,24 @@ public:
 
   // [spanstream.members], members
 
-  basic_spanbuf<_CharT, _Traits>* rdbuf() const noexcept { return __sb_; }
+  _LIBCPP_HIDE_FROM_ABI basic_spanbuf<_CharT, _Traits>* rdbuf() const noexcept { return __sb_; }
 
-  std::span<_CharT> span() const noexcept { return rdbuf()->span(); }
+  _LIBCPP_HIDE_FROM_ABI std::span<_CharT> span() const noexcept { return rdbuf()->span(); }
 
-  void span(std::span<_CharT> __s) noexcept { rdbuf()->span(__s); }
+  _LIBCPP_HIDE_FROM_ABI void span(std::span<_CharT> __s) noexcept { rdbuf()->span(__s); }
 
 private:
   basic_spanbuf<_CharT, _Traits> __sb_; // exposition only
 };
 
 template <class _CharT, class _Traits>
-void swap(basic_spanstream<_CharT, _Traits>& __x, basic_spanstream<_CharT, _Traits>& __y) {
+_LIBCPP_HIDE_FROM_ABI void swap(basic_spanstream<_CharT, _Traits>& __x, basic_spanstream<_CharT, _Traits>& __y) {
   __x.swap(__y);
 }
 
-using spanstream = basic_spanstream<char>;
+using std::spanstream;
 #  ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
-using wspanstream = basic_spanstream<wchar_t>;
+using std::wspanstream;
 #  endif
 
 #endif // _LIBCPP_STD_VER >= 23

>From 5c9ead0e830ef80fa84dc1d0bda1c805d285cca2 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Thu, 29 Feb 2024 11:05:55 +0200
Subject: [PATCH 05/56] Tests: `spanbuf` constructor tests

---
 .../ispanstream/types.compile.pass.cpp        |  14 +-
 .../std/input.output/span.streams/macros.h    |  18 ++
 .../ospanstream/types.compile.pass.cpp        |  14 +-
 .../spanbuf/spanbuf.cons/default.pass.cpp     |  25 +-
 .../spanbuf/spanbuf.cons/mode.pass.cpp        |  96 ++++++++
 .../spanbuf/spanbuf.cons/move.pass.cpp        | 224 ++++++++++++++++++
 .../spanbuf/spanbuf.cons/span.mode.pass.cpp   | 155 ++++++++++++
 .../spanbuf/types.compile.pass.cpp            |  14 +-
 .../spanstream/types.compile.pass.cpp         |  14 +-
 .../std/input.output/span.streams/types.h     |  73 ++++++
 10 files changed, 615 insertions(+), 32 deletions(-)
 create mode 100644 libcxx/test/std/input.output/span.streams/macros.h
 create mode 100644 libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/mode.pass.cpp
 create mode 100644 libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/move.pass.cpp
 create mode 100644 libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/span.mode.pass.cpp
 create mode 100644 libcxx/test/std/input.output/span.streams/types.h

diff --git a/libcxx/test/std/input.output/span.streams/ispanstream/types.compile.pass.cpp b/libcxx/test/std/input.output/span.streams/ispanstream/types.compile.pass.cpp
index 9615d270116ee..c566a3fce647d 100644
--- a/libcxx/test/std/input.output/span.streams/ispanstream/types.compile.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/ispanstream/types.compile.pass.cpp
@@ -30,18 +30,18 @@
 #include "constexpr_char_traits.h"
 #include "test_macros.h"
 
-template <typename CharT, typename Traits = std::char_traits<CharT>>
+template <typename CharT, typename TraitsT = std::char_traits<CharT>>
 void test() {
-  using SpStream = std::basic_ispanstream<CharT, Traits>;
+  using SpStream = std::basic_ispanstream<CharT, TraitsT>;
 
   // Types
 
-  static_assert(std::is_base_of_v<std::basic_istream<CharT, Traits>, SpStream>);
+  static_assert(std::is_base_of_v<std::basic_istream<CharT, TraitsT>, SpStream>);
   static_assert(std::is_same_v<typename SpStream::char_type, CharT>);
-  static_assert(std::is_same_v<typename SpStream::int_type, typename Traits::int_type>);
-  static_assert(std::is_same_v<typename SpStream::pos_type, typename Traits::pos_type>);
-  static_assert(std::is_same_v<typename SpStream::off_type, typename Traits::off_type>);
-  static_assert(std::is_same_v<typename SpStream::traits_type, Traits>);
+  static_assert(std::is_same_v<typename SpStream::int_type, typename TraitsT::int_type>);
+  static_assert(std::is_same_v<typename SpStream::pos_type, typename TraitsT::pos_type>);
+  static_assert(std::is_same_v<typename SpStream::off_type, typename TraitsT::off_type>);
+  static_assert(std::is_same_v<typename SpStream::traits_type, TraitsT>);
 
   // Copy properties
 
diff --git a/libcxx/test/std/input.output/span.streams/macros.h b/libcxx/test/std/input.output/span.streams/macros.h
new file mode 100644
index 0000000000000..679686eaa41a8
--- /dev/null
+++ b/libcxx/test/std/input.output/span.streams/macros.h
@@ -0,0 +1,18 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 TEST_STD_INPUTOUTPUT_SPANSTREAMS_MACROS_H
+#define TEST_STD_INPUTOUTPUT_SPANSTREAMS_MACROS_H
+
+#include "make_string.h"
+
+#define CS(S) MAKE_CSTRING(CharT, S)
+#define ST(S, a) std::basic_string<CharT, TraitsT, AllocT>(MAKE_CSTRING(CharT, S), MKSTR_LEN(CharT, S), a)
+#define SV(S) std::basic_string_view<CharT, TraitsT>(MAKE_CSTRING(CharT, S), MKSTR_LEN(CharT, S))
+
+#endif // TEST_STD_INPUTOUTPUT_SPANSTREAMS_MACROS_H
diff --git a/libcxx/test/std/input.output/span.streams/ospanstream/types.compile.pass.cpp b/libcxx/test/std/input.output/span.streams/ospanstream/types.compile.pass.cpp
index e5a9e574eb39f..595770aa5bd6b 100644
--- a/libcxx/test/std/input.output/span.streams/ospanstream/types.compile.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/ospanstream/types.compile.pass.cpp
@@ -30,18 +30,18 @@
 #include "constexpr_char_traits.h"
 #include "test_macros.h"
 
-template <typename CharT, typename Traits = std::char_traits<CharT>>
+template <typename CharT, typename TraitsT = std::char_traits<CharT>>
 void test() {
-  using SpStream = std::basic_ospanstream<CharT, Traits>;
+  using SpStream = std::basic_ospanstream<CharT, TraitsT>;
 
   // Types
 
-  static_assert(std::is_base_of_v<std::basic_ostream<CharT, Traits>, SpStream>);
+  static_assert(std::is_base_of_v<std::basic_ostream<CharT, TraitsT>, SpStream>);
   static_assert(std::is_same_v<typename SpStream::char_type, CharT>);
-  static_assert(std::is_same_v<typename SpStream::int_type, typename Traits::int_type>);
-  static_assert(std::is_same_v<typename SpStream::pos_type, typename Traits::pos_type>);
-  static_assert(std::is_same_v<typename SpStream::off_type, typename Traits::off_type>);
-  static_assert(std::is_same_v<typename SpStream::traits_type, Traits>);
+  static_assert(std::is_same_v<typename SpStream::int_type, typename TraitsT::int_type>);
+  static_assert(std::is_same_v<typename SpStream::pos_type, typename TraitsT::pos_type>);
+  static_assert(std::is_same_v<typename SpStream::off_type, typename TraitsT::off_type>);
+  static_assert(std::is_same_v<typename SpStream::traits_type, TraitsT>);
 
   // Copy properties
 
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/default.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/default.pass.cpp
index 4675c0e5fc299..4c6b1ae3080d9 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/default.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/default.pass.cpp
@@ -21,19 +21,36 @@
 #include <spanstream>
 
 #include "constexpr_char_traits.h"
+#include "nasty_string.h"
 #include "test_macros.h"
 
-template <typename CharT, typename Traits = std::char_traits<CharT>>
-void test() {
-  using SpanBuf = std::basic_spanbuf<CharT, Traits>;
+void test_sfinae_with_nasty_char() {
+  using SpBuf = std::basic_spanbuf<nasty_char, nasty_char_traits>;
+
+  static_assert(std::default_initializable<SpBuf>);
+}
+
+template <typename CharT, typename TraitsT = std::char_traits<CharT>>
+void test_sfinae() {
+  using SpBuf = std::basic_spanbuf<CharT, TraitsT>;
 
-  static_assert(std::default_initializable<SpanBuf>);
+  static_assert(std::default_initializable<SpBuf>);
+}
+
+template <typename CharT, typename TraitsT = std::char_traits<CharT>>
+void test() {
+  using SpanBuf = std::basic_spanbuf<CharT, TraitsT>;
 
   SpanBuf spBuf;
+  assert(spBuf.span().data() == nullptr);
   assert(spBuf.span().empty());
+  assert(spBuf.span().size() == 0);
 }
 
 int main(int, char**) {
+  test_sfinae_with_nasty_char();
+  test_sfinae<char>();
+  test_sfinae<char, constexpr_char_traits<char>>();
   test<char>();
   test<char, constexpr_char_traits<char>>();
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/mode.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/mode.pass.cpp
new file mode 100644
index 0000000000000..5a497e5b3238c
--- /dev/null
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/mode.pass.cpp
@@ -0,0 +1,96 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <spanstream>
+
+//   template<class charT, class traits = char_traits<charT>>
+//   class basic_spanbuf
+//     : public basic_streambuf<charT, traits> {
+
+//     // [spanbuf.cons], constructors
+//
+//     explicit basic_spanbuf(ios_base::openmode which);
+
+#include <cassert>
+#include <concepts>
+#include <span>
+#include <spanstream>
+
+#include "constexpr_char_traits.h"
+#include "nasty_string.h"
+#include "test_convertible.h"
+#include "test_macros.h"
+
+#include "../../types.h"
+
+void test_sfinae_with_nasty_char() {
+  using SpBuf = std::basic_spanbuf<nasty_char, nasty_char_traits>;
+
+  static_assert(std::constructible_from<SpBuf, std::ios_base::openmode>);
+  static_assert(!test_convertible<SpBuf, std::ios_base::openmode>());
+}
+
+template <typename CharT, typename TraitsT = std::char_traits<CharT>>
+void test_sfinae() {
+  using SpBuf = std::basic_spanbuf<CharT, TraitsT>;
+
+  // `Mode`
+  static_assert(std::constructible_from<SpBuf, std::ios_base::openmode>);
+  static_assert(!test_convertible<SpBuf, std::ios_base::openmode>());
+
+  // Non-mode
+  static_assert(!std::constructible_from<SpBuf, const NonMode>);
+  static_assert(!test_convertible<SpBuf, const NonMode>());
+}
+
+template <typename CharT, typename TraitsT = std::char_traits<CharT>>
+void test() {
+  using SpBuf = std::basic_spanbuf<CharT, TraitsT>;
+
+  static_assert(std::default_initializable<SpBuf>);
+
+  // Mode: `in`
+  {
+    SpBuf spBuf(std::ios_base::in);
+    assert(spBuf.span().data() == nullptr);
+    assert(spBuf.span().empty());
+    assert(spBuf.span().size() == 0);
+  }
+  // Mode: `out`
+  {
+    SpBuf spBuf(std::ios_base::out);
+    assert(spBuf.span().data() == nullptr);
+    assert(spBuf.span().empty());
+    assert(spBuf.span().size() == 0);
+  }
+  // Mode: multiple
+  {
+    SpBuf spBuf(std::ios_base::out | std::ios_base::in | std::ios_base::binary);
+    assert(spBuf.span().data() == nullptr);
+    assert(spBuf.span().empty());
+    assert(spBuf.span().size() == 0);
+  }
+}
+
+int main(int, char**) {
+  test_sfinae_with_nasty_char();
+  test_sfinae<char>();
+  test_sfinae<char, constexpr_char_traits<char>>();
+  test<char>();
+  test<char, constexpr_char_traits<char>>();
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  test_sfinae<wchar_t>();
+  test_sfinae<wchar_t, constexpr_char_traits<wchar_t>>();
+  test<wchar_t>();
+  test<wchar_t, constexpr_char_traits<wchar_t>>();
+#endif
+
+  return 0;
+}
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/move.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/move.pass.cpp
new file mode 100644
index 0000000000000..cfc67b07ea303
--- /dev/null
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/move.pass.cpp
@@ -0,0 +1,224 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <spanstream>
+
+//   template<class charT, class traits = char_traits<charT>>
+//   class basic_spanbuf
+//     : public basic_streambuf<charT, traits> {
+
+//     // [spanbuf.cons], constructors
+//
+//     basic_spanbuf(basic_spanbuf&& rhs);
+
+#include <cassert>
+#include <concepts>
+#include <span>
+#include <spanstream>
+
+#include "constexpr_char_traits.h"
+#include "nasty_string.h"
+#include "test_convertible.h"
+#include "test_macros.h"
+
+template <typename CharT, typename TraitsT>
+struct TestSpanBuf : std::basic_spanbuf<CharT, TraitsT> {
+  using std::basic_spanbuf<CharT, TraitsT>::basic_spanbuf;
+
+  TestSpanBuf(std::basic_spanbuf<CharT, TraitsT>&& rhs) : std::basic_spanbuf<CharT, TraitsT>(std::move(rhs)) {}
+
+  void check_postconditions(TestSpanBuf<CharT, TraitsT> const& rhs_p) const {
+    assert(this->span().data() == rhs_p.span().data());
+    assert(this->span().size() == rhs_p.span().size());
+    assert(this->eback() == rhs_p.eback());
+    assert(this->gptr() == rhs_p.gptr());
+    assert(this->egptr() == rhs_p.egptr());
+    assert(this->pbase() == rhs_p.pbase());
+    assert(this->pptr() == rhs_p.pptr());
+    assert(this->epptr() == rhs_p.epptr());
+    assert(this->getloc() == rhs_p.getloc());
+  }
+};
+
+void test_sfinae_with_nasty_char() {
+  using SpBuf = std::basic_spanbuf<nasty_char, nasty_char_traits>;
+
+  static_assert(std::move_constructible<SpBuf>);
+}
+
+template <typename CharT, typename TraitsT = std::char_traits<CharT>>
+void test_sfinae() {
+  using SpBuf = std::basic_spanbuf<CharT, TraitsT>;
+
+  static_assert(std::move_constructible<SpBuf>);
+}
+
+template <typename CharT, typename TraitsT = std::char_traits<CharT>>
+void test() {
+  using SpBuf = std::basic_spanbuf<CharT, TraitsT>;
+
+  {
+    // Empty `span`
+    {
+      // Mode: `ios_base::in`
+      {
+        SpBuf rhsSpBuf{std::ios_base::in};
+        SpBuf spBuf(std::move(rhsSpBuf));
+        assert(spBuf.span().data() == nullptr);
+        assert(spBuf.span().empty());
+        assert(spBuf.span().size() == 0);
+      }
+      // Mode: `ios_base::out`
+      {
+        SpBuf rhsSpBuf{std::ios_base::out};
+        SpBuf spBuf(std::move(rhsSpBuf));
+        assert(spBuf.span().data() == nullptr);
+        assert(spBuf.span().empty());
+        assert(spBuf.span().size() == 0);
+      }
+      // Mode: multiple
+      {
+        SpBuf rhsSpBuf{std::ios_base::out | std::ios_base::in};
+        SpBuf spBuf(std::move(rhsSpBuf));
+        assert(spBuf.span().data() == nullptr);
+        assert(spBuf.span().empty());
+        assert(spBuf.span().size() == 0);
+      }
+    }
+
+    // Non-empty `span`
+    {
+      CharT arr[4];
+      std::span<CharT> sp{arr};
+
+      // Mode: `ios_base::in`
+      {
+        SpBuf rhsSpBuf{sp, std::ios_base::in};
+        SpBuf spBuf(std::move(rhsSpBuf));
+        assert(spBuf.span().data() == arr);
+        assert(!spBuf.span().empty());
+        assert(spBuf.span().size() == 4);
+      }
+      // Mode `ios_base::out`
+      {
+        SpBuf rhsSpBuf{sp, std::ios_base::out};
+        SpBuf spBuf(std::move(rhsSpBuf));
+        assert(spBuf.span().data() == arr);
+        assert(spBuf.span().empty());
+        assert(spBuf.span().size() == 0);
+      }
+      // Mode: multiple
+      {
+        SpBuf rhsSpBuf{sp, std::ios_base::out | std::ios_base::in | std::ios_base::binary};
+        SpBuf spBuf(std::move(rhsSpBuf));
+        assert(spBuf.span().data() == arr);
+        assert(spBuf.span().empty());
+        assert(spBuf.span().size() == 0);
+      }
+    }
+  }
+
+  // Check post-conditions
+  {
+    // Empty `span`
+    {
+      {
+        std::span<CharT> sp;
+        TestSpanBuf<CharT, TraitsT> rhsSpBuf(sp);
+        TestSpanBuf<CharT, TraitsT> spBuf(std::move(static_cast<SpBuf&>(rhsSpBuf)));
+        assert(rhsSpBuf.span().empty());
+        assert(spBuf.span().data() == nullptr);
+        spBuf.check_postconditions(rhsSpBuf);
+      }
+      // Mode: `ios_base::in`
+      {
+        std::span<CharT> sp;
+        TestSpanBuf<CharT, TraitsT> rhsSpBuf(sp, std::ios_base::in);
+        TestSpanBuf<CharT, TraitsT> spBuf(std::move(static_cast<SpBuf&>(rhsSpBuf)));
+        assert(rhsSpBuf.span().empty());
+        assert(spBuf.span().data() == nullptr);
+        spBuf.check_postconditions(rhsSpBuf);
+      }
+      // Mode: `ios_base::out`
+      {
+        std::span<CharT> sp;
+        TestSpanBuf<CharT, TraitsT> rhsSpBuf(sp, std::ios_base::out);
+        TestSpanBuf<CharT, TraitsT> spBuf(std::move(static_cast<SpBuf&>(rhsSpBuf)));
+        assert(rhsSpBuf.span().empty());
+        assert(spBuf.span().data() == nullptr);
+        spBuf.check_postconditions(rhsSpBuf);
+      }
+      // Mode: multiple
+      {
+        std::span<CharT> sp;
+        TestSpanBuf<CharT, TraitsT> rhsSpBuf(sp, std::ios_base::out | std::ios_base::in | std::ios_base::binary);
+        TestSpanBuf<CharT, TraitsT> spBuf(std::move(static_cast<SpBuf&>(rhsSpBuf)));
+        assert(rhsSpBuf.span().empty());
+        assert(spBuf.span().data() == nullptr);
+        spBuf.check_postconditions(rhsSpBuf);
+      }
+    }
+
+    // Non-empty `span`
+    {
+      CharT arr[4];
+
+      {
+        std::span<CharT> sp{arr};
+        TestSpanBuf<CharT, TraitsT> rhsSpBuf(sp);
+        TestSpanBuf<CharT, TraitsT> spBuf(std::move(static_cast<SpBuf&>(rhsSpBuf)));
+        assert(rhsSpBuf.span().empty());
+        assert(spBuf.span().data() == arr);
+        spBuf.check_postconditions(rhsSpBuf);
+      }
+      // Mode: `ios_base::in`
+      {
+        std::span<CharT> sp{arr};
+        TestSpanBuf<CharT, TraitsT> rhsSpBuf(sp, std::ios_base::in);
+        TestSpanBuf<CharT, TraitsT> spBuf(std::move(static_cast<SpBuf&>(rhsSpBuf)));
+        assert(!rhsSpBuf.span().empty());
+        assert(spBuf.span().data() == arr);
+        spBuf.check_postconditions(rhsSpBuf);
+      }
+      // Mode: `ios_base::out`
+      {
+        std::span<CharT> sp{arr};
+        TestSpanBuf<CharT, TraitsT> rhsSpBuf(sp, std::ios_base::out);
+        TestSpanBuf<CharT, TraitsT> spBuf(std::move(static_cast<SpBuf&>(rhsSpBuf)));
+        assert(rhsSpBuf.span().empty());
+        assert(spBuf.span().data() == arr);
+        spBuf.check_postconditions(rhsSpBuf);
+      }
+      // Mode: multiple
+      {
+        std::span<CharT> sp{arr};
+        TestSpanBuf<CharT, TraitsT> rhsSpBuf(sp, std::ios_base::out | std::ios_base::in | std::ios_base::binary);
+        TestSpanBuf<CharT, TraitsT> spBuf(std::move(static_cast<SpBuf&>(rhsSpBuf)));
+        assert(rhsSpBuf.span().empty());
+        assert(spBuf.span().data() == arr);
+        spBuf.check_postconditions(rhsSpBuf);
+      }
+    }
+  }
+}
+
+int main(int, char**) {
+  test_sfinae_with_nasty_char();
+  test_sfinae<char>();
+  test_sfinae<char, constexpr_char_traits<char>>();
+  test<char>();
+  test<char, constexpr_char_traits<char>>();
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  test<wchar_t>();
+  test<wchar_t, constexpr_char_traits<wchar_t>>();
+#endif
+
+  return 0;
+}
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/span.mode.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/span.mode.pass.cpp
new file mode 100644
index 0000000000000..fb58235d8c1fe
--- /dev/null
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/span.mode.pass.cpp
@@ -0,0 +1,155 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <spanstream>
+
+//   template<class charT, class traits = char_traits<charT>>
+//   class basic_spanbuf
+//     : public basic_streambuf<charT, traits> {
+
+//     // [spanbuf.cons], constructors
+//
+//     explicit basic_spanbuf(std::span<charT> s,
+//                            ios_base::openmode which = ios_base::in | ios_base::out);
+
+#include <cassert>
+#include <concepts>
+#include <span>
+#include <spanstream>
+#include <utility>
+
+#include "constexpr_char_traits.h"
+#include "nasty_string.h"
+#include "test_convertible.h"
+#include "test_macros.h"
+
+#include "../../macros.h"
+#include "../../types.h"
+
+void test_sfinae_with_nasty_char() {
+  using SpBuf = std::basic_spanbuf<nasty_char, nasty_char_traits>;
+
+  static_assert(std::constructible_from<SpBuf, const std::span<nasty_char>, std::ios_base::openmode>);
+  static_assert(!test_convertible<SpBuf, std::ios_base::openmode>());
+}
+
+template <typename CharT, typename TraitsT = std::char_traits<CharT>>
+void test_sfinae() {
+  using SpBuf = std::basic_spanbuf<CharT, TraitsT>;
+
+  // `Mode`
+  static_assert(std::constructible_from<SpBuf, const std::span<CharT>, std::ios_base::openmode>);
+  static_assert(!test_convertible<SpBuf, const std::span<CharT>, std::ios_base::openmode>());
+
+  // Non-mode
+  static_assert(!std::constructible_from<SpBuf, const std::span<CharT>, const NonMode>);
+  static_assert(!test_convertible<SpBuf, const std::span<CharT>, const NonMode>());
+}
+
+template <typename CharT, typename TraitsT = std::char_traits<CharT>>
+void test() {
+  using SpBuf = std::basic_spanbuf<CharT, TraitsT>;
+
+  static_assert(std::default_initializable<SpBuf>);
+
+  // Empty `span`
+  {
+    std::span<CharT> sp{};
+
+    // Mode: `ios_base::in`
+    {
+      SpBuf spBuf(sp, std::ios_base::in);
+      assert(spBuf.span().data() == nullptr);
+      assert(spBuf.span().empty());
+      assert(spBuf.span().size() == 0);
+    }
+    {
+      SpBuf spBuf(std::as_const(sp), std::ios_base::in);
+      assert(spBuf.span().data() == nullptr);
+      assert(spBuf.span().empty());
+      assert(spBuf.span().size() == 0);
+    }
+    // Mode: `ios_base::out`
+    {
+      SpBuf spBuf(sp, std::ios_base::out);
+      assert(spBuf.span().data() == nullptr);
+      assert(spBuf.span().empty());
+      assert(spBuf.span().size() == 0);
+    }
+    {
+      SpBuf spBuf(std::as_const(sp), std::ios_base::out);
+      assert(spBuf.span().data() == nullptr);
+      assert(spBuf.span().empty());
+      assert(spBuf.span().size() == 0);
+    }
+  }
+
+  // Non-empty `span`
+  {
+    CharT arr[4];
+    std::span<CharT> sp{arr};
+
+    // Mode: `ios_base::in`
+    {
+      SpBuf spBuf(sp, std::ios_base::in);
+      assert(spBuf.span().data() == arr);
+      assert(!spBuf.span().empty());
+      assert(spBuf.span().size() == 4);
+    }
+    {
+      SpBuf spBuf(std::as_const(sp), std::ios_base::in);
+      assert(spBuf.span().data() == arr);
+      assert(!spBuf.span().empty());
+      assert(spBuf.span().size() == 4);
+    }
+    // Mode `ios_base::out`
+    {
+      SpBuf spBuf(sp, std::ios_base::out);
+      assert(spBuf.span().data() == arr);
+      assert(spBuf.span().empty());
+      assert(spBuf.span().size() == 0);
+    }
+    {
+      SpBuf spBuf(std::as_const(sp), std::ios_base::out);
+      assert(spBuf.span().data() == arr);
+      assert(spBuf.span().empty());
+      assert(spBuf.span().size() == 0);
+    }
+    // Mode: multiple
+    {
+      SpBuf spBuf(sp, std::ios_base::out | std::ios_base::in);
+      assert(spBuf.span().data() == arr);
+      assert(spBuf.span().empty());
+      assert(spBuf.span().size() == 0);
+    }
+    {
+      SpBuf spBuf(std::as_const(sp), std::ios_base::out | std::ios_base::in | std::ios_base::binary);
+      assert(spBuf.span().data() == arr);
+      assert(spBuf.span().empty());
+      assert(spBuf.span().size() == 0);
+    }
+  }
+}
+
+int main(int, char**) {
+  test_sfinae_with_nasty_char();
+  test_sfinae<char>();
+  test_sfinae<char, constexpr_char_traits<char>>();
+  test<char>();
+  test<char, constexpr_char_traits<char>>();
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  test_sfinae<wchar_t>();
+  test_sfinae<wchar_t, constexpr_char_traits<wchar_t>>();
+  test<wchar_t>();
+  test<wchar_t, constexpr_char_traits<wchar_t>>();
+#endif
+
+  return 0;
+}
\ No newline at end of file
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/types.compile.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/types.compile.pass.cpp
index a8cc07ed524ea..4c18422ebff28 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/types.compile.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/types.compile.pass.cpp
@@ -30,18 +30,18 @@
 #include "constexpr_char_traits.h"
 #include "test_macros.h"
 
-template <typename CharT, typename Traits = std::char_traits<CharT>>
+template <typename CharT, typename TraitsT = std::char_traits<CharT>>
 void test() {
-  using SpBuf = std::basic_spanbuf<CharT, Traits>;
+  using SpBuf = std::basic_spanbuf<CharT, TraitsT>;
 
   // Types
 
-  static_assert(std::is_base_of_v<std::basic_streambuf<CharT, Traits>, SpBuf>);
+  static_assert(std::is_base_of_v<std::basic_streambuf<CharT, TraitsT>, SpBuf>);
   static_assert(std::is_same_v<typename SpBuf::char_type, CharT>);
-  static_assert(std::is_same_v<typename SpBuf::int_type, typename Traits::int_type>);
-  static_assert(std::is_same_v<typename SpBuf::pos_type, typename Traits::pos_type>);
-  static_assert(std::is_same_v<typename SpBuf::off_type, typename Traits::off_type>);
-  static_assert(std::is_same_v<typename SpBuf::traits_type, Traits>);
+  static_assert(std::is_same_v<typename SpBuf::int_type, typename TraitsT::int_type>);
+  static_assert(std::is_same_v<typename SpBuf::pos_type, typename TraitsT::pos_type>);
+  static_assert(std::is_same_v<typename SpBuf::off_type, typename TraitsT::off_type>);
+  static_assert(std::is_same_v<typename SpBuf::traits_type, TraitsT>);
 
   // Copy properties
 
diff --git a/libcxx/test/std/input.output/span.streams/spanstream/types.compile.pass.cpp b/libcxx/test/std/input.output/span.streams/spanstream/types.compile.pass.cpp
index 5714834be2ce1..67d29cf041d9c 100644
--- a/libcxx/test/std/input.output/span.streams/spanstream/types.compile.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanstream/types.compile.pass.cpp
@@ -30,18 +30,18 @@
 #include "constexpr_char_traits.h"
 #include "test_macros.h"
 
-template <typename CharT, typename Traits = std::char_traits<CharT>>
+template <typename CharT, typename TraitsT = std::char_traits<CharT>>
 void test() {
-  using SpStream = std::basic_spanstream<CharT, Traits>;
+  using SpStream = std::basic_spanstream<CharT, TraitsT>;
 
   // Types
 
-  static_assert(std::is_base_of_v<std::basic_iostream<CharT, Traits>, SpStream>);
+  static_assert(std::is_base_of_v<std::basic_iostream<CharT, TraitsT>, SpStream>);
   static_assert(std::is_same_v<typename SpStream::char_type, CharT>);
-  static_assert(std::is_same_v<typename SpStream::int_type, typename Traits::int_type>);
-  static_assert(std::is_same_v<typename SpStream::pos_type, typename Traits::pos_type>);
-  static_assert(std::is_same_v<typename SpStream::off_type, typename Traits::off_type>);
-  static_assert(std::is_same_v<typename SpStream::traits_type, Traits>);
+  static_assert(std::is_same_v<typename SpStream::int_type, typename TraitsT::int_type>);
+  static_assert(std::is_same_v<typename SpStream::pos_type, typename TraitsT::pos_type>);
+  static_assert(std::is_same_v<typename SpStream::off_type, typename TraitsT::off_type>);
+  static_assert(std::is_same_v<typename SpStream::traits_type, TraitsT>);
 
   // Copy properties
 
diff --git a/libcxx/test/std/input.output/span.streams/types.h b/libcxx/test/std/input.output/span.streams/types.h
new file mode 100644
index 0000000000000..18788a56579dc
--- /dev/null
+++ b/libcxx/test/std/input.output/span.streams/types.h
@@ -0,0 +1,73 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 TEST_STD_INPUTOUTPUT_SPANSTREAMS_TYPES_H
+#define TEST_STD_INPUTOUTPUT_SPANSTREAMS_TYPES_H
+
+#include <string_view>
+#include <concepts>
+
+#include "test_macros.h"
+
+// template <typename CharT, class Traits = std::char_traits<CharT>>
+// class ConstConvertibleStringView {
+// public:
+//   explicit ConstConvertibleStringView(const CharT* cs) : cs_{cs} {}
+
+//   operator std::basic_string_view<CharT, Traits>() = delete;
+//   operator std::basic_string_view<CharT, Traits>() const { return std::basic_string_view<CharT, Traits>(cs_); }
+
+// private:
+//   const CharT* cs_;
+// };
+
+// static_assert(!std::constructible_from<std::basic_string_view<char>, ConstConvertibleStringView<char>>);
+// static_assert(!std::convertible_to<ConstConvertibleStringView<char>, std::basic_string_view<char>>);
+
+// static_assert(std::constructible_from<std::basic_string_view<char>, const ConstConvertibleStringView<char>>);
+// static_assert(std::convertible_to<const ConstConvertibleStringView<char>, std::basic_string_view<char>>);
+
+// #ifndef TEST_HAS_NO_WIDE_CHARACTERS
+// static_assert(!std::constructible_from<std::basic_string_view<wchar_t>, ConstConvertibleStringView<wchar_t>>);
+// static_assert(!std::convertible_to<ConstConvertibleStringView<wchar_t>, std::basic_string_view<wchar_t>>);
+
+// static_assert(std::constructible_from<std::basic_string_view<wchar_t>, const ConstConvertibleStringView<wchar_t>>);
+// static_assert(std::convertible_to<const ConstConvertibleStringView<wchar_t>, std::basic_string_view<wchar_t>>);
+// #endif
+
+// template <typename CharT, class Traits = std::char_traits<CharT>>
+// class NonConstConvertibleStringView {
+// public:
+//   explicit NonConstConvertibleStringView(const CharT* cs) : cs_{cs} {}
+
+//   operator std::basic_string_view<CharT, Traits>() { return std::basic_string_view<CharT, Traits>(cs_); }
+//   operator std::basic_string_view<CharT, Traits>() const = delete;
+
+// private:
+//   const CharT* cs_;
+// };
+
+// static_assert(std::constructible_from<std::basic_string_view<char>, NonConstConvertibleStringView<char>>);
+// static_assert(std::convertible_to<NonConstConvertibleStringView<char>, std::basic_string_view<char>>);
+
+// static_assert(!std::constructible_from<std::basic_string_view<char>, const NonConstConvertibleStringView<char>>);
+// static_assert(!std::convertible_to<const NonConstConvertibleStringView<char>, std::basic_string_view<char>>);
+
+// #ifndef TEST_HAS_NO_WIDE_CHARACTERS
+// static_assert(std::constructible_from<std::basic_string_view<wchar_t>, NonConstConvertibleStringView<wchar_t>>);
+// static_assert(std::convertible_to<NonConstConvertibleStringView<wchar_t>, std::basic_string_view<wchar_t>>);
+
+// static_assert(!std::constructible_from<std::basic_string_view<wchar_t>, const NonConstConvertibleStringView<wchar_t>>);
+// static_assert(!std::convertible_to<const NonConstConvertibleStringView<wchar_t>, std::basic_string_view<wchar_t>>);
+// #endif
+
+struct SomeObject {};
+
+struct NonMode {};
+
+#endif // TEST_STD_INPUTOUTPUT_SPANSTREAMS_TYPES_H

>From f071960089a131f5f66746782f3e87c7ee166fd7 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Fri, 1 Mar 2024 09:49:14 +0200
Subject: [PATCH 06/56] Tests: tweaks

---
 .../ospanstream/types.compile.pass.cpp        | 11 +++---
 .../spanbuf/spanbuf.cons/default.pass.cpp     | 20 +---------
 .../spanbuf/spanbuf.cons/mode.pass.cpp        |  9 ++++-
 .../spanbuf/spanbuf.cons/move.pass.cpp        | 24 ++++++++++--
 .../spanbuf/spanbuf.cons/span.mode.pass.cpp   | 38 +++++++++++++++++--
 .../spanbuf/types.compile.pass.cpp            | 11 +++---
 .../spanstream/types.compile.pass.cpp         | 11 +++---
 7 files changed, 83 insertions(+), 41 deletions(-)

diff --git a/libcxx/test/std/input.output/span.streams/ospanstream/types.compile.pass.cpp b/libcxx/test/std/input.output/span.streams/ospanstream/types.compile.pass.cpp
index 595770aa5bd6b..5374011f61cc2 100644
--- a/libcxx/test/std/input.output/span.streams/ospanstream/types.compile.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/ospanstream/types.compile.pass.cpp
@@ -28,12 +28,17 @@
 #include <type_traits>
 
 #include "constexpr_char_traits.h"
+#include "nasty_string.h"
 #include "test_macros.h"
 
 template <typename CharT, typename TraitsT = std::char_traits<CharT>>
 void test() {
   using SpStream = std::basic_ospanstream<CharT, TraitsT>;
 
+  // Constructors
+
+  static_assert(!std::is_default_constructible_v<SpStream>);
+
   // Types
 
   static_assert(std::is_base_of_v<std::basic_ostream<CharT, TraitsT>, SpStream>);
@@ -50,11 +55,6 @@ void test() {
 
   // Move properties
 
-  static_assert(!std::is_copy_constructible_v<SpStream>);
-  static_assert(!std::is_copy_assignable_v<SpStream>);
-
-  // Move properties
-
   static_assert(std::is_move_constructible_v<SpStream>);
   static_assert(std::is_move_assignable_v<SpStream>);
 }
@@ -62,6 +62,7 @@ void test() {
 void test() {
   test<char>();
   test<char, constexpr_char_traits<char>>();
+  test<nasty_char, nasty_char_traits>();
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
   test<wchar_t>();
   test<wchar_t, constexpr_char_traits<wchar_t>>();
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/default.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/default.pass.cpp
index 4c6b1ae3080d9..a94551a96e000 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/default.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/default.pass.cpp
@@ -24,33 +24,17 @@
 #include "nasty_string.h"
 #include "test_macros.h"
 
-void test_sfinae_with_nasty_char() {
-  using SpBuf = std::basic_spanbuf<nasty_char, nasty_char_traits>;
-
-  static_assert(std::default_initializable<SpBuf>);
-}
-
-template <typename CharT, typename TraitsT = std::char_traits<CharT>>
-void test_sfinae() {
-  using SpBuf = std::basic_spanbuf<CharT, TraitsT>;
-
-  static_assert(std::default_initializable<SpBuf>);
-}
-
 template <typename CharT, typename TraitsT = std::char_traits<CharT>>
 void test() {
-  using SpanBuf = std::basic_spanbuf<CharT, TraitsT>;
+  using SpBuf = std::basic_spanbuf<CharT, TraitsT>;
 
-  SpanBuf spBuf;
+  SpBuf spBuf;
   assert(spBuf.span().data() == nullptr);
   assert(spBuf.span().empty());
   assert(spBuf.span().size() == 0);
 }
 
 int main(int, char**) {
-  test_sfinae_with_nasty_char();
-  test_sfinae<char>();
-  test_sfinae<char, constexpr_char_traits<char>>();
   test<char>();
   test<char, constexpr_char_traits<char>>();
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/mode.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/mode.pass.cpp
index 5a497e5b3238c..b452b6e80248e 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/mode.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/mode.pass.cpp
@@ -33,15 +33,20 @@
 void test_sfinae_with_nasty_char() {
   using SpBuf = std::basic_spanbuf<nasty_char, nasty_char_traits>;
 
+  // Mode
   static_assert(std::constructible_from<SpBuf, std::ios_base::openmode>);
   static_assert(!test_convertible<SpBuf, std::ios_base::openmode>());
+
+  // Non-mode
+  static_assert(!std::constructible_from<SpBuf, const NonMode>);
+  static_assert(!test_convertible<SpBuf, const NonMode>());
 }
 
 template <typename CharT, typename TraitsT = std::char_traits<CharT>>
 void test_sfinae() {
   using SpBuf = std::basic_spanbuf<CharT, TraitsT>;
 
-  // `Mode`
+  // Mode
   static_assert(std::constructible_from<SpBuf, std::ios_base::openmode>);
   static_assert(!test_convertible<SpBuf, std::ios_base::openmode>());
 
@@ -72,7 +77,7 @@ void test() {
   }
   // Mode: multiple
   {
-    SpBuf spBuf(std::ios_base::out | std::ios_base::in | std::ios_base::binary);
+    SpBuf spBuf(std::ios_base::in | std::ios_base::out | std::ios_base::binary);
     assert(spBuf.span().data() == nullptr);
     assert(spBuf.span().empty());
     assert(spBuf.span().size() == 0);
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/move.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/move.pass.cpp
index cfc67b07ea303..b32f6703981af 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/move.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/move.pass.cpp
@@ -32,7 +32,7 @@ template <typename CharT, typename TraitsT>
 struct TestSpanBuf : std::basic_spanbuf<CharT, TraitsT> {
   using std::basic_spanbuf<CharT, TraitsT>::basic_spanbuf;
 
-  TestSpanBuf(std::basic_spanbuf<CharT, TraitsT>&& rhs) : std::basic_spanbuf<CharT, TraitsT>(std::move(rhs)) {}
+  TestSpanBuf(std::basic_spanbuf<CharT, TraitsT>&& rhs_p) : std::basic_spanbuf<CharT, TraitsT>(std::move(rhs_p)) {}
 
   void check_postconditions(TestSpanBuf<CharT, TraitsT> const& rhs_p) const {
     assert(this->span().data() == rhs_p.span().data());
@@ -67,6 +67,14 @@ void test() {
   {
     // Empty `span`
     {
+      // Mode: default
+      {
+        SpBuf rhsSpBuf;
+        SpBuf spBuf(std::move(rhsSpBuf));
+        assert(spBuf.span().data() == nullptr);
+        assert(spBuf.span().empty());
+        assert(spBuf.span().size() == 0);
+      }
       // Mode: `ios_base::in`
       {
         SpBuf rhsSpBuf{std::ios_base::in};
@@ -98,6 +106,14 @@ void test() {
       CharT arr[4];
       std::span<CharT> sp{arr};
 
+      // Mode: default
+      {
+        SpBuf rhsSpBuf{sp};
+        SpBuf spBuf(std::move(rhsSpBuf));
+        assert(spBuf.span().data() == arr);
+        assert(spBuf.span().empty());
+        assert(spBuf.span().size() == 0);
+      }
       // Mode: `ios_base::in`
       {
         SpBuf rhsSpBuf{sp, std::ios_base::in};
@@ -129,6 +145,7 @@ void test() {
   {
     // Empty `span`
     {
+      // Mode: default
       {
         std::span<CharT> sp;
         TestSpanBuf<CharT, TraitsT> rhsSpBuf(sp);
@@ -158,7 +175,7 @@ void test() {
       // Mode: multiple
       {
         std::span<CharT> sp;
-        TestSpanBuf<CharT, TraitsT> rhsSpBuf(sp, std::ios_base::out | std::ios_base::in | std::ios_base::binary);
+        TestSpanBuf<CharT, TraitsT> rhsSpBuf(sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary);
         TestSpanBuf<CharT, TraitsT> spBuf(std::move(static_cast<SpBuf&>(rhsSpBuf)));
         assert(rhsSpBuf.span().empty());
         assert(spBuf.span().data() == nullptr);
@@ -170,6 +187,7 @@ void test() {
     {
       CharT arr[4];
 
+      // Mode: default
       {
         std::span<CharT> sp{arr};
         TestSpanBuf<CharT, TraitsT> rhsSpBuf(sp);
@@ -199,7 +217,7 @@ void test() {
       // Mode: multiple
       {
         std::span<CharT> sp{arr};
-        TestSpanBuf<CharT, TraitsT> rhsSpBuf(sp, std::ios_base::out | std::ios_base::in | std::ios_base::binary);
+        TestSpanBuf<CharT, TraitsT> rhsSpBuf(sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary);
         TestSpanBuf<CharT, TraitsT> spBuf(std::move(static_cast<SpBuf&>(rhsSpBuf)));
         assert(rhsSpBuf.span().empty());
         assert(spBuf.span().data() == arr);
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/span.mode.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/span.mode.pass.cpp
index fb58235d8c1fe..ff600b92e5c02 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/span.mode.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/span.mode.pass.cpp
@@ -36,15 +36,20 @@
 void test_sfinae_with_nasty_char() {
   using SpBuf = std::basic_spanbuf<nasty_char, nasty_char_traits>;
 
+  // Mode
   static_assert(std::constructible_from<SpBuf, const std::span<nasty_char>, std::ios_base::openmode>);
   static_assert(!test_convertible<SpBuf, std::ios_base::openmode>());
+
+  // Non-mode
+  static_assert(!std::constructible_from<SpBuf, const std::span<nasty_char>, const NonMode>);
+  static_assert(!test_convertible<SpBuf, const NonMode>());
 }
 
 template <typename CharT, typename TraitsT = std::char_traits<CharT>>
 void test_sfinae() {
   using SpBuf = std::basic_spanbuf<CharT, TraitsT>;
 
-  // `Mode`
+  // Mode
   static_assert(std::constructible_from<SpBuf, const std::span<CharT>, std::ios_base::openmode>);
   static_assert(!test_convertible<SpBuf, const std::span<CharT>, std::ios_base::openmode>());
 
@@ -63,6 +68,13 @@ void test() {
   {
     std::span<CharT> sp{};
 
+    // Mode: default
+    {
+      SpBuf spBuf(sp);
+      assert(spBuf.span().data() == nullptr);
+      assert(spBuf.span().empty());
+      assert(spBuf.span().size() == 0);
+    }
     // Mode: `ios_base::in`
     {
       SpBuf spBuf(sp, std::ios_base::in);
@@ -89,6 +101,19 @@ void test() {
       assert(spBuf.span().empty());
       assert(spBuf.span().size() == 0);
     }
+    // Mode: multiple
+    {
+      SpBuf spBuf(sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary);
+      assert(spBuf.span().data() == nullptr);
+      assert(spBuf.span().empty());
+      assert(spBuf.span().size() == 0);
+    }
+    {
+      SpBuf spBuf(std::as_const(sp), std::ios_base::in | std::ios_base::out | std::ios_base::binary);
+      assert(spBuf.span().data() == nullptr);
+      assert(spBuf.span().empty());
+      assert(spBuf.span().size() == 0);
+    }
   }
 
   // Non-empty `span`
@@ -96,6 +121,13 @@ void test() {
     CharT arr[4];
     std::span<CharT> sp{arr};
 
+    // Mode: default
+    {
+      SpBuf spBuf(sp);
+      assert(spBuf.span().data() == arr);
+      assert(spBuf.span().empty());
+      assert(spBuf.span().size() == 0);
+    }
     // Mode: `ios_base::in`
     {
       SpBuf spBuf(sp, std::ios_base::in);
@@ -124,13 +156,13 @@ void test() {
     }
     // Mode: multiple
     {
-      SpBuf spBuf(sp, std::ios_base::out | std::ios_base::in);
+      SpBuf spBuf(sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary);
       assert(spBuf.span().data() == arr);
       assert(spBuf.span().empty());
       assert(spBuf.span().size() == 0);
     }
     {
-      SpBuf spBuf(std::as_const(sp), std::ios_base::out | std::ios_base::in | std::ios_base::binary);
+      SpBuf spBuf(std::as_const(sp), std::ios_base::in | std::ios_base::out | std::ios_base::binary);
       assert(spBuf.span().data() == arr);
       assert(spBuf.span().empty());
       assert(spBuf.span().size() == 0);
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/types.compile.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/types.compile.pass.cpp
index 4c18422ebff28..dec47dbf7b8eb 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/types.compile.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/types.compile.pass.cpp
@@ -28,12 +28,17 @@
 #include <type_traits>
 
 #include "constexpr_char_traits.h"
+#include "nasty_string.h"
 #include "test_macros.h"
 
 template <typename CharT, typename TraitsT = std::char_traits<CharT>>
 void test() {
   using SpBuf = std::basic_spanbuf<CharT, TraitsT>;
 
+  // Constructors
+
+  static_assert(std::is_default_constructible_v<SpBuf>);
+
   // Types
 
   static_assert(std::is_base_of_v<std::basic_streambuf<CharT, TraitsT>, SpBuf>);
@@ -50,11 +55,6 @@ void test() {
 
   // Move properties
 
-  static_assert(!std::is_copy_constructible_v<SpBuf>);
-  static_assert(!std::is_copy_assignable_v<SpBuf>);
-
-  // Move properties
-
   static_assert(std::is_move_constructible_v<SpBuf>);
   static_assert(std::is_move_assignable_v<SpBuf>);
 }
@@ -62,6 +62,7 @@ void test() {
 void test() {
   test<char>();
   test<char, constexpr_char_traits<char>>();
+  test<nasty_char, nasty_char_traits>();
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
   test<wchar_t>();
   test<wchar_t, constexpr_char_traits<wchar_t>>();
diff --git a/libcxx/test/std/input.output/span.streams/spanstream/types.compile.pass.cpp b/libcxx/test/std/input.output/span.streams/spanstream/types.compile.pass.cpp
index 67d29cf041d9c..7c33c604237a3 100644
--- a/libcxx/test/std/input.output/span.streams/spanstream/types.compile.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanstream/types.compile.pass.cpp
@@ -28,12 +28,17 @@
 #include <type_traits>
 
 #include "constexpr_char_traits.h"
+#include "nasty_string.h"
 #include "test_macros.h"
 
 template <typename CharT, typename TraitsT = std::char_traits<CharT>>
 void test() {
   using SpStream = std::basic_spanstream<CharT, TraitsT>;
 
+  // Constructors
+
+  static_assert(!std::is_default_constructible_v<SpStream>);
+
   // Types
 
   static_assert(std::is_base_of_v<std::basic_iostream<CharT, TraitsT>, SpStream>);
@@ -50,11 +55,6 @@ void test() {
 
   // Move properties
 
-  static_assert(!std::is_copy_constructible_v<SpStream>);
-  static_assert(!std::is_copy_assignable_v<SpStream>);
-
-  // Move properties
-
   static_assert(std::is_move_constructible_v<SpStream>);
   static_assert(std::is_move_assignable_v<SpStream>);
 }
@@ -62,6 +62,7 @@ void test() {
 void test() {
   test<char>();
   test<char, constexpr_char_traits<char>>();
+  test<nasty_char, nasty_char_traits>();
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
   test<wchar_t>();
   test<wchar_t, constexpr_char_traits<wchar_t>>();

>From df3d1fe1169493e3e383128512b68970eef72b40 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Fri, 1 Mar 2024 09:49:44 +0200
Subject: [PATCH 07/56] Tests: `ispanstream` constructors - WIP

---
 .../ispanstream.cons/move.pass.cpp            |  81 +++++++++++
 .../ispanstream/ispanstream.cons/ros.pass.cpp |  60 ++++++++
 .../ispanstream.cons/span.mode.pass.cpp       | 136 ++++++++++++++++++
 .../ispanstream/types.compile.pass.cpp        |  11 +-
 4 files changed, 283 insertions(+), 5 deletions(-)
 create mode 100644 libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/move.pass.cpp
 create mode 100644 libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/ros.pass.cpp
 create mode 100644 libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/span.mode.pass.cpp

diff --git a/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/move.pass.cpp b/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/move.pass.cpp
new file mode 100644
index 0000000000000..ce711deedc140
--- /dev/null
+++ b/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/move.pass.cpp
@@ -0,0 +1,81 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <spanstream>
+
+//   template<class charT, class traits = char_traits<charT>>
+//   class basic_ispanstream
+//     : public basic_streambuf<charT, traits> {
+
+//     // [spanbuf.cons], constructors
+//
+//     basic_ispanstream(basic_ispanstream&& rhs);
+
+#include <cassert>
+#include <concepts>
+#include <span>
+#include <spanstream>
+
+#include "constexpr_char_traits.h"
+#include "nasty_string.h"
+#include "test_convertible.h"
+#include "test_macros.h"
+
+template <typename CharT, typename TraitsT = std::char_traits<CharT>>
+void test() {
+  using SpStream = std::basic_ispanstream<CharT, TraitsT>;
+
+  CharT arr[4];
+  std::span<CharT> sp{arr};
+
+  // Mode: default
+  {
+    SpStream rhsSpStream{sp};
+    SpStream sps(std::move(rhsSpStream));
+    assert(sps.span().data() == arr);
+    assert(!sps.span().empty());
+    assert(sps.span().size() == 4);
+  }
+  // Mode: `ios_base::in`
+  {
+    SpStream rhsSpStream{sp, std::ios_base::in};
+    SpStream sps(std::move(rhsSpStream));
+    assert(sps.span().data() == arr);
+    assert(!sps.span().empty());
+    assert(sps.span().size() == 4);
+  }
+  // Mode `ios_base::out`
+  {
+    SpStream rhsSpStream{sp, std::ios_base::out};
+    SpStream sps(std::move(rhsSpStream));
+    assert(sps.span().data() == arr);
+    assert(sps.span().empty());
+    assert(sps.span().size() == 0);
+  }
+  // Mode: multiple
+  {
+    SpStream rhsSpStream{sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary};
+    SpStream sps(std::move(rhsSpStream));
+    assert(sps.span().data() == arr);
+    assert(sps.span().empty());
+    assert(sps.span().size() == 0);
+  }
+}
+
+int main(int, char**) {
+  test<char>();
+  test<char, constexpr_char_traits<char>>();
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  test<wchar_t>();
+  test<wchar_t, constexpr_char_traits<wchar_t>>();
+#endif
+
+  return 0;
+}
diff --git a/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/ros.pass.cpp b/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/ros.pass.cpp
new file mode 100644
index 0000000000000..d4c9b2a765ac1
--- /dev/null
+++ b/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/ros.pass.cpp
@@ -0,0 +1,60 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <spanstream>
+
+//   template<class charT, class traits = char_traits<charT>>
+//   class basic_ispanstream
+//     : public basic_streambuf<charT, traits> {
+
+//     // [spanbuf.cons], constructors
+//
+//     template<class ROS> explicit basic_ispanstream(ROS&& s);
+
+#include <cassert>
+#include <spanstream>
+
+#include "constexpr_char_traits.h"
+#include "nasty_string.h"
+#include "test_macros.h"
+
+void test_sfinae_with_nasty_char() {
+  using SpStream = std::basic_ispanstream<nasty_char, nasty_char_traits>;
+
+  // TODO:
+}
+
+template <typename CharT, typename TraitsT = std::char_traits<CharT>>
+void test_sfinae() {
+  using SpStream = std::basic_ispanstream<CharT, TraitsT>;
+
+  // TODO:
+}
+
+template <typename CharT, typename TraitsT = std::char_traits<CharT>>
+void test() {
+  using SpStream = std::basic_ispanstream<CharT, TraitsT>;
+
+  // TODO:
+}
+
+int main(int, char**) {
+  test_sfinae_with_nasty_char();
+  test_sfinae<char>();
+  test_sfinae<char, constexpr_char_traits<char>>();
+  test<char>();
+  test<char, constexpr_char_traits<char>>();
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  test<wchar_t>();
+  test<wchar_t, constexpr_char_traits<wchar_t>>();
+#endif
+
+  return 0;
+}
diff --git a/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/span.mode.pass.cpp b/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/span.mode.pass.cpp
new file mode 100644
index 0000000000000..0938e35d0fb60
--- /dev/null
+++ b/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/span.mode.pass.cpp
@@ -0,0 +1,136 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <spanstream>
+
+//   template<class charT, class traits = char_traits<charT>>
+//   class basic_ispanstream
+//     : public basic_streambuf<charT, traits> {
+
+//     // [spanbuf.cons], constructors
+//
+//     explicit basic_ispanstream(std::span<charT> s,
+//                                ios_base::openmode which = ios_base::in);
+
+#include <cassert>
+#include <concepts>
+#include <span>
+#include <spanstream>
+#include <utility>
+
+#include "constexpr_char_traits.h"
+#include "nasty_string.h"
+#include "test_convertible.h"
+#include "test_macros.h"
+
+#include "../../macros.h"
+#include "../../types.h"
+
+void test_sfinae_with_nasty_char() {
+  using SpStream = std::basic_ispanstream<nasty_char, nasty_char_traits>;
+
+  // Mode
+  static_assert(std::constructible_from<SpStream, const std::span<nasty_char>, std::ios_base::openmode>);
+  static_assert(!test_convertible<SpStream, std::ios_base::openmode>());
+
+  // Non-mode
+  static_assert(!std::constructible_from<SpStream, const std::span<nasty_char>, const NonMode>);
+  static_assert(!test_convertible<SpStream, const std::span<nasty_char>, const NonMode>());
+}
+
+template <typename CharT, typename TraitsT = std::char_traits<CharT>>
+void test_sfinae() {
+  using SpStream = std::basic_ispanstream<CharT, TraitsT>;
+
+  // Mode
+  static_assert(std::constructible_from<SpStream, const std::span<CharT>, std::ios_base::openmode>);
+  static_assert(!test_convertible<SpStream, const std::span<CharT>, std::ios_base::openmode>());
+
+  // Non-mode
+  static_assert(!std::constructible_from<SpStream, const std::span<CharT>, const NonMode>);
+  static_assert(!test_convertible<SpStream, const std::span<CharT>, const NonMode>());
+}
+
+template <typename CharT, typename TraitsT = std::char_traits<CharT>>
+void test() {
+  using SpStream = std::basic_ispanstream<CharT, TraitsT>;
+
+  CharT arr[4];
+  std::span<CharT> sp{arr};
+
+  // Mode: default
+  {
+    SpStream sps(sp);
+    assert(sps.span().data() == arr);
+    assert(!sps.span().empty());
+    assert(sps.span().size() == 4);
+  }
+  {
+    SpStream sps(std::as_const(sp));
+    assert(sps.span().data() == arr);
+    assert(!sps.span().empty());
+    assert(sps.span().size() == 4);
+  }
+  // Mode: `ios_base::in`
+  {
+    SpStream sps(sp, std::ios_base::in);
+    assert(sps.span().data() == arr);
+    assert(!sps.span().empty());
+    assert(sps.span().size() == 4);
+  }
+  {
+    SpStream sps(std::as_const(sp), std::ios_base::in);
+    assert(sps.span().data() == arr);
+    assert(!sps.span().empty());
+    assert(sps.span().size() == 4);
+  }
+  // Mode `ios_base::out`
+  {
+    SpStream sps(sp, std::ios_base::out);
+    assert(sps.span().data() == arr);
+    assert(sps.span().empty());
+    assert(sps.span().size() == 0);
+  }
+  {
+    SpStream sps(std::as_const(sp), std::ios_base::out);
+    assert(sps.span().data() == arr);
+    assert(sps.span().empty());
+    assert(sps.span().size() == 0);
+  }
+  // Mode: multiple
+  {
+    SpStream sps(sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary);
+    assert(sps.span().data() == arr);
+    assert(sps.span().empty());
+    assert(sps.span().size() == 0);
+  }
+  {
+    SpStream sps(std::as_const(sp), std::ios_base::in | std::ios_base::out | std::ios_base::binary);
+    assert(sps.span().data() == arr);
+    assert(sps.span().empty());
+    assert(sps.span().size() == 0);
+  }
+}
+
+int main(int, char**) {
+  test_sfinae_with_nasty_char();
+  test_sfinae<char>();
+  test_sfinae<char, constexpr_char_traits<char>>();
+  test<char>();
+  test<char, constexpr_char_traits<char>>();
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  test_sfinae<wchar_t>();
+  test_sfinae<wchar_t, constexpr_char_traits<wchar_t>>();
+  test<wchar_t>();
+  test<wchar_t, constexpr_char_traits<wchar_t>>();
+#endif
+
+  return 0;
+}
\ No newline at end of file
diff --git a/libcxx/test/std/input.output/span.streams/ispanstream/types.compile.pass.cpp b/libcxx/test/std/input.output/span.streams/ispanstream/types.compile.pass.cpp
index c566a3fce647d..ddd15186b7c18 100644
--- a/libcxx/test/std/input.output/span.streams/ispanstream/types.compile.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/ispanstream/types.compile.pass.cpp
@@ -28,12 +28,17 @@
 #include <type_traits>
 
 #include "constexpr_char_traits.h"
+#include "nasty_string.h"
 #include "test_macros.h"
 
 template <typename CharT, typename TraitsT = std::char_traits<CharT>>
 void test() {
   using SpStream = std::basic_ispanstream<CharT, TraitsT>;
 
+  // Constructors
+
+  static_assert(!std::is_default_constructible_v<SpStream>);
+
   // Types
 
   static_assert(std::is_base_of_v<std::basic_istream<CharT, TraitsT>, SpStream>);
@@ -50,11 +55,6 @@ void test() {
 
   // Move properties
 
-  static_assert(!std::is_copy_constructible_v<SpStream>);
-  static_assert(!std::is_copy_assignable_v<SpStream>);
-
-  // Move properties
-
   static_assert(std::is_move_constructible_v<SpStream>);
   static_assert(std::is_move_assignable_v<SpStream>);
 }
@@ -62,6 +62,7 @@ void test() {
 void test() {
   test<char>();
   test<char, constexpr_char_traits<char>>();
+  test<nasty_char, nasty_char_traits>();
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
   test<wchar_t>();
   test<wchar_t, constexpr_char_traits<wchar_t>>();

>From 8a3406343e485e7c201d4bb16d4e7b98e2383ae9 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Fri, 1 Mar 2024 10:52:23 +0200
Subject: [PATCH 08/56] Implementation: fixed module and forward declarations

---
 libcxx/modules/std/spanstream.inc     | 4 ++--
 libcxx/utils/generate_iwyu_mapping.py | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/libcxx/modules/std/spanstream.inc b/libcxx/modules/std/spanstream.inc
index e6383a185e079..c9a50f0c2b841 100644
--- a/libcxx/modules/std/spanstream.inc
+++ b/libcxx/modules/std/spanstream.inc
@@ -8,7 +8,7 @@
 //===----------------------------------------------------------------------===//
 
 export namespace std {
-#if 0
+#if _LIBCPP_STD_VER >= 23
   using std::basic_spanbuf;
 
   using std::swap;
@@ -38,5 +38,5 @@ export namespace std {
 #  ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
   using std::wspanstream;
 #  endif
-#endif
+#endif // _LIBCPP_STD_VER >= 23
 } // namespace std
diff --git a/libcxx/utils/generate_iwyu_mapping.py b/libcxx/utils/generate_iwyu_mapping.py
index b0ebe1b9e93d2..c2908bddf5259 100644
--- a/libcxx/utils/generate_iwyu_mapping.py
+++ b/libcxx/utils/generate_iwyu_mapping.py
@@ -44,7 +44,7 @@ def IWYU_mapping(header: str) -> typing.Optional[typing.List[str]]:
         return ["utility"]
     elif header == "__fwd/subrange.h":
         return ["ranges"]
-    elif re.match("__fwd/(fstream|ios|istream|ostream|sstream|streambuf)[.]h", header):
+    elif re.match("__fwd/(fstream|ios|istream|ostream|spanstream|sstream|streambuf)[.]h", header):
         return ["iosfwd"]
     # Handle remaining forward declaration headers
     elif re.match("__fwd/(.+)[.]h", header):

>From e1cf40001f80f23738ce31afbfebd25e8042174d Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Fri, 1 Mar 2024 10:56:25 +0200
Subject: [PATCH 09/56] Implementation: fixed python code formatting

---
 libcxx/utils/generate_iwyu_mapping.py | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/libcxx/utils/generate_iwyu_mapping.py b/libcxx/utils/generate_iwyu_mapping.py
index c2908bddf5259..b0a1208660f2b 100644
--- a/libcxx/utils/generate_iwyu_mapping.py
+++ b/libcxx/utils/generate_iwyu_mapping.py
@@ -44,7 +44,9 @@ def IWYU_mapping(header: str) -> typing.Optional[typing.List[str]]:
         return ["utility"]
     elif header == "__fwd/subrange.h":
         return ["ranges"]
-    elif re.match("__fwd/(fstream|ios|istream|ostream|spanstream|sstream|streambuf)[.]h", header):
+    elif re.match(
+        "__fwd/(fstream|ios|istream|ostream|spanstream|sstream|streambuf)[.]h", header
+    ):
         return ["iosfwd"]
     # Handle remaining forward declaration headers
     elif re.match("__fwd/(.+)[.]h", header):

>From 5ae4a3cd10762d3b98e0f7cf4ed52b756f68b22b Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Fri, 1 Mar 2024 11:20:59 +0200
Subject: [PATCH 10/56] Implementation: updated transitive includes

---
 libcxx/test/libcxx/transitive_includes/cxx03.csv | 8 ++++++++
 libcxx/test/libcxx/transitive_includes/cxx11.csv | 8 ++++++++
 libcxx/test/libcxx/transitive_includes/cxx14.csv | 8 ++++++++
 libcxx/test/libcxx/transitive_includes/cxx17.csv | 8 ++++++++
 libcxx/test/libcxx/transitive_includes/cxx20.csv | 8 ++++++++
 libcxx/test/libcxx/transitive_includes/cxx23.csv | 7 +++++++
 libcxx/test/libcxx/transitive_includes/cxx26.csv | 7 +++++++
 7 files changed, 54 insertions(+)

diff --git a/libcxx/test/libcxx/transitive_includes/cxx03.csv b/libcxx/test/libcxx/transitive_includes/cxx03.csv
index 51e659f52000b..64d4fa9d9dc84 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx03.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx03.csv
@@ -756,6 +756,14 @@ span limits
 span stdexcept
 span type_traits
 span version
+spanstream cstddef
+spanstream initializer_list
+spanstream iostream
+spanstream limits
+spanstream span
+spanstream streambuf
+spanstream type_traits
+spanstream version
 sstream bitset
 sstream cerrno
 sstream cstddef
diff --git a/libcxx/test/libcxx/transitive_includes/cxx11.csv b/libcxx/test/libcxx/transitive_includes/cxx11.csv
index 17e85e982729c..ada559b88dd7d 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx11.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx11.csv
@@ -762,6 +762,14 @@ span limits
 span stdexcept
 span type_traits
 span version
+spanstream cstddef
+spanstream initializer_list
+spanstream iostream
+spanstream limits
+spanstream span
+spanstream streambuf
+spanstream type_traits
+spanstream version
 sstream bitset
 sstream cerrno
 sstream cstddef
diff --git a/libcxx/test/libcxx/transitive_includes/cxx14.csv b/libcxx/test/libcxx/transitive_includes/cxx14.csv
index 8aed93da9e6cc..0986aefbb7b6e 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx14.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx14.csv
@@ -765,6 +765,14 @@ span limits
 span stdexcept
 span type_traits
 span version
+spanstream cstddef
+spanstream initializer_list
+spanstream iostream
+spanstream limits
+spanstream span
+spanstream streambuf
+spanstream type_traits
+spanstream version
 sstream bitset
 sstream cerrno
 sstream cstddef
diff --git a/libcxx/test/libcxx/transitive_includes/cxx17.csv b/libcxx/test/libcxx/transitive_includes/cxx17.csv
index 2c028462144ee..14a23d2e97a50 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx17.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx17.csv
@@ -766,6 +766,14 @@ span limits
 span stdexcept
 span type_traits
 span version
+spanstream cstddef
+spanstream initializer_list
+spanstream iostream
+spanstream limits
+spanstream span
+spanstream streambuf
+spanstream type_traits
+spanstream version
 sstream bitset
 sstream cerrno
 sstream cstddef
diff --git a/libcxx/test/libcxx/transitive_includes/cxx20.csv b/libcxx/test/libcxx/transitive_includes/cxx20.csv
index 982c2013e3417..d4ba26e6582ba 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx20.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx20.csv
@@ -774,6 +774,14 @@ span limits
 span stdexcept
 span type_traits
 span version
+spanstream cstddef
+spanstream initializer_list
+spanstream iostream
+spanstream limits
+spanstream span
+spanstream streambuf
+spanstream type_traits
+spanstream version
 sstream bitset
 sstream cerrno
 sstream cstddef
diff --git a/libcxx/test/libcxx/transitive_includes/cxx23.csv b/libcxx/test/libcxx/transitive_includes/cxx23.csv
index 8ffb71d8b566b..63dfebbbb02b0 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx23.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx23.csv
@@ -519,6 +519,13 @@ span initializer_list
 span limits
 span stdexcept
 span version
+spanstream cstddef
+spanstream initializer_list
+spanstream iostream
+spanstream limits
+spanstream span
+spanstream streambuf
+spanstream version
 sstream bitset
 sstream cerrno
 sstream cstddef
diff --git a/libcxx/test/libcxx/transitive_includes/cxx26.csv b/libcxx/test/libcxx/transitive_includes/cxx26.csv
index 8ffb71d8b566b..63dfebbbb02b0 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx26.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx26.csv
@@ -519,6 +519,13 @@ span initializer_list
 span limits
 span stdexcept
 span version
+spanstream cstddef
+spanstream initializer_list
+spanstream iostream
+spanstream limits
+spanstream span
+spanstream streambuf
+spanstream version
 sstream bitset
 sstream cerrno
 sstream cstddef

>From 2758e03531fa7cd03a2327d22f403532340e2b8d Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Fri, 1 Mar 2024 11:45:01 +0200
Subject: [PATCH 11/56] Implementation: fix CI

---
 libcxx/include/spanstream | 1 +
 1 file changed, 1 insertion(+)

diff --git a/libcxx/include/spanstream b/libcxx/include/spanstream
index 16bbf04d81c55..814fa9a6f00e2 100644
--- a/libcxx/include/spanstream
+++ b/libcxx/include/spanstream
@@ -56,6 +56,7 @@
 
 #include <__assert> // all public C++ headers provide the assertion handler
 #include <__availability>
+#include <__concepts/convertible_to.h>
 #include <__config>
 #include <__fwd/spanstream.h>
 #include <__memory/addressof.h>

>From 2e58c6dbe2f4f3db695b810c91ce22876706b7cd Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Fri, 1 Mar 2024 13:33:23 +0200
Subject: [PATCH 12/56] Implementation: try to fix CI

---
 .../ispanstream/ispanstream.cons/move.pass.cpp  |  1 -
 .../ispanstream/ispanstream.cons/ros.pass.cpp   |  4 ++++
 .../ispanstream.cons/span.mode.pass.cpp         |  4 ++++
 .../ispanstream/types.compile.pass.cpp          |  4 +++-
 .../ospanstream/types.compile.pass.cpp          |  4 +++-
 .../spanbuf/spanbuf.cons/default.pass.cpp       |  1 -
 .../spanbuf/spanbuf.cons/mode.pass.cpp          |  4 ++++
 .../spanbuf/spanbuf.cons/move.pass.cpp          | 17 -----------------
 .../spanbuf/spanbuf.cons/span.mode.pass.cpp     |  4 ++++
 .../span.streams/spanbuf/types.compile.pass.cpp |  4 +++-
 .../spanstream/types.compile.pass.cpp           |  4 +++-
 11 files changed, 28 insertions(+), 23 deletions(-)

diff --git a/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/move.pass.cpp b/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/move.pass.cpp
index ce711deedc140..1b456a8a0ef38 100644
--- a/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/move.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/move.pass.cpp
@@ -24,7 +24,6 @@
 #include <spanstream>
 
 #include "constexpr_char_traits.h"
-#include "nasty_string.h"
 #include "test_convertible.h"
 #include "test_macros.h"
 
diff --git a/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/ros.pass.cpp b/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/ros.pass.cpp
index d4c9b2a765ac1..421ba8ff10e16 100644
--- a/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/ros.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/ros.pass.cpp
@@ -25,11 +25,13 @@
 #include "nasty_string.h"
 #include "test_macros.h"
 
+#ifndef TEST_HAS_NO_NASTY_STRING
 void test_sfinae_with_nasty_char() {
   using SpStream = std::basic_ispanstream<nasty_char, nasty_char_traits>;
 
   // TODO:
 }
+#endif // TEST_HAS_NO_NASTY_STRING
 
 template <typename CharT, typename TraitsT = std::char_traits<CharT>>
 void test_sfinae() {
@@ -46,7 +48,9 @@ void test() {
 }
 
 int main(int, char**) {
+#ifndef TEST_HAS_NO_NASTY_STRING
   test_sfinae_with_nasty_char();
+#endif
   test_sfinae<char>();
   test_sfinae<char, constexpr_char_traits<char>>();
   test<char>();
diff --git a/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/span.mode.pass.cpp b/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/span.mode.pass.cpp
index 0938e35d0fb60..cd793210e2c06 100644
--- a/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/span.mode.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/span.mode.pass.cpp
@@ -33,6 +33,7 @@
 #include "../../macros.h"
 #include "../../types.h"
 
+#ifndef TEST_HAS_NO_NASTY_STRING
 void test_sfinae_with_nasty_char() {
   using SpStream = std::basic_ispanstream<nasty_char, nasty_char_traits>;
 
@@ -44,6 +45,7 @@ void test_sfinae_with_nasty_char() {
   static_assert(!std::constructible_from<SpStream, const std::span<nasty_char>, const NonMode>);
   static_assert(!test_convertible<SpStream, const std::span<nasty_char>, const NonMode>());
 }
+#endif // TEST_HAS_NO_NASTY_STRING
 
 template <typename CharT, typename TraitsT = std::char_traits<CharT>>
 void test_sfinae() {
@@ -120,7 +122,9 @@ void test() {
 }
 
 int main(int, char**) {
+#ifndef TEST_HAS_NO_NASTY_STRING
   test_sfinae_with_nasty_char();
+#endif
   test_sfinae<char>();
   test_sfinae<char, constexpr_char_traits<char>>();
   test<char>();
diff --git a/libcxx/test/std/input.output/span.streams/ispanstream/types.compile.pass.cpp b/libcxx/test/std/input.output/span.streams/ispanstream/types.compile.pass.cpp
index ddd15186b7c18..9b492a9c59985 100644
--- a/libcxx/test/std/input.output/span.streams/ispanstream/types.compile.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/ispanstream/types.compile.pass.cpp
@@ -60,9 +60,11 @@ void test() {
 }
 
 void test() {
+#ifndef TEST_HAS_NO_NASTY_STRING
+  test<nasty_char, nasty_char_traits>();
+#endif
   test<char>();
   test<char, constexpr_char_traits<char>>();
-  test<nasty_char, nasty_char_traits>();
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
   test<wchar_t>();
   test<wchar_t, constexpr_char_traits<wchar_t>>();
diff --git a/libcxx/test/std/input.output/span.streams/ospanstream/types.compile.pass.cpp b/libcxx/test/std/input.output/span.streams/ospanstream/types.compile.pass.cpp
index 5374011f61cc2..71f76790d66fd 100644
--- a/libcxx/test/std/input.output/span.streams/ospanstream/types.compile.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/ospanstream/types.compile.pass.cpp
@@ -60,9 +60,11 @@ void test() {
 }
 
 void test() {
+#ifndef TEST_HAS_NO_NASTY_STRING
+  test<nasty_char, nasty_char_traits>();
+#endif
   test<char>();
   test<char, constexpr_char_traits<char>>();
-  test<nasty_char, nasty_char_traits>();
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
   test<wchar_t>();
   test<wchar_t, constexpr_char_traits<wchar_t>>();
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/default.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/default.pass.cpp
index a94551a96e000..b76af127f4314 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/default.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/default.pass.cpp
@@ -21,7 +21,6 @@
 #include <spanstream>
 
 #include "constexpr_char_traits.h"
-#include "nasty_string.h"
 #include "test_macros.h"
 
 template <typename CharT, typename TraitsT = std::char_traits<CharT>>
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/mode.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/mode.pass.cpp
index b452b6e80248e..eb8b29de9fbff 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/mode.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/mode.pass.cpp
@@ -30,6 +30,7 @@
 
 #include "../../types.h"
 
+#ifndef TEST_HAS_NO_NASTY_STRING
 void test_sfinae_with_nasty_char() {
   using SpBuf = std::basic_spanbuf<nasty_char, nasty_char_traits>;
 
@@ -41,6 +42,7 @@ void test_sfinae_with_nasty_char() {
   static_assert(!std::constructible_from<SpBuf, const NonMode>);
   static_assert(!test_convertible<SpBuf, const NonMode>());
 }
+#endif // TEST_HAS_NO_NASTY_STRING
 
 template <typename CharT, typename TraitsT = std::char_traits<CharT>>
 void test_sfinae() {
@@ -85,7 +87,9 @@ void test() {
 }
 
 int main(int, char**) {
+#ifndef TEST_HAS_NO_NASTY_STRING
   test_sfinae_with_nasty_char();
+#endif
   test_sfinae<char>();
   test_sfinae<char, constexpr_char_traits<char>>();
   test<char>();
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/move.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/move.pass.cpp
index b32f6703981af..1bab0f860d9f3 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/move.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/move.pass.cpp
@@ -24,7 +24,6 @@
 #include <spanstream>
 
 #include "constexpr_char_traits.h"
-#include "nasty_string.h"
 #include "test_convertible.h"
 #include "test_macros.h"
 
@@ -47,19 +46,6 @@ struct TestSpanBuf : std::basic_spanbuf<CharT, TraitsT> {
   }
 };
 
-void test_sfinae_with_nasty_char() {
-  using SpBuf = std::basic_spanbuf<nasty_char, nasty_char_traits>;
-
-  static_assert(std::move_constructible<SpBuf>);
-}
-
-template <typename CharT, typename TraitsT = std::char_traits<CharT>>
-void test_sfinae() {
-  using SpBuf = std::basic_spanbuf<CharT, TraitsT>;
-
-  static_assert(std::move_constructible<SpBuf>);
-}
-
 template <typename CharT, typename TraitsT = std::char_traits<CharT>>
 void test() {
   using SpBuf = std::basic_spanbuf<CharT, TraitsT>;
@@ -228,9 +214,6 @@ void test() {
 }
 
 int main(int, char**) {
-  test_sfinae_with_nasty_char();
-  test_sfinae<char>();
-  test_sfinae<char, constexpr_char_traits<char>>();
   test<char>();
   test<char, constexpr_char_traits<char>>();
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/span.mode.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/span.mode.pass.cpp
index ff600b92e5c02..fbcc8eeded259 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/span.mode.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/span.mode.pass.cpp
@@ -33,6 +33,7 @@
 #include "../../macros.h"
 #include "../../types.h"
 
+#ifndef TEST_HAS_NO_NASTY_STRING
 void test_sfinae_with_nasty_char() {
   using SpBuf = std::basic_spanbuf<nasty_char, nasty_char_traits>;
 
@@ -44,6 +45,7 @@ void test_sfinae_with_nasty_char() {
   static_assert(!std::constructible_from<SpBuf, const std::span<nasty_char>, const NonMode>);
   static_assert(!test_convertible<SpBuf, const NonMode>());
 }
+#endif // TEST_HAS_NO_NASTY_STRING
 
 template <typename CharT, typename TraitsT = std::char_traits<CharT>>
 void test_sfinae() {
@@ -171,7 +173,9 @@ void test() {
 }
 
 int main(int, char**) {
+#ifndef TEST_HAS_NO_NASTY_STRING
   test_sfinae_with_nasty_char();
+#endif
   test_sfinae<char>();
   test_sfinae<char, constexpr_char_traits<char>>();
   test<char>();
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/types.compile.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/types.compile.pass.cpp
index dec47dbf7b8eb..7ffbb9d24eab9 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/types.compile.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/types.compile.pass.cpp
@@ -60,9 +60,11 @@ void test() {
 }
 
 void test() {
+#ifndef TEST_HAS_NO_NASTY_STRING
+  test<nasty_char, nasty_char_traits>();
+#endif
   test<char>();
   test<char, constexpr_char_traits<char>>();
-  test<nasty_char, nasty_char_traits>();
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
   test<wchar_t>();
   test<wchar_t, constexpr_char_traits<wchar_t>>();
diff --git a/libcxx/test/std/input.output/span.streams/spanstream/types.compile.pass.cpp b/libcxx/test/std/input.output/span.streams/spanstream/types.compile.pass.cpp
index 7c33c604237a3..83f6b235ae913 100644
--- a/libcxx/test/std/input.output/span.streams/spanstream/types.compile.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanstream/types.compile.pass.cpp
@@ -60,9 +60,11 @@ void test() {
 }
 
 void test() {
+#ifndef TEST_HAS_NO_NASTY_STRING
+  test<nasty_char, nasty_char_traits>();
+#endif
   test<char>();
   test<char, constexpr_char_traits<char>>();
-  test<nasty_char, nasty_char_traits>();
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
   test<wchar_t>();
   test<wchar_t, constexpr_char_traits<wchar_t>>();

>From 462163b2ece1335594077bbfb08703eb8b35da4a Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Fri, 1 Mar 2024 14:47:23 +0200
Subject: [PATCH 13/56] Implementation: fixes

---
 libcxx/include/spanstream | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libcxx/include/spanstream b/libcxx/include/spanstream
index 814fa9a6f00e2..9f048a065c5c0 100644
--- a/libcxx/include/spanstream
+++ b/libcxx/include/spanstream
@@ -323,7 +323,7 @@ public:
   basic_ospanstream(const basic_ospanstream&) = delete;
 
   _LIBCPP_HIDE_FROM_ABI basic_ospanstream(basic_ospanstream&& __rhs)
-      : basic_ospanstream(std::move(__rhs)), __sb_(std::move(__rhs.__sb_)) {
+      : basic_ostream(std::move(__rhs)), __sb_(std::move(__rhs.__sb_)) {
     basic_ostream<_CharT, _Traits>::set_rdbuf(std::addressof(__sb_));
   }
 
@@ -382,7 +382,7 @@ public:
   basic_spanstream(const basic_spanstream&) = delete;
 
   _LIBCPP_HIDE_FROM_ABI basic_spanstream(basic_spanstream&& __rhs)
-      : basic_spanstream(std::move(__rhs)), __sb_(__rhs.__sb_) {
+      : basic_iostream(std::move(__rhs)), __sb_(__rhs.__sb_) {
     basic_iostream<_CharT, _Traits>::set_rdbuf(std::addressof(__sb_));
   }
 

>From 5957ab170e0d46e9147583a570af2c8e7bb2b1bd Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Fri, 1 Mar 2024 15:53:25 +0200
Subject: [PATCH 14/56] Implementation: fixes

---
 libcxx/include/spanstream | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libcxx/include/spanstream b/libcxx/include/spanstream
index 9f048a065c5c0..1cad46a2cd1f5 100644
--- a/libcxx/include/spanstream
+++ b/libcxx/include/spanstream
@@ -323,7 +323,7 @@ public:
   basic_ospanstream(const basic_ospanstream&) = delete;
 
   _LIBCPP_HIDE_FROM_ABI basic_ospanstream(basic_ospanstream&& __rhs)
-      : basic_ostream(std::move(__rhs)), __sb_(std::move(__rhs.__sb_)) {
+      : basic_iostream<_CharT, _Traits>(std::move(__rhs)), __sb_(std::move(__rhs.__sb_)) {
     basic_ostream<_CharT, _Traits>::set_rdbuf(std::addressof(__sb_));
   }
 
@@ -382,7 +382,7 @@ public:
   basic_spanstream(const basic_spanstream&) = delete;
 
   _LIBCPP_HIDE_FROM_ABI basic_spanstream(basic_spanstream&& __rhs)
-      : basic_iostream(std::move(__rhs)), __sb_(__rhs.__sb_) {
+      : basic_iostream<_CharT, _Traits>(std::move(__rhs)), __sb_(__rhs.__sb_) {
     basic_iostream<_CharT, _Traits>::set_rdbuf(std::addressof(__sb_));
   }
 

>From 87d6e0f3b18cc813d3059a43e9961210f831467d Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Fri, 1 Mar 2024 16:35:45 +0200
Subject: [PATCH 15/56] Tests: `ospanstream` and `spanstream` constructors +
 fixes

---
 libcxx/include/spanstream                     |  14 +-
 .../ospanstream.cons/move.pass.cpp            |  80 ++++++++++
 .../ospanstream.cons/span.mode.pass.cpp       | 140 ++++++++++++++++++
 .../spanstream/spanstream.cons/move.pass.cpp  |  80 ++++++++++
 .../spanstream.cons/span.mode.pass.cpp        | 140 ++++++++++++++++++
 5 files changed, 449 insertions(+), 5 deletions(-)
 create mode 100644 libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.cons/move.pass.cpp
 create mode 100644 libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.cons/span.mode.pass.cpp
 create mode 100644 libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/move.pass.cpp
 create mode 100644 libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/span.mode.pass.cpp

diff --git a/libcxx/include/spanstream b/libcxx/include/spanstream
index 1cad46a2cd1f5..6a3911a08a047 100644
--- a/libcxx/include/spanstream
+++ b/libcxx/include/spanstream
@@ -323,7 +323,7 @@ public:
   basic_ospanstream(const basic_ospanstream&) = delete;
 
   _LIBCPP_HIDE_FROM_ABI basic_ospanstream(basic_ospanstream&& __rhs)
-      : basic_iostream<_CharT, _Traits>(std::move(__rhs)), __sb_(std::move(__rhs.__sb_)) {
+      : basic_ostream<_CharT, _Traits>(std::move(__rhs)), __sb_(std::move(__rhs.__sb_)) {
     basic_ostream<_CharT, _Traits>::set_rdbuf(std::addressof(__sb_));
   }
 
@@ -344,9 +344,11 @@ public:
 
   // [ospanstream.members], member functions
 
-  _LIBCPP_HIDE_FROM_ABI basic_spanbuf<_CharT, _Traits>* rdbuf() const noexcept { return __sb_; }
+  _LIBCPP_HIDE_FROM_ABI basic_spanbuf<_CharT, _Traits>* rdbuf() const noexcept {
+    return const_cast<basic_spanbuf<_CharT, _Traits>*>(std::addressof(__sb_));
+  }
 
-  _LIBCPP_HIDE_FROM_ABI std::span<_CharT> span() const noexcept { return __sb_.rdbuf()->span(); }
+  _LIBCPP_HIDE_FROM_ABI std::span<_CharT> span() const noexcept { return rdbuf()->span(); }
 
   _LIBCPP_HIDE_FROM_ABI void span(std::span<_CharT> __s) noexcept { rdbuf()->span(__s); }
 
@@ -382,7 +384,7 @@ public:
   basic_spanstream(const basic_spanstream&) = delete;
 
   _LIBCPP_HIDE_FROM_ABI basic_spanstream(basic_spanstream&& __rhs)
-      : basic_iostream<_CharT, _Traits>(std::move(__rhs)), __sb_(__rhs.__sb_) {
+      : basic_iostream<_CharT, _Traits>(std::move(__rhs)), __sb_(std::move(__rhs.__sb_)) {
     basic_iostream<_CharT, _Traits>::set_rdbuf(std::addressof(__sb_));
   }
 
@@ -403,7 +405,9 @@ public:
 
   // [spanstream.members], members
 
-  _LIBCPP_HIDE_FROM_ABI basic_spanbuf<_CharT, _Traits>* rdbuf() const noexcept { return __sb_; }
+  _LIBCPP_HIDE_FROM_ABI basic_spanbuf<_CharT, _Traits>* rdbuf() const noexcept {
+    return const_cast<basic_spanbuf<_CharT, _Traits>*>(std::addressof(__sb_));
+  }
 
   _LIBCPP_HIDE_FROM_ABI std::span<_CharT> span() const noexcept { return rdbuf()->span(); }
 
diff --git a/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.cons/move.pass.cpp b/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.cons/move.pass.cpp
new file mode 100644
index 0000000000000..895e07cdf7ecb
--- /dev/null
+++ b/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.cons/move.pass.cpp
@@ -0,0 +1,80 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <spanstream>
+
+//   template<class charT, class traits = char_traits<charT>>
+//   class basic_ospanstream
+//     : public basic_streambuf<charT, traits> {
+
+//     // [spanbuf.cons], constructors
+//
+//     basic_ospanstream(basic_ospanstream&& rhs);
+
+#include <cassert>
+#include <concepts>
+#include <span>
+#include <spanstream>
+
+#include "constexpr_char_traits.h"
+#include "test_convertible.h"
+#include "test_macros.h"
+
+template <typename CharT, typename TraitsT = std::char_traits<CharT>>
+void test() {
+  using SpStream = std::basic_ospanstream<CharT, TraitsT>;
+
+  CharT arr[4];
+  std::span<CharT> sp{arr};
+
+  // Mode: default
+  {
+    SpStream rhsSpStream{sp};
+    SpStream sps(std::move(rhsSpStream));
+    assert(sps.span().data() == arr);
+    assert(sps.span().empty());
+    assert(sps.span().size() == 0);
+  }
+  // Mode: `ios_base::in`
+  {
+    SpStream rhsSpStream{sp, std::ios_base::in};
+    SpStream sps(std::move(rhsSpStream));
+    assert(sps.span().data() == arr);
+    assert(sps.span().empty());
+    assert(sps.span().size() == 0);
+  }
+  // Mode `ios_base::out`
+  {
+    SpStream rhsSpStream{sp, std::ios_base::out};
+    SpStream sps(std::move(rhsSpStream));
+    assert(sps.span().data() == arr);
+    assert(sps.span().empty());
+    assert(sps.span().size() == 0);
+  }
+  // Mode: multiple
+  {
+    SpStream rhsSpStream{sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary};
+    SpStream sps(std::move(rhsSpStream));
+    assert(sps.span().data() == arr);
+    assert(sps.span().empty());
+    assert(sps.span().size() == 0);
+  }
+}
+
+int main(int, char**) {
+  test<char>();
+  test<char, constexpr_char_traits<char>>();
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  test<wchar_t>();
+  test<wchar_t, constexpr_char_traits<wchar_t>>();
+#endif
+
+  return 0;
+}
diff --git a/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.cons/span.mode.pass.cpp b/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.cons/span.mode.pass.cpp
new file mode 100644
index 0000000000000..086ea7c765382
--- /dev/null
+++ b/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.cons/span.mode.pass.cpp
@@ -0,0 +1,140 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <spanstream>
+
+//   template<class charT, class traits = char_traits<charT>>
+//   class basic_ospanstream
+//     : public basic_streambuf<charT, traits> {
+
+//     // [spanbuf.cons], constructors
+//
+//     explicit basic_ospanstream(std::span<charT> s,
+//                                ios_base::openmode which = ios_base::in);
+
+#include <cassert>
+#include <concepts>
+#include <span>
+#include <spanstream>
+#include <utility>
+
+#include "constexpr_char_traits.h"
+#include "nasty_string.h"
+#include "test_convertible.h"
+#include "test_macros.h"
+
+#include "../../macros.h"
+#include "../../types.h"
+
+#ifndef TEST_HAS_NO_NASTY_STRING
+void test_sfinae_with_nasty_char() {
+  using SpStream = std::basic_ospanstream<nasty_char, nasty_char_traits>;
+
+  // Mode
+  static_assert(std::constructible_from<SpStream, const std::span<nasty_char>, std::ios_base::openmode>);
+  static_assert(!test_convertible<SpStream, std::ios_base::openmode>());
+
+  // Non-mode
+  static_assert(!std::constructible_from<SpStream, const std::span<nasty_char>, const NonMode>);
+  static_assert(!test_convertible<SpStream, const std::span<nasty_char>, const NonMode>());
+}
+#endif // TEST_HAS_NO_NASTY_STRING
+
+template <typename CharT, typename TraitsT = std::char_traits<CharT>>
+void test_sfinae() {
+  using SpStream = std::basic_ospanstream<CharT, TraitsT>;
+
+  // Mode
+  static_assert(std::constructible_from<SpStream, const std::span<CharT>, std::ios_base::openmode>);
+  static_assert(!test_convertible<SpStream, const std::span<CharT>, std::ios_base::openmode>());
+
+  // Non-mode
+  static_assert(!std::constructible_from<SpStream, const std::span<CharT>, const NonMode>);
+  static_assert(!test_convertible<SpStream, const std::span<CharT>, const NonMode>());
+}
+
+template <typename CharT, typename TraitsT = std::char_traits<CharT>>
+void test() {
+  using SpStream = std::basic_ospanstream<CharT, TraitsT>;
+
+  CharT arr[4];
+  std::span<CharT> sp{arr};
+
+  // Mode: default
+  {
+    SpStream sps(sp);
+    assert(sps.span().data() == arr);
+    assert(sps.span().empty());
+    assert(sps.span().size() == 0);
+  }
+  {
+    SpStream sps(std::as_const(sp));
+    assert(sps.span().data() == arr);
+    assert(sps.span().empty());
+    assert(sps.span().size() == 0);
+  }
+  // Mode: `ios_base::in`
+  {
+    SpStream sps(sp, std::ios_base::in);
+    assert(sps.span().data() == arr);
+    assert(sps.span().empty());
+    assert(sps.span().size() == 0);
+  }
+  {
+    SpStream sps(std::as_const(sp), std::ios_base::in);
+    assert(sps.span().data() == arr);
+    assert(sps.span().empty());
+    assert(sps.span().size() == 0);
+  }
+  // Mode `ios_base::out`
+  {
+    SpStream sps(sp, std::ios_base::out);
+    assert(sps.span().data() == arr);
+    assert(sps.span().empty());
+    assert(sps.span().size() == 0);
+  }
+  {
+    SpStream sps(std::as_const(sp), std::ios_base::out);
+    assert(sps.span().data() == arr);
+    assert(sps.span().empty());
+    assert(sps.span().size() == 0);
+  }
+  // Mode: multiple
+  {
+    SpStream sps(sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary);
+    assert(sps.span().data() == arr);
+    assert(sps.span().empty());
+    assert(sps.span().size() == 0);
+  }
+  {
+    SpStream sps(std::as_const(sp), std::ios_base::in | std::ios_base::out | std::ios_base::binary);
+    assert(sps.span().data() == arr);
+    assert(sps.span().empty());
+    assert(sps.span().size() == 0);
+  }
+}
+
+int main(int, char**) {
+#ifndef TEST_HAS_NO_NASTY_STRING
+  test_sfinae_with_nasty_char();
+#endif
+  test_sfinae<char>();
+  test_sfinae<char, constexpr_char_traits<char>>();
+  test<char>();
+  test<char, constexpr_char_traits<char>>();
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  test_sfinae<wchar_t>();
+  test_sfinae<wchar_t, constexpr_char_traits<wchar_t>>();
+  test<wchar_t>();
+  test<wchar_t, constexpr_char_traits<wchar_t>>();
+#endif
+
+  return 0;
+}
\ No newline at end of file
diff --git a/libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/move.pass.cpp b/libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/move.pass.cpp
new file mode 100644
index 0000000000000..1a02487d07198
--- /dev/null
+++ b/libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/move.pass.cpp
@@ -0,0 +1,80 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <spanstream>
+
+//   template<class charT, class traits = char_traits<charT>>
+//   class basic_spanstream
+//     : public basic_streambuf<charT, traits> {
+
+//     // [spanbuf.cons], constructors
+//
+//     basic_spanstream(basic_spanstream&& rhs);
+
+#include <cassert>
+#include <concepts>
+#include <span>
+#include <spanstream>
+
+#include "constexpr_char_traits.h"
+#include "test_convertible.h"
+#include "test_macros.h"
+
+template <typename CharT, typename TraitsT = std::char_traits<CharT>>
+void test() {
+  using SpStream = std::basic_spanstream<CharT, TraitsT>;
+
+  CharT arr[4];
+  std::span<CharT> sp{arr};
+
+  // Mode: default
+  {
+    SpStream rhsSpStream{sp};
+    SpStream sps(std::move(rhsSpStream));
+    assert(sps.span().data() == arr);
+    assert(sps.span().empty());
+    assert(sps.span().size() == 0);
+  }
+  // Mode: `ios_base::in`
+  {
+    SpStream rhsSpStream{sp, std::ios_base::in};
+    SpStream sps(std::move(rhsSpStream));
+    assert(sps.span().data() == arr);
+    assert(!sps.span().empty());
+    assert(sps.span().size() == 4);
+  }
+  // Mode `ios_base::out`
+  {
+    SpStream rhsSpStream{sp, std::ios_base::out};
+    SpStream sps(std::move(rhsSpStream));
+    assert(sps.span().data() == arr);
+    assert(sps.span().empty());
+    assert(sps.span().size() == 0);
+  }
+  // Mode: multiple
+  {
+    SpStream rhsSpStream{sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary};
+    SpStream sps(std::move(rhsSpStream));
+    assert(sps.span().data() == arr);
+    assert(sps.span().empty());
+    assert(sps.span().size() == 0);
+  }
+}
+
+int main(int, char**) {
+  test<char>();
+  test<char, constexpr_char_traits<char>>();
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  test<wchar_t>();
+  test<wchar_t, constexpr_char_traits<wchar_t>>();
+#endif
+
+  return 0;
+}
diff --git a/libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/span.mode.pass.cpp b/libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/span.mode.pass.cpp
new file mode 100644
index 0000000000000..8fcc216b2ef6b
--- /dev/null
+++ b/libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/span.mode.pass.cpp
@@ -0,0 +1,140 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <spanstream>
+
+//   template<class charT, class traits = char_traits<charT>>
+//   class basic_spanstream
+//     : public basic_streambuf<charT, traits> {
+
+//     // [spanbuf.cons], constructors
+//
+//     explicit basic_spanstream(std::span<charT> s,
+//                                ios_base::openmode which = ios_base::in);
+
+#include <cassert>
+#include <concepts>
+#include <span>
+#include <spanstream>
+#include <utility>
+
+#include "constexpr_char_traits.h"
+#include "nasty_string.h"
+#include "test_convertible.h"
+#include "test_macros.h"
+
+#include "../../macros.h"
+#include "../../types.h"
+
+#ifndef TEST_HAS_NO_NASTY_STRING
+void test_sfinae_with_nasty_char() {
+  using SpStream = std::basic_spanstream<nasty_char, nasty_char_traits>;
+
+  // Mode
+  static_assert(std::constructible_from<SpStream, const std::span<nasty_char>, std::ios_base::openmode>);
+  static_assert(!test_convertible<SpStream, std::ios_base::openmode>());
+
+  // Non-mode
+  static_assert(!std::constructible_from<SpStream, const std::span<nasty_char>, const NonMode>);
+  static_assert(!test_convertible<SpStream, const std::span<nasty_char>, const NonMode>());
+}
+#endif // TEST_HAS_NO_NASTY_STRING
+
+template <typename CharT, typename TraitsT = std::char_traits<CharT>>
+void test_sfinae() {
+  using SpStream = std::basic_spanstream<CharT, TraitsT>;
+
+  // Mode
+  static_assert(std::constructible_from<SpStream, const std::span<CharT>, std::ios_base::openmode>);
+  static_assert(!test_convertible<SpStream, const std::span<CharT>, std::ios_base::openmode>());
+
+  // Non-mode
+  static_assert(!std::constructible_from<SpStream, const std::span<CharT>, const NonMode>);
+  static_assert(!test_convertible<SpStream, const std::span<CharT>, const NonMode>());
+}
+
+template <typename CharT, typename TraitsT = std::char_traits<CharT>>
+void test() {
+  using SpStream = std::basic_spanstream<CharT, TraitsT>;
+
+  CharT arr[4];
+  std::span<CharT> sp{arr};
+
+  // Mode: default
+  {
+    SpStream sps(sp);
+    assert(sps.span().data() == arr);
+    assert(sps.span().empty());
+    assert(sps.span().size() == 0);
+  }
+  {
+    SpStream sps(std::as_const(sp));
+    assert(sps.span().data() == arr);
+    assert(sps.span().empty());
+    assert(sps.span().size() == 0);
+  }
+  // Mode: `ios_base::in`
+  {
+    SpStream sps(sp, std::ios_base::in);
+    assert(sps.span().data() == arr);
+    assert(!sps.span().empty());
+    assert(sps.span().size() == 4);
+  }
+  {
+    SpStream sps(std::as_const(sp), std::ios_base::in);
+    assert(sps.span().data() == arr);
+    assert(!sps.span().empty());
+    assert(sps.span().size() == 4);
+  }
+  // Mode `ios_base::out`
+  {
+    SpStream sps(sp, std::ios_base::out);
+    assert(sps.span().data() == arr);
+    assert(sps.span().empty());
+    assert(sps.span().size() == 0);
+  }
+  {
+    SpStream sps(std::as_const(sp), std::ios_base::out);
+    assert(sps.span().data() == arr);
+    assert(sps.span().empty());
+    assert(sps.span().size() == 0);
+  }
+  // Mode: multiple
+  {
+    SpStream sps(sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary);
+    assert(sps.span().data() == arr);
+    assert(sps.span().empty());
+    assert(sps.span().size() == 0);
+  }
+  {
+    SpStream sps(std::as_const(sp), std::ios_base::in | std::ios_base::out | std::ios_base::binary);
+    assert(sps.span().data() == arr);
+    assert(sps.span().empty());
+    assert(sps.span().size() == 0);
+  }
+}
+
+int main(int, char**) {
+#ifndef TEST_HAS_NO_NASTY_STRING
+  test_sfinae_with_nasty_char();
+#endif
+  test_sfinae<char>();
+  test_sfinae<char, constexpr_char_traits<char>>();
+  test<char>();
+  test<char, constexpr_char_traits<char>>();
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  test_sfinae<wchar_t>();
+  test_sfinae<wchar_t, constexpr_char_traits<wchar_t>>();
+  test<wchar_t>();
+  test<wchar_t, constexpr_char_traits<wchar_t>>();
+#endif
+
+  return 0;
+}
\ No newline at end of file

>From 774ac260d4ff6078abddb8a04abb741fd949c55c Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Sat, 2 Mar 2024 08:26:39 +0200
Subject: [PATCH 16/56] Tests: `ispanstream` added assign and swap

---
 libcxx/include/spanstream                     | 45 ++++++----
 .../ispanstream.assign/move.pass.cpp          | 80 ++++++++++++++++++
 .../ispanstream.assign/swap.pass.cpp          | 83 +++++++++++++++++++
 .../swap_nonmember.pass.cpp                   | 79 ++++++++++++++++++
 .../ispanstream.cons/move.pass.cpp            | 40 ++++-----
 .../ispanstream.cons/span.mode.pass.cpp       | 64 +++++++-------
 .../ospanstream.cons/move.pass.cpp            | 40 ++++-----
 .../ospanstream.cons/span.mode.pass.cpp       | 64 +++++++-------
 .../spanstream/spanstream.cons/move.pass.cpp  | 40 ++++-----
 .../spanstream.cons/span.mode.pass.cpp        | 64 +++++++-------
 10 files changed, 427 insertions(+), 172 deletions(-)
 create mode 100644 libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.assign/move.pass.cpp
 create mode 100644 libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.assign/swap.pass.cpp
 create mode 100644 libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.assign/swap_nonmember.pass.cpp

diff --git a/libcxx/include/spanstream b/libcxx/include/spanstream
index 6a3911a08a047..70e6faa4206fb 100644
--- a/libcxx/include/spanstream
+++ b/libcxx/include/spanstream
@@ -167,24 +167,37 @@ protected:
     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());
-      }
-    }();
+    // Calculate __baseoff
+
+    off_type __baseoff;
+
+    switch (__way) {
+    case ios_base::beg:
+      __baseoff = off_type(0);
+      break;
+
+    case ios_base::cur:
+      if (__which & ios_base::out)
+        __baseoff = off_type(this->pptr() - this->pbase());
+      else
+        __baseoff = off_type(this->gptr() - this->eback());
+      break;
+
+    case ios_base::end:
+      if ((__which & ios_base::out) && !(__which & ios_base::in))
+        __baseoff = off_type(this->pptr() - this->pbase());
+      else
+        __baseoff = off_type(__buf_.size());
+      break;
+
+    default:
+      return __error;
+    };
+
+    // Calculate __newoff
 
     off_type __newoff;
+
     if (__builtin_add_overflow(__baseoff, __off, &__newoff) || (__newoff < off_type(0)) ||
         (std::cmp_greater(__newoff, __buf_.size())))
       return __error;
diff --git a/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.assign/move.pass.cpp b/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.assign/move.pass.cpp
new file mode 100644
index 0000000000000..117e2a6828e9d
--- /dev/null
+++ b/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.assign/move.pass.cpp
@@ -0,0 +1,80 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <spanstream>
+
+//   template<class charT, class traits = char_traits<charT>>
+//   class basic_ispanstream
+//     : public basic_streambuf<charT, traits> {
+
+//     // [spanbuf.cons], constructors
+//
+//     basic_ispanstream& operator=(basic_ispanstream&& rhs);
+
+#include <cassert>
+#include <concepts>
+#include <span>
+#include <spanstream>
+
+#include "constexpr_char_traits.h"
+#include "test_convertible.h"
+#include "test_macros.h"
+
+template <typename CharT, typename TraitsT = std::char_traits<CharT>>
+void test() {
+  using SpStream = std::basic_ispanstream<CharT, TraitsT>;
+
+  CharT arr[4];
+  std::span<CharT> sp{arr};
+
+  // Mode: default
+  {
+    SpStream rhsSpSt{sp};
+    SpStream spSt = std::move(rhsSpSt);
+    assert(spSt.span().data() == arr);
+    assert(!spSt.span().empty());
+    assert(spSt.span().size() == 4);
+  }
+  // Mode: `ios_base::in`
+  {
+    SpStream rhsSpSt{sp, std::ios_base::in};
+    SpStream spSt = std::move(rhsSpSt);
+    assert(spSt.span().data() == arr);
+    assert(!spSt.span().empty());
+    assert(spSt.span().size() == 4);
+  }
+  // Mode `ios_base::out`
+  {
+    SpStream rhsSpSt{sp, std::ios_base::out};
+    SpStream spSt = std::move(rhsSpSt);
+    assert(spSt.span().data() == arr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+  }
+  // Mode: multiple
+  {
+    SpStream rhsSpSt{sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary};
+    SpStream spSt = std::move(rhsSpSt);
+    assert(spSt.span().data() == arr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+  }
+}
+
+int main(int, char**) {
+  test<char>();
+  test<char, constexpr_char_traits<char>>();
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  test<wchar_t>();
+  test<wchar_t, constexpr_char_traits<wchar_t>>();
+#endif
+
+  return 0;
+}
diff --git a/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.assign/swap.pass.cpp b/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.assign/swap.pass.cpp
new file mode 100644
index 0000000000000..45fc6370a06d4
--- /dev/null
+++ b/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.assign/swap.pass.cpp
@@ -0,0 +1,83 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <spanstream>
+
+//   template<class charT, class traits = char_traits<charT>>
+//   class basic_ispanstream
+//     : public basic_streambuf<charT, traits> {
+
+//     // [ispanstream.swap], swap
+//     void swap(basic_ispanstream& rhs);
+
+#include <cassert>
+#include <concepts>
+#include <span>
+#include <spanstream>
+
+#include "constexpr_char_traits.h"
+#include "test_convertible.h"
+#include "test_macros.h"
+
+template <typename CharT, typename TraitsT = std::char_traits<CharT>>
+void test() {
+  using SpStream = std::basic_ispanstream<CharT, TraitsT>;
+
+  CharT arr[4];
+  std::span<CharT> sp{arr};
+
+  // Mode: default
+  {
+    SpStream rhsSpSt{sp};
+    SpStream spSt(std::span<CharT>{});
+    spSt.swap(rhsSpSt);
+    assert(spSt.span().data() == arr);
+    assert(!spSt.span().empty());
+    assert(spSt.span().size() == 4);
+  }
+  // Mode: `ios_base::in`
+  {
+    SpStream rhsSpSt{sp, std::ios_base::in};
+    SpStream spSt(std::span<CharT>{});
+    spSt.swap(rhsSpSt);
+    assert(spSt.span().data() == arr);
+    assert(!spSt.span().empty());
+    assert(spSt.span().size() == 4);
+  }
+  // Mode `ios_base::out`
+  {
+    SpStream rhsSpSt{sp, std::ios_base::out};
+    SpStream spSt(std::span<CharT>{});
+    spSt.swap(rhsSpSt);
+    assert(spSt.span().data() == arr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+  }
+  // Mode: multiple
+  {
+    SpStream rhsSpSt{sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary};
+    SpStream spSt(std::span<CharT>{});
+    spSt.swap(rhsSpSt);
+    assert(spSt.span().data() == arr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+  }
+}
+
+int main(int, char**) {
+  test<char>();
+  test<char, constexpr_char_traits<char>>();
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  test<wchar_t>();
+  test<wchar_t, constexpr_char_traits<wchar_t>>();
+#endif
+
+  return 0;
+}
diff --git a/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.assign/swap_nonmember.pass.cpp b/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.assign/swap_nonmember.pass.cpp
new file mode 100644
index 0000000000000..ae54e40929745
--- /dev/null
+++ b/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.assign/swap_nonmember.pass.cpp
@@ -0,0 +1,79 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <spanstream>
+
+//   template<class charT, class traits>
+//     void swap(basic_ispanstream<charT, traits>& x, basic_ispanstream<charT, traits>& y);
+
+#include <cassert>
+#include <concepts>
+#include <span>
+#include <spanstream>
+
+#include "constexpr_char_traits.h"
+#include "test_convertible.h"
+#include "test_macros.h"
+
+template <typename CharT, typename TraitsT = std::char_traits<CharT>>
+void test() {
+  using SpStream = std::basic_ispanstream<CharT, TraitsT>;
+
+  CharT arr[4];
+  std::span<CharT> sp{arr};
+
+  // Mode: default
+  {
+    SpStream rhsSpSt{sp};
+    SpStream spSt(std::span<CharT>{});
+    std::swap(spSt, rhsSpSt);
+    assert(spSt.span().data() == arr);
+    assert(!spSt.span().empty());
+    assert(spSt.span().size() == 4);
+  }
+  // Mode: `ios_base::in`
+  {
+    SpStream rhsSpSt{sp, std::ios_base::in};
+    SpStream spSt(std::span<CharT>{});
+    std::swap(spSt, rhsSpSt);
+    assert(spSt.span().data() == arr);
+    assert(!spSt.span().empty());
+    assert(spSt.span().size() == 4);
+  }
+  // Mode `ios_base::out`
+  {
+    SpStream rhsSpSt{sp, std::ios_base::out};
+    SpStream spSt(std::span<CharT>{});
+    std::swap(spSt, rhsSpSt);
+    assert(spSt.span().data() == arr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+  }
+  // Mode: multiple
+  {
+    SpStream rhsSpSt{sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary};
+    SpStream spSt(std::span<CharT>{});
+    std::swap(spSt, rhsSpSt);
+    assert(spSt.span().data() == arr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+  }
+}
+
+int main(int, char**) {
+  test<char>();
+  test<char, constexpr_char_traits<char>>();
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  test<wchar_t>();
+  test<wchar_t, constexpr_char_traits<wchar_t>>();
+#endif
+
+  return 0;
+}
diff --git a/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/move.pass.cpp b/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/move.pass.cpp
index 1b456a8a0ef38..2207b773bd9ce 100644
--- a/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/move.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/move.pass.cpp
@@ -36,35 +36,35 @@ void test() {
 
   // Mode: default
   {
-    SpStream rhsSpStream{sp};
-    SpStream sps(std::move(rhsSpStream));
-    assert(sps.span().data() == arr);
-    assert(!sps.span().empty());
-    assert(sps.span().size() == 4);
+    SpStream rhsSpSt{sp};
+    SpStream spSt(std::move(rhsSpSt));
+    assert(spSt.span().data() == arr);
+    assert(!spSt.span().empty());
+    assert(spSt.span().size() == 4);
   }
   // Mode: `ios_base::in`
   {
-    SpStream rhsSpStream{sp, std::ios_base::in};
-    SpStream sps(std::move(rhsSpStream));
-    assert(sps.span().data() == arr);
-    assert(!sps.span().empty());
-    assert(sps.span().size() == 4);
+    SpStream rhsSpSt{sp, std::ios_base::in};
+    SpStream spSt(std::move(rhsSpSt));
+    assert(spSt.span().data() == arr);
+    assert(!spSt.span().empty());
+    assert(spSt.span().size() == 4);
   }
   // Mode `ios_base::out`
   {
-    SpStream rhsSpStream{sp, std::ios_base::out};
-    SpStream sps(std::move(rhsSpStream));
-    assert(sps.span().data() == arr);
-    assert(sps.span().empty());
-    assert(sps.span().size() == 0);
+    SpStream rhsSpSt{sp, std::ios_base::out};
+    SpStream spSt(std::move(rhsSpSt));
+    assert(spSt.span().data() == arr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
   }
   // Mode: multiple
   {
-    SpStream rhsSpStream{sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary};
-    SpStream sps(std::move(rhsSpStream));
-    assert(sps.span().data() == arr);
-    assert(sps.span().empty());
-    assert(sps.span().size() == 0);
+    SpStream rhsSpSt{sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary};
+    SpStream spSt(std::move(rhsSpSt));
+    assert(spSt.span().data() == arr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
   }
 }
 
diff --git a/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/span.mode.pass.cpp b/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/span.mode.pass.cpp
index cd793210e2c06..3502bbc1d676d 100644
--- a/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/span.mode.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/span.mode.pass.cpp
@@ -69,55 +69,55 @@ void test() {
 
   // Mode: default
   {
-    SpStream sps(sp);
-    assert(sps.span().data() == arr);
-    assert(!sps.span().empty());
-    assert(sps.span().size() == 4);
+    SpStream spSt(sp);
+    assert(spSt.span().data() == arr);
+    assert(!spSt.span().empty());
+    assert(spSt.span().size() == 4);
   }
   {
-    SpStream sps(std::as_const(sp));
-    assert(sps.span().data() == arr);
-    assert(!sps.span().empty());
-    assert(sps.span().size() == 4);
+    SpStream spSt(std::as_const(sp));
+    assert(spSt.span().data() == arr);
+    assert(!spSt.span().empty());
+    assert(spSt.span().size() == 4);
   }
   // Mode: `ios_base::in`
   {
-    SpStream sps(sp, std::ios_base::in);
-    assert(sps.span().data() == arr);
-    assert(!sps.span().empty());
-    assert(sps.span().size() == 4);
+    SpStream spSt(sp, std::ios_base::in);
+    assert(spSt.span().data() == arr);
+    assert(!spSt.span().empty());
+    assert(spSt.span().size() == 4);
   }
   {
-    SpStream sps(std::as_const(sp), std::ios_base::in);
-    assert(sps.span().data() == arr);
-    assert(!sps.span().empty());
-    assert(sps.span().size() == 4);
+    SpStream spSt(std::as_const(sp), std::ios_base::in);
+    assert(spSt.span().data() == arr);
+    assert(!spSt.span().empty());
+    assert(spSt.span().size() == 4);
   }
   // Mode `ios_base::out`
   {
-    SpStream sps(sp, std::ios_base::out);
-    assert(sps.span().data() == arr);
-    assert(sps.span().empty());
-    assert(sps.span().size() == 0);
+    SpStream spSt(sp, std::ios_base::out);
+    assert(spSt.span().data() == arr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
   }
   {
-    SpStream sps(std::as_const(sp), std::ios_base::out);
-    assert(sps.span().data() == arr);
-    assert(sps.span().empty());
-    assert(sps.span().size() == 0);
+    SpStream spSt(std::as_const(sp), std::ios_base::out);
+    assert(spSt.span().data() == arr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
   }
   // Mode: multiple
   {
-    SpStream sps(sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary);
-    assert(sps.span().data() == arr);
-    assert(sps.span().empty());
-    assert(sps.span().size() == 0);
+    SpStream spSt(sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary);
+    assert(spSt.span().data() == arr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
   }
   {
-    SpStream sps(std::as_const(sp), std::ios_base::in | std::ios_base::out | std::ios_base::binary);
-    assert(sps.span().data() == arr);
-    assert(sps.span().empty());
-    assert(sps.span().size() == 0);
+    SpStream spSt(std::as_const(sp), std::ios_base::in | std::ios_base::out | std::ios_base::binary);
+    assert(spSt.span().data() == arr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
   }
 }
 
diff --git a/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.cons/move.pass.cpp b/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.cons/move.pass.cpp
index 895e07cdf7ecb..43354d6b8dfcb 100644
--- a/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.cons/move.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.cons/move.pass.cpp
@@ -36,35 +36,35 @@ void test() {
 
   // Mode: default
   {
-    SpStream rhsSpStream{sp};
-    SpStream sps(std::move(rhsSpStream));
-    assert(sps.span().data() == arr);
-    assert(sps.span().empty());
-    assert(sps.span().size() == 0);
+    SpStream rhsSpSt{sp};
+    SpStream spSt(std::move(rhsSpSt));
+    assert(spSt.span().data() == arr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
   }
   // Mode: `ios_base::in`
   {
-    SpStream rhsSpStream{sp, std::ios_base::in};
-    SpStream sps(std::move(rhsSpStream));
-    assert(sps.span().data() == arr);
-    assert(sps.span().empty());
-    assert(sps.span().size() == 0);
+    SpStream rhsSpSt{sp, std::ios_base::in};
+    SpStream spSt(std::move(rhsSpSt));
+    assert(spSt.span().data() == arr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
   }
   // Mode `ios_base::out`
   {
-    SpStream rhsSpStream{sp, std::ios_base::out};
-    SpStream sps(std::move(rhsSpStream));
-    assert(sps.span().data() == arr);
-    assert(sps.span().empty());
-    assert(sps.span().size() == 0);
+    SpStream rhsSpSt{sp, std::ios_base::out};
+    SpStream spSt(std::move(rhsSpSt));
+    assert(spSt.span().data() == arr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
   }
   // Mode: multiple
   {
-    SpStream rhsSpStream{sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary};
-    SpStream sps(std::move(rhsSpStream));
-    assert(sps.span().data() == arr);
-    assert(sps.span().empty());
-    assert(sps.span().size() == 0);
+    SpStream rhsSpSt{sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary};
+    SpStream spSt(std::move(rhsSpSt));
+    assert(spSt.span().data() == arr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
   }
 }
 
diff --git a/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.cons/span.mode.pass.cpp b/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.cons/span.mode.pass.cpp
index 086ea7c765382..f353719875bc9 100644
--- a/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.cons/span.mode.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.cons/span.mode.pass.cpp
@@ -69,55 +69,55 @@ void test() {
 
   // Mode: default
   {
-    SpStream sps(sp);
-    assert(sps.span().data() == arr);
-    assert(sps.span().empty());
-    assert(sps.span().size() == 0);
+    SpStream spSt(sp);
+    assert(spSt.span().data() == arr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
   }
   {
-    SpStream sps(std::as_const(sp));
-    assert(sps.span().data() == arr);
-    assert(sps.span().empty());
-    assert(sps.span().size() == 0);
+    SpStream spSt(std::as_const(sp));
+    assert(spSt.span().data() == arr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
   }
   // Mode: `ios_base::in`
   {
-    SpStream sps(sp, std::ios_base::in);
-    assert(sps.span().data() == arr);
-    assert(sps.span().empty());
-    assert(sps.span().size() == 0);
+    SpStream spSt(sp, std::ios_base::in);
+    assert(spSt.span().data() == arr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
   }
   {
-    SpStream sps(std::as_const(sp), std::ios_base::in);
-    assert(sps.span().data() == arr);
-    assert(sps.span().empty());
-    assert(sps.span().size() == 0);
+    SpStream spSt(std::as_const(sp), std::ios_base::in);
+    assert(spSt.span().data() == arr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
   }
   // Mode `ios_base::out`
   {
-    SpStream sps(sp, std::ios_base::out);
-    assert(sps.span().data() == arr);
-    assert(sps.span().empty());
-    assert(sps.span().size() == 0);
+    SpStream spSt(sp, std::ios_base::out);
+    assert(spSt.span().data() == arr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
   }
   {
-    SpStream sps(std::as_const(sp), std::ios_base::out);
-    assert(sps.span().data() == arr);
-    assert(sps.span().empty());
-    assert(sps.span().size() == 0);
+    SpStream spSt(std::as_const(sp), std::ios_base::out);
+    assert(spSt.span().data() == arr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
   }
   // Mode: multiple
   {
-    SpStream sps(sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary);
-    assert(sps.span().data() == arr);
-    assert(sps.span().empty());
-    assert(sps.span().size() == 0);
+    SpStream spSt(sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary);
+    assert(spSt.span().data() == arr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
   }
   {
-    SpStream sps(std::as_const(sp), std::ios_base::in | std::ios_base::out | std::ios_base::binary);
-    assert(sps.span().data() == arr);
-    assert(sps.span().empty());
-    assert(sps.span().size() == 0);
+    SpStream spSt(std::as_const(sp), std::ios_base::in | std::ios_base::out | std::ios_base::binary);
+    assert(spSt.span().data() == arr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
   }
 }
 
diff --git a/libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/move.pass.cpp b/libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/move.pass.cpp
index 1a02487d07198..73206597cd27d 100644
--- a/libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/move.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/move.pass.cpp
@@ -36,35 +36,35 @@ void test() {
 
   // Mode: default
   {
-    SpStream rhsSpStream{sp};
-    SpStream sps(std::move(rhsSpStream));
-    assert(sps.span().data() == arr);
-    assert(sps.span().empty());
-    assert(sps.span().size() == 0);
+    SpStream rhsSpSt{sp};
+    SpStream spSt(std::move(rhsSpSt));
+    assert(spSt.span().data() == arr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
   }
   // Mode: `ios_base::in`
   {
-    SpStream rhsSpStream{sp, std::ios_base::in};
-    SpStream sps(std::move(rhsSpStream));
-    assert(sps.span().data() == arr);
-    assert(!sps.span().empty());
-    assert(sps.span().size() == 4);
+    SpStream rhsSpSt{sp, std::ios_base::in};
+    SpStream spSt(std::move(rhsSpSt));
+    assert(spSt.span().data() == arr);
+    assert(!spSt.span().empty());
+    assert(spSt.span().size() == 4);
   }
   // Mode `ios_base::out`
   {
-    SpStream rhsSpStream{sp, std::ios_base::out};
-    SpStream sps(std::move(rhsSpStream));
-    assert(sps.span().data() == arr);
-    assert(sps.span().empty());
-    assert(sps.span().size() == 0);
+    SpStream rhsSpSt{sp, std::ios_base::out};
+    SpStream spSt(std::move(rhsSpSt));
+    assert(spSt.span().data() == arr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
   }
   // Mode: multiple
   {
-    SpStream rhsSpStream{sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary};
-    SpStream sps(std::move(rhsSpStream));
-    assert(sps.span().data() == arr);
-    assert(sps.span().empty());
-    assert(sps.span().size() == 0);
+    SpStream rhsSpSt{sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary};
+    SpStream spSt(std::move(rhsSpSt));
+    assert(spSt.span().data() == arr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
   }
 }
 
diff --git a/libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/span.mode.pass.cpp b/libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/span.mode.pass.cpp
index 8fcc216b2ef6b..61a1a2530ad75 100644
--- a/libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/span.mode.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/span.mode.pass.cpp
@@ -69,55 +69,55 @@ void test() {
 
   // Mode: default
   {
-    SpStream sps(sp);
-    assert(sps.span().data() == arr);
-    assert(sps.span().empty());
-    assert(sps.span().size() == 0);
+    SpStream spSt(sp);
+    assert(spSt.span().data() == arr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
   }
   {
-    SpStream sps(std::as_const(sp));
-    assert(sps.span().data() == arr);
-    assert(sps.span().empty());
-    assert(sps.span().size() == 0);
+    SpStream spSt(std::as_const(sp));
+    assert(spSt.span().data() == arr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
   }
   // Mode: `ios_base::in`
   {
-    SpStream sps(sp, std::ios_base::in);
-    assert(sps.span().data() == arr);
-    assert(!sps.span().empty());
-    assert(sps.span().size() == 4);
+    SpStream spSt(sp, std::ios_base::in);
+    assert(spSt.span().data() == arr);
+    assert(!spSt.span().empty());
+    assert(spSt.span().size() == 4);
   }
   {
-    SpStream sps(std::as_const(sp), std::ios_base::in);
-    assert(sps.span().data() == arr);
-    assert(!sps.span().empty());
-    assert(sps.span().size() == 4);
+    SpStream spSt(std::as_const(sp), std::ios_base::in);
+    assert(spSt.span().data() == arr);
+    assert(!spSt.span().empty());
+    assert(spSt.span().size() == 4);
   }
   // Mode `ios_base::out`
   {
-    SpStream sps(sp, std::ios_base::out);
-    assert(sps.span().data() == arr);
-    assert(sps.span().empty());
-    assert(sps.span().size() == 0);
+    SpStream spSt(sp, std::ios_base::out);
+    assert(spSt.span().data() == arr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
   }
   {
-    SpStream sps(std::as_const(sp), std::ios_base::out);
-    assert(sps.span().data() == arr);
-    assert(sps.span().empty());
-    assert(sps.span().size() == 0);
+    SpStream spSt(std::as_const(sp), std::ios_base::out);
+    assert(spSt.span().data() == arr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
   }
   // Mode: multiple
   {
-    SpStream sps(sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary);
-    assert(sps.span().data() == arr);
-    assert(sps.span().empty());
-    assert(sps.span().size() == 0);
+    SpStream spSt(sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary);
+    assert(spSt.span().data() == arr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
   }
   {
-    SpStream sps(std::as_const(sp), std::ios_base::in | std::ios_base::out | std::ios_base::binary);
-    assert(sps.span().data() == arr);
-    assert(sps.span().empty());
-    assert(sps.span().size() == 0);
+    SpStream spSt(std::as_const(sp), std::ios_base::in | std::ios_base::out | std::ios_base::binary);
+    assert(spSt.span().data() == arr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
   }
 }
 

>From 32fb9fde7bd22c4e00f9cba9b809efbf6650d2b1 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Sun, 3 Mar 2024 18:08:43 +0200
Subject: [PATCH 17/56] Tests: added `ReadonlySpan` type

---
 .../ispanstream/ispanstream.cons/ros.pass.cpp |   2 +
 .../std/input.output/span.streams/types.h     | 230 +++++++++++++++---
 2 files changed, 193 insertions(+), 39 deletions(-)

diff --git a/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/ros.pass.cpp b/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/ros.pass.cpp
index 421ba8ff10e16..017cf24a89d7b 100644
--- a/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/ros.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/ros.pass.cpp
@@ -25,6 +25,8 @@
 #include "nasty_string.h"
 #include "test_macros.h"
 
+#include "../../types.h"
+
 #ifndef TEST_HAS_NO_NASTY_STRING
 void test_sfinae_with_nasty_char() {
   using SpStream = std::basic_ispanstream<nasty_char, nasty_char_traits>;
diff --git a/libcxx/test/std/input.output/span.streams/types.h b/libcxx/test/std/input.output/span.streams/types.h
index 18788a56579dc..0d8eecd5f4db0 100644
--- a/libcxx/test/std/input.output/span.streams/types.h
+++ b/libcxx/test/std/input.output/span.streams/types.h
@@ -9,62 +9,214 @@
 #ifndef TEST_STD_INPUTOUTPUT_SPANSTREAMS_TYPES_H
 #define TEST_STD_INPUTOUTPUT_SPANSTREAMS_TYPES_H
 
-#include <string_view>
 #include <concepts>
+#include <cstddef>
+#include <span>
+#include <ranges>
 
 #include "test_macros.h"
 
-// template <typename CharT, class Traits = std::char_traits<CharT>>
-// class ConstConvertibleStringView {
-// public:
-//   explicit ConstConvertibleStringView(const CharT* cs) : cs_{cs} {}
+template <typename CharT, std::size_t N = 0>
+class ReadOnlySpan {
+  explicit ReadOnlySpan(CharT (&arr)[N]) : arr_{arr} {}
 
-//   operator std::basic_string_view<CharT, Traits>() = delete;
-//   operator std::basic_string_view<CharT, Traits>() const { return std::basic_string_view<CharT, Traits>(cs_); }
+public:
+  operator std::span<CharT>() = delete;
 
-// private:
-//   const CharT* cs_;
-// };
+  operator std::span<const CharT>() { return std::span<const CharT, N>{arr_}; }
 
-// static_assert(!std::constructible_from<std::basic_string_view<char>, ConstConvertibleStringView<char>>);
-// static_assert(!std::convertible_to<ConstConvertibleStringView<char>, std::basic_string_view<char>>);
+  const CharT* begin() { return arr_; }
+  const CharT* end() { return arr_ + N; }
 
-// static_assert(std::constructible_from<std::basic_string_view<char>, const ConstConvertibleStringView<char>>);
-// static_assert(std::convertible_to<const ConstConvertibleStringView<char>, std::basic_string_view<char>>);
+private:
+  CharT* arr_;
+};
 
-// #ifndef TEST_HAS_NO_WIDE_CHARACTERS
-// static_assert(!std::constructible_from<std::basic_string_view<wchar_t>, ConstConvertibleStringView<wchar_t>>);
-// static_assert(!std::convertible_to<ConstConvertibleStringView<wchar_t>, std::basic_string_view<wchar_t>>);
+template <typename CharT, std::size_t N>
+inline constexpr bool std::ranges::enable_borrowed_range<ReadOnlySpan<CharT, N>> = true;
 
-// static_assert(std::constructible_from<std::basic_string_view<wchar_t>, const ConstConvertibleStringView<wchar_t>>);
-// static_assert(std::convertible_to<const ConstConvertibleStringView<wchar_t>, std::basic_string_view<wchar_t>>);
-// #endif
+static_assert(std::ranges::borrowed_range<ReadOnlySpan<char>>);
 
-// template <typename CharT, class Traits = std::char_traits<CharT>>
-// class NonConstConvertibleStringView {
-// public:
-//   explicit NonConstConvertibleStringView(const CharT* cs) : cs_{cs} {}
+static_assert(!std::constructible_from<std::span<char>, ReadOnlySpan<char>>);
+static_assert(!std::convertible_to<ReadOnlySpan<char>, std::span<char>>);
 
-//   operator std::basic_string_view<CharT, Traits>() { return std::basic_string_view<CharT, Traits>(cs_); }
-//   operator std::basic_string_view<CharT, Traits>() const = delete;
+static_assert(!std::constructible_from<std::span<char>, const ReadOnlySpan<char>>);
+static_assert(!std::convertible_to<const ReadOnlySpan<char>, std::span<char>>);
 
-// private:
-//   const CharT* cs_;
-// };
+static_assert(std::constructible_from<std::span<const char>, ReadOnlySpan<char>>);
+static_assert(std::convertible_to<ReadOnlySpan<char>, std::span<const char>>);
 
-// static_assert(std::constructible_from<std::basic_string_view<char>, NonConstConvertibleStringView<char>>);
-// static_assert(std::convertible_to<NonConstConvertibleStringView<char>, std::basic_string_view<char>>);
+static_assert(!std::constructible_from<std::span<const char>, const ReadOnlySpan<char>>);
+static_assert(!std::convertible_to<const ReadOnlySpan<char>, std::span<const char>>);
 
-// static_assert(!std::constructible_from<std::basic_string_view<char>, const NonConstConvertibleStringView<char>>);
-// static_assert(!std::convertible_to<const NonConstConvertibleStringView<char>, std::basic_string_view<char>>);
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
 
-// #ifndef TEST_HAS_NO_WIDE_CHARACTERS
-// static_assert(std::constructible_from<std::basic_string_view<wchar_t>, NonConstConvertibleStringView<wchar_t>>);
-// static_assert(std::convertible_to<NonConstConvertibleStringView<wchar_t>, std::basic_string_view<wchar_t>>);
+static_assert(std::ranges::borrowed_range<ReadOnlySpan<wchar_t>>);
 
-// static_assert(!std::constructible_from<std::basic_string_view<wchar_t>, const NonConstConvertibleStringView<wchar_t>>);
-// static_assert(!std::convertible_to<const NonConstConvertibleStringView<wchar_t>, std::basic_string_view<wchar_t>>);
-// #endif
+static_assert(!std::constructible_from<std::span<wchar_t>, ReadOnlySpan<wchar_t>>);
+static_assert(!std::convertible_to<ReadOnlySpan<wchar_t>, std::span<wchar_t>>);
+
+static_assert(!std::constructible_from<std::span<wchar_t>, const ReadOnlySpan<wchar_t>>);
+static_assert(!std::convertible_to<const ReadOnlySpan<wchar_t>, std::span<wchar_t>>);
+
+static_assert(std::constructible_from<std::span<const wchar_t>, ReadOnlySpan<wchar_t>>);
+static_assert(std::convertible_to<ReadOnlySpan<wchar_t>, std::span<const wchar_t>>);
+
+static_assert(!std::constructible_from<std::span<const wchar_t>, const ReadOnlySpan<wchar_t>>);
+static_assert(!std::convertible_to<const ReadOnlySpan<wchar_t>, std::span<const wchar_t>>);
+#endif
+
+template <typename CharT, std::size_t N = 0>
+class NonReadOnlySpan {
+  explicit NonReadOnlySpan(CharT (&arr)[N]) : arr_{arr} {}
+
+public:
+  operator std::span<CharT>() { return std::span<CharT, N>{arr_}; }
+
+  operator std::span<const CharT>() = delete;
+
+  CharT* begin() { return arr_; }
+  CharT* end() { return arr_ + N; }
+
+private:
+  CharT* arr_;
+};
+
+template <typename CharT, std::size_t N>
+inline constexpr bool std::ranges::enable_borrowed_range<NonReadOnlySpan<CharT, N>> = true;
+
+static_assert(std::ranges::borrowed_range<NonReadOnlySpan<char>>);
+
+static_assert(std::constructible_from<std::span<char>, NonReadOnlySpan<char>>);
+static_assert(std::convertible_to<NonReadOnlySpan<char>, std::span<char>>);
+
+static_assert(!std::constructible_from<std::span<char>, const NonReadOnlySpan<char>>);
+static_assert(!std::convertible_to<const NonReadOnlySpan<char>, std::span<char>>);
+
+static_assert(std::constructible_from<std::span<const char>, NonReadOnlySpan<char>>);
+static_assert(!std::convertible_to<NonReadOnlySpan<char>, std::span<const char>>);
+
+static_assert(!std::constructible_from<std::span<const char>, const NonReadOnlySpan<char>>);
+static_assert(!std::convertible_to<const NonReadOnlySpan<char>, std::span<const char>>);
+
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+static_assert(std::ranges::borrowed_range<NonReadOnlySpan<wchar_t>>);
+
+static_assert(std::constructible_from<std::span<wchar_t>, NonReadOnlySpan<wchar_t>>);
+static_assert(std::convertible_to<NonReadOnlySpan<wchar_t>, std::span<wchar_t>>);
+
+static_assert(!std::constructible_from<std::span<wchar_t>, const NonReadOnlySpan<wchar_t>>);
+static_assert(!std::convertible_to<const NonReadOnlySpan<wchar_t>, std::span<wchar_t>>);
+
+static_assert(std::constructible_from<std::span<const wchar_t>, NonReadOnlySpan<wchar_t>>);
+static_assert(!std::convertible_to<NonReadOnlySpan<wchar_t>, std::span<const wchar_t>>);
+
+static_assert(!std::constructible_from<std::span<const wchar_t>, const NonReadOnlySpan<wchar_t>>);
+static_assert(!std::convertible_to<const NonReadOnlySpan<wchar_t>, std::span<const wchar_t>>);
+#endif
+
+template <typename CharT, std::size_t N = 0>
+class ConstConvertibleReadOnlySpan {
+  explicit ConstConvertibleReadOnlySpan(CharT (&arr)[N]) : arr_{arr} {}
+
+public:
+  operator std::span<CharT>()       = delete;
+  operator std::span<CharT>() const = delete;
+
+  operator std::span<const CharT>() = delete;
+  operator std::span<const CharT>() const { return std::span<const CharT, N>{arr_}; }
+
+  const CharT* begin() { return arr_; }
+  const CharT* end() { return arr_ + N; }
+
+private:
+  CharT* arr_;
+};
+
+template <typename CharT, std::size_t N>
+inline constexpr bool std::ranges::enable_borrowed_range<ConstConvertibleReadOnlySpan<CharT, N>> = true;
+
+static_assert(std::ranges::borrowed_range<ConstConvertibleReadOnlySpan<char>>);
+
+static_assert(!std::constructible_from<std::span<char>, ConstConvertibleReadOnlySpan<char>>);
+static_assert(!std::convertible_to<ConstConvertibleReadOnlySpan<char>, std::span<char>>);
+
+static_assert(!std::constructible_from<std::span<char>, const ConstConvertibleReadOnlySpan<char>>);
+static_assert(!std::convertible_to<const ConstConvertibleReadOnlySpan<char>, std::span<char>>);
+
+static_assert(std::constructible_from<std::span<const char>, ConstConvertibleReadOnlySpan<char>>);
+static_assert(!std::convertible_to<ConstConvertibleReadOnlySpan<char>, std::span<const char>>);
+
+static_assert(std::constructible_from<std::span<const char>, const ConstConvertibleReadOnlySpan<char>>);
+static_assert(std::convertible_to<const ConstConvertibleReadOnlySpan<char>, std::span<const char>>);
+
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+
+static_assert(std::ranges::borrowed_range<ConstConvertibleReadOnlySpan<wchar_t>>);
+
+static_assert(!std::constructible_from<std::span<wchar_t>, ConstConvertibleReadOnlySpan<wchar_t>>);
+static_assert(!std::convertible_to<ConstConvertibleReadOnlySpan<wchar_t>, std::span<wchar_t>>);
+
+static_assert(!std::constructible_from<std::span<wchar_t>, const ConstConvertibleReadOnlySpan<wchar_t>>);
+static_assert(!std::convertible_to<const ConstConvertibleReadOnlySpan<wchar_t>, std::span<wchar_t>>);
+
+static_assert(std::constructible_from<std::span<const wchar_t>, ConstConvertibleReadOnlySpan<wchar_t>>);
+static_assert(!std::convertible_to<ConstConvertibleReadOnlySpan<wchar_t>, std::span<const wchar_t>>);
+
+static_assert(std::constructible_from<std::span<const wchar_t>, const ConstConvertibleReadOnlySpan<wchar_t>>);
+static_assert(std::convertible_to<const ConstConvertibleReadOnlySpan<wchar_t>, std::span<const wchar_t>>);
+#endif
+
+template <typename CharT, std::size_t N = 0>
+class NonConstConvertibleReadOnlySpan {
+  explicit NonConstConvertibleReadOnlySpan(CharT (&arr)[N]) : arr_{arr} {}
+
+public:
+  operator std::span<CharT>()       = delete;
+  operator std::span<CharT>() const = delete;
+
+  operator std::span<const CharT>() { return std::span<const CharT, N>{arr_}; }
+  operator std::span<const CharT>() const = delete;
+
+  const CharT* begin() { return arr_; }
+  const CharT* end() { return arr_ + N; }
+
+private:
+  CharT* arr_;
+};
+
+template <typename CharT, std::size_t N>
+inline constexpr bool std::ranges::enable_borrowed_range<NonConstConvertibleReadOnlySpan<CharT, N>> = true;
+
+static_assert(std::ranges::borrowed_range<NonConstConvertibleReadOnlySpan<char>>);
+
+static_assert(!std::constructible_from<std::span<char>, NonConstConvertibleReadOnlySpan<char>>);
+static_assert(!std::convertible_to<NonConstConvertibleReadOnlySpan<char>, std::span<char>>);
+
+static_assert(!std::constructible_from<std::span<char>, const NonConstConvertibleReadOnlySpan<char>>);
+static_assert(!std::convertible_to<const NonConstConvertibleReadOnlySpan<char>, std::span<char>>);
+
+static_assert(std::constructible_from<std::span<const char>, NonConstConvertibleReadOnlySpan<char>>);
+static_assert(std::convertible_to<NonConstConvertibleReadOnlySpan<char>, std::span<const char>>);
+
+static_assert(!std::constructible_from<std::span<const char>, const NonConstConvertibleReadOnlySpan<char>>);
+static_assert(!std::convertible_to<const NonConstConvertibleReadOnlySpan<char>, std::span<const char>>);
+
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+static_assert(std::ranges::borrowed_range<NonConstConvertibleReadOnlySpan<wchar_t>>);
+
+static_assert(!std::constructible_from<std::span<wchar_t>, NonConstConvertibleReadOnlySpan<wchar_t>>);
+static_assert(!std::convertible_to<NonConstConvertibleReadOnlySpan<wchar_t>, std::span<wchar_t>>);
+
+static_assert(!std::constructible_from<std::span<wchar_t>, const NonConstConvertibleReadOnlySpan<wchar_t>>);
+static_assert(!std::convertible_to<const NonConstConvertibleReadOnlySpan<wchar_t>, std::span<wchar_t>>);
+
+static_assert(std::constructible_from<std::span<const wchar_t>, NonConstConvertibleReadOnlySpan<wchar_t>>);
+static_assert(std::convertible_to<NonConstConvertibleReadOnlySpan<wchar_t>, std::span<const wchar_t>>);
+
+static_assert(!std::constructible_from<std::span<const wchar_t>, const NonConstConvertibleReadOnlySpan<wchar_t>>);
+static_assert(!std::convertible_to<const NonConstConvertibleReadOnlySpan<wchar_t>, std::span<const wchar_t>>);
+#endif
 
 struct SomeObject {};
 

>From d93a27d39b9b5ca5e5b48f78ec446e4c1724de39 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Mon, 4 Mar 2024 07:42:41 +0200
Subject: [PATCH 18/56] Tests: WIP `ROS` constructor

---
 libcxx/include/spanstream                     |  7 +++
 .../{macros.h => helper_macros.h}             |  0
 .../span.streams/{types.h => helper_types.h}  | 21 +++++--
 .../ispanstream/ispanstream.cons/ros.pass.cpp | 62 +++++++++++++++++--
 .../ispanstream.cons/span.mode.pass.cpp       |  4 +-
 .../input.output/span.streams/lit.local.cfg   |  3 +
 .../ospanstream.cons/span.mode.pass.cpp       |  4 +-
 .../spanbuf/spanbuf.cons/mode.pass.cpp        |  2 +-
 .../spanbuf/spanbuf.cons/span.mode.pass.cpp   |  4 +-
 .../spanstream.cons/span.mode.pass.cpp        |  4 +-
 10 files changed, 93 insertions(+), 18 deletions(-)
 rename libcxx/test/std/input.output/span.streams/{macros.h => helper_macros.h} (100%)
 rename libcxx/test/std/input.output/span.streams/{types.h => helper_types.h} (96%)
 create mode 100644 libcxx/test/std/input.output/span.streams/lit.local.cfg

diff --git a/libcxx/include/spanstream b/libcxx/include/spanstream
index 70e6faa4206fb..14fd39d93e991 100644
--- a/libcxx/include/spanstream
+++ b/libcxx/include/spanstream
@@ -66,6 +66,7 @@
 #include <__utility/move.h>
 #include <__utility/swap.h>
 #include <iostream>
+#include <print>
 #include <span>
 #include <streambuf>
 #include <version>
@@ -266,8 +267,14 @@ public:
     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::println(stderr, "ispanstream");
     std::span<const _CharT> __sp(std::forward<_ROSeq>(__s));
+    std::println(stderr, "span __sb_ {} {}", __sb_.span().empty(), __sb_.span().size());
+    std::println(stderr, "span data {} {}", __sp.empty(), __sp.size());
+    std::println(stderr, "ispanstream 2");
     this->span(std::span<_CharT>(std::span<_CharT>(const_cast<_CharT*>(__sp.data()), __sp.size())));
+    std::println(stderr, "span __sb_ {} {}", __sb_.span().empty(), __sb_.span().size());
+    std::println(stderr, "ispanstream 3");
   }
 
   basic_ispanstream& operator=(const basic_ispanstream&) = delete;
diff --git a/libcxx/test/std/input.output/span.streams/macros.h b/libcxx/test/std/input.output/span.streams/helper_macros.h
similarity index 100%
rename from libcxx/test/std/input.output/span.streams/macros.h
rename to libcxx/test/std/input.output/span.streams/helper_macros.h
diff --git a/libcxx/test/std/input.output/span.streams/types.h b/libcxx/test/std/input.output/span.streams/helper_types.h
similarity index 96%
rename from libcxx/test/std/input.output/span.streams/types.h
rename to libcxx/test/std/input.output/span.streams/helper_types.h
index 0d8eecd5f4db0..81fb2c7557714 100644
--- a/libcxx/test/std/input.output/span.streams/types.h
+++ b/libcxx/test/std/input.output/span.streams/helper_types.h
@@ -16,17 +16,28 @@
 
 #include "test_macros.h"
 
+#include <print>
+
 template <typename CharT, std::size_t N = 0>
 class ReadOnlySpan {
+public:
   explicit ReadOnlySpan(CharT (&arr)[N]) : arr_{arr} {}
 
-public:
   operator std::span<CharT>() = delete;
 
-  operator std::span<const CharT>() { return std::span<const CharT, N>{arr_}; }
+  operator std::span<const CharT>() {
+    std::println(stderr, "----> ROspan");
+    return std::span<const CharT, N>{arr_};
+  }
 
-  const CharT* begin() { return arr_; }
-  const CharT* end() { return arr_ + N; }
+  const CharT* begin() {
+    std::println(stderr, "----> ROspan begin");
+    return arr_;
+  }
+  const CharT* end() {
+    std::println(stderr, "----> ROspan end");
+    return arr_ + N;
+  }
 
 private:
   CharT* arr_;
@@ -68,9 +79,9 @@ static_assert(!std::convertible_to<const ReadOnlySpan<wchar_t>, std::span<const
 
 template <typename CharT, std::size_t N = 0>
 class NonReadOnlySpan {
+public:
   explicit NonReadOnlySpan(CharT (&arr)[N]) : arr_{arr} {}
 
-public:
   operator std::span<CharT>() { return std::span<CharT, N>{arr_}; }
 
   operator std::span<const CharT>() = delete;
diff --git a/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/ros.pass.cpp b/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/ros.pass.cpp
index 017cf24a89d7b..7a4f0f422404f 100644
--- a/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/ros.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/ros.pass.cpp
@@ -19,27 +19,60 @@
 //     template<class ROS> explicit basic_ispanstream(ROS&& s);
 
 #include <cassert>
+#include <concepts>
 #include <spanstream>
 
 #include "constexpr_char_traits.h"
 #include "nasty_string.h"
+#include "test_convertible.h"
 #include "test_macros.h"
 
-#include "../../types.h"
+#include "../../helper_types.h"
 
 #ifndef TEST_HAS_NO_NASTY_STRING
 void test_sfinae_with_nasty_char() {
   using SpStream = std::basic_ispanstream<nasty_char, nasty_char_traits>;
 
-  // TODO:
+  // Non-const convertible
+  static_assert(std::constructible_from<SpStream, ReadOnlySpan<nasty_char>>);
+  static_assert(!test_convertible<SpStream, ReadOnlySpan<nasty_char>>());
+
+  // Const convertible
+  static_assert(!std::constructible_from<SpStream, const ReadOnlySpan<nasty_char>>);
+  static_assert(!test_convertible<SpStream, const ReadOnlySpan<nasty_char>>());
+
+  // Non-const non-convertible
+  static_assert(std::constructible_from<SpStream, ReadOnlySpan<nasty_char>>);
+  static_assert(!test_convertible<SpStream, ReadOnlySpan<nasty_char>>());
+
+  // Const non-convertible
+  static_assert(!std::constructible_from<SpStream, const ReadOnlySpan<nasty_char>>);
+  static_assert(!test_convertible<SpStream, const ReadOnlySpan<nasty_char>>());
 }
 #endif // TEST_HAS_NO_NASTY_STRING
 
 template <typename CharT, typename TraitsT = std::char_traits<CharT>>
 void test_sfinae() {
-  using SpStream = std::basic_ispanstream<CharT, TraitsT>;
+  using SpStream =
+      std::conditional_t<std::same_as<CharT, nasty_char>,
+                         std::basic_ispanstream<nasty_char, nasty_char_traits>,
+                         std::basic_ispanstream<CharT, TraitsT>>;
 
-  // TODO:
+  // Non-const convertible
+  static_assert(std::constructible_from<SpStream, ReadOnlySpan<CharT>>);
+  static_assert(!test_convertible<SpStream, ReadOnlySpan<CharT>>());
+
+  // Const convertible
+  static_assert(!std::constructible_from<SpStream, const ReadOnlySpan<CharT>>);
+  static_assert(!test_convertible<SpStream, const ReadOnlySpan<CharT>>());
+
+  // Non-const non-convertible
+  static_assert(std::constructible_from<SpStream, NonReadOnlySpan<CharT>>);
+  static_assert(!test_convertible<SpStream, NonReadOnlySpan<CharT>>());
+
+  // Const non-convertible
+  static_assert(!std::constructible_from<SpStream, const NonReadOnlySpan<CharT>>);
+  static_assert(!test_convertible<SpStream, const NonReadOnlySpan<CharT>>());
 }
 
 template <typename CharT, typename TraitsT = std::char_traits<CharT>>
@@ -47,10 +80,31 @@ void test() {
   using SpStream = std::basic_ispanstream<CharT, TraitsT>;
 
   // TODO:
+  CharT arr[4];
+  ReadOnlySpan<CharT, 4> ros{arr};
+
+  {
+    SpStream spSt(ros);
+    assert(spSt.span().data() == arr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+  }
+
+  CharT arr1[6];
+  ReadOnlySpan<CharT, 6> ros2{arr1};
+
+  {
+    SpStream spSt(ros2);
+    assert(spSt.span().data() == arr);
+    assert(spSt.span().data() == arr1);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+  }
 }
 
 int main(int, char**) {
 #ifndef TEST_HAS_NO_NASTY_STRING
+  // test_sfinae<nasty_char, nasty_char_traits>();
   test_sfinae_with_nasty_char();
 #endif
   test_sfinae<char>();
diff --git a/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/span.mode.pass.cpp b/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/span.mode.pass.cpp
index 3502bbc1d676d..3527d197e7cdf 100644
--- a/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/span.mode.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/span.mode.pass.cpp
@@ -30,8 +30,8 @@
 #include "test_convertible.h"
 #include "test_macros.h"
 
-#include "../../macros.h"
-#include "../../types.h"
+#include "../../helper_macros.h"
+#include "../../helper_types.h"
 
 #ifndef TEST_HAS_NO_NASTY_STRING
 void test_sfinae_with_nasty_char() {
diff --git a/libcxx/test/std/input.output/span.streams/lit.local.cfg b/libcxx/test/std/input.output/span.streams/lit.local.cfg
new file mode 100644
index 0000000000000..2cb10010c4507
--- /dev/null
+++ b/libcxx/test/std/input.output/span.streams/lit.local.cfg
@@ -0,0 +1,3 @@
+# All non-trivial uses of iostreams require localization support
+if "no-localization" in config.available_features:
+    config.unsupported = True
diff --git a/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.cons/span.mode.pass.cpp b/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.cons/span.mode.pass.cpp
index f353719875bc9..e036a0be4a48b 100644
--- a/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.cons/span.mode.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.cons/span.mode.pass.cpp
@@ -30,8 +30,8 @@
 #include "test_convertible.h"
 #include "test_macros.h"
 
-#include "../../macros.h"
-#include "../../types.h"
+#include "../../helper_macros.h"
+#include "../../helper_types.h"
 
 #ifndef TEST_HAS_NO_NASTY_STRING
 void test_sfinae_with_nasty_char() {
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/mode.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/mode.pass.cpp
index eb8b29de9fbff..d040f0beb92a5 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/mode.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/mode.pass.cpp
@@ -28,7 +28,7 @@
 #include "test_convertible.h"
 #include "test_macros.h"
 
-#include "../../types.h"
+#include "../../helper_types.h"
 
 #ifndef TEST_HAS_NO_NASTY_STRING
 void test_sfinae_with_nasty_char() {
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/span.mode.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/span.mode.pass.cpp
index fbcc8eeded259..45985aed49c61 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/span.mode.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/span.mode.pass.cpp
@@ -30,8 +30,8 @@
 #include "test_convertible.h"
 #include "test_macros.h"
 
-#include "../../macros.h"
-#include "../../types.h"
+#include "../../helper_macros.h"
+#include "../../helper_types.h"
 
 #ifndef TEST_HAS_NO_NASTY_STRING
 void test_sfinae_with_nasty_char() {
diff --git a/libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/span.mode.pass.cpp b/libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/span.mode.pass.cpp
index 61a1a2530ad75..2423c92fda9f8 100644
--- a/libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/span.mode.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/span.mode.pass.cpp
@@ -30,8 +30,8 @@
 #include "test_convertible.h"
 #include "test_macros.h"
 
-#include "../../macros.h"
-#include "../../types.h"
+#include "../../helper_macros.h"
+#include "../../helper_types.h"
 
 #ifndef TEST_HAS_NO_NASTY_STRING
 void test_sfinae_with_nasty_char() {

>From 2aaedaacb3710f456a0ea4ee0fae379fba11a4b8 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Mon, 4 Mar 2024 07:47:34 +0200
Subject: [PATCH 19/56] Tests: WIP retry CI

---
 libcxx/include/spanstream                     |  14 +--
 .../input.output/span.streams/helper_types.h  | 111 +-----------------
 .../ispanstream/ispanstream.cons/ros.pass.cpp |  27 +----
 3 files changed, 13 insertions(+), 139 deletions(-)

diff --git a/libcxx/include/spanstream b/libcxx/include/spanstream
index 14fd39d93e991..c735baaae93d9 100644
--- a/libcxx/include/spanstream
+++ b/libcxx/include/spanstream
@@ -66,7 +66,7 @@
 #include <__utility/move.h>
 #include <__utility/swap.h>
 #include <iostream>
-#include <print>
+// #include <print>
 #include <span>
 #include <streambuf>
 #include <version>
@@ -267,14 +267,14 @@ public:
     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::println(stderr, "ispanstream");
+    // std::println(stderr, "ispanstream");
     std::span<const _CharT> __sp(std::forward<_ROSeq>(__s));
-    std::println(stderr, "span __sb_ {} {}", __sb_.span().empty(), __sb_.span().size());
-    std::println(stderr, "span data {} {}", __sp.empty(), __sp.size());
-    std::println(stderr, "ispanstream 2");
+    // std::println(stderr, "span __sb_ {} {}", __sb_.span().empty(), __sb_.span().size());
+    // std::println(stderr, "span data {} {}", __sp.empty(), __sp.size());
+    // std::println(stderr, "ispanstream 2");
     this->span(std::span<_CharT>(std::span<_CharT>(const_cast<_CharT*>(__sp.data()), __sp.size())));
-    std::println(stderr, "span __sb_ {} {}", __sb_.span().empty(), __sb_.span().size());
-    std::println(stderr, "ispanstream 3");
+    // std::println(stderr, "span __sb_ {} {}", __sb_.span().empty(), __sb_.span().size());
+    // std::println(stderr, "ispanstream 3");
   }
 
   basic_ispanstream& operator=(const basic_ispanstream&) = delete;
diff --git a/libcxx/test/std/input.output/span.streams/helper_types.h b/libcxx/test/std/input.output/span.streams/helper_types.h
index 81fb2c7557714..7f67432f9f880 100644
--- a/libcxx/test/std/input.output/span.streams/helper_types.h
+++ b/libcxx/test/std/input.output/span.streams/helper_types.h
@@ -16,7 +16,7 @@
 
 #include "test_macros.h"
 
-#include <print>
+// #include <print>
 
 template <typename CharT, std::size_t N = 0>
 class ReadOnlySpan {
@@ -26,16 +26,16 @@ class ReadOnlySpan {
   operator std::span<CharT>() = delete;
 
   operator std::span<const CharT>() {
-    std::println(stderr, "----> ROspan");
+    // std::println(stderr, "----> ROspan");
     return std::span<const CharT, N>{arr_};
   }
 
   const CharT* begin() {
-    std::println(stderr, "----> ROspan begin");
+    // std::println(stderr, "----> ROspan begin");
     return arr_;
   }
   const CharT* end() {
-    std::println(stderr, "----> ROspan end");
+    // std::println(stderr, "----> ROspan end");
     return arr_ + N;
   }
 
@@ -126,109 +126,6 @@ static_assert(!std::constructible_from<std::span<const wchar_t>, const NonReadOn
 static_assert(!std::convertible_to<const NonReadOnlySpan<wchar_t>, std::span<const wchar_t>>);
 #endif
 
-template <typename CharT, std::size_t N = 0>
-class ConstConvertibleReadOnlySpan {
-  explicit ConstConvertibleReadOnlySpan(CharT (&arr)[N]) : arr_{arr} {}
-
-public:
-  operator std::span<CharT>()       = delete;
-  operator std::span<CharT>() const = delete;
-
-  operator std::span<const CharT>() = delete;
-  operator std::span<const CharT>() const { return std::span<const CharT, N>{arr_}; }
-
-  const CharT* begin() { return arr_; }
-  const CharT* end() { return arr_ + N; }
-
-private:
-  CharT* arr_;
-};
-
-template <typename CharT, std::size_t N>
-inline constexpr bool std::ranges::enable_borrowed_range<ConstConvertibleReadOnlySpan<CharT, N>> = true;
-
-static_assert(std::ranges::borrowed_range<ConstConvertibleReadOnlySpan<char>>);
-
-static_assert(!std::constructible_from<std::span<char>, ConstConvertibleReadOnlySpan<char>>);
-static_assert(!std::convertible_to<ConstConvertibleReadOnlySpan<char>, std::span<char>>);
-
-static_assert(!std::constructible_from<std::span<char>, const ConstConvertibleReadOnlySpan<char>>);
-static_assert(!std::convertible_to<const ConstConvertibleReadOnlySpan<char>, std::span<char>>);
-
-static_assert(std::constructible_from<std::span<const char>, ConstConvertibleReadOnlySpan<char>>);
-static_assert(!std::convertible_to<ConstConvertibleReadOnlySpan<char>, std::span<const char>>);
-
-static_assert(std::constructible_from<std::span<const char>, const ConstConvertibleReadOnlySpan<char>>);
-static_assert(std::convertible_to<const ConstConvertibleReadOnlySpan<char>, std::span<const char>>);
-
-#ifndef TEST_HAS_NO_WIDE_CHARACTERS
-
-static_assert(std::ranges::borrowed_range<ConstConvertibleReadOnlySpan<wchar_t>>);
-
-static_assert(!std::constructible_from<std::span<wchar_t>, ConstConvertibleReadOnlySpan<wchar_t>>);
-static_assert(!std::convertible_to<ConstConvertibleReadOnlySpan<wchar_t>, std::span<wchar_t>>);
-
-static_assert(!std::constructible_from<std::span<wchar_t>, const ConstConvertibleReadOnlySpan<wchar_t>>);
-static_assert(!std::convertible_to<const ConstConvertibleReadOnlySpan<wchar_t>, std::span<wchar_t>>);
-
-static_assert(std::constructible_from<std::span<const wchar_t>, ConstConvertibleReadOnlySpan<wchar_t>>);
-static_assert(!std::convertible_to<ConstConvertibleReadOnlySpan<wchar_t>, std::span<const wchar_t>>);
-
-static_assert(std::constructible_from<std::span<const wchar_t>, const ConstConvertibleReadOnlySpan<wchar_t>>);
-static_assert(std::convertible_to<const ConstConvertibleReadOnlySpan<wchar_t>, std::span<const wchar_t>>);
-#endif
-
-template <typename CharT, std::size_t N = 0>
-class NonConstConvertibleReadOnlySpan {
-  explicit NonConstConvertibleReadOnlySpan(CharT (&arr)[N]) : arr_{arr} {}
-
-public:
-  operator std::span<CharT>()       = delete;
-  operator std::span<CharT>() const = delete;
-
-  operator std::span<const CharT>() { return std::span<const CharT, N>{arr_}; }
-  operator std::span<const CharT>() const = delete;
-
-  const CharT* begin() { return arr_; }
-  const CharT* end() { return arr_ + N; }
-
-private:
-  CharT* arr_;
-};
-
-template <typename CharT, std::size_t N>
-inline constexpr bool std::ranges::enable_borrowed_range<NonConstConvertibleReadOnlySpan<CharT, N>> = true;
-
-static_assert(std::ranges::borrowed_range<NonConstConvertibleReadOnlySpan<char>>);
-
-static_assert(!std::constructible_from<std::span<char>, NonConstConvertibleReadOnlySpan<char>>);
-static_assert(!std::convertible_to<NonConstConvertibleReadOnlySpan<char>, std::span<char>>);
-
-static_assert(!std::constructible_from<std::span<char>, const NonConstConvertibleReadOnlySpan<char>>);
-static_assert(!std::convertible_to<const NonConstConvertibleReadOnlySpan<char>, std::span<char>>);
-
-static_assert(std::constructible_from<std::span<const char>, NonConstConvertibleReadOnlySpan<char>>);
-static_assert(std::convertible_to<NonConstConvertibleReadOnlySpan<char>, std::span<const char>>);
-
-static_assert(!std::constructible_from<std::span<const char>, const NonConstConvertibleReadOnlySpan<char>>);
-static_assert(!std::convertible_to<const NonConstConvertibleReadOnlySpan<char>, std::span<const char>>);
-
-#ifndef TEST_HAS_NO_WIDE_CHARACTERS
-static_assert(std::ranges::borrowed_range<NonConstConvertibleReadOnlySpan<wchar_t>>);
-
-static_assert(!std::constructible_from<std::span<wchar_t>, NonConstConvertibleReadOnlySpan<wchar_t>>);
-static_assert(!std::convertible_to<NonConstConvertibleReadOnlySpan<wchar_t>, std::span<wchar_t>>);
-
-static_assert(!std::constructible_from<std::span<wchar_t>, const NonConstConvertibleReadOnlySpan<wchar_t>>);
-static_assert(!std::convertible_to<const NonConstConvertibleReadOnlySpan<wchar_t>, std::span<wchar_t>>);
-
-static_assert(std::constructible_from<std::span<const wchar_t>, NonConstConvertibleReadOnlySpan<wchar_t>>);
-static_assert(std::convertible_to<NonConstConvertibleReadOnlySpan<wchar_t>, std::span<const wchar_t>>);
-
-static_assert(!std::constructible_from<std::span<const wchar_t>, const NonConstConvertibleReadOnlySpan<wchar_t>>);
-static_assert(!std::convertible_to<const NonConstConvertibleReadOnlySpan<wchar_t>, std::span<const wchar_t>>);
-#endif
-
 struct SomeObject {};
 
 struct NonMode {};
diff --git a/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/ros.pass.cpp b/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/ros.pass.cpp
index 7a4f0f422404f..6425b6ed94e49 100644
--- a/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/ros.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/ros.pass.cpp
@@ -29,28 +29,6 @@
 
 #include "../../helper_types.h"
 
-#ifndef TEST_HAS_NO_NASTY_STRING
-void test_sfinae_with_nasty_char() {
-  using SpStream = std::basic_ispanstream<nasty_char, nasty_char_traits>;
-
-  // Non-const convertible
-  static_assert(std::constructible_from<SpStream, ReadOnlySpan<nasty_char>>);
-  static_assert(!test_convertible<SpStream, ReadOnlySpan<nasty_char>>());
-
-  // Const convertible
-  static_assert(!std::constructible_from<SpStream, const ReadOnlySpan<nasty_char>>);
-  static_assert(!test_convertible<SpStream, const ReadOnlySpan<nasty_char>>());
-
-  // Non-const non-convertible
-  static_assert(std::constructible_from<SpStream, ReadOnlySpan<nasty_char>>);
-  static_assert(!test_convertible<SpStream, ReadOnlySpan<nasty_char>>());
-
-  // Const non-convertible
-  static_assert(!std::constructible_from<SpStream, const ReadOnlySpan<nasty_char>>);
-  static_assert(!test_convertible<SpStream, const ReadOnlySpan<nasty_char>>());
-}
-#endif // TEST_HAS_NO_NASTY_STRING
-
 template <typename CharT, typename TraitsT = std::char_traits<CharT>>
 void test_sfinae() {
   using SpStream =
@@ -95,7 +73,7 @@ void test() {
 
   {
     SpStream spSt(ros2);
-    assert(spSt.span().data() == arr);
+    assert(spSt.span().data() != arr);
     assert(spSt.span().data() == arr1);
     assert(spSt.span().empty());
     assert(spSt.span().size() == 0);
@@ -104,8 +82,7 @@ void test() {
 
 int main(int, char**) {
 #ifndef TEST_HAS_NO_NASTY_STRING
-  // test_sfinae<nasty_char, nasty_char_traits>();
-  test_sfinae_with_nasty_char();
+  test_sfinae<nasty_char, nasty_char_traits>();
 #endif
   test_sfinae<char>();
   test_sfinae<char, constexpr_char_traits<char>>();

>From 6368cd119803921a783011f64077fd6f87f13014 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Tue, 5 Mar 2024 09:50:42 +0200
Subject: [PATCH 20/56] Tests: Try to fix CI

---
 .../span.streams/ispanstream/ispanstream.cons/ros.pass.cpp    | 4 ++++
 libcxx/utils/generate_feature_test_macro_components.py        | 1 +
 2 files changed, 5 insertions(+)

diff --git a/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/ros.pass.cpp b/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/ros.pass.cpp
index 6425b6ed94e49..b2cae9b9f54ce 100644
--- a/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/ros.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/ros.pass.cpp
@@ -32,9 +32,13 @@
 template <typename CharT, typename TraitsT = std::char_traits<CharT>>
 void test_sfinae() {
   using SpStream =
+#ifndef TEST_HAS_NO_NASTY_STRING
       std::conditional_t<std::same_as<CharT, nasty_char>,
                          std::basic_ispanstream<nasty_char, nasty_char_traits>,
                          std::basic_ispanstream<CharT, TraitsT>>;
+#else
+      std::basic_ispanstream<CharT, TraitsT>;
+#endif
 
   // Non-const convertible
   static_assert(std::constructible_from<SpStream, ReadOnlySpan<CharT>>);
diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py
index 5fa3f0b6aef98..b53b6cd746356 100755
--- a/libcxx/utils/generate_feature_test_macro_components.py
+++ b/libcxx/utils/generate_feature_test_macro_components.py
@@ -1435,6 +1435,7 @@ def add_version_header(tc):
     "regex": ["UNSUPPORTED: no-localization"],
     "semaphore": ["UNSUPPORTED: no-threads"],
     "shared_mutex": ["UNSUPPORTED: no-threads"],
+    "spanstream": ["UNSUPPORTED: no-localization"],
     "sstream": ["UNSUPPORTED: no-localization"],
     "syncstream": ["UNSUPPORTED: no-localization"],
     "stdatomic.h": ["UNSUPPORTED: no-threads"],

>From 0e0030919b43731a9eb537b0d2082ceac7c6f39d Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Tue, 5 Mar 2024 10:29:11 +0200
Subject: [PATCH 21/56] Tests: updated generated tests

---
 .../support.limits.general/spanstream.version.compile.pass.cpp  | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/spanstream.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/spanstream.version.compile.pass.cpp
index 8719352d4367e..53c528e320a87 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/spanstream.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/spanstream.version.compile.pass.cpp
@@ -11,6 +11,8 @@
 //
 // clang-format off
 
+// UNSUPPORTED: no-localization
+
 // <spanstream>
 
 // Test the feature test macros defined by <spanstream>

>From 8d5fbc9f33e995b5529fddd6cd1f3a2f7e58a6d2 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Tue, 5 Mar 2024 17:13:47 +0200
Subject: [PATCH 22/56] Tests: WIP

---
 .../ispanstream.cons/span.mode.pass.cpp       |  2 +-
 .../ospanstream.cons/span.mode.pass.cpp       | 27 +++++++------------
 .../spanbuf/spanbuf.cons/mode.pass.cpp        | 25 +++++++----------
 .../spanbuf/spanbuf.cons/span.mode.pass.cpp   |  2 +-
 .../spanstream.cons/span.mode.pass.cpp        | 13 ++++++---
 5 files changed, 31 insertions(+), 38 deletions(-)

diff --git a/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/span.mode.pass.cpp b/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/span.mode.pass.cpp
index 3527d197e7cdf..a04cc578153b2 100644
--- a/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/span.mode.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/span.mode.pass.cpp
@@ -137,4 +137,4 @@ int main(int, char**) {
 #endif
 
   return 0;
-}
\ No newline at end of file
+}
diff --git a/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.cons/span.mode.pass.cpp b/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.cons/span.mode.pass.cpp
index e036a0be4a48b..bf619e8f18f7e 100644
--- a/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.cons/span.mode.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.cons/span.mode.pass.cpp
@@ -33,23 +33,16 @@
 #include "../../helper_macros.h"
 #include "../../helper_types.h"
 
-#ifndef TEST_HAS_NO_NASTY_STRING
-void test_sfinae_with_nasty_char() {
-  using SpStream = std::basic_ospanstream<nasty_char, nasty_char_traits>;
-
-  // Mode
-  static_assert(std::constructible_from<SpStream, const std::span<nasty_char>, std::ios_base::openmode>);
-  static_assert(!test_convertible<SpStream, std::ios_base::openmode>());
-
-  // Non-mode
-  static_assert(!std::constructible_from<SpStream, const std::span<nasty_char>, const NonMode>);
-  static_assert(!test_convertible<SpStream, const std::span<nasty_char>, const NonMode>());
-}
-#endif // TEST_HAS_NO_NASTY_STRING
-
 template <typename CharT, typename TraitsT = std::char_traits<CharT>>
 void test_sfinae() {
-  using SpStream = std::basic_ospanstream<CharT, TraitsT>;
+  using SpStream =
+#ifndef TEST_HAS_NO_NASTY_STRING
+      std::conditional_t<std::same_as<CharT, nasty_char>,
+                         std::basic_ispanstream<nasty_char, nasty_char_traits>,
+                         std::basic_ispanstream<CharT, TraitsT>>;
+#else
+      std::basic_ispanstream<CharT, TraitsT>;
+#endif
 
   // Mode
   static_assert(std::constructible_from<SpStream, const std::span<CharT>, std::ios_base::openmode>);
@@ -123,7 +116,7 @@ void test() {
 
 int main(int, char**) {
 #ifndef TEST_HAS_NO_NASTY_STRING
-  test_sfinae_with_nasty_char();
+  test_sfinae<nasty_char, nasty_char_traits>();
 #endif
   test_sfinae<char>();
   test_sfinae<char, constexpr_char_traits<char>>();
@@ -137,4 +130,4 @@ int main(int, char**) {
 #endif
 
   return 0;
-}
\ No newline at end of file
+}
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/mode.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/mode.pass.cpp
index d040f0beb92a5..f4d7667ca8327 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/mode.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/mode.pass.cpp
@@ -30,23 +30,16 @@
 
 #include "../../helper_types.h"
 
-#ifndef TEST_HAS_NO_NASTY_STRING
-void test_sfinae_with_nasty_char() {
-  using SpBuf = std::basic_spanbuf<nasty_char, nasty_char_traits>;
-
-  // Mode
-  static_assert(std::constructible_from<SpBuf, std::ios_base::openmode>);
-  static_assert(!test_convertible<SpBuf, std::ios_base::openmode>());
-
-  // Non-mode
-  static_assert(!std::constructible_from<SpBuf, const NonMode>);
-  static_assert(!test_convertible<SpBuf, const NonMode>());
-}
-#endif // TEST_HAS_NO_NASTY_STRING
-
 template <typename CharT, typename TraitsT = std::char_traits<CharT>>
 void test_sfinae() {
-  using SpBuf = std::basic_spanbuf<CharT, TraitsT>;
+  using SpStream =
+#ifndef TEST_HAS_NO_NASTY_STRING
+      std::conditional_t<std::same_as<CharT, nasty_char>,
+                         std::basic_ispanstream<nasty_char, nasty_char_traits>,
+                         std::basic_ispanstream<CharT, TraitsT>>;
+#else
+      std::basic_ispanstream<CharT, TraitsT>;
+#endif
 
   // Mode
   static_assert(std::constructible_from<SpBuf, std::ios_base::openmode>);
@@ -88,7 +81,7 @@ void test() {
 
 int main(int, char**) {
 #ifndef TEST_HAS_NO_NASTY_STRING
-  test_sfinae_with_nasty_char();
+  test_sfinae<nasty_char, nasty_char_traits>();
 #endif
   test_sfinae<char>();
   test_sfinae<char, constexpr_char_traits<char>>();
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/span.mode.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/span.mode.pass.cpp
index 45985aed49c61..b0326f82451ed 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/span.mode.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/span.mode.pass.cpp
@@ -188,4 +188,4 @@ int main(int, char**) {
 #endif
 
   return 0;
-}
\ No newline at end of file
+}
diff --git a/libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/span.mode.pass.cpp b/libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/span.mode.pass.cpp
index 2423c92fda9f8..322ac32e1126c 100644
--- a/libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/span.mode.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/span.mode.pass.cpp
@@ -49,7 +49,14 @@ void test_sfinae_with_nasty_char() {
 
 template <typename CharT, typename TraitsT = std::char_traits<CharT>>
 void test_sfinae() {
-  using SpStream = std::basic_spanstream<CharT, TraitsT>;
+  using SpStream =
+#ifndef TEST_HAS_NO_NASTY_STRING
+      std::conditional_t<std::same_as<CharT, nasty_char>,
+                         std::basic_ispanstream<nasty_char, nasty_char_traits>,
+                         std::basic_ispanstream<CharT, TraitsT>>;
+#else
+      std::basic_ispanstream<CharT, TraitsT>;
+#endif
 
   // Mode
   static_assert(std::constructible_from<SpStream, const std::span<CharT>, std::ios_base::openmode>);
@@ -123,7 +130,7 @@ void test() {
 
 int main(int, char**) {
 #ifndef TEST_HAS_NO_NASTY_STRING
-  test_sfinae_with_nasty_char();
+  test_sfinae<nasty_char>();
 #endif
   test_sfinae<char>();
   test_sfinae<char, constexpr_char_traits<char>>();
@@ -137,4 +144,4 @@ int main(int, char**) {
 #endif
 
   return 0;
-}
\ No newline at end of file
+}

>From ebf2543d92fe532afa01bf8d009896b8601ec252 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Tue, 5 Mar 2024 17:24:55 +0200
Subject: [PATCH 23/56] Tests: WIP cleanup

---
 .../ispanstream/ispanstream.cons/ros.pass.cpp |  9 +------
 .../ispanstream.cons/span.mode.pass.cpp       | 16 +-----------
 .../ospanstream.cons/span.mode.pass.cpp       |  9 +------
 .../spanbuf/spanbuf.cons/mode.pass.cpp        |  9 +------
 .../spanbuf/spanbuf.cons/span.mode.pass.cpp   | 16 +-----------
 .../spanstream.cons/span.mode.pass.cpp        | 25 ++-----------------
 6 files changed, 7 insertions(+), 77 deletions(-)

diff --git a/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/ros.pass.cpp b/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/ros.pass.cpp
index b2cae9b9f54ce..ac64e66725f15 100644
--- a/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/ros.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/ros.pass.cpp
@@ -31,14 +31,7 @@
 
 template <typename CharT, typename TraitsT = std::char_traits<CharT>>
 void test_sfinae() {
-  using SpStream =
-#ifndef TEST_HAS_NO_NASTY_STRING
-      std::conditional_t<std::same_as<CharT, nasty_char>,
-                         std::basic_ispanstream<nasty_char, nasty_char_traits>,
-                         std::basic_ispanstream<CharT, TraitsT>>;
-#else
-      std::basic_ispanstream<CharT, TraitsT>;
-#endif
+  using SpStream = std::basic_ispanstream<CharT, TraitsT>;
 
   // Non-const convertible
   static_assert(std::constructible_from<SpStream, ReadOnlySpan<CharT>>);
diff --git a/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/span.mode.pass.cpp b/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/span.mode.pass.cpp
index a04cc578153b2..55b2aaf5c3b2b 100644
--- a/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/span.mode.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/span.mode.pass.cpp
@@ -33,20 +33,6 @@
 #include "../../helper_macros.h"
 #include "../../helper_types.h"
 
-#ifndef TEST_HAS_NO_NASTY_STRING
-void test_sfinae_with_nasty_char() {
-  using SpStream = std::basic_ispanstream<nasty_char, nasty_char_traits>;
-
-  // Mode
-  static_assert(std::constructible_from<SpStream, const std::span<nasty_char>, std::ios_base::openmode>);
-  static_assert(!test_convertible<SpStream, std::ios_base::openmode>());
-
-  // Non-mode
-  static_assert(!std::constructible_from<SpStream, const std::span<nasty_char>, const NonMode>);
-  static_assert(!test_convertible<SpStream, const std::span<nasty_char>, const NonMode>());
-}
-#endif // TEST_HAS_NO_NASTY_STRING
-
 template <typename CharT, typename TraitsT = std::char_traits<CharT>>
 void test_sfinae() {
   using SpStream = std::basic_ispanstream<CharT, TraitsT>;
@@ -123,7 +109,7 @@ void test() {
 
 int main(int, char**) {
 #ifndef TEST_HAS_NO_NASTY_STRING
-  test_sfinae_with_nasty_char();
+  test_sfinae<nasty_char, nasty_char_traits>();
 #endif
   test_sfinae<char>();
   test_sfinae<char, constexpr_char_traits<char>>();
diff --git a/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.cons/span.mode.pass.cpp b/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.cons/span.mode.pass.cpp
index bf619e8f18f7e..fe274e9208c62 100644
--- a/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.cons/span.mode.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.cons/span.mode.pass.cpp
@@ -35,14 +35,7 @@
 
 template <typename CharT, typename TraitsT = std::char_traits<CharT>>
 void test_sfinae() {
-  using SpStream =
-#ifndef TEST_HAS_NO_NASTY_STRING
-      std::conditional_t<std::same_as<CharT, nasty_char>,
-                         std::basic_ispanstream<nasty_char, nasty_char_traits>,
-                         std::basic_ispanstream<CharT, TraitsT>>;
-#else
-      std::basic_ispanstream<CharT, TraitsT>;
-#endif
+  using SpStream = std::basic_ispanstream<CharT, TraitsT>;
 
   // Mode
   static_assert(std::constructible_from<SpStream, const std::span<CharT>, std::ios_base::openmode>);
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/mode.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/mode.pass.cpp
index f4d7667ca8327..d2bd64f35cb59 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/mode.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/mode.pass.cpp
@@ -32,14 +32,7 @@
 
 template <typename CharT, typename TraitsT = std::char_traits<CharT>>
 void test_sfinae() {
-  using SpStream =
-#ifndef TEST_HAS_NO_NASTY_STRING
-      std::conditional_t<std::same_as<CharT, nasty_char>,
-                         std::basic_ispanstream<nasty_char, nasty_char_traits>,
-                         std::basic_ispanstream<CharT, TraitsT>>;
-#else
-      std::basic_ispanstream<CharT, TraitsT>;
-#endif
+  using SpBuf = std::basic_spanbuf<CharT, TraitsT>;
 
   // Mode
   static_assert(std::constructible_from<SpBuf, std::ios_base::openmode>);
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/span.mode.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/span.mode.pass.cpp
index b0326f82451ed..fbfc2f144ab6d 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/span.mode.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/span.mode.pass.cpp
@@ -33,20 +33,6 @@
 #include "../../helper_macros.h"
 #include "../../helper_types.h"
 
-#ifndef TEST_HAS_NO_NASTY_STRING
-void test_sfinae_with_nasty_char() {
-  using SpBuf = std::basic_spanbuf<nasty_char, nasty_char_traits>;
-
-  // Mode
-  static_assert(std::constructible_from<SpBuf, const std::span<nasty_char>, std::ios_base::openmode>);
-  static_assert(!test_convertible<SpBuf, std::ios_base::openmode>());
-
-  // Non-mode
-  static_assert(!std::constructible_from<SpBuf, const std::span<nasty_char>, const NonMode>);
-  static_assert(!test_convertible<SpBuf, const NonMode>());
-}
-#endif // TEST_HAS_NO_NASTY_STRING
-
 template <typename CharT, typename TraitsT = std::char_traits<CharT>>
 void test_sfinae() {
   using SpBuf = std::basic_spanbuf<CharT, TraitsT>;
@@ -174,7 +160,7 @@ void test() {
 
 int main(int, char**) {
 #ifndef TEST_HAS_NO_NASTY_STRING
-  test_sfinae_with_nasty_char();
+  test_sfinae<nasty_char, nasty_char_traits>();
 #endif
   test_sfinae<char>();
   test_sfinae<char, constexpr_char_traits<char>>();
diff --git a/libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/span.mode.pass.cpp b/libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/span.mode.pass.cpp
index 322ac32e1126c..122d210430d9f 100644
--- a/libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/span.mode.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/span.mode.pass.cpp
@@ -33,30 +33,9 @@
 #include "../../helper_macros.h"
 #include "../../helper_types.h"
 
-#ifndef TEST_HAS_NO_NASTY_STRING
-void test_sfinae_with_nasty_char() {
-  using SpStream = std::basic_spanstream<nasty_char, nasty_char_traits>;
-
-  // Mode
-  static_assert(std::constructible_from<SpStream, const std::span<nasty_char>, std::ios_base::openmode>);
-  static_assert(!test_convertible<SpStream, std::ios_base::openmode>());
-
-  // Non-mode
-  static_assert(!std::constructible_from<SpStream, const std::span<nasty_char>, const NonMode>);
-  static_assert(!test_convertible<SpStream, const std::span<nasty_char>, const NonMode>());
-}
-#endif // TEST_HAS_NO_NASTY_STRING
-
 template <typename CharT, typename TraitsT = std::char_traits<CharT>>
 void test_sfinae() {
-  using SpStream =
-#ifndef TEST_HAS_NO_NASTY_STRING
-      std::conditional_t<std::same_as<CharT, nasty_char>,
-                         std::basic_ispanstream<nasty_char, nasty_char_traits>,
-                         std::basic_ispanstream<CharT, TraitsT>>;
-#else
-      std::basic_ispanstream<CharT, TraitsT>;
-#endif
+  using SpStream = std::basic_ispanstream<CharT, TraitsT>;
 
   // Mode
   static_assert(std::constructible_from<SpStream, const std::span<CharT>, std::ios_base::openmode>);
@@ -130,7 +109,7 @@ void test() {
 
 int main(int, char**) {
 #ifndef TEST_HAS_NO_NASTY_STRING
-  test_sfinae<nasty_char>();
+  test_sfinae<nasty_char, nasty_char_traits>();
 #endif
   test_sfinae<char>();
   test_sfinae<char, constexpr_char_traits<char>>();

>From dd28de6ac92dd66aa755ccc63d7f8cfbe0fd49e8 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Tue, 5 Mar 2024 17:55:59 +0200
Subject: [PATCH 24/56] Tests: added test skelettons

---
 .../ispanstream.assign/move.pass.cpp          |  2 +
 .../ispanstream.assign/swap.pass.cpp          |  2 +
 .../swap_nonmember.pass.cpp                   |  2 +
 .../spanbuf/spanbuf.assign/move.pass.cpp      | 82 ++++++++++++++++++
 .../spanbuf/spanbuf.assign/swap.pass.cpp      | 85 +++++++++++++++++++
 .../spanbuf.assign/swap_nonmember.pass.cpp    | 81 ++++++++++++++++++
 .../spanbuf/spanbuf.members/span.pass.cpp     | 58 +++++++++++++
 .../spanbuf.members/span.span.pass.cpp        | 59 +++++++++++++
 ...ekoff.off_type.seek_dir.open_mode.pass.cpp | 62 ++++++++++++++
 .../seekoff.pos_type.open_mode.pass.cpp       | 58 +++++++++++++
 .../spanbuf/spanbuf.virtuals/setbuf.pass.cpp  | 58 +++++++++++++
 11 files changed, 549 insertions(+)
 create mode 100644 libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/move.pass.cpp
 create mode 100644 libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/swap.pass.cpp
 create mode 100644 libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/swap_nonmember.pass.cpp
 create mode 100644 libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.members/span.pass.cpp
 create mode 100644 libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.members/span.span.pass.cpp
 create mode 100644 libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekoff.off_type.seek_dir.open_mode.pass.cpp
 create mode 100644 libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekoff.pos_type.open_mode.pass.cpp
 create mode 100644 libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/setbuf.pass.cpp

diff --git a/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.assign/move.pass.cpp b/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.assign/move.pass.cpp
index 117e2a6828e9d..75ae944d01c82 100644
--- a/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.assign/move.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.assign/move.pass.cpp
@@ -34,6 +34,8 @@ void test() {
   CharT arr[4];
   std::span<CharT> sp{arr};
 
+  // TODO:
+
   // Mode: default
   {
     SpStream rhsSpSt{sp};
diff --git a/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.assign/swap.pass.cpp b/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.assign/swap.pass.cpp
index 45fc6370a06d4..1aef6a3f47629 100644
--- a/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.assign/swap.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.assign/swap.pass.cpp
@@ -33,6 +33,8 @@ void test() {
   CharT arr[4];
   std::span<CharT> sp{arr};
 
+  // TODO:
+
   // Mode: default
   {
     SpStream rhsSpSt{sp};
diff --git a/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.assign/swap_nonmember.pass.cpp b/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.assign/swap_nonmember.pass.cpp
index ae54e40929745..165dc72673e9f 100644
--- a/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.assign/swap_nonmember.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.assign/swap_nonmember.pass.cpp
@@ -29,6 +29,8 @@ void test() {
   CharT arr[4];
   std::span<CharT> sp{arr};
 
+  // TODO:
+
   // Mode: default
   {
     SpStream rhsSpSt{sp};
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/move.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/move.pass.cpp
new file mode 100644
index 0000000000000..798a4de1ae4d4
--- /dev/null
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/move.pass.cpp
@@ -0,0 +1,82 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <spanstream>
+
+//   template<class charT, class traits = char_traits<charT>>
+//   class basic_spanbuf
+//     : public basic_streambuf<charT, traits> {
+
+//     // [spanbuf.cons], constructors
+//
+//     basic_spanbuf& operator=(basic_spanbuf&& rhs);
+
+#include <cassert>
+#include <concepts>
+#include <span>
+#include <spanstream>
+
+#include "constexpr_char_traits.h"
+#include "test_convertible.h"
+#include "test_macros.h"
+
+template <typename CharT, typename TraitsT = std::char_traits<CharT>>
+void test() {
+  using SpBuf = std::basic_spanbuf<CharT, TraitsT>;
+
+  CharT arr[4];
+  std::span<CharT> sp{arr};
+
+  // TODO:
+  
+  // Mode: default
+  {
+    SpBuf rhsSpBuf{sp};
+    SpBuf spBuf = std::move(rhsSpBuf);
+    assert(spBuf.span().data() == arr);
+    assert(!spBuf.span().empty());
+    assert(spBuf.span().size() == 4);
+  }
+  // Mode: `ios_base::in`
+  {
+    SpBuf rhsSpBuf{sp, std::ios_base::in};
+    SpBuf spBuf = std::move(rhsSpBuf);
+    assert(spBuf.span().data() == arr);
+    assert(!spBuf.span().empty());
+    assert(spBuf.span().size() == 4);
+  }
+  // Mode `ios_base::out`
+  {
+    SpBuf rhsSpBuf{sp, std::ios_base::out};
+    SpBuf spBuf = std::move(rhsSpBuf);
+    assert(spBuf.span().data() == arr);
+    assert(spBuf.span().empty());
+    assert(spBuf.span().size() == 0);
+  }
+  // Mode: multiple
+  {
+    SpBuf rhsSpBuf{sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary};
+    SpBuf spBuf = std::move(rhsSpBuf);
+    assert(spBuf.span().data() == arr);
+    assert(spBuf.span().empty());
+    assert(spBuf.span().size() == 0);
+  }
+}
+
+int main(int, char**) {
+  test<char>();
+  test<char, constexpr_char_traits<char>>();
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  test<wchar_t>();
+  test<wchar_t, constexpr_char_traits<wchar_t>>();
+#endif
+
+  return 0;
+}
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/swap.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/swap.pass.cpp
new file mode 100644
index 0000000000000..26aed41479890
--- /dev/null
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/swap.pass.cpp
@@ -0,0 +1,85 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <spanstream>
+
+//   template<class charT, class traits = char_traits<charT>>
+//   class basic_spanbuf
+//     : public basic_spanbuf<charT, traits> {
+
+//     // [ispanstream.swap], swap
+//     void swap(basic_spanbuf& rhs);
+
+#include <cassert>
+#include <concepts>
+#include <span>
+#include <spanstream>
+
+#include "constexpr_char_traits.h"
+#include "test_convertible.h"
+#include "test_macros.h"
+
+template <typename CharT, typename TraitsT = std::char_traits<CharT>>
+void test() {
+  using SpBuf = std::basic_spanbuf<CharT, TraitsT>;
+
+  CharT arr[4];
+  std::span<CharT> sp{arr};
+
+  // TODO:
+
+  // Mode: default
+  {
+    SpBuf rhsSpBuf{sp};
+    SpBuf spBuf(std::span<CharT>{});
+    spBuf.swap(rhsSpBuf);
+    assert(spBuf.span().data() == arr);
+    assert(!spBuf.span().empty());
+    assert(spBuf.span().size() == 4);
+  }
+  // Mode: `ios_base::in`
+  {
+    SpBuf rhsSpBuf{sp, std::ios_base::in};
+    SpBuf spBuf(std::span<CharT>{});
+    spBuf.swap(rhsSpBuf);
+    assert(spBuf.span().data() == arr);
+    assert(!spBuf.span().empty());
+    assert(spBuf.span().size() == 4);
+  }
+  // Mode `ios_base::out`
+  {
+    SpBuf rhsSpBuf{sp, std::ios_base::out};
+    SpBuf spBuf(std::span<CharT>{});
+    spBuf.swap(rhsSpBuf);
+    assert(spBuf.span().data() == arr);
+    assert(spBuf.span().empty());
+    assert(spBuf.span().size() == 0);
+  }
+  // Mode: multiple
+  {
+    SpBuf rhsSpBuf{sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary};
+    SpBuf spBuf(std::span<CharT>{});
+    spBuf.swap(rhsSpBuf);
+    assert(spBuf.span().data() == arr);
+    assert(spBuf.span().empty());
+    assert(spBuf.span().size() == 0);
+  }
+}
+
+int main(int, char**) {
+  test<char>();
+  test<char, constexpr_char_traits<char>>();
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  test<wchar_t>();
+  test<wchar_t, constexpr_char_traits<wchar_t>>();
+#endif
+
+  return 0;
+}
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/swap_nonmember.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/swap_nonmember.pass.cpp
new file mode 100644
index 0000000000000..f92b77bfc1511
--- /dev/null
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/swap_nonmember.pass.cpp
@@ -0,0 +1,81 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <spanstream>
+
+//   template<class charT, class traits>
+//     void swap(basic_spanbuf<charT, traits>& x, basic_spanbuf<charT, traits>& y);
+
+#include <cassert>
+#include <concepts>
+#include <span>
+#include <spanstream>
+
+#include "constexpr_char_traits.h"
+#include "test_convertible.h"
+#include "test_macros.h"
+
+template <typename CharT, typename TraitsT = std::char_traits<CharT>>
+void test() {
+  using SpBuf= std::basic_spanbuf<CharT, TraitsT>;
+
+  CharT arr[4];
+  std::span<CharT> sp{arr};
+
+  // TODO:
+
+  // Mode: default
+  {
+    SpBuf rhsSpBuf{sp};
+    SpBuf spBuf(std::span<CharT>{});
+    std::swap(spBuf, rhsSpBuf);
+    assert(spBuf.span().data() == arr);
+    assert(!spBuf.span().empty());
+    assert(spBuf.span().size() == 4);
+  }
+  // Mode: `ios_base::in`
+  {
+    SpBuf rhsSpBuf{sp, std::ios_base::in};
+    SpBuf spBuf(std::span<CharT>{});
+    std::swap(spBuf, rhsSpBuf);
+    assert(spBuf.span().data() == arr);
+    assert(!spBuf.span().empty());
+    assert(spBuf.span().size() == 4);
+  }
+  // Mode `ios_base::out`
+  {
+    SpBuf rhsSpBuf{sp, std::ios_base::out};
+    SpBuf spBuf(std::span<CharT>{});
+    std::swap(spBuf, rhsSpBuf);
+    assert(spBuf.span().data() == arr);
+    assert(spBuf.span().empty());
+    assert(spBuf.span().size() == 0);
+  }
+  // Mode: multiple
+  {
+    SpBuf rhsSpBuf{sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary};
+    SpBuf spBuf(std::span<CharT>{});
+    std::swap(spBuf, rhsSpBuf);
+    assert(spBuf.span().data() == arr);
+    assert(spBuf.span().empty());
+    assert(spBuf.span().size() == 0);
+  }
+}
+
+int main(int, char**) {
+  test<char>();
+  test<char, constexpr_char_traits<char>>();
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  test<wchar_t>();
+  test<wchar_t, constexpr_char_traits<wchar_t>>();
+#endif
+
+  return 0;
+}
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.members/span.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.members/span.pass.cpp
new file mode 100644
index 0000000000000..25cee72694163
--- /dev/null
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.members/span.pass.cpp
@@ -0,0 +1,58 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <spanstream>
+
+//   template<class charT, class traits = char_traits<charT>>
+//   class basic_spanbuf
+//     : public basic_spanbuf<charT, traits> {
+
+//     // [spanbuf.members], member functions
+//     std::span<charT> span() const noexcept;
+
+#include <cassert>
+#include <concepts>
+#include <span>
+#include <spanstream>
+
+#include "constexpr_char_traits.h"
+#include "test_convertible.h"
+#include "test_macros.h"
+
+template <typename CharT, typename TraitsT = std::char_traits<CharT>>
+void test() {
+  using SpBuf = std::basic_spanbuf<CharT, TraitsT>;
+
+  CharT arr[4];
+  std::span<CharT> sp{arr};
+
+  // TODO:
+
+  // Mode: default
+  {
+    SpBuf rhsSpBuf{sp};
+    SpBuf spBuf(std::span<CharT>{});
+    spBuf.swap(rhsSpBuf);
+    assert(spBuf.span().data() == arr);
+    assert(!spBuf.span().empty());
+    assert(spBuf.span().size() == 4);
+  }
+}
+
+int main(int, char**) {
+  test<char>();
+  test<char, constexpr_char_traits<char>>();
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  test<wchar_t>();
+  test<wchar_t, constexpr_char_traits<wchar_t>>();
+#endif
+
+  return 0;
+}
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.members/span.span.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.members/span.span.pass.cpp
new file mode 100644
index 0000000000000..9b696391b746f
--- /dev/null
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.members/span.span.pass.cpp
@@ -0,0 +1,59 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <spanstream>
+
+//   template<class charT, class traits = char_traits<charT>>
+//   class basic_spanbuf
+//     : public basic_spanbuf<charT, traits> {
+
+//     // [spanbuf.members], member functions
+//
+//     void span(std::span<charT> s) noexcept;
+
+#include <cassert>
+#include <concepts>
+#include <span>
+#include <spanstream>
+
+#include "constexpr_char_traits.h"
+#include "test_convertible.h"
+#include "test_macros.h"
+
+template <typename CharT, typename TraitsT = std::char_traits<CharT>>
+void test() {
+  using SpBuf = std::basic_spanbuf<CharT, TraitsT>;
+
+  CharT arr[4];
+  std::span<CharT> sp{arr};
+
+  // TODO:
+
+  // Mode: default
+  {
+    SpBuf rhsSpBuf{sp};
+    SpBuf spBuf(std::span<CharT>{});
+    spBuf.swap(rhsSpBuf);
+    assert(spBuf.span().data() == arr);
+    assert(!spBuf.span().empty());
+    assert(spBuf.span().size() == 4);
+  }
+}
+
+int main(int, char**) {
+  test<char>();
+  test<char, constexpr_char_traits<char>>();
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  test<wchar_t>();
+  test<wchar_t, constexpr_char_traits<wchar_t>>();
+#endif
+
+  return 0;
+}
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekoff.off_type.seek_dir.open_mode.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekoff.off_type.seek_dir.open_mode.pass.cpp
new file mode 100644
index 0000000000000..039fa1f61c09a
--- /dev/null
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekoff.off_type.seek_dir.open_mode.pass.cpp
@@ -0,0 +1,62 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <spanstream>
+
+//   template<class charT, class traits = char_traits<charT>>
+//   class basic_spanbuf
+//     : public basic_spanbuf<charT, traits> {
+
+//     // [spanbuf.virtuals], overridden virtual functions
+//
+//     pos_type seekoff(off_type off, ios_base::seekdir way,
+//                      ios_base::openmode which = ios_base::in | ios_base::out) override;
+//     pos_type seekpos(pos_type sp,
+//                      ios_base::openmode which = ios_base::in | ios_base::out) override;
+
+#include <cassert>
+#include <concepts>
+#include <span>
+#include <spanstream>
+
+#include "constexpr_char_traits.h"
+#include "test_convertible.h"
+#include "test_macros.h"
+
+template <typename CharT, typename TraitsT = std::char_traits<CharT>>
+void test() {
+  using SpBuf = std::basic_spanbuf<CharT, TraitsT>;
+
+  CharT arr[4];
+  std::span<CharT> sp{arr};
+
+  // TODO:
+
+  // Mode: default
+  {
+    SpBuf rhsSpBuf{sp};
+    SpBuf spBuf(std::span<CharT>{});
+    spBuf.swap(rhsSpBuf);
+    assert(spBuf.span().data() == arr);
+    assert(!spBuf.span().empty());
+    assert(spBuf.span().size() == 4);
+  }
+}
+
+int main(int, char**) {
+  test<char>();
+  test<char, constexpr_char_traits<char>>();
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  test<wchar_t>();
+  test<wchar_t, constexpr_char_traits<wchar_t>>();
+#endif
+
+  return 0;
+}
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekoff.pos_type.open_mode.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekoff.pos_type.open_mode.pass.cpp
new file mode 100644
index 0000000000000..006d282cacc78
--- /dev/null
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekoff.pos_type.open_mode.pass.cpp
@@ -0,0 +1,58 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <spanstream>
+
+//   template<class charT, class traits = char_traits<charT>>
+//   class basic_spanbuf
+//     : public basic_spanbuf<charT, traits> {
+
+//     // [spanbuf.virtuals], overridden virtual functions
+//
+//     pos_type seekpos(pos_type sp,
+//                      ios_base::openmode which = ios_base::in | ios_base::out) override;
+
+#include <cassert>
+#include <concepts>
+#include <span>
+#include <spanstream>
+
+#include "constexpr_char_traits.h"
+#include "test_convertible.h"
+#include "test_macros.h"
+
+template <typename CharT, typename TraitsT = std::char_traits<CharT>>
+void test() {
+  using SpBuf = std::basic_spanbuf<CharT, TraitsT>;
+
+  CharT arr[4];
+  std::span<CharT> sp{arr};
+
+  // Mode: default
+  {
+    SpBuf rhsSpBuf{sp};
+    SpBuf spBuf(std::span<CharT>{});
+    spBuf.swap(rhsSpBuf);
+    assert(spBuf.span().data() == arr);
+    assert(!spBuf.span().empty());
+    assert(spBuf.span().size() == 4);
+  }
+}
+
+int main(int, char**) {
+  test<char>();
+  test<char, constexpr_char_traits<char>>();
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  test<wchar_t>();
+  test<wchar_t, constexpr_char_traits<wchar_t>>();
+#endif
+
+  return 0;
+}
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/setbuf.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/setbuf.pass.cpp
new file mode 100644
index 0000000000000..fe9f5c3bf9cd8
--- /dev/null
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/setbuf.pass.cpp
@@ -0,0 +1,58 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <spanstream>
+
+//   template<class charT, class traits = char_traits<charT>>
+//   class basic_spanbuf
+//     : public basic_spanbuf<charT, traits> {
+
+//     // [spanbuf.virtuals], overridden virtual functions
+//     basic_streambuf<charT, traits>* setbuf(charT*, streamsize) override;
+
+#include <cassert>
+#include <concepts>
+#include <span>
+#include <spanstream>
+
+#include "constexpr_char_traits.h"
+#include "test_convertible.h"
+#include "test_macros.h"
+
+template <typename CharT, typename TraitsT = std::char_traits<CharT>>
+void test() {
+  using SpBuf = std::basic_spanbuf<CharT, TraitsT>;
+
+  CharT arr[4];
+  std::span<CharT> sp{arr};
+
+  // TODO:
+
+  // Mode: default
+  {
+    SpBuf rhsSpBuf{sp};
+    SpBuf spBuf(std::span<CharT>{});
+    spBuf.swap(rhsSpBuf);
+    assert(spBuf.span().data() == arr);
+    assert(!spBuf.span().empty());
+    assert(spBuf.span().size() == 4);
+  }
+}
+
+int main(int, char**) {
+  test<char>();
+  test<char, constexpr_char_traits<char>>();
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  test<wchar_t>();
+  test<wchar_t, constexpr_char_traits<wchar_t>>();
+#endif
+
+  return 0;
+}

>From c3aa9dfbb38f9ecac8f798e18b522df526072612 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Tue, 5 Mar 2024 18:27:22 +0200
Subject: [PATCH 25/56] Tests: updated `iosfwd.pass.cpp`

---
 .../iostream.forward/iosfwd.pass.cpp          | 37 +++++++++++++++++++
 1 file changed, 37 insertions(+)

diff --git a/libcxx/test/std/input.output/iostream.forward/iosfwd.pass.cpp b/libcxx/test/std/input.output/iostream.forward/iosfwd.pass.cpp
index 1a28a5985a011..bd9a6ae00de35 100644
--- a/libcxx/test/std/input.output/iostream.forward/iosfwd.pass.cpp
+++ b/libcxx/test/std/input.output/iostream.forward/iosfwd.pass.cpp
@@ -83,6 +83,29 @@ int main(int, char**)
 #endif
     test<std::basic_stringstream<unsigned short>*>();
 
+#if TEST_STD_VER >= 23
+    test<std::basic_spanbuf<unsigned short>*>();
+    test<std::basic_spanbuf<char>*>();
+#  ifndef TEST_HAS_NO_WIDE_CHARACTERS
+    test<std::basic_spanbuf<wchar_t>*>();
+#  endif
+    test<std::basic_ispanstream<unsigned short>*>();
+    test<std::basic_ispanstream<char>*>();
+#  ifndef TEST_HAS_NO_WIDE_CHARACTERS
+    test<std::basic_ispanstream<wchar_t>*>();
+#  endif
+    test<std::basic_ospanstream<unsigned short>*>();
+    test<std::basic_ospanstream<char>*>();
+#  ifndef TEST_HAS_NO_WIDE_CHARACTERS
+    test<std::basic_ospanstream<wchar_t>*>();
+#  endif
+    test<std::basic_spanstream<char>*>();
+    test<std::basic_spanstream<unsigned short>*>();
+#  ifndef TEST_HAS_NO_WIDE_CHARACTERS
+    test<std::basic_spanstream<wchar_t>*>();
+#  endif
+#endif // TEST_STD_VER >= 23
+
     test<std::basic_filebuf<char>*          >();
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
     test<std::basic_filebuf<wchar_t>*       >();
@@ -134,6 +157,13 @@ int main(int, char**)
     test<std::ostringstream*>();
     test<std::stringstream* >();
 
+#if TEST_STD_VER >= 23
+    test<std::spanbuf*>();
+    test<std::ispanstream*>();
+    test<std::ospanstream*>();
+    test<std::spanstream*>();
+#endif // TEST_STD_VER >= 23
+
     test<std::filebuf* >();
     test<std::ifstream*>();
     test<std::ofstream*>();
@@ -150,6 +180,13 @@ int main(int, char**)
     test<std::wostringstream*>();
     test<std::wstringstream* >();
 
+#  if TEST_STD_VER >= 23
+    test<std::wspanbuf*>();
+    test<std::wispanstream*>();
+    test<std::wospanstream*>();
+    test<std::wspanstream*>();
+#  endif // TEST_STD_VER >= 23
+
     test<std::wfilebuf* >();
     test<std::wifstream*>();
     test<std::wofstream*>();

>From 851c9a27eb6804ea1981c139fd6883d82bf0efcb Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Tue, 5 Mar 2024 18:33:06 +0200
Subject: [PATCH 26/56] Tests: WIP fix test skelettons

---
 .../spanbuf/spanbuf.assign/move.pass.cpp      | 66 ++++++++--------
 .../spanbuf/spanbuf.assign/swap.pass.cpp      | 74 +++++++++---------
 .../spanbuf.assign/swap_nonmember.pass.cpp    | 76 +++++++++----------
 .../spanbuf/spanbuf.members/span.pass.cpp     | 20 ++---
 .../spanbuf.members/span.span.pass.cpp        | 18 ++---
 ...ekoff.off_type.seek_dir.open_mode.pass.cpp | 20 ++---
 .../seekoff.pos_type.open_mode.pass.cpp       | 20 ++---
 .../spanbuf/spanbuf.virtuals/setbuf.pass.cpp  | 18 ++---
 8 files changed, 156 insertions(+), 156 deletions(-)

diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/move.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/move.pass.cpp
index 798a4de1ae4d4..7702c2c51dbc8 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/move.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/move.pass.cpp
@@ -35,39 +35,39 @@ void test() {
   std::span<CharT> sp{arr};
 
   // TODO:
-  
-  // Mode: default
-  {
-    SpBuf rhsSpBuf{sp};
-    SpBuf spBuf = std::move(rhsSpBuf);
-    assert(spBuf.span().data() == arr);
-    assert(!spBuf.span().empty());
-    assert(spBuf.span().size() == 4);
-  }
-  // Mode: `ios_base::in`
-  {
-    SpBuf rhsSpBuf{sp, std::ios_base::in};
-    SpBuf spBuf = std::move(rhsSpBuf);
-    assert(spBuf.span().data() == arr);
-    assert(!spBuf.span().empty());
-    assert(spBuf.span().size() == 4);
-  }
-  // Mode `ios_base::out`
-  {
-    SpBuf rhsSpBuf{sp, std::ios_base::out};
-    SpBuf spBuf = std::move(rhsSpBuf);
-    assert(spBuf.span().data() == arr);
-    assert(spBuf.span().empty());
-    assert(spBuf.span().size() == 0);
-  }
-  // Mode: multiple
-  {
-    SpBuf rhsSpBuf{sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary};
-    SpBuf spBuf = std::move(rhsSpBuf);
-    assert(spBuf.span().data() == arr);
-    assert(spBuf.span().empty());
-    assert(spBuf.span().size() == 0);
-  }
+  (void)sp;
+  // // Mode: default
+  // {
+  //   SpBuf rhsSpBuf{sp};
+  //   SpBuf spBuf = std::move(rhsSpBuf);
+  //   assert(spBuf.span().data() == arr);
+  //   assert(!spBuf.span().empty());
+  //   assert(spBuf.span().size() == 4);
+  // }
+  // // Mode: `ios_base::in`
+  // {
+  //   SpBuf rhsSpBuf{sp, std::ios_base::in};
+  //   SpBuf spBuf = std::move(rhsSpBuf);
+  //   assert(spBuf.span().data() == arr);
+  //   assert(!spBuf.span().empty());
+  //   assert(spBuf.span().size() == 4);
+  // }
+  // // Mode `ios_base::out`
+  // {
+  //   SpBuf rhsSpBuf{sp, std::ios_base::out};
+  //   SpBuf spBuf = std::move(rhsSpBuf);
+  //   assert(spBuf.span().data() == arr);
+  //   assert(spBuf.span().empty());
+  //   assert(spBuf.span().size() == 0);
+  // }
+  // // Mode: multiple
+  // {
+  //   SpBuf rhsSpBuf{sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary};
+  //   SpBuf spBuf = std::move(rhsSpBuf);
+  //   assert(spBuf.span().data() == arr);
+  //   assert(spBuf.span().empty());
+  //   assert(spBuf.span().size() == 0);
+  // }
 }
 
 int main(int, char**) {
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/swap.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/swap.pass.cpp
index 26aed41479890..e5a2fff2ba8ba 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/swap.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/swap.pass.cpp
@@ -34,43 +34,43 @@ void test() {
   std::span<CharT> sp{arr};
 
   // TODO:
-
-  // Mode: default
-  {
-    SpBuf rhsSpBuf{sp};
-    SpBuf spBuf(std::span<CharT>{});
-    spBuf.swap(rhsSpBuf);
-    assert(spBuf.span().data() == arr);
-    assert(!spBuf.span().empty());
-    assert(spBuf.span().size() == 4);
-  }
-  // Mode: `ios_base::in`
-  {
-    SpBuf rhsSpBuf{sp, std::ios_base::in};
-    SpBuf spBuf(std::span<CharT>{});
-    spBuf.swap(rhsSpBuf);
-    assert(spBuf.span().data() == arr);
-    assert(!spBuf.span().empty());
-    assert(spBuf.span().size() == 4);
-  }
-  // Mode `ios_base::out`
-  {
-    SpBuf rhsSpBuf{sp, std::ios_base::out};
-    SpBuf spBuf(std::span<CharT>{});
-    spBuf.swap(rhsSpBuf);
-    assert(spBuf.span().data() == arr);
-    assert(spBuf.span().empty());
-    assert(spBuf.span().size() == 0);
-  }
-  // Mode: multiple
-  {
-    SpBuf rhsSpBuf{sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary};
-    SpBuf spBuf(std::span<CharT>{});
-    spBuf.swap(rhsSpBuf);
-    assert(spBuf.span().data() == arr);
-    assert(spBuf.span().empty());
-    assert(spBuf.span().size() == 0);
-  }
+  (void)sp;
+  // // Mode: default
+  // {
+  //   SpBuf rhsSpBuf{sp};
+  //   SpBuf spBuf(std::span<CharT>{});
+  //   spBuf.swap(rhsSpBuf);
+  //   assert(spBuf.span().data() == arr);
+  //   assert(!spBuf.span().empty());
+  //   assert(spBuf.span().size() == 4);
+  // }
+  // // Mode: `ios_base::in`
+  // {
+  //   SpBuf rhsSpBuf{sp, std::ios_base::in};
+  //   SpBuf spBuf(std::span<CharT>{});
+  //   spBuf.swap(rhsSpBuf);
+  //   assert(spBuf.span().data() == arr);
+  //   assert(!spBuf.span().empty());
+  //   assert(spBuf.span().size() == 4);
+  // }
+  // // Mode `ios_base::out`
+  // {
+  //   SpBuf rhsSpBuf{sp, std::ios_base::out};
+  //   SpBuf spBuf(std::span<CharT>{});
+  //   spBuf.swap(rhsSpBuf);
+  //   assert(spBuf.span().data() == arr);
+  //   assert(spBuf.span().empty());
+  //   assert(spBuf.span().size() == 0);
+  // }
+  // // Mode: multiple
+  // {
+  //   SpBuf rhsSpBuf{sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary};
+  //   SpBuf spBuf(std::span<CharT>{});
+  //   spBuf.swap(rhsSpBuf);
+  //   assert(spBuf.span().data() == arr);
+  //   assert(spBuf.span().empty());
+  //   assert(spBuf.span().size() == 0);
+  // }
 }
 
 int main(int, char**) {
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/swap_nonmember.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/swap_nonmember.pass.cpp
index f92b77bfc1511..e3342253bc741 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/swap_nonmember.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/swap_nonmember.pass.cpp
@@ -24,49 +24,49 @@
 
 template <typename CharT, typename TraitsT = std::char_traits<CharT>>
 void test() {
-  using SpBuf= std::basic_spanbuf<CharT, TraitsT>;
+  using SpBuf = std::basic_spanbuf<CharT, TraitsT>;
 
   CharT arr[4];
   std::span<CharT> sp{arr};
 
   // TODO:
-
-  // Mode: default
-  {
-    SpBuf rhsSpBuf{sp};
-    SpBuf spBuf(std::span<CharT>{});
-    std::swap(spBuf, rhsSpBuf);
-    assert(spBuf.span().data() == arr);
-    assert(!spBuf.span().empty());
-    assert(spBuf.span().size() == 4);
-  }
-  // Mode: `ios_base::in`
-  {
-    SpBuf rhsSpBuf{sp, std::ios_base::in};
-    SpBuf spBuf(std::span<CharT>{});
-    std::swap(spBuf, rhsSpBuf);
-    assert(spBuf.span().data() == arr);
-    assert(!spBuf.span().empty());
-    assert(spBuf.span().size() == 4);
-  }
-  // Mode `ios_base::out`
-  {
-    SpBuf rhsSpBuf{sp, std::ios_base::out};
-    SpBuf spBuf(std::span<CharT>{});
-    std::swap(spBuf, rhsSpBuf);
-    assert(spBuf.span().data() == arr);
-    assert(spBuf.span().empty());
-    assert(spBuf.span().size() == 0);
-  }
-  // Mode: multiple
-  {
-    SpBuf rhsSpBuf{sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary};
-    SpBuf spBuf(std::span<CharT>{});
-    std::swap(spBuf, rhsSpBuf);
-    assert(spBuf.span().data() == arr);
-    assert(spBuf.span().empty());
-    assert(spBuf.span().size() == 0);
-  }
+  (void)sp;
+  // // Mode: default
+  // {
+  //   SpBuf rhsSpBuf{sp};
+  //   SpBuf spBuf(std::span<CharT>{});
+  //   std::swap(spBuf, rhsSpBuf);
+  //   assert(spBuf.span().data() == arr);
+  //   assert(!spBuf.span().empty());
+  //   assert(spBuf.span().size() == 4);
+  // }
+  // // Mode: `ios_base::in`
+  // {
+  //   SpBuf rhsSpBuf{sp, std::ios_base::in};
+  //   SpBuf spBuf(std::span<CharT>{});
+  //   std::swap(spBuf, rhsSpBuf);
+  //   assert(spBuf.span().data() == arr);
+  //   assert(!spBuf.span().empty());
+  //   assert(spBuf.span().size() == 4);
+  // }
+  // // Mode `ios_base::out`
+  // {
+  //   SpBuf rhsSpBuf{sp, std::ios_base::out};
+  //   SpBuf spBuf(std::span<CharT>{});
+  //   std::swap(spBuf, rhsSpBuf);
+  //   assert(spBuf.span().data() == arr);
+  //   assert(spBuf.span().empty());
+  //   assert(spBuf.span().size() == 0);
+  // }
+  // // Mode: multiple
+  // {
+  //   SpBuf rhsSpBuf{sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary};
+  //   SpBuf spBuf(std::span<CharT>{});
+  //   std::swap(spBuf, rhsSpBuf);
+  //   assert(spBuf.span().data() == arr);
+  //   assert(spBuf.span().empty());
+  //   assert(spBuf.span().size() == 0);
+  // }
 }
 
 int main(int, char**) {
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.members/span.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.members/span.pass.cpp
index 25cee72694163..10316fe19f9ff 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.members/span.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.members/span.pass.cpp
@@ -34,16 +34,16 @@ void test() {
   std::span<CharT> sp{arr};
 
   // TODO:
-
-  // Mode: default
-  {
-    SpBuf rhsSpBuf{sp};
-    SpBuf spBuf(std::span<CharT>{});
-    spBuf.swap(rhsSpBuf);
-    assert(spBuf.span().data() == arr);
-    assert(!spBuf.span().empty());
-    assert(spBuf.span().size() == 4);
-  }
+  (void)sp;
+  // // Mode: default
+  // {
+  //   SpBuf rhsSpBuf{sp};
+  //   SpBuf spBuf(std::span<CharT>{});
+  //   spBuf.swap(rhsSpBuf);
+  //   assert(spBuf.span().data() == arr);
+  //   assert(!spBuf.span().empty());
+  //   assert(spBuf.span().size() == 4);
+  // }
 }
 
 int main(int, char**) {
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.members/span.span.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.members/span.span.pass.cpp
index 9b696391b746f..8a0e3adc9df0e 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.members/span.span.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.members/span.span.pass.cpp
@@ -35,16 +35,16 @@ void test() {
   std::span<CharT> sp{arr};
 
   // TODO:
-
+  (void)sp;
   // Mode: default
-  {
-    SpBuf rhsSpBuf{sp};
-    SpBuf spBuf(std::span<CharT>{});
-    spBuf.swap(rhsSpBuf);
-    assert(spBuf.span().data() == arr);
-    assert(!spBuf.span().empty());
-    assert(spBuf.span().size() == 4);
-  }
+  // {
+  //   SpBuf rhsSpBuf{sp};
+  //   SpBuf spBuf(std::span<CharT>{});
+  //   spBuf.swap(rhsSpBuf);
+  //   assert(spBuf.span().data() == arr);
+  //   assert(!spBuf.span().empty());
+  //   assert(spBuf.span().size() == 4);
+  // }
 }
 
 int main(int, char**) {
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekoff.off_type.seek_dir.open_mode.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekoff.off_type.seek_dir.open_mode.pass.cpp
index 039fa1f61c09a..341e9f3f61d24 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekoff.off_type.seek_dir.open_mode.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekoff.off_type.seek_dir.open_mode.pass.cpp
@@ -38,16 +38,16 @@ void test() {
   std::span<CharT> sp{arr};
 
   // TODO:
-
-  // Mode: default
-  {
-    SpBuf rhsSpBuf{sp};
-    SpBuf spBuf(std::span<CharT>{});
-    spBuf.swap(rhsSpBuf);
-    assert(spBuf.span().data() == arr);
-    assert(!spBuf.span().empty());
-    assert(spBuf.span().size() == 4);
-  }
+  (void)sp;
+  // // Mode: default
+  // {
+  //   SpBuf rhsSpBuf{sp};
+  //   SpBuf spBuf(std::span<CharT>{});
+  //   spBuf.swap(rhsSpBuf);
+  //   assert(spBuf.span().data() == arr);
+  //   assert(!spBuf.span().empty());
+  //   assert(spBuf.span().size() == 4);
+  // }
 }
 
 int main(int, char**) {
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekoff.pos_type.open_mode.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekoff.pos_type.open_mode.pass.cpp
index 006d282cacc78..08b6cade94fb3 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekoff.pos_type.open_mode.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekoff.pos_type.open_mode.pass.cpp
@@ -34,16 +34,16 @@ void test() {
 
   CharT arr[4];
   std::span<CharT> sp{arr};
-
-  // Mode: default
-  {
-    SpBuf rhsSpBuf{sp};
-    SpBuf spBuf(std::span<CharT>{});
-    spBuf.swap(rhsSpBuf);
-    assert(spBuf.span().data() == arr);
-    assert(!spBuf.span().empty());
-    assert(spBuf.span().size() == 4);
-  }
+  (void)sp;
+  // // Mode: default
+  // {
+  //   SpBuf rhsSpBuf{sp};
+  //   SpBuf spBuf(std::span<CharT>{});
+  //   spBuf.swap(rhsSpBuf);
+  //   assert(spBuf.span().data() == arr);
+  //   assert(!spBuf.span().empty());
+  //   assert(spBuf.span().size() == 4);
+  // }
 }
 
 int main(int, char**) {
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/setbuf.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/setbuf.pass.cpp
index fe9f5c3bf9cd8..50e5b02a01c25 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/setbuf.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/setbuf.pass.cpp
@@ -34,16 +34,16 @@ void test() {
   std::span<CharT> sp{arr};
 
   // TODO:
-
+  (void)sp;
   // Mode: default
-  {
-    SpBuf rhsSpBuf{sp};
-    SpBuf spBuf(std::span<CharT>{});
-    spBuf.swap(rhsSpBuf);
-    assert(spBuf.span().data() == arr);
-    assert(!spBuf.span().empty());
-    assert(spBuf.span().size() == 4);
-  }
+  // {
+  //   SpBuf rhsSpBuf{sp};
+  //   SpBuf spBuf(std::span<CharT>{});
+  //   spBuf.swap(rhsSpBuf);
+  //   assert(spBuf.span().data() == arr);
+  //   assert(!spBuf.span().empty());
+  //   assert(spBuf.span().size() == 4);
+  // }
 }
 
 int main(int, char**) {

>From 404378227adf5a7926bce5cdef4baa1880b980ec Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Tue, 5 Mar 2024 19:26:52 +0200
Subject: [PATCH 27/56] Tests: try to fix CI

---
 .../spanbuf/spanbuf.assign/move.pass.cpp      | 19 +++++++++---------
 .../spanbuf/spanbuf.assign/swap.pass.cpp      | 20 +++++++++----------
 .../spanbuf.assign/swap_nonmember.pass.cpp    | 20 +++++++++----------
 .../spanbuf/spanbuf.members/span.pass.cpp     | 20 +++++++++----------
 .../spanbuf.members/span.span.pass.cpp        | 18 ++++++++---------
 ...ekoff.off_type.seek_dir.open_mode.pass.cpp | 20 +++++++++----------
 .../seekoff.pos_type.open_mode.pass.cpp       | 20 +++++++++----------
 .../spanbuf/spanbuf.virtuals/setbuf.pass.cpp  | 18 ++++++++---------
 8 files changed, 78 insertions(+), 77 deletions(-)

diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/move.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/move.pass.cpp
index 7702c2c51dbc8..c2cc8104707be 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/move.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/move.pass.cpp
@@ -35,15 +35,16 @@ void test() {
   std::span<CharT> sp{arr};
 
   // TODO:
-  (void)sp;
-  // // Mode: default
-  // {
-  //   SpBuf rhsSpBuf{sp};
-  //   SpBuf spBuf = std::move(rhsSpBuf);
-  //   assert(spBuf.span().data() == arr);
-  //   assert(!spBuf.span().empty());
-  //   assert(spBuf.span().size() == 4);
-  // }
+
+  // Mode: default
+  {
+    SpBuf rhsSpBuf{sp};
+    SpBuf spBuf = std::move(rhsSpBuf);
+    (void)spBuf;
+    // assert(spBuf.span().data() == arr);
+    // assert(!spBuf.span().empty());
+    // assert(spBuf.span().size() == 4);
+  }
   // // Mode: `ios_base::in`
   // {
   //   SpBuf rhsSpBuf{sp, std::ios_base::in};
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/swap.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/swap.pass.cpp
index e5a2fff2ba8ba..cf036856f0b00 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/swap.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/swap.pass.cpp
@@ -34,16 +34,16 @@ void test() {
   std::span<CharT> sp{arr};
 
   // TODO:
-  (void)sp;
-  // // Mode: default
-  // {
-  //   SpBuf rhsSpBuf{sp};
-  //   SpBuf spBuf(std::span<CharT>{});
-  //   spBuf.swap(rhsSpBuf);
-  //   assert(spBuf.span().data() == arr);
-  //   assert(!spBuf.span().empty());
-  //   assert(spBuf.span().size() == 4);
-  // }
+
+  // Mode: default
+  {
+    SpBuf rhsSpBuf{sp};
+    SpBuf spBuf(std::span<CharT>{});
+    spBuf.swap(rhsSpBuf);
+    // assert(spBuf.span().data() == arr);
+    // assert(!spBuf.span().empty());
+    // assert(spBuf.span().size() == 4);
+  }
   // // Mode: `ios_base::in`
   // {
   //   SpBuf rhsSpBuf{sp, std::ios_base::in};
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/swap_nonmember.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/swap_nonmember.pass.cpp
index e3342253bc741..d834332bdca15 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/swap_nonmember.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/swap_nonmember.pass.cpp
@@ -30,16 +30,16 @@ void test() {
   std::span<CharT> sp{arr};
 
   // TODO:
-  (void)sp;
-  // // Mode: default
-  // {
-  //   SpBuf rhsSpBuf{sp};
-  //   SpBuf spBuf(std::span<CharT>{});
-  //   std::swap(spBuf, rhsSpBuf);
-  //   assert(spBuf.span().data() == arr);
-  //   assert(!spBuf.span().empty());
-  //   assert(spBuf.span().size() == 4);
-  // }
+
+  // Mode: default
+  {
+    SpBuf rhsSpBuf{sp};
+    SpBuf spBuf(std::span<CharT>{});
+    std::swap(spBuf, rhsSpBuf);
+    // assert(spBuf.span().data() == arr);
+    // assert(!spBuf.span().empty());
+    // assert(spBuf.span().size() == 4);
+  }
   // // Mode: `ios_base::in`
   // {
   //   SpBuf rhsSpBuf{sp, std::ios_base::in};
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.members/span.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.members/span.pass.cpp
index 10316fe19f9ff..98e8aef0330e9 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.members/span.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.members/span.pass.cpp
@@ -34,16 +34,16 @@ void test() {
   std::span<CharT> sp{arr};
 
   // TODO:
-  (void)sp;
-  // // Mode: default
-  // {
-  //   SpBuf rhsSpBuf{sp};
-  //   SpBuf spBuf(std::span<CharT>{});
-  //   spBuf.swap(rhsSpBuf);
-  //   assert(spBuf.span().data() == arr);
-  //   assert(!spBuf.span().empty());
-  //   assert(spBuf.span().size() == 4);
-  // }
+
+  // Mode: default
+  {
+    SpBuf rhsSpBuf{sp};
+    SpBuf spBuf(std::span<CharT>{});
+    spBuf.swap(rhsSpBuf);
+    // assert(spBuf.span().data() == arr);
+    // assert(!spBuf.span().empty());
+    // assert(spBuf.span().size() == 4);
+  }
 }
 
 int main(int, char**) {
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.members/span.span.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.members/span.span.pass.cpp
index 8a0e3adc9df0e..3b3ef6704bade 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.members/span.span.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.members/span.span.pass.cpp
@@ -35,16 +35,16 @@ void test() {
   std::span<CharT> sp{arr};
 
   // TODO:
-  (void)sp;
+
   // Mode: default
-  // {
-  //   SpBuf rhsSpBuf{sp};
-  //   SpBuf spBuf(std::span<CharT>{});
-  //   spBuf.swap(rhsSpBuf);
-  //   assert(spBuf.span().data() == arr);
-  //   assert(!spBuf.span().empty());
-  //   assert(spBuf.span().size() == 4);
-  // }
+  {
+    SpBuf rhsSpBuf{sp};
+    SpBuf spBuf(std::span<CharT>{});
+    spBuf.swap(rhsSpBuf);
+    // assert(spBuf.span().data() == arr);
+    // assert(!spBuf.span().empty());
+    // assert(spBuf.span().size() == 4);
+  }
 }
 
 int main(int, char**) {
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekoff.off_type.seek_dir.open_mode.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekoff.off_type.seek_dir.open_mode.pass.cpp
index 341e9f3f61d24..6b4580bedb89c 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekoff.off_type.seek_dir.open_mode.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekoff.off_type.seek_dir.open_mode.pass.cpp
@@ -38,16 +38,16 @@ void test() {
   std::span<CharT> sp{arr};
 
   // TODO:
-  (void)sp;
-  // // Mode: default
-  // {
-  //   SpBuf rhsSpBuf{sp};
-  //   SpBuf spBuf(std::span<CharT>{});
-  //   spBuf.swap(rhsSpBuf);
-  //   assert(spBuf.span().data() == arr);
-  //   assert(!spBuf.span().empty());
-  //   assert(spBuf.span().size() == 4);
-  // }
+
+  // Mode: default
+  {
+    SpBuf rhsSpBuf{sp};
+    SpBuf spBuf(std::span<CharT>{});
+    spBuf.swap(rhsSpBuf);
+    // assert(spBuf.span().data() == arr);
+    // assert(!spBuf.span().empty());
+    // assert(spBuf.span().size() == 4);
+  }
 }
 
 int main(int, char**) {
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekoff.pos_type.open_mode.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekoff.pos_type.open_mode.pass.cpp
index 08b6cade94fb3..0980143e67407 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekoff.pos_type.open_mode.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekoff.pos_type.open_mode.pass.cpp
@@ -34,16 +34,16 @@ void test() {
 
   CharT arr[4];
   std::span<CharT> sp{arr};
-  (void)sp;
-  // // Mode: default
-  // {
-  //   SpBuf rhsSpBuf{sp};
-  //   SpBuf spBuf(std::span<CharT>{});
-  //   spBuf.swap(rhsSpBuf);
-  //   assert(spBuf.span().data() == arr);
-  //   assert(!spBuf.span().empty());
-  //   assert(spBuf.span().size() == 4);
-  // }
+
+  // Mode: default
+  {
+    SpBuf rhsSpBuf{sp};
+    SpBuf spBuf(std::span<CharT>{});
+    spBuf.swap(rhsSpBuf);
+    // assert(spBuf.span().data() == arr);
+    // assert(!spBuf.span().empty());
+    // assert(spBuf.span().size() == 4);
+  }
 }
 
 int main(int, char**) {
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/setbuf.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/setbuf.pass.cpp
index 50e5b02a01c25..193185da8d9ca 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/setbuf.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/setbuf.pass.cpp
@@ -34,16 +34,16 @@ void test() {
   std::span<CharT> sp{arr};
 
   // TODO:
-  (void)sp;
+
   // Mode: default
-  // {
-  //   SpBuf rhsSpBuf{sp};
-  //   SpBuf spBuf(std::span<CharT>{});
-  //   spBuf.swap(rhsSpBuf);
-  //   assert(spBuf.span().data() == arr);
-  //   assert(!spBuf.span().empty());
-  //   assert(spBuf.span().size() == 4);
-  // }
+  {
+    SpBuf rhsSpBuf{sp};
+    SpBuf spBuf(std::span<CharT>{});
+    spBuf.swap(rhsSpBuf);
+    // assert(spBuf.span().data() == arr);
+    // assert(!spBuf.span().empty());
+    // assert(spBuf.span().size() == 4);
+  }
 }
 
 int main(int, char**) {

>From 3b8573a02d8416856af7c56b12244283bdc8eb32 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Wed, 6 Mar 2024 14:53:21 +0200
Subject: [PATCH 28/56] Tests: WIP `span.pass` and `span.span.pass`

---
 libcxx/include/spanstream                     | 13 +--
 .../input.output/span.streams/helper_types.h  | 23 ++---
 .../spanbuf/spanbuf.members/span.pass.cpp     | 20 ++--
 .../spanbuf.members/span.span.pass.cpp        | 94 +++++++++++++++++--
 4 files changed, 107 insertions(+), 43 deletions(-)

diff --git a/libcxx/include/spanstream b/libcxx/include/spanstream
index c735baaae93d9..f1ffd4f201368 100644
--- a/libcxx/include/spanstream
+++ b/libcxx/include/spanstream
@@ -66,11 +66,12 @@
 #include <__utility/move.h>
 #include <__utility/swap.h>
 #include <iostream>
-// #include <print>
 #include <span>
 #include <streambuf>
 #include <version>
 
+// #include <print>
+
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
 #endif
@@ -98,11 +99,11 @@ public:
   _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) {}
+      : basic_streambuf<_CharT, _Traits>{}, __mode_{__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} {
+      : basic_streambuf<_CharT, _Traits>{}, __mode_{__which} {
     this->span(__s);
   }
 
@@ -267,14 +268,8 @@ public:
     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::println(stderr, "ispanstream");
     std::span<const _CharT> __sp(std::forward<_ROSeq>(__s));
-    // std::println(stderr, "span __sb_ {} {}", __sb_.span().empty(), __sb_.span().size());
-    // std::println(stderr, "span data {} {}", __sp.empty(), __sp.size());
-    // std::println(stderr, "ispanstream 2");
     this->span(std::span<_CharT>(std::span<_CharT>(const_cast<_CharT*>(__sp.data()), __sp.size())));
-    // std::println(stderr, "span __sb_ {} {}", __sb_.span().empty(), __sb_.span().size());
-    // std::println(stderr, "ispanstream 3");
   }
 
   basic_ispanstream& operator=(const basic_ispanstream&) = delete;
diff --git a/libcxx/test/std/input.output/span.streams/helper_types.h b/libcxx/test/std/input.output/span.streams/helper_types.h
index 7f67432f9f880..79760f97e223b 100644
--- a/libcxx/test/std/input.output/span.streams/helper_types.h
+++ b/libcxx/test/std/input.output/span.streams/helper_types.h
@@ -16,7 +16,7 @@
 
 #include "test_macros.h"
 
-// #include <print>
+// ROS types
 
 template <typename CharT, std::size_t N = 0>
 class ReadOnlySpan {
@@ -25,19 +25,10 @@ class ReadOnlySpan {
 
   operator std::span<CharT>() = delete;
 
-  operator std::span<const CharT>() {
-    // std::println(stderr, "----> ROspan");
-    return std::span<const CharT, N>{arr_};
-  }
+  operator std::span<const CharT>() { return std::span<const CharT, N>{arr_}; }
 
-  const CharT* begin() {
-    // std::println(stderr, "----> ROspan begin");
-    return arr_;
-  }
-  const CharT* end() {
-    // std::println(stderr, "----> ROspan end");
-    return arr_ + N;
-  }
+  const CharT* begin() { return arr_; }
+  const CharT* end() { return arr_ + N; }
 
 private:
   CharT* arr_;
@@ -46,6 +37,8 @@ class ReadOnlySpan {
 template <typename CharT, std::size_t N>
 inline constexpr bool std::ranges::enable_borrowed_range<ReadOnlySpan<CharT, N>> = true;
 
+// Constraints: Constructors [ispanstream.cons]
+
 static_assert(std::ranges::borrowed_range<ReadOnlySpan<char>>);
 
 static_assert(!std::constructible_from<std::span<char>, ReadOnlySpan<char>>);
@@ -96,6 +89,8 @@ class NonReadOnlySpan {
 template <typename CharT, std::size_t N>
 inline constexpr bool std::ranges::enable_borrowed_range<NonReadOnlySpan<CharT, N>> = true;
 
+// Constraints: Constructors [ispanstream.cons]
+
 static_assert(std::ranges::borrowed_range<NonReadOnlySpan<char>>);
 
 static_assert(std::constructible_from<std::span<char>, NonReadOnlySpan<char>>);
@@ -126,7 +121,7 @@ static_assert(!std::constructible_from<std::span<const wchar_t>, const NonReadOn
 static_assert(!std::convertible_to<const NonReadOnlySpan<wchar_t>, std::span<const wchar_t>>);
 #endif
 
-struct SomeObject {};
+// Mode types
 
 struct NonMode {};
 
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.members/span.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.members/span.pass.cpp
index 98e8aef0330e9..7d5ebea2903ea 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.members/span.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.members/span.pass.cpp
@@ -31,19 +31,17 @@ void test() {
   using SpBuf = std::basic_spanbuf<CharT, TraitsT>;
 
   CharT arr[4];
-  std::span<CharT> sp{arr};
-
-  // TODO:
 
-  // Mode: default
+  std::span<CharT> sp{arr};
+  assert(sp.data() == arr);
+  assert(!sp.empty());
+  assert(sp.size() == 4);
+  
   {
-    SpBuf rhsSpBuf{sp};
-    SpBuf spBuf(std::span<CharT>{});
-    spBuf.swap(rhsSpBuf);
-    // assert(spBuf.span().data() == arr);
-    // assert(!spBuf.span().empty());
-    // assert(spBuf.span().size() == 4);
-  }
+  SpBuf spBuf(sp);
+  assert(spBuf.span().data() == arr);
+  assert(!spBuf.span().empty());
+  assert(spBuf.span().size() == 4);
 }
 
 int main(int, char**) {
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.members/span.span.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.members/span.span.pass.cpp
index 3b3ef6704bade..e1dfe517fe0d6 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.members/span.span.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.members/span.span.pass.cpp
@@ -32,18 +32,94 @@ void test() {
   using SpBuf = std::basic_spanbuf<CharT, TraitsT>;
 
   CharT arr[4];
-  std::span<CharT> sp{arr};
 
-  // TODO:
+  // Mode: default (`in` | `out`)
+  {
+    SpBuf spBuf;
+    assert(spBuf.span().data() == nullptr);
+    assert(spBuf.span().empty());
+    assert(spBuf.span().size() == 0);
+
+    spBuf.span(arr);
+    assert(spBuf.span().data() == arr);
+    // Mode `out` counts read characters
+    assert(spBuf.span().empty());
+    assert(spBuf.span().size() == 0);
+  }
+  {
+    SpBuf spBuf;
+    assert(spBuf.span().data() == nullptr);
+    assert(spBuf.span().empty());
+    assert(spBuf.span().size() == 0);
+
+    std::span<CharT> sp{arr};
+    assert(sp.data() == arr);
+    assert(!sp.empty());
+    assert(sp.size() == 4);
+
+    spBuf.span(sp);
+    assert(spBuf.span().data() == arr);
+    // Mode `out` counts read characters
+    assert(spBuf.span().empty());
+    assert(spBuf.span().size() == 0);
+  }
+  // Mode: `in`
+  {
+    SpBuf spBuf{std::ios_base::in};
+    assert(spBuf.span().data() == nullptr);
+    assert(spBuf.span().empty());
+    assert(spBuf.span().size() == 0);
+
+    spBuf.span(arr);
+    assert(spBuf.span().data() == arr);
+    assert(!spBuf.span().empty());
+    assert(spBuf.span().size() == 4);
+  }
+  {
+    SpBuf spBuf{std::ios_base::in};
+    assert(spBuf.span().data() == nullptr);
+    assert(spBuf.span().empty());
+    assert(spBuf.span().size() == 0);
+
+    std::span<CharT> sp{arr};
+    assert(sp.data() == arr);
+    assert(!sp.empty());
+    assert(sp.size() == 4);
 
-  // Mode: default
+    spBuf.span(sp);
+    assert(spBuf.span().data() == arr);
+    assert(!spBuf.span().empty());
+    assert(spBuf.span().size() == 4);
+  }
+  // Mode: `out`
   {
-    SpBuf rhsSpBuf{sp};
-    SpBuf spBuf(std::span<CharT>{});
-    spBuf.swap(rhsSpBuf);
-    // assert(spBuf.span().data() == arr);
-    // assert(!spBuf.span().empty());
-    // assert(spBuf.span().size() == 4);
+    SpBuf spBuf{std::ios_base::out};
+    assert(spBuf.span().data() == nullptr);
+    assert(spBuf.span().empty());
+    assert(spBuf.span().size() == 0);
+
+    spBuf.span(arr);
+    assert(spBuf.span().data() == arr);
+    // Mode `out` counts read characters
+    assert(spBuf.span().empty());
+    assert(spBuf.span().size() == 0);
+  }
+  {
+    SpBuf spBuf{std::ios_base::out};
+    assert(spBuf.span().data() == nullptr);
+    assert(spBuf.span().empty());
+    assert(spBuf.span().size() == 0);
+
+    std::span<CharT> sp{arr};
+    assert(sp.data() == arr);
+    assert(!sp.empty());
+    assert(sp.size() == 4);
+
+    spBuf.span(sp);
+    assert(spBuf.span().data() == arr);
+    // Mode `out` counts read characters
+    assert(spBuf.span().empty());
+    assert(spBuf.span().size() == 0);
   }
 }
 

>From b16e2acdff975f1b5edf68f19cf64a6f268de965 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Wed, 6 Mar 2024 21:59:17 +0200
Subject: [PATCH 29/56] Tests: updated `span.pass` and `span.span.pass`

---
 .../spanbuf/spanbuf.members/span.pass.cpp     | 36 ++++++++--
 .../spanbuf.members/span.span.pass.cpp        | 66 +++++++++++++++----
 2 files changed, 83 insertions(+), 19 deletions(-)

diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.members/span.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.members/span.pass.cpp
index 7d5ebea2903ea..635b8d2a03073 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.members/span.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.members/span.pass.cpp
@@ -36,12 +36,38 @@ void test() {
   assert(sp.data() == arr);
   assert(!sp.empty());
   assert(sp.size() == 4);
-  
+
+  // Mode: default (`in` | `out`)
+  {
+    SpBuf spBuf(sp);
+    assert(spBuf.span().data() == arr);
+    // Mode `out` counts read characters
+    assert(spBuf.span().empty());
+    assert(spBuf.span().size() == 0);
+  }
+  // Mode: `in`
+  {
+    SpBuf spBuf(sp, std::ios_base::in);
+    assert(spBuf.span().data() == arr);
+    assert(!spBuf.span().empty());
+    assert(spBuf.span().size() == 4);
+  }
+  // Mode: `out`
+  {
+    SpBuf spBuf(sp, std::ios_base::out);
+    assert(spBuf.span().data() == arr);
+    // Mode `out` counts read characters
+    assert(spBuf.span().empty());
+    assert(spBuf.span().size() == 0);
+  }
+  // Mode: multiple
   {
-  SpBuf spBuf(sp);
-  assert(spBuf.span().data() == arr);
-  assert(!spBuf.span().empty());
-  assert(spBuf.span().size() == 4);
+    SpBuf spBuf(sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary);
+    assert(spBuf.span().data() == arr);
+    // Mode `out` counts read characters
+    assert(spBuf.span().empty());
+    assert(spBuf.span().size() == 0);
+  }
 }
 
 int main(int, char**) {
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.members/span.span.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.members/span.span.pass.cpp
index e1dfe517fe0d6..5495cdefbe7c6 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.members/span.span.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.members/span.span.pass.cpp
@@ -33,6 +33,11 @@ void test() {
 
   CharT arr[4];
 
+  std::span<CharT> sp{arr};
+  assert(sp.data() == arr);
+  assert(!sp.empty());
+  assert(sp.size() == 4);
+
   // Mode: default (`in` | `out`)
   {
     SpBuf spBuf;
@@ -52,11 +57,6 @@ void test() {
     assert(spBuf.span().empty());
     assert(spBuf.span().size() == 0);
 
-    std::span<CharT> sp{arr};
-    assert(sp.data() == arr);
-    assert(!sp.empty());
-    assert(sp.size() == 4);
-
     spBuf.span(sp);
     assert(spBuf.span().data() == arr);
     // Mode `out` counts read characters
@@ -81,11 +81,6 @@ void test() {
     assert(spBuf.span().empty());
     assert(spBuf.span().size() == 0);
 
-    std::span<CharT> sp{arr};
-    assert(sp.data() == arr);
-    assert(!sp.empty());
-    assert(sp.size() == 4);
-
     spBuf.span(sp);
     assert(spBuf.span().data() == arr);
     assert(!spBuf.span().empty());
@@ -110,10 +105,30 @@ void test() {
     assert(spBuf.span().empty());
     assert(spBuf.span().size() == 0);
 
-    std::span<CharT> sp{arr};
-    assert(sp.data() == arr);
-    assert(!sp.empty());
-    assert(sp.size() == 4);
+    spBuf.span(sp);
+    assert(spBuf.span().data() == arr);
+    // Mode `out` counts read characters
+    assert(spBuf.span().empty());
+    assert(spBuf.span().size() == 0);
+  }
+  // Mode: multiple
+  {
+    SpBuf spBuf(std::ios_base::in | std::ios_base::out | std::ios_base::binary);
+    assert(spBuf.span().data() == nullptr);
+    assert(spBuf.span().empty());
+    assert(spBuf.span().size() == 0);
+
+    spBuf.span(arr);
+    assert(spBuf.span().data() == arr);
+    // Mode `out` counts read characters
+    assert(spBuf.span().empty());
+    assert(spBuf.span().size() == 0);
+  }
+  {
+    SpBuf spBuf(std::ios_base::in | std::ios_base::out | std::ios_base::binary);
+    assert(spBuf.span().data() == nullptr);
+    assert(spBuf.span().empty());
+    assert(spBuf.span().size() == 0);
 
     spBuf.span(sp);
     assert(spBuf.span().data() == arr);
@@ -121,6 +136,29 @@ void test() {
     assert(spBuf.span().empty());
     assert(spBuf.span().size() == 0);
   }
+  // Mode: `ate`
+  {
+    SpBuf spBuf(std::ios_base::out | std::ios_base::ate);
+    assert(spBuf.span().data() == nullptr);
+    assert(spBuf.span().empty());
+    assert(spBuf.span().size() == 0);
+
+    spBuf.span(arr);
+    assert(spBuf.span().data() == arr);
+    assert(!spBuf.span().empty());
+    assert(spBuf.span().size() == 4);
+  }
+  {
+    SpBuf spBuf(std::ios_base::out | std::ios_base::ate);
+    assert(spBuf.span().data() == nullptr);
+    assert(spBuf.span().empty());
+    assert(spBuf.span().size() == 0);
+
+    spBuf.span(sp);
+    assert(spBuf.span().data() == arr);
+    assert(!spBuf.span().empty());
+    assert(spBuf.span().size() == 4);
+  }
 }
 
 int main(int, char**) {

>From 6a5fdde69ba0a235a202a296fcd22538df4e30b3 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Sat, 9 Mar 2024 07:52:45 +0200
Subject: [PATCH 30/56] Implementations: `basic_spanbuf` improved constructors
 and member functions

---
 libcxx/include/spanstream | 39 ++++++++++++++++++++-------------------
 1 file changed, 20 insertions(+), 19 deletions(-)

diff --git a/libcxx/include/spanstream b/libcxx/include/spanstream
index f1ffd4f201368..63b61d1dee26d 100644
--- a/libcxx/include/spanstream
+++ b/libcxx/include/spanstream
@@ -99,12 +99,12 @@ public:
   _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_streambuf<_CharT, _Traits>{}, __mode_{__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} {
-    this->span(__s);
+      : basic_streambuf<_CharT, _Traits>{}, __mode_(__which) {
+    span(__s);
   }
 
   basic_spanbuf(const basic_spanbuf&) = delete;
@@ -113,6 +113,7 @@ public:
       : basic_streambuf<_CharT, _Traits>{std::move(__rhs)},
         __mode_{std::move(__rhs.__mode_)},
         __buf_{std::move(__rhs.__buf_)} {}
+  // __buf_{std::exchange(__rhs.__buf_, {})} {}
 
   // [spanbuf.assign], assignment and swap
 
@@ -120,7 +121,7 @@ public:
 
   _LIBCPP_HIDE_FROM_ABI basic_spanbuf& operator=(basic_spanbuf&& __rhs) {
     basic_spanbuf __tmp{std::move(__rhs)};
-    this->swap(__tmp);
+    swap(__tmp);
     return *this;
   }
 
@@ -134,7 +135,7 @@ public:
 
   _LIBCPP_HIDE_FROM_ABI std::span<_CharT> span() const noexcept {
     if (__mode_ & ios_base::out) {
-      return std::span<_CharT>(this->pbase(), this->pptr());
+      return std::span<_CharT>{this->pbase(), this->pptr()};
     }
     return __buf_;
   }
@@ -158,38 +159,38 @@ 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));
+    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));
+    const auto __error = static_cast<pos_type>(off_type{-1});
 
     if ((__which & ios_base::in) && (__which & ios_base::out) && (ios_base::cur == __way))
       return __error;
 
     // Calculate __baseoff
 
-    off_type __baseoff;
+    std::size_t __baseoff;
 
     switch (__way) {
     case ios_base::beg:
-      __baseoff = off_type(0);
+      __baseoff = 0Z;
       break;
 
     case ios_base::cur:
       if (__which & ios_base::out)
-        __baseoff = off_type(this->pptr() - this->pbase());
+        __baseoff = this->pptr() - this->pbase();
       else
-        __baseoff = off_type(this->gptr() - this->eback());
+        __baseoff = this->gptr() - this->eback();
       break;
 
     case ios_base::end:
       if ((__which & ios_base::out) && !(__which & ios_base::in))
-        __baseoff = off_type(this->pptr() - this->pbase());
+        __baseoff = this->pptr() - this->pbase();
       else
-        __baseoff = off_type(__buf_.size());
+        __baseoff = __buf_.size();
       break;
 
     default:
@@ -200,29 +201,29 @@ protected:
 
     off_type __newoff;
 
-    if (__builtin_add_overflow(__baseoff, __off, &__newoff) || (__newoff < off_type(0)) ||
-        (std::cmp_greater(__newoff, __buf_.size())))
+    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)))
+      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)))
+      if ((this->pptr() == nullptr) && (__newoff != off_type{0}))
         return __error;
       this->setp(this->pbase(), this->epptr());
       this->pbump(__newoff);
     }
 
-    return pos_type(__newoff);
+    return static_cast<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);
+    return seekoff(static_cast<off_type>(__sp), ios_base::beg, __which);
   }
 
 private:

>From f7569a1ed2c532683aef9c2a3b82ac0ffd3cd37c Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Sat, 9 Mar 2024 07:53:28 +0200
Subject: [PATCH 31/56] Tests: `basic_spanbuf` improved tests for constructors
 and member functions

---
 .../spanbuf/spanbuf.assign/move.pass.cpp      | 353 ++++++++++++--
 .../spanbuf/spanbuf.assign/swap.pass.cpp      | 138 ++++--
 .../spanbuf.assign/swap_nonmember.pass.cpp    | 138 ++++--
 .../spanbuf/spanbuf.cons/default.pass.cpp     |  14 +-
 .../spanbuf/spanbuf.cons/mode.pass.cpp        |  15 +-
 .../spanbuf/spanbuf.cons/move.pass.cpp        | 449 ++++++++++++------
 .../spanbuf/spanbuf.cons/span.mode.pass.cpp   |  67 ++-
 .../spanbuf/spanbuf.members/span.pass.cpp     |   7 +
 8 files changed, 912 insertions(+), 269 deletions(-)

diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/move.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/move.pass.cpp
index c2cc8104707be..c1749a1068ea9 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/move.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/move.pass.cpp
@@ -24,54 +24,337 @@
 #include <spanstream>
 
 #include "constexpr_char_traits.h"
-#include "test_convertible.h"
+#include "nasty_string.h"
 #include "test_macros.h"
 
+template <typename CharT, typename TraitsT>
+struct TestSpanBuf : std::basic_spanbuf<CharT, TraitsT> {
+  using std::basic_spanbuf<CharT, TraitsT>::basic_spanbuf;
+
+  TestSpanBuf(std::basic_spanbuf<CharT, TraitsT>&& rhs_p) : std::basic_spanbuf<CharT, TraitsT>(std::move(rhs_p)) {}
+
+  void check_postconditions(TestSpanBuf<CharT, TraitsT> const& rhs_p) const {
+    assert(this->span().data() == rhs_p.span().data());
+    assert(this->span().size() == rhs_p.span().size());
+    assert(this->eback() == rhs_p.eback());
+    assert(this->gptr() == rhs_p.gptr());
+    assert(this->egptr() == rhs_p.egptr());
+    assert(this->pbase() == rhs_p.pbase());
+    assert(this->pptr() == rhs_p.pptr());
+    assert(this->epptr() == rhs_p.epptr());
+    assert(this->getloc() == rhs_p.getloc());
+  }
+};
+
+template <typename CharT, typename TraitsT = std::char_traits<CharT>>
+void test_postconditions() {
+  using SpBuf = std::basic_spanbuf<CharT, TraitsT>;
+
+  // Empty `span`
+  {
+    // Mode: default
+    {
+      std::span<CharT> sp;
+      TestSpanBuf<CharT, TraitsT> rhsSpBuf(sp);
+      TestSpanBuf<CharT, TraitsT> spBuf = std::move(static_cast<SpBuf&>(rhsSpBuf));
+      assert(rhsSpBuf.span().data() == nullptr);
+      assert(spBuf.span().data() == nullptr);
+      spBuf.check_postconditions(rhsSpBuf);
+    }
+    // Mode: `in`
+    {
+      std::span<CharT> sp;
+      TestSpanBuf<CharT, TraitsT> rhsSpBuf(sp, std::ios_base::in);
+      TestSpanBuf<CharT, TraitsT> spBuf = std::move(static_cast<SpBuf&>(rhsSpBuf));
+      assert(rhsSpBuf.span().data() == nullptr);
+      assert(spBuf.span().data() == nullptr);
+      spBuf.check_postconditions(rhsSpBuf);
+    }
+    // Mode: `out`
+    {
+      std::span<CharT> sp;
+      TestSpanBuf<CharT, TraitsT> rhsSpBuf(sp, std::ios_base::out);
+      TestSpanBuf<CharT, TraitsT> spBuf = std::move(static_cast<SpBuf&>(rhsSpBuf));
+      assert(rhsSpBuf.span().data() == nullptr);
+      assert(spBuf.span().data() == nullptr);
+      spBuf.check_postconditions(rhsSpBuf);
+    }
+    // Mode: multiple
+    {
+      std::span<CharT> sp;
+      TestSpanBuf<CharT, TraitsT> rhsSpBuf(sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary);
+      TestSpanBuf<CharT, TraitsT> spBuf = std::move(static_cast<SpBuf&>(rhsSpBuf));
+      assert(rhsSpBuf.span().data() == nullptr);
+      assert(spBuf.span().data() == nullptr);
+      spBuf.check_postconditions(rhsSpBuf);
+    }
+    // Mode: `ate`
+    {
+      std::span<CharT> sp;
+      TestSpanBuf<CharT, TraitsT> rhsSpBuf(sp, std::ios_base::out | std::ios_base::ate);
+      TestSpanBuf<CharT, TraitsT> spBuf = std::move(static_cast<SpBuf&>(rhsSpBuf));
+      assert(rhsSpBuf.span().data() == nullptr);
+      assert(spBuf.span().data() == nullptr);
+      spBuf.check_postconditions(rhsSpBuf);
+    }
+  }
+
+  // Non-empty `span`
+  {
+    CharT arr[4];
+
+    // Mode: default
+    {
+      std::span<CharT> sp{arr};
+      TestSpanBuf<CharT, TraitsT> rhsSpBuf(sp);
+      TestSpanBuf<CharT, TraitsT> spBuf = std::move(static_cast<SpBuf&>(rhsSpBuf));
+      assert(rhsSpBuf.span().data() == arr);
+      assert(spBuf.span().data() == arr);
+      spBuf.check_postconditions(rhsSpBuf);
+    }
+    // Mode: `in`
+    {
+      std::span<CharT> sp{arr};
+      TestSpanBuf<CharT, TraitsT> rhsSpBuf(sp, std::ios_base::in);
+      TestSpanBuf<CharT, TraitsT> spBuf = std::move(static_cast<SpBuf&>(rhsSpBuf));
+      assert(rhsSpBuf.span().data() == arr);
+      assert(spBuf.span().data() == arr);
+      spBuf.check_postconditions(rhsSpBuf);
+    }
+    // Mode: `out`
+    {
+      std::span<CharT> sp{arr};
+      TestSpanBuf<CharT, TraitsT> rhsSpBuf(sp, std::ios_base::out);
+      TestSpanBuf<CharT, TraitsT> spBuf = std::move(static_cast<SpBuf&>(rhsSpBuf));
+      assert(rhsSpBuf.span().data() == arr);
+      assert(spBuf.span().data() == arr);
+      spBuf.check_postconditions(rhsSpBuf);
+    }
+    // Mode: multiple
+    {
+      std::span<CharT> sp{arr};
+      TestSpanBuf<CharT, TraitsT> rhsSpBuf(sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary);
+      TestSpanBuf<CharT, TraitsT> spBuf = std::move(static_cast<SpBuf&>(rhsSpBuf));
+      assert(rhsSpBuf.span().data() == arr);
+      assert(spBuf.span().data() == arr);
+      spBuf.check_postconditions(rhsSpBuf);
+    }
+    // Mode: `ate`
+    {
+      std::span<CharT> sp{arr};
+      TestSpanBuf<CharT, TraitsT> rhsSpBuf(sp, std::ios_base::out | std::ios_base::ate);
+      TestSpanBuf<CharT, TraitsT> spBuf = std::move(static_cast<SpBuf&>(rhsSpBuf));
+      assert(rhsSpBuf.span().data() == arr);
+      assert(spBuf.span().data() == arr);
+      spBuf.check_postconditions(rhsSpBuf);
+    }
+  }
+}
+
 template <typename CharT, typename TraitsT = std::char_traits<CharT>>
 void test() {
   using SpBuf = std::basic_spanbuf<CharT, TraitsT>;
 
-  CharT arr[4];
-  std::span<CharT> sp{arr};
+  // Empty `span`
+  {
+    // Mode: default (`in` | `out`)
+    {
+      SpBuf rhsSpBuf;
+      assert(rhsSpBuf.span().data() == nullptr);
+      // Mode `out` counts read characters
+      assert(rhsSpBuf.span().empty());
+      assert(rhsSpBuf.span().size() == 0);
+
+      SpBuf spBuf = std::move(rhsSpBuf);
+      assert(spBuf.span().data() == nullptr);
+      // Mode `out` counts read characters
+      assert(spBuf.span().empty());
+      assert(spBuf.span().size() == 0);
+
+      // After move
+      assert(rhsSpBuf.span().data() == nullptr);
+      assert(rhsSpBuf.span().empty());
+      assert(rhsSpBuf.span().size() == 0);
+    }
+    // Mode: `in`
+    {
+      SpBuf rhsSpBuf{std::ios_base::in};
+      assert(rhsSpBuf.span().data() == nullptr);
+      // Mode `out` counts read characters
+      assert(rhsSpBuf.span().empty());
+      assert(rhsSpBuf.span().size() == 0);
+
+      SpBuf spBuf = std::move(rhsSpBuf);
+      assert(spBuf.span().data() == nullptr);
+      assert(spBuf.span().empty());
+      assert(spBuf.span().size() == 0);
+
+      // After move
+      assert(rhsSpBuf.span().data() == nullptr);
+      assert(rhsSpBuf.span().empty());
+      assert(rhsSpBuf.span().size() == 0);
+    }
+    // Mode: `out`
+    {
+      SpBuf rhsSpBuf{std::ios_base::out};
+      assert(rhsSpBuf.span().data() == nullptr);
+      // Mode `out` counts read characters
+      assert(rhsSpBuf.span().empty());
+      assert(rhsSpBuf.span().size() == 0);
 
-  // TODO:
+      SpBuf spBuf = std::move(rhsSpBuf);
+      assert(spBuf.span().data() == nullptr);
+      // Mode `out` counts read characters
+      assert(spBuf.span().empty());
+      assert(spBuf.span().size() == 0);
 
-  // Mode: default
+      // After move
+      assert(rhsSpBuf.span().data() == nullptr);
+      // Mode `out` counts read characters
+      assert(rhsSpBuf.span().empty());
+      assert(rhsSpBuf.span().size() == 0);
+    }
+    // Mode: multiple
+    {
+      SpBuf rhsSpBuf{std::ios_base::out | std::ios_base::in | std::ios_base::binary};
+      assert(rhsSpBuf.span().data() == nullptr);
+      // Mode `out` counts read characters
+      assert(rhsSpBuf.span().empty());
+      assert(rhsSpBuf.span().size() == 0);
+
+      SpBuf spBuf = std::move(rhsSpBuf);
+      assert(spBuf.span().data() == nullptr);
+      // Mode `out` counts read characters
+      assert(spBuf.span().empty());
+      assert(spBuf.span().size() == 0);
+
+      // After move
+      assert(rhsSpBuf.span().data() == nullptr);
+      assert(rhsSpBuf.span().empty());
+      assert(rhsSpBuf.span().size() == 0);
+    }
+    // Mode: `ate`
+    {
+      SpBuf rhsSpBuf{std::ios_base::ate};
+      SpBuf spBuf = std::move(rhsSpBuf);
+      assert(spBuf.span().data() == nullptr);
+      assert(spBuf.span().empty());
+      assert(spBuf.span().size() == 0);
+
+      // After move
+      assert(rhsSpBuf.span().data() == nullptr);
+      assert(rhsSpBuf.span().empty());
+      assert(rhsSpBuf.span().size() == 0);
+    }
+  }
+
+  // Non-empty `span`
   {
-    SpBuf rhsSpBuf{sp};
-    SpBuf spBuf = std::move(rhsSpBuf);
-    (void)spBuf;
-    // assert(spBuf.span().data() == arr);
-    // assert(!spBuf.span().empty());
-    // assert(spBuf.span().size() == 4);
+    CharT arr[4];
+    std::span<CharT> sp{arr};
+
+    // Mode: default (`in` | `out`)
+    {
+      SpBuf rhsSpBuf{sp};
+      assert(rhsSpBuf.span().data() == arr);
+      // Mode `out` counts read characters
+      assert(rhsSpBuf.span().empty());
+      assert(rhsSpBuf.span().size() == 0);
+
+      SpBuf spBuf = std::move(rhsSpBuf);
+      assert(spBuf.span().data() == arr);
+      // Mode `out` counts read characters
+      assert(spBuf.span().empty());
+      assert(spBuf.span().size() == 0);
+
+      // After move
+      assert(rhsSpBuf.span().data() == arr);
+      assert(rhsSpBuf.span().empty());
+      assert(rhsSpBuf.span().size() == 0);
+    }
+    // Mode: `in`
+    {
+      SpBuf rhsSpBuf{sp, std::ios_base::in};
+      assert(rhsSpBuf.span().data() == arr);
+      assert(!rhsSpBuf.span().empty());
+      assert(rhsSpBuf.span().size() == 4);
+
+      SpBuf spBuf = std::move(rhsSpBuf);
+      assert(spBuf.span().data() == arr);
+      assert(!spBuf.span().empty());
+      assert(spBuf.span().size() == 4);
+    }
+    // Mode `out`
+    {
+      SpBuf rhsSpBuf{sp, std::ios_base::out};
+      assert(rhsSpBuf.span().data() == arr);
+      // Mode `out` counts read characters
+      assert(rhsSpBuf.span().empty());
+      assert(rhsSpBuf.span().size() == 0);
+
+      SpBuf spBuf = std::move(rhsSpBuf);
+      assert(spBuf.span().data() == arr);
+      // Mode `out` counts read characters
+      assert(spBuf.span().empty());
+      assert(spBuf.span().size() == 0);
+
+      // After move
+      assert(rhsSpBuf.span().data() == arr);
+      assert(rhsSpBuf.span().empty());
+      assert(rhsSpBuf.span().size() == 0);
+    }
+    // Mode: multiple
+    {
+      SpBuf rhsSpBuf{sp, std::ios_base::out | std::ios_base::in | std::ios_base::binary};
+      assert(rhsSpBuf.span().data() == arr);
+      // Mode `out` counts read characters
+      assert(rhsSpBuf.span().empty());
+      assert(rhsSpBuf.span().size() == 0);
+
+      SpBuf spBuf = std::move(rhsSpBuf);
+      assert(spBuf.span().data() == arr);
+      // Mode `out` counts read characters
+      assert(spBuf.span().empty());
+      assert(spBuf.span().size() == 0);
+
+      // After move
+      assert(rhsSpBuf.span().data() == arr);
+      assert(rhsSpBuf.span().empty());
+      assert(rhsSpBuf.span().size() == 0);
+    }
+    // Mode: `ate`
+    {
+      SpBuf rhsSpBuf{sp, std::ios_base::ate};
+      assert(rhsSpBuf.span().data() == arr);
+      assert(!rhsSpBuf.span().empty());
+      assert(rhsSpBuf.span().size() == 4);
+
+      SpBuf spBuf = std::move(rhsSpBuf);
+      assert(spBuf.span().data() == arr);
+      assert(!spBuf.span().empty());
+      assert(spBuf.span().size() == 4);
+
+      // After move
+      assert(rhsSpBuf.span().data() == arr);
+      assert(!rhsSpBuf.span().empty());
+      assert(rhsSpBuf.span().size() == 4);
+    }
   }
-  // // Mode: `ios_base::in`
-  // {
-  //   SpBuf rhsSpBuf{sp, std::ios_base::in};
-  //   SpBuf spBuf = std::move(rhsSpBuf);
-  //   assert(spBuf.span().data() == arr);
-  //   assert(!spBuf.span().empty());
-  //   assert(spBuf.span().size() == 4);
-  // }
-  // // Mode `ios_base::out`
-  // {
-  //   SpBuf rhsSpBuf{sp, std::ios_base::out};
-  //   SpBuf spBuf = std::move(rhsSpBuf);
-  //   assert(spBuf.span().data() == arr);
-  //   assert(spBuf.span().empty());
-  //   assert(spBuf.span().size() == 0);
-  // }
-  // // Mode: multiple
-  // {
-  //   SpBuf rhsSpBuf{sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary};
-  //   SpBuf spBuf = std::move(rhsSpBuf);
-  //   assert(spBuf.span().data() == arr);
-  //   assert(spBuf.span().empty());
-  //   assert(spBuf.span().size() == 0);
-  // }
 }
 
 int main(int, char**) {
+#ifndef TEST_HAS_NO_NASTY_STRING
+  test_postconditions<nasty_char, nasty_char_traits>();
+#endif
+  test_postconditions<char>();
+  test_postconditions<char, constexpr_char_traits<char>>();
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  test_postconditions<wchar_t>();
+  test_postconditions<wchar_t, constexpr_char_traits<wchar_t>>();
+#endif
+#ifndef TEST_HAS_NO_NASTY_STRING
+  test<nasty_char, nasty_char_traits>();
+#endif
   test<char>();
   test<char, constexpr_char_traits<char>>();
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/swap.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/swap.pass.cpp
index cf036856f0b00..6db44e92be58d 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/swap.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/swap.pass.cpp
@@ -31,46 +31,118 @@ void test() {
   using SpBuf = std::basic_spanbuf<CharT, TraitsT>;
 
   CharT arr[4];
-  std::span<CharT> sp{arr};
 
-  // TODO:
+  std::span<CharT> sp{arr};
+  assert(sp.data() == arr);
+  assert(!sp.empty());
+  assert(sp.size() == 4);
 
-  // Mode: default
+  // Mode: default (`in` | `out`)
   {
     SpBuf rhsSpBuf{sp};
+    assert(rhsSpBuf.span().data() == arr);
+    // Mode `out` counts read characters
+    assert(rhsSpBuf.span().empty());
+    assert(rhsSpBuf.span().size() == 0);
+
+    SpBuf spBuf;
+    assert(spBuf.span().data() == nullptr);
+    // Mode `out` counts read characters
+    assert(spBuf.span().empty());
+    assert(spBuf.span().size() == 0);
+
+    spBuf.swap(rhsSpBuf);
+    assert(spBuf.span().data() == arr);
+    assert(spBuf.span().empty());
+    assert(spBuf.span().size() == 0);
+    assert(rhsSpBuf.span().data() == nullptr);
+    assert(rhsSpBuf.span().empty());
+    assert(rhsSpBuf.span().size() == 0);
+  }
+  // Mode: `ios_base::in`
+  {
+    SpBuf rhsSpBuf{sp, std::ios_base::in};
+    assert(rhsSpBuf.span().data() == arr);
+    assert(!rhsSpBuf.span().empty());
+    assert(rhsSpBuf.span().size() == 4);
+
     SpBuf spBuf(std::span<CharT>{});
+    assert(spBuf.span().data() == nullptr);
+    assert(spBuf.span().empty());
+    assert(spBuf.span().size() == 0);
+
+    spBuf.swap(rhsSpBuf);
+    assert(spBuf.span().data() == arr);
+    assert(!spBuf.span().empty());
+    assert(spBuf.span().size() == 4);
+    assert(rhsSpBuf.span().data() == nullptr);
+    assert(rhsSpBuf.span().empty());
+    assert(rhsSpBuf.span().size() == 0);
+  }
+  // Mode `ios_base::out`
+  {
+    SpBuf rhsSpBuf{sp, std::ios_base::out};
+    assert(rhsSpBuf.span().data() == arr);
+    // Mode `out` counts read characters
+    assert(rhsSpBuf.span().empty());
+    assert(rhsSpBuf.span().size() == 0);
+
+    SpBuf spBuf;
+    assert(spBuf.span().data() == nullptr);
+    // Mode `out` counts read characters
+    assert(spBuf.span().empty());
+    assert(spBuf.span().size() == 0);
+
+    spBuf.swap(rhsSpBuf);
+    assert(spBuf.span().data() == arr);
+    assert(spBuf.span().empty());
+    assert(spBuf.span().size() == 0);
+    assert(rhsSpBuf.span().data() == nullptr);
+    assert(rhsSpBuf.span().empty());
+    assert(rhsSpBuf.span().size() == 0);
+  }
+  // Mode: multiple
+  {
+    SpBuf rhsSpBuf{sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary};
+    assert(rhsSpBuf.span().data() == arr);
+    // Mode `out` counts read characters
+    assert(rhsSpBuf.span().empty());
+    assert(rhsSpBuf.span().size() == 0);
+
+    SpBuf spBuf;
+    assert(spBuf.span().data() == nullptr);
+    // Mode `out` counts read characters
+    assert(spBuf.span().empty());
+    assert(spBuf.span().size() == 0);
+
+    spBuf.swap(rhsSpBuf);
+    assert(spBuf.span().data() == arr);
+    assert(spBuf.span().empty());
+    assert(spBuf.span().size() == 0);
+    assert(rhsSpBuf.span().data() == nullptr);
+    assert(rhsSpBuf.span().empty());
+    assert(rhsSpBuf.span().size() == 0);
+  }
+  // Mode: `ios_base::ate`
+  {
+    SpBuf rhsSpBuf{sp, std::ios_base::out | std::ios_base::ate};
+    assert(rhsSpBuf.span().data() == arr);
+    assert(!rhsSpBuf.span().empty());
+    assert(rhsSpBuf.span().size() == 4);
+
+    SpBuf spBuf(std::span<CharT>{});
+    assert(spBuf.span().data() == nullptr);
+    assert(spBuf.span().empty());
+    assert(spBuf.span().size() == 0);
+
     spBuf.swap(rhsSpBuf);
-    // assert(spBuf.span().data() == arr);
-    // assert(!spBuf.span().empty());
-    // assert(spBuf.span().size() == 4);
+    assert(spBuf.span().data() == arr);
+    assert(!spBuf.span().empty());
+    assert(spBuf.span().size() == 4);
+    assert(rhsSpBuf.span().data() == nullptr);
+    assert(rhsSpBuf.span().empty());
+    assert(rhsSpBuf.span().size() == 0);
   }
-  // // Mode: `ios_base::in`
-  // {
-  //   SpBuf rhsSpBuf{sp, std::ios_base::in};
-  //   SpBuf spBuf(std::span<CharT>{});
-  //   spBuf.swap(rhsSpBuf);
-  //   assert(spBuf.span().data() == arr);
-  //   assert(!spBuf.span().empty());
-  //   assert(spBuf.span().size() == 4);
-  // }
-  // // Mode `ios_base::out`
-  // {
-  //   SpBuf rhsSpBuf{sp, std::ios_base::out};
-  //   SpBuf spBuf(std::span<CharT>{});
-  //   spBuf.swap(rhsSpBuf);
-  //   assert(spBuf.span().data() == arr);
-  //   assert(spBuf.span().empty());
-  //   assert(spBuf.span().size() == 0);
-  // }
-  // // Mode: multiple
-  // {
-  //   SpBuf rhsSpBuf{sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary};
-  //   SpBuf spBuf(std::span<CharT>{});
-  //   spBuf.swap(rhsSpBuf);
-  //   assert(spBuf.span().data() == arr);
-  //   assert(spBuf.span().empty());
-  //   assert(spBuf.span().size() == 0);
-  // }
 }
 
 int main(int, char**) {
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/swap_nonmember.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/swap_nonmember.pass.cpp
index d834332bdca15..78c5015674019 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/swap_nonmember.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/swap_nonmember.pass.cpp
@@ -27,46 +27,118 @@ void test() {
   using SpBuf = std::basic_spanbuf<CharT, TraitsT>;
 
   CharT arr[4];
-  std::span<CharT> sp{arr};
 
-  // TODO:
+  std::span<CharT> sp{arr};
+  assert(sp.data() == arr);
+  assert(!sp.empty());
+  assert(sp.size() == 4);
 
-  // Mode: default
+  // Mode: default (`in` | `out`)
   {
     SpBuf rhsSpBuf{sp};
+    assert(rhsSpBuf.span().data() == arr);
+    // Mode `out` counts read characters
+    assert(rhsSpBuf.span().empty());
+    assert(rhsSpBuf.span().size() == 0);
+
+    SpBuf spBuf;
+    assert(spBuf.span().data() == nullptr);
+    // Mode `out` counts read characters
+    assert(spBuf.span().empty());
+    assert(spBuf.span().size() == 0);
+
+    std::swap(spBuf, rhsSpBuf);
+    assert(spBuf.span().data() == arr);
+    assert(spBuf.span().empty());
+    assert(spBuf.span().size() == 0);
+    assert(rhsSpBuf.span().data() == nullptr);
+    assert(rhsSpBuf.span().empty());
+    assert(rhsSpBuf.span().size() == 0);
+  }
+  // Mode: `ios_base::in`
+  {
+    SpBuf rhsSpBuf{sp, std::ios_base::in};
+    assert(rhsSpBuf.span().data() == arr);
+    assert(!rhsSpBuf.span().empty());
+    assert(rhsSpBuf.span().size() == 4);
+
     SpBuf spBuf(std::span<CharT>{});
+    assert(spBuf.span().data() == nullptr);
+    assert(spBuf.span().empty());
+    assert(spBuf.span().size() == 0);
+
+    std::swap(spBuf, rhsSpBuf);
+    assert(spBuf.span().data() == arr);
+    assert(!spBuf.span().empty());
+    assert(spBuf.span().size() == 4);
+    assert(rhsSpBuf.span().data() == nullptr);
+    assert(rhsSpBuf.span().empty());
+    assert(rhsSpBuf.span().size() == 0);
+  }
+  // Mode `ios_base::out`
+  {
+    SpBuf rhsSpBuf{sp, std::ios_base::out};
+    assert(rhsSpBuf.span().data() == arr);
+    // Mode `out` counts read characters
+    assert(rhsSpBuf.span().empty());
+    assert(rhsSpBuf.span().size() == 0);
+
+    SpBuf spBuf;
+    assert(spBuf.span().data() == nullptr);
+    // Mode `out` counts read characters
+    assert(spBuf.span().empty());
+    assert(spBuf.span().size() == 0);
+
+    std::swap(spBuf, rhsSpBuf);
+    assert(spBuf.span().data() == arr);
+    assert(spBuf.span().empty());
+    assert(spBuf.span().size() == 0);
+    assert(rhsSpBuf.span().data() == nullptr);
+    assert(rhsSpBuf.span().empty());
+    assert(rhsSpBuf.span().size() == 0);
+  }
+  // Mode: multiple
+  {
+    SpBuf rhsSpBuf{sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary};
+    assert(rhsSpBuf.span().data() == arr);
+    // Mode `out` counts read characters
+    assert(rhsSpBuf.span().empty());
+    assert(rhsSpBuf.span().size() == 0);
+
+    SpBuf spBuf;
+    assert(spBuf.span().data() == nullptr);
+    // Mode `out` counts read characters
+    assert(spBuf.span().empty());
+    assert(spBuf.span().size() == 0);
+
+    std::swap(spBuf, rhsSpBuf);
+    assert(spBuf.span().data() == arr);
+    assert(spBuf.span().empty());
+    assert(spBuf.span().size() == 0);
+    assert(rhsSpBuf.span().data() == nullptr);
+    assert(rhsSpBuf.span().empty());
+    assert(rhsSpBuf.span().size() == 0);
+  }
+  // Mode: `ios_base::ate`
+  {
+    SpBuf rhsSpBuf{sp, std::ios_base::out | std::ios_base::ate};
+    assert(rhsSpBuf.span().data() == arr);
+    assert(!rhsSpBuf.span().empty());
+    assert(rhsSpBuf.span().size() == 4);
+
+    SpBuf spBuf(std::span<CharT>{});
+    assert(spBuf.span().data() == nullptr);
+    assert(spBuf.span().empty());
+    assert(spBuf.span().size() == 0);
+
     std::swap(spBuf, rhsSpBuf);
-    // assert(spBuf.span().data() == arr);
-    // assert(!spBuf.span().empty());
-    // assert(spBuf.span().size() == 4);
+    assert(spBuf.span().data() == arr);
+    assert(!spBuf.span().empty());
+    assert(spBuf.span().size() == 4);
+    assert(rhsSpBuf.span().data() == nullptr);
+    assert(rhsSpBuf.span().empty());
+    assert(rhsSpBuf.span().size() == 0);
   }
-  // // Mode: `ios_base::in`
-  // {
-  //   SpBuf rhsSpBuf{sp, std::ios_base::in};
-  //   SpBuf spBuf(std::span<CharT>{});
-  //   std::swap(spBuf, rhsSpBuf);
-  //   assert(spBuf.span().data() == arr);
-  //   assert(!spBuf.span().empty());
-  //   assert(spBuf.span().size() == 4);
-  // }
-  // // Mode `ios_base::out`
-  // {
-  //   SpBuf rhsSpBuf{sp, std::ios_base::out};
-  //   SpBuf spBuf(std::span<CharT>{});
-  //   std::swap(spBuf, rhsSpBuf);
-  //   assert(spBuf.span().data() == arr);
-  //   assert(spBuf.span().empty());
-  //   assert(spBuf.span().size() == 0);
-  // }
-  // // Mode: multiple
-  // {
-  //   SpBuf rhsSpBuf{sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary};
-  //   SpBuf spBuf(std::span<CharT>{});
-  //   std::swap(spBuf, rhsSpBuf);
-  //   assert(spBuf.span().data() == arr);
-  //   assert(spBuf.span().empty());
-  //   assert(spBuf.span().size() == 0);
-  // }
 }
 
 int main(int, char**) {
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/default.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/default.pass.cpp
index b76af127f4314..e1c6604b1bceb 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/default.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/default.pass.cpp
@@ -21,19 +21,25 @@
 #include <spanstream>
 
 #include "constexpr_char_traits.h"
+#include "nasty_string.h"
 #include "test_macros.h"
 
 template <typename CharT, typename TraitsT = std::char_traits<CharT>>
 void test() {
   using SpBuf = std::basic_spanbuf<CharT, TraitsT>;
 
-  SpBuf spBuf;
-  assert(spBuf.span().data() == nullptr);
-  assert(spBuf.span().empty());
-  assert(spBuf.span().size() == 0);
+  {
+    SpBuf spBuf;
+    assert(spBuf.span().data() == nullptr);
+    assert(spBuf.span().empty());
+    assert(spBuf.span().size() == 0);
+  }
 }
 
 int main(int, char**) {
+#ifndef TEST_HAS_NO_NASTY_STRING
+  test<nasty_char, nasty_char_traits>();
+#endif
   test<char>();
   test<char, constexpr_char_traits<char>>();
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/mode.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/mode.pass.cpp
index d2bd64f35cb59..91fc5385484f7 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/mode.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/mode.pass.cpp
@@ -47,8 +47,6 @@ template <typename CharT, typename TraitsT = std::char_traits<CharT>>
 void test() {
   using SpBuf = std::basic_spanbuf<CharT, TraitsT>;
 
-  static_assert(std::default_initializable<SpBuf>);
-
   // Mode: `in`
   {
     SpBuf spBuf(std::ios_base::in);
@@ -60,6 +58,7 @@ void test() {
   {
     SpBuf spBuf(std::ios_base::out);
     assert(spBuf.span().data() == nullptr);
+    // Mode `out` counts read characters
     assert(spBuf.span().empty());
     assert(spBuf.span().size() == 0);
   }
@@ -67,6 +66,15 @@ void test() {
   {
     SpBuf spBuf(std::ios_base::in | std::ios_base::out | std::ios_base::binary);
     assert(spBuf.span().data() == nullptr);
+    // Mode `out` counts read character
+    assert(spBuf.span().empty());
+    assert(spBuf.span().size() == 0);
+  }
+  // Mode: `ate`
+  {
+    SpBuf spBuf(std::ios_base::out | std::ios_base::ate);
+    assert(spBuf.span().data() == nullptr);
+
     assert(spBuf.span().empty());
     assert(spBuf.span().size() == 0);
   }
@@ -78,6 +86,9 @@ int main(int, char**) {
 #endif
   test_sfinae<char>();
   test_sfinae<char, constexpr_char_traits<char>>();
+#ifndef TEST_HAS_NO_NASTY_STRING
+  test<nasty_char, nasty_char_traits>();
+#endif
   test<char>();
   test<char, constexpr_char_traits<char>>();
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/move.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/move.pass.cpp
index 1bab0f860d9f3..9252f64908de4 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/move.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/move.pass.cpp
@@ -24,7 +24,7 @@
 #include <spanstream>
 
 #include "constexpr_char_traits.h"
-#include "test_convertible.h"
+#include "nasty_string.h"
 #include "test_macros.h"
 
 template <typename CharT, typename TraitsT>
@@ -47,173 +47,314 @@ struct TestSpanBuf : std::basic_spanbuf<CharT, TraitsT> {
 };
 
 template <typename CharT, typename TraitsT = std::char_traits<CharT>>
-void test() {
+void test_postconditions() {
   using SpBuf = std::basic_spanbuf<CharT, TraitsT>;
 
+  // Empty `span`
+  {
+    // Mode: default
+    {
+      std::span<CharT> sp;
+      TestSpanBuf<CharT, TraitsT> rhsSpBuf(sp);
+      TestSpanBuf<CharT, TraitsT> spBuf(std::move(static_cast<SpBuf&>(rhsSpBuf)));
+      assert(rhsSpBuf.span().data() == nullptr);
+      assert(spBuf.span().data() == nullptr);
+      spBuf.check_postconditions(rhsSpBuf);
+    }
+    // Mode: `in`
+    {
+      std::span<CharT> sp;
+      TestSpanBuf<CharT, TraitsT> rhsSpBuf(sp, std::ios_base::in);
+      TestSpanBuf<CharT, TraitsT> spBuf(std::move(static_cast<SpBuf&>(rhsSpBuf)));
+      assert(rhsSpBuf.span().data() == nullptr);
+      assert(spBuf.span().data() == nullptr);
+      spBuf.check_postconditions(rhsSpBuf);
+    }
+    // Mode: `out`
+    {
+      std::span<CharT> sp;
+      TestSpanBuf<CharT, TraitsT> rhsSpBuf(sp, std::ios_base::out);
+      TestSpanBuf<CharT, TraitsT> spBuf(std::move(static_cast<SpBuf&>(rhsSpBuf)));
+      assert(rhsSpBuf.span().data() == nullptr);
+      assert(spBuf.span().data() == nullptr);
+      spBuf.check_postconditions(rhsSpBuf);
+    }
+    // Mode: multiple
+    {
+      std::span<CharT> sp;
+      TestSpanBuf<CharT, TraitsT> rhsSpBuf(sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary);
+      TestSpanBuf<CharT, TraitsT> spBuf(std::move(static_cast<SpBuf&>(rhsSpBuf)));
+      assert(rhsSpBuf.span().data() == nullptr);
+      assert(spBuf.span().data() == nullptr);
+      spBuf.check_postconditions(rhsSpBuf);
+    }
+    // Mode: `ate`
+    {
+      std::span<CharT> sp;
+      TestSpanBuf<CharT, TraitsT> rhsSpBuf(sp, std::ios_base::out | std::ios_base::ate);
+      TestSpanBuf<CharT, TraitsT> spBuf(std::move(static_cast<SpBuf&>(rhsSpBuf)));
+      assert(rhsSpBuf.span().data() == nullptr);
+      assert(spBuf.span().data() == nullptr);
+      spBuf.check_postconditions(rhsSpBuf);
+    }
+  }
+
+  // Non-empty `span`
   {
-    // Empty `span`
-    {
-      // Mode: default
-      {
-        SpBuf rhsSpBuf;
-        SpBuf spBuf(std::move(rhsSpBuf));
-        assert(spBuf.span().data() == nullptr);
-        assert(spBuf.span().empty());
-        assert(spBuf.span().size() == 0);
-      }
-      // Mode: `ios_base::in`
-      {
-        SpBuf rhsSpBuf{std::ios_base::in};
-        SpBuf spBuf(std::move(rhsSpBuf));
-        assert(spBuf.span().data() == nullptr);
-        assert(spBuf.span().empty());
-        assert(spBuf.span().size() == 0);
-      }
-      // Mode: `ios_base::out`
-      {
-        SpBuf rhsSpBuf{std::ios_base::out};
-        SpBuf spBuf(std::move(rhsSpBuf));
-        assert(spBuf.span().data() == nullptr);
-        assert(spBuf.span().empty());
-        assert(spBuf.span().size() == 0);
-      }
-      // Mode: multiple
-      {
-        SpBuf rhsSpBuf{std::ios_base::out | std::ios_base::in};
-        SpBuf spBuf(std::move(rhsSpBuf));
-        assert(spBuf.span().data() == nullptr);
-        assert(spBuf.span().empty());
-        assert(spBuf.span().size() == 0);
-      }
-    }
-
-    // Non-empty `span`
-    {
-      CharT arr[4];
+    CharT arr[4];
+
+    // Mode: default
+    {
       std::span<CharT> sp{arr};
+      TestSpanBuf<CharT, TraitsT> rhsSpBuf(sp);
+      TestSpanBuf<CharT, TraitsT> spBuf(std::move(static_cast<SpBuf&>(rhsSpBuf)));
+      assert(rhsSpBuf.span().data() == arr);
+      assert(spBuf.span().data() == arr);
+      spBuf.check_postconditions(rhsSpBuf);
+    }
+    // Mode: `in`
+    {
+      std::span<CharT> sp{arr};
+      TestSpanBuf<CharT, TraitsT> rhsSpBuf(sp, std::ios_base::in);
+      TestSpanBuf<CharT, TraitsT> spBuf(std::move(static_cast<SpBuf&>(rhsSpBuf)));
+      assert(rhsSpBuf.span().data() == arr);
+      assert(spBuf.span().data() == arr);
+      spBuf.check_postconditions(rhsSpBuf);
+    }
+    // Mode: `out`
+    {
+      std::span<CharT> sp{arr};
+      TestSpanBuf<CharT, TraitsT> rhsSpBuf(sp, std::ios_base::out);
+      TestSpanBuf<CharT, TraitsT> spBuf(std::move(static_cast<SpBuf&>(rhsSpBuf)));
+      assert(rhsSpBuf.span().data() == arr);
+      assert(spBuf.span().data() == arr);
+      spBuf.check_postconditions(rhsSpBuf);
+    }
+    // Mode: multiple
+    {
+      std::span<CharT> sp{arr};
+      TestSpanBuf<CharT, TraitsT> rhsSpBuf(sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary);
+      TestSpanBuf<CharT, TraitsT> spBuf(std::move(static_cast<SpBuf&>(rhsSpBuf)));
+      assert(rhsSpBuf.span().data() == arr);
+      assert(spBuf.span().data() == arr);
+      spBuf.check_postconditions(rhsSpBuf);
+    }
+    // Mode: `ate`
+    {
+      std::span<CharT> sp{arr};
+      TestSpanBuf<CharT, TraitsT> rhsSpBuf(sp, std::ios_base::out | std::ios_base::ate);
+      TestSpanBuf<CharT, TraitsT> spBuf(std::move(static_cast<SpBuf&>(rhsSpBuf)));
+      assert(rhsSpBuf.span().data() == arr);
+      assert(spBuf.span().data() == arr);
+      spBuf.check_postconditions(rhsSpBuf);
+    }
+  }
+}
+
+template <typename CharT, typename TraitsT = std::char_traits<CharT>>
+void test() {
+  using SpBuf = std::basic_spanbuf<CharT, TraitsT>;
+
+  // Empty `span`
+  {
+    // Mode: default (`in` | `out`)
+    {
+      SpBuf rhsSpBuf;
+      assert(rhsSpBuf.span().data() == nullptr);
+      // Mode `out` counts read characters
+      assert(rhsSpBuf.span().empty());
+      assert(rhsSpBuf.span().size() == 0);
+
+      SpBuf spBuf(std::move(rhsSpBuf));
+      assert(spBuf.span().data() == nullptr);
+      // Mode `out` counts read characters
+      assert(spBuf.span().empty());
+      assert(spBuf.span().size() == 0);
 
-      // Mode: default
-      {
-        SpBuf rhsSpBuf{sp};
-        SpBuf spBuf(std::move(rhsSpBuf));
-        assert(spBuf.span().data() == arr);
-        assert(spBuf.span().empty());
-        assert(spBuf.span().size() == 0);
-      }
-      // Mode: `ios_base::in`
-      {
-        SpBuf rhsSpBuf{sp, std::ios_base::in};
-        SpBuf spBuf(std::move(rhsSpBuf));
-        assert(spBuf.span().data() == arr);
-        assert(!spBuf.span().empty());
-        assert(spBuf.span().size() == 4);
-      }
-      // Mode `ios_base::out`
-      {
-        SpBuf rhsSpBuf{sp, std::ios_base::out};
-        SpBuf spBuf(std::move(rhsSpBuf));
-        assert(spBuf.span().data() == arr);
-        assert(spBuf.span().empty());
-        assert(spBuf.span().size() == 0);
-      }
-      // Mode: multiple
-      {
-        SpBuf rhsSpBuf{sp, std::ios_base::out | std::ios_base::in | std::ios_base::binary};
-        SpBuf spBuf(std::move(rhsSpBuf));
-        assert(spBuf.span().data() == arr);
-        assert(spBuf.span().empty());
-        assert(spBuf.span().size() == 0);
-      }
+      // After move
+      assert(rhsSpBuf.span().data() == nullptr);
+      assert(rhsSpBuf.span().empty());
+      assert(rhsSpBuf.span().size() == 0);
+    }
+    // Mode: `in`
+    {
+      SpBuf rhsSpBuf{std::ios_base::in};
+      assert(rhsSpBuf.span().data() == nullptr);
+      // Mode `out` counts read characters
+      assert(rhsSpBuf.span().empty());
+      assert(rhsSpBuf.span().size() == 0);
+
+      SpBuf spBuf(std::move(rhsSpBuf));
+      assert(spBuf.span().data() == nullptr);
+      assert(spBuf.span().empty());
+      assert(spBuf.span().size() == 0);
+
+      // After move
+      assert(rhsSpBuf.span().data() == nullptr);
+      assert(rhsSpBuf.span().empty());
+      assert(rhsSpBuf.span().size() == 0);
+    }
+    // Mode: `out`
+    {
+      SpBuf rhsSpBuf{std::ios_base::out};
+      assert(rhsSpBuf.span().data() == nullptr);
+      // Mode `out` counts read characters
+      assert(rhsSpBuf.span().empty());
+      assert(rhsSpBuf.span().size() == 0);
+
+      SpBuf spBuf(std::move(rhsSpBuf));
+      assert(spBuf.span().data() == nullptr);
+      // Mode `out` counts read characters
+      assert(spBuf.span().empty());
+      assert(spBuf.span().size() == 0);
+
+      // After move
+      assert(rhsSpBuf.span().data() == nullptr);
+      // Mode `out` counts read characters
+      assert(rhsSpBuf.span().empty());
+      assert(rhsSpBuf.span().size() == 0);
+    }
+    // Mode: multiple
+    {
+      SpBuf rhsSpBuf{std::ios_base::out | std::ios_base::in | std::ios_base::binary};
+      assert(rhsSpBuf.span().data() == nullptr);
+      // Mode `out` counts read characters
+      assert(rhsSpBuf.span().empty());
+      assert(rhsSpBuf.span().size() == 0);
+
+      SpBuf spBuf(std::move(rhsSpBuf));
+      assert(spBuf.span().data() == nullptr);
+      // Mode `out` counts read characters
+      assert(spBuf.span().empty());
+      assert(spBuf.span().size() == 0);
+
+      // After move
+      assert(rhsSpBuf.span().data() == nullptr);
+      assert(rhsSpBuf.span().empty());
+      assert(rhsSpBuf.span().size() == 0);
+    }
+    // Mode: `ate`
+    {
+      SpBuf rhsSpBuf{std::ios_base::ate};
+      SpBuf spBuf(std::move(rhsSpBuf));
+      assert(spBuf.span().data() == nullptr);
+      assert(spBuf.span().empty());
+      assert(spBuf.span().size() == 0);
+
+      // After move
+      assert(rhsSpBuf.span().data() == nullptr);
+      assert(rhsSpBuf.span().empty());
+      assert(rhsSpBuf.span().size() == 0);
     }
   }
 
-  // Check post-conditions
+  // Non-empty `span`
   {
-    // Empty `span`
-    {
-      // Mode: default
-      {
-        std::span<CharT> sp;
-        TestSpanBuf<CharT, TraitsT> rhsSpBuf(sp);
-        TestSpanBuf<CharT, TraitsT> spBuf(std::move(static_cast<SpBuf&>(rhsSpBuf)));
-        assert(rhsSpBuf.span().empty());
-        assert(spBuf.span().data() == nullptr);
-        spBuf.check_postconditions(rhsSpBuf);
-      }
-      // Mode: `ios_base::in`
-      {
-        std::span<CharT> sp;
-        TestSpanBuf<CharT, TraitsT> rhsSpBuf(sp, std::ios_base::in);
-        TestSpanBuf<CharT, TraitsT> spBuf(std::move(static_cast<SpBuf&>(rhsSpBuf)));
-        assert(rhsSpBuf.span().empty());
-        assert(spBuf.span().data() == nullptr);
-        spBuf.check_postconditions(rhsSpBuf);
-      }
-      // Mode: `ios_base::out`
-      {
-        std::span<CharT> sp;
-        TestSpanBuf<CharT, TraitsT> rhsSpBuf(sp, std::ios_base::out);
-        TestSpanBuf<CharT, TraitsT> spBuf(std::move(static_cast<SpBuf&>(rhsSpBuf)));
-        assert(rhsSpBuf.span().empty());
-        assert(spBuf.span().data() == nullptr);
-        spBuf.check_postconditions(rhsSpBuf);
-      }
-      // Mode: multiple
-      {
-        std::span<CharT> sp;
-        TestSpanBuf<CharT, TraitsT> rhsSpBuf(sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary);
-        TestSpanBuf<CharT, TraitsT> spBuf(std::move(static_cast<SpBuf&>(rhsSpBuf)));
-        assert(rhsSpBuf.span().empty());
-        assert(spBuf.span().data() == nullptr);
-        spBuf.check_postconditions(rhsSpBuf);
-      }
-    }
-
-    // Non-empty `span`
-    {
-      CharT arr[4];
-
-      // Mode: default
-      {
-        std::span<CharT> sp{arr};
-        TestSpanBuf<CharT, TraitsT> rhsSpBuf(sp);
-        TestSpanBuf<CharT, TraitsT> spBuf(std::move(static_cast<SpBuf&>(rhsSpBuf)));
-        assert(rhsSpBuf.span().empty());
-        assert(spBuf.span().data() == arr);
-        spBuf.check_postconditions(rhsSpBuf);
-      }
-      // Mode: `ios_base::in`
-      {
-        std::span<CharT> sp{arr};
-        TestSpanBuf<CharT, TraitsT> rhsSpBuf(sp, std::ios_base::in);
-        TestSpanBuf<CharT, TraitsT> spBuf(std::move(static_cast<SpBuf&>(rhsSpBuf)));
-        assert(!rhsSpBuf.span().empty());
-        assert(spBuf.span().data() == arr);
-        spBuf.check_postconditions(rhsSpBuf);
-      }
-      // Mode: `ios_base::out`
-      {
-        std::span<CharT> sp{arr};
-        TestSpanBuf<CharT, TraitsT> rhsSpBuf(sp, std::ios_base::out);
-        TestSpanBuf<CharT, TraitsT> spBuf(std::move(static_cast<SpBuf&>(rhsSpBuf)));
-        assert(rhsSpBuf.span().empty());
-        assert(spBuf.span().data() == arr);
-        spBuf.check_postconditions(rhsSpBuf);
-      }
-      // Mode: multiple
-      {
-        std::span<CharT> sp{arr};
-        TestSpanBuf<CharT, TraitsT> rhsSpBuf(sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary);
-        TestSpanBuf<CharT, TraitsT> spBuf(std::move(static_cast<SpBuf&>(rhsSpBuf)));
-        assert(rhsSpBuf.span().empty());
-        assert(spBuf.span().data() == arr);
-        spBuf.check_postconditions(rhsSpBuf);
-      }
+    CharT arr[4];
+    std::span<CharT> sp{arr};
+
+    // Mode: default (`in` | `out`)
+    {
+      SpBuf rhsSpBuf{sp};
+      assert(rhsSpBuf.span().data() == arr);
+      // Mode `out` counts read characters
+      assert(rhsSpBuf.span().empty());
+      assert(rhsSpBuf.span().size() == 0);
+
+      SpBuf spBuf(std::move(rhsSpBuf));
+      assert(spBuf.span().data() == arr);
+      // Mode `out` counts read characters
+      assert(spBuf.span().empty());
+      assert(spBuf.span().size() == 0);
+
+      // After move
+      assert(rhsSpBuf.span().data() == arr);
+      assert(rhsSpBuf.span().empty());
+      assert(rhsSpBuf.span().size() == 0);
+    }
+    // Mode: `in`
+    {
+      SpBuf rhsSpBuf{sp, std::ios_base::in};
+      assert(rhsSpBuf.span().data() == arr);
+      assert(!rhsSpBuf.span().empty());
+      assert(rhsSpBuf.span().size() == 4);
+
+      SpBuf spBuf(std::move(rhsSpBuf));
+      assert(spBuf.span().data() == arr);
+      assert(!spBuf.span().empty());
+      assert(spBuf.span().size() == 4);
+    }
+    // Mode `out`
+    {
+      SpBuf rhsSpBuf{sp, std::ios_base::out};
+      assert(rhsSpBuf.span().data() == arr);
+      // Mode `out` counts read characters
+      assert(rhsSpBuf.span().empty());
+      assert(rhsSpBuf.span().size() == 0);
+
+      SpBuf spBuf(std::move(rhsSpBuf));
+      assert(spBuf.span().data() == arr);
+      // Mode `out` counts read characters
+      assert(spBuf.span().empty());
+      assert(spBuf.span().size() == 0);
+
+      // After move
+      assert(rhsSpBuf.span().data() == arr);
+      assert(rhsSpBuf.span().empty());
+      assert(rhsSpBuf.span().size() == 0);
+    }
+    // Mode: multiple
+    {
+      SpBuf rhsSpBuf{sp, std::ios_base::out | std::ios_base::in | std::ios_base::binary};
+      assert(rhsSpBuf.span().data() == arr);
+      // Mode `out` counts read characters
+      assert(rhsSpBuf.span().empty());
+      assert(rhsSpBuf.span().size() == 0);
+
+      SpBuf spBuf(std::move(rhsSpBuf));
+      assert(spBuf.span().data() == arr);
+      // Mode `out` counts read characters
+      assert(spBuf.span().empty());
+      assert(spBuf.span().size() == 0);
+
+      // After move
+      assert(rhsSpBuf.span().data() == arr);
+      assert(rhsSpBuf.span().empty());
+      assert(rhsSpBuf.span().size() == 0);
+    }
+    // Mode: `ate`
+    {
+      SpBuf rhsSpBuf{sp, std::ios_base::ate};
+      assert(rhsSpBuf.span().data() == arr);
+      assert(!rhsSpBuf.span().empty());
+      assert(rhsSpBuf.span().size() == 4);
+
+      SpBuf spBuf(std::move(rhsSpBuf));
+      assert(spBuf.span().data() == arr);
+      assert(!spBuf.span().empty());
+      assert(spBuf.span().size() == 4);
+
+      // After move
+      assert(rhsSpBuf.span().data() == arr);
+      assert(!rhsSpBuf.span().empty());
+      assert(rhsSpBuf.span().size() == 4);
     }
   }
 }
 
 int main(int, char**) {
+#ifndef TEST_HAS_NO_NASTY_STRING
+  test_postconditions<nasty_char, nasty_char_traits>();
+#endif
+  test_postconditions<char>();
+  test_postconditions<char, constexpr_char_traits<char>>();
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  test_postconditions<wchar_t>();
+  test_postconditions<wchar_t, constexpr_char_traits<wchar_t>>();
+#endif
+#ifndef TEST_HAS_NO_NASTY_STRING
+  test<nasty_char, nasty_char_traits>();
+#endif
   test<char>();
   test<char, constexpr_char_traits<char>>();
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/span.mode.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/span.mode.pass.cpp
index fbfc2f144ab6d..dc6b6e9e5a83b 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/span.mode.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/span.mode.pass.cpp
@@ -50,20 +50,26 @@ template <typename CharT, typename TraitsT = std::char_traits<CharT>>
 void test() {
   using SpBuf = std::basic_spanbuf<CharT, TraitsT>;
 
-  static_assert(std::default_initializable<SpBuf>);
-
   // Empty `span`
   {
     std::span<CharT> sp{};
 
-    // Mode: default
+    // Mode: default (`in` | `out`)
     {
       SpBuf spBuf(sp);
       assert(spBuf.span().data() == nullptr);
+      // Mode `out` counts read characters
       assert(spBuf.span().empty());
       assert(spBuf.span().size() == 0);
     }
-    // Mode: `ios_base::in`
+    {
+      SpBuf spBuf(std::as_const(sp));
+      assert(spBuf.span().data() == nullptr);
+      // Mode `out` counts read characters
+      assert(spBuf.span().empty());
+      assert(spBuf.span().size() == 0);
+    }
+    // Mode: `in`
     {
       SpBuf spBuf(sp, std::ios_base::in);
       assert(spBuf.span().data() == nullptr);
@@ -76,16 +82,18 @@ void test() {
       assert(spBuf.span().empty());
       assert(spBuf.span().size() == 0);
     }
-    // Mode: `ios_base::out`
+    // Mode: `out`
     {
       SpBuf spBuf(sp, std::ios_base::out);
       assert(spBuf.span().data() == nullptr);
+      // Mode `out` counts read characters
       assert(spBuf.span().empty());
       assert(spBuf.span().size() == 0);
     }
     {
       SpBuf spBuf(std::as_const(sp), std::ios_base::out);
       assert(spBuf.span().data() == nullptr);
+      // Mode `out` counts read characters
       assert(spBuf.span().empty());
       assert(spBuf.span().size() == 0);
     }
@@ -93,12 +101,27 @@ void test() {
     {
       SpBuf spBuf(sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary);
       assert(spBuf.span().data() == nullptr);
+      // Mode `out` counts read characters
       assert(spBuf.span().empty());
       assert(spBuf.span().size() == 0);
     }
     {
       SpBuf spBuf(std::as_const(sp), std::ios_base::in | std::ios_base::out | std::ios_base::binary);
       assert(spBuf.span().data() == nullptr);
+      // Mode `out` counts read characters
+      assert(spBuf.span().empty());
+      assert(spBuf.span().size() == 0);
+    }
+    // Mode: `ate`
+    {
+      SpBuf spBuf(sp, std::ios_base::out | std::ios_base::ate);
+      assert(spBuf.span().data() == nullptr);
+      assert(spBuf.span().empty());
+      assert(spBuf.span().size() == 0);
+    }
+    {
+      SpBuf spBuf(std::as_const(sp), std::ios_base::out | std::ios_base::ate);
+      assert(spBuf.span().data() == nullptr);
       assert(spBuf.span().empty());
       assert(spBuf.span().size() == 0);
     }
@@ -109,14 +132,22 @@ void test() {
     CharT arr[4];
     std::span<CharT> sp{arr};
 
-    // Mode: default
+    // Mode: default (`in` | `out`)
     {
       SpBuf spBuf(sp);
       assert(spBuf.span().data() == arr);
+      // Mode `out` counts read characters
       assert(spBuf.span().empty());
       assert(spBuf.span().size() == 0);
     }
-    // Mode: `ios_base::in`
+    {
+      SpBuf spBuf(std::as_const(sp));
+      assert(spBuf.span().data() == arr);
+      // Mode `out` counts read characters
+      assert(spBuf.span().empty());
+      assert(spBuf.span().size() == 0);
+    }
+    // Mode: `in`
     {
       SpBuf spBuf(sp, std::ios_base::in);
       assert(spBuf.span().data() == arr);
@@ -129,16 +160,18 @@ void test() {
       assert(!spBuf.span().empty());
       assert(spBuf.span().size() == 4);
     }
-    // Mode `ios_base::out`
+    // Mode `out`
     {
       SpBuf spBuf(sp, std::ios_base::out);
       assert(spBuf.span().data() == arr);
+      // Mode `out` counts read characters
       assert(spBuf.span().empty());
       assert(spBuf.span().size() == 0);
     }
     {
       SpBuf spBuf(std::as_const(sp), std::ios_base::out);
       assert(spBuf.span().data() == arr);
+      // Mode `out` counts read characters
       assert(spBuf.span().empty());
       assert(spBuf.span().size() == 0);
     }
@@ -146,15 +179,30 @@ void test() {
     {
       SpBuf spBuf(sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary);
       assert(spBuf.span().data() == arr);
+      // Mode `out` counts read characters
       assert(spBuf.span().empty());
       assert(spBuf.span().size() == 0);
     }
     {
       SpBuf spBuf(std::as_const(sp), std::ios_base::in | std::ios_base::out | std::ios_base::binary);
       assert(spBuf.span().data() == arr);
+      // Mode `out` counts read characters
       assert(spBuf.span().empty());
       assert(spBuf.span().size() == 0);
     }
+    // Mode: `ate`
+    {
+      SpBuf spBuf(sp, std::ios_base::out | std::ios_base::ate);
+      assert(spBuf.span().data() == arr);
+      assert(!spBuf.span().empty());
+      assert(spBuf.span().size() == 4);
+    }
+    {
+      SpBuf spBuf(std::as_const(sp), std::ios_base::out | std::ios_base::ate);
+      assert(spBuf.span().data() == arr);
+      assert(!spBuf.span().empty());
+      assert(spBuf.span().size() == 4);
+    }
   }
 }
 
@@ -164,6 +212,9 @@ int main(int, char**) {
 #endif
   test_sfinae<char>();
   test_sfinae<char, constexpr_char_traits<char>>();
+#ifndef TEST_HAS_NO_NASTY_STRING
+  test<nasty_char, nasty_char_traits>();
+#endif
   test<char>();
   test<char, constexpr_char_traits<char>>();
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.members/span.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.members/span.pass.cpp
index 635b8d2a03073..a13fbd10d051c 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.members/span.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.members/span.pass.cpp
@@ -68,6 +68,13 @@ void test() {
     assert(spBuf.span().empty());
     assert(spBuf.span().size() == 0);
   }
+  // Mode: `ate`
+  {
+    SpBuf spBuf(sp, std::ios_base::out | std::ios_base::ate);
+    assert(spBuf.span().data() == arr);
+    assert(!spBuf.span().empty());
+    assert(spBuf.span().size() == 4);
+  }
 }
 
 int main(int, char**) {

>From b82b21068dc2b1968c84c450983b373f05876969 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Mon, 11 Mar 2024 08:47:58 +0200
Subject: [PATCH 32/56] Tests: Added `setbuf.pass`

---
 ...ekoff.off_type.seek_dir.open_mode.pass.cpp |  5 +-
 .../seekoff.pos_type.open_mode.pass.cpp       |  5 +-
 .../spanbuf/spanbuf.virtuals/setbuf.pass.cpp  | 76 ++++++++++++++++---
 3 files changed, 75 insertions(+), 11 deletions(-)

diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekoff.off_type.seek_dir.open_mode.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekoff.off_type.seek_dir.open_mode.pass.cpp
index 6b4580bedb89c..2378a23dc8aef 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekoff.off_type.seek_dir.open_mode.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekoff.off_type.seek_dir.open_mode.pass.cpp
@@ -27,7 +27,7 @@
 #include <spanstream>
 
 #include "constexpr_char_traits.h"
-#include "test_convertible.h"
+#include "nasty_string.h"
 #include "test_macros.h"
 
 template <typename CharT, typename TraitsT = std::char_traits<CharT>>
@@ -51,6 +51,9 @@ void test() {
 }
 
 int main(int, char**) {
+#ifndef TEST_HAS_NO_NASTY_STRING
+  test<nasty_char, nasty_char_traits>();
+#endif
   test<char>();
   test<char, constexpr_char_traits<char>>();
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekoff.pos_type.open_mode.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekoff.pos_type.open_mode.pass.cpp
index 0980143e67407..2558e2999dc09 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekoff.pos_type.open_mode.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekoff.pos_type.open_mode.pass.cpp
@@ -25,7 +25,7 @@
 #include <spanstream>
 
 #include "constexpr_char_traits.h"
-#include "test_convertible.h"
+#include "nasty_string.h"
 #include "test_macros.h"
 
 template <typename CharT, typename TraitsT = std::char_traits<CharT>>
@@ -47,6 +47,9 @@ void test() {
 }
 
 int main(int, char**) {
+#ifndef TEST_HAS_NO_NASTY_STRING
+  test<nasty_char, nasty_char_traits>();
+#endif
   test<char>();
   test<char, constexpr_char_traits<char>>();
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/setbuf.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/setbuf.pass.cpp
index 193185da8d9ca..2fd0e791e13e6 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/setbuf.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/setbuf.pass.cpp
@@ -23,7 +23,7 @@
 #include <spanstream>
 
 #include "constexpr_char_traits.h"
-#include "test_convertible.h"
+#include "nasty_string.h"
 #include "test_macros.h"
 
 template <typename CharT, typename TraitsT = std::char_traits<CharT>>
@@ -33,20 +33,78 @@ void test() {
   CharT arr[4];
   std::span<CharT> sp{arr};
 
-  // TODO:
+  // Mode: default (`in` | `out`)
+  {
+    SpBuf spBuf{sp};
+    assert(spBuf.span().data() == arr);
+    // Mode `out` counts read characters
+    assert(spBuf.span().empty());
+    assert(spBuf.span().size() == 0);
 
-  // Mode: default
+    spBuf.pubsetbuf(nullptr, 0);
+    assert(spBuf.span().data() == nullptr);
+    // Mode `out` counts read characters
+    assert(spBuf.span().empty());
+    assert(spBuf.span().size() == 0);
+  }
+  // Mode: `ios_base::in`
   {
-    SpBuf rhsSpBuf{sp};
-    SpBuf spBuf(std::span<CharT>{});
-    spBuf.swap(rhsSpBuf);
-    // assert(spBuf.span().data() == arr);
-    // assert(!spBuf.span().empty());
-    // assert(spBuf.span().size() == 4);
+    SpBuf spBuf{sp, std::ios_base::in};
+    assert(spBuf.span().data() == arr);
+    assert(!spBuf.span().empty());
+    assert(spBuf.span().size() == 4);
+
+    spBuf.pubsetbuf(nullptr, 0);
+    assert(spBuf.span().data() == nullptr);
+    assert(spBuf.span().empty());
+    assert(spBuf.span().size() == 0);
+  }
+  // Mode `ios_base::out`
+  {
+    SpBuf spBuf{sp, std::ios_base::out};
+    assert(spBuf.span().data() == arr);
+    // Mode `out` counts read characters
+    assert(spBuf.span().empty());
+    assert(spBuf.span().size() == 0);
+
+    spBuf.pubsetbuf(nullptr, 0);
+    assert(spBuf.span().data() == nullptr);
+    // Mode `out` counts read characters
+    assert(spBuf.span().empty());
+    assert(spBuf.span().size() == 0);
+  }
+  // Mode: multiple
+  {
+    SpBuf spBuf{sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary};
+    assert(spBuf.span().data() == arr);
+    // Mode `out` counts read characters
+    assert(spBuf.span().empty());
+    assert(spBuf.span().size() == 0);
+
+    spBuf.pubsetbuf(nullptr, 0);
+    assert(spBuf.span().data() == nullptr);
+    // Mode `out` counts read characters
+    assert(spBuf.span().empty());
+    assert(spBuf.span().size() == 0);
+  }
+  // Mode: `ios_base::ate`
+  {
+    SpBuf spBuf{sp, std::ios_base::out | std::ios_base::ate};
+    assert(spBuf.span().data() == arr);
+    assert(!spBuf.span().empty());
+    assert(spBuf.span().size() == 4);
+
+    spBuf.pubsetbuf(nullptr, 0);
+    assert(spBuf.span().data() == nullptr);
+    assert(spBuf.span().empty());
+    assert(spBuf.span().size() == 0);
   }
 }
 
 int main(int, char**) {
+#ifndef TEST_HAS_NO_NASTY_STRING
+  test<nasty_char, nasty_char_traits>();
+#endif
   test<char>();
   test<char, constexpr_char_traits<char>>();
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS

>From 28fe1870bb5726bbe30506d39ce976312a4fd18e Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Mon, 11 Mar 2024 12:15:48 +0200
Subject: [PATCH 33/56] Tests: WIP `seekoff`

---
 .../spanbuf/spanbuf.assign/move.pass.cpp      |   4 +-
 ...ekoff.off_type.seek_dir.open_mode.pass.cpp | 200 ++++++++++++++++--
 2 files changed, 186 insertions(+), 18 deletions(-)

diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/move.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/move.pass.cpp
index c1749a1068ea9..07306326b99e4 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/move.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/move.pass.cpp
@@ -52,7 +52,7 @@ void test_postconditions() {
 
   // Empty `span`
   {
-    // Mode: default
+    // Mode: default (`in` | `out`)
     {
       std::span<CharT> sp;
       TestSpanBuf<CharT, TraitsT> rhsSpBuf(sp);
@@ -103,7 +103,7 @@ void test_postconditions() {
   {
     CharT arr[4];
 
-    // Mode: default
+    // Mode: default (`in` | `out`)
     {
       std::span<CharT> sp{arr};
       TestSpanBuf<CharT, TraitsT> rhsSpBuf(sp);
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekoff.off_type.seek_dir.open_mode.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekoff.off_type.seek_dir.open_mode.pass.cpp
index 2378a23dc8aef..b7e44293a5d69 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekoff.off_type.seek_dir.open_mode.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekoff.off_type.seek_dir.open_mode.pass.cpp
@@ -18,47 +18,215 @@
 //
 //     pos_type seekoff(off_type off, ios_base::seekdir way,
 //                      ios_base::openmode which = ios_base::in | ios_base::out) override;
-//     pos_type seekpos(pos_type sp,
-//                      ios_base::openmode which = ios_base::in | ios_base::out) override;
 
+#include <algorithm>
 #include <cassert>
 #include <concepts>
 #include <span>
 #include <spanstream>
+// #include <string>
 
 #include "constexpr_char_traits.h"
 #include "nasty_string.h"
 #include "test_macros.h"
 
+// #include "../../helper_macros.h"
+#include <print>
+
 template <typename CharT, typename TraitsT = std::char_traits<CharT>>
 void test() {
-  using SpBuf = std::basic_spanbuf<CharT, TraitsT>;
+  using SpBuf       = std::basic_spanbuf<CharT, TraitsT>;
+  using SpBuffError = typename SpBuf::pos_type;
 
-  CharT arr[4];
-  std::span<CharT> sp{arr};
+  const SpBuffError error{-1};
 
-  // TODO:
+  // Empty `span`
+  {
+    std::span<CharT> sp;
+
+    // Mode: default (`in` | `out`)
+    {
+      SpBuf spBuf{sp};
+      assert(spBuf.pubseekoff(3, std::ios_base::beg, std::ios_base::in) == -1);
+      assert(spBuf.pubseekoff(3, std::ios_base::cur, std::ios_base::in) == -1);
+      assert(spBuf.pubseekoff(-3, std::ios_base::end, std::ios_base::in) == -1);
+      assert(spBuf.pubseekoff(3, std::ios_base::beg, std::ios_base::in | std::ios_base::out) == -1);
+      assert(spBuf.pubseekoff(3, std::ios_base::cur, std::ios_base::in | std::ios_base::out) == -1);
+      assert(spBuf.pubseekoff(-3, std::ios_base::end, std::ios_base::in | std::ios_base::out) == -1);
+      assert(spBuf.pubseekoff(0, std::ios_base::beg, std::ios_base::out) == 0);
+      assert(spBuf.pubseekoff(0, std::ios_base::cur, std::ios_base::out) == 0);
+      assert(spBuf.pubseekoff(0, std::ios_base::end, std::ios_base::out) == 0);
+    }
+    // Mode: `in`
+    {
+      SpBuf spBuf{sp, std::ios_base::in};
+      assert(spBuf.pubseekoff(3, std::ios_base::beg, std::ios_base::out) == -1);
+      assert(spBuf.pubseekoff(3, std::ios_base::cur, std::ios_base::out) == -1);
+      assert(spBuf.pubseekoff(-3, std::ios_base::end, std::ios_base::out) == -1);
+      assert(spBuf.pubseekoff(3, std::ios_base::beg, std::ios_base::in | std::ios_base::out) == -1);
+      assert(spBuf.pubseekoff(3, std::ios_base::cur, std::ios_base::in | std::ios_base::out) == -1);
+      assert(spBuf.pubseekoff(-3, std::ios_base::end, std::ios_base::in | std::ios_base::out) == -1);
+      assert(spBuf.pubseekoff(0, std::ios_base::beg, std::ios_base::in) == 0);
+      assert(spBuf.pubseekoff(0, std::ios_base::cur, std::ios_base::in) == 0);
+      assert(spBuf.pubseekoff(0, std::ios_base::end, std::ios_base::in) == 0);
+    }
+    // Mode: `out`
+    {
+      SpBuf spBuf{sp, std::ios_base::out};
+      assert(spBuf.pubseekoff(3, std::ios_base::beg, std::ios_base::in) == -1);
+      assert(spBuf.pubseekoff(3, std::ios_base::cur, std::ios_base::in) == -1);
+      assert(spBuf.pubseekoff(-3, std::ios_base::end, std::ios_base::in) == -1);
+      assert(spBuf.pubseekoff(3, std::ios_base::beg, std::ios_base::in | std::ios_base::out) == -1);
+      assert(spBuf.pubseekoff(3, std::ios_base::cur, std::ios_base::in | std::ios_base::out) == -1);
+      assert(spBuf.pubseekoff(-3, std::ios_base::end, std::ios_base::in | std::ios_base::out) == -1);
+      assert(spBuf.pubseekoff(0, std::ios_base::beg, std::ios_base::out) == 0);
+      assert(spBuf.pubseekoff(0, std::ios_base::cur, std::ios_base::out) == 0);
+      assert(spBuf.pubseekoff(0, std::ios_base::end, std::ios_base::out) == 0);
+    }
+    // Mode: `multiple`
+    {
+      SpBuf spBuf{sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary};
+      assert(spBuf.pubseekoff(3, std::ios_base::beg, std::ios_base::in) == -1);
+      assert(spBuf.pubseekoff(3, std::ios_base::cur, std::ios_base::in) == -1);
+      assert(spBuf.pubseekoff(-3, std::ios_base::end, std::ios_base::in) == -1);
+      assert(spBuf.pubseekoff(3, std::ios_base::beg, std::ios_base::in | std::ios_base::out) == -1);
+      assert(spBuf.pubseekoff(3, std::ios_base::cur, std::ios_base::in | std::ios_base::out) == -1);
+      assert(spBuf.pubseekoff(-3, std::ios_base::end, std::ios_base::in | std::ios_base::out) == -1);
+      assert(spBuf.pubseekoff(0, std::ios_base::beg, std::ios_base::out) == 0);
+      assert(spBuf.pubseekoff(0, std::ios_base::cur, std::ios_base::out) == 0);
+      assert(spBuf.pubseekoff(0, std::ios_base::end, std::ios_base::out) == 0);
+    }
+    // Mode: `ate`
+    {
+      SpBuf spBuf{sp, std::ios_base::out | std::ios_base::ate};
+      assert(spBuf.pubseekoff(3, std::ios_base::beg, std::ios_base::out) == -1);
+      assert(spBuf.pubseekoff(3, std::ios_base::cur, std::ios_base::out) == -1);
+      assert(spBuf.pubseekoff(-3, std::ios_base::end, std::ios_base::out) == -1);
+      assert(spBuf.pubseekoff(3, std::ios_base::beg, std::ios_base::in | std::ios_base::out) == -1);
+      assert(spBuf.pubseekoff(3, std::ios_base::cur, std::ios_base::in | std::ios_base::out) == -1);
+      assert(spBuf.pubseekoff(-3, std::ios_base::end, std::ios_base::in | std::ios_base::out) == -1);
+      assert(spBuf.pubseekoff(0, std::ios_base::beg, std::ios_base::in) == 0);
+      assert(spBuf.pubseekoff(0, std::ios_base::cur, std::ios_base::in) == 0);
+      assert(spBuf.pubseekoff(0, std::ios_base::end, std::ios_base::in) == 0);
+    }
+  }
 
-  // Mode: default
+  // Non-empty `span`
   {
-    SpBuf rhsSpBuf{sp};
-    SpBuf spBuf(std::span<CharT>{});
-    spBuf.swap(rhsSpBuf);
-    // assert(spBuf.span().data() == arr);
-    // assert(!spBuf.span().empty());
-    // assert(spBuf.span().size() == 4);
+    // const CharT* cStr = CS("0123456789");
+    // const std::basic_string_view<CharT, TraitsT> sv{SV("0123456789")};
+    // std::span sp{sv.begin(), sv.end()};
+
+    // std::print(stderr, "-=----- {}", sp);
+
+    // Initialize with ASCII codes: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
+    CharT arr[]{
+        CharT{48}, CharT{49}, CharT{50}, CharT{51}, CharT{52}, CharT{53}, CharT{54}, CharT{55}, CharT{56}, CharT{57}};
+    std::span sp{arr};
+    // std::print(stderr, "-=----- {}", sp);
+    // assert(false);
+
+    // Mode: default (`in` | `out`)
+    {
+      // TestSpanBuf<CharT, TraitsT> rhsSpBuf(sp);
+      // TestSpanBuf<CharT, TraitsT> spBuf = std::move(static_cast<SpBuf&>(rhsSpBuf));
+      // assert(rhsSpBuf.span().data() == arr);
+      // assert(spBuf.span().data() == arr);
+      // spBuf.check_postconditions(rhsSpBuf);
+    }
+    // Mode: `in`
+    {
+      SpBuf spBuf(sp, std::ios_base::in);
+      assert(spBuf.pubseekoff(3, std::ios_base::beg, std::ios_base::out) == -1);
+      assert(spBuf.pubseekoff(3, std::ios_base::cur, std::ios_base::out) == -1);
+      assert(spBuf.pubseekoff(-3, std::ios_base::end, std::ios_base::out) == -1);
+      assert(spBuf.pubseekoff(3, std::ios_base::beg, std::ios_base::in | std::ios_base::out) == -1);
+      assert(spBuf.pubseekoff(3, std::ios_base::cur, std::ios_base::in | std::ios_base::out) == -1);
+      assert(spBuf.pubseekoff(-3, std::ios_base::end, std::ios_base::in | std::ios_base::out) == -1);
+      assert(spBuf.pubseekoff(3, std::ios_base::beg, std::ios_base::in) == 3);
+      // assert(spBuf.sgetc() == '3');
+      assert(spBuf.sgetc() == 51);
+      // std::print(stderr, CS("-=-=======> {}"), spBuf.sgetc());
+      std::println(stderr, "-------- {}", spBuf.sgetc());
+      assert(spBuf.pubseekoff(3, std::ios_base::cur, std::ios_base::in) == 6);
+      assert(spBuf.sgetc() == 54);
+      // std::print(stderr, CS("-=-=======> {}"), spBuf.sgetc());
+      std::println(stderr, "-------- {}", spBuf.sgetc());
+      assert(spBuf.pubseekoff(-3, std::ios_base::end, std::ios_base::in) == 7);
+      assert(spBuf.sgetc() == 55);
+      // std::print(stderr, CS("-=-=======> {}"), spBuf.sgetc());
+      std::println(stderr, "-------- {}", spBuf.sgetc());
+      // assert(false);
+    }
+    // Mode: `out`
+    {
+      CharT resultArr[]{
+          CharT{48}, CharT{49}, CharT{50}, CharT{51}, CharT{52}, CharT{53}, CharT{54}, CharT{55}, CharT{56}, CharT{57}};
+
+      SpBuf spBuf(sp, std::ios_base::out);
+      std::println(stderr, "fasdfasdfasdfasdfasd 0 {}", spBuf.span());
+      assert(spBuf.pubseekoff(3, std::ios_base::beg, std::ios_base::in) == -1);
+      assert(spBuf.pubseekoff(3, std::ios_base::cur, std::ios_base::in) == -1);
+      assert(spBuf.pubseekoff(-3, std::ios_base::end, std::ios_base::in) == -1);
+      assert(spBuf.pubseekoff(3, std::ios_base::beg, std::ios_base::out | std::ios_base::in) == -1);
+      assert(spBuf.pubseekoff(3, std::ios_base::cur, std::ios_base::out | std::ios_base::in) == -1);
+      assert(spBuf.pubseekoff(-3, std::ios_base::end, std::ios_base::out | std::ios_base::in) == -1);
+      assert(spBuf.pubseekoff(3, std::ios_base::beg, std::ios_base::out) == 3);
+      assert(spBuf.sputc(CharT{90}) == 90);
+      // assert(spBuf.str() == "012a456789");
+      resultArr[3] = CharT{90};
+      // assert(spBuf.span() == std::span<CharT>{resultArr});
+      std::println(stderr, "fasdfasdfasdfasdfasd 1 {}", spBuf.span());
+      std::println(stderr, "fasdfasdfasdfasdfasd {}", spBuf.span().data());
+      std::println(stderr, "fasdfasdfasdfasdfasd {}", spBuf.span().size());
+      std::println(stderr, "fasdfasdfasdfasdfasd 2 {}", std::span<CharT>{resultArr});
+      // assert(std::ranges::equal(spBuf.span(), std::span<CharT>{resultArr}));
+      assert(spBuf.pubseekoff(3, std::ios_base::cur, std::ios_base::out) == 7);
+      assert(spBuf.sputc(CharT{77}) == 77);
+       std::println(stderr, "fasdfasdfasdfasdfasd 5 {}", spBuf.span());
+      // assert(spBuf.str() == "012a456b89");
+      resultArr[7] = CharT{77};
+      // assert(spBuf.span() == std::span<CharT>{resultArr});
+      // assert(std::ranges::equal(spBuf.span(), std::span<CharT>{resultArr}));
+      assert(spBuf.pubseekoff(-3, std::ios_base::end, std::ios_base::out) == 7);
+       std::println(stderr, "fasdfasdfasdfasdfasd 6 {}", spBuf.span());
+#if 0
+      assert(spBuf.sputc(CharT{84}) == 84);
+      // assert(spBuf.str() == "012a456c89");
+      resultArr[6] = CharT{84};
+      assert(spBuf.span() == std::span<CharT>{resultArr});
+#endif
+    }
+    // Mode: multiple
+    {
+      // std::span<CharT> sp{arr};
+      // TestSpanBuf<CharT, TraitsT> rhsSpBuf(sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary);
+      // TestSpanBuf<CharT, TraitsT> spBuf = std::move(static_cast<SpBuf&>(rhsSpBuf));
+      // assert(rhsSpBuf.span().data() == arr);
+      // assert(spBuf.span().data() == arr);
+      // spBuf.check_postconditions(rhsSpBuf);
+    }
+    // Mode: `ate`
+    {
+      // std::span<CharT> sp{arr};
+      // TestSpanBuf<CharT, TraitsT> rhsSpBuf(sp, std::ios_base::out | std::ios_base::ate);
+      // TestSpanBuf<CharT, TraitsT> spBuf = std::move(static_cast<SpBuf&>(rhsSpBuf));
+      // assert(rhsSpBuf.span().data() == arr);
+      // assert(spBuf.span().data() == arr);
+      // spBuf.check_postconditions(rhsSpBuf);
+    }
   }
 }
 
 int main(int, char**) {
 #ifndef TEST_HAS_NO_NASTY_STRING
-  test<nasty_char, nasty_char_traits>();
+  // test<nasty_char, nasty_char_traits>();
 #endif
   test<char>();
   test<char, constexpr_char_traits<char>>();
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
-  test<wchar_t>();
-  test<wchar_t, constexpr_char_traits<wchar_t>>();
+  // test<wchar_t>();
+  // test<wchar_t, constexpr_char_traits<wchar_t>>();
 #endif
 
   return 0;

>From c3e071a9255c33a04cb53c79224c6e2ed65de360 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Mon, 11 Mar 2024 15:13:37 +0200
Subject: [PATCH 34/56] Tests: WIP cleanup

---
 .../spanbuf/spanbuf.assign/move.pass.cpp      |  1 -
 .../spanbuf/spanbuf.assign/swap.pass.cpp      |  1 -
 .../spanbuf.assign/swap_nonmember.pass.cpp    |  1 -
 .../spanbuf/spanbuf.cons/move.pass.cpp        |  1 -
 .../spanbuf/spanbuf.cons/span.mode.pass.cpp   |  1 -
 .../spanbuf/spanbuf.members/span.pass.cpp     |  1 -
 .../spanbuf.members/span.span.pass.cpp        |  1 -
 ...ekoff.off_type.seek_dir.open_mode.pass.cpp | 32 ++++++-------------
 .../seekoff.pos_type.open_mode.pass.cpp       |  1 -
 .../spanbuf/spanbuf.virtuals/setbuf.pass.cpp  |  1 -
 10 files changed, 9 insertions(+), 32 deletions(-)

diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/move.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/move.pass.cpp
index 07306326b99e4..88179fece5908 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/move.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/move.pass.cpp
@@ -19,7 +19,6 @@
 //     basic_spanbuf& operator=(basic_spanbuf&& rhs);
 
 #include <cassert>
-#include <concepts>
 #include <span>
 #include <spanstream>
 
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/swap.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/swap.pass.cpp
index 6db44e92be58d..26b305333e42e 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/swap.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/swap.pass.cpp
@@ -18,7 +18,6 @@
 //     void swap(basic_spanbuf& rhs);
 
 #include <cassert>
-#include <concepts>
 #include <span>
 #include <spanstream>
 
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/swap_nonmember.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/swap_nonmember.pass.cpp
index 78c5015674019..681f157553326 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/swap_nonmember.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/swap_nonmember.pass.cpp
@@ -14,7 +14,6 @@
 //     void swap(basic_spanbuf<charT, traits>& x, basic_spanbuf<charT, traits>& y);
 
 #include <cassert>
-#include <concepts>
 #include <span>
 #include <spanstream>
 
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/move.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/move.pass.cpp
index 9252f64908de4..e9e483d290c55 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/move.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/move.pass.cpp
@@ -19,7 +19,6 @@
 //     basic_spanbuf(basic_spanbuf&& rhs);
 
 #include <cassert>
-#include <concepts>
 #include <span>
 #include <spanstream>
 
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/span.mode.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/span.mode.pass.cpp
index dc6b6e9e5a83b..9557b096f8f91 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/span.mode.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/span.mode.pass.cpp
@@ -20,7 +20,6 @@
 //                            ios_base::openmode which = ios_base::in | ios_base::out);
 
 #include <cassert>
-#include <concepts>
 #include <span>
 #include <spanstream>
 #include <utility>
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.members/span.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.members/span.pass.cpp
index a13fbd10d051c..d868676c18886 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.members/span.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.members/span.pass.cpp
@@ -18,7 +18,6 @@
 //     std::span<charT> span() const noexcept;
 
 #include <cassert>
-#include <concepts>
 #include <span>
 #include <spanstream>
 
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.members/span.span.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.members/span.span.pass.cpp
index 5495cdefbe7c6..e3c836d27e349 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.members/span.span.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.members/span.span.pass.cpp
@@ -19,7 +19,6 @@
 //     void span(std::span<charT> s) noexcept;
 
 #include <cassert>
-#include <concepts>
 #include <span>
 #include <spanstream>
 
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekoff.off_type.seek_dir.open_mode.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekoff.off_type.seek_dir.open_mode.pass.cpp
index b7e44293a5d69..2d378127e5fa4 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekoff.off_type.seek_dir.open_mode.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekoff.off_type.seek_dir.open_mode.pass.cpp
@@ -21,16 +21,13 @@
 
 #include <algorithm>
 #include <cassert>
-#include <concepts>
 #include <span>
 #include <spanstream>
-// #include <string>
 
 #include "constexpr_char_traits.h"
 #include "nasty_string.h"
 #include "test_macros.h"
 
-// #include "../../helper_macros.h"
 #include <print>
 
 template <typename CharT, typename TraitsT = std::char_traits<CharT>>
@@ -113,12 +110,6 @@ void test() {
 
   // Non-empty `span`
   {
-    // const CharT* cStr = CS("0123456789");
-    // const std::basic_string_view<CharT, TraitsT> sv{SV("0123456789")};
-    // std::span sp{sv.begin(), sv.end()};
-
-    // std::print(stderr, "-=----- {}", sp);
-
     // Initialize with ASCII codes: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
     CharT arr[]{
         CharT{48}, CharT{49}, CharT{50}, CharT{51}, CharT{52}, CharT{53}, CharT{54}, CharT{55}, CharT{56}, CharT{57}};
@@ -144,19 +135,11 @@ void test() {
       assert(spBuf.pubseekoff(3, std::ios_base::cur, std::ios_base::in | std::ios_base::out) == -1);
       assert(spBuf.pubseekoff(-3, std::ios_base::end, std::ios_base::in | std::ios_base::out) == -1);
       assert(spBuf.pubseekoff(3, std::ios_base::beg, std::ios_base::in) == 3);
-      // assert(spBuf.sgetc() == '3');
       assert(spBuf.sgetc() == 51);
-      // std::print(stderr, CS("-=-=======> {}"), spBuf.sgetc());
-      std::println(stderr, "-------- {}", spBuf.sgetc());
       assert(spBuf.pubseekoff(3, std::ios_base::cur, std::ios_base::in) == 6);
       assert(spBuf.sgetc() == 54);
-      // std::print(stderr, CS("-=-=======> {}"), spBuf.sgetc());
-      std::println(stderr, "-------- {}", spBuf.sgetc());
       assert(spBuf.pubseekoff(-3, std::ios_base::end, std::ios_base::in) == 7);
       assert(spBuf.sgetc() == 55);
-      // std::print(stderr, CS("-=-=======> {}"), spBuf.sgetc());
-      std::println(stderr, "-------- {}", spBuf.sgetc());
-      // assert(false);
     }
     // Mode: `out`
     {
@@ -164,7 +147,7 @@ void test() {
           CharT{48}, CharT{49}, CharT{50}, CharT{51}, CharT{52}, CharT{53}, CharT{54}, CharT{55}, CharT{56}, CharT{57}};
 
       SpBuf spBuf(sp, std::ios_base::out);
-      std::println(stderr, "fasdfasdfasdfasdfasd 0 {}", spBuf.span());
+      // std::println(stderr, "fasdfasdfasdfasdfasd 0 {}", spBuf.span());
       assert(spBuf.pubseekoff(3, std::ios_base::beg, std::ios_base::in) == -1);
       assert(spBuf.pubseekoff(3, std::ios_base::cur, std::ios_base::in) == -1);
       assert(spBuf.pubseekoff(-3, std::ios_base::end, std::ios_base::in) == -1);
@@ -172,6 +155,7 @@ void test() {
       assert(spBuf.pubseekoff(3, std::ios_base::cur, std::ios_base::out | std::ios_base::in) == -1);
       assert(spBuf.pubseekoff(-3, std::ios_base::end, std::ios_base::out | std::ios_base::in) == -1);
       assert(spBuf.pubseekoff(3, std::ios_base::beg, std::ios_base::out) == 3);
+      // #if 0
       assert(spBuf.sputc(CharT{90}) == 90);
       // assert(spBuf.str() == "012a456789");
       resultArr[3] = CharT{90};
@@ -181,21 +165,23 @@ void test() {
       std::println(stderr, "fasdfasdfasdfasdfasd {}", spBuf.span().size());
       std::println(stderr, "fasdfasdfasdfasdfasd 2 {}", std::span<CharT>{resultArr});
       // assert(std::ranges::equal(spBuf.span(), std::span<CharT>{resultArr}));
-      assert(spBuf.pubseekoff(3, std::ios_base::cur, std::ios_base::out) == 7);
+      // assert(spBuf.pubseekoff(3, std::ios_base::cur, std::ios_base::out) == 7);
       assert(spBuf.sputc(CharT{77}) == 77);
-       std::println(stderr, "fasdfasdfasdfasdfasd 5 {}", spBuf.span());
+      std::println(stderr,"fasdfasdfasdfasdfasd 5 {}", spBuf.span());
       // assert(spBuf.str() == "012a456b89");
       resultArr[7] = CharT{77};
       // assert(spBuf.span() == std::span<CharT>{resultArr});
       // assert(std::ranges::equal(spBuf.span(), std::span<CharT>{resultArr}));
-      assert(spBuf.pubseekoff(-3, std::ios_base::end, std::ios_base::out) == 7);
-       std::println(stderr, "fasdfasdfasdfasdfasd 6 {}", spBuf.span());
-#if 0
+      // std::println(stderr, "ljjklj {}",  static_cast<int>(spBuf.pubseekoff(-3, std::ios_base::end, std::ios_base::out)));
+      assert(spBuf.pubseekoff(-3, std::ios_base::end, std::ios_base::out) == 2);
+      std::println(stderr, "fasdfasdfasdfasdfasd 6 {}", spBuf.span());
       assert(spBuf.sputc(CharT{84}) == 84);
+#if 0
       // assert(spBuf.str() == "012a456c89");
       resultArr[6] = CharT{84};
       assert(spBuf.span() == std::span<CharT>{resultArr});
 #endif
+      assert(false);
     }
     // Mode: multiple
     {
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekoff.pos_type.open_mode.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekoff.pos_type.open_mode.pass.cpp
index 2558e2999dc09..78fda49908601 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekoff.pos_type.open_mode.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekoff.pos_type.open_mode.pass.cpp
@@ -20,7 +20,6 @@
 //                      ios_base::openmode which = ios_base::in | ios_base::out) override;
 
 #include <cassert>
-#include <concepts>
 #include <span>
 #include <spanstream>
 
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/setbuf.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/setbuf.pass.cpp
index 2fd0e791e13e6..b0d6471097998 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/setbuf.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/setbuf.pass.cpp
@@ -18,7 +18,6 @@
 //     basic_streambuf<charT, traits>* setbuf(charT*, streamsize) override;
 
 #include <cassert>
-#include <concepts>
 #include <span>
 #include <spanstream>
 

>From 5ae016057fe55519b30b5e17f9955e1664ddebf6 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Tue, 12 Mar 2024 14:34:48 +0200
Subject: [PATCH 35/56] Tests: WIP `seekoff`

---
 libcxx/include/spanstream                     |   3 +-
 ...ekoff.off_type.seek_dir.open_mode.pass.cpp | 231 ++++---
 .../temp_test/temp_test.pass.cpp              | 575 ++++++++++++++++++
 3 files changed, 723 insertions(+), 86 deletions(-)
 create mode 100644 libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/temp_test/temp_test.pass.cpp

diff --git a/libcxx/include/spanstream b/libcxx/include/spanstream
index 63b61d1dee26d..68d65db9d0afe 100644
--- a/libcxx/include/spanstream
+++ b/libcxx/include/spanstream
@@ -113,7 +113,6 @@ public:
       : basic_streambuf<_CharT, _Traits>{std::move(__rhs)},
         __mode_{std::move(__rhs.__mode_)},
         __buf_{std::move(__rhs.__buf_)} {}
-  // __buf_{std::exchange(__rhs.__buf_, {})} {}
 
   // [spanbuf.assign], assignment and swap
 
@@ -187,7 +186,7 @@ protected:
       break;
 
     case ios_base::end:
-      if ((__which & ios_base::out) && !(__which & ios_base::in))
+      if ((__mode_ & ios_base::out) && !(__mode_ & ios_base::in))
         __baseoff = this->pptr() - this->pbase();
       else
         __baseoff = __buf_.size();
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekoff.off_type.seek_dir.open_mode.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekoff.off_type.seek_dir.open_mode.pass.cpp
index 2d378127e5fa4..3dac603ca1fbe 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekoff.off_type.seek_dir.open_mode.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekoff.off_type.seek_dir.open_mode.pass.cpp
@@ -28,14 +28,11 @@
 #include "nasty_string.h"
 #include "test_macros.h"
 
-#include <print>
+#include <iostream>
 
 template <typename CharT, typename TraitsT = std::char_traits<CharT>>
 void test() {
-  using SpBuf       = std::basic_spanbuf<CharT, TraitsT>;
-  using SpBuffError = typename SpBuf::pos_type;
-
-  const SpBuffError error{-1};
+  using SpBuf = std::basic_spanbuf<CharT, TraitsT>;
 
   // Empty `span`
   {
@@ -44,149 +41,215 @@ void test() {
     // Mode: default (`in` | `out`)
     {
       SpBuf spBuf{sp};
+
+      // Out-of-range
+      assert(spBuf.pubseekoff(-999, std::ios_base::beg, std::ios_base::in) == -1);
+      assert(spBuf.pubseekoff(-999, std::ios_base::cur, std::ios_base::in) == -1);
+      assert(spBuf.pubseekoff(-999, std::ios_base::end, std::ios_base::in) == -1);
+      assert(spBuf.pubseekoff(999, std::ios_base::beg, std::ios_base::out) == -1);
+      assert(spBuf.pubseekoff(999, std::ios_base::cur, std::ios_base::out) == -1);
+      assert(spBuf.pubseekoff(999, std::ios_base::end, std::ios_base::out) == -1);
+
       assert(spBuf.pubseekoff(3, std::ios_base::beg, std::ios_base::in) == -1);
       assert(spBuf.pubseekoff(3, std::ios_base::cur, std::ios_base::in) == -1);
       assert(spBuf.pubseekoff(-3, std::ios_base::end, std::ios_base::in) == -1);
-      assert(spBuf.pubseekoff(3, std::ios_base::beg, std::ios_base::in | std::ios_base::out) == -1);
-      assert(spBuf.pubseekoff(3, std::ios_base::cur, std::ios_base::in | std::ios_base::out) == -1);
-      assert(spBuf.pubseekoff(-3, std::ios_base::end, std::ios_base::in | std::ios_base::out) == -1);
+
       assert(spBuf.pubseekoff(0, std::ios_base::beg, std::ios_base::out) == 0);
       assert(spBuf.pubseekoff(0, std::ios_base::cur, std::ios_base::out) == 0);
       assert(spBuf.pubseekoff(0, std::ios_base::end, std::ios_base::out) == 0);
+
+      // Default `in` && `out`
+      assert(spBuf.pubseekoff(3, std::ios_base::beg) == -1);
+      assert(spBuf.pubseekoff(3, std::ios_base::cur) == -1);
+      assert(spBuf.pubseekoff(-3, std::ios_base::end) == -1);
     }
     // Mode: `in`
     {
       SpBuf spBuf{sp, std::ios_base::in};
-      assert(spBuf.pubseekoff(3, std::ios_base::beg, std::ios_base::out) == -1);
-      assert(spBuf.pubseekoff(3, std::ios_base::cur, std::ios_base::out) == -1);
-      assert(spBuf.pubseekoff(-3, std::ios_base::end, std::ios_base::out) == -1);
-      assert(spBuf.pubseekoff(3, std::ios_base::beg, std::ios_base::in | std::ios_base::out) == -1);
-      assert(spBuf.pubseekoff(3, std::ios_base::cur, std::ios_base::in | std::ios_base::out) == -1);
-      assert(spBuf.pubseekoff(-3, std::ios_base::end, std::ios_base::in | std::ios_base::out) == -1);
+
+      // Out-of-range
+      assert(spBuf.pubseekoff(-999, std::ios_base::beg, std::ios_base::out) == -1);
+      assert(spBuf.pubseekoff(-999, std::ios_base::cur, std::ios_base::out) == -1);
+      assert(spBuf.pubseekoff(-999, std::ios_base::end, std::ios_base::out) == -1);
+      assert(spBuf.pubseekoff(999, std::ios_base::beg, std::ios_base::out) == -1);
+      assert(spBuf.pubseekoff(999, std::ios_base::cur, std::ios_base::out) == -1);
+      assert(spBuf.pubseekoff(999, std::ios_base::end, std::ios_base::out) == -1);
+
       assert(spBuf.pubseekoff(0, std::ios_base::beg, std::ios_base::in) == 0);
       assert(spBuf.pubseekoff(0, std::ios_base::cur, std::ios_base::in) == 0);
       assert(spBuf.pubseekoff(0, std::ios_base::end, std::ios_base::in) == 0);
+
+      assert(spBuf.pubseekoff(3, std::ios_base::beg, std::ios_base::out) == -1);
+      assert(spBuf.pubseekoff(3, std::ios_base::cur, std::ios_base::out) == -1);
+      assert(spBuf.pubseekoff(-3, std::ios_base::end, std::ios_base::out) == -1);
+
+      // Default `in` && `out`
+      assert(spBuf.pubseekoff(3, std::ios_base::beg) == -1);
+      assert(spBuf.pubseekoff(3, std::ios_base::cur) == -1);
+      assert(spBuf.pubseekoff(-3, std::ios_base::end) == -1);
     }
     // Mode: `out`
     {
       SpBuf spBuf{sp, std::ios_base::out};
+
+      // Out-of-range
+      assert(spBuf.pubseekoff(-999, std::ios_base::beg, std::ios_base::out) == -1);
+      assert(spBuf.pubseekoff(-999, std::ios_base::cur, std::ios_base::out) == -1);
+      assert(spBuf.pubseekoff(-999, std::ios_base::end, std::ios_base::out) == -1);
+      assert(spBuf.pubseekoff(999, std::ios_base::beg, std::ios_base::out) == -1);
+      assert(spBuf.pubseekoff(999, std::ios_base::cur, std::ios_base::out) == -1);
+      assert(spBuf.pubseekoff(999, std::ios_base::end, std::ios_base::out) == -1);
+
       assert(spBuf.pubseekoff(3, std::ios_base::beg, std::ios_base::in) == -1);
       assert(spBuf.pubseekoff(3, std::ios_base::cur, std::ios_base::in) == -1);
       assert(spBuf.pubseekoff(-3, std::ios_base::end, std::ios_base::in) == -1);
-      assert(spBuf.pubseekoff(3, std::ios_base::beg, std::ios_base::in | std::ios_base::out) == -1);
-      assert(spBuf.pubseekoff(3, std::ios_base::cur, std::ios_base::in | std::ios_base::out) == -1);
-      assert(spBuf.pubseekoff(-3, std::ios_base::end, std::ios_base::in | std::ios_base::out) == -1);
+
       assert(spBuf.pubseekoff(0, std::ios_base::beg, std::ios_base::out) == 0);
       assert(spBuf.pubseekoff(0, std::ios_base::cur, std::ios_base::out) == 0);
       assert(spBuf.pubseekoff(0, std::ios_base::end, std::ios_base::out) == 0);
+
+      // Default `in` && `out`
+      assert(spBuf.pubseekoff(3, std::ios_base::beg) == -1);
+      assert(spBuf.pubseekoff(3, std::ios_base::cur) == -1);
+      assert(spBuf.pubseekoff(-3, std::ios_base::end) == -1);
     }
     // Mode: `multiple`
     {
       SpBuf spBuf{sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary};
+
+      // Out-of-range
+      assert(spBuf.pubseekoff(-999, std::ios_base::beg, std::ios_base::out) == -1);
+      assert(spBuf.pubseekoff(-999, std::ios_base::cur, std::ios_base::out) == -1);
+      assert(spBuf.pubseekoff(-999, std::ios_base::end, std::ios_base::out) == -1);
+      assert(spBuf.pubseekoff(999, std::ios_base::beg, std::ios_base::out) == -1);
+      assert(spBuf.pubseekoff(999, std::ios_base::cur, std::ios_base::out) == -1);
+      assert(spBuf.pubseekoff(999, std::ios_base::end, std::ios_base::out) == -1);
+
       assert(spBuf.pubseekoff(3, std::ios_base::beg, std::ios_base::in) == -1);
       assert(spBuf.pubseekoff(3, std::ios_base::cur, std::ios_base::in) == -1);
       assert(spBuf.pubseekoff(-3, std::ios_base::end, std::ios_base::in) == -1);
-      assert(spBuf.pubseekoff(3, std::ios_base::beg, std::ios_base::in | std::ios_base::out) == -1);
-      assert(spBuf.pubseekoff(3, std::ios_base::cur, std::ios_base::in | std::ios_base::out) == -1);
-      assert(spBuf.pubseekoff(-3, std::ios_base::end, std::ios_base::in | std::ios_base::out) == -1);
+
       assert(spBuf.pubseekoff(0, std::ios_base::beg, std::ios_base::out) == 0);
       assert(spBuf.pubseekoff(0, std::ios_base::cur, std::ios_base::out) == 0);
       assert(spBuf.pubseekoff(0, std::ios_base::end, std::ios_base::out) == 0);
+
+      // Default `in` && `out`
+      assert(spBuf.pubseekoff(3, std::ios_base::beg) == -1);
+      assert(spBuf.pubseekoff(3, std::ios_base::cur) == -1);
+      assert(spBuf.pubseekoff(-3, std::ios_base::end) == -1);
     }
     // Mode: `ate`
     {
       SpBuf spBuf{sp, std::ios_base::out | std::ios_base::ate};
-      assert(spBuf.pubseekoff(3, std::ios_base::beg, std::ios_base::out) == -1);
-      assert(spBuf.pubseekoff(3, std::ios_base::cur, std::ios_base::out) == -1);
-      assert(spBuf.pubseekoff(-3, std::ios_base::end, std::ios_base::out) == -1);
-      assert(spBuf.pubseekoff(3, std::ios_base::beg, std::ios_base::in | std::ios_base::out) == -1);
-      assert(spBuf.pubseekoff(3, std::ios_base::cur, std::ios_base::in | std::ios_base::out) == -1);
-      assert(spBuf.pubseekoff(-3, std::ios_base::end, std::ios_base::in | std::ios_base::out) == -1);
+
+      // Out-of-range
+      assert(spBuf.pubseekoff(-999, std::ios_base::beg, std::ios_base::out) == -1);
+      assert(spBuf.pubseekoff(-999, std::ios_base::cur, std::ios_base::out) == -1);
+      assert(spBuf.pubseekoff(-999, std::ios_base::end, std::ios_base::out) == -1);
+      assert(spBuf.pubseekoff(999, std::ios_base::beg, std::ios_base::out) == -1);
+      assert(spBuf.pubseekoff(999, std::ios_base::cur, std::ios_base::out) == -1);
+      assert(spBuf.pubseekoff(999, std::ios_base::end, std::ios_base::out) == -1);
+
       assert(spBuf.pubseekoff(0, std::ios_base::beg, std::ios_base::in) == 0);
       assert(spBuf.pubseekoff(0, std::ios_base::cur, std::ios_base::in) == 0);
       assert(spBuf.pubseekoff(0, std::ios_base::end, std::ios_base::in) == 0);
+
+      assert(spBuf.pubseekoff(3, std::ios_base::beg, std::ios_base::out) == -1);
+      assert(spBuf.pubseekoff(3, std::ios_base::cur, std::ios_base::out) == -1);
+      assert(spBuf.pubseekoff(-3, std::ios_base::end, std::ios_base::out) == -1);
+
+      // Default `in` && `out`
+      assert(spBuf.pubseekoff(3, std::ios_base::beg) == -1);
+      assert(spBuf.pubseekoff(3, std::ios_base::cur) == -1);
+      assert(spBuf.pubseekoff(-3, std::ios_base::end) == -1);
     }
   }
 
   // Non-empty `span`
   {
-    // Initialize with ASCII codes: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
-    CharT arr[]{
-        CharT{48}, CharT{49}, CharT{50}, CharT{51}, CharT{52}, CharT{53}, CharT{54}, CharT{55}, CharT{56}, CharT{57}};
+    CharT arr[10];
     std::span sp{arr};
-    // std::print(stderr, "-=----- {}", sp);
-    // assert(false);
 
     // Mode: default (`in` | `out`)
     {
-      // TestSpanBuf<CharT, TraitsT> rhsSpBuf(sp);
-      // TestSpanBuf<CharT, TraitsT> spBuf = std::move(static_cast<SpBuf&>(rhsSpBuf));
-      // assert(rhsSpBuf.span().data() == arr);
-      // assert(spBuf.span().data() == arr);
-      // spBuf.check_postconditions(rhsSpBuf);
+      SpBuf spBuf{sp};
+
+      // Out-of-range
+      assert(spBuf.pubseekoff(-999, std::ios_base::beg, std::ios_base::out) == -1);
+      assert(spBuf.pubseekoff(-999, std::ios_base::cur, std::ios_base::out) == -1);
+      assert(spBuf.pubseekoff(-999, std::ios_base::end, std::ios_base::out) == -1);
+      assert(spBuf.pubseekoff(999, std::ios_base::beg, std::ios_base::out) == -1);
+      assert(spBuf.pubseekoff(999, std::ios_base::cur, std::ios_base::out) == -1);
+      assert(spBuf.pubseekoff(999, std::ios_base::end, std::ios_base::out) == -1);
+
+      std::cerr << spBuf.pubseekoff(3, std::ios_base::beg, std::ios_base::in) << std::endl;
+      // assert(spBuf.pubseekoff(3, std::ios_base::beg, std::ios_base::in) == -1);
+      assert(spBuf.pubseekoff(3, std::ios_base::cur, std::ios_base::in) == -1);
+      assert(spBuf.pubseekoff(-3, std::ios_base::end, std::ios_base::in) == -1);
+
+      assert(spBuf.pubseekoff(3, std::ios_base::beg, std::ios_base::out) == 3);
+      assert(spBuf.pubseekoff(3, std::ios_base::cur, std::ios_base::out) == 6);
+      assert(spBuf.pubseekoff(-3, std::ios_base::end, std::ios_base::out) == 3);
+
+      // Default `in` && `out`
+      assert(spBuf.pubseekoff(3, std::ios_base::beg) == -1);
+      assert(spBuf.pubseekoff(3, std::ios_base::cur) == -1);
+      assert(spBuf.pubseekoff(-3, std::ios_base::end) == -1);
     }
     // Mode: `in`
     {
-      SpBuf spBuf(sp, std::ios_base::in);
-      assert(spBuf.pubseekoff(3, std::ios_base::beg, std::ios_base::out) == -1);
-      assert(spBuf.pubseekoff(3, std::ios_base::cur, std::ios_base::out) == -1);
-      assert(spBuf.pubseekoff(-3, std::ios_base::end, std::ios_base::out) == -1);
-      assert(spBuf.pubseekoff(3, std::ios_base::beg, std::ios_base::in | std::ios_base::out) == -1);
-      assert(spBuf.pubseekoff(3, std::ios_base::cur, std::ios_base::in | std::ios_base::out) == -1);
-      assert(spBuf.pubseekoff(-3, std::ios_base::end, std::ios_base::in | std::ios_base::out) == -1);
+      SpBuf spBuf{sp, std::ios_base::in};
+
+      // Out-of-range
+      assert(spBuf.pubseekoff(-999, std::ios_base::beg, std::ios_base::out) == -1);
+      assert(spBuf.pubseekoff(-999, std::ios_base::cur, std::ios_base::out) == -1);
+      assert(spBuf.pubseekoff(-999, std::ios_base::end, std::ios_base::out) == -1);
+      assert(spBuf.pubseekoff(999, std::ios_base::beg, std::ios_base::out) == -1);
+      assert(spBuf.pubseekoff(999, std::ios_base::cur, std::ios_base::out) == -1);
+      assert(spBuf.pubseekoff(999, std::ios_base::end, std::ios_base::out) == -1);
+
       assert(spBuf.pubseekoff(3, std::ios_base::beg, std::ios_base::in) == 3);
-      assert(spBuf.sgetc() == 51);
       assert(spBuf.pubseekoff(3, std::ios_base::cur, std::ios_base::in) == 6);
-      assert(spBuf.sgetc() == 54);
       assert(spBuf.pubseekoff(-3, std::ios_base::end, std::ios_base::in) == 7);
-      assert(spBuf.sgetc() == 55);
+
+      assert(spBuf.pubseekoff(3, std::ios_base::beg, std::ios_base::out) == -1);
+      assert(spBuf.pubseekoff(3, std::ios_base::cur, std::ios_base::out) == -1);
+      assert(spBuf.pubseekoff(-3, std::ios_base::end, std::ios_base::out) == -1);
+
+      // Default `in` && `out`
+      assert(spBuf.pubseekoff(3, std::ios_base::beg) == -1);
+      assert(spBuf.pubseekoff(3, std::ios_base::cur) == -1);
+      assert(spBuf.pubseekoff(-3, std::ios_base::end) == -1);
     }
     // Mode: `out`
     {
-      CharT resultArr[]{
-          CharT{48}, CharT{49}, CharT{50}, CharT{51}, CharT{52}, CharT{53}, CharT{54}, CharT{55}, CharT{56}, CharT{57}};
+      SpBuf spBuf{sp, std::ios_base::out};
+
+      // Out-of-range
+      assert(spBuf.pubseekoff(-999, std::ios_base::beg, std::ios_base::out) == -1);
+      assert(spBuf.pubseekoff(-999, std::ios_base::cur, std::ios_base::out) == -1);
+      assert(spBuf.pubseekoff(-999, std::ios_base::end, std::ios_base::out) == -1);
+      assert(spBuf.pubseekoff(999, std::ios_base::beg, std::ios_base::out) == -1);
+      assert(spBuf.pubseekoff(999, std::ios_base::cur, std::ios_base::out) == -1);
+      assert(spBuf.pubseekoff(999, std::ios_base::end, std::ios_base::out) == -1);
 
-      SpBuf spBuf(sp, std::ios_base::out);
-      // std::println(stderr, "fasdfasdfasdfasdfasd 0 {}", spBuf.span());
       assert(spBuf.pubseekoff(3, std::ios_base::beg, std::ios_base::in) == -1);
       assert(spBuf.pubseekoff(3, std::ios_base::cur, std::ios_base::in) == -1);
       assert(spBuf.pubseekoff(-3, std::ios_base::end, std::ios_base::in) == -1);
-      assert(spBuf.pubseekoff(3, std::ios_base::beg, std::ios_base::out | std::ios_base::in) == -1);
-      assert(spBuf.pubseekoff(3, std::ios_base::cur, std::ios_base::out | std::ios_base::in) == -1);
-      assert(spBuf.pubseekoff(-3, std::ios_base::end, std::ios_base::out | std::ios_base::in) == -1);
+
       assert(spBuf.pubseekoff(3, std::ios_base::beg, std::ios_base::out) == 3);
-      // #if 0
-      assert(spBuf.sputc(CharT{90}) == 90);
-      // assert(spBuf.str() == "012a456789");
-      resultArr[3] = CharT{90};
-      // assert(spBuf.span() == std::span<CharT>{resultArr});
-      std::println(stderr, "fasdfasdfasdfasdfasd 1 {}", spBuf.span());
-      std::println(stderr, "fasdfasdfasdfasdfasd {}", spBuf.span().data());
-      std::println(stderr, "fasdfasdfasdfasdfasd {}", spBuf.span().size());
-      std::println(stderr, "fasdfasdfasdfasdfasd 2 {}", std::span<CharT>{resultArr});
-      // assert(std::ranges::equal(spBuf.span(), std::span<CharT>{resultArr}));
-      // assert(spBuf.pubseekoff(3, std::ios_base::cur, std::ios_base::out) == 7);
-      assert(spBuf.sputc(CharT{77}) == 77);
-      std::println(stderr,"fasdfasdfasdfasdfasd 5 {}", spBuf.span());
-      // assert(spBuf.str() == "012a456b89");
-      resultArr[7] = CharT{77};
-      // assert(spBuf.span() == std::span<CharT>{resultArr});
-      // assert(std::ranges::equal(spBuf.span(), std::span<CharT>{resultArr}));
-      // std::println(stderr, "ljjklj {}",  static_cast<int>(spBuf.pubseekoff(-3, std::ios_base::end, std::ios_base::out)));
-      assert(spBuf.pubseekoff(-3, std::ios_base::end, std::ios_base::out) == 2);
-      std::println(stderr, "fasdfasdfasdfasdfasd 6 {}", spBuf.span());
-      assert(spBuf.sputc(CharT{84}) == 84);
-#if 0
-      // assert(spBuf.str() == "012a456c89");
-      resultArr[6] = CharT{84};
-      assert(spBuf.span() == std::span<CharT>{resultArr});
-#endif
-      assert(false);
+      assert(spBuf.pubseekoff(3, std::ios_base::cur, std::ios_base::out) == 6);
+      assert(spBuf.pubseekoff(-3, std::ios_base::end, std::ios_base::out) == 3);
+
+      // Default `in` && `out`
+      assert(spBuf.pubseekoff(3, std::ios_base::beg) == -1);
+      assert(spBuf.pubseekoff(3, std::ios_base::cur) == -1);
+      assert(spBuf.pubseekoff(-3, std::ios_base::end) == -1);
     }
     // Mode: multiple
     {
       // std::span<CharT> sp{arr};
-      // TestSpanBuf<CharT, TraitsT> rhsSpBuf(sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary);
+      // TestSpanBuf<CharT, TraitsT> rhsSpBuf(sp | std::ios_base::binary);
       // TestSpanBuf<CharT, TraitsT> spBuf = std::move(static_cast<SpBuf&>(rhsSpBuf));
       // assert(rhsSpBuf.span().data() == arr);
       // assert(spBuf.span().data() == arr);
@@ -206,13 +269,13 @@ void test() {
 
 int main(int, char**) {
 #ifndef TEST_HAS_NO_NASTY_STRING
-  // test<nasty_char, nasty_char_traits>();
+  test<nasty_char, nasty_char_traits>();
 #endif
   test<char>();
   test<char, constexpr_char_traits<char>>();
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
-  // test<wchar_t>();
-  // test<wchar_t, constexpr_char_traits<wchar_t>>();
+  test<wchar_t>();
+  test<wchar_t, constexpr_char_traits<wchar_t>>();
 #endif
 
   return 0;
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/temp_test/temp_test.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/temp_test/temp_test.pass.cpp
new file mode 100644
index 0000000000000..33c75ba9b1fa8
--- /dev/null
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/temp_test/temp_test.pass.cpp
@@ -0,0 +1,575 @@
+#include <algorithm>
+#include <array>
+#include <cassert>
+#include <ios>
+#include <limits>
+#include <span>
+#include <spanstream>
+#include <string_view>
+#include <type_traits>
+#include <utility>
+
+#include <algorithm>
+#include <cassert>
+#include <span>
+#include <spanstream>
+
+#include "constexpr_char_traits.h"
+#include "nasty_string.h"
+#include "test_macros.h"
+
+#include <iostream>
+
+using namespace std;
+
+template <class Spanbuf>
+class basic_test_buf : public Spanbuf {
+public:
+  using Spanbuf::Spanbuf;
+
+  using Spanbuf::eback;
+  using Spanbuf::egptr;
+  using Spanbuf::epptr;
+  using Spanbuf::gptr;
+  using Spanbuf::pbase;
+  using Spanbuf::pptr;
+
+  using Spanbuf::setp;
+
+  using Spanbuf::seekoff;
+  using Spanbuf::seekpos;
+  using Spanbuf::setbuf;
+};
+
+template <typename CharT, typename TraitsT = std::char_traits<CharT>>
+void test() {
+  using test_buf = basic_test_buf<basic_spanbuf<CharT>>;
+  { // construction
+    CharT buffer[10];
+    const test_buf default_constructed{};
+    assert(default_constructed.span().data() == nullptr);
+    assert(default_constructed.eback() == nullptr);
+    assert(default_constructed.gptr() == nullptr);
+    assert(default_constructed.egptr() == nullptr);
+    assert(default_constructed.pbase() == nullptr);
+    assert(default_constructed.pptr() == nullptr);
+    assert(default_constructed.epptr() == nullptr);
+
+    const test_buf mode_constructed{ios_base::in};
+    assert(mode_constructed.span().data() == nullptr);
+    assert(mode_constructed.eback() == nullptr);
+    assert(mode_constructed.gptr() == nullptr);
+    assert(mode_constructed.egptr() == nullptr);
+    assert(mode_constructed.pbase() == nullptr);
+    assert(mode_constructed.pptr() == nullptr);
+    assert(mode_constructed.epptr() == nullptr);
+
+    test_buf span_constructed{span<CharT>{buffer}};
+    assert(span_constructed.span().data() == buffer);
+    assert(span_constructed.eback() == buffer);
+    assert(span_constructed.gptr() == buffer);
+    // assert(span_constructed.egptr() == std::end(buffer));
+    assert(span_constructed.pbase() == buffer);
+    assert(span_constructed.pptr() == buffer);
+    // assert(span_constructed.epptr() == std::end(buffer));
+
+    const test_buf span_mode_in_constructed{span<CharT>{buffer}, ios_base::in};
+    assert(span_mode_in_constructed.span().data() == buffer);
+    assert(span_mode_in_constructed.eback() == buffer);
+    assert(span_mode_in_constructed.gptr() == buffer);
+    // assert(span_mode_in_constructed.egptr() == std::end(buffer));
+    assert(span_mode_in_constructed.pbase() == nullptr);
+    assert(span_mode_in_constructed.pptr() == nullptr);
+    assert(span_mode_in_constructed.epptr() == nullptr);
+
+    const test_buf span_mode_in_ate_constructed{span<CharT>{buffer}, ios_base::in | ios_base::ate};
+    assert(span_mode_in_ate_constructed.span().data() == buffer);
+    assert(span_mode_in_ate_constructed.eback() == buffer);
+    assert(span_mode_in_ate_constructed.gptr() == buffer);
+    // assert(span_mode_in_ate_constructed.egptr() == std::end(buffer));
+    assert(span_mode_in_ate_constructed.pbase() == nullptr);
+    assert(span_mode_in_ate_constructed.pptr() == nullptr);
+    assert(span_mode_in_ate_constructed.epptr() == nullptr);
+
+    const test_buf span_mode_out_constructed{span<CharT>{buffer}, ios_base::out};
+    assert(span_mode_out_constructed.span().data() == buffer);
+    assert(span_mode_out_constructed.eback() == nullptr);
+    assert(span_mode_out_constructed.gptr() == nullptr);
+    assert(span_mode_out_constructed.egptr() == nullptr);
+    assert(span_mode_out_constructed.pbase() == buffer);
+    assert(span_mode_out_constructed.pptr() == buffer);
+    assert(span_mode_out_constructed.epptr() == std::end(buffer));
+
+    const test_buf span_mode_out_ate_constructed{span<CharT>{buffer}, ios_base::out | ios_base::ate};
+    assert(span_mode_out_ate_constructed.span().data() == buffer);
+    assert(span_mode_out_ate_constructed.eback() == nullptr);
+    assert(span_mode_out_ate_constructed.gptr() == nullptr);
+    assert(span_mode_out_ate_constructed.egptr() == nullptr);
+    assert(span_mode_out_ate_constructed.pbase() == buffer);
+    // assert(span_mode_out_ate_constructed.pptr() == std::end(buffer));
+    // assert(span_mode_out_ate_constructed.epptr() == std::end(buffer));
+
+    const test_buf span_mode_unknown_constructed{span<CharT>{buffer}, 0};
+    assert(span_mode_unknown_constructed.span().data() == buffer);
+    assert(span_mode_unknown_constructed.eback() == nullptr);
+    assert(span_mode_unknown_constructed.gptr() == nullptr);
+    assert(span_mode_unknown_constructed.egptr() == nullptr);
+    assert(span_mode_unknown_constructed.pbase() == nullptr);
+    assert(span_mode_unknown_constructed.pptr() == nullptr);
+    assert(span_mode_unknown_constructed.epptr() == nullptr);
+#if 0
+    test_buf move_constructed{std::move(span_constructed)};
+    assert(move_constructed.span().data() == buffer);
+    assert(move_constructed.eback() == buffer);
+    assert(move_constructed.gptr() == buffer);
+    // assert(move_constructed.egptr() == std::end(buffer));
+    assert(move_constructed.pbase() == buffer);
+    assert(move_constructed.pptr() == buffer);
+    // assert(move_constructed.epptr() == std::end(buffer));
+    assert(span_constructed.span().data() == nullptr);
+    assert(span_constructed.eback() == nullptr);
+    assert(span_constructed.gptr() == nullptr);
+    assert(span_constructed.egptr() == nullptr);
+    assert(span_constructed.pbase() == nullptr);
+    assert(span_constructed.pptr() == nullptr);
+    assert(span_constructed.epptr() == nullptr);
+
+    test_buf move_assigned;
+    move_assigned = std::move(move_constructed);
+    assert(move_assigned.span().data() == buffer);
+    assert(move_assigned.eback() == buffer);
+    assert(move_assigned.gptr() == buffer);
+    // assert(move_assigned.egptr() == std::end(buffer));
+    assert(move_assigned.pbase() == buffer);
+    assert(move_assigned.pptr() == buffer);
+    // assert(move_assigned.epptr() == std::end(buffer));
+    assert(move_constructed.span().data() == nullptr);
+    assert(move_constructed.eback() == nullptr);
+    assert(move_constructed.gptr() == nullptr);
+    assert(move_constructed.egptr() == nullptr);
+    assert(move_constructed.pbase() == nullptr);
+    assert(move_constructed.pptr() == nullptr);
+    assert(move_constructed.epptr() == nullptr);
+#endif
+  }
+
+  // { // swap
+  //   CharT buffer1[10];
+  //   CharT buffer2[20];
+  //   test_buf first{span<CharT>{buffer1}};
+  //   test_buf second{span<CharT>{buffer2}};
+  //   assert(first.span().data() == buffer1);
+  //   assert(second.span().data() == buffer2);
+
+  //   first.swap(second);
+  //   assert(first.span().data() == buffer2);
+  //   assert(second.span().data() == buffer1);
+
+  //   swap(first, second);
+  //   assert(first.span().data() == buffer1);
+  //   assert(second.span().data() == buffer2);
+  // }
+
+  // { // span, span, span, span
+  //   CharT buffer1[10];
+  //   test_buf input_buffer{span<CharT>{buffer1}, ios_base::in};
+  //   assert(input_buffer.span().data() == buffer1);
+  //   assert(input_buffer.span().size() == std::size(buffer1));
+
+  //   test_buf output_buffer{span<CharT>{buffer1}, ios_base::out};
+  //   assert(output_buffer.span().data() == buffer1);
+  //   assert(output_buffer.span().size() == 0); // counts the written characters
+
+  //   // Manually move the written pointer
+  //   output_buffer.setp(buffer1, buffer1 + 5, std::end(buffer1));
+  //   assert(output_buffer.span().data() == buffer1);
+  //   assert(output_buffer.span().size() == 5);
+
+  //   CharT buffer2[10];
+  //   input_buffer.span(span<CharT>{buffer2});
+  //   assert(input_buffer.span().data() == buffer2);
+  //   assert(input_buffer.span().size() == std::size(buffer2));
+
+  //   output_buffer.span(span<CharT>{buffer2});
+  //   assert(output_buffer.span().data() == buffer2);
+  //   assert(output_buffer.span().size() == 0);
+
+  //   test_buf hungry_buffer{span<CharT>{buffer1}, ios_base::out | ios_base::ate};
+  //   assert(hungry_buffer.span().data() == buffer1);
+  //   assert(hungry_buffer.span().size() == std::size(buffer1));
+
+  //   hungry_buffer.span(span<CharT>{buffer2});
+  //   assert(hungry_buffer.span().data() == buffer2);
+  //   assert(hungry_buffer.span().size() == std::size(buffer2));
+  // }
+
+  { // seekoff ios_base::beg
+    CharT buffer[10];
+    test_buf input_buffer{span<CharT>{buffer}, ios_base::in};
+    test_buf output_buffer{span<CharT>{buffer}, ios_base::out};
+
+    auto result = input_buffer.seekoff(0, ios_base::beg, ios_base::in);
+    assert(result == 0);
+
+    // pptr not set but off is 0
+    result = input_buffer.seekoff(0, ios_base::beg, ios_base::out);
+    assert(result == 0);
+
+    // pptr not set and off != 0 -> fail
+    result = input_buffer.seekoff(1, ios_base::beg, ios_base::out);
+    assert(result == -1);
+
+    // gptr not set but off is 0
+    result = output_buffer.seekoff(0, ios_base::beg, ios_base::in);
+    assert(result == 0);
+
+    // gptr not set and off != 0 -> fail
+    result = output_buffer.seekoff(1, ios_base::beg, ios_base::in);
+    assert(result == -1);
+
+    // negative off -> fail
+    result = input_buffer.seekoff(-1, ios_base::beg, ios_base::in);
+    assert(result == -1);
+
+    // negative off -> fail
+    result = output_buffer.seekoff(-1, ios_base::beg, ios_base::out);
+    assert(result == -1);
+
+    // off larger than buf -> fail
+    result = input_buffer.seekoff(20, ios_base::beg, ios_base::in);
+    assert(result == -1);
+
+    // off larger than buf -> fail
+    result = output_buffer.seekoff(20, ios_base::beg, ios_base::out);
+    assert(result == -1);
+
+    // passes
+    result = input_buffer.seekoff(5, ios_base::beg, ios_base::in);
+    assert(result == 5);
+
+    result = output_buffer.seekoff(5, ios_base::beg, ios_base::out);
+    assert(result == 5);
+
+    // always from front
+    result = input_buffer.seekoff(7, ios_base::beg, ios_base::in);
+    assert(result == 7);
+
+    result = output_buffer.seekoff(7, ios_base::beg, ios_base::out);
+    assert(result == 7);
+  }
+
+  { // seekoff ios_base::end
+    CharT buffer[10];
+    test_buf input_buffer{span<CharT>{buffer}, ios_base::in};
+    // all fine we move to end of stream
+    auto result = input_buffer.seekoff(0, ios_base::end, ios_base::in);
+    assert(result == 10);
+
+    // pptr not set but off is == 0
+    result = input_buffer.seekoff(-10, ios_base::end, ios_base::out);
+    std::cerr << result << std::endl;
+    assert(result == 0);
+
+    // pptr not set and off != 0 -> fail
+    result = input_buffer.seekoff(0, ios_base::end, ios_base::out);
+    std::cerr << result << std::endl;
+    assert(result == -1);
+
+    // negative off -> fail
+    result = input_buffer.seekoff(-20, ios_base::end, ios_base::in);
+    assert(result == -1);
+
+    // off beyond end of buffer -> fail
+    result = input_buffer.seekoff(1, ios_base::end, ios_base::in);
+    assert(result == -1);
+
+    // passes and moves to buffer size - off
+    result = input_buffer.seekoff(-5, ios_base::end, ios_base::in);
+    assert(result == 5);
+
+    // always from front
+    result = input_buffer.seekoff(-7, ios_base::end, ios_base::in);
+    assert(result == 3);
+
+    // integer overflow due to large off
+    result = input_buffer.seekoff(numeric_limits<long long>::max(), ios_base::end, ios_base::in);
+    assert(result == -1);
+
+    test_buf output_buffer{span<CharT>{buffer}, ios_base::out};
+    // gptr not set but off is 0
+    result = output_buffer.seekoff(0, ios_base::end, ios_base::in);
+    assert(result == 0);
+
+    // newoff is negative -> fail
+    result = output_buffer.seekoff(-10, ios_base::end, ios_base::out);
+    assert(result == -1);
+
+    // pptr not set but off == 0
+    result = output_buffer.seekoff(0, ios_base::end, ios_base::out);
+    assert(result == 0);
+
+    // all fine we stay at end of stream
+    result = output_buffer.seekoff(0, ios_base::end, ios_base::in);
+    assert(result == 0);
+
+    // gptr not set and off != 0 -> fail
+    result = output_buffer.seekoff(1, ios_base::end, ios_base::in);
+    assert(result == -1);
+
+    // off + buffer size is negative -> fail
+    result = output_buffer.seekoff(-20, ios_base::end, ios_base::out);
+    assert(result == -1);
+
+    // off larger than buffer -> fail
+    result = output_buffer.seekoff(11, ios_base::end, ios_base::out);
+    assert(result == -1);
+
+    // passes and moves to buffer size - off
+    result = output_buffer.seekoff(5, ios_base::end, ios_base::out);
+    assert(result == 5);
+
+    // passes we are still below buffer size
+    result = output_buffer.seekoff(3, ios_base::end, ios_base::out);
+    assert(result == 8);
+
+    // moves beyond buffer size -> fails
+    result = output_buffer.seekoff(3, ios_base::end, ios_base::out);
+    assert(result == -1);
+
+    // integer overflow due to large off
+    result = output_buffer.seekoff(numeric_limits<long long>::max(), ios_base::end, ios_base::in);
+    assert(result == -1);
+
+    test_buf inout_buffer{span<CharT>{buffer}, ios_base::in | ios_base::out};
+    // all fine we move to end of stream
+    result = inout_buffer.seekoff(0, ios_base::end, ios_base::in);
+    assert(result == 10);
+
+    // we move to front of the buffer
+    result = inout_buffer.seekoff(-10, ios_base::end, ios_base::out);
+    assert(result == 0);
+
+    // we move to end of buffer
+    result = inout_buffer.seekoff(0, ios_base::end, ios_base::out);
+    assert(result == 10);
+
+    // negative off -> fail
+    result = inout_buffer.seekoff(-20, ios_base::end, ios_base::in);
+    assert(result == -1);
+
+    // off beyond end of buffer -> fail
+    result = inout_buffer.seekoff(1, ios_base::end, ios_base::in);
+    assert(result == -1);
+
+    // passes and moves to buffer size - off
+    result = inout_buffer.seekoff(-5, ios_base::end, ios_base::in);
+    assert(result == 5);
+
+    // always from front
+    result = inout_buffer.seekoff(-7, ios_base::end, ios_base::in);
+    assert(result == 3);
+
+    // integer overflow due to large off
+    result = inout_buffer.seekoff(numeric_limits<long long>::max(), ios_base::end, ios_base::in);
+    assert(result == -1);
+  }
+
+  { // seekoff ios_base::cur
+    CharT buffer[10];
+    test_buf input_buffer{span<CharT>{buffer}, ios_base::in};
+
+    // no mode set -> fail
+    auto result = input_buffer.seekoff(0, ios_base::cur, 0);
+    std::cerr << result << std::endl;
+    assert(result == -1);
+
+    // both in and out modes set -> fail
+    result = input_buffer.seekoff(0, ios_base::cur, ios_base::in | ios_base::out);
+    assert(result == -1);
+
+    // pptr not set and off is != 0 -> fail
+    result = input_buffer.seekoff(1, ios_base::cur, ios_base::out);
+    assert(result == -1);
+
+    // off larger than buffer size -> fail
+    result = input_buffer.seekoff(20, ios_base::cur, ios_base::out);
+    assert(result == -1);
+
+    // off negative -> fail
+    result = input_buffer.seekoff(-1, ios_base::cur, ios_base::out);
+    assert(result == -1);
+
+    // pptr not set but off is == 0
+    result = input_buffer.seekoff(0, ios_base::cur, ios_base::out);
+    assert(result == 0);
+
+    // passes and sets position
+    result = input_buffer.seekoff(3, ios_base::cur, ios_base::in);
+    assert(result == 3);
+
+    // negative off moves back
+    result = input_buffer.seekoff(-2, ios_base::cur, ios_base::in);
+    assert(result == 1);
+
+    // off + current position is beyond buffer size -> fail
+    result = input_buffer.seekoff(10, ios_base::cur, ios_base::in);
+    assert(result == -1);
+
+    test_buf output_buffer{span<CharT>{buffer}, ios_base::out};
+    // no mode set -> fail
+    result = output_buffer.seekoff(0, ios_base::cur, 0);
+    std::cerr << result << std::endl;
+    // assert(result == -1);
+
+    // both in and out modes set -> fail
+    result = output_buffer.seekoff(0, ios_base::cur, ios_base::in | ios_base::out);
+    assert(result == -1);
+
+    // gptr not set and off is != 0 -> fail
+    result = output_buffer.seekoff(1, ios_base::cur, ios_base::in);
+    assert(result == -1);
+
+    // off larger than buffer size -> fail
+    result = output_buffer.seekoff(20, ios_base::cur, ios_base::out);
+    assert(result == -1);
+
+    // off negative -> fail
+    result = output_buffer.seekoff(-1, ios_base::cur, ios_base::out);
+    assert(result == -1);
+
+    // gptr not set but off is == 0
+    result = output_buffer.seekoff(0, ios_base::cur, ios_base::in);
+    assert(result == 0);
+
+    // passes and sets position
+    result = output_buffer.seekoff(3, ios_base::cur, ios_base::out);
+    assert(result == 3);
+
+    // negative off moves back
+    result = output_buffer.seekoff(-2, ios_base::cur, ios_base::out);
+    assert(result == 1);
+
+    // off + current position is beyond buffer size -> fail
+    result = output_buffer.seekoff(10, ios_base::cur, ios_base::out);
+    assert(result == -1);
+
+    test_buf inout_buffer{span<CharT>{buffer}, ios_base::in | ios_base::out};
+    // no mode set -> fail
+    result = inout_buffer.seekoff(0, ios_base::cur, 0);
+    std::cerr << result << std::endl;
+    // assert(result == -1);
+
+    // both in and out modes set -> fail
+    result = inout_buffer.seekoff(0, ios_base::cur, ios_base::in | ios_base::out);
+    assert(result == -1);
+
+    // off larger than buffer size -> fail
+    result = inout_buffer.seekoff(20, ios_base::cur, ios_base::out);
+    assert(result == -1);
+
+    // off negative -> fail
+    result = inout_buffer.seekoff(-1, ios_base::cur, ios_base::out);
+    assert(result == -1);
+
+    // Moves input sequence to position 3
+    result = inout_buffer.seekoff(3, ios_base::cur, ios_base::in);
+    assert(result == 3);
+
+    // Moves output sequence to position 3
+    result = inout_buffer.seekoff(3, ios_base::cur, ios_base::out);
+    assert(result == 3);
+
+    // negative off moves back
+    result = inout_buffer.seekoff(-2, ios_base::cur, ios_base::in);
+    assert(result == 1);
+
+    // negative off moves back
+    result = inout_buffer.seekoff(-2, ios_base::cur, ios_base::out);
+    assert(result == 1);
+
+    // off + current position is beyond buffer size -> fail
+    result = inout_buffer.seekoff(10, ios_base::cur, ios_base::in);
+    assert(result == -1);
+
+    // off + current position is beyond buffer size -> fail
+    result = inout_buffer.seekoff(10, ios_base::cur, ios_base::out);
+    assert(result == -1);
+
+    // off + current position is before buffer size -> fail
+    result = inout_buffer.seekoff(-2, ios_base::cur, ios_base::in);
+    assert(result == -1);
+
+    // off + current position is before buffer size -> fail
+    result = inout_buffer.seekoff(-2, ios_base::cur, ios_base::out);
+    assert(result == -1);
+  }
+
+  { // seekpos (same as seekoff with ios_base::beg)
+    CharT buffer[10];
+    test_buf input_buffer{span<CharT>{buffer}, ios_base::in};
+    test_buf output_buffer{span<CharT>{buffer}, ios_base::out};
+
+    auto result = input_buffer.seekpos(0, ios_base::in);
+    assert(result == 0);
+
+    // pptr not set but off is 0
+    result = input_buffer.seekpos(0, ios_base::out);
+    assert(result == 0);
+
+    // pptr not set and off != 0 -> fail
+    result = input_buffer.seekpos(1, ios_base::out);
+    assert(result == -1);
+
+    // gptr not set but off is 0
+    result = output_buffer.seekpos(0, ios_base::in);
+    assert(result == 0);
+
+    // gptr not set and off != 0 -> fail
+    result = output_buffer.seekpos(1, ios_base::in);
+    assert(result == -1);
+
+    // negative off -> fail
+    result = input_buffer.seekpos(-1, ios_base::in);
+    assert(result == -1);
+
+    // negative off -> fail
+    result = output_buffer.seekpos(-1, ios_base::out);
+    assert(result == -1);
+
+    // off larger than buf -> fail
+    result = input_buffer.seekpos(20, ios_base::in);
+    assert(result == -1);
+
+    // off larger than buf -> fail
+    result = output_buffer.seekpos(20, ios_base::out);
+    assert(result == -1);
+
+    // passes
+    result = input_buffer.seekpos(5, ios_base::in);
+    assert(result == 5);
+
+    result = output_buffer.seekpos(5, ios_base::out);
+    assert(result == 5);
+
+    // always from front
+    result = input_buffer.seekpos(7, ios_base::in);
+    assert(result == 7);
+
+    result = output_buffer.seekpos(7, ios_base::out);
+    assert(result == 7);
+  }
+}
+
+int main(int, char**) {
+#ifndef TEST_HAS_NO_NASTY_STRING
+  // test<nasty_char, nasty_char_traits>();
+#endif
+  test<char>();
+  test<char, constexpr_char_traits<char>>();
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  test<wchar_t>();
+  test<wchar_t, constexpr_char_traits<wchar_t>>();
+#endif
+
+  return 0;
+}

>From 404ce2251eeb03f5f0fb4d78b4b85055cc44daa9 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Tue, 12 Mar 2024 17:39:41 +0200
Subject: [PATCH 36/56] Implementation: `seekoff` no mode is set

---
 libcxx/include/spanstream                                | 9 +++++++++
 .../spanbuf.virtuals/temp_test/temp_test.pass.cpp        | 8 ++++----
 2 files changed, 13 insertions(+), 4 deletions(-)

diff --git a/libcxx/include/spanstream b/libcxx/include/spanstream
index 68d65db9d0afe..ed998566f1541 100644
--- a/libcxx/include/spanstream
+++ b/libcxx/include/spanstream
@@ -166,8 +166,12 @@ protected:
   seekoff(off_type __off, ios_base::seekdir __way, ios_base::openmode __which = ios_base::in | ios_base::out) override {
     const auto __error = static_cast<pos_type>(off_type{-1});
 
+    // Both `in` and `out` modes are set
     if ((__which & ios_base::in) && (__which & ios_base::out) && (ios_base::cur == __way))
       return __error;
+    // No mode is set
+    if (!((__which & ios_base::in) || (__which & ios_base::out)) && (ios_base::cur == __way))
+      return __error;
 
     // Calculate __baseoff
 
@@ -204,6 +208,11 @@ protected:
         std::cmp_greater(__newoff, __buf_.size()))
       return __error;
 
+    // if (((__which & ios_base::in && (this->gptr() == nullptr)) ||
+    //      (__which & ios_base::out && (this->pptr() == nullptr))) &&
+    //     (__newoff != off_type{0}))
+    //   return __error;
+
     if (__which & ios_base::in) {
       if ((this->gptr() == nullptr) && (__newoff != off_type{0}))
         return __error;
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/temp_test/temp_test.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/temp_test/temp_test.pass.cpp
index 33c75ba9b1fa8..8c613e2a26bfd 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/temp_test/temp_test.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/temp_test/temp_test.pass.cpp
@@ -267,12 +267,12 @@ void test() {
 
     // pptr not set but off is == 0
     result = input_buffer.seekoff(-10, ios_base::end, ios_base::out);
-    std::cerr << result << std::endl;
+    // std::cerr << result << std::endl;
     assert(result == 0);
 
     // pptr not set and off != 0 -> fail
     result = input_buffer.seekoff(0, ios_base::end, ios_base::out);
-    std::cerr << result << std::endl;
+    // std::cerr << result << std::endl;
     assert(result == -1);
 
     // negative off -> fail
@@ -419,7 +419,7 @@ void test() {
     // no mode set -> fail
     result = output_buffer.seekoff(0, ios_base::cur, 0);
     std::cerr << result << std::endl;
-    // assert(result == -1);
+    assert(result == -1);
 
     // both in and out modes set -> fail
     result = output_buffer.seekoff(0, ios_base::cur, ios_base::in | ios_base::out);
@@ -457,7 +457,7 @@ void test() {
     // no mode set -> fail
     result = inout_buffer.seekoff(0, ios_base::cur, 0);
     std::cerr << result << std::endl;
-    // assert(result == -1);
+    assert(result == -1);
 
     // both in and out modes set -> fail
     result = inout_buffer.seekoff(0, ios_base::cur, ios_base::in | ios_base::out);

>From 6b906fdcae43709db78d41d5a1ef282a2bed6eaa Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Tue, 12 Mar 2024 21:12:10 +0200
Subject: [PATCH 37/56] Tests: WIP `seekoff.pass`

---
 libcxx/include/spanstream                     |  16 +-
 ...ekoff.off_type.seek_dir.open_mode.pass.cpp |  15 +-
 .../temp_test/temp_test.pass.cpp              | 575 ------------------
 3 files changed, 13 insertions(+), 593 deletions(-)
 delete mode 100644 libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/temp_test/temp_test.pass.cpp

diff --git a/libcxx/include/spanstream b/libcxx/include/spanstream
index ed998566f1541..2b4b6b79d86fd 100644
--- a/libcxx/include/spanstream
+++ b/libcxx/include/spanstream
@@ -70,8 +70,6 @@
 #include <streambuf>
 #include <version>
 
-// #include <print>
-
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
 #endif
@@ -166,14 +164,15 @@ protected:
   seekoff(off_type __off, ios_base::seekdir __way, ios_base::openmode __which = ios_base::in | ios_base::out) override {
     const auto __error = static_cast<pos_type>(off_type{-1});
 
-    // Both `in` and `out` modes are set
+    // Mode: `in` and `out`
     if ((__which & ios_base::in) && (__which & ios_base::out) && (ios_base::cur == __way))
       return __error;
-    // No mode is set
+
+    // Mode: none
     if (!((__which & ios_base::in) || (__which & ios_base::out)) && (ios_base::cur == __way))
       return __error;
 
-    // Calculate __baseoff
+    // Calculate `__baseoff`
 
     std::size_t __baseoff;
 
@@ -200,7 +199,7 @@ protected:
       return __error;
     };
 
-    // Calculate __newoff
+    // Calculate `__newoff`
 
     off_type __newoff;
 
@@ -208,10 +207,7 @@ protected:
         std::cmp_greater(__newoff, __buf_.size()))
       return __error;
 
-    // if (((__which & ios_base::in && (this->gptr() == nullptr)) ||
-    //      (__which & ios_base::out && (this->pptr() == nullptr))) &&
-    //     (__newoff != off_type{0}))
-    //   return __error;
+    // Set pointers
 
     if (__which & ios_base::in) {
       if ((this->gptr() == nullptr) && (__newoff != off_type{0}))
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekoff.off_type.seek_dir.open_mode.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekoff.off_type.seek_dir.open_mode.pass.cpp
index 3dac603ca1fbe..e5814eaeabe77 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekoff.off_type.seek_dir.open_mode.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekoff.off_type.seek_dir.open_mode.pass.cpp
@@ -182,19 +182,18 @@ void test() {
       assert(spBuf.pubseekoff(999, std::ios_base::cur, std::ios_base::out) == -1);
       assert(spBuf.pubseekoff(999, std::ios_base::end, std::ios_base::out) == -1);
 
-      std::cerr << spBuf.pubseekoff(3, std::ios_base::beg, std::ios_base::in) << std::endl;
-      // assert(spBuf.pubseekoff(3, std::ios_base::beg, std::ios_base::in) == -1);
-      assert(spBuf.pubseekoff(3, std::ios_base::cur, std::ios_base::in) == -1);
-      assert(spBuf.pubseekoff(-3, std::ios_base::end, std::ios_base::in) == -1);
+      assert(spBuf.pubseekoff(3, std::ios_base::beg, std::ios_base::in) == 3);
+      assert(spBuf.pubseekoff(3, std::ios_base::cur, std::ios_base::in) == 6);
+      assert(spBuf.pubseekoff(-3, std::ios_base::end, std::ios_base::in) == 7);
 
       assert(spBuf.pubseekoff(3, std::ios_base::beg, std::ios_base::out) == 3);
       assert(spBuf.pubseekoff(3, std::ios_base::cur, std::ios_base::out) == 6);
-      assert(spBuf.pubseekoff(-3, std::ios_base::end, std::ios_base::out) == 3);
+      assert(spBuf.pubseekoff(-3, std::ios_base::end, std::ios_base::out) == 7);
 
       // Default `in` && `out`
-      assert(spBuf.pubseekoff(3, std::ios_base::beg) == -1);
+      assert(spBuf.pubseekoff(3, std::ios_base::beg) == 3);
       assert(spBuf.pubseekoff(3, std::ios_base::cur) == -1);
-      assert(spBuf.pubseekoff(-3, std::ios_base::end) == -1);
+      assert(spBuf.pubseekoff(-3, std::ios_base::end) == 7);
     }
     // Mode: `in`
     {
@@ -244,7 +243,7 @@ void test() {
       // Default `in` && `out`
       assert(spBuf.pubseekoff(3, std::ios_base::beg) == -1);
       assert(spBuf.pubseekoff(3, std::ios_base::cur) == -1);
-      assert(spBuf.pubseekoff(-3, std::ios_base::end) == -1);
+      assert(spBuf.pubseekoff(-3, std::ios_base::end) == 0);
     }
     // Mode: multiple
     {
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/temp_test/temp_test.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/temp_test/temp_test.pass.cpp
deleted file mode 100644
index 8c613e2a26bfd..0000000000000
--- a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/temp_test/temp_test.pass.cpp
+++ /dev/null
@@ -1,575 +0,0 @@
-#include <algorithm>
-#include <array>
-#include <cassert>
-#include <ios>
-#include <limits>
-#include <span>
-#include <spanstream>
-#include <string_view>
-#include <type_traits>
-#include <utility>
-
-#include <algorithm>
-#include <cassert>
-#include <span>
-#include <spanstream>
-
-#include "constexpr_char_traits.h"
-#include "nasty_string.h"
-#include "test_macros.h"
-
-#include <iostream>
-
-using namespace std;
-
-template <class Spanbuf>
-class basic_test_buf : public Spanbuf {
-public:
-  using Spanbuf::Spanbuf;
-
-  using Spanbuf::eback;
-  using Spanbuf::egptr;
-  using Spanbuf::epptr;
-  using Spanbuf::gptr;
-  using Spanbuf::pbase;
-  using Spanbuf::pptr;
-
-  using Spanbuf::setp;
-
-  using Spanbuf::seekoff;
-  using Spanbuf::seekpos;
-  using Spanbuf::setbuf;
-};
-
-template <typename CharT, typename TraitsT = std::char_traits<CharT>>
-void test() {
-  using test_buf = basic_test_buf<basic_spanbuf<CharT>>;
-  { // construction
-    CharT buffer[10];
-    const test_buf default_constructed{};
-    assert(default_constructed.span().data() == nullptr);
-    assert(default_constructed.eback() == nullptr);
-    assert(default_constructed.gptr() == nullptr);
-    assert(default_constructed.egptr() == nullptr);
-    assert(default_constructed.pbase() == nullptr);
-    assert(default_constructed.pptr() == nullptr);
-    assert(default_constructed.epptr() == nullptr);
-
-    const test_buf mode_constructed{ios_base::in};
-    assert(mode_constructed.span().data() == nullptr);
-    assert(mode_constructed.eback() == nullptr);
-    assert(mode_constructed.gptr() == nullptr);
-    assert(mode_constructed.egptr() == nullptr);
-    assert(mode_constructed.pbase() == nullptr);
-    assert(mode_constructed.pptr() == nullptr);
-    assert(mode_constructed.epptr() == nullptr);
-
-    test_buf span_constructed{span<CharT>{buffer}};
-    assert(span_constructed.span().data() == buffer);
-    assert(span_constructed.eback() == buffer);
-    assert(span_constructed.gptr() == buffer);
-    // assert(span_constructed.egptr() == std::end(buffer));
-    assert(span_constructed.pbase() == buffer);
-    assert(span_constructed.pptr() == buffer);
-    // assert(span_constructed.epptr() == std::end(buffer));
-
-    const test_buf span_mode_in_constructed{span<CharT>{buffer}, ios_base::in};
-    assert(span_mode_in_constructed.span().data() == buffer);
-    assert(span_mode_in_constructed.eback() == buffer);
-    assert(span_mode_in_constructed.gptr() == buffer);
-    // assert(span_mode_in_constructed.egptr() == std::end(buffer));
-    assert(span_mode_in_constructed.pbase() == nullptr);
-    assert(span_mode_in_constructed.pptr() == nullptr);
-    assert(span_mode_in_constructed.epptr() == nullptr);
-
-    const test_buf span_mode_in_ate_constructed{span<CharT>{buffer}, ios_base::in | ios_base::ate};
-    assert(span_mode_in_ate_constructed.span().data() == buffer);
-    assert(span_mode_in_ate_constructed.eback() == buffer);
-    assert(span_mode_in_ate_constructed.gptr() == buffer);
-    // assert(span_mode_in_ate_constructed.egptr() == std::end(buffer));
-    assert(span_mode_in_ate_constructed.pbase() == nullptr);
-    assert(span_mode_in_ate_constructed.pptr() == nullptr);
-    assert(span_mode_in_ate_constructed.epptr() == nullptr);
-
-    const test_buf span_mode_out_constructed{span<CharT>{buffer}, ios_base::out};
-    assert(span_mode_out_constructed.span().data() == buffer);
-    assert(span_mode_out_constructed.eback() == nullptr);
-    assert(span_mode_out_constructed.gptr() == nullptr);
-    assert(span_mode_out_constructed.egptr() == nullptr);
-    assert(span_mode_out_constructed.pbase() == buffer);
-    assert(span_mode_out_constructed.pptr() == buffer);
-    assert(span_mode_out_constructed.epptr() == std::end(buffer));
-
-    const test_buf span_mode_out_ate_constructed{span<CharT>{buffer}, ios_base::out | ios_base::ate};
-    assert(span_mode_out_ate_constructed.span().data() == buffer);
-    assert(span_mode_out_ate_constructed.eback() == nullptr);
-    assert(span_mode_out_ate_constructed.gptr() == nullptr);
-    assert(span_mode_out_ate_constructed.egptr() == nullptr);
-    assert(span_mode_out_ate_constructed.pbase() == buffer);
-    // assert(span_mode_out_ate_constructed.pptr() == std::end(buffer));
-    // assert(span_mode_out_ate_constructed.epptr() == std::end(buffer));
-
-    const test_buf span_mode_unknown_constructed{span<CharT>{buffer}, 0};
-    assert(span_mode_unknown_constructed.span().data() == buffer);
-    assert(span_mode_unknown_constructed.eback() == nullptr);
-    assert(span_mode_unknown_constructed.gptr() == nullptr);
-    assert(span_mode_unknown_constructed.egptr() == nullptr);
-    assert(span_mode_unknown_constructed.pbase() == nullptr);
-    assert(span_mode_unknown_constructed.pptr() == nullptr);
-    assert(span_mode_unknown_constructed.epptr() == nullptr);
-#if 0
-    test_buf move_constructed{std::move(span_constructed)};
-    assert(move_constructed.span().data() == buffer);
-    assert(move_constructed.eback() == buffer);
-    assert(move_constructed.gptr() == buffer);
-    // assert(move_constructed.egptr() == std::end(buffer));
-    assert(move_constructed.pbase() == buffer);
-    assert(move_constructed.pptr() == buffer);
-    // assert(move_constructed.epptr() == std::end(buffer));
-    assert(span_constructed.span().data() == nullptr);
-    assert(span_constructed.eback() == nullptr);
-    assert(span_constructed.gptr() == nullptr);
-    assert(span_constructed.egptr() == nullptr);
-    assert(span_constructed.pbase() == nullptr);
-    assert(span_constructed.pptr() == nullptr);
-    assert(span_constructed.epptr() == nullptr);
-
-    test_buf move_assigned;
-    move_assigned = std::move(move_constructed);
-    assert(move_assigned.span().data() == buffer);
-    assert(move_assigned.eback() == buffer);
-    assert(move_assigned.gptr() == buffer);
-    // assert(move_assigned.egptr() == std::end(buffer));
-    assert(move_assigned.pbase() == buffer);
-    assert(move_assigned.pptr() == buffer);
-    // assert(move_assigned.epptr() == std::end(buffer));
-    assert(move_constructed.span().data() == nullptr);
-    assert(move_constructed.eback() == nullptr);
-    assert(move_constructed.gptr() == nullptr);
-    assert(move_constructed.egptr() == nullptr);
-    assert(move_constructed.pbase() == nullptr);
-    assert(move_constructed.pptr() == nullptr);
-    assert(move_constructed.epptr() == nullptr);
-#endif
-  }
-
-  // { // swap
-  //   CharT buffer1[10];
-  //   CharT buffer2[20];
-  //   test_buf first{span<CharT>{buffer1}};
-  //   test_buf second{span<CharT>{buffer2}};
-  //   assert(first.span().data() == buffer1);
-  //   assert(second.span().data() == buffer2);
-
-  //   first.swap(second);
-  //   assert(first.span().data() == buffer2);
-  //   assert(second.span().data() == buffer1);
-
-  //   swap(first, second);
-  //   assert(first.span().data() == buffer1);
-  //   assert(second.span().data() == buffer2);
-  // }
-
-  // { // span, span, span, span
-  //   CharT buffer1[10];
-  //   test_buf input_buffer{span<CharT>{buffer1}, ios_base::in};
-  //   assert(input_buffer.span().data() == buffer1);
-  //   assert(input_buffer.span().size() == std::size(buffer1));
-
-  //   test_buf output_buffer{span<CharT>{buffer1}, ios_base::out};
-  //   assert(output_buffer.span().data() == buffer1);
-  //   assert(output_buffer.span().size() == 0); // counts the written characters
-
-  //   // Manually move the written pointer
-  //   output_buffer.setp(buffer1, buffer1 + 5, std::end(buffer1));
-  //   assert(output_buffer.span().data() == buffer1);
-  //   assert(output_buffer.span().size() == 5);
-
-  //   CharT buffer2[10];
-  //   input_buffer.span(span<CharT>{buffer2});
-  //   assert(input_buffer.span().data() == buffer2);
-  //   assert(input_buffer.span().size() == std::size(buffer2));
-
-  //   output_buffer.span(span<CharT>{buffer2});
-  //   assert(output_buffer.span().data() == buffer2);
-  //   assert(output_buffer.span().size() == 0);
-
-  //   test_buf hungry_buffer{span<CharT>{buffer1}, ios_base::out | ios_base::ate};
-  //   assert(hungry_buffer.span().data() == buffer1);
-  //   assert(hungry_buffer.span().size() == std::size(buffer1));
-
-  //   hungry_buffer.span(span<CharT>{buffer2});
-  //   assert(hungry_buffer.span().data() == buffer2);
-  //   assert(hungry_buffer.span().size() == std::size(buffer2));
-  // }
-
-  { // seekoff ios_base::beg
-    CharT buffer[10];
-    test_buf input_buffer{span<CharT>{buffer}, ios_base::in};
-    test_buf output_buffer{span<CharT>{buffer}, ios_base::out};
-
-    auto result = input_buffer.seekoff(0, ios_base::beg, ios_base::in);
-    assert(result == 0);
-
-    // pptr not set but off is 0
-    result = input_buffer.seekoff(0, ios_base::beg, ios_base::out);
-    assert(result == 0);
-
-    // pptr not set and off != 0 -> fail
-    result = input_buffer.seekoff(1, ios_base::beg, ios_base::out);
-    assert(result == -1);
-
-    // gptr not set but off is 0
-    result = output_buffer.seekoff(0, ios_base::beg, ios_base::in);
-    assert(result == 0);
-
-    // gptr not set and off != 0 -> fail
-    result = output_buffer.seekoff(1, ios_base::beg, ios_base::in);
-    assert(result == -1);
-
-    // negative off -> fail
-    result = input_buffer.seekoff(-1, ios_base::beg, ios_base::in);
-    assert(result == -1);
-
-    // negative off -> fail
-    result = output_buffer.seekoff(-1, ios_base::beg, ios_base::out);
-    assert(result == -1);
-
-    // off larger than buf -> fail
-    result = input_buffer.seekoff(20, ios_base::beg, ios_base::in);
-    assert(result == -1);
-
-    // off larger than buf -> fail
-    result = output_buffer.seekoff(20, ios_base::beg, ios_base::out);
-    assert(result == -1);
-
-    // passes
-    result = input_buffer.seekoff(5, ios_base::beg, ios_base::in);
-    assert(result == 5);
-
-    result = output_buffer.seekoff(5, ios_base::beg, ios_base::out);
-    assert(result == 5);
-
-    // always from front
-    result = input_buffer.seekoff(7, ios_base::beg, ios_base::in);
-    assert(result == 7);
-
-    result = output_buffer.seekoff(7, ios_base::beg, ios_base::out);
-    assert(result == 7);
-  }
-
-  { // seekoff ios_base::end
-    CharT buffer[10];
-    test_buf input_buffer{span<CharT>{buffer}, ios_base::in};
-    // all fine we move to end of stream
-    auto result = input_buffer.seekoff(0, ios_base::end, ios_base::in);
-    assert(result == 10);
-
-    // pptr not set but off is == 0
-    result = input_buffer.seekoff(-10, ios_base::end, ios_base::out);
-    // std::cerr << result << std::endl;
-    assert(result == 0);
-
-    // pptr not set and off != 0 -> fail
-    result = input_buffer.seekoff(0, ios_base::end, ios_base::out);
-    // std::cerr << result << std::endl;
-    assert(result == -1);
-
-    // negative off -> fail
-    result = input_buffer.seekoff(-20, ios_base::end, ios_base::in);
-    assert(result == -1);
-
-    // off beyond end of buffer -> fail
-    result = input_buffer.seekoff(1, ios_base::end, ios_base::in);
-    assert(result == -1);
-
-    // passes and moves to buffer size - off
-    result = input_buffer.seekoff(-5, ios_base::end, ios_base::in);
-    assert(result == 5);
-
-    // always from front
-    result = input_buffer.seekoff(-7, ios_base::end, ios_base::in);
-    assert(result == 3);
-
-    // integer overflow due to large off
-    result = input_buffer.seekoff(numeric_limits<long long>::max(), ios_base::end, ios_base::in);
-    assert(result == -1);
-
-    test_buf output_buffer{span<CharT>{buffer}, ios_base::out};
-    // gptr not set but off is 0
-    result = output_buffer.seekoff(0, ios_base::end, ios_base::in);
-    assert(result == 0);
-
-    // newoff is negative -> fail
-    result = output_buffer.seekoff(-10, ios_base::end, ios_base::out);
-    assert(result == -1);
-
-    // pptr not set but off == 0
-    result = output_buffer.seekoff(0, ios_base::end, ios_base::out);
-    assert(result == 0);
-
-    // all fine we stay at end of stream
-    result = output_buffer.seekoff(0, ios_base::end, ios_base::in);
-    assert(result == 0);
-
-    // gptr not set and off != 0 -> fail
-    result = output_buffer.seekoff(1, ios_base::end, ios_base::in);
-    assert(result == -1);
-
-    // off + buffer size is negative -> fail
-    result = output_buffer.seekoff(-20, ios_base::end, ios_base::out);
-    assert(result == -1);
-
-    // off larger than buffer -> fail
-    result = output_buffer.seekoff(11, ios_base::end, ios_base::out);
-    assert(result == -1);
-
-    // passes and moves to buffer size - off
-    result = output_buffer.seekoff(5, ios_base::end, ios_base::out);
-    assert(result == 5);
-
-    // passes we are still below buffer size
-    result = output_buffer.seekoff(3, ios_base::end, ios_base::out);
-    assert(result == 8);
-
-    // moves beyond buffer size -> fails
-    result = output_buffer.seekoff(3, ios_base::end, ios_base::out);
-    assert(result == -1);
-
-    // integer overflow due to large off
-    result = output_buffer.seekoff(numeric_limits<long long>::max(), ios_base::end, ios_base::in);
-    assert(result == -1);
-
-    test_buf inout_buffer{span<CharT>{buffer}, ios_base::in | ios_base::out};
-    // all fine we move to end of stream
-    result = inout_buffer.seekoff(0, ios_base::end, ios_base::in);
-    assert(result == 10);
-
-    // we move to front of the buffer
-    result = inout_buffer.seekoff(-10, ios_base::end, ios_base::out);
-    assert(result == 0);
-
-    // we move to end of buffer
-    result = inout_buffer.seekoff(0, ios_base::end, ios_base::out);
-    assert(result == 10);
-
-    // negative off -> fail
-    result = inout_buffer.seekoff(-20, ios_base::end, ios_base::in);
-    assert(result == -1);
-
-    // off beyond end of buffer -> fail
-    result = inout_buffer.seekoff(1, ios_base::end, ios_base::in);
-    assert(result == -1);
-
-    // passes and moves to buffer size - off
-    result = inout_buffer.seekoff(-5, ios_base::end, ios_base::in);
-    assert(result == 5);
-
-    // always from front
-    result = inout_buffer.seekoff(-7, ios_base::end, ios_base::in);
-    assert(result == 3);
-
-    // integer overflow due to large off
-    result = inout_buffer.seekoff(numeric_limits<long long>::max(), ios_base::end, ios_base::in);
-    assert(result == -1);
-  }
-
-  { // seekoff ios_base::cur
-    CharT buffer[10];
-    test_buf input_buffer{span<CharT>{buffer}, ios_base::in};
-
-    // no mode set -> fail
-    auto result = input_buffer.seekoff(0, ios_base::cur, 0);
-    std::cerr << result << std::endl;
-    assert(result == -1);
-
-    // both in and out modes set -> fail
-    result = input_buffer.seekoff(0, ios_base::cur, ios_base::in | ios_base::out);
-    assert(result == -1);
-
-    // pptr not set and off is != 0 -> fail
-    result = input_buffer.seekoff(1, ios_base::cur, ios_base::out);
-    assert(result == -1);
-
-    // off larger than buffer size -> fail
-    result = input_buffer.seekoff(20, ios_base::cur, ios_base::out);
-    assert(result == -1);
-
-    // off negative -> fail
-    result = input_buffer.seekoff(-1, ios_base::cur, ios_base::out);
-    assert(result == -1);
-
-    // pptr not set but off is == 0
-    result = input_buffer.seekoff(0, ios_base::cur, ios_base::out);
-    assert(result == 0);
-
-    // passes and sets position
-    result = input_buffer.seekoff(3, ios_base::cur, ios_base::in);
-    assert(result == 3);
-
-    // negative off moves back
-    result = input_buffer.seekoff(-2, ios_base::cur, ios_base::in);
-    assert(result == 1);
-
-    // off + current position is beyond buffer size -> fail
-    result = input_buffer.seekoff(10, ios_base::cur, ios_base::in);
-    assert(result == -1);
-
-    test_buf output_buffer{span<CharT>{buffer}, ios_base::out};
-    // no mode set -> fail
-    result = output_buffer.seekoff(0, ios_base::cur, 0);
-    std::cerr << result << std::endl;
-    assert(result == -1);
-
-    // both in and out modes set -> fail
-    result = output_buffer.seekoff(0, ios_base::cur, ios_base::in | ios_base::out);
-    assert(result == -1);
-
-    // gptr not set and off is != 0 -> fail
-    result = output_buffer.seekoff(1, ios_base::cur, ios_base::in);
-    assert(result == -1);
-
-    // off larger than buffer size -> fail
-    result = output_buffer.seekoff(20, ios_base::cur, ios_base::out);
-    assert(result == -1);
-
-    // off negative -> fail
-    result = output_buffer.seekoff(-1, ios_base::cur, ios_base::out);
-    assert(result == -1);
-
-    // gptr not set but off is == 0
-    result = output_buffer.seekoff(0, ios_base::cur, ios_base::in);
-    assert(result == 0);
-
-    // passes and sets position
-    result = output_buffer.seekoff(3, ios_base::cur, ios_base::out);
-    assert(result == 3);
-
-    // negative off moves back
-    result = output_buffer.seekoff(-2, ios_base::cur, ios_base::out);
-    assert(result == 1);
-
-    // off + current position is beyond buffer size -> fail
-    result = output_buffer.seekoff(10, ios_base::cur, ios_base::out);
-    assert(result == -1);
-
-    test_buf inout_buffer{span<CharT>{buffer}, ios_base::in | ios_base::out};
-    // no mode set -> fail
-    result = inout_buffer.seekoff(0, ios_base::cur, 0);
-    std::cerr << result << std::endl;
-    assert(result == -1);
-
-    // both in and out modes set -> fail
-    result = inout_buffer.seekoff(0, ios_base::cur, ios_base::in | ios_base::out);
-    assert(result == -1);
-
-    // off larger than buffer size -> fail
-    result = inout_buffer.seekoff(20, ios_base::cur, ios_base::out);
-    assert(result == -1);
-
-    // off negative -> fail
-    result = inout_buffer.seekoff(-1, ios_base::cur, ios_base::out);
-    assert(result == -1);
-
-    // Moves input sequence to position 3
-    result = inout_buffer.seekoff(3, ios_base::cur, ios_base::in);
-    assert(result == 3);
-
-    // Moves output sequence to position 3
-    result = inout_buffer.seekoff(3, ios_base::cur, ios_base::out);
-    assert(result == 3);
-
-    // negative off moves back
-    result = inout_buffer.seekoff(-2, ios_base::cur, ios_base::in);
-    assert(result == 1);
-
-    // negative off moves back
-    result = inout_buffer.seekoff(-2, ios_base::cur, ios_base::out);
-    assert(result == 1);
-
-    // off + current position is beyond buffer size -> fail
-    result = inout_buffer.seekoff(10, ios_base::cur, ios_base::in);
-    assert(result == -1);
-
-    // off + current position is beyond buffer size -> fail
-    result = inout_buffer.seekoff(10, ios_base::cur, ios_base::out);
-    assert(result == -1);
-
-    // off + current position is before buffer size -> fail
-    result = inout_buffer.seekoff(-2, ios_base::cur, ios_base::in);
-    assert(result == -1);
-
-    // off + current position is before buffer size -> fail
-    result = inout_buffer.seekoff(-2, ios_base::cur, ios_base::out);
-    assert(result == -1);
-  }
-
-  { // seekpos (same as seekoff with ios_base::beg)
-    CharT buffer[10];
-    test_buf input_buffer{span<CharT>{buffer}, ios_base::in};
-    test_buf output_buffer{span<CharT>{buffer}, ios_base::out};
-
-    auto result = input_buffer.seekpos(0, ios_base::in);
-    assert(result == 0);
-
-    // pptr not set but off is 0
-    result = input_buffer.seekpos(0, ios_base::out);
-    assert(result == 0);
-
-    // pptr not set and off != 0 -> fail
-    result = input_buffer.seekpos(1, ios_base::out);
-    assert(result == -1);
-
-    // gptr not set but off is 0
-    result = output_buffer.seekpos(0, ios_base::in);
-    assert(result == 0);
-
-    // gptr not set and off != 0 -> fail
-    result = output_buffer.seekpos(1, ios_base::in);
-    assert(result == -1);
-
-    // negative off -> fail
-    result = input_buffer.seekpos(-1, ios_base::in);
-    assert(result == -1);
-
-    // negative off -> fail
-    result = output_buffer.seekpos(-1, ios_base::out);
-    assert(result == -1);
-
-    // off larger than buf -> fail
-    result = input_buffer.seekpos(20, ios_base::in);
-    assert(result == -1);
-
-    // off larger than buf -> fail
-    result = output_buffer.seekpos(20, ios_base::out);
-    assert(result == -1);
-
-    // passes
-    result = input_buffer.seekpos(5, ios_base::in);
-    assert(result == 5);
-
-    result = output_buffer.seekpos(5, ios_base::out);
-    assert(result == 5);
-
-    // always from front
-    result = input_buffer.seekpos(7, ios_base::in);
-    assert(result == 7);
-
-    result = output_buffer.seekpos(7, ios_base::out);
-    assert(result == 7);
-  }
-}
-
-int main(int, char**) {
-#ifndef TEST_HAS_NO_NASTY_STRING
-  // test<nasty_char, nasty_char_traits>();
-#endif
-  test<char>();
-  test<char, constexpr_char_traits<char>>();
-#ifndef TEST_HAS_NO_WIDE_CHARACTERS
-  test<wchar_t>();
-  test<wchar_t, constexpr_char_traits<wchar_t>>();
-#endif
-
-  return 0;
-}

>From 22c6525314f5b36f901eca6386e504b904125db3 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Wed, 13 Mar 2024 11:41:35 +0200
Subject: [PATCH 38/56] Tests: `seekoff.off_type.seek_dir.open_mode.pass`

---
 ...ekoff.off_type.seek_dir.open_mode.pass.cpp | 236 +++++++++++-------
 1 file changed, 144 insertions(+), 92 deletions(-)

diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekoff.off_type.seek_dir.open_mode.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekoff.off_type.seek_dir.open_mode.pass.cpp
index e5814eaeabe77..ce9fd90f6e7c3 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekoff.off_type.seek_dir.open_mode.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekoff.off_type.seek_dir.open_mode.pass.cpp
@@ -28,27 +28,30 @@
 #include "nasty_string.h"
 #include "test_macros.h"
 
-#include <iostream>
+// #include <iostream>
 
 template <typename CharT, typename TraitsT = std::char_traits<CharT>>
 void test() {
   using SpBuf = std::basic_spanbuf<CharT, TraitsT>;
 
+  constexpr auto no_mode = 0;
+
   // Empty `span`
   {
     std::span<CharT> sp;
 
+    // For an empty span:
+    //   -3 is an out-of-range offset value
+    //    0 is an in-range offset value for an empty span
+    //    3 is an out-of-range offset value
+
     // Mode: default (`in` | `out`)
     {
       SpBuf spBuf{sp};
 
-      // Out-of-range
-      assert(spBuf.pubseekoff(-999, std::ios_base::beg, std::ios_base::in) == -1);
-      assert(spBuf.pubseekoff(-999, std::ios_base::cur, std::ios_base::in) == -1);
-      assert(spBuf.pubseekoff(-999, std::ios_base::end, std::ios_base::in) == -1);
-      assert(spBuf.pubseekoff(999, std::ios_base::beg, std::ios_base::out) == -1);
-      assert(spBuf.pubseekoff(999, std::ios_base::cur, std::ios_base::out) == -1);
-      assert(spBuf.pubseekoff(999, std::ios_base::end, std::ios_base::out) == -1);
+      assert(spBuf.pubseekoff(0, std::ios_base::beg, std::ios_base::in) == 0);
+      assert(spBuf.pubseekoff(0, std::ios_base::cur, std::ios_base::in) == 0);
+      assert(spBuf.pubseekoff(0, std::ios_base::end, std::ios_base::in) == 0);
 
       assert(spBuf.pubseekoff(3, std::ios_base::beg, std::ios_base::in) == -1);
       assert(spBuf.pubseekoff(3, std::ios_base::cur, std::ios_base::in) == -1);
@@ -58,48 +61,36 @@ void test() {
       assert(spBuf.pubseekoff(0, std::ios_base::cur, std::ios_base::out) == 0);
       assert(spBuf.pubseekoff(0, std::ios_base::end, std::ios_base::out) == 0);
 
-      // Default `in` && `out`
+      assert(spBuf.pubseekoff(3, std::ios_base::beg, std::ios_base::out) == -1);
+      assert(spBuf.pubseekoff(3, std::ios_base::cur, std::ios_base::out) == -1);
+      assert(spBuf.pubseekoff(-3, std::ios_base::end, std::ios_base::out) == -1);
+
+      // Default parameter value `openmode`
+      assert(spBuf.pubseekoff(0, std::ios_base::beg) == 0);
+      assert(spBuf.pubseekoff(0, std::ios_base::cur) == -1);
+      assert(spBuf.pubseekoff(0, std::ios_base::end) == 0);
+
       assert(spBuf.pubseekoff(3, std::ios_base::beg) == -1);
       assert(spBuf.pubseekoff(3, std::ios_base::cur) == -1);
       assert(spBuf.pubseekoff(-3, std::ios_base::end) == -1);
+
+      // No mode
+      assert(spBuf.pubseekoff(0, std::ios_base::beg, no_mode) == 0);
+      assert(spBuf.pubseekoff(0, std::ios_base::cur, no_mode) == -1);
+      assert(spBuf.pubseekoff(0, std::ios_base::end, no_mode) == 0);
+
+      assert(spBuf.pubseekoff(3, std::ios_base::beg, no_mode) == -1);
+      assert(spBuf.pubseekoff(3, std::ios_base::cur, no_mode) == -1);
+      assert(spBuf.pubseekoff(-1, std::ios_base::end, no_mode) == -1);
     }
     // Mode: `in`
     {
       SpBuf spBuf{sp, std::ios_base::in};
 
-      // Out-of-range
-      assert(spBuf.pubseekoff(-999, std::ios_base::beg, std::ios_base::out) == -1);
-      assert(spBuf.pubseekoff(-999, std::ios_base::cur, std::ios_base::out) == -1);
-      assert(spBuf.pubseekoff(-999, std::ios_base::end, std::ios_base::out) == -1);
-      assert(spBuf.pubseekoff(999, std::ios_base::beg, std::ios_base::out) == -1);
-      assert(spBuf.pubseekoff(999, std::ios_base::cur, std::ios_base::out) == -1);
-      assert(spBuf.pubseekoff(999, std::ios_base::end, std::ios_base::out) == -1);
-
       assert(spBuf.pubseekoff(0, std::ios_base::beg, std::ios_base::in) == 0);
       assert(spBuf.pubseekoff(0, std::ios_base::cur, std::ios_base::in) == 0);
       assert(spBuf.pubseekoff(0, std::ios_base::end, std::ios_base::in) == 0);
 
-      assert(spBuf.pubseekoff(3, std::ios_base::beg, std::ios_base::out) == -1);
-      assert(spBuf.pubseekoff(3, std::ios_base::cur, std::ios_base::out) == -1);
-      assert(spBuf.pubseekoff(-3, std::ios_base::end, std::ios_base::out) == -1);
-
-      // Default `in` && `out`
-      assert(spBuf.pubseekoff(3, std::ios_base::beg) == -1);
-      assert(spBuf.pubseekoff(3, std::ios_base::cur) == -1);
-      assert(spBuf.pubseekoff(-3, std::ios_base::end) == -1);
-    }
-    // Mode: `out`
-    {
-      SpBuf spBuf{sp, std::ios_base::out};
-
-      // Out-of-range
-      assert(spBuf.pubseekoff(-999, std::ios_base::beg, std::ios_base::out) == -1);
-      assert(spBuf.pubseekoff(-999, std::ios_base::cur, std::ios_base::out) == -1);
-      assert(spBuf.pubseekoff(-999, std::ios_base::end, std::ios_base::out) == -1);
-      assert(spBuf.pubseekoff(999, std::ios_base::beg, std::ios_base::out) == -1);
-      assert(spBuf.pubseekoff(999, std::ios_base::cur, std::ios_base::out) == -1);
-      assert(spBuf.pubseekoff(999, std::ios_base::end, std::ios_base::out) == -1);
-
       assert(spBuf.pubseekoff(3, std::ios_base::beg, std::ios_base::in) == -1);
       assert(spBuf.pubseekoff(3, std::ios_base::cur, std::ios_base::in) == -1);
       assert(spBuf.pubseekoff(-3, std::ios_base::end, std::ios_base::in) == -1);
@@ -108,22 +99,35 @@ void test() {
       assert(spBuf.pubseekoff(0, std::ios_base::cur, std::ios_base::out) == 0);
       assert(spBuf.pubseekoff(0, std::ios_base::end, std::ios_base::out) == 0);
 
-      // Default `in` && `out`
+      assert(spBuf.pubseekoff(3, std::ios_base::beg, std::ios_base::out) == -1);
+      assert(spBuf.pubseekoff(3, std::ios_base::cur, std::ios_base::out) == -1);
+      assert(spBuf.pubseekoff(-3, std::ios_base::end, std::ios_base::out) == -1);
+
+      // Default parameter value `openmode`
+      assert(spBuf.pubseekoff(0, std::ios_base::beg) == 0);
+      assert(spBuf.pubseekoff(0, std::ios_base::cur) == -1); // ???
+      assert(spBuf.pubseekoff(0, std::ios_base::end) == 0);
+
       assert(spBuf.pubseekoff(3, std::ios_base::beg) == -1);
       assert(spBuf.pubseekoff(3, std::ios_base::cur) == -1);
       assert(spBuf.pubseekoff(-3, std::ios_base::end) == -1);
+
+      // No mode
+      assert(spBuf.pubseekoff(0, std::ios_base::beg, no_mode) == 0);
+      assert(spBuf.pubseekoff(0, std::ios_base::cur, no_mode) == -1);
+      assert(spBuf.pubseekoff(0, std::ios_base::end, no_mode) == 0);
+
+      assert(spBuf.pubseekoff(3, std::ios_base::beg, no_mode) == -1);
+      assert(spBuf.pubseekoff(3, std::ios_base::cur, no_mode) == -1);
+      assert(spBuf.pubseekoff(-3, std::ios_base::end, no_mode) == -1);
     }
-    // Mode: `multiple`
+    // Mode: `out`
     {
-      SpBuf spBuf{sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary};
+      SpBuf spBuf{sp, std::ios_base::out};
 
-      // Out-of-range
-      assert(spBuf.pubseekoff(-999, std::ios_base::beg, std::ios_base::out) == -1);
-      assert(spBuf.pubseekoff(-999, std::ios_base::cur, std::ios_base::out) == -1);
-      assert(spBuf.pubseekoff(-999, std::ios_base::end, std::ios_base::out) == -1);
-      assert(spBuf.pubseekoff(999, std::ios_base::beg, std::ios_base::out) == -1);
-      assert(spBuf.pubseekoff(999, std::ios_base::cur, std::ios_base::out) == -1);
-      assert(spBuf.pubseekoff(999, std::ios_base::end, std::ios_base::out) == -1);
+      assert(spBuf.pubseekoff(0, std::ios_base::beg, std::ios_base::in) == 0);
+      assert(spBuf.pubseekoff(0, std::ios_base::cur, std::ios_base::in) == 0);
+      assert(spBuf.pubseekoff(0, std::ios_base::end, std::ios_base::in) == 0);
 
       assert(spBuf.pubseekoff(3, std::ios_base::beg, std::ios_base::in) == -1);
       assert(spBuf.pubseekoff(3, std::ios_base::cur, std::ios_base::in) == -1);
@@ -133,35 +137,27 @@ void test() {
       assert(spBuf.pubseekoff(0, std::ios_base::cur, std::ios_base::out) == 0);
       assert(spBuf.pubseekoff(0, std::ios_base::end, std::ios_base::out) == 0);
 
-      // Default `in` && `out`
-      assert(spBuf.pubseekoff(3, std::ios_base::beg) == -1);
-      assert(spBuf.pubseekoff(3, std::ios_base::cur) == -1);
-      assert(spBuf.pubseekoff(-3, std::ios_base::end) == -1);
-    }
-    // Mode: `ate`
-    {
-      SpBuf spBuf{sp, std::ios_base::out | std::ios_base::ate};
-
-      // Out-of-range
-      assert(spBuf.pubseekoff(-999, std::ios_base::beg, std::ios_base::out) == -1);
-      assert(spBuf.pubseekoff(-999, std::ios_base::cur, std::ios_base::out) == -1);
-      assert(spBuf.pubseekoff(-999, std::ios_base::end, std::ios_base::out) == -1);
-      assert(spBuf.pubseekoff(999, std::ios_base::beg, std::ios_base::out) == -1);
-      assert(spBuf.pubseekoff(999, std::ios_base::cur, std::ios_base::out) == -1);
-      assert(spBuf.pubseekoff(999, std::ios_base::end, std::ios_base::out) == -1);
-
-      assert(spBuf.pubseekoff(0, std::ios_base::beg, std::ios_base::in) == 0);
-      assert(spBuf.pubseekoff(0, std::ios_base::cur, std::ios_base::in) == 0);
-      assert(spBuf.pubseekoff(0, std::ios_base::end, std::ios_base::in) == 0);
-
       assert(spBuf.pubseekoff(3, std::ios_base::beg, std::ios_base::out) == -1);
       assert(spBuf.pubseekoff(3, std::ios_base::cur, std::ios_base::out) == -1);
       assert(spBuf.pubseekoff(-3, std::ios_base::end, std::ios_base::out) == -1);
 
-      // Default `in` && `out`
+      // Default parameter value `openmode`
+      assert(spBuf.pubseekoff(0, std::ios_base::beg) == 0);
+      assert(spBuf.pubseekoff(0, std::ios_base::cur) == -1); // ???
+      assert(spBuf.pubseekoff(0, std::ios_base::end) == 0);
+
       assert(spBuf.pubseekoff(3, std::ios_base::beg) == -1);
       assert(spBuf.pubseekoff(3, std::ios_base::cur) == -1);
       assert(spBuf.pubseekoff(-3, std::ios_base::end) == -1);
+
+      // No mode
+      assert(spBuf.pubseekoff(0, std::ios_base::beg, no_mode) == 0);
+      assert(spBuf.pubseekoff(0, std::ios_base::cur, no_mode) == -1);
+      assert(spBuf.pubseekoff(0, std::ios_base::end, no_mode) == 0);
+
+      assert(spBuf.pubseekoff(3, std::ios_base::beg, no_mode) == -1);
+      assert(spBuf.pubseekoff(3, std::ios_base::cur, no_mode) == -1);
+      assert(spBuf.pubseekoff(-3, std::ios_base::end, no_mode) == -1);
     }
   }
 
@@ -170,6 +166,10 @@ void test() {
     CharT arr[10];
     std::span sp{arr};
 
+    // For an empty span:
+    //   -999 is an out-of-range offset value
+    //    999 is an out-of-range offset value
+
     // Mode: default (`in` | `out`)
     {
       SpBuf spBuf{sp};
@@ -182,18 +182,43 @@ void test() {
       assert(spBuf.pubseekoff(999, std::ios_base::cur, std::ios_base::out) == -1);
       assert(spBuf.pubseekoff(999, std::ios_base::end, std::ios_base::out) == -1);
 
+      // In-range
+      assert(spBuf.pubseekoff(0, std::ios_base::beg, std::ios_base::in) == 0);
+      assert(spBuf.pubseekoff(0, std::ios_base::cur, std::ios_base::in) == 0);
+      // std::cerr << spBuf.pubseekoff(0, std::ios_base::end, std::ios_base::in) << std::endl;
+      assert(spBuf.pubseekoff(0, std::ios_base::end, std::ios_base::in) == 10); // ???
+
       assert(spBuf.pubseekoff(3, std::ios_base::beg, std::ios_base::in) == 3);
       assert(spBuf.pubseekoff(3, std::ios_base::cur, std::ios_base::in) == 6);
       assert(spBuf.pubseekoff(-3, std::ios_base::end, std::ios_base::in) == 7);
 
+      assert(spBuf.pubseekoff(0, std::ios_base::beg, std::ios_base::out) == 0);
+      assert(spBuf.pubseekoff(0, std::ios_base::cur, std::ios_base::out) == 0);
+      // std::cerr << spBuf.pubseekoff(0, std::ios_base::end, std::ios_base::out) << std::endl;
+      assert(spBuf.pubseekoff(0, std::ios_base::end, std::ios_base::out) == 10); // ???
+
       assert(spBuf.pubseekoff(3, std::ios_base::beg, std::ios_base::out) == 3);
       assert(spBuf.pubseekoff(3, std::ios_base::cur, std::ios_base::out) == 6);
       assert(spBuf.pubseekoff(-3, std::ios_base::end, std::ios_base::out) == 7);
 
-      // Default `in` && `out`
+      // Default parameter value `openmode`
+      assert(spBuf.pubseekoff(0, std::ios_base::beg) == 0);
+      // std::cerr << spBuf.pubseekoff(0, std::ios_base::cur) << std::endl;
+      assert(spBuf.pubseekoff(0, std::ios_base::cur) == -1); // ???
+      assert(spBuf.pubseekoff(0, std::ios_base::end) == 10);
+
       assert(spBuf.pubseekoff(3, std::ios_base::beg) == 3);
       assert(spBuf.pubseekoff(3, std::ios_base::cur) == -1);
       assert(spBuf.pubseekoff(-3, std::ios_base::end) == 7);
+
+      // No mode
+      assert(spBuf.pubseekoff(0, std::ios_base::beg, no_mode) == 0);
+      assert(spBuf.pubseekoff(0, std::ios_base::cur, no_mode) == -1);
+      assert(spBuf.pubseekoff(0, std::ios_base::end, no_mode) == 10); // ???
+
+      assert(spBuf.pubseekoff(3, std::ios_base::beg, no_mode) == 3);
+      assert(spBuf.pubseekoff(3, std::ios_base::cur, no_mode) == -1);
+      assert(spBuf.pubseekoff(-3, std::ios_base::end, no_mode) == 7);
     }
     // Mode: `in`
     {
@@ -207,18 +232,41 @@ void test() {
       assert(spBuf.pubseekoff(999, std::ios_base::cur, std::ios_base::out) == -1);
       assert(spBuf.pubseekoff(999, std::ios_base::end, std::ios_base::out) == -1);
 
+      // In-range
+      assert(spBuf.pubseekoff(0, std::ios_base::beg, std::ios_base::in) == 0);
+      assert(spBuf.pubseekoff(0, std::ios_base::cur, std::ios_base::in) == 0);
+      assert(spBuf.pubseekoff(0, std::ios_base::end, std::ios_base::in) == 10); // ???
+
       assert(spBuf.pubseekoff(3, std::ios_base::beg, std::ios_base::in) == 3);
       assert(spBuf.pubseekoff(3, std::ios_base::cur, std::ios_base::in) == 6);
       assert(spBuf.pubseekoff(-3, std::ios_base::end, std::ios_base::in) == 7);
 
+      assert(spBuf.pubseekoff(0, std::ios_base::beg, std::ios_base::out) == 0);
+      assert(spBuf.pubseekoff(0, std::ios_base::cur, std::ios_base::out) == 0);
+      // std::cerr << spBuf.pubseekoff(0, std::ios_base::end, std::ios_base::out) << std::endl;
+      assert(spBuf.pubseekoff(0, std::ios_base::end, std::ios_base::out) == -1); // ???
+
       assert(spBuf.pubseekoff(3, std::ios_base::beg, std::ios_base::out) == -1);
       assert(spBuf.pubseekoff(3, std::ios_base::cur, std::ios_base::out) == -1);
       assert(spBuf.pubseekoff(-3, std::ios_base::end, std::ios_base::out) == -1);
 
-      // Default `in` && `out`
+      // Default parameter value `openmode`
+      assert(spBuf.pubseekoff(0, std::ios_base::beg) == 0);
+      assert(spBuf.pubseekoff(0, std::ios_base::cur) == -1); // ???
+      assert(spBuf.pubseekoff(0, std::ios_base::end) == -1); // ???
+
       assert(spBuf.pubseekoff(3, std::ios_base::beg) == -1);
       assert(spBuf.pubseekoff(3, std::ios_base::cur) == -1);
       assert(spBuf.pubseekoff(-3, std::ios_base::end) == -1);
+
+      // No mode
+      assert(spBuf.pubseekoff(0, std::ios_base::beg, no_mode) == 0);
+      assert(spBuf.pubseekoff(0, std::ios_base::cur, no_mode) == -1);
+      assert(spBuf.pubseekoff(0, std::ios_base::end, no_mode) == 10); // ???
+
+      assert(spBuf.pubseekoff(3, std::ios_base::beg, no_mode) == 3);
+      assert(spBuf.pubseekoff(3, std::ios_base::cur, no_mode) == -1);
+      assert(spBuf.pubseekoff(-3, std::ios_base::end, no_mode) == 7);
     }
     // Mode: `out`
     {
@@ -232,36 +280,40 @@ void test() {
       assert(spBuf.pubseekoff(999, std::ios_base::cur, std::ios_base::out) == -1);
       assert(spBuf.pubseekoff(999, std::ios_base::end, std::ios_base::out) == -1);
 
+      // In-range
+      assert(spBuf.pubseekoff(0, std::ios_base::beg, std::ios_base::in) == 0);
+      assert(spBuf.pubseekoff(0, std::ios_base::cur, std::ios_base::in) == 0);
+      assert(spBuf.pubseekoff(0, std::ios_base::end, std::ios_base::in) == 0);
+
       assert(spBuf.pubseekoff(3, std::ios_base::beg, std::ios_base::in) == -1);
       assert(spBuf.pubseekoff(3, std::ios_base::cur, std::ios_base::in) == -1);
       assert(spBuf.pubseekoff(-3, std::ios_base::end, std::ios_base::in) == -1);
 
+      assert(spBuf.pubseekoff(0, std::ios_base::beg, std::ios_base::out) == 0);
+      assert(spBuf.pubseekoff(0, std::ios_base::cur, std::ios_base::out) == 0);
+      assert(spBuf.pubseekoff(0, std::ios_base::end, std::ios_base::out) == 0);
+
       assert(spBuf.pubseekoff(3, std::ios_base::beg, std::ios_base::out) == 3);
       assert(spBuf.pubseekoff(3, std::ios_base::cur, std::ios_base::out) == 6);
       assert(spBuf.pubseekoff(-3, std::ios_base::end, std::ios_base::out) == 3);
 
-      // Default `in` && `out`
+      // Default parameter value `openmode`
+      assert(spBuf.pubseekoff(0, std::ios_base::beg) == 0);
+      assert(spBuf.pubseekoff(0, std::ios_base::cur) == -1); // ???
+      assert(spBuf.pubseekoff(0, std::ios_base::end) == 0);
+
       assert(spBuf.pubseekoff(3, std::ios_base::beg) == -1);
       assert(spBuf.pubseekoff(3, std::ios_base::cur) == -1);
-      assert(spBuf.pubseekoff(-3, std::ios_base::end) == 0);
-    }
-    // Mode: multiple
-    {
-      // std::span<CharT> sp{arr};
-      // TestSpanBuf<CharT, TraitsT> rhsSpBuf(sp | std::ios_base::binary);
-      // TestSpanBuf<CharT, TraitsT> spBuf = std::move(static_cast<SpBuf&>(rhsSpBuf));
-      // assert(rhsSpBuf.span().data() == arr);
-      // assert(spBuf.span().data() == arr);
-      // spBuf.check_postconditions(rhsSpBuf);
-    }
-    // Mode: `ate`
-    {
-      // std::span<CharT> sp{arr};
-      // TestSpanBuf<CharT, TraitsT> rhsSpBuf(sp, std::ios_base::out | std::ios_base::ate);
-      // TestSpanBuf<CharT, TraitsT> spBuf = std::move(static_cast<SpBuf&>(rhsSpBuf));
-      // assert(rhsSpBuf.span().data() == arr);
-      // assert(spBuf.span().data() == arr);
-      // spBuf.check_postconditions(rhsSpBuf);
+      assert(spBuf.pubseekoff(-3, std::ios_base::end) == -1);
+
+      // No mode
+      assert(spBuf.pubseekoff(0, std::ios_base::beg, no_mode) == 0);
+      assert(spBuf.pubseekoff(0, std::ios_base::cur, no_mode) == -1);
+      assert(spBuf.pubseekoff(0, std::ios_base::end, no_mode) == 0); // ???
+
+      assert(spBuf.pubseekoff(3, std::ios_base::beg, no_mode) == 3);
+      assert(spBuf.pubseekoff(3, std::ios_base::cur, no_mode) == -1);
+      assert(spBuf.pubseekoff(-3, std::ios_base::end, no_mode) == -1); // ???
     }
   }
 }

>From 213e3dc4b7f494dc31394c7779055ba1846eba33 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Wed, 13 Mar 2024 11:50:47 +0200
Subject: [PATCH 39/56] Tests: clean-up
 `seekoff.off_type.seek_dir.open_mode.pass`

---
 ...ekoff.off_type.seek_dir.open_mode.pass.cpp | 87 ++++++++++++++++---
 1 file changed, 75 insertions(+), 12 deletions(-)

diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekoff.off_type.seek_dir.open_mode.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekoff.off_type.seek_dir.open_mode.pass.cpp
index ce9fd90f6e7c3..1a3d43f99b0ff 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekoff.off_type.seek_dir.open_mode.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekoff.off_type.seek_dir.open_mode.pass.cpp
@@ -28,8 +28,6 @@
 #include "nasty_string.h"
 #include "test_macros.h"
 
-// #include <iostream>
-
 template <typename CharT, typename TraitsT = std::char_traits<CharT>>
 void test() {
   using SpBuf = std::basic_spanbuf<CharT, TraitsT>;
@@ -174,18 +172,24 @@ void test() {
     {
       SpBuf spBuf{sp};
 
-      // Out-of-range
+      assert(spBuf.pubseekoff(-999, std::ios_base::beg, std::ios_base::in) == -1);
+      assert(spBuf.pubseekoff(-999, std::ios_base::cur, std::ios_base::in) == -1);
+      assert(spBuf.pubseekoff(-999, std::ios_base::end, std::ios_base::in) == -1);
+
+      assert(spBuf.pubseekoff(999, std::ios_base::beg, std::ios_base::in) == -1);
+      assert(spBuf.pubseekoff(999, std::ios_base::cur, std::ios_base::in) == -1);
+      assert(spBuf.pubseekoff(999, std::ios_base::end, std::ios_base::in) == -1);
+
       assert(spBuf.pubseekoff(-999, std::ios_base::beg, std::ios_base::out) == -1);
       assert(spBuf.pubseekoff(-999, std::ios_base::cur, std::ios_base::out) == -1);
       assert(spBuf.pubseekoff(-999, std::ios_base::end, std::ios_base::out) == -1);
+
       assert(spBuf.pubseekoff(999, std::ios_base::beg, std::ios_base::out) == -1);
       assert(spBuf.pubseekoff(999, std::ios_base::cur, std::ios_base::out) == -1);
       assert(spBuf.pubseekoff(999, std::ios_base::end, std::ios_base::out) == -1);
 
-      // In-range
       assert(spBuf.pubseekoff(0, std::ios_base::beg, std::ios_base::in) == 0);
       assert(spBuf.pubseekoff(0, std::ios_base::cur, std::ios_base::in) == 0);
-      // std::cerr << spBuf.pubseekoff(0, std::ios_base::end, std::ios_base::in) << std::endl;
       assert(spBuf.pubseekoff(0, std::ios_base::end, std::ios_base::in) == 10); // ???
 
       assert(spBuf.pubseekoff(3, std::ios_base::beg, std::ios_base::in) == 3);
@@ -194,7 +198,6 @@ void test() {
 
       assert(spBuf.pubseekoff(0, std::ios_base::beg, std::ios_base::out) == 0);
       assert(spBuf.pubseekoff(0, std::ios_base::cur, std::ios_base::out) == 0);
-      // std::cerr << spBuf.pubseekoff(0, std::ios_base::end, std::ios_base::out) << std::endl;
       assert(spBuf.pubseekoff(0, std::ios_base::end, std::ios_base::out) == 10); // ???
 
       assert(spBuf.pubseekoff(3, std::ios_base::beg, std::ios_base::out) == 3);
@@ -202,8 +205,15 @@ void test() {
       assert(spBuf.pubseekoff(-3, std::ios_base::end, std::ios_base::out) == 7);
 
       // Default parameter value `openmode`
+      assert(spBuf.pubseekoff(-999, std::ios_base::beg) == -1);
+      assert(spBuf.pubseekoff(-999, std::ios_base::cur) == -1);
+      assert(spBuf.pubseekoff(-999, std::ios_base::end) == -1);
+
+      assert(spBuf.pubseekoff(999, std::ios_base::beg) == -1);
+      assert(spBuf.pubseekoff(999, std::ios_base::cur) == -1);
+      assert(spBuf.pubseekoff(999, std::ios_base::end) == -1);
+
       assert(spBuf.pubseekoff(0, std::ios_base::beg) == 0);
-      // std::cerr << spBuf.pubseekoff(0, std::ios_base::cur) << std::endl;
       assert(spBuf.pubseekoff(0, std::ios_base::cur) == -1); // ???
       assert(spBuf.pubseekoff(0, std::ios_base::end) == 10);
 
@@ -212,6 +222,14 @@ void test() {
       assert(spBuf.pubseekoff(-3, std::ios_base::end) == 7);
 
       // No mode
+      assert(spBuf.pubseekoff(-999, std::ios_base::beg, no_mode) == -1);
+      assert(spBuf.pubseekoff(-999, std::ios_base::cur, no_mode) == -1);
+      assert(spBuf.pubseekoff(-999, std::ios_base::end, no_mode) == -1);
+
+      assert(spBuf.pubseekoff(999, std::ios_base::beg, no_mode) == -1);
+      assert(spBuf.pubseekoff(999, std::ios_base::cur, no_mode) == -1);
+      assert(spBuf.pubseekoff(999, std::ios_base::end, no_mode) == -1);
+
       assert(spBuf.pubseekoff(0, std::ios_base::beg, no_mode) == 0);
       assert(spBuf.pubseekoff(0, std::ios_base::cur, no_mode) == -1);
       assert(spBuf.pubseekoff(0, std::ios_base::end, no_mode) == 10); // ???
@@ -224,15 +242,22 @@ void test() {
     {
       SpBuf spBuf{sp, std::ios_base::in};
 
-      // Out-of-range
+      assert(spBuf.pubseekoff(-999, std::ios_base::beg, std::ios_base::in) == -1);
+      assert(spBuf.pubseekoff(-999, std::ios_base::cur, std::ios_base::in) == -1);
+      assert(spBuf.pubseekoff(-999, std::ios_base::end, std::ios_base::in) == -1);
+
+      assert(spBuf.pubseekoff(999, std::ios_base::beg, std::ios_base::in) == -1);
+      assert(spBuf.pubseekoff(999, std::ios_base::cur, std::ios_base::in) == -1);
+      assert(spBuf.pubseekoff(999, std::ios_base::end, std::ios_base::in) == -1);
+
       assert(spBuf.pubseekoff(-999, std::ios_base::beg, std::ios_base::out) == -1);
       assert(spBuf.pubseekoff(-999, std::ios_base::cur, std::ios_base::out) == -1);
       assert(spBuf.pubseekoff(-999, std::ios_base::end, std::ios_base::out) == -1);
+
       assert(spBuf.pubseekoff(999, std::ios_base::beg, std::ios_base::out) == -1);
       assert(spBuf.pubseekoff(999, std::ios_base::cur, std::ios_base::out) == -1);
       assert(spBuf.pubseekoff(999, std::ios_base::end, std::ios_base::out) == -1);
 
-      // In-range
       assert(spBuf.pubseekoff(0, std::ios_base::beg, std::ios_base::in) == 0);
       assert(spBuf.pubseekoff(0, std::ios_base::cur, std::ios_base::in) == 0);
       assert(spBuf.pubseekoff(0, std::ios_base::end, std::ios_base::in) == 10); // ???
@@ -243,7 +268,6 @@ void test() {
 
       assert(spBuf.pubseekoff(0, std::ios_base::beg, std::ios_base::out) == 0);
       assert(spBuf.pubseekoff(0, std::ios_base::cur, std::ios_base::out) == 0);
-      // std::cerr << spBuf.pubseekoff(0, std::ios_base::end, std::ios_base::out) << std::endl;
       assert(spBuf.pubseekoff(0, std::ios_base::end, std::ios_base::out) == -1); // ???
 
       assert(spBuf.pubseekoff(3, std::ios_base::beg, std::ios_base::out) == -1);
@@ -251,6 +275,14 @@ void test() {
       assert(spBuf.pubseekoff(-3, std::ios_base::end, std::ios_base::out) == -1);
 
       // Default parameter value `openmode`
+      assert(spBuf.pubseekoff(-999, std::ios_base::beg) == -1);
+      assert(spBuf.pubseekoff(-999, std::ios_base::cur) == -1);
+      assert(spBuf.pubseekoff(-999, std::ios_base::end) == -1);
+
+      assert(spBuf.pubseekoff(999, std::ios_base::beg) == -1);
+      assert(spBuf.pubseekoff(999, std::ios_base::cur) == -1);
+      assert(spBuf.pubseekoff(999, std::ios_base::end) == -1);
+
       assert(spBuf.pubseekoff(0, std::ios_base::beg) == 0);
       assert(spBuf.pubseekoff(0, std::ios_base::cur) == -1); // ???
       assert(spBuf.pubseekoff(0, std::ios_base::end) == -1); // ???
@@ -260,6 +292,14 @@ void test() {
       assert(spBuf.pubseekoff(-3, std::ios_base::end) == -1);
 
       // No mode
+      assert(spBuf.pubseekoff(-999, std::ios_base::beg, no_mode) == -1);
+      assert(spBuf.pubseekoff(-999, std::ios_base::cur, no_mode) == -1);
+      assert(spBuf.pubseekoff(-999, std::ios_base::end, no_mode) == -1);
+
+      assert(spBuf.pubseekoff(999, std::ios_base::beg, no_mode) == -1);
+      assert(spBuf.pubseekoff(999, std::ios_base::cur, no_mode) == -1);
+      assert(spBuf.pubseekoff(999, std::ios_base::end, no_mode) == -1);
+
       assert(spBuf.pubseekoff(0, std::ios_base::beg, no_mode) == 0);
       assert(spBuf.pubseekoff(0, std::ios_base::cur, no_mode) == -1);
       assert(spBuf.pubseekoff(0, std::ios_base::end, no_mode) == 10); // ???
@@ -272,15 +312,22 @@ void test() {
     {
       SpBuf spBuf{sp, std::ios_base::out};
 
-      // Out-of-range
+      assert(spBuf.pubseekoff(-999, std::ios_base::beg, std::ios_base::in) == -1);
+      assert(spBuf.pubseekoff(-999, std::ios_base::cur, std::ios_base::in) == -1);
+      assert(spBuf.pubseekoff(-999, std::ios_base::end, std::ios_base::in) == -1);
+
+      assert(spBuf.pubseekoff(999, std::ios_base::beg, std::ios_base::in) == -1);
+      assert(spBuf.pubseekoff(999, std::ios_base::cur, std::ios_base::in) == -1);
+      assert(spBuf.pubseekoff(999, std::ios_base::end, std::ios_base::in) == -1);
+
       assert(spBuf.pubseekoff(-999, std::ios_base::beg, std::ios_base::out) == -1);
       assert(spBuf.pubseekoff(-999, std::ios_base::cur, std::ios_base::out) == -1);
       assert(spBuf.pubseekoff(-999, std::ios_base::end, std::ios_base::out) == -1);
+
       assert(spBuf.pubseekoff(999, std::ios_base::beg, std::ios_base::out) == -1);
       assert(spBuf.pubseekoff(999, std::ios_base::cur, std::ios_base::out) == -1);
       assert(spBuf.pubseekoff(999, std::ios_base::end, std::ios_base::out) == -1);
 
-      // In-range
       assert(spBuf.pubseekoff(0, std::ios_base::beg, std::ios_base::in) == 0);
       assert(spBuf.pubseekoff(0, std::ios_base::cur, std::ios_base::in) == 0);
       assert(spBuf.pubseekoff(0, std::ios_base::end, std::ios_base::in) == 0);
@@ -298,6 +345,14 @@ void test() {
       assert(spBuf.pubseekoff(-3, std::ios_base::end, std::ios_base::out) == 3);
 
       // Default parameter value `openmode`
+      assert(spBuf.pubseekoff(-999, std::ios_base::beg) == -1);
+      assert(spBuf.pubseekoff(-999, std::ios_base::cur) == -1);
+      assert(spBuf.pubseekoff(-999, std::ios_base::end) == -1);
+
+      assert(spBuf.pubseekoff(999, std::ios_base::beg) == -1);
+      assert(spBuf.pubseekoff(999, std::ios_base::cur) == -1);
+      assert(spBuf.pubseekoff(999, std::ios_base::end) == -1);
+
       assert(spBuf.pubseekoff(0, std::ios_base::beg) == 0);
       assert(spBuf.pubseekoff(0, std::ios_base::cur) == -1); // ???
       assert(spBuf.pubseekoff(0, std::ios_base::end) == 0);
@@ -307,6 +362,14 @@ void test() {
       assert(spBuf.pubseekoff(-3, std::ios_base::end) == -1);
 
       // No mode
+      assert(spBuf.pubseekoff(-999, std::ios_base::beg, no_mode) == -1);
+      assert(spBuf.pubseekoff(-999, std::ios_base::cur, no_mode) == -1);
+      assert(spBuf.pubseekoff(-999, std::ios_base::end, no_mode) == -1);
+
+      assert(spBuf.pubseekoff(999, std::ios_base::beg, no_mode) == -1);
+      assert(spBuf.pubseekoff(999, std::ios_base::cur, no_mode) == -1);
+      assert(spBuf.pubseekoff(999, std::ios_base::end, no_mode) == -1);
+
       assert(spBuf.pubseekoff(0, std::ios_base::beg, no_mode) == 0);
       assert(spBuf.pubseekoff(0, std::ios_base::cur, no_mode) == -1);
       assert(spBuf.pubseekoff(0, std::ios_base::end, no_mode) == 0); // ???

>From 81210978dd01ffb39d11f25b113dbdaa042114a7 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Wed, 13 Mar 2024 13:10:16 +0200
Subject: [PATCH 40/56] Tests: updated `seekoff.pass` and `seekpos.pass`

---
 ...ir.open_mode.pass.cpp => seekoff.pass.cpp} |   1 -
 .../seekoff.pos_type.open_mode.pass.cpp       |  60 -----
 .../spanbuf/spanbuf.virtuals/seekpos.pass.cpp | 211 ++++++++++++++++++
 3 files changed, 211 insertions(+), 61 deletions(-)
 rename libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/{seekoff.off_type.seek_dir.open_mode.pass.cpp => seekoff.pass.cpp} (99%)
 delete mode 100644 libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekoff.pos_type.open_mode.pass.cpp
 create mode 100644 libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekpos.pass.cpp

diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekoff.off_type.seek_dir.open_mode.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekoff.pass.cpp
similarity index 99%
rename from libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekoff.off_type.seek_dir.open_mode.pass.cpp
rename to libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekoff.pass.cpp
index 1a3d43f99b0ff..006bd0786ccc8 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekoff.off_type.seek_dir.open_mode.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekoff.pass.cpp
@@ -19,7 +19,6 @@
 //     pos_type seekoff(off_type off, ios_base::seekdir way,
 //                      ios_base::openmode which = ios_base::in | ios_base::out) override;
 
-#include <algorithm>
 #include <cassert>
 #include <span>
 #include <spanstream>
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekoff.pos_type.open_mode.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekoff.pos_type.open_mode.pass.cpp
deleted file mode 100644
index 78fda49908601..0000000000000
--- a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekoff.pos_type.open_mode.pass.cpp
+++ /dev/null
@@ -1,60 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
-
-// <spanstream>
-
-//   template<class charT, class traits = char_traits<charT>>
-//   class basic_spanbuf
-//     : public basic_spanbuf<charT, traits> {
-
-//     // [spanbuf.virtuals], overridden virtual functions
-//
-//     pos_type seekpos(pos_type sp,
-//                      ios_base::openmode which = ios_base::in | ios_base::out) override;
-
-#include <cassert>
-#include <span>
-#include <spanstream>
-
-#include "constexpr_char_traits.h"
-#include "nasty_string.h"
-#include "test_macros.h"
-
-template <typename CharT, typename TraitsT = std::char_traits<CharT>>
-void test() {
-  using SpBuf = std::basic_spanbuf<CharT, TraitsT>;
-
-  CharT arr[4];
-  std::span<CharT> sp{arr};
-
-  // Mode: default
-  {
-    SpBuf rhsSpBuf{sp};
-    SpBuf spBuf(std::span<CharT>{});
-    spBuf.swap(rhsSpBuf);
-    // assert(spBuf.span().data() == arr);
-    // assert(!spBuf.span().empty());
-    // assert(spBuf.span().size() == 4);
-  }
-}
-
-int main(int, char**) {
-#ifndef TEST_HAS_NO_NASTY_STRING
-  test<nasty_char, nasty_char_traits>();
-#endif
-  test<char>();
-  test<char, constexpr_char_traits<char>>();
-#ifndef TEST_HAS_NO_WIDE_CHARACTERS
-  test<wchar_t>();
-  test<wchar_t, constexpr_char_traits<wchar_t>>();
-#endif
-
-  return 0;
-}
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekpos.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekpos.pass.cpp
new file mode 100644
index 0000000000000..3b7f0d1b67323
--- /dev/null
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekpos.pass.cpp
@@ -0,0 +1,211 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <spanstream>
+
+//   template<class charT, class traits = char_traits<charT>>
+//   class basic_spanbuf
+//     : public basic_spanbuf<charT, traits> {
+
+//     // [spanbuf.virtuals], overridden virtual functions
+//
+//     pos_type seekpos(pos_type sp,
+//                      ios_base::openmode which = ios_base::in | ios_base::out) override;
+
+#include <cassert>
+#include <span>
+#include <spanstream>
+
+#include "constexpr_char_traits.h"
+#include "nasty_string.h"
+#include "test_macros.h"
+
+// `seekpos` is the same as `seekoff` with `ios_base::beg`
+template <typename CharT, typename TraitsT = std::char_traits<CharT>>
+void test() {
+  using SpBuf = std::basic_spanbuf<CharT, TraitsT>;
+
+  constexpr auto no_mode = 0;
+
+  // Empty `span`
+  {
+    std::span<CharT> sp;
+
+    // For an empty span:
+    //    0 is an in-range offset value for an empty span
+    //    3 is an out-of-range offset value
+
+    // Mode: default (`in` | `out`)
+    {
+      SpBuf spBuf{sp};
+
+      assert(spBuf.pubseekpos(0, std::ios_base::in) == 0);
+      assert(spBuf.pubseekpos(3, std::ios_base::in) == -1);
+
+      assert(spBuf.pubseekpos(0, std::ios_base::out) == 0);
+      assert(spBuf.pubseekpos(3, std::ios_base::out) == -1);
+
+      // Default parameter value `openmode`
+      assert(spBuf.pubseekpos(0) == 0);
+      assert(spBuf.pubseekpos(3) == -1);
+
+      // No mode
+      assert(spBuf.pubseekpos(0, no_mode) == 0);
+      assert(spBuf.pubseekpos(3, no_mode) == -1);
+    }
+    // Mode: `in`
+    {
+      SpBuf spBuf{sp, std::ios_base::in};
+
+      assert(spBuf.pubseekpos(0, std::ios_base::in) == 0);
+      assert(spBuf.pubseekpos(3, std::ios_base::in) == -1);
+
+      assert(spBuf.pubseekpos(0, std::ios_base::out) == 0);
+      assert(spBuf.pubseekpos(3, std::ios_base::out) == -1);
+
+      // Default parameter value `openmode`
+      assert(spBuf.pubseekpos(0) == 0);
+      assert(spBuf.pubseekpos(3) == -1);
+
+      // No mode
+      assert(spBuf.pubseekpos(0, no_mode) == 0);
+      assert(spBuf.pubseekpos(3, no_mode) == -1);
+    }
+    // Mode: `out`
+    {
+      SpBuf spBuf{sp, std::ios_base::out};
+
+      assert(spBuf.pubseekpos(0, std::ios_base::in) == 0);
+      assert(spBuf.pubseekpos(3, std::ios_base::in) == -1);
+
+      assert(spBuf.pubseekpos(0, std::ios_base::out) == 0);
+      assert(spBuf.pubseekpos(3, std::ios_base::out) == -1);
+
+      // Default parameter value `openmode`
+      assert(spBuf.pubseekpos(0) == 0);
+      assert(spBuf.pubseekpos(3) == -1);
+
+      // No mode
+      assert(spBuf.pubseekpos(0, no_mode) == 0);
+      assert(spBuf.pubseekpos(3, no_mode) == -1);
+    }
+  }
+
+  // Non-empty `span`
+  {
+    CharT arr[10];
+    std::span sp{arr};
+
+    // For an empty span:
+    //    999 is an out-of-range offset value
+
+    // Mode: default (`in` | `out`)
+    {
+      SpBuf spBuf{sp};
+
+      assert(spBuf.pubseekpos(999, std::ios_base::in) == -1);
+
+      assert(spBuf.pubseekpos(999, std::ios_base::out) == -1);
+
+      assert(spBuf.pubseekpos(0, std::ios_base::in) == 0);
+      assert(spBuf.pubseekpos(3, std::ios_base::in) == 3);
+
+      assert(spBuf.pubseekpos(0, std::ios_base::out) == 0);
+      assert(spBuf.pubseekpos(3, std::ios_base::out) == 3);
+
+      // Default parameter value `openmode`
+      assert(spBuf.pubseekpos(-999) == -1);
+      assert(spBuf.pubseekpos(999) == -1);
+
+      assert(spBuf.pubseekpos(0) == 0);
+      assert(spBuf.pubseekpos(3) == 3);
+
+      // No mode
+      assert(spBuf.pubseekpos(-999, no_mode) == -1);
+      assert(spBuf.pubseekpos(999, no_mode) == -1);
+
+      assert(spBuf.pubseekpos(0, no_mode) == 0);
+      assert(spBuf.pubseekpos(3, no_mode) == 3);
+    }
+    // Mode: `in`
+    {
+      SpBuf spBuf{sp, std::ios_base::in};
+
+      assert(spBuf.pubseekpos(999, std::ios_base::in) == -1);
+
+
+      assert(spBuf.pubseekpos(999, std::ios_base::out) == -1);
+
+      assert(spBuf.pubseekpos(0, std::ios_base::in) == 0);
+      assert(spBuf.pubseekpos(3, std::ios_base::in) == 3);
+
+
+      assert(spBuf.pubseekpos(0, std::ios_base::out) == 0);
+      assert(spBuf.pubseekpos(3, std::ios_base::out) == -1);
+
+
+      // Default parameter value `openmode`
+      assert(spBuf.pubseekpos(999) == -1);
+
+      assert(spBuf.pubseekpos(0) == 0);
+      assert(spBuf.pubseekpos(3) == -1);
+
+
+      // No mode
+      assert(spBuf.pubseekpos(999, no_mode) == -1);
+
+      assert(spBuf.pubseekpos(0, no_mode) == 0);
+      assert(spBuf.pubseekpos(3, no_mode) == 3);
+    }
+    // Mode: `out`
+    {
+      SpBuf spBuf{sp, std::ios_base::out};
+
+      assert(spBuf.pubseekpos(999, std::ios_base::in) == -1);
+
+
+      assert(spBuf.pubseekpos(999, std::ios_base::out) == -1);
+
+
+      assert(spBuf.pubseekpos(0, std::ios_base::in) == 0);
+      assert(spBuf.pubseekpos(3, std::ios_base::in) == -1);
+
+
+      assert(spBuf.pubseekpos(0, std::ios_base::out) == 0);
+      assert(spBuf.pubseekpos(3, std::ios_base::out) == 3);
+
+
+      // Default parameter value `openmode`
+      assert(spBuf.pubseekpos(999) == -1);
+      assert(spBuf.pubseekpos(0) == 0);
+      assert(spBuf.pubseekpos(3) == -1);
+
+
+      // No mode
+      assert(spBuf.pubseekpos(999, no_mode) == -1);
+      assert(spBuf.pubseekpos(0, no_mode) == 0);
+      assert(spBuf.pubseekpos(3, no_mode) == 3);
+    }
+  }
+}
+
+int main(int, char**) {
+#ifndef TEST_HAS_NO_NASTY_STRING
+  test<nasty_char, nasty_char_traits>();
+#endif
+  test<char>();
+  test<char, constexpr_char_traits<char>>();
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  test<wchar_t>();
+  test<wchar_t, constexpr_char_traits<wchar_t>>();
+#endif
+
+  return 0;
+}

>From bda8caeada0d2623edb668fdee255a9eec768d5b Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Wed, 13 Mar 2024 19:15:42 +0200
Subject: [PATCH 41/56] Tests: WIP `operator>>` tests

---
 .../spanbuf/spanbuf.virtuals/seekpos.pass.cpp |  12 +-
 .../spanstream/inherited.stream.ops.pass.cpp  | 177 ++++++++++++++++++
 2 files changed, 178 insertions(+), 11 deletions(-)
 create mode 100644 libcxx/test/std/input.output/span.streams/spanstream/inherited.stream.ops.pass.cpp

diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekpos.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekpos.pass.cpp
index 3b7f0d1b67323..71594c0066720 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekpos.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekpos.pass.cpp
@@ -121,7 +121,6 @@ void test() {
       assert(spBuf.pubseekpos(3, std::ios_base::out) == 3);
 
       // Default parameter value `openmode`
-      assert(spBuf.pubseekpos(-999) == -1);
       assert(spBuf.pubseekpos(999) == -1);
 
       assert(spBuf.pubseekpos(0) == 0);
@@ -140,24 +139,20 @@ void test() {
 
       assert(spBuf.pubseekpos(999, std::ios_base::in) == -1);
 
-
       assert(spBuf.pubseekpos(999, std::ios_base::out) == -1);
 
       assert(spBuf.pubseekpos(0, std::ios_base::in) == 0);
       assert(spBuf.pubseekpos(3, std::ios_base::in) == 3);
 
-
       assert(spBuf.pubseekpos(0, std::ios_base::out) == 0);
       assert(spBuf.pubseekpos(3, std::ios_base::out) == -1);
 
-
       // Default parameter value `openmode`
       assert(spBuf.pubseekpos(999) == -1);
 
       assert(spBuf.pubseekpos(0) == 0);
       assert(spBuf.pubseekpos(3) == -1);
 
-
       // No mode
       assert(spBuf.pubseekpos(999, no_mode) == -1);
 
@@ -169,25 +164,20 @@ void test() {
       SpBuf spBuf{sp, std::ios_base::out};
 
       assert(spBuf.pubseekpos(999, std::ios_base::in) == -1);
-
-
+      
       assert(spBuf.pubseekpos(999, std::ios_base::out) == -1);
 
-
       assert(spBuf.pubseekpos(0, std::ios_base::in) == 0);
       assert(spBuf.pubseekpos(3, std::ios_base::in) == -1);
 
-
       assert(spBuf.pubseekpos(0, std::ios_base::out) == 0);
       assert(spBuf.pubseekpos(3, std::ios_base::out) == 3);
 
-
       // Default parameter value `openmode`
       assert(spBuf.pubseekpos(999) == -1);
       assert(spBuf.pubseekpos(0) == 0);
       assert(spBuf.pubseekpos(3) == -1);
 
-
       // No mode
       assert(spBuf.pubseekpos(999, no_mode) == -1);
       assert(spBuf.pubseekpos(0, no_mode) == 0);
diff --git a/libcxx/test/std/input.output/span.streams/spanstream/inherited.stream.ops.pass.cpp b/libcxx/test/std/input.output/span.streams/spanstream/inherited.stream.ops.pass.cpp
new file mode 100644
index 0000000000000..7517c301dd56f
--- /dev/null
+++ b/libcxx/test/std/input.output/span.streams/spanstream/inherited.stream.ops.pass.cpp
@@ -0,0 +1,177 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <spanstream>
+
+//   template<class charT, class traits = char_traits<charT>>
+//   class basic_spanstream
+//     : public basic_streambuf<charT, traits> {
+
+//   Test stream operations inherited from `basic_istream` and `basic_ostream`
+
+#include <cassert>
+#include <concepts>
+#include <span>
+#include <spanstream>
+#include <string>
+#include <sstream>
+
+#include "constexpr_char_traits.h"
+#include "test_convertible.h"
+#include "test_macros.h"
+
+#include "../helper_macros.h"
+
+#include <print>
+#include <iostream>
+
+template <typename CharT, typename TraitsT = std::char_traits<CharT>>
+void initialize_array(CharT* arr, std::basic_string_view<CharT, TraitsT> sv) {
+  if constexpr (std::same_as<CharT, char>)
+    strncpy(arr, sv.data(), sv.size() + 1);
+  else
+    wcsncpy(arr, sv.data(), sv.size() + 1);
+}
+
+template <typename CharT, typename TraitsT = std::char_traits<CharT>>
+void test() {
+  using SpStream = std::basic_spanstream<CharT, TraitsT>;
+
+  constexpr std::basic_string_view<CharT, TraitsT> sv{SV("zmt 94 hkt 82 pir ")};
+  CharT arr[sv.size() + 1];
+  initialize_array(arr, sv);
+  // if constexpr (std::same_as<CharT, char>)
+  //   strncpy(arr, sv.data(), sv.size() + 1);
+  // else
+  //   wcsncpy(arr, sv.data(), sv.size() + 1);
+
+  std::span<CharT> sp{arr};
+
+  // if constexpr (std::same_as<CharT, char>) {
+  //   std::println(stderr, "{}", sp.data());
+  //   std::println(stderr, "{}", sp);
+  // } else {
+  //   // std::println(stderr, "{}", sp.data());
+  //   // std::println(stderr, "{}", sp);
+  //   // std::println(stderr, L"{}", L"sv.data()");
+  //   std::wcerr << std::format(L"L {}", sp.data()) << std::endl;
+  //   std::wcerr << std::format(L"L {}", sp) << std::endl;
+  // }
+
+  // Mode: default
+  {
+    SpStream spSt(sp);
+    std::basic_string<CharT, TraitsT> str1;
+    spSt >> str1;
+    int i1;
+    spSt >> i1;
+    std::basic_string<CharT, TraitsT> str2;
+    spSt >> str2;
+    int i2;
+    spSt >> i2;
+    std::basic_string<CharT, TraitsT> str3;
+    spSt >> str3;
+
+    if constexpr (std::same_as<CharT, char>) {
+      std::println(stderr, "str1 '{}'", str1);
+      std::println(stderr, "str2 '{}'", str2);
+      std::println(stderr, "str3 '{}'", str3);
+    } else {
+      // std::println(stderr, "{}", sp.data());
+      // std::println(stderr, "{}", sp);
+      // std::println(stderr, L"{}", L"sv.data()");
+      std::wcerr << std::format(L"L str1 '{}'", str1) << std::endl;
+      std::wcerr << std::format(L"L str2 '{}'", str2) << std::endl;
+      std::wcerr << std::format(L"L str3 '{}'", str3) << std::endl;
+    }
+    assert(str1 == CS("zmt"));
+    assert(i1 == 94);
+    assert(str2 == CS("hkt"));
+    assert(i2 == 82);
+    assert(str3 == CS("pir"));
+  }
+  // std::cerr << "========================================" << std::endl;
+  {
+    std::basic_istringstream<CharT> spSt{sv.data()};
+    std::basic_string<CharT, TraitsT> str1;
+    spSt >> str1;
+    int i1;
+    spSt >> i1;
+    std::basic_string<CharT, TraitsT> str2;
+    spSt >> str2;
+    int i2;
+    spSt >> i2;
+    std::basic_string<CharT, TraitsT> str3;
+    spSt >> str3;
+
+    if constexpr (std::same_as<CharT, char>) {
+      std::println(stderr, "- str1 '{}'", str1);
+      std::println(stderr, "str2 '{}'", str2);
+      std::println(stderr, "str3 '{}'", str3);
+    } else {
+      // std::cerr << "lfasdfasdfasdfasd" << std::endl;
+      // std::wcerr << std::format(L"L - str1 '{}'", L"+++++++++++++++++++++++++") << std::endl;
+      std::wcerr << std::format(L"L - str1 '{}'", str1) << std::endl;
+      std::wcerr << std::format(L"L str2 '{}'", str2) << std::endl;
+      std::wcerr << std::format(L"L str3 '{}'", str3) << std::endl;
+    }
+  }
+
+  //   // Mode: default
+  //   {
+  //     SpStream rhsSpSt{sp};
+  //     SpStream spSt(std::move(rhsSpSt));
+  //     assert(spSt.span().data() == arr);
+  //     assert(spSt.span().empty());
+  //     assert(spSt.span().size() == 0);
+  //   }
+  //   // Mode: `ios_base::in`
+  //   {
+  //     SpStream rhsSpSt{sp, std::ios_base::in};
+  //     SpStream spSt(std::move(rhsSpSt));
+  //     assert(spSt.span().data() == arr);
+  //     assert(!spSt.span().empty());
+  //     assert(spSt.span().size() == 4);
+  //   }
+  //   // Mode `ios_base::out`
+  //   {
+  //     SpStream rhsSpSt{sp, std::ios_base::out};
+  //     SpStream spSt(std::move(rhsSpSt));
+  //     assert(spSt.span().data() == arr);
+  //     assert(spSt.span().empty());
+  //     assert(spSt.span().size() == 0);
+  //   }
+  //   // Mode: multiple
+  //   {
+  //     SpStream rhsSpSt{sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary};
+  //     SpStream spSt(std::move(rhsSpSt));
+  //     assert(spSt.span().data() == arr);
+  //     assert(spSt.span().empty());
+  //     assert(spSt.span().size() == 0);
+  //   }
+}
+
+int main(int, char**) {
+  test<char>();
+  // test<char, constexpr_char_traits<char>>();
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  test<wchar_t>();
+  // test<wchar_t, constexpr_char_traits<wchar_t>>();
+#endif
+  // std::println(stderr, "fasdfas");
+  // std::println(std::cerr, "fasdfasdfasd{}", "-----");
+  // std::println(std::cout, "fasdfasdfasd{}", "-----");
+  // std::println(std::wcout, L"fasdfasdfasd{}", L"-----");
+  // std::println(std::wcerr, L"fasdfasdfasd{}", L"-----");
+
+  // assert(false);
+
+  return 0;
+}

>From b3ade40763313414dea3d33469fe289b187b68fd Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Wed, 13 Mar 2024 20:35:09 +0200
Subject: [PATCH 42/56] Test: WIP `basic_spanstream`'s `operator>>` and
 `operator<<`

---
 .../spanstream/inherited.stream.ops.pass.cpp  | 91 +++----------------
 1 file changed, 13 insertions(+), 78 deletions(-)

diff --git a/libcxx/test/std/input.output/span.streams/spanstream/inherited.stream.ops.pass.cpp b/libcxx/test/std/input.output/span.streams/spanstream/inherited.stream.ops.pass.cpp
index 7517c301dd56f..febba22eee00b 100644
--- a/libcxx/test/std/input.output/span.streams/spanstream/inherited.stream.ops.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanstream/inherited.stream.ops.pass.cpp
@@ -21,17 +21,11 @@
 #include <span>
 #include <spanstream>
 #include <string>
-#include <sstream>
 
-#include "constexpr_char_traits.h"
-#include "test_convertible.h"
 #include "test_macros.h"
 
 #include "../helper_macros.h"
 
-#include <print>
-#include <iostream>
-
 template <typename CharT, typename TraitsT = std::char_traits<CharT>>
 void initialize_array(CharT* arr, std::basic_string_view<CharT, TraitsT> sv) {
   if constexpr (std::same_as<CharT, char>)
@@ -44,27 +38,11 @@ template <typename CharT, typename TraitsT = std::char_traits<CharT>>
 void test() {
   using SpStream = std::basic_spanstream<CharT, TraitsT>;
 
-  constexpr std::basic_string_view<CharT, TraitsT> sv{SV("zmt 94 hkt 82 pir ")};
+  constexpr std::basic_string_view<CharT, TraitsT> sv{SV("zmt 94 hkt 82 pir 43vr")};
   CharT arr[sv.size() + 1];
   initialize_array(arr, sv);
-  // if constexpr (std::same_as<CharT, char>)
-  //   strncpy(arr, sv.data(), sv.size() + 1);
-  // else
-  //   wcsncpy(arr, sv.data(), sv.size() + 1);
-
   std::span<CharT> sp{arr};
 
-  // if constexpr (std::same_as<CharT, char>) {
-  //   std::println(stderr, "{}", sp.data());
-  //   std::println(stderr, "{}", sp);
-  // } else {
-  //   // std::println(stderr, "{}", sp.data());
-  //   // std::println(stderr, "{}", sp);
-  //   // std::println(stderr, L"{}", L"sv.data()");
-  //   std::wcerr << std::format(L"L {}", sp.data()) << std::endl;
-  //   std::wcerr << std::format(L"L {}", sp) << std::endl;
-  // }
-
   // Mode: default
   {
     SpStream spSt(sp);
@@ -78,60 +56,26 @@ void test() {
     spSt >> i2;
     std::basic_string<CharT, TraitsT> str3;
     spSt >> str3;
+    int i3;
+    spSt >> i3;
 
-    if constexpr (std::same_as<CharT, char>) {
-      std::println(stderr, "str1 '{}'", str1);
-      std::println(stderr, "str2 '{}'", str2);
-      std::println(stderr, "str3 '{}'", str3);
-    } else {
-      // std::println(stderr, "{}", sp.data());
-      // std::println(stderr, "{}", sp);
-      // std::println(stderr, L"{}", L"sv.data()");
-      std::wcerr << std::format(L"L str1 '{}'", str1) << std::endl;
-      std::wcerr << std::format(L"L str2 '{}'", str2) << std::endl;
-      std::wcerr << std::format(L"L str3 '{}'", str3) << std::endl;
-    }
     assert(str1 == CS("zmt"));
     assert(i1 == 94);
     assert(str2 == CS("hkt"));
     assert(i2 == 82);
     assert(str3 == CS("pir"));
-  }
-  // std::cerr << "========================================" << std::endl;
-  {
-    std::basic_istringstream<CharT> spSt{sv.data()};
-    std::basic_string<CharT, TraitsT> str1;
-    spSt >> str1;
-    int i1;
-    spSt >> i1;
-    std::basic_string<CharT, TraitsT> str2;
-    spSt >> str2;
-    int i2;
-    spSt >> i2;
-    std::basic_string<CharT, TraitsT> str3;
-    spSt >> str3;
+    assert(i3 == 43);
 
-    if constexpr (std::same_as<CharT, char>) {
-      std::println(stderr, "- str1 '{}'", str1);
-      std::println(stderr, "str2 '{}'", str2);
-      std::println(stderr, "str3 '{}'", str3);
-    } else {
-      // std::cerr << "lfasdfasdfasdfasd" << std::endl;
-      // std::wcerr << std::format(L"L - str1 '{}'", L"+++++++++++++++++++++++++") << std::endl;
-      std::wcerr << std::format(L"L - str1 '{}'", str1) << std::endl;
-      std::wcerr << std::format(L"L str2 '{}'", str2) << std::endl;
-      std::wcerr << std::format(L"L str3 '{}'", str3) << std::endl;
-    }
-  }
+    spSt << CS("year 2024");
+    spSt.seekg(0);
+    std::basic_string<CharT, TraitsT> str4;
+    spSt >> str4;
+    int i4;
+    spSt >> i4;
 
-  //   // Mode: default
-  //   {
-  //     SpStream rhsSpSt{sp};
-  //     SpStream spSt(std::move(rhsSpSt));
-  //     assert(spSt.span().data() == arr);
-  //     assert(spSt.span().empty());
-  //     assert(spSt.span().size() == 0);
-  //   }
+    assert(str4 == CS("year"));
+    assert(i4 == 2024);
+  }
   //   // Mode: `ios_base::in`
   //   {
   //     SpStream rhsSpSt{sp, std::ios_base::in};
@@ -160,18 +104,9 @@ void test() {
 
 int main(int, char**) {
   test<char>();
-  // test<char, constexpr_char_traits<char>>();
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
   test<wchar_t>();
-  // test<wchar_t, constexpr_char_traits<wchar_t>>();
 #endif
-  // std::println(stderr, "fasdfas");
-  // std::println(std::cerr, "fasdfasdfasd{}", "-----");
-  // std::println(std::cout, "fasdfasdfasd{}", "-----");
-  // std::println(std::wcout, L"fasdfasdfasd{}", L"-----");
-  // std::println(std::wcerr, L"fasdfasdfasd{}", L"-----");
-
-  // assert(false);
 
   return 0;
 }

>From 88519243e13a67e296adc3b35015ed5f70dc35aa Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Wed, 13 Mar 2024 20:41:31 +0200
Subject: [PATCH 43/56] Tests: fixed formatting

---
 .../spanbuf/spanbuf.virtuals/seekpos.pass.cpp |  2 +-
 .../spanstream/inherited.stream.ops.pass.cpp  | 38 +++++++------------
 2 files changed, 14 insertions(+), 26 deletions(-)

diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekpos.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekpos.pass.cpp
index 71594c0066720..a7e9584ed2fd7 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekpos.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/seekpos.pass.cpp
@@ -164,7 +164,7 @@ void test() {
       SpBuf spBuf{sp, std::ios_base::out};
 
       assert(spBuf.pubseekpos(999, std::ios_base::in) == -1);
-      
+
       assert(spBuf.pubseekpos(999, std::ios_base::out) == -1);
 
       assert(spBuf.pubseekpos(0, std::ios_base::in) == 0);
diff --git a/libcxx/test/std/input.output/span.streams/spanstream/inherited.stream.ops.pass.cpp b/libcxx/test/std/input.output/span.streams/spanstream/inherited.stream.ops.pass.cpp
index febba22eee00b..e0d161d92437f 100644
--- a/libcxx/test/std/input.output/span.streams/spanstream/inherited.stream.ops.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanstream/inherited.stream.ops.pass.cpp
@@ -43,7 +43,7 @@ void test() {
   initialize_array(arr, sv);
   std::span<CharT> sp{arr};
 
-  // Mode: default
+  // Mode: default (`in` | `out`)
   {
     SpStream spSt(sp);
     std::basic_string<CharT, TraitsT> str1;
@@ -76,30 +76,18 @@ void test() {
     assert(str4 == CS("year"));
     assert(i4 == 2024);
   }
-  //   // Mode: `ios_base::in`
-  //   {
-  //     SpStream rhsSpSt{sp, std::ios_base::in};
-  //     SpStream spSt(std::move(rhsSpSt));
-  //     assert(spSt.span().data() == arr);
-  //     assert(!spSt.span().empty());
-  //     assert(spSt.span().size() == 4);
-  //   }
-  //   // Mode `ios_base::out`
-  //   {
-  //     SpStream rhsSpSt{sp, std::ios_base::out};
-  //     SpStream spSt(std::move(rhsSpSt));
-  //     assert(spSt.span().data() == arr);
-  //     assert(spSt.span().empty());
-  //     assert(spSt.span().size() == 0);
-  //   }
-  //   // Mode: multiple
-  //   {
-  //     SpStream rhsSpSt{sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary};
-  //     SpStream spSt(std::move(rhsSpSt));
-  //     assert(spSt.span().data() == arr);
-  //     assert(spSt.span().empty());
-  //     assert(spSt.span().size() == 0);
-  //   }
+  // Mode: `ios_base::in`
+  {
+    SpStream spSt{sp, std::ios_base::in};
+    //TODO
+    (void)spSt;
+  }
+  // Mode `ios_base::out`
+  {
+    SpStream spSt{sp, std::ios_base::out};
+    //TODO
+    (void)spSt;
+  }
 }
 
 int main(int, char**) {

>From 3eae8584c052d84bea2b54920f941c704f601ea1 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Fri, 15 Mar 2024 11:04:19 +0200
Subject: [PATCH 44/56] Tests: WIP `spanstream`

---
 .../spanbuf/spanbuf.members/span.pass.cpp     |   1 -
 .../spanbuf.members/span.span.pass.cpp        |   1 -
 .../spanstream/inherited.stream.ops.pass.cpp  |   2 +-
 .../spanstream.cons/assign.move.pass.cpp      |  86 +++++++++
 .../spanstream.cons/ctor.move.pass.cpp        |  86 +++++++++
 ....mode.pass.cpp => ctor.span.mode.pass.cpp} |  43 +++--
 .../spanstream.members/rdbuf.pass.cpp         |  87 +++++++++
 .../spanstream.members/span.pass.cpp          |  88 +++++++++
 .../spanstream.members/span.span.pass.cpp     | 171 ++++++++++++++++++
 .../swap.pass.cpp}                            |  27 +--
 .../spanstream.swap/swap_nonmember.pass.cpp   |  81 +++++++++
 11 files changed, 643 insertions(+), 30 deletions(-)
 create mode 100644 libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/assign.move.pass.cpp
 create mode 100644 libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/ctor.move.pass.cpp
 rename libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/{span.mode.pass.cpp => ctor.span.mode.pass.cpp} (73%)
 create mode 100644 libcxx/test/std/input.output/span.streams/spanstream/spanstream.members/rdbuf.pass.cpp
 create mode 100644 libcxx/test/std/input.output/span.streams/spanstream/spanstream.members/span.pass.cpp
 create mode 100644 libcxx/test/std/input.output/span.streams/spanstream/spanstream.members/span.span.pass.cpp
 rename libcxx/test/std/input.output/span.streams/spanstream/{spanstream.cons/move.pass.cpp => spanstream.swap/swap.pass.cpp} (77%)
 create mode 100644 libcxx/test/std/input.output/span.streams/spanstream/spanstream.swap/swap_nonmember.pass.cpp

diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.members/span.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.members/span.pass.cpp
index d868676c18886..bf21a0bc7844c 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.members/span.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.members/span.pass.cpp
@@ -22,7 +22,6 @@
 #include <spanstream>
 
 #include "constexpr_char_traits.h"
-#include "test_convertible.h"
 #include "test_macros.h"
 
 template <typename CharT, typename TraitsT = std::char_traits<CharT>>
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.members/span.span.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.members/span.span.pass.cpp
index e3c836d27e349..3bcfe3ec3ead1 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.members/span.span.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.members/span.span.pass.cpp
@@ -23,7 +23,6 @@
 #include <spanstream>
 
 #include "constexpr_char_traits.h"
-#include "test_convertible.h"
 #include "test_macros.h"
 
 template <typename CharT, typename TraitsT = std::char_traits<CharT>>
diff --git a/libcxx/test/std/input.output/span.streams/spanstream/inherited.stream.ops.pass.cpp b/libcxx/test/std/input.output/span.streams/spanstream/inherited.stream.ops.pass.cpp
index e0d161d92437f..ab43356a28846 100644
--- a/libcxx/test/std/input.output/span.streams/spanstream/inherited.stream.ops.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanstream/inherited.stream.ops.pass.cpp
@@ -12,7 +12,7 @@
 
 //   template<class charT, class traits = char_traits<charT>>
 //   class basic_spanstream
-//     : public basic_streambuf<charT, traits> {
+//     : public basic_iostream<charT, traits> {
 
 //   Test stream operations inherited from `basic_istream` and `basic_ostream`
 
diff --git a/libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/assign.move.pass.cpp b/libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/assign.move.pass.cpp
new file mode 100644
index 0000000000000..f59f975d062ff
--- /dev/null
+++ b/libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/assign.move.pass.cpp
@@ -0,0 +1,86 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <spanstream>
+
+//   template<class charT, class traits = char_traits<charT>>
+//   class basic_spanstream
+//     : public basic_iostream<charT, traits> {
+
+//     // [spanstream.cons], constructors
+
+//     basic_spanstream& operator=(basic_spanstream&& rhs);
+
+#include <cassert>
+#include <span>
+#include <spanstream>
+
+#include "constexpr_char_traits.h"
+#include "test_macros.h"
+
+template <typename CharT, typename TraitsT = std::char_traits<CharT>>
+void test() {
+  using SpStream = std::basic_ispanstream<CharT, TraitsT>;
+
+  CharT arr[4];
+  std::span<CharT> sp{arr};
+
+  // Mode: default (`in` | `out`)
+  {
+    SpStream rhsSpSt{sp};
+    SpStream spSt = std::move(rhsSpSt);
+    assert(spSt.span().data() == arr);
+    assert(!spSt.span().empty());
+    assert(spSt.span().size() == 4);
+  }
+  // Mode: `in`
+  {
+    SpStream rhsSpSt{sp, std::ios_base::in};
+    SpStream spSt = std::move(rhsSpSt);
+    assert(spSt.span().data() == arr);
+    assert(!spSt.span().empty());
+    assert(spSt.span().size() == 4);
+  }
+  // Mode `out`
+  {
+    SpStream rhsSpSt{sp, std::ios_base::out};
+    SpStream spSt = std::move(rhsSpSt);
+    assert(spSt.span().data() == arr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+  }
+  // Mode: multiple
+  {
+    SpStream rhsSpSt{sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary};
+    SpStream spSt = std::move(rhsSpSt);
+    assert(spSt.span().data() == arr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+  }
+  // Mode `ate`
+  {
+    SpStream rhsSpSt{sp, std::ios_base::in};
+    SpStream spSt = std::move(rhsSpSt);
+    assert(spSt.span().data() == arr);
+    assert(!spSt.span().empty());
+    assert(spSt.span().size() == 4);
+  }
+}
+
+int main(int, char**) {
+  test<char>();
+  test<char, constexpr_char_traits<char>>();
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  test<wchar_t>();
+  test<wchar_t, constexpr_char_traits<wchar_t>>();
+#endif
+
+  return 0;
+}
diff --git a/libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/ctor.move.pass.cpp b/libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/ctor.move.pass.cpp
new file mode 100644
index 0000000000000..e6367fb667fb6
--- /dev/null
+++ b/libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/ctor.move.pass.cpp
@@ -0,0 +1,86 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <spanstream>
+
+//   template<class charT, class traits = char_traits<charT>>
+//   class basic_spanstream
+//     : public basic_iostream<charT, traits> {
+
+//     // [spanstream.cons], constructors
+
+//     basic_spanstream(basic_spanstream&& rhs);
+
+#include <cassert>
+#include <span>
+#include <spanstream>
+
+#include "constexpr_char_traits.h"
+#include "test_macros.h"
+
+template <typename CharT, typename TraitsT = std::char_traits<CharT>>
+void test() {
+  using SpStream = std::basic_spanstream<CharT, TraitsT>;
+
+  CharT arr[4];
+  std::span<CharT> sp{arr};
+
+  // Mode: default (`in` | `out`)
+  {
+    SpStream rhsSpSt{sp};
+    SpStream spSt{std::move(rhsSpSt)};
+    assert(spSt.span().data() == arr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+  }
+  // Mode: `in`
+  {
+    SpStream rhsSpSt{sp, std::ios_base::in};
+    SpStream spSt{std::move(rhsSpSt)};
+    assert(spSt.span().data() == arr);
+    assert(!spSt.span().empty());
+    assert(spSt.span().size() == 4);
+  }
+  // Mode `out`
+  {
+    SpStream rhsSpSt{sp, std::ios_base::out};
+    SpStream spSt{std::move(rhsSpSt)};
+    assert(spSt.span().data() == arr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+  }
+  // Mode: multiple
+  {
+    SpStream rhsSpSt{sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary};
+    SpStream spSt{std::move(rhsSpSt)};
+    assert(spSt.span().data() == arr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+  }
+  // Mode `ate`
+  {
+    SpStream rhsSpSt{sp, std::ios_base::out | std::ios_base::ate};
+    SpStream spSt{std::move(rhsSpSt)};
+    assert(spSt.span().data() == arr);
+    assert(!spSt.span().empty());
+    assert(spSt.span().size() == 4);
+  }
+}
+
+int main(int, char**) {
+  test<char>();
+  test<char, constexpr_char_traits<char>>();
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  test<wchar_t>();
+  test<wchar_t, constexpr_char_traits<wchar_t>>();
+#endif
+
+  return 0;
+}
diff --git a/libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/span.mode.pass.cpp b/libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/ctor.span.mode.pass.cpp
similarity index 73%
rename from libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/span.mode.pass.cpp
rename to libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/ctor.span.mode.pass.cpp
index 122d210430d9f..5a6c7c1c90e2c 100644
--- a/libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/span.mode.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/ctor.span.mode.pass.cpp
@@ -12,15 +12,13 @@
 
 //   template<class charT, class traits = char_traits<charT>>
 //   class basic_spanstream
-//     : public basic_streambuf<charT, traits> {
+//     : public basic_iostream<charT, traits> {
 
-//     // [spanbuf.cons], constructors
-//
+//     // [spanstream.cons], constructors
 //     explicit basic_spanstream(std::span<charT> s,
-//                                ios_base::openmode which = ios_base::in);
+//                               ios_base::openmode which = ios_base::out | ios_base::in);
 
 #include <cassert>
-#include <concepts>
 #include <span>
 #include <spanstream>
 #include <utility>
@@ -53,58 +51,71 @@ void test() {
   CharT arr[4];
   std::span<CharT> sp{arr};
 
-  // Mode: default
+  // Mode: default (`in` | `out`)
   {
-    SpStream spSt(sp);
+    SpStream spSt{sp};
     assert(spSt.span().data() == arr);
     assert(spSt.span().empty());
     assert(spSt.span().size() == 0);
   }
   {
-    SpStream spSt(std::as_const(sp));
+    SpStream spSt{std::as_const(sp)};
     assert(spSt.span().data() == arr);
     assert(spSt.span().empty());
     assert(spSt.span().size() == 0);
   }
-  // Mode: `ios_base::in`
+  // Mode: `in`
   {
-    SpStream spSt(sp, std::ios_base::in);
+    SpStream spSt{sp, std::ios_base::in};
     assert(spSt.span().data() == arr);
     assert(!spSt.span().empty());
     assert(spSt.span().size() == 4);
   }
   {
-    SpStream spSt(std::as_const(sp), std::ios_base::in);
+    SpStream spSt{std::as_const(sp), std::ios_base::in};
     assert(spSt.span().data() == arr);
     assert(!spSt.span().empty());
     assert(spSt.span().size() == 4);
   }
-  // Mode `ios_base::out`
+  // Mode `out`
   {
-    SpStream spSt(sp, std::ios_base::out);
+    SpStream spSt{sp, std::ios_base::out};
     assert(spSt.span().data() == arr);
     assert(spSt.span().empty());
     assert(spSt.span().size() == 0);
   }
   {
-    SpStream spSt(std::as_const(sp), std::ios_base::out);
+    SpStream spSt{std::as_const(sp), std::ios_base::out};
     assert(spSt.span().data() == arr);
     assert(spSt.span().empty());
     assert(spSt.span().size() == 0);
   }
   // Mode: multiple
   {
-    SpStream spSt(sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary);
+    SpStream spSt{sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary};
     assert(spSt.span().data() == arr);
     assert(spSt.span().empty());
     assert(spSt.span().size() == 0);
   }
   {
-    SpStream spSt(std::as_const(sp), std::ios_base::in | std::ios_base::out | std::ios_base::binary);
+    SpStream spSt{std::as_const(sp), std::ios_base::in | std::ios_base::out | std::ios_base::binary};
     assert(spSt.span().data() == arr);
     assert(spSt.span().empty());
     assert(spSt.span().size() == 0);
   }
+  // Mode `ate`
+  {
+    SpStream spSt{sp, std::ios_base::out | std::ios_base::ate};
+    assert(spSt.span().data() == arr);
+    assert(!spSt.span().empty());
+    assert(spSt.span().size() == 4);
+  }
+  {
+    SpStream spSt{std::as_const(sp), std::ios_base::out | std::ios_base::ate};
+    assert(spSt.span().data() == arr);
+    assert(!spSt.span().empty());
+    assert(spSt.span().size() == 4);
+  }
 }
 
 int main(int, char**) {
diff --git a/libcxx/test/std/input.output/span.streams/spanstream/spanstream.members/rdbuf.pass.cpp b/libcxx/test/std/input.output/span.streams/spanstream/spanstream.members/rdbuf.pass.cpp
new file mode 100644
index 0000000000000..38f998fda05f8
--- /dev/null
+++ b/libcxx/test/std/input.output/span.streams/spanstream/spanstream.members/rdbuf.pass.cpp
@@ -0,0 +1,87 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <spanstream>
+
+//   template<class charT, class traits = char_traits<charT>>
+//   class basic_spanstream
+//     : public basic_iostream<charT, traits> {
+
+//     // [spanstream.members], members
+//     basic_spanbuf<charT, traits>* rdbuf() const noexcept;
+
+#include <cassert>
+#include <span>
+#include <spanstream>
+
+#include "constexpr_char_traits.h"
+#include "test_macros.h"
+
+template <typename CharT, typename TraitsT = std::char_traits<CharT>>
+void test() {
+  using SpStream = std::basic_spanstream<CharT, TraitsT>;
+
+  CharT arr[4];
+
+  std::span<CharT> sp{arr};
+  assert(sp.data() == arr);
+  assert(!sp.empty());
+  assert(sp.size() == 4);
+
+  // Mode: default (`in` | `out`)
+  {
+    SpStream spSt{sp};
+    assert(spSt.rdbuf()->span().data() == arr);
+    // Mode `out` counts read characters
+    assert(spSt.rdbuf()->span().empty());
+    assert(spSt.rdbuf()->span().size() == 0);
+  }
+  // Mode: `in`
+  {
+    SpStream spSt{sp, std::ios_base::in};
+    assert(spSt.rdbuf()->span().data() == arr);
+    assert(!spSt.rdbuf()->span().empty());
+    assert(spSt.rdbuf()->span().size() == 4);
+  }
+  // Mode: `out`
+  {
+    SpStream spSt{sp, std::ios_base::out};
+    assert(spSt.rdbuf()->span().data() == arr);
+    // Mode `out` counts read characters
+    assert(spSt.rdbuf()->span().empty());
+    assert(spSt.rdbuf()->span().size() == 0);
+  }
+  // Mode: multiple
+  {
+    SpStream spSt{sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary};
+    assert(spSt.rdbuf()->span().data() == arr);
+    // Mode `out` counts read characters
+    assert(spSt.rdbuf()->span().empty());
+    assert(spSt.rdbuf()->span().size() == 0);
+  }
+  // Mode: `ate`
+  {
+    SpStream spSt{sp, std::ios_base::out | std::ios_base::ate};
+    assert(spSt.rdbuf()->span().data() == arr);
+    assert(!spSt.rdbuf()->span().empty());
+    assert(spSt.rdbuf()->span().size() == 4);
+  }
+}
+
+int main(int, char**) {
+  test<char>();
+  test<char, constexpr_char_traits<char>>();
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  test<wchar_t>();
+  test<wchar_t, constexpr_char_traits<wchar_t>>();
+#endif
+
+  return 0;
+}
diff --git a/libcxx/test/std/input.output/span.streams/spanstream/spanstream.members/span.pass.cpp b/libcxx/test/std/input.output/span.streams/spanstream/spanstream.members/span.pass.cpp
new file mode 100644
index 0000000000000..96ba53a588e6e
--- /dev/null
+++ b/libcxx/test/std/input.output/span.streams/spanstream/spanstream.members/span.pass.cpp
@@ -0,0 +1,88 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <spanstream>
+
+//   template<class charT, class traits = char_traits<charT>>
+//   class basic_spanstream
+//     : public basic_iostream<charT, traits> {
+
+//     // [spanstream.members], members
+
+//     std::span<charT> span() const noexcept;
+
+#include <cassert>
+#include <span>
+#include <spanstream>
+
+#include "constexpr_char_traits.h"
+#include "test_macros.h"
+
+template <typename CharT, typename TraitsT = std::char_traits<CharT>>
+void test() {
+  using SpStream = std::basic_spanstream<CharT, TraitsT>;
+
+  CharT arr[4];
+
+  std::span<CharT> sp{arr};
+  assert(sp.data() == arr);
+  assert(!sp.empty());
+  assert(sp.size() == 4);
+
+  // Mode: default (`in` | `out`)
+  {
+    SpStream spSt{sp};
+    assert(spSt.span().data() == arr);
+    // Mode `out` counts read characters
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+  }
+  // Mode: `in`
+  {
+    SpStream spSt{sp, std::ios_base::in};
+    assert(spSt.span().data() == arr);
+    assert(!spSt.span().empty());
+    assert(spSt.span().size() == 4);
+  }
+  // Mode: `out`
+  {
+    SpStream spSt{sp, std::ios_base::out};
+    assert(spSt.span().data() == arr);
+    // Mode `out` counts read characters
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+  }
+  // Mode: multiple
+  {
+    SpStream spSt{sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary};
+    assert(spSt.span().data() == arr);
+    // Mode `out` counts read characters
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+  }
+  // Mode: `ate`
+  {
+    SpStream spSt{sp, std::ios_base::out | std::ios_base::ate};
+    assert(spSt.span().data() == arr);
+    assert(!spSt.span().empty());
+    assert(spSt.span().size() == 4);
+  }
+}
+
+int main(int, char**) {
+  test<char>();
+  test<char, constexpr_char_traits<char>>();
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  test<wchar_t>();
+  test<wchar_t, constexpr_char_traits<wchar_t>>();
+#endif
+
+  return 0;
+}
diff --git a/libcxx/test/std/input.output/span.streams/spanstream/spanstream.members/span.span.pass.cpp b/libcxx/test/std/input.output/span.streams/spanstream/spanstream.members/span.span.pass.cpp
new file mode 100644
index 0000000000000..2aae1c34a8bb8
--- /dev/null
+++ b/libcxx/test/std/input.output/span.streams/spanstream/spanstream.members/span.span.pass.cpp
@@ -0,0 +1,171 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <spanstream>
+
+//   template<class charT, class traits = char_traits<charT>>
+//   class basic_spanstream
+//     : public basic_iostream<charT, traits> {
+
+//     // [spanstream.members], members
+
+//     void span(std::span<charT> s) noexcept;
+
+#include <cassert>
+#include <span>
+#include <spanstream>
+
+#include "constexpr_char_traits.h"
+#include "test_macros.h"
+
+template <typename CharT, typename TraitsT = std::char_traits<CharT>>
+void test() {
+  using SpStream = std::basic_spanbuf<CharT, TraitsT>;
+
+  CharT arr[4];
+
+  std::span<CharT> sp{arr};
+  assert(sp.data() == arr);
+  assert(!sp.empty());
+  assert(sp.size() == 4);
+
+  // Mode: default (`in` | `out`)
+  {
+    SpStream spSt;
+    assert(spSt.span().data() == nullptr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+
+    spSt.span(arr);
+    assert(spSt.span().data() == arr);
+    // Mode `out` counts read characters
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+  }
+  {
+    SpStream spSt;
+    assert(spSt.span().data() == nullptr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+
+    spSt.span(sp);
+    assert(spSt.span().data() == arr);
+    // Mode `out` counts read characters
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+  }
+  // Mode: `in`
+  {
+    SpStream spSt{std::ios_base::in};
+    assert(spSt.span().data() == nullptr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+
+    spSt.span(arr);
+    assert(spSt.span().data() == arr);
+    assert(!spSt.span().empty());
+    assert(spSt.span().size() == 4);
+  }
+  {
+    SpStream spSt{std::ios_base::in};
+    assert(spSt.span().data() == nullptr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+
+    spSt.span(sp);
+    assert(spSt.span().data() == arr);
+    assert(!spSt.span().empty());
+    assert(spSt.span().size() == 4);
+  }
+  // Mode: `out`
+  {
+    SpStream spSt{std::ios_base::out};
+    assert(spSt.span().data() == nullptr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+
+    spSt.span(arr);
+    assert(spSt.span().data() == arr);
+    // Mode `out` counts read characters
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+  }
+  {
+    SpStream spSt{std::ios_base::out};
+    assert(spSt.span().data() == nullptr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+
+    spSt.span(sp);
+    assert(spSt.span().data() == arr);
+    // Mode `out` counts read characters
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+  }
+  // Mode: multiple
+  {
+    SpStream spSt{std::ios_base::in | std::ios_base::out | std::ios_base::binary};
+    assert(spSt.span().data() == nullptr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+
+    spSt.span(arr);
+    assert(spSt.span().data() == arr);
+    // Mode `out` counts read characters
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+  }
+  {
+    SpStream spSt{std::ios_base::in | std::ios_base::out | std::ios_base::binary};
+    assert(spSt.span().data() == nullptr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+
+    spSt.span(sp);
+    assert(spSt.span().data() == arr);
+    // Mode `out` counts read characters
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+  }
+  // Mode: `ate`
+  {
+    SpStream spSt{std::ios_base::out | std::ios_base::ate};
+    assert(spSt.span().data() == nullptr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+
+    spSt.span(arr);
+    assert(spSt.span().data() == arr);
+    assert(!spSt.span().empty());
+    assert(spSt.span().size() == 4);
+  }
+  {
+    SpStream spSt{std::ios_base::out | std::ios_base::ate};
+    assert(spSt.span().data() == nullptr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+
+    spSt.span(sp);
+    assert(spSt.span().data() == arr);
+    assert(!spSt.span().empty());
+    assert(spSt.span().size() == 4);
+  }
+}
+
+int main(int, char**) {
+  test<char>();
+  test<char, constexpr_char_traits<char>>();
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  test<wchar_t>();
+  test<wchar_t, constexpr_char_traits<wchar_t>>();
+#endif
+
+  return 0;
+}
diff --git a/libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/move.pass.cpp b/libcxx/test/std/input.output/span.streams/spanstream/spanstream.swap/swap.pass.cpp
similarity index 77%
rename from libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/move.pass.cpp
rename to libcxx/test/std/input.output/span.streams/spanstream/spanstream.swap/swap.pass.cpp
index 73206597cd27d..6a3e736e34f68 100644
--- a/libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/move.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanstream/spanstream.swap/swap.pass.cpp
@@ -12,11 +12,10 @@
 
 //   template<class charT, class traits = char_traits<charT>>
 //   class basic_spanstream
-//     : public basic_streambuf<charT, traits> {
+//     : public basic_iostream<charT, traits> {
 
-//     // [spanbuf.cons], constructors
-//
-//     basic_spanstream(basic_spanstream&& rhs);
+//    // [spanstream.swap], swap
+//    void swap(basic_spanstream& rhs);
 
 #include <cassert>
 #include <concepts>
@@ -29,23 +28,27 @@
 
 template <typename CharT, typename TraitsT = std::char_traits<CharT>>
 void test() {
-  using SpStream = std::basic_spanstream<CharT, TraitsT>;
+  using SpStream = std::basic_ispanstream<CharT, TraitsT>;
 
   CharT arr[4];
   std::span<CharT> sp{arr};
 
+  // TODO:
+
   // Mode: default
   {
     SpStream rhsSpSt{sp};
-    SpStream spSt(std::move(rhsSpSt));
+    SpStream spSt(std::span<CharT>{});
+    spSt.swap(rhsSpSt);
     assert(spSt.span().data() == arr);
-    assert(spSt.span().empty());
-    assert(spSt.span().size() == 0);
+    assert(!spSt.span().empty());
+    assert(spSt.span().size() == 4);
   }
   // Mode: `ios_base::in`
   {
     SpStream rhsSpSt{sp, std::ios_base::in};
-    SpStream spSt(std::move(rhsSpSt));
+    SpStream spSt(std::span<CharT>{});
+    spSt.swap(rhsSpSt);
     assert(spSt.span().data() == arr);
     assert(!spSt.span().empty());
     assert(spSt.span().size() == 4);
@@ -53,7 +56,8 @@ void test() {
   // Mode `ios_base::out`
   {
     SpStream rhsSpSt{sp, std::ios_base::out};
-    SpStream spSt(std::move(rhsSpSt));
+    SpStream spSt(std::span<CharT>{});
+    spSt.swap(rhsSpSt);
     assert(spSt.span().data() == arr);
     assert(spSt.span().empty());
     assert(spSt.span().size() == 0);
@@ -61,7 +65,8 @@ void test() {
   // Mode: multiple
   {
     SpStream rhsSpSt{sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary};
-    SpStream spSt(std::move(rhsSpSt));
+    SpStream spSt(std::span<CharT>{});
+    spSt.swap(rhsSpSt);
     assert(spSt.span().data() == arr);
     assert(spSt.span().empty());
     assert(spSt.span().size() == 0);
diff --git a/libcxx/test/std/input.output/span.streams/spanstream/spanstream.swap/swap_nonmember.pass.cpp b/libcxx/test/std/input.output/span.streams/spanstream/spanstream.swap/swap_nonmember.pass.cpp
new file mode 100644
index 0000000000000..5319ca57ce9de
--- /dev/null
+++ b/libcxx/test/std/input.output/span.streams/spanstream/spanstream.swap/swap_nonmember.pass.cpp
@@ -0,0 +1,81 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <spanstream>
+
+//   template<class charT, class traits>
+//     void swap(basic_spanstream<charT, traits>& x, basic_spanstream<charT, traits>& y);
+
+#include <cassert>
+#include <concepts>
+#include <span>
+#include <spanstream>
+
+#include "constexpr_char_traits.h"
+#include "test_convertible.h"
+#include "test_macros.h"
+
+template <typename CharT, typename TraitsT = std::char_traits<CharT>>
+void test() {
+  using SpStream = std::basic_ispanstream<CharT, TraitsT>;
+
+  CharT arr[4];
+  std::span<CharT> sp{arr};
+
+  // TODO:
+
+  // Mode: default
+  {
+    SpStream rhsSpSt{sp};
+    SpStream spSt(std::span<CharT>{});
+    std::swap(spSt, rhsSpSt);
+    assert(spSt.span().data() == arr);
+    assert(!spSt.span().empty());
+    assert(spSt.span().size() == 4);
+  }
+  // Mode: `ios_base::in`
+  {
+    SpStream rhsSpSt{sp, std::ios_base::in};
+    SpStream spSt(std::span<CharT>{});
+    std::swap(spSt, rhsSpSt);
+    assert(spSt.span().data() == arr);
+    assert(!spSt.span().empty());
+    assert(spSt.span().size() == 4);
+  }
+  // Mode `ios_base::out`
+  {
+    SpStream rhsSpSt{sp, std::ios_base::out};
+    SpStream spSt(std::span<CharT>{});
+    std::swap(spSt, rhsSpSt);
+    assert(spSt.span().data() == arr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+  }
+  // Mode: multiple
+  {
+    SpStream rhsSpSt{sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary};
+    SpStream spSt(std::span<CharT>{});
+    std::swap(spSt, rhsSpSt);
+    assert(spSt.span().data() == arr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+  }
+}
+
+int main(int, char**) {
+  test<char>();
+  test<char, constexpr_char_traits<char>>();
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  test<wchar_t>();
+  test<wchar_t, constexpr_char_traits<wchar_t>>();
+#endif
+
+  return 0;
+}

>From eeecd2d06dcb2587a88519b31c3ef2f9fe5ff501 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Fri, 15 Mar 2024 11:40:36 +0200
Subject: [PATCH 45/56] Tests: `spanstream`

---
 .../ispanstream.assign/move.pass.cpp          |  5 +-
 .../ispanstream.assign/swap.pass.cpp          |  4 +-
 .../swap_nonmember.pass.cpp                   |  4 +-
 .../ispanstream.cons/move.pass.cpp            |  4 +-
 .../ispanstream.cons/span.mode.pass.cpp       |  4 +-
 .../ospanstream.cons/move.pass.cpp            |  4 +-
 .../ospanstream.cons/span.mode.pass.cpp       |  4 +-
 .../spanbuf/spanbuf.assign/swap.pass.cpp      |  7 +-
 .../spanbuf.assign/swap_nonmember.pass.cpp    |  7 +-
 .../spanbuf/spanbuf.virtuals/setbuf.pass.cpp  |  6 +-
 .../spanstream/inherited.stream.ops.pass.cpp  |  4 +-
 .../spanstream/spanstream.swap/swap.pass.cpp  | 97 ++++++++++++++++---
 .../spanstream.swap/swap_nonmember.pass.cpp   | 96 +++++++++++++++---
 13 files changed, 192 insertions(+), 54 deletions(-)

diff --git a/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.assign/move.pass.cpp b/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.assign/move.pass.cpp
index 75ae944d01c82..cc14bfb41671e 100644
--- a/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.assign/move.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.assign/move.pass.cpp
@@ -24,7 +24,6 @@
 #include <spanstream>
 
 #include "constexpr_char_traits.h"
-#include "test_convertible.h"
 #include "test_macros.h"
 
 template <typename CharT, typename TraitsT = std::char_traits<CharT>>
@@ -44,7 +43,7 @@ void test() {
     assert(!spSt.span().empty());
     assert(spSt.span().size() == 4);
   }
-  // Mode: `ios_base::in`
+  // Mode: `in`
   {
     SpStream rhsSpSt{sp, std::ios_base::in};
     SpStream spSt = std::move(rhsSpSt);
@@ -52,7 +51,7 @@ void test() {
     assert(!spSt.span().empty());
     assert(spSt.span().size() == 4);
   }
-  // Mode `ios_base::out`
+  // Mode `out`
   {
     SpStream rhsSpSt{sp, std::ios_base::out};
     SpStream spSt = std::move(rhsSpSt);
diff --git a/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.assign/swap.pass.cpp b/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.assign/swap.pass.cpp
index 1aef6a3f47629..c70d9017e53bd 100644
--- a/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.assign/swap.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.assign/swap.pass.cpp
@@ -44,7 +44,7 @@ void test() {
     assert(!spSt.span().empty());
     assert(spSt.span().size() == 4);
   }
-  // Mode: `ios_base::in`
+  // Mode: `in`
   {
     SpStream rhsSpSt{sp, std::ios_base::in};
     SpStream spSt(std::span<CharT>{});
@@ -53,7 +53,7 @@ void test() {
     assert(!spSt.span().empty());
     assert(spSt.span().size() == 4);
   }
-  // Mode `ios_base::out`
+  // Mode `out`
   {
     SpStream rhsSpSt{sp, std::ios_base::out};
     SpStream spSt(std::span<CharT>{});
diff --git a/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.assign/swap_nonmember.pass.cpp b/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.assign/swap_nonmember.pass.cpp
index 165dc72673e9f..06f59daafac08 100644
--- a/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.assign/swap_nonmember.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.assign/swap_nonmember.pass.cpp
@@ -40,7 +40,7 @@ void test() {
     assert(!spSt.span().empty());
     assert(spSt.span().size() == 4);
   }
-  // Mode: `ios_base::in`
+  // Mode: `in`
   {
     SpStream rhsSpSt{sp, std::ios_base::in};
     SpStream spSt(std::span<CharT>{});
@@ -49,7 +49,7 @@ void test() {
     assert(!spSt.span().empty());
     assert(spSt.span().size() == 4);
   }
-  // Mode `ios_base::out`
+  // Mode `out`
   {
     SpStream rhsSpSt{sp, std::ios_base::out};
     SpStream spSt(std::span<CharT>{});
diff --git a/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/move.pass.cpp b/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/move.pass.cpp
index 2207b773bd9ce..aafcbf6c88961 100644
--- a/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/move.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/move.pass.cpp
@@ -42,7 +42,7 @@ void test() {
     assert(!spSt.span().empty());
     assert(spSt.span().size() == 4);
   }
-  // Mode: `ios_base::in`
+  // Mode: `in`
   {
     SpStream rhsSpSt{sp, std::ios_base::in};
     SpStream spSt(std::move(rhsSpSt));
@@ -50,7 +50,7 @@ void test() {
     assert(!spSt.span().empty());
     assert(spSt.span().size() == 4);
   }
-  // Mode `ios_base::out`
+  // Mode `out`
   {
     SpStream rhsSpSt{sp, std::ios_base::out};
     SpStream spSt(std::move(rhsSpSt));
diff --git a/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/span.mode.pass.cpp b/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/span.mode.pass.cpp
index 55b2aaf5c3b2b..75691ebc84fc6 100644
--- a/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/span.mode.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/span.mode.pass.cpp
@@ -66,7 +66,7 @@ void test() {
     assert(!spSt.span().empty());
     assert(spSt.span().size() == 4);
   }
-  // Mode: `ios_base::in`
+  // Mode: `in`
   {
     SpStream spSt(sp, std::ios_base::in);
     assert(spSt.span().data() == arr);
@@ -79,7 +79,7 @@ void test() {
     assert(!spSt.span().empty());
     assert(spSt.span().size() == 4);
   }
-  // Mode `ios_base::out`
+  // Mode `out`
   {
     SpStream spSt(sp, std::ios_base::out);
     assert(spSt.span().data() == arr);
diff --git a/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.cons/move.pass.cpp b/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.cons/move.pass.cpp
index 43354d6b8dfcb..f361f0489e32f 100644
--- a/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.cons/move.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.cons/move.pass.cpp
@@ -42,7 +42,7 @@ void test() {
     assert(spSt.span().empty());
     assert(spSt.span().size() == 0);
   }
-  // Mode: `ios_base::in`
+  // Mode: `in`
   {
     SpStream rhsSpSt{sp, std::ios_base::in};
     SpStream spSt(std::move(rhsSpSt));
@@ -50,7 +50,7 @@ void test() {
     assert(spSt.span().empty());
     assert(spSt.span().size() == 0);
   }
-  // Mode `ios_base::out`
+  // Mode `out`
   {
     SpStream rhsSpSt{sp, std::ios_base::out};
     SpStream spSt(std::move(rhsSpSt));
diff --git a/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.cons/span.mode.pass.cpp b/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.cons/span.mode.pass.cpp
index fe274e9208c62..3e2a7f1604aa5 100644
--- a/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.cons/span.mode.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.cons/span.mode.pass.cpp
@@ -66,7 +66,7 @@ void test() {
     assert(spSt.span().empty());
     assert(spSt.span().size() == 0);
   }
-  // Mode: `ios_base::in`
+  // Mode: `in`
   {
     SpStream spSt(sp, std::ios_base::in);
     assert(spSt.span().data() == arr);
@@ -79,7 +79,7 @@ void test() {
     assert(spSt.span().empty());
     assert(spSt.span().size() == 0);
   }
-  // Mode `ios_base::out`
+  // Mode `out`
   {
     SpStream spSt(sp, std::ios_base::out);
     assert(spSt.span().data() == arr);
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/swap.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/swap.pass.cpp
index 26b305333e42e..0adbd21a7ee62 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/swap.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/swap.pass.cpp
@@ -22,7 +22,6 @@
 #include <spanstream>
 
 #include "constexpr_char_traits.h"
-#include "test_convertible.h"
 #include "test_macros.h"
 
 template <typename CharT, typename TraitsT = std::char_traits<CharT>>
@@ -58,7 +57,7 @@ void test() {
     assert(rhsSpBuf.span().empty());
     assert(rhsSpBuf.span().size() == 0);
   }
-  // Mode: `ios_base::in`
+  // Mode: `in`
   {
     SpBuf rhsSpBuf{sp, std::ios_base::in};
     assert(rhsSpBuf.span().data() == arr);
@@ -78,7 +77,7 @@ void test() {
     assert(rhsSpBuf.span().empty());
     assert(rhsSpBuf.span().size() == 0);
   }
-  // Mode `ios_base::out`
+  // Mode `out`
   {
     SpBuf rhsSpBuf{sp, std::ios_base::out};
     assert(rhsSpBuf.span().data() == arr);
@@ -122,7 +121,7 @@ void test() {
     assert(rhsSpBuf.span().empty());
     assert(rhsSpBuf.span().size() == 0);
   }
-  // Mode: `ios_base::ate`
+  // Mode: `ate`
   {
     SpBuf rhsSpBuf{sp, std::ios_base::out | std::ios_base::ate};
     assert(rhsSpBuf.span().data() == arr);
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/swap_nonmember.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/swap_nonmember.pass.cpp
index 681f157553326..cfbd8e9948a57 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/swap_nonmember.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/swap_nonmember.pass.cpp
@@ -18,7 +18,6 @@
 #include <spanstream>
 
 #include "constexpr_char_traits.h"
-#include "test_convertible.h"
 #include "test_macros.h"
 
 template <typename CharT, typename TraitsT = std::char_traits<CharT>>
@@ -54,7 +53,7 @@ void test() {
     assert(rhsSpBuf.span().empty());
     assert(rhsSpBuf.span().size() == 0);
   }
-  // Mode: `ios_base::in`
+  // Mode: `in`
   {
     SpBuf rhsSpBuf{sp, std::ios_base::in};
     assert(rhsSpBuf.span().data() == arr);
@@ -74,7 +73,7 @@ void test() {
     assert(rhsSpBuf.span().empty());
     assert(rhsSpBuf.span().size() == 0);
   }
-  // Mode `ios_base::out`
+  // Mode `out`
   {
     SpBuf rhsSpBuf{sp, std::ios_base::out};
     assert(rhsSpBuf.span().data() == arr);
@@ -118,7 +117,7 @@ void test() {
     assert(rhsSpBuf.span().empty());
     assert(rhsSpBuf.span().size() == 0);
   }
-  // Mode: `ios_base::ate`
+  // Mode: `ate`
   {
     SpBuf rhsSpBuf{sp, std::ios_base::out | std::ios_base::ate};
     assert(rhsSpBuf.span().data() == arr);
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/setbuf.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/setbuf.pass.cpp
index b0d6471097998..254f4cdc40c0c 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/setbuf.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.virtuals/setbuf.pass.cpp
@@ -46,7 +46,7 @@ void test() {
     assert(spBuf.span().empty());
     assert(spBuf.span().size() == 0);
   }
-  // Mode: `ios_base::in`
+  // Mode: `in`
   {
     SpBuf spBuf{sp, std::ios_base::in};
     assert(spBuf.span().data() == arr);
@@ -58,7 +58,7 @@ void test() {
     assert(spBuf.span().empty());
     assert(spBuf.span().size() == 0);
   }
-  // Mode `ios_base::out`
+  // Mode `out`
   {
     SpBuf spBuf{sp, std::ios_base::out};
     assert(spBuf.span().data() == arr);
@@ -86,7 +86,7 @@ void test() {
     assert(spBuf.span().empty());
     assert(spBuf.span().size() == 0);
   }
-  // Mode: `ios_base::ate`
+  // Mode: `ate`
   {
     SpBuf spBuf{sp, std::ios_base::out | std::ios_base::ate};
     assert(spBuf.span().data() == arr);
diff --git a/libcxx/test/std/input.output/span.streams/spanstream/inherited.stream.ops.pass.cpp b/libcxx/test/std/input.output/span.streams/spanstream/inherited.stream.ops.pass.cpp
index ab43356a28846..a03ff9d257d63 100644
--- a/libcxx/test/std/input.output/span.streams/spanstream/inherited.stream.ops.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanstream/inherited.stream.ops.pass.cpp
@@ -76,13 +76,13 @@ void test() {
     assert(str4 == CS("year"));
     assert(i4 == 2024);
   }
-  // Mode: `ios_base::in`
+  // Mode: `in`
   {
     SpStream spSt{sp, std::ios_base::in};
     //TODO
     (void)spSt;
   }
-  // Mode `ios_base::out`
+  // Mode `out`
   {
     SpStream spSt{sp, std::ios_base::out};
     //TODO
diff --git a/libcxx/test/std/input.output/span.streams/spanstream/spanstream.swap/swap.pass.cpp b/libcxx/test/std/input.output/span.streams/spanstream/spanstream.swap/swap.pass.cpp
index 6a3e736e34f68..4b29b153664ce 100644
--- a/libcxx/test/std/input.output/span.streams/spanstream/spanstream.swap/swap.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanstream/spanstream.swap/swap.pass.cpp
@@ -17,59 +17,130 @@
 //    // [spanstream.swap], swap
 //    void swap(basic_spanstream& rhs);
 
+
 #include <cassert>
-#include <concepts>
 #include <span>
 #include <spanstream>
 
 #include "constexpr_char_traits.h"
-#include "test_convertible.h"
 #include "test_macros.h"
 
 template <typename CharT, typename TraitsT = std::char_traits<CharT>>
 void test() {
-  using SpStream = std::basic_ispanstream<CharT, TraitsT>;
+  using SpStream = std::basic_spanstream<CharT, TraitsT>;
 
   CharT arr[4];
-  std::span<CharT> sp{arr};
 
-  // TODO:
+  std::span<CharT> sp{arr};
+  assert(sp.data() == arr);
+  assert(!sp.empty());
+  assert(sp.size() == 4);
 
-  // Mode: default
+  // Mode: default (`in` | `out`)
   {
     SpStream rhsSpSt{sp};
-    SpStream spSt(std::span<CharT>{});
+    assert(rhsSpSt.span().data() == arr);
+    // Mode `out` counts read characters
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
+
+    SpStream spSt{std::span<CharT>{}};
+    assert(spSt.span().data() == nullptr);
+    // Mode `out` counts read characters
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+
     spSt.swap(rhsSpSt);
     assert(spSt.span().data() == arr);
-    assert(!spSt.span().empty());
-    assert(spSt.span().size() == 4);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+    assert(rhsSpSt.span().data() == nullptr);
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
   }
-  // Mode: `ios_base::in`
+  // Mode: `in`
   {
     SpStream rhsSpSt{sp, std::ios_base::in};
+    assert(rhsSpSt.span().data() == arr);
+    assert(!rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 4);
+
     SpStream spSt(std::span<CharT>{});
+    assert(spSt.span().data() == nullptr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+
     spSt.swap(rhsSpSt);
     assert(spSt.span().data() == arr);
     assert(!spSt.span().empty());
     assert(spSt.span().size() == 4);
+    assert(rhsSpSt.span().data() == nullptr);
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
   }
-  // Mode `ios_base::out`
+  // Mode `out`
   {
     SpStream rhsSpSt{sp, std::ios_base::out};
-    SpStream spSt(std::span<CharT>{});
+    assert(rhsSpSt.span().data() == arr);
+    // Mode `out` counts read characters
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
+
+    SpStream spSt{std::span<CharT>{}};
+    assert(spSt.span().data() == nullptr);
+    // Mode `out` counts read characters
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+
     spSt.swap(rhsSpSt);
     assert(spSt.span().data() == arr);
     assert(spSt.span().empty());
     assert(spSt.span().size() == 0);
+    assert(rhsSpSt.span().data() == nullptr);
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
   }
   // Mode: multiple
   {
     SpStream rhsSpSt{sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary};
-    SpStream spSt(std::span<CharT>{});
+    assert(rhsSpSt.span().data() == arr);
+    // Mode `out` counts read characters
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
+
+    SpStream spSt{std::span<CharT>{}};
+    assert(spSt.span().data() == nullptr);
+    // Mode `out` counts read characters
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+
     spSt.swap(rhsSpSt);
     assert(spSt.span().data() == arr);
     assert(spSt.span().empty());
     assert(spSt.span().size() == 0);
+    assert(rhsSpSt.span().data() == nullptr);
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
+  }
+  // Mode: `ate`
+  {
+    SpStream rhsSpSt{sp, std::ios_base::out | std::ios_base::ate};
+    assert(rhsSpSt.span().data() == arr);
+    assert(!rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 4);
+
+    SpStream spSt(std::span<CharT>{});
+    assert(spSt.span().data() == nullptr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+
+    spSt.swap(rhsSpSt);
+    assert(spSt.span().data() == arr);
+    assert(!spSt.span().empty());
+    assert(spSt.span().size() == 4);
+    assert(rhsSpSt.span().data() == nullptr);
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
   }
 }
 
diff --git a/libcxx/test/std/input.output/span.streams/spanstream/spanstream.swap/swap_nonmember.pass.cpp b/libcxx/test/std/input.output/span.streams/spanstream/spanstream.swap/swap_nonmember.pass.cpp
index 5319ca57ce9de..50fd1cab63b7c 100644
--- a/libcxx/test/std/input.output/span.streams/spanstream/spanstream.swap/swap_nonmember.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanstream/spanstream.swap/swap_nonmember.pass.cpp
@@ -14,58 +14,128 @@
 //     void swap(basic_spanstream<charT, traits>& x, basic_spanstream<charT, traits>& y);
 
 #include <cassert>
-#include <concepts>
 #include <span>
 #include <spanstream>
 
 #include "constexpr_char_traits.h"
-#include "test_convertible.h"
 #include "test_macros.h"
 
 template <typename CharT, typename TraitsT = std::char_traits<CharT>>
 void test() {
-  using SpStream = std::basic_ispanstream<CharT, TraitsT>;
+  using SpStream = std::basic_spanstream<CharT, TraitsT>;
 
   CharT arr[4];
-  std::span<CharT> sp{arr};
 
-  // TODO:
+  std::span<CharT> sp{arr};
+  assert(sp.data() == arr);
+  assert(!sp.empty());
+  assert(sp.size() == 4);
 
-  // Mode: default
+  // Mode: default (`in` | `out`)
   {
     SpStream rhsSpSt{sp};
-    SpStream spSt(std::span<CharT>{});
+    assert(rhsSpSt.span().data() == arr);
+    // Mode `out` counts read characters
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
+
+    SpStream spSt{std::span<CharT>{}};
+    assert(spSt.span().data() == nullptr);
+    // Mode `out` counts read characters
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+
     std::swap(spSt, rhsSpSt);
     assert(spSt.span().data() == arr);
-    assert(!spSt.span().empty());
-    assert(spSt.span().size() == 4);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+    assert(rhsSpSt.span().data() == nullptr);
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
   }
-  // Mode: `ios_base::in`
+  // Mode: `in`
   {
     SpStream rhsSpSt{sp, std::ios_base::in};
+    assert(rhsSpSt.span().data() == arr);
+    assert(!rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 4);
+
     SpStream spSt(std::span<CharT>{});
+    assert(spSt.span().data() == nullptr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+
     std::swap(spSt, rhsSpSt);
     assert(spSt.span().data() == arr);
     assert(!spSt.span().empty());
     assert(spSt.span().size() == 4);
+    assert(rhsSpSt.span().data() == nullptr);
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
   }
-  // Mode `ios_base::out`
+  // Mode `out`
   {
     SpStream rhsSpSt{sp, std::ios_base::out};
-    SpStream spSt(std::span<CharT>{});
+    assert(rhsSpSt.span().data() == arr);
+    // Mode `out` counts read characters
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
+
+    SpStream spSt{std::span<CharT>{}};
+    assert(spSt.span().data() == nullptr);
+    // Mode `out` counts read characters
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+
     std::swap(spSt, rhsSpSt);
     assert(spSt.span().data() == arr);
     assert(spSt.span().empty());
     assert(spSt.span().size() == 0);
+    assert(rhsSpSt.span().data() == nullptr);
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
   }
   // Mode: multiple
   {
     SpStream rhsSpSt{sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary};
-    SpStream spSt(std::span<CharT>{});
+    assert(rhsSpSt.span().data() == arr);
+    // Mode `out` counts read characters
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
+
+    SpStream spSt{std::span<CharT>{}};
+    assert(spSt.span().data() == nullptr);
+    // Mode `out` counts read characters
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+
     std::swap(spSt, rhsSpSt);
     assert(spSt.span().data() == arr);
     assert(spSt.span().empty());
     assert(spSt.span().size() == 0);
+    assert(rhsSpSt.span().data() == nullptr);
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
+  }
+  // Mode: `ate`
+  {
+    SpStream rhsSpSt{sp, std::ios_base::out | std::ios_base::ate};
+    assert(rhsSpSt.span().data() == arr);
+    assert(!rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 4);
+
+    SpStream spSt(std::span<CharT>{});
+    assert(spSt.span().data() == nullptr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+
+    std::swap(spSt, rhsSpSt);
+    assert(spSt.span().data() == arr);
+    assert(!spSt.span().empty());
+    assert(spSt.span().size() == 4);
+    assert(rhsSpSt.span().data() == nullptr);
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
   }
 }
 

>From 831edf3e6d450e1b0495fffbce0ddf29547a58d2 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Fri, 15 Mar 2024 11:47:23 +0200
Subject: [PATCH 46/56] Tests: Fix CI

---
 .../span.streams/spanstream/spanstream.swap/swap.pass.cpp        | 1 -
 1 file changed, 1 deletion(-)

diff --git a/libcxx/test/std/input.output/span.streams/spanstream/spanstream.swap/swap.pass.cpp b/libcxx/test/std/input.output/span.streams/spanstream/spanstream.swap/swap.pass.cpp
index 4b29b153664ce..e4169cb581b3b 100644
--- a/libcxx/test/std/input.output/span.streams/spanstream/spanstream.swap/swap.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanstream/spanstream.swap/swap.pass.cpp
@@ -17,7 +17,6 @@
 //    // [spanstream.swap], swap
 //    void swap(basic_spanstream& rhs);
 
-
 #include <cassert>
 #include <span>
 #include <spanstream>

>From a2fc513a896dd2215792a6169c7de3a9a3f979e8 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Fri, 15 Mar 2024 13:44:47 +0200
Subject: [PATCH 47/56] Tests: tweaks `spanbuf` and `spanstream`

---
 .../span.streams/spanbuf/spanbuf.assign/swap.pass.cpp         | 4 ++++
 .../spanbuf/spanbuf.assign/swap_nonmember.pass.cpp            | 4 ++++
 .../span.streams/spanbuf/spanbuf.members/span.pass.cpp        | 4 ++++
 .../span.streams/spanbuf/spanbuf.members/span.span.pass.cpp   | 4 ++++
 .../spanstream/spanstream.cons/assign.move.pass.cpp           | 4 ++++
 .../spanstream/spanstream.cons/ctor.move.pass.cpp             | 4 ++++
 .../spanstream/spanstream.cons/ctor.span.mode.pass.cpp        | 4 +++-
 .../span.streams/spanstream/spanstream.members/rdbuf.pass.cpp | 4 ++++
 .../span.streams/spanstream/spanstream.members/span.pass.cpp  | 4 ++++
 .../spanstream/spanstream.members/span.span.pass.cpp          | 4 ++++
 .../span.streams/spanstream/spanstream.swap/swap.pass.cpp     | 4 ++++
 .../spanstream/spanstream.swap/swap_nonmember.pass.cpp        | 4 ++++
 12 files changed, 47 insertions(+), 1 deletion(-)

diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/swap.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/swap.pass.cpp
index 0adbd21a7ee62..0b906c8a6a4fc 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/swap.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/swap.pass.cpp
@@ -22,6 +22,7 @@
 #include <spanstream>
 
 #include "constexpr_char_traits.h"
+#include "nasty_string.h"
 #include "test_macros.h"
 
 template <typename CharT, typename TraitsT = std::char_traits<CharT>>
@@ -144,6 +145,9 @@ void test() {
 }
 
 int main(int, char**) {
+#ifndef TEST_HAS_NO_NASTY_STRING
+  test<nasty_char, nasty_char_traits>();
+#endif
   test<char>();
   test<char, constexpr_char_traits<char>>();
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/swap_nonmember.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/swap_nonmember.pass.cpp
index cfbd8e9948a57..9b9f78928a5af 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/swap_nonmember.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/swap_nonmember.pass.cpp
@@ -18,6 +18,7 @@
 #include <spanstream>
 
 #include "constexpr_char_traits.h"
+#include "nasty_string.h"
 #include "test_macros.h"
 
 template <typename CharT, typename TraitsT = std::char_traits<CharT>>
@@ -140,6 +141,9 @@ void test() {
 }
 
 int main(int, char**) {
+#ifndef TEST_HAS_NO_NASTY_STRING
+  test<nasty_char, nasty_char_traits>();
+#endif
   test<char>();
   test<char, constexpr_char_traits<char>>();
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.members/span.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.members/span.pass.cpp
index bf21a0bc7844c..3eb51e6076e60 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.members/span.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.members/span.pass.cpp
@@ -22,6 +22,7 @@
 #include <spanstream>
 
 #include "constexpr_char_traits.h"
+#include "nasty_string.h"
 #include "test_macros.h"
 
 template <typename CharT, typename TraitsT = std::char_traits<CharT>>
@@ -76,6 +77,9 @@ void test() {
 }
 
 int main(int, char**) {
+#ifndef TEST_HAS_NO_NASTY_STRING
+  test<nasty_char, nasty_char_traits>();
+#endif
   test<char>();
   test<char, constexpr_char_traits<char>>();
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.members/span.span.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.members/span.span.pass.cpp
index 3bcfe3ec3ead1..d02527a6fd3c6 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.members/span.span.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.members/span.span.pass.cpp
@@ -23,6 +23,7 @@
 #include <spanstream>
 
 #include "constexpr_char_traits.h"
+#include "nasty_string.h"
 #include "test_macros.h"
 
 template <typename CharT, typename TraitsT = std::char_traits<CharT>>
@@ -160,6 +161,9 @@ void test() {
 }
 
 int main(int, char**) {
+#ifndef TEST_HAS_NO_NASTY_STRING
+  test<nasty_char, nasty_char_traits>();
+#endif
   test<char>();
   test<char, constexpr_char_traits<char>>();
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
diff --git a/libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/assign.move.pass.cpp b/libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/assign.move.pass.cpp
index f59f975d062ff..7caa7020cb0ff 100644
--- a/libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/assign.move.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/assign.move.pass.cpp
@@ -23,6 +23,7 @@
 #include <spanstream>
 
 #include "constexpr_char_traits.h"
+#include "nasty_string.h"
 #include "test_macros.h"
 
 template <typename CharT, typename TraitsT = std::char_traits<CharT>>
@@ -75,6 +76,9 @@ void test() {
 }
 
 int main(int, char**) {
+#ifndef TEST_HAS_NO_NASTY_STRING
+  test<nasty_char, nasty_char_traits>();
+#endif
   test<char>();
   test<char, constexpr_char_traits<char>>();
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
diff --git a/libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/ctor.move.pass.cpp b/libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/ctor.move.pass.cpp
index e6367fb667fb6..4878ebcda13df 100644
--- a/libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/ctor.move.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/ctor.move.pass.cpp
@@ -23,6 +23,7 @@
 #include <spanstream>
 
 #include "constexpr_char_traits.h"
+#include "nasty_string.h"
 #include "test_macros.h"
 
 template <typename CharT, typename TraitsT = std::char_traits<CharT>>
@@ -75,6 +76,9 @@ void test() {
 }
 
 int main(int, char**) {
+#ifndef TEST_HAS_NO_NASTY_STRING
+  test<nasty_char, nasty_char_traits>();
+#endif
   test<char>();
   test<char, constexpr_char_traits<char>>();
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
diff --git a/libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/ctor.span.mode.pass.cpp b/libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/ctor.span.mode.pass.cpp
index 5a6c7c1c90e2c..2a320bf9cca26 100644
--- a/libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/ctor.span.mode.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/ctor.span.mode.pass.cpp
@@ -28,7 +28,6 @@
 #include "test_convertible.h"
 #include "test_macros.h"
 
-#include "../../helper_macros.h"
 #include "../../helper_types.h"
 
 template <typename CharT, typename TraitsT = std::char_traits<CharT>>
@@ -124,6 +123,9 @@ int main(int, char**) {
 #endif
   test_sfinae<char>();
   test_sfinae<char, constexpr_char_traits<char>>();
+#ifndef TEST_HAS_NO_NASTY_STRING
+  test<nasty_char, nasty_char_traits>();
+#endif
   test<char>();
   test<char, constexpr_char_traits<char>>();
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
diff --git a/libcxx/test/std/input.output/span.streams/spanstream/spanstream.members/rdbuf.pass.cpp b/libcxx/test/std/input.output/span.streams/spanstream/spanstream.members/rdbuf.pass.cpp
index 38f998fda05f8..9cc0db4b9dc9a 100644
--- a/libcxx/test/std/input.output/span.streams/spanstream/spanstream.members/rdbuf.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanstream/spanstream.members/rdbuf.pass.cpp
@@ -22,6 +22,7 @@
 #include <spanstream>
 
 #include "constexpr_char_traits.h"
+#include "nasty_string.h"
 #include "test_macros.h"
 
 template <typename CharT, typename TraitsT = std::char_traits<CharT>>
@@ -76,6 +77,9 @@ void test() {
 }
 
 int main(int, char**) {
+#ifndef TEST_HAS_NO_NASTY_STRING
+  test<nasty_char, nasty_char_traits>();
+#endif
   test<char>();
   test<char, constexpr_char_traits<char>>();
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
diff --git a/libcxx/test/std/input.output/span.streams/spanstream/spanstream.members/span.pass.cpp b/libcxx/test/std/input.output/span.streams/spanstream/spanstream.members/span.pass.cpp
index 96ba53a588e6e..5eedf9e01d9ec 100644
--- a/libcxx/test/std/input.output/span.streams/spanstream/spanstream.members/span.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanstream/spanstream.members/span.pass.cpp
@@ -23,6 +23,7 @@
 #include <spanstream>
 
 #include "constexpr_char_traits.h"
+#include "nasty_string.h"
 #include "test_macros.h"
 
 template <typename CharT, typename TraitsT = std::char_traits<CharT>>
@@ -77,6 +78,9 @@ void test() {
 }
 
 int main(int, char**) {
+#ifndef TEST_HAS_NO_NASTY_STRING
+  test<nasty_char, nasty_char_traits>();
+#endif
   test<char>();
   test<char, constexpr_char_traits<char>>();
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
diff --git a/libcxx/test/std/input.output/span.streams/spanstream/spanstream.members/span.span.pass.cpp b/libcxx/test/std/input.output/span.streams/spanstream/spanstream.members/span.span.pass.cpp
index 2aae1c34a8bb8..58bdf38166ab7 100644
--- a/libcxx/test/std/input.output/span.streams/spanstream/spanstream.members/span.span.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanstream/spanstream.members/span.span.pass.cpp
@@ -23,6 +23,7 @@
 #include <spanstream>
 
 #include "constexpr_char_traits.h"
+#include "nasty_string.h"
 #include "test_macros.h"
 
 template <typename CharT, typename TraitsT = std::char_traits<CharT>>
@@ -160,6 +161,9 @@ void test() {
 }
 
 int main(int, char**) {
+#ifndef TEST_HAS_NO_NASTY_STRING
+  test<nasty_char, nasty_char_traits>();
+#endif
   test<char>();
   test<char, constexpr_char_traits<char>>();
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
diff --git a/libcxx/test/std/input.output/span.streams/spanstream/spanstream.swap/swap.pass.cpp b/libcxx/test/std/input.output/span.streams/spanstream/spanstream.swap/swap.pass.cpp
index e4169cb581b3b..4225e80a4da2f 100644
--- a/libcxx/test/std/input.output/span.streams/spanstream/spanstream.swap/swap.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanstream/spanstream.swap/swap.pass.cpp
@@ -22,6 +22,7 @@
 #include <spanstream>
 
 #include "constexpr_char_traits.h"
+#include "nasty_string.h"
 #include "test_macros.h"
 
 template <typename CharT, typename TraitsT = std::char_traits<CharT>>
@@ -144,6 +145,9 @@ void test() {
 }
 
 int main(int, char**) {
+#ifndef TEST_HAS_NO_NASTY_STRING
+  test<nasty_char, nasty_char_traits>();
+#endif
   test<char>();
   test<char, constexpr_char_traits<char>>();
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
diff --git a/libcxx/test/std/input.output/span.streams/spanstream/spanstream.swap/swap_nonmember.pass.cpp b/libcxx/test/std/input.output/span.streams/spanstream/spanstream.swap/swap_nonmember.pass.cpp
index 50fd1cab63b7c..baba48cbb1d0b 100644
--- a/libcxx/test/std/input.output/span.streams/spanstream/spanstream.swap/swap_nonmember.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanstream/spanstream.swap/swap_nonmember.pass.cpp
@@ -18,6 +18,7 @@
 #include <spanstream>
 
 #include "constexpr_char_traits.h"
+#include "nasty_string.h"
 #include "test_macros.h"
 
 template <typename CharT, typename TraitsT = std::char_traits<CharT>>
@@ -140,6 +141,9 @@ void test() {
 }
 
 int main(int, char**) {
+#ifndef TEST_HAS_NO_NASTY_STRING
+  test<nasty_char, nasty_char_traits>();
+#endif
   test<char>();
   test<char, constexpr_char_traits<char>>();
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS

>From d348c6f0cb082d4c80f2ac75ac46e0afb204474c Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Fri, 15 Mar 2024 18:13:31 +0200
Subject: [PATCH 48/56] Tests: updated `spanstream` and `ospanstream`

---
 .../ospanstream.cons/assign.move.pass.cpp     |  90 ++++++++++
 .../{move.pass.cpp => ctor.move.pass.cpp}     |  30 ++--
 ....mode.pass.cpp => ctor.span.mode.pass.cpp} |  45 +++--
 .../ospanstream.members/rdbuf.pass.cpp        |  91 ++++++++++
 .../ospanstream.members/span.pass.cpp         |  92 ++++++++++
 .../ospanstream.members/span.span.pass.cpp    | 117 +++++++++++++
 .../ospanstream.swap/swap.pass.cpp            | 159 ++++++++++++++++++
 .../ospanstream.swap/swap_nonmember.pass.cpp  | 155 +++++++++++++++++
 .../spanbuf.members/span.span.pass.cpp        |  58 -------
 .../spanstream.members/span.span.pass.cpp     |  58 -------
 10 files changed, 753 insertions(+), 142 deletions(-)
 create mode 100644 libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.cons/assign.move.pass.cpp
 rename libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.cons/{move.pass.cpp => ctor.move.pass.cpp} (74%)
 rename libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.cons/{span.mode.pass.cpp => ctor.span.mode.pass.cpp} (72%)
 create mode 100644 libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.members/rdbuf.pass.cpp
 create mode 100644 libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.members/span.pass.cpp
 create mode 100644 libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.members/span.span.pass.cpp
 create mode 100644 libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.swap/swap.pass.cpp
 create mode 100644 libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.swap/swap_nonmember.pass.cpp

diff --git a/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.cons/assign.move.pass.cpp b/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.cons/assign.move.pass.cpp
new file mode 100644
index 0000000000000..ead2efb5d6bef
--- /dev/null
+++ b/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.cons/assign.move.pass.cpp
@@ -0,0 +1,90 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <spanstream>
+
+//   template<class charT, class traits = char_traits<charT>>
+//   class basic_ospanstream
+//     : public basic_ostream<charT, traits> {
+
+//     // [spanstream.cons], constructors
+
+//     basic_spanstream& operator=(basic_ospanstream&& rhs);
+
+#include <cassert>
+#include <span>
+#include <spanstream>
+
+#include "constexpr_char_traits.h"
+#include "nasty_string.h"
+#include "test_macros.h"
+
+template <typename CharT, typename TraitsT = std::char_traits<CharT>>
+void test() {
+  using SpStream = std::basic_ospanstream<CharT, TraitsT>;
+
+  CharT arr[4];
+  std::span<CharT> sp{arr};
+
+  // Mode: default (`in` | `out`)
+  {
+    SpStream rhsSpSt{sp};
+    SpStream spSt = std::move(rhsSpSt);
+    assert(spSt.span().data() == arr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+  }
+  // Mode: `in`
+  {
+    SpStream rhsSpSt{sp, std::ios_base::in};
+    SpStream spSt = std::move(rhsSpSt);
+    assert(spSt.span().data() == arr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+  }
+  // Mode `out`
+  {
+    SpStream rhsSpSt{sp, std::ios_base::out};
+    SpStream spSt = std::move(rhsSpSt);
+    assert(spSt.span().data() == arr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+  }
+  // Mode: multiple
+  {
+    SpStream rhsSpSt{sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary};
+    SpStream spSt = std::move(rhsSpSt);
+    assert(spSt.span().data() == arr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+  }
+  // Mode `ate`
+  {
+    SpStream rhsSpSt{sp, std::ios_base::out | std::ios_base::ate};
+    SpStream spSt = std::move(rhsSpSt);
+    assert(spSt.span().data() == arr);
+    assert(!spSt.span().empty());
+    assert(spSt.span().size() == 4);
+  }
+}
+
+int main(int, char**) {
+#ifndef TEST_HAS_NO_NASTY_STRING
+  test<nasty_char, nasty_char_traits>();
+#endif
+  test<char>();
+  test<char, constexpr_char_traits<char>>();
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  test<wchar_t>();
+  test<wchar_t, constexpr_char_traits<wchar_t>>();
+#endif
+
+  return 0;
+}
diff --git a/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.cons/move.pass.cpp b/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.cons/ctor.move.pass.cpp
similarity index 74%
rename from libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.cons/move.pass.cpp
rename to libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.cons/ctor.move.pass.cpp
index f361f0489e32f..8e1937d6d3c2f 100644
--- a/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.cons/move.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.cons/ctor.move.pass.cpp
@@ -12,19 +12,18 @@
 
 //   template<class charT, class traits = char_traits<charT>>
 //   class basic_ospanstream
-//     : public basic_streambuf<charT, traits> {
+//     : public basic_ostream<charT, traits> {
+
+//     // [spanstream.cons], constructors
 
-//     // [spanbuf.cons], constructors
-//
 //     basic_ospanstream(basic_ospanstream&& rhs);
 
 #include <cassert>
-#include <concepts>
 #include <span>
 #include <spanstream>
 
 #include "constexpr_char_traits.h"
-#include "test_convertible.h"
+#include "nasty_string.h"
 #include "test_macros.h"
 
 template <typename CharT, typename TraitsT = std::char_traits<CharT>>
@@ -34,10 +33,10 @@ void test() {
   CharT arr[4];
   std::span<CharT> sp{arr};
 
-  // Mode: default
+  // Mode: default (`in` | `out`)
   {
     SpStream rhsSpSt{sp};
-    SpStream spSt(std::move(rhsSpSt));
+    SpStream spSt{std::move(rhsSpSt)};
     assert(spSt.span().data() == arr);
     assert(spSt.span().empty());
     assert(spSt.span().size() == 0);
@@ -45,7 +44,7 @@ void test() {
   // Mode: `in`
   {
     SpStream rhsSpSt{sp, std::ios_base::in};
-    SpStream spSt(std::move(rhsSpSt));
+    SpStream spSt{std::move(rhsSpSt)};
     assert(spSt.span().data() == arr);
     assert(spSt.span().empty());
     assert(spSt.span().size() == 0);
@@ -53,7 +52,7 @@ void test() {
   // Mode `out`
   {
     SpStream rhsSpSt{sp, std::ios_base::out};
-    SpStream spSt(std::move(rhsSpSt));
+    SpStream spSt{std::move(rhsSpSt)};
     assert(spSt.span().data() == arr);
     assert(spSt.span().empty());
     assert(spSt.span().size() == 0);
@@ -61,14 +60,25 @@ void test() {
   // Mode: multiple
   {
     SpStream rhsSpSt{sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary};
-    SpStream spSt(std::move(rhsSpSt));
+    SpStream spSt{std::move(rhsSpSt)};
     assert(spSt.span().data() == arr);
     assert(spSt.span().empty());
     assert(spSt.span().size() == 0);
   }
+  // Mode `ate`
+  {
+    SpStream rhsSpSt{sp, std::ios_base::out | std::ios_base::ate};
+    SpStream spSt{std::move(rhsSpSt)};
+    assert(spSt.span().data() == arr);
+    assert(!spSt.span().empty());
+    assert(spSt.span().size() == 4);
+  }
 }
 
 int main(int, char**) {
+#ifndef TEST_HAS_NO_NASTY_STRING
+  test<nasty_char, nasty_char_traits>();
+#endif
   test<char>();
   test<char, constexpr_char_traits<char>>();
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
diff --git a/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.cons/span.mode.pass.cpp b/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.cons/ctor.span.mode.pass.cpp
similarity index 72%
rename from libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.cons/span.mode.pass.cpp
rename to libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.cons/ctor.span.mode.pass.cpp
index 3e2a7f1604aa5..6d369945f8537 100644
--- a/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.cons/span.mode.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.cons/ctor.span.mode.pass.cpp
@@ -12,15 +12,13 @@
 
 //   template<class charT, class traits = char_traits<charT>>
 //   class basic_ospanstream
-//     : public basic_streambuf<charT, traits> {
+//     : public basic_ostream<charT, traits> {
 
-//     // [spanbuf.cons], constructors
-//
+//     // [spanstream.cons], constructors
 //     explicit basic_ospanstream(std::span<charT> s,
-//                                ios_base::openmode which = ios_base::in);
+//                                ios_base::openmode which = ios_base::out | ios_base::in);
 
 #include <cassert>
-#include <concepts>
 #include <span>
 #include <spanstream>
 #include <utility>
@@ -30,12 +28,11 @@
 #include "test_convertible.h"
 #include "test_macros.h"
 
-#include "../../helper_macros.h"
 #include "../../helper_types.h"
 
 template <typename CharT, typename TraitsT = std::char_traits<CharT>>
 void test_sfinae() {
-  using SpStream = std::basic_ispanstream<CharT, TraitsT>;
+  using SpStream = std::basic_ospanstream<CharT, TraitsT>;
 
   // Mode
   static_assert(std::constructible_from<SpStream, const std::span<CharT>, std::ios_base::openmode>);
@@ -53,58 +50,71 @@ void test() {
   CharT arr[4];
   std::span<CharT> sp{arr};
 
-  // Mode: default
+  // Mode: default (`in` | `out`)
   {
-    SpStream spSt(sp);
+    SpStream spSt{sp};
     assert(spSt.span().data() == arr);
     assert(spSt.span().empty());
     assert(spSt.span().size() == 0);
   }
   {
-    SpStream spSt(std::as_const(sp));
+    SpStream spSt{std::as_const(sp)};
     assert(spSt.span().data() == arr);
     assert(spSt.span().empty());
     assert(spSt.span().size() == 0);
   }
   // Mode: `in`
   {
-    SpStream spSt(sp, std::ios_base::in);
+    SpStream spSt{sp, std::ios_base::in};
     assert(spSt.span().data() == arr);
     assert(spSt.span().empty());
     assert(spSt.span().size() == 0);
   }
   {
-    SpStream spSt(std::as_const(sp), std::ios_base::in);
+    SpStream spSt{std::as_const(sp), std::ios_base::in};
     assert(spSt.span().data() == arr);
     assert(spSt.span().empty());
     assert(spSt.span().size() == 0);
   }
   // Mode `out`
   {
-    SpStream spSt(sp, std::ios_base::out);
+    SpStream spSt{sp, std::ios_base::out};
     assert(spSt.span().data() == arr);
     assert(spSt.span().empty());
     assert(spSt.span().size() == 0);
   }
   {
-    SpStream spSt(std::as_const(sp), std::ios_base::out);
+    SpStream spSt{std::as_const(sp), std::ios_base::out};
     assert(spSt.span().data() == arr);
     assert(spSt.span().empty());
     assert(spSt.span().size() == 0);
   }
   // Mode: multiple
   {
-    SpStream spSt(sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary);
+    SpStream spSt{sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary};
     assert(spSt.span().data() == arr);
     assert(spSt.span().empty());
     assert(spSt.span().size() == 0);
   }
   {
-    SpStream spSt(std::as_const(sp), std::ios_base::in | std::ios_base::out | std::ios_base::binary);
+    SpStream spSt{std::as_const(sp), std::ios_base::in | std::ios_base::out | std::ios_base::binary};
     assert(spSt.span().data() == arr);
     assert(spSt.span().empty());
     assert(spSt.span().size() == 0);
   }
+  // Mode `ate`
+  {
+    SpStream spSt{sp, std::ios_base::out | std::ios_base::ate};
+    assert(spSt.span().data() == arr);
+    assert(!spSt.span().empty());
+    assert(spSt.span().size() == 4);
+  }
+  {
+    SpStream spSt{std::as_const(sp), std::ios_base::out | std::ios_base::ate};
+    assert(spSt.span().data() == arr);
+    assert(!spSt.span().empty());
+    assert(spSt.span().size() == 4);
+  }
 }
 
 int main(int, char**) {
@@ -113,6 +123,9 @@ int main(int, char**) {
 #endif
   test_sfinae<char>();
   test_sfinae<char, constexpr_char_traits<char>>();
+#ifndef TEST_HAS_NO_NASTY_STRING
+  test<nasty_char, nasty_char_traits>();
+#endif
   test<char>();
   test<char, constexpr_char_traits<char>>();
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
diff --git a/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.members/rdbuf.pass.cpp b/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.members/rdbuf.pass.cpp
new file mode 100644
index 0000000000000..fac9df7c7d913
--- /dev/null
+++ b/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.members/rdbuf.pass.cpp
@@ -0,0 +1,91 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <spanstream>
+
+//   template<class charT, class traits = char_traits<charT>>
+//   class basic_ospanstream
+//     : public basic_ostream<charT, traits> {
+
+//     // [ospanstream.members], members
+//     basic_spanbuf<charT, traits>* rdbuf() const noexcept;
+
+#include <cassert>
+#include <span>
+#include <spanstream>
+
+#include "constexpr_char_traits.h"
+#include "nasty_string.h"
+#include "test_macros.h"
+
+template <typename CharT, typename TraitsT = std::char_traits<CharT>>
+void test() {
+  using SpStream = std::basic_ospanstream<CharT, TraitsT>;
+
+  CharT arr[4];
+
+  std::span<CharT> sp{arr};
+  assert(sp.data() == arr);
+  assert(!sp.empty());
+  assert(sp.size() == 4);
+
+  // Mode: default (`in` | `out`)
+  {
+    SpStream spSt{sp};
+    assert(spSt.rdbuf()->span().data() == arr);
+    // Mode `out` counts read characters
+    assert(spSt.rdbuf()->span().empty());
+    assert(spSt.rdbuf()->span().size() == 0);
+  }
+  // Mode: `in`
+  {
+    SpStream spSt{sp, std::ios_base::in};
+    assert(spSt.rdbuf()->span().data() == arr);
+    assert(spSt.rdbuf()->span().empty());
+    assert(spSt.rdbuf()->span().size() == 0);
+  }
+  // Mode: `out`
+  {
+    SpStream spSt{sp, std::ios_base::out};
+    assert(spSt.rdbuf()->span().data() == arr);
+    // Mode `out` counts read characters
+    assert(spSt.rdbuf()->span().empty());
+    assert(spSt.rdbuf()->span().size() == 0);
+  }
+  // Mode: multiple
+  {
+    SpStream spSt{sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary};
+    assert(spSt.rdbuf()->span().data() == arr);
+    // Mode `out` counts read characters
+    assert(spSt.rdbuf()->span().empty());
+    assert(spSt.rdbuf()->span().size() == 0);
+  }
+  // Mode: `ate`
+  {
+    SpStream spSt{sp, std::ios_base::out | std::ios_base::ate};
+    assert(spSt.rdbuf()->span().data() == arr);
+    assert(!spSt.rdbuf()->span().empty());
+    assert(spSt.rdbuf()->span().size() == 4);
+  }
+}
+
+int main(int, char**) {
+#ifndef TEST_HAS_NO_NASTY_STRING
+  test<nasty_char, nasty_char_traits>();
+#endif
+  test<char>();
+  test<char, constexpr_char_traits<char>>();
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  test<wchar_t>();
+  test<wchar_t, constexpr_char_traits<wchar_t>>();
+#endif
+
+  return 0;
+}
diff --git a/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.members/span.pass.cpp b/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.members/span.pass.cpp
new file mode 100644
index 0000000000000..f92ed56c53b6d
--- /dev/null
+++ b/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.members/span.pass.cpp
@@ -0,0 +1,92 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <spanstream>
+
+//   template<class charT, class traits = char_traits<charT>>
+//   class basic_ospanstream
+//     : public basic_ostream<charT, traits> {
+
+//     // [ospanstream.members], members
+
+//     std::span<charT> span() const noexcept;
+
+#include <cassert>
+#include <span>
+#include <spanstream>
+
+#include "constexpr_char_traits.h"
+#include "nasty_string.h"
+#include "test_macros.h"
+
+template <typename CharT, typename TraitsT = std::char_traits<CharT>>
+void test() {
+  using SpStream = std::basic_ospanstream<CharT, TraitsT>;
+
+  CharT arr[4];
+
+  std::span<CharT> sp{arr};
+  assert(sp.data() == arr);
+  assert(!sp.empty());
+  assert(sp.size() == 4);
+
+  // Mode: default (`in` | `out`)
+  {
+    SpStream spSt{sp};
+    assert(spSt.span().data() == arr);
+    // Mode `out` counts read characters
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+  }
+  // Mode: `in`
+  {
+    SpStream spSt{sp, std::ios_base::in};
+    assert(spSt.span().data() == arr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+  }
+  // Mode: `out`
+  {
+    SpStream spSt{sp, std::ios_base::out};
+    assert(spSt.span().data() == arr);
+    // Mode `out` counts read characters
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+  }
+  // Mode: multiple
+  {
+    SpStream spSt{sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary};
+    assert(spSt.span().data() == arr);
+    // Mode `out` counts read characters
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+  }
+  // Mode: `ate`
+  {
+    SpStream spSt{sp, std::ios_base::out | std::ios_base::ate};
+    assert(spSt.span().data() == arr);
+    assert(!spSt.span().empty());
+    assert(spSt.span().size() == 4);
+  }
+}
+
+int main(int, char**) {
+#ifndef TEST_HAS_NO_NASTY_STRING
+  test<nasty_char, nasty_char_traits>();
+#endif
+  test<char>();
+  test<char, constexpr_char_traits<char>>();
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  test<wchar_t>();
+  test<wchar_t, constexpr_char_traits<wchar_t>>();
+#endif
+
+  return 0;
+}
diff --git a/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.members/span.span.pass.cpp b/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.members/span.span.pass.cpp
new file mode 100644
index 0000000000000..45411696e0d68
--- /dev/null
+++ b/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.members/span.span.pass.cpp
@@ -0,0 +1,117 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <spanstream>
+
+//   template<class charT, class traits = char_traits<charT>>
+//   class basic_spanstream
+//     : public basic_iostream<charT, traits> {
+
+//     // [spanstream.members], members
+
+//     void span(std::span<charT> s) noexcept;
+
+#include <cassert>
+#include <span>
+#include <spanstream>
+
+#include "constexpr_char_traits.h"
+#include "nasty_string.h"
+#include "test_macros.h"
+
+template <typename CharT, typename TraitsT = std::char_traits<CharT>>
+void test() {
+  using SpStream = std::basic_spanbuf<CharT, TraitsT>;
+
+  CharT arr[4];
+
+  std::span<CharT> sp{arr};
+  assert(sp.data() == arr);
+  assert(!sp.empty());
+  assert(sp.size() == 4);
+
+  // Mode: default (`in` | `out`)
+  {
+    SpStream spSt;
+    assert(spSt.span().data() == nullptr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+
+    spSt.span(arr);
+    assert(spSt.span().data() == arr);
+    // Mode `out` counts read characters
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+  }
+  // Mode: `in`
+  {
+    SpStream spSt{std::ios_base::in};
+    assert(spSt.span().data() == nullptr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+
+    spSt.span(arr);
+    assert(spSt.span().data() == arr);
+    assert(!spSt.span().empty());
+    assert(spSt.span().size() == 4);
+  }
+  // Mode: `out`
+  {
+    SpStream spSt{std::ios_base::out};
+    assert(spSt.span().data() == nullptr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+
+    spSt.span(arr);
+    assert(spSt.span().data() == arr);
+    // Mode `out` counts read characters
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+  }
+  // Mode: multiple
+  {
+    SpStream spSt{std::ios_base::in | std::ios_base::out | std::ios_base::binary};
+    assert(spSt.span().data() == nullptr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+
+    spSt.span(arr);
+    assert(spSt.span().data() == arr);
+    // Mode `out` counts read characters
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+  }
+  // Mode: `ate`
+  {
+    SpStream spSt{std::ios_base::out | std::ios_base::ate};
+    assert(spSt.span().data() == nullptr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+
+    spSt.span(arr);
+    assert(spSt.span().data() == arr);
+    assert(!spSt.span().empty());
+    assert(spSt.span().size() == 4);
+  }
+}
+
+int main(int, char**) {
+#ifndef TEST_HAS_NO_NASTY_STRING
+  test<nasty_char, nasty_char_traits>();
+#endif
+  test<char>();
+  test<char, constexpr_char_traits<char>>();
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  test<wchar_t>();
+  test<wchar_t, constexpr_char_traits<wchar_t>>();
+#endif
+
+  return 0;
+}
diff --git a/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.swap/swap.pass.cpp b/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.swap/swap.pass.cpp
new file mode 100644
index 0000000000000..e6a7d2d457e20
--- /dev/null
+++ b/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.swap/swap.pass.cpp
@@ -0,0 +1,159 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <spanstream>
+
+//   template<class charT, class traits = char_traits<charT>>
+//   class basic_ospanstream
+//     : public basic_ostream<charT, traits> {
+
+//    // [spanstream.swap], swap
+//    void swap(basic_ospanstream& rhs);
+
+#include <cassert>
+#include <span>
+#include <spanstream>
+
+#include "constexpr_char_traits.h"
+#include "nasty_string.h"
+#include "test_macros.h"
+
+template <typename CharT, typename TraitsT = std::char_traits<CharT>>
+void test() {
+  using SpStream = std::basic_ospanstream<CharT, TraitsT>;
+
+  CharT arr[4];
+
+  std::span<CharT> sp{arr};
+  assert(sp.data() == arr);
+  assert(!sp.empty());
+  assert(sp.size() == 4);
+
+  // Mode: default (`in` | `out`)
+  {
+    SpStream rhsSpSt{sp};
+    assert(rhsSpSt.span().data() == arr);
+    // Mode `out` counts read characters
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
+
+    SpStream spSt{std::span<CharT>{}};
+    assert(spSt.span().data() == nullptr);
+    // Mode `out` counts read characters
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+
+    spSt.swap(rhsSpSt);
+    assert(spSt.span().data() == arr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+    assert(rhsSpSt.span().data() == nullptr);
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
+  }
+  // Mode: `in`
+  {
+    SpStream rhsSpSt{sp, std::ios_base::in};
+    assert(rhsSpSt.span().data() == arr);
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
+
+    SpStream spSt(std::span<CharT>{});
+    assert(spSt.span().data() == nullptr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+
+    spSt.swap(rhsSpSt);
+    assert(spSt.span().data() == arr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+    assert(rhsSpSt.span().data() == nullptr);
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
+  }
+  // Mode `out`
+  {
+    SpStream rhsSpSt{sp, std::ios_base::out};
+    assert(rhsSpSt.span().data() == arr);
+    // Mode `out` counts read characters
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
+
+    SpStream spSt{std::span<CharT>{}};
+    assert(spSt.span().data() == nullptr);
+    // Mode `out` counts read characters
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+
+    spSt.swap(rhsSpSt);
+    assert(spSt.span().data() == arr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+    assert(rhsSpSt.span().data() == nullptr);
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
+  }
+  // Mode: multiple
+  {
+    SpStream rhsSpSt{sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary};
+    assert(rhsSpSt.span().data() == arr);
+    // Mode `out` counts read characters
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
+
+    SpStream spSt{std::span<CharT>{}};
+    assert(spSt.span().data() == nullptr);
+    // Mode `out` counts read characters
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+
+    spSt.swap(rhsSpSt);
+    assert(spSt.span().data() == arr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+    assert(rhsSpSt.span().data() == nullptr);
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
+  }
+  // Mode: `ate`
+  {
+    SpStream rhsSpSt{sp, std::ios_base::out | std::ios_base::ate};
+    assert(rhsSpSt.span().data() == arr);
+    assert(!rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 4);
+
+    SpStream spSt(std::span<CharT>{});
+    assert(spSt.span().data() == nullptr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+
+    spSt.swap(rhsSpSt);
+    assert(spSt.span().data() == arr);
+    assert(!spSt.span().empty());
+    assert(spSt.span().size() == 4);
+    assert(rhsSpSt.span().data() == nullptr);
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
+  }
+}
+
+int main(int, char**) {
+#ifndef TEST_HAS_NO_NASTY_STRING
+  test<nasty_char, nasty_char_traits>();
+#endif
+  test<char>();
+  test<char, constexpr_char_traits<char>>();
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  test<wchar_t>();
+  test<wchar_t, constexpr_char_traits<wchar_t>>();
+#endif
+
+  return 0;
+}
diff --git a/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.swap/swap_nonmember.pass.cpp b/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.swap/swap_nonmember.pass.cpp
new file mode 100644
index 0000000000000..fc3f9a57afcf5
--- /dev/null
+++ b/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.swap/swap_nonmember.pass.cpp
@@ -0,0 +1,155 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <spanstream>
+
+//   template<class charT, class traits>
+//     void swap(basic_ospanstream<charT, traits>& x, basic_ospanstream<charT, traits>& y);
+
+#include <cassert>
+#include <span>
+#include <spanstream>
+
+#include "constexpr_char_traits.h"
+#include "nasty_string.h"
+#include "test_macros.h"
+
+template <typename CharT, typename TraitsT = std::char_traits<CharT>>
+void test() {
+  using SpStream = std::basic_ospanstream<CharT, TraitsT>;
+
+  CharT arr[4];
+
+  std::span<CharT> sp{arr};
+  assert(sp.data() == arr);
+  assert(!sp.empty());
+  assert(sp.size() == 4);
+
+  // Mode: default (`in` | `out`)
+  {
+    SpStream rhsSpSt{sp};
+    assert(rhsSpSt.span().data() == arr);
+    // Mode `out` counts read characters
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
+
+    SpStream spSt{std::span<CharT>{}};
+    assert(spSt.span().data() == nullptr);
+    // Mode `out` counts read characters
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+
+    std::swap(spSt, rhsSpSt);
+    assert(spSt.span().data() == arr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+    assert(rhsSpSt.span().data() == nullptr);
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
+  }
+  // Mode: `in`
+  {
+    SpStream rhsSpSt{sp, std::ios_base::in};
+    assert(rhsSpSt.span().data() == arr);
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
+
+    SpStream spSt(std::span<CharT>{});
+    assert(spSt.span().data() == nullptr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+
+    std::swap(spSt, rhsSpSt);
+    assert(spSt.span().data() == arr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+    assert(rhsSpSt.span().data() == nullptr);
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
+  }
+  // Mode `out`
+  {
+    SpStream rhsSpSt{sp, std::ios_base::out};
+    assert(rhsSpSt.span().data() == arr);
+    // Mode `out` counts read characters
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
+
+    SpStream spSt{std::span<CharT>{}};
+    assert(spSt.span().data() == nullptr);
+    // Mode `out` counts read characters
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+
+    std::swap(spSt, rhsSpSt);
+    assert(spSt.span().data() == arr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+    assert(rhsSpSt.span().data() == nullptr);
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
+  }
+  // Mode: multiple
+  {
+    SpStream rhsSpSt{sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary};
+    assert(rhsSpSt.span().data() == arr);
+    // Mode `out` counts read characters
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
+
+    SpStream spSt{std::span<CharT>{}};
+    assert(spSt.span().data() == nullptr);
+    // Mode `out` counts read characters
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+
+    std::swap(spSt, rhsSpSt);
+    assert(spSt.span().data() == arr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+    assert(rhsSpSt.span().data() == nullptr);
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
+  }
+  // Mode: `ate`
+  {
+    SpStream rhsSpSt{sp, std::ios_base::out | std::ios_base::ate};
+    assert(rhsSpSt.span().data() == arr);
+    assert(!rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 4);
+
+    SpStream spSt(std::span<CharT>{});
+    assert(spSt.span().data() == nullptr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+
+    std::swap(spSt, rhsSpSt);
+    assert(spSt.span().data() == arr);
+    assert(!spSt.span().empty());
+    assert(spSt.span().size() == 4);
+    assert(rhsSpSt.span().data() == nullptr);
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
+  }
+}
+
+int main(int, char**) {
+#ifndef TEST_HAS_NO_NASTY_STRING
+  test<nasty_char, nasty_char_traits>();
+#endif
+  test<char>();
+  test<char, constexpr_char_traits<char>>();
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  test<wchar_t>();
+  test<wchar_t, constexpr_char_traits<wchar_t>>();
+#endif
+
+  return 0;
+}
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.members/span.span.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.members/span.span.pass.cpp
index d02527a6fd3c6..510b5f9d70f4c 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.members/span.span.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.members/span.span.pass.cpp
@@ -50,18 +50,6 @@ void test() {
     assert(spBuf.span().empty());
     assert(spBuf.span().size() == 0);
   }
-  {
-    SpBuf spBuf;
-    assert(spBuf.span().data() == nullptr);
-    assert(spBuf.span().empty());
-    assert(spBuf.span().size() == 0);
-
-    spBuf.span(sp);
-    assert(spBuf.span().data() == arr);
-    // Mode `out` counts read characters
-    assert(spBuf.span().empty());
-    assert(spBuf.span().size() == 0);
-  }
   // Mode: `in`
   {
     SpBuf spBuf{std::ios_base::in};
@@ -74,17 +62,6 @@ void test() {
     assert(!spBuf.span().empty());
     assert(spBuf.span().size() == 4);
   }
-  {
-    SpBuf spBuf{std::ios_base::in};
-    assert(spBuf.span().data() == nullptr);
-    assert(spBuf.span().empty());
-    assert(spBuf.span().size() == 0);
-
-    spBuf.span(sp);
-    assert(spBuf.span().data() == arr);
-    assert(!spBuf.span().empty());
-    assert(spBuf.span().size() == 4);
-  }
   // Mode: `out`
   {
     SpBuf spBuf{std::ios_base::out};
@@ -98,18 +75,6 @@ void test() {
     assert(spBuf.span().empty());
     assert(spBuf.span().size() == 0);
   }
-  {
-    SpBuf spBuf{std::ios_base::out};
-    assert(spBuf.span().data() == nullptr);
-    assert(spBuf.span().empty());
-    assert(spBuf.span().size() == 0);
-
-    spBuf.span(sp);
-    assert(spBuf.span().data() == arr);
-    // Mode `out` counts read characters
-    assert(spBuf.span().empty());
-    assert(spBuf.span().size() == 0);
-  }
   // Mode: multiple
   {
     SpBuf spBuf(std::ios_base::in | std::ios_base::out | std::ios_base::binary);
@@ -123,18 +88,6 @@ void test() {
     assert(spBuf.span().empty());
     assert(spBuf.span().size() == 0);
   }
-  {
-    SpBuf spBuf(std::ios_base::in | std::ios_base::out | std::ios_base::binary);
-    assert(spBuf.span().data() == nullptr);
-    assert(spBuf.span().empty());
-    assert(spBuf.span().size() == 0);
-
-    spBuf.span(sp);
-    assert(spBuf.span().data() == arr);
-    // Mode `out` counts read characters
-    assert(spBuf.span().empty());
-    assert(spBuf.span().size() == 0);
-  }
   // Mode: `ate`
   {
     SpBuf spBuf(std::ios_base::out | std::ios_base::ate);
@@ -147,17 +100,6 @@ void test() {
     assert(!spBuf.span().empty());
     assert(spBuf.span().size() == 4);
   }
-  {
-    SpBuf spBuf(std::ios_base::out | std::ios_base::ate);
-    assert(spBuf.span().data() == nullptr);
-    assert(spBuf.span().empty());
-    assert(spBuf.span().size() == 0);
-
-    spBuf.span(sp);
-    assert(spBuf.span().data() == arr);
-    assert(!spBuf.span().empty());
-    assert(spBuf.span().size() == 4);
-  }
 }
 
 int main(int, char**) {
diff --git a/libcxx/test/std/input.output/span.streams/spanstream/spanstream.members/span.span.pass.cpp b/libcxx/test/std/input.output/span.streams/spanstream/spanstream.members/span.span.pass.cpp
index 58bdf38166ab7..45411696e0d68 100644
--- a/libcxx/test/std/input.output/span.streams/spanstream/spanstream.members/span.span.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanstream/spanstream.members/span.span.pass.cpp
@@ -50,18 +50,6 @@ void test() {
     assert(spSt.span().empty());
     assert(spSt.span().size() == 0);
   }
-  {
-    SpStream spSt;
-    assert(spSt.span().data() == nullptr);
-    assert(spSt.span().empty());
-    assert(spSt.span().size() == 0);
-
-    spSt.span(sp);
-    assert(spSt.span().data() == arr);
-    // Mode `out` counts read characters
-    assert(spSt.span().empty());
-    assert(spSt.span().size() == 0);
-  }
   // Mode: `in`
   {
     SpStream spSt{std::ios_base::in};
@@ -74,17 +62,6 @@ void test() {
     assert(!spSt.span().empty());
     assert(spSt.span().size() == 4);
   }
-  {
-    SpStream spSt{std::ios_base::in};
-    assert(spSt.span().data() == nullptr);
-    assert(spSt.span().empty());
-    assert(spSt.span().size() == 0);
-
-    spSt.span(sp);
-    assert(spSt.span().data() == arr);
-    assert(!spSt.span().empty());
-    assert(spSt.span().size() == 4);
-  }
   // Mode: `out`
   {
     SpStream spSt{std::ios_base::out};
@@ -98,18 +75,6 @@ void test() {
     assert(spSt.span().empty());
     assert(spSt.span().size() == 0);
   }
-  {
-    SpStream spSt{std::ios_base::out};
-    assert(spSt.span().data() == nullptr);
-    assert(spSt.span().empty());
-    assert(spSt.span().size() == 0);
-
-    spSt.span(sp);
-    assert(spSt.span().data() == arr);
-    // Mode `out` counts read characters
-    assert(spSt.span().empty());
-    assert(spSt.span().size() == 0);
-  }
   // Mode: multiple
   {
     SpStream spSt{std::ios_base::in | std::ios_base::out | std::ios_base::binary};
@@ -123,18 +88,6 @@ void test() {
     assert(spSt.span().empty());
     assert(spSt.span().size() == 0);
   }
-  {
-    SpStream spSt{std::ios_base::in | std::ios_base::out | std::ios_base::binary};
-    assert(spSt.span().data() == nullptr);
-    assert(spSt.span().empty());
-    assert(spSt.span().size() == 0);
-
-    spSt.span(sp);
-    assert(spSt.span().data() == arr);
-    // Mode `out` counts read characters
-    assert(spSt.span().empty());
-    assert(spSt.span().size() == 0);
-  }
   // Mode: `ate`
   {
     SpStream spSt{std::ios_base::out | std::ios_base::ate};
@@ -147,17 +100,6 @@ void test() {
     assert(!spSt.span().empty());
     assert(spSt.span().size() == 4);
   }
-  {
-    SpStream spSt{std::ios_base::out | std::ios_base::ate};
-    assert(spSt.span().data() == nullptr);
-    assert(spSt.span().empty());
-    assert(spSt.span().size() == 0);
-
-    spSt.span(sp);
-    assert(spSt.span().data() == arr);
-    assert(!spSt.span().empty());
-    assert(spSt.span().size() == 4);
-  }
 }
 
 int main(int, char**) {

>From 7b7d8253b940b0a822881146013873052a07dbd1 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Fri, 15 Mar 2024 18:54:15 +0200
Subject: [PATCH 49/56] Tests: updated `ospanstream`, `spanbuf`, `spanstream`

---
 .../ospanstream.cons/assign.move.pass.cpp     | 45 +++++++++++++++++++
 .../ospanstream.cons/ctor.move.pass.cpp       | 41 +++++++++++++++++
 .../{move.pass.cpp => assign.move.pass.cpp}   |  0
 .../spanbuf/spanbuf.cons/mode.pass.cpp        |  9 ++--
 .../spanbuf/spanbuf.cons/move.pass.cpp        | 25 ++++++-----
 .../spanbuf/spanbuf.cons/span.mode.pass.cpp   | 40 ++++++++---------
 .../spanstream.cons/assign.move.pass.cpp      | 45 +++++++++++++++++++
 .../spanstream.cons/ctor.move.pass.cpp        | 45 +++++++++++++++++++
 8 files changed, 215 insertions(+), 35 deletions(-)
 rename libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/{move.pass.cpp => assign.move.pass.cpp} (100%)

diff --git a/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.cons/assign.move.pass.cpp b/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.cons/assign.move.pass.cpp
index ead2efb5d6bef..8dd4eab2c86f5 100644
--- a/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.cons/assign.move.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.cons/assign.move.pass.cpp
@@ -36,42 +36,87 @@ void test() {
   // Mode: default (`in` | `out`)
   {
     SpStream rhsSpSt{sp};
+    assert(rhsSpSt.span().data() == arr);
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
+
     SpStream spSt = std::move(rhsSpSt);
     assert(spSt.span().data() == arr);
     assert(spSt.span().empty());
     assert(spSt.span().size() == 0);
+
+    // After move
+    assert(rhsSpSt.span().data() == arr);
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
   }
   // Mode: `in`
   {
     SpStream rhsSpSt{sp, std::ios_base::in};
+    assert(rhsSpSt.span().data() == arr);
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
+
     SpStream spSt = std::move(rhsSpSt);
     assert(spSt.span().data() == arr);
     assert(spSt.span().empty());
     assert(spSt.span().size() == 0);
+
+    // After move
+    assert(rhsSpSt.span().data() == arr);
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
   }
   // Mode `out`
   {
     SpStream rhsSpSt{sp, std::ios_base::out};
+    assert(rhsSpSt.span().data() == arr);
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
+
     SpStream spSt = std::move(rhsSpSt);
     assert(spSt.span().data() == arr);
     assert(spSt.span().empty());
     assert(spSt.span().size() == 0);
+
+    // After move
+    assert(rhsSpSt.span().data() == arr);
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
   }
   // Mode: multiple
   {
     SpStream rhsSpSt{sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary};
+    assert(rhsSpSt.span().data() == arr);
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
+
     SpStream spSt = std::move(rhsSpSt);
     assert(spSt.span().data() == arr);
     assert(spSt.span().empty());
     assert(spSt.span().size() == 0);
+
+    // After move
+    assert(rhsSpSt.span().data() == arr);
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
   }
   // Mode `ate`
   {
     SpStream rhsSpSt{sp, std::ios_base::out | std::ios_base::ate};
+    assert(rhsSpSt.span().data() == arr);
+    assert(!rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 4);
+
     SpStream spSt = std::move(rhsSpSt);
     assert(spSt.span().data() == arr);
     assert(!spSt.span().empty());
     assert(spSt.span().size() == 4);
+
+    // After move
+    assert(rhsSpSt.span().data() == arr);
+    assert(!rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 4);
   }
 }
 
diff --git a/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.cons/ctor.move.pass.cpp b/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.cons/ctor.move.pass.cpp
index 8e1937d6d3c2f..cdd625529264e 100644
--- a/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.cons/ctor.move.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.cons/ctor.move.pass.cpp
@@ -36,26 +36,53 @@ void test() {
   // Mode: default (`in` | `out`)
   {
     SpStream rhsSpSt{sp};
+    assert(rhsSpSt.span().data() == arr);
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
+
     SpStream spSt{std::move(rhsSpSt)};
     assert(spSt.span().data() == arr);
     assert(spSt.span().empty());
     assert(spSt.span().size() == 0);
+
+    // After move
+    assert(rhsSpSt.span().data() == arr);
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
   }
   // Mode: `in`
   {
     SpStream rhsSpSt{sp, std::ios_base::in};
+    assert(rhsSpSt.span().data() == arr);
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
+
     SpStream spSt{std::move(rhsSpSt)};
     assert(spSt.span().data() == arr);
     assert(spSt.span().empty());
     assert(spSt.span().size() == 0);
+
+    // After move
+    assert(rhsSpSt.span().data() == arr);
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
   }
   // Mode `out`
   {
     SpStream rhsSpSt{sp, std::ios_base::out};
+    assert(rhsSpSt.span().data() == arr);
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
+
     SpStream spSt{std::move(rhsSpSt)};
     assert(spSt.span().data() == arr);
     assert(spSt.span().empty());
     assert(spSt.span().size() == 0);
+
+    // After move
+    assert(rhsSpSt.span().data() == arr);
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
   }
   // Mode: multiple
   {
@@ -64,14 +91,28 @@ void test() {
     assert(spSt.span().data() == arr);
     assert(spSt.span().empty());
     assert(spSt.span().size() == 0);
+
+    // After move
+    assert(rhsSpSt.span().data() == arr);
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
   }
   // Mode `ate`
   {
     SpStream rhsSpSt{sp, std::ios_base::out | std::ios_base::ate};
+    assert(rhsSpSt.span().data() == arr);
+    assert(!rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 4);
+
     SpStream spSt{std::move(rhsSpSt)};
     assert(spSt.span().data() == arr);
     assert(!spSt.span().empty());
     assert(spSt.span().size() == 4);
+
+    // After move
+    assert(rhsSpSt.span().data() == arr);
+    assert(!rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 4);
   }
 }
 
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/move.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/assign.move.pass.cpp
similarity index 100%
rename from libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/move.pass.cpp
rename to libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.assign/assign.move.pass.cpp
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/mode.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/mode.pass.cpp
index 91fc5385484f7..4acc5d7d862ba 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/mode.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/mode.pass.cpp
@@ -49,14 +49,14 @@ void test() {
 
   // Mode: `in`
   {
-    SpBuf spBuf(std::ios_base::in);
+    SpBuf spBuf{std::ios_base::in};
     assert(spBuf.span().data() == nullptr);
     assert(spBuf.span().empty());
     assert(spBuf.span().size() == 0);
   }
   // Mode: `out`
   {
-    SpBuf spBuf(std::ios_base::out);
+    SpBuf spBuf{std::ios_base::out};
     assert(spBuf.span().data() == nullptr);
     // Mode `out` counts read characters
     assert(spBuf.span().empty());
@@ -64,7 +64,7 @@ void test() {
   }
   // Mode: multiple
   {
-    SpBuf spBuf(std::ios_base::in | std::ios_base::out | std::ios_base::binary);
+    SpBuf spBuf{std::ios_base::in | std::ios_base::out | std::ios_base::binary};
     assert(spBuf.span().data() == nullptr);
     // Mode `out` counts read character
     assert(spBuf.span().empty());
@@ -72,9 +72,8 @@ void test() {
   }
   // Mode: `ate`
   {
-    SpBuf spBuf(std::ios_base::out | std::ios_base::ate);
+    SpBuf spBuf{std::ios_base::out | std::ios_base::ate};
     assert(spBuf.span().data() == nullptr);
-
     assert(spBuf.span().empty());
     assert(spBuf.span().size() == 0);
   }
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/move.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/move.pass.cpp
index e9e483d290c55..d094c491ca45e 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/move.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/move.pass.cpp
@@ -164,7 +164,7 @@ void test() {
       assert(rhsSpBuf.span().empty());
       assert(rhsSpBuf.span().size() == 0);
 
-      SpBuf spBuf(std::move(rhsSpBuf));
+      SpBuf spBuf{std::move(rhsSpBuf)};
       assert(spBuf.span().data() == nullptr);
       // Mode `out` counts read characters
       assert(spBuf.span().empty());
@@ -183,7 +183,7 @@ void test() {
       assert(rhsSpBuf.span().empty());
       assert(rhsSpBuf.span().size() == 0);
 
-      SpBuf spBuf(std::move(rhsSpBuf));
+      SpBuf spBuf{std::move(rhsSpBuf)};
       assert(spBuf.span().data() == nullptr);
       assert(spBuf.span().empty());
       assert(spBuf.span().size() == 0);
@@ -201,7 +201,7 @@ void test() {
       assert(rhsSpBuf.span().empty());
       assert(rhsSpBuf.span().size() == 0);
 
-      SpBuf spBuf(std::move(rhsSpBuf));
+      SpBuf spBuf{std::move(rhsSpBuf)};
       assert(spBuf.span().data() == nullptr);
       // Mode `out` counts read characters
       assert(spBuf.span().empty());
@@ -221,7 +221,7 @@ void test() {
       assert(rhsSpBuf.span().empty());
       assert(rhsSpBuf.span().size() == 0);
 
-      SpBuf spBuf(std::move(rhsSpBuf));
+      SpBuf spBuf{std::move(rhsSpBuf)};
       assert(spBuf.span().data() == nullptr);
       // Mode `out` counts read characters
       assert(spBuf.span().empty());
@@ -235,7 +235,7 @@ void test() {
     // Mode: `ate`
     {
       SpBuf rhsSpBuf{std::ios_base::ate};
-      SpBuf spBuf(std::move(rhsSpBuf));
+      SpBuf spBuf{std::move(rhsSpBuf)};
       assert(spBuf.span().data() == nullptr);
       assert(spBuf.span().empty());
       assert(spBuf.span().size() == 0);
@@ -260,7 +260,7 @@ void test() {
       assert(rhsSpBuf.span().empty());
       assert(rhsSpBuf.span().size() == 0);
 
-      SpBuf spBuf(std::move(rhsSpBuf));
+      SpBuf spBuf{std::move(rhsSpBuf)};
       assert(spBuf.span().data() == arr);
       // Mode `out` counts read characters
       assert(spBuf.span().empty());
@@ -278,10 +278,15 @@ void test() {
       assert(!rhsSpBuf.span().empty());
       assert(rhsSpBuf.span().size() == 4);
 
-      SpBuf spBuf(std::move(rhsSpBuf));
+      SpBuf spBuf{std::move(rhsSpBuf)};
       assert(spBuf.span().data() == arr);
       assert(!spBuf.span().empty());
       assert(spBuf.span().size() == 4);
+
+      // After move
+      assert(rhsSpBuf.span().data() == arr);
+      assert(!rhsSpBuf.span().empty());
+      assert(rhsSpBuf.span().size() == 4);
     }
     // Mode `out`
     {
@@ -291,7 +296,7 @@ void test() {
       assert(rhsSpBuf.span().empty());
       assert(rhsSpBuf.span().size() == 0);
 
-      SpBuf spBuf(std::move(rhsSpBuf));
+      SpBuf spBuf{std::move(rhsSpBuf)};
       assert(spBuf.span().data() == arr);
       // Mode `out` counts read characters
       assert(spBuf.span().empty());
@@ -310,7 +315,7 @@ void test() {
       assert(rhsSpBuf.span().empty());
       assert(rhsSpBuf.span().size() == 0);
 
-      SpBuf spBuf(std::move(rhsSpBuf));
+      SpBuf spBuf{std::move(rhsSpBuf)};
       assert(spBuf.span().data() == arr);
       // Mode `out` counts read characters
       assert(spBuf.span().empty());
@@ -328,7 +333,7 @@ void test() {
       assert(!rhsSpBuf.span().empty());
       assert(rhsSpBuf.span().size() == 4);
 
-      SpBuf spBuf(std::move(rhsSpBuf));
+      SpBuf spBuf{std::move(rhsSpBuf)};
       assert(spBuf.span().data() == arr);
       assert(!spBuf.span().empty());
       assert(spBuf.span().size() == 4);
diff --git a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/span.mode.pass.cpp b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/span.mode.pass.cpp
index 9557b096f8f91..c719c9caa9865 100644
--- a/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/span.mode.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanbuf/spanbuf.cons/span.mode.pass.cpp
@@ -55,14 +55,14 @@ void test() {
 
     // Mode: default (`in` | `out`)
     {
-      SpBuf spBuf(sp);
+      SpBuf spBuf{sp};
       assert(spBuf.span().data() == nullptr);
       // Mode `out` counts read characters
       assert(spBuf.span().empty());
       assert(spBuf.span().size() == 0);
     }
     {
-      SpBuf spBuf(std::as_const(sp));
+      SpBuf spBuf{std::as_const(sp)};
       assert(spBuf.span().data() == nullptr);
       // Mode `out` counts read characters
       assert(spBuf.span().empty());
@@ -70,27 +70,27 @@ void test() {
     }
     // Mode: `in`
     {
-      SpBuf spBuf(sp, std::ios_base::in);
+      SpBuf spBuf{sp, std::ios_base::in};
       assert(spBuf.span().data() == nullptr);
       assert(spBuf.span().empty());
       assert(spBuf.span().size() == 0);
     }
     {
-      SpBuf spBuf(std::as_const(sp), std::ios_base::in);
+      SpBuf spBuf{std::as_const(sp), std::ios_base::in};
       assert(spBuf.span().data() == nullptr);
       assert(spBuf.span().empty());
       assert(spBuf.span().size() == 0);
     }
     // Mode: `out`
     {
-      SpBuf spBuf(sp, std::ios_base::out);
+      SpBuf spBuf{sp, std::ios_base::out};
       assert(spBuf.span().data() == nullptr);
       // Mode `out` counts read characters
       assert(spBuf.span().empty());
       assert(spBuf.span().size() == 0);
     }
     {
-      SpBuf spBuf(std::as_const(sp), std::ios_base::out);
+      SpBuf spBuf{std::as_const(sp), std::ios_base::out};
       assert(spBuf.span().data() == nullptr);
       // Mode `out` counts read characters
       assert(spBuf.span().empty());
@@ -98,14 +98,14 @@ void test() {
     }
     // Mode: multiple
     {
-      SpBuf spBuf(sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary);
+      SpBuf spBuf{sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary};
       assert(spBuf.span().data() == nullptr);
       // Mode `out` counts read characters
       assert(spBuf.span().empty());
       assert(spBuf.span().size() == 0);
     }
     {
-      SpBuf spBuf(std::as_const(sp), std::ios_base::in | std::ios_base::out | std::ios_base::binary);
+      SpBuf spBuf{std::as_const(sp), std::ios_base::in | std::ios_base::out | std::ios_base::binary};
       assert(spBuf.span().data() == nullptr);
       // Mode `out` counts read characters
       assert(spBuf.span().empty());
@@ -113,13 +113,13 @@ void test() {
     }
     // Mode: `ate`
     {
-      SpBuf spBuf(sp, std::ios_base::out | std::ios_base::ate);
+      SpBuf spBuf{sp, std::ios_base::out | std::ios_base::ate};
       assert(spBuf.span().data() == nullptr);
       assert(spBuf.span().empty());
       assert(spBuf.span().size() == 0);
     }
     {
-      SpBuf spBuf(std::as_const(sp), std::ios_base::out | std::ios_base::ate);
+      SpBuf spBuf{std::as_const(sp), std::ios_base::out | std::ios_base::ate};
       assert(spBuf.span().data() == nullptr);
       assert(spBuf.span().empty());
       assert(spBuf.span().size() == 0);
@@ -133,14 +133,14 @@ void test() {
 
     // Mode: default (`in` | `out`)
     {
-      SpBuf spBuf(sp);
+      SpBuf spBuf{sp};
       assert(spBuf.span().data() == arr);
       // Mode `out` counts read characters
       assert(spBuf.span().empty());
       assert(spBuf.span().size() == 0);
     }
     {
-      SpBuf spBuf(std::as_const(sp));
+      SpBuf spBuf{std::as_const(sp)};
       assert(spBuf.span().data() == arr);
       // Mode `out` counts read characters
       assert(spBuf.span().empty());
@@ -148,27 +148,27 @@ void test() {
     }
     // Mode: `in`
     {
-      SpBuf spBuf(sp, std::ios_base::in);
+      SpBuf spBuf{sp, std::ios_base::in};
       assert(spBuf.span().data() == arr);
       assert(!spBuf.span().empty());
       assert(spBuf.span().size() == 4);
     }
     {
-      SpBuf spBuf(std::as_const(sp), std::ios_base::in);
+      SpBuf spBuf{std::as_const(sp), std::ios_base::in};
       assert(spBuf.span().data() == arr);
       assert(!spBuf.span().empty());
       assert(spBuf.span().size() == 4);
     }
     // Mode `out`
     {
-      SpBuf spBuf(sp, std::ios_base::out);
+      SpBuf spBuf{sp, std::ios_base::out};
       assert(spBuf.span().data() == arr);
       // Mode `out` counts read characters
       assert(spBuf.span().empty());
       assert(spBuf.span().size() == 0);
     }
     {
-      SpBuf spBuf(std::as_const(sp), std::ios_base::out);
+      SpBuf spBuf{std::as_const(sp), std::ios_base::out};
       assert(spBuf.span().data() == arr);
       // Mode `out` counts read characters
       assert(spBuf.span().empty());
@@ -176,14 +176,14 @@ void test() {
     }
     // Mode: multiple
     {
-      SpBuf spBuf(sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary);
+      SpBuf spBuf{sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary};
       assert(spBuf.span().data() == arr);
       // Mode `out` counts read characters
       assert(spBuf.span().empty());
       assert(spBuf.span().size() == 0);
     }
     {
-      SpBuf spBuf(std::as_const(sp), std::ios_base::in | std::ios_base::out | std::ios_base::binary);
+      SpBuf spBuf{std::as_const(sp), std::ios_base::in | std::ios_base::out | std::ios_base::binary};
       assert(spBuf.span().data() == arr);
       // Mode `out` counts read characters
       assert(spBuf.span().empty());
@@ -191,13 +191,13 @@ void test() {
     }
     // Mode: `ate`
     {
-      SpBuf spBuf(sp, std::ios_base::out | std::ios_base::ate);
+      SpBuf spBuf{sp, std::ios_base::out | std::ios_base::ate};
       assert(spBuf.span().data() == arr);
       assert(!spBuf.span().empty());
       assert(spBuf.span().size() == 4);
     }
     {
-      SpBuf spBuf(std::as_const(sp), std::ios_base::out | std::ios_base::ate);
+      SpBuf spBuf{std::as_const(sp), std::ios_base::out | std::ios_base::ate};
       assert(spBuf.span().data() == arr);
       assert(!spBuf.span().empty());
       assert(spBuf.span().size() == 4);
diff --git a/libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/assign.move.pass.cpp b/libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/assign.move.pass.cpp
index 7caa7020cb0ff..ac807b405b18a 100644
--- a/libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/assign.move.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/assign.move.pass.cpp
@@ -36,42 +36,87 @@ void test() {
   // Mode: default (`in` | `out`)
   {
     SpStream rhsSpSt{sp};
+    assert(rhsSpSt.span().data() == arr);
+    assert(!rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 4);
+
     SpStream spSt = std::move(rhsSpSt);
     assert(spSt.span().data() == arr);
     assert(!spSt.span().empty());
     assert(spSt.span().size() == 4);
+
+    // After move
+    assert(rhsSpSt.span().data() == arr);
+    assert(!rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 4);
   }
   // Mode: `in`
   {
     SpStream rhsSpSt{sp, std::ios_base::in};
+    assert(rhsSpSt.span().data() == arr);
+    assert(!rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 4);
+
     SpStream spSt = std::move(rhsSpSt);
     assert(spSt.span().data() == arr);
     assert(!spSt.span().empty());
     assert(spSt.span().size() == 4);
+
+    // After move
+    assert(rhsSpSt.span().data() == arr);
+    assert(!rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 4);
   }
   // Mode `out`
   {
     SpStream rhsSpSt{sp, std::ios_base::out};
+    assert(rhsSpSt.span().data() == arr);
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
+
     SpStream spSt = std::move(rhsSpSt);
     assert(spSt.span().data() == arr);
     assert(spSt.span().empty());
     assert(spSt.span().size() == 0);
+
+    // After move
+    assert(rhsSpSt.span().data() == arr);
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
   }
   // Mode: multiple
   {
     SpStream rhsSpSt{sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary};
+    assert(rhsSpSt.span().data() == arr);
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
+
     SpStream spSt = std::move(rhsSpSt);
     assert(spSt.span().data() == arr);
     assert(spSt.span().empty());
     assert(spSt.span().size() == 0);
+
+    // After move
+    assert(rhsSpSt.span().data() == arr);
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
   }
   // Mode `ate`
   {
     SpStream rhsSpSt{sp, std::ios_base::in};
+    assert(rhsSpSt.span().data() == arr);
+    assert(!rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 4);
+
     SpStream spSt = std::move(rhsSpSt);
     assert(spSt.span().data() == arr);
     assert(!spSt.span().empty());
     assert(spSt.span().size() == 4);
+
+    // After move
+    assert(rhsSpSt.span().data() == arr);
+    assert(!rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 4);
   }
 }
 
diff --git a/libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/ctor.move.pass.cpp b/libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/ctor.move.pass.cpp
index 4878ebcda13df..87ef4c06a8ff8 100644
--- a/libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/ctor.move.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/ctor.move.pass.cpp
@@ -36,42 +36,87 @@ void test() {
   // Mode: default (`in` | `out`)
   {
     SpStream rhsSpSt{sp};
+    assert(rhsSpSt.span().data() == arr);
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
+
     SpStream spSt{std::move(rhsSpSt)};
     assert(spSt.span().data() == arr);
     assert(spSt.span().empty());
     assert(spSt.span().size() == 0);
+
+    // After move
+    assert(rhsSpSt.span().data() == arr);
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
   }
   // Mode: `in`
   {
     SpStream rhsSpSt{sp, std::ios_base::in};
+    assert(rhsSpSt.span().data() == arr);
+    assert(!rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 4);
+
     SpStream spSt{std::move(rhsSpSt)};
     assert(spSt.span().data() == arr);
     assert(!spSt.span().empty());
     assert(spSt.span().size() == 4);
+
+    // After move
+    assert(rhsSpSt.span().data() == arr);
+    assert(!rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 4);
   }
   // Mode `out`
   {
     SpStream rhsSpSt{sp, std::ios_base::out};
+    assert(rhsSpSt.span().data() == arr);
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
+
     SpStream spSt{std::move(rhsSpSt)};
     assert(spSt.span().data() == arr);
     assert(spSt.span().empty());
     assert(spSt.span().size() == 0);
+
+    // After move
+    assert(rhsSpSt.span().data() == arr);
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
   }
   // Mode: multiple
   {
     SpStream rhsSpSt{sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary};
+    assert(rhsSpSt.span().data() == arr);
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
+
     SpStream spSt{std::move(rhsSpSt)};
     assert(spSt.span().data() == arr);
     assert(spSt.span().empty());
     assert(spSt.span().size() == 0);
+
+    // After move
+    assert(rhsSpSt.span().data() == arr);
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
   }
   // Mode `ate`
   {
     SpStream rhsSpSt{sp, std::ios_base::out | std::ios_base::ate};
+    assert(rhsSpSt.span().data() == arr);
+    assert(!rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 4);
+
     SpStream spSt{std::move(rhsSpSt)};
     assert(spSt.span().data() == arr);
     assert(!spSt.span().empty());
     assert(spSt.span().size() == 4);
+
+    // After move
+    assert(rhsSpSt.span().data() == arr);
+    assert(!rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 4);
   }
 }
 

>From 9c3ac3f34a0c4664e52ca3f979f0e1a35d93b38c Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Fri, 15 Mar 2024 20:50:19 +0200
Subject: [PATCH 50/56] Tests: updated and fixed tests

---
 .../ispanstream.assign/swap.pass.cpp          |  85 ----------
 .../swap_nonmember.pass.cpp                   |  81 ---------
 .../ispanstream.cons/assign.move.pass.cpp     | 140 ++++++++++++++++
 .../{move.pass.cpp => ctor.move.pass.cpp}     |  70 +++++++-
 .../{ros.pass.cpp => ctor.ros.pass.cpp}       |   6 +-
 ....mode.pass.cpp => ctor.span.mode.pass.cpp} |  43 +++--
 .../ispanstream.members/rdbuf.pass.cpp        |  91 ++++++++++
 .../span.pass.cpp}                            |  43 +++--
 .../ispanstream.members/span.span.pass.cpp    | 116 +++++++++++++
 .../ispanstream.swap/swap.pass.cpp            | 155 ++++++++++++++++++
 .../ispanstream.swap/swap_nonmember.pass.cpp  | 153 +++++++++++++++++
 .../ospanstream.cons/assign.move.pass.cpp     |   4 +
 .../ospanstream.cons/ctor.move.pass.cpp       |   8 +
 .../ospanstream.cons/ctor.span.mode.pass.cpp  |   5 +
 .../ospanstream.members/span.span.pass.cpp    |  20 +--
 .../ospanstream.swap/swap.pass.cpp            |   2 +-
 .../spanstream.cons/assign.move.pass.cpp      |  18 +-
 .../spanstream.cons/ctor.move.pass.cpp        |   4 +
 .../spanstream.cons/ctor.span.mode.pass.cpp   |   6 +-
 .../spanstream.members/span.span.pass.cpp     |  12 +-
 20 files changed, 836 insertions(+), 226 deletions(-)
 delete mode 100644 libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.assign/swap.pass.cpp
 delete mode 100644 libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.assign/swap_nonmember.pass.cpp
 create mode 100644 libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/assign.move.pass.cpp
 rename libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/{move.pass.cpp => ctor.move.pass.cpp} (51%)
 rename libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/{ros.pass.cpp => ctor.ros.pass.cpp} (95%)
 rename libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/{span.mode.pass.cpp => ctor.span.mode.pass.cpp} (73%)
 create mode 100644 libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.members/rdbuf.pass.cpp
 rename libcxx/test/std/input.output/span.streams/ispanstream/{ispanstream.assign/move.pass.cpp => ispanstream.members/span.pass.cpp} (65%)
 create mode 100644 libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.members/span.span.pass.cpp
 create mode 100644 libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.swap/swap.pass.cpp
 create mode 100644 libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.swap/swap_nonmember.pass.cpp

diff --git a/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.assign/swap.pass.cpp b/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.assign/swap.pass.cpp
deleted file mode 100644
index c70d9017e53bd..0000000000000
--- a/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.assign/swap.pass.cpp
+++ /dev/null
@@ -1,85 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
-
-// <spanstream>
-
-//   template<class charT, class traits = char_traits<charT>>
-//   class basic_ispanstream
-//     : public basic_streambuf<charT, traits> {
-
-//     // [ispanstream.swap], swap
-//     void swap(basic_ispanstream& rhs);
-
-#include <cassert>
-#include <concepts>
-#include <span>
-#include <spanstream>
-
-#include "constexpr_char_traits.h"
-#include "test_convertible.h"
-#include "test_macros.h"
-
-template <typename CharT, typename TraitsT = std::char_traits<CharT>>
-void test() {
-  using SpStream = std::basic_ispanstream<CharT, TraitsT>;
-
-  CharT arr[4];
-  std::span<CharT> sp{arr};
-
-  // TODO:
-
-  // Mode: default
-  {
-    SpStream rhsSpSt{sp};
-    SpStream spSt(std::span<CharT>{});
-    spSt.swap(rhsSpSt);
-    assert(spSt.span().data() == arr);
-    assert(!spSt.span().empty());
-    assert(spSt.span().size() == 4);
-  }
-  // Mode: `in`
-  {
-    SpStream rhsSpSt{sp, std::ios_base::in};
-    SpStream spSt(std::span<CharT>{});
-    spSt.swap(rhsSpSt);
-    assert(spSt.span().data() == arr);
-    assert(!spSt.span().empty());
-    assert(spSt.span().size() == 4);
-  }
-  // Mode `out`
-  {
-    SpStream rhsSpSt{sp, std::ios_base::out};
-    SpStream spSt(std::span<CharT>{});
-    spSt.swap(rhsSpSt);
-    assert(spSt.span().data() == arr);
-    assert(spSt.span().empty());
-    assert(spSt.span().size() == 0);
-  }
-  // Mode: multiple
-  {
-    SpStream rhsSpSt{sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary};
-    SpStream spSt(std::span<CharT>{});
-    spSt.swap(rhsSpSt);
-    assert(spSt.span().data() == arr);
-    assert(spSt.span().empty());
-    assert(spSt.span().size() == 0);
-  }
-}
-
-int main(int, char**) {
-  test<char>();
-  test<char, constexpr_char_traits<char>>();
-#ifndef TEST_HAS_NO_WIDE_CHARACTERS
-  test<wchar_t>();
-  test<wchar_t, constexpr_char_traits<wchar_t>>();
-#endif
-
-  return 0;
-}
diff --git a/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.assign/swap_nonmember.pass.cpp b/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.assign/swap_nonmember.pass.cpp
deleted file mode 100644
index 06f59daafac08..0000000000000
--- a/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.assign/swap_nonmember.pass.cpp
+++ /dev/null
@@ -1,81 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
-
-// <spanstream>
-
-//   template<class charT, class traits>
-//     void swap(basic_ispanstream<charT, traits>& x, basic_ispanstream<charT, traits>& y);
-
-#include <cassert>
-#include <concepts>
-#include <span>
-#include <spanstream>
-
-#include "constexpr_char_traits.h"
-#include "test_convertible.h"
-#include "test_macros.h"
-
-template <typename CharT, typename TraitsT = std::char_traits<CharT>>
-void test() {
-  using SpStream = std::basic_ispanstream<CharT, TraitsT>;
-
-  CharT arr[4];
-  std::span<CharT> sp{arr};
-
-  // TODO:
-
-  // Mode: default
-  {
-    SpStream rhsSpSt{sp};
-    SpStream spSt(std::span<CharT>{});
-    std::swap(spSt, rhsSpSt);
-    assert(spSt.span().data() == arr);
-    assert(!spSt.span().empty());
-    assert(spSt.span().size() == 4);
-  }
-  // Mode: `in`
-  {
-    SpStream rhsSpSt{sp, std::ios_base::in};
-    SpStream spSt(std::span<CharT>{});
-    std::swap(spSt, rhsSpSt);
-    assert(spSt.span().data() == arr);
-    assert(!spSt.span().empty());
-    assert(spSt.span().size() == 4);
-  }
-  // Mode `out`
-  {
-    SpStream rhsSpSt{sp, std::ios_base::out};
-    SpStream spSt(std::span<CharT>{});
-    std::swap(spSt, rhsSpSt);
-    assert(spSt.span().data() == arr);
-    assert(spSt.span().empty());
-    assert(spSt.span().size() == 0);
-  }
-  // Mode: multiple
-  {
-    SpStream rhsSpSt{sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary};
-    SpStream spSt(std::span<CharT>{});
-    std::swap(spSt, rhsSpSt);
-    assert(spSt.span().data() == arr);
-    assert(spSt.span().empty());
-    assert(spSt.span().size() == 0);
-  }
-}
-
-int main(int, char**) {
-  test<char>();
-  test<char, constexpr_char_traits<char>>();
-#ifndef TEST_HAS_NO_WIDE_CHARACTERS
-  test<wchar_t>();
-  test<wchar_t, constexpr_char_traits<wchar_t>>();
-#endif
-
-  return 0;
-}
diff --git a/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/assign.move.pass.cpp b/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/assign.move.pass.cpp
new file mode 100644
index 0000000000000..bba20cd973141
--- /dev/null
+++ b/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/assign.move.pass.cpp
@@ -0,0 +1,140 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <spanstream>
+
+//   template<class charT, class traits = char_traits<charT>>
+//   class basic_ispanstream
+//     : public basic_istream<charT, traits> {
+
+//     // [spanbuf.cons], constructors
+//
+//     basic_ispanstream& operator=(basic_ispanstream&& rhs);
+
+#include <cassert>
+#include <concepts>
+#include <span>
+#include <spanstream>
+
+#include "constexpr_char_traits.h"
+#include "nasty_string.h"
+#include "test_macros.h"
+
+template <typename CharT, typename TraitsT = std::char_traits<CharT>>
+void test() {
+  using SpStream = std::basic_ispanstream<CharT, TraitsT>;
+
+  CharT arr[4];
+
+  std::span<CharT> sp{arr};
+  assert(sp.data() == arr);
+  assert(!sp.empty());
+  assert(sp.size() == 4);
+
+  // Mode: default (`in` | `out`)
+  {
+    SpStream rhsSpSt{sp};
+    assert(rhsSpSt.span().data() == arr);
+    assert(!rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 4);
+
+    SpStream spSt = std::move(rhsSpSt);
+    assert(spSt.span().data() == arr);
+    assert(!spSt.span().empty());
+    assert(spSt.span().size() == 4);
+
+    // After move
+    assert(rhsSpSt.span().data() == arr);
+    assert(!rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 4);
+  }
+  // Mode: `in`
+  {
+    SpStream rhsSpSt{sp, std::ios_base::in};
+    assert(rhsSpSt.span().data() == arr);
+    assert(!rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 4);
+
+    SpStream spSt = std::move(rhsSpSt);
+    assert(spSt.span().data() == arr);
+    assert(!spSt.span().empty());
+    assert(spSt.span().size() == 4);
+
+    // After move
+    assert(rhsSpSt.span().data() == arr);
+    assert(!rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 4);
+  }
+  // Mode `out`
+  {
+    SpStream rhsSpSt{sp, std::ios_base::out};
+    assert(rhsSpSt.span().data() == arr);
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
+
+    SpStream spSt = std::move(rhsSpSt);
+    assert(spSt.span().data() == arr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+
+    // After move
+    assert(rhsSpSt.span().data() == arr);
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
+  }
+  // Mode: multiple
+  {
+    SpStream rhsSpSt{sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary};
+    assert(rhsSpSt.span().data() == arr);
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
+
+    SpStream spSt = std::move(rhsSpSt);
+    assert(spSt.span().data() == arr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+
+    // After move
+    assert(rhsSpSt.span().data() == arr);
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
+  }
+  // Mode `ate`
+  {
+    SpStream rhsSpSt{sp, std::ios_base::out | std::ios_base::ate};
+    assert(rhsSpSt.span().data() == arr);
+    assert(!rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 4);
+
+    SpStream spSt = std::move(rhsSpSt);
+    assert(spSt.span().data() == arr);
+    assert(!spSt.span().empty());
+    assert(spSt.span().size() == 4);
+
+    // After move
+    assert(rhsSpSt.span().data() == arr);
+    assert(!rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 4);
+  }
+}
+
+int main(int, char**) {
+#ifndef TEST_HAS_NO_NASTY_STRING
+  test<nasty_char, nasty_char_traits>();
+#endif
+  test<char>();
+  test<char, constexpr_char_traits<char>>();
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  test<wchar_t>();
+  test<wchar_t, constexpr_char_traits<wchar_t>>();
+#endif
+
+  return 0;
+}
diff --git a/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/move.pass.cpp b/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/ctor.move.pass.cpp
similarity index 51%
rename from libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/move.pass.cpp
rename to libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/ctor.move.pass.cpp
index aafcbf6c88961..8ed9f0aba190e 100644
--- a/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/move.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/ctor.move.pass.cpp
@@ -12,7 +12,7 @@
 
 //   template<class charT, class traits = char_traits<charT>>
 //   class basic_ispanstream
-//     : public basic_streambuf<charT, traits> {
+//     : public basic_istream<charT, traits> {
 
 //     // [spanbuf.cons], constructors
 //
@@ -24,7 +24,7 @@
 #include <spanstream>
 
 #include "constexpr_char_traits.h"
-#include "test_convertible.h"
+#include "nasty_string.h"
 #include "test_macros.h"
 
 template <typename CharT, typename TraitsT = std::char_traits<CharT>>
@@ -32,43 +32,103 @@ void test() {
   using SpStream = std::basic_ispanstream<CharT, TraitsT>;
 
   CharT arr[4];
+
   std::span<CharT> sp{arr};
+  assert(sp.data() == arr);
+  assert(!sp.empty());
+  assert(sp.size() == 4);
 
-  // Mode: default
+  // Mode: default (`in` | `out`)
   {
     SpStream rhsSpSt{sp};
+    assert(rhsSpSt.span().data() == arr);
+    assert(!rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 4);
+
     SpStream spSt(std::move(rhsSpSt));
     assert(spSt.span().data() == arr);
     assert(!spSt.span().empty());
     assert(spSt.span().size() == 4);
+
+    // After move
+    assert(rhsSpSt.span().data() == arr);
+    assert(!rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 4);
   }
   // Mode: `in`
   {
     SpStream rhsSpSt{sp, std::ios_base::in};
+    assert(rhsSpSt.span().data() == arr);
+    assert(!rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 4);
+
     SpStream spSt(std::move(rhsSpSt));
     assert(spSt.span().data() == arr);
     assert(!spSt.span().empty());
     assert(spSt.span().size() == 4);
+
+    // After move
+    assert(rhsSpSt.span().data() == arr);
+    assert(!rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 4);
   }
   // Mode `out`
   {
     SpStream rhsSpSt{sp, std::ios_base::out};
-    SpStream spSt(std::move(rhsSpSt));
+    assert(rhsSpSt.span().data() == arr);
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
+
+    SpStream spSt{std::move(rhsSpSt)};
     assert(spSt.span().data() == arr);
     assert(spSt.span().empty());
     assert(spSt.span().size() == 0);
+
+    // After move
+    assert(rhsSpSt.span().data() == arr);
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
   }
   // Mode: multiple
   {
     SpStream rhsSpSt{sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary};
-    SpStream spSt(std::move(rhsSpSt));
+    assert(rhsSpSt.span().data() == arr);
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
+
+    SpStream spSt{std::move(rhsSpSt)};
     assert(spSt.span().data() == arr);
     assert(spSt.span().empty());
     assert(spSt.span().size() == 0);
+
+    // After move
+    assert(rhsSpSt.span().data() == arr);
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
+  }
+  // Mode `ate`
+  {
+    SpStream rhsSpSt{sp, std::ios_base::out | std::ios_base::ate};
+    assert(rhsSpSt.span().data() == arr);
+    assert(!rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 4);
+
+    SpStream spSt{std::move(rhsSpSt)};
+    assert(spSt.span().data() == arr);
+    assert(!spSt.span().empty());
+    assert(spSt.span().size() == 4);
+
+    // After move
+    assert(rhsSpSt.span().data() == arr);
+    assert(!rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 4);
   }
 }
 
 int main(int, char**) {
+#ifndef TEST_HAS_NO_NASTY_STRING
+  test<nasty_char, nasty_char_traits>();
+#endif
   test<char>();
   test<char, constexpr_char_traits<char>>();
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
diff --git a/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/ros.pass.cpp b/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/ctor.ros.pass.cpp
similarity index 95%
rename from libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/ros.pass.cpp
rename to libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/ctor.ros.pass.cpp
index ac64e66725f15..5cec1de19ffb1 100644
--- a/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/ros.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/ctor.ros.pass.cpp
@@ -12,7 +12,7 @@
 
 //   template<class charT, class traits = char_traits<charT>>
 //   class basic_ispanstream
-//     : public basic_streambuf<charT, traits> {
+//     : public basic_istream<charT, traits> {
 
 //     // [spanbuf.cons], constructors
 //
@@ -56,6 +56,7 @@ void test() {
 
   // TODO:
   CharT arr[4];
+  
   ReadOnlySpan<CharT, 4> ros{arr};
 
   {
@@ -83,6 +84,9 @@ int main(int, char**) {
 #endif
   test_sfinae<char>();
   test_sfinae<char, constexpr_char_traits<char>>();
+#ifndef TEST_HAS_NO_NASTY_STRING
+  test<nasty_char, nasty_char_traits>();
+#endif
   test<char>();
   test<char, constexpr_char_traits<char>>();
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
diff --git a/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/span.mode.pass.cpp b/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/ctor.span.mode.pass.cpp
similarity index 73%
rename from libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/span.mode.pass.cpp
rename to libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/ctor.span.mode.pass.cpp
index 75691ebc84fc6..81e544da3c263 100644
--- a/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/span.mode.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/ctor.span.mode.pass.cpp
@@ -12,9 +12,9 @@
 
 //   template<class charT, class traits = char_traits<charT>>
 //   class basic_ispanstream
-//     : public basic_streambuf<charT, traits> {
+//     : public basic_istream<charT, traits> {
 
-//     // [spanbuf.cons], constructors
+//     // [ispanstream.cons], constructors
 //
 //     explicit basic_ispanstream(std::span<charT> s,
 //                                ios_base::openmode which = ios_base::in);
@@ -30,7 +30,6 @@
 #include "test_convertible.h"
 #include "test_macros.h"
 
-#include "../../helper_macros.h"
 #include "../../helper_types.h"
 
 template <typename CharT, typename TraitsT = std::char_traits<CharT>>
@@ -51,60 +50,77 @@ void test() {
   using SpStream = std::basic_ispanstream<CharT, TraitsT>;
 
   CharT arr[4];
+
   std::span<CharT> sp{arr};
+  assert(sp.data() == arr);
+  assert(!sp.empty());
+  assert(sp.size() == 4);
 
-  // Mode: default
+  // Mode: default (`in` | `out`)
   {
-    SpStream spSt(sp);
+    SpStream spSt{sp};
     assert(spSt.span().data() == arr);
     assert(!spSt.span().empty());
     assert(spSt.span().size() == 4);
   }
   {
-    SpStream spSt(std::as_const(sp));
+    SpStream spSt{std::as_const(sp)};
     assert(spSt.span().data() == arr);
     assert(!spSt.span().empty());
     assert(spSt.span().size() == 4);
   }
   // Mode: `in`
   {
-    SpStream spSt(sp, std::ios_base::in);
+    SpStream spSt{sp, std::ios_base::in};
     assert(spSt.span().data() == arr);
     assert(!spSt.span().empty());
     assert(spSt.span().size() == 4);
   }
   {
-    SpStream spSt(std::as_const(sp), std::ios_base::in);
+    SpStream spSt{std::as_const(sp), std::ios_base::in};
     assert(spSt.span().data() == arr);
     assert(!spSt.span().empty());
     assert(spSt.span().size() == 4);
   }
   // Mode `out`
   {
-    SpStream spSt(sp, std::ios_base::out);
+    SpStream spSt{sp, std::ios_base::out};
     assert(spSt.span().data() == arr);
     assert(spSt.span().empty());
     assert(spSt.span().size() == 0);
   }
   {
-    SpStream spSt(std::as_const(sp), std::ios_base::out);
+    SpStream spSt{std::as_const(sp), std::ios_base::out};
     assert(spSt.span().data() == arr);
     assert(spSt.span().empty());
     assert(spSt.span().size() == 0);
   }
   // Mode: multiple
   {
-    SpStream spSt(sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary);
+    SpStream spSt{sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary};
     assert(spSt.span().data() == arr);
     assert(spSt.span().empty());
     assert(spSt.span().size() == 0);
   }
   {
-    SpStream spSt(std::as_const(sp), std::ios_base::in | std::ios_base::out | std::ios_base::binary);
+    SpStream spSt{std::as_const(sp), std::ios_base::in | std::ios_base::out | std::ios_base::binary};
     assert(spSt.span().data() == arr);
     assert(spSt.span().empty());
     assert(spSt.span().size() == 0);
   }
+  // Mode `ate`
+  {
+    SpStream spSt{sp, std::ios_base::out | std::ios_base::ate};
+    assert(spSt.span().data() == arr);
+    assert(!spSt.span().empty());
+    assert(spSt.span().size() == 4);
+  }
+  {
+    SpStream spSt{std::as_const(sp), std::ios_base::out | std::ios_base::ate};
+    assert(spSt.span().data() == arr);
+    assert(!spSt.span().empty());
+    assert(spSt.span().size() == 4);
+  }
 }
 
 int main(int, char**) {
@@ -113,6 +129,9 @@ int main(int, char**) {
 #endif
   test_sfinae<char>();
   test_sfinae<char, constexpr_char_traits<char>>();
+#ifndef TEST_HAS_NO_NASTY_STRING
+  test<nasty_char, nasty_char_traits>();
+#endif
   test<char>();
   test<char, constexpr_char_traits<char>>();
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
diff --git a/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.members/rdbuf.pass.cpp b/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.members/rdbuf.pass.cpp
new file mode 100644
index 0000000000000..0b5aa94f1b88a
--- /dev/null
+++ b/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.members/rdbuf.pass.cpp
@@ -0,0 +1,91 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <spanstream>
+
+//   template<class charT, class traits = char_traits<charT>>
+//   class basic_ospanstream
+//     : public basic_istream<charT, traits> {
+
+//     // [ospanstream.members], members
+//     basic_spanbuf<charT, traits>* rdbuf() const noexcept;
+
+#include <cassert>
+#include <span>
+#include <spanstream>
+
+#include "constexpr_char_traits.h"
+#include "nasty_string.h"
+#include "test_macros.h"
+
+template <typename CharT, typename TraitsT = std::char_traits<CharT>>
+void test() {
+  using SpStream = std::basic_ospanstream<CharT, TraitsT>;
+
+  CharT arr[4];
+
+  std::span<CharT> sp{arr};
+  assert(sp.data() == arr);
+  assert(!sp.empty());
+  assert(sp.size() == 4);
+
+  // Mode: default (`in` | `out`)
+  {
+    SpStream spSt{sp};
+    assert(spSt.rdbuf()->span().data() == arr);
+    // Mode `out` counts read characters
+    assert(spSt.rdbuf()->span().empty());
+    assert(spSt.rdbuf()->span().size() == 0);
+  }
+  // Mode: `in`
+  {
+    SpStream spSt{sp, std::ios_base::in};
+    assert(spSt.rdbuf()->span().data() == arr);
+    assert(spSt.rdbuf()->span().empty());
+    assert(spSt.rdbuf()->span().size() == 0);
+  }
+  // Mode: `out`
+  {
+    SpStream spSt{sp, std::ios_base::out};
+    assert(spSt.rdbuf()->span().data() == arr);
+    // Mode `out` counts read characters
+    assert(spSt.rdbuf()->span().empty());
+    assert(spSt.rdbuf()->span().size() == 0);
+  }
+  // Mode: multiple
+  {
+    SpStream spSt{sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary};
+    assert(spSt.rdbuf()->span().data() == arr);
+    // Mode `out` counts read characters
+    assert(spSt.rdbuf()->span().empty());
+    assert(spSt.rdbuf()->span().size() == 0);
+  }
+  // Mode: `ate`
+  {
+    SpStream spSt{sp, std::ios_base::out | std::ios_base::ate};
+    assert(spSt.rdbuf()->span().data() == arr);
+    assert(!spSt.rdbuf()->span().empty());
+    assert(spSt.rdbuf()->span().size() == 4);
+  }
+}
+
+int main(int, char**) {
+#ifndef TEST_HAS_NO_NASTY_STRING
+  test<nasty_char, nasty_char_traits>();
+#endif
+  test<char>();
+  test<char, constexpr_char_traits<char>>();
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  test<wchar_t>();
+  test<wchar_t, constexpr_char_traits<wchar_t>>();
+#endif
+
+  return 0;
+}
diff --git a/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.assign/move.pass.cpp b/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.members/span.pass.cpp
similarity index 65%
rename from libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.assign/move.pass.cpp
rename to libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.members/span.pass.cpp
index cc14bfb41671e..e1b6734301e06 100644
--- a/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.assign/move.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.members/span.pass.cpp
@@ -12,18 +12,18 @@
 
 //   template<class charT, class traits = char_traits<charT>>
 //   class basic_ispanstream
-//     : public basic_streambuf<charT, traits> {
+//     : public basic_istream<charT, traits> {
 
-//     // [spanbuf.cons], constructors
-//
-//     basic_ispanstream& operator=(basic_ispanstream&& rhs);
+//     // [ispanstream.members], members
+
+//     std::span<charT> span() const noexcept;
 
 #include <cassert>
-#include <concepts>
 #include <span>
 #include <spanstream>
 
 #include "constexpr_char_traits.h"
+#include "nasty_string.h"
 #include "test_macros.h"
 
 template <typename CharT, typename TraitsT = std::char_traits<CharT>>
@@ -31,45 +31,54 @@ void test() {
   using SpStream = std::basic_ispanstream<CharT, TraitsT>;
 
   CharT arr[4];
-  std::span<CharT> sp{arr};
 
-  // TODO:
+  std::span<CharT> sp{arr};
+  assert(sp.data() == arr);
+  assert(!sp.empty());
+  assert(sp.size() == 4);
 
-  // Mode: default
+  // Mode: default (`in` | `out`)
   {
-    SpStream rhsSpSt{sp};
-    SpStream spSt = std::move(rhsSpSt);
+    SpStream spSt{sp};
     assert(spSt.span().data() == arr);
     assert(!spSt.span().empty());
     assert(spSt.span().size() == 4);
   }
   // Mode: `in`
   {
-    SpStream rhsSpSt{sp, std::ios_base::in};
-    SpStream spSt = std::move(rhsSpSt);
+    SpStream spSt{sp, std::ios_base::in};
     assert(spSt.span().data() == arr);
     assert(!spSt.span().empty());
     assert(spSt.span().size() == 4);
   }
-  // Mode `out`
+  // Mode: `out`
   {
-    SpStream rhsSpSt{sp, std::ios_base::out};
-    SpStream spSt = std::move(rhsSpSt);
+    SpStream spSt{sp, std::ios_base::out};
     assert(spSt.span().data() == arr);
+    // Mode `out` counts read characters
     assert(spSt.span().empty());
     assert(spSt.span().size() == 0);
   }
   // Mode: multiple
   {
-    SpStream rhsSpSt{sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary};
-    SpStream spSt = std::move(rhsSpSt);
+    SpStream spSt{sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary};
     assert(spSt.span().data() == arr);
     assert(spSt.span().empty());
     assert(spSt.span().size() == 0);
   }
+  // Mode: `ate`
+  {
+    SpStream spSt{sp, std::ios_base::out | std::ios_base::ate};
+    assert(spSt.span().data() == arr);
+    assert(!spSt.span().empty());
+    assert(spSt.span().size() == 4);
+  }
 }
 
 int main(int, char**) {
+#ifndef TEST_HAS_NO_NASTY_STRING
+  test<nasty_char, nasty_char_traits>();
+#endif
   test<char>();
   test<char, constexpr_char_traits<char>>();
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
diff --git a/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.members/span.span.pass.cpp b/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.members/span.span.pass.cpp
new file mode 100644
index 0000000000000..8603e0b87c9f7
--- /dev/null
+++ b/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.members/span.span.pass.cpp
@@ -0,0 +1,116 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <spanstream>
+
+//   template<class charT, class traits = char_traits<charT>>
+//   class basic_ispanstream
+//     : public basic_istream<charT, traits> {
+
+//     // [ispanstream.members], members
+
+//     void span(std::span<charT> s) noexcept;
+
+#include <cassert>
+#include <span>
+#include <spanstream>
+
+#include "constexpr_char_traits.h"
+#include "nasty_string.h"
+#include "test_macros.h"
+
+template <typename CharT, typename TraitsT = std::char_traits<CharT>>
+void test() {
+  using SpStream = std::basic_ispanstream<CharT, TraitsT>;
+
+  CharT arr[4];
+
+  std::span<CharT> sp{arr};
+  assert(sp.data() == arr);
+  assert(!sp.empty());
+  assert(sp.size() == 4);
+
+  // Mode: default (`in` | `out`)
+  {
+    SpStream spSt{std::span<CharT>{}};
+    assert(spSt.span().data() == nullptr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+
+    spSt.span(arr);
+    assert(spSt.span().data() == arr);
+    assert(!spSt.span().empty());
+    assert(spSt.span().size() == 4);
+  }
+  // Mode: `in`
+  {
+    SpStream spSt{std::span<CharT>{}, std::ios_base::in};
+    assert(spSt.span().data() == nullptr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+
+    spSt.span(arr);
+    assert(spSt.span().data() == arr);
+    assert(!spSt.span().empty());
+    assert(spSt.span().size() == 4);
+  }
+  // Mode: `out`
+  {
+    SpStream spSt{std::span<CharT>{}, std::ios_base::out};
+    assert(spSt.span().data() == nullptr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+
+    spSt.span(arr);
+    assert(spSt.span().data() == arr);
+    // Mode `out` counts read characters
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+  }
+  // Mode: multiple
+  {
+    SpStream spSt{std::span<CharT>{}, std::ios_base::in | std::ios_base::out | std::ios_base::binary};
+    assert(spSt.span().data() == nullptr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+
+    spSt.span(arr);
+    assert(spSt.span().data() == arr);
+    // Mode `out` counts read characters
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+  }
+  // Mode: `ate`
+  {
+    SpStream spSt{std::span<CharT>{}, std::ios_base::out | std::ios_base::ate};
+    assert(spSt.span().data() == nullptr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+
+    spSt.span(arr);
+    assert(spSt.span().data() == arr);
+    assert(!spSt.span().empty());
+    assert(spSt.span().size() == 4);
+  }
+}
+
+int main(int, char**) {
+#ifndef TEST_HAS_NO_NASTY_STRING
+  test<nasty_char, nasty_char_traits>();
+#endif
+  test<char>();
+  test<char, constexpr_char_traits<char>>();
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  test<wchar_t>();
+  test<wchar_t, constexpr_char_traits<wchar_t>>();
+#endif
+
+  return 0;
+}
diff --git a/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.swap/swap.pass.cpp b/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.swap/swap.pass.cpp
new file mode 100644
index 0000000000000..d0abcb6b2b6d1
--- /dev/null
+++ b/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.swap/swap.pass.cpp
@@ -0,0 +1,155 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <spanstream>
+
+//   template<class charT, class traits = char_traits<charT>>
+//   class basic_ispanstream
+//     : public basic_istream<charT, traits> {
+
+//     // [ispanstream.swap], swap
+//     void swap(basic_ispanstream& rhs);
+
+#include <cassert>
+#include <span>
+#include <spanstream>
+
+#include "constexpr_char_traits.h"
+#include "nasty_string.h"
+#include "test_macros.h"
+
+template <typename CharT, typename TraitsT = std::char_traits<CharT>>
+void test() {
+  using SpStream = std::basic_ispanstream<CharT, TraitsT>;
+
+  CharT arr[4];
+
+  std::span<CharT> sp{arr};
+  assert(sp.data() == arr);
+  assert(!sp.empty());
+  assert(sp.size() == 4);
+
+  // Mode: default (`in` | `out`)
+  {
+    SpStream rhsSpSt{sp};
+    assert(rhsSpSt.span().data() == arr);
+    assert(!rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 4);
+
+    SpStream spSt{std::span<CharT>{}};
+    assert(spSt.span().data() == nullptr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+
+    spSt.swap(rhsSpSt);
+    assert(spSt.span().data() == arr);
+    assert(!spSt.span().empty());
+    assert(spSt.span().size() == 4);
+    assert(rhsSpSt.span().data() == nullptr);
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
+  }
+  // Mode: `in`
+  {
+    SpStream rhsSpSt{sp, std::ios_base::in};
+    assert(rhsSpSt.span().data() == arr);
+    assert(!rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 4);
+
+    SpStream spSt(std::span<CharT>{});
+    assert(spSt.span().data() == nullptr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+
+    spSt.swap(rhsSpSt);
+    assert(spSt.span().data() == arr);
+    assert(!spSt.span().empty());
+    assert(spSt.span().size() == 4);
+    assert(rhsSpSt.span().data() == nullptr);
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
+  }
+  // Mode `out`
+  {
+    SpStream rhsSpSt{sp, std::ios_base::out};
+    assert(rhsSpSt.span().data() == arr);
+    // Mode `out` counts read characters
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
+
+    SpStream spSt{std::span<CharT>{}};
+    assert(spSt.span().data() == nullptr);
+    // Mode `out` counts read characters
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+
+    spSt.swap(rhsSpSt);
+    assert(spSt.span().data() == arr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+    assert(rhsSpSt.span().data() == nullptr);
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
+  }
+  // Mode: multiple
+  {
+    SpStream rhsSpSt{sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary};
+    assert(rhsSpSt.span().data() == arr);
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
+
+    SpStream spSt{std::span<CharT>{}};
+    assert(spSt.span().data() == nullptr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+
+    spSt.swap(rhsSpSt);
+    assert(spSt.span().data() == arr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+    assert(rhsSpSt.span().data() == nullptr);
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
+  }
+  // Mode: `ate`
+  {
+    SpStream rhsSpSt{sp, std::ios_base::out | std::ios_base::ate};
+    assert(rhsSpSt.span().data() == arr);
+    assert(!rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 4);
+
+    SpStream spSt(std::span<CharT>{});
+    assert(spSt.span().data() == nullptr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+
+    spSt.swap(rhsSpSt);
+    assert(spSt.span().data() == arr);
+    assert(!spSt.span().empty());
+    assert(spSt.span().size() == 4);
+    assert(rhsSpSt.span().data() == nullptr);
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
+  }
+}
+
+int main(int, char**) {
+#ifndef TEST_HAS_NO_NASTY_STRING
+  test<nasty_char, nasty_char_traits>();
+#endif
+  test<char>();
+  test<char, constexpr_char_traits<char>>();
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  test<wchar_t>();
+  test<wchar_t, constexpr_char_traits<wchar_t>>();
+#endif
+
+  return 0;
+}
diff --git a/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.swap/swap_nonmember.pass.cpp b/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.swap/swap_nonmember.pass.cpp
new file mode 100644
index 0000000000000..9b8f32d1f08b0
--- /dev/null
+++ b/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.swap/swap_nonmember.pass.cpp
@@ -0,0 +1,153 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <spanstream>
+
+//   template<class charT, class traits>
+//     void swap(basic_ispanstream<charT, traits>& x, basic_ispanstream<charT, traits>& y);
+
+#include <cassert>
+#include <span>
+#include <spanstream>
+
+#include "constexpr_char_traits.h"
+#include "nasty_string.h"
+#include "test_macros.h"
+
+template <typename CharT, typename TraitsT = std::char_traits<CharT>>
+void test() {
+  using SpStream = std::basic_ispanstream<CharT, TraitsT>;
+
+  CharT arr[4];
+
+  std::span<CharT> sp{arr};
+  assert(sp.data() == arr);
+  assert(!sp.empty());
+  assert(sp.size() == 4);
+
+  // Mode: default (`in` | `out`)
+  {
+    SpStream rhsSpSt{sp};
+    assert(rhsSpSt.span().data() == arr);
+    assert(!rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 4);
+
+    SpStream spSt{std::span<CharT>{}};
+    assert(spSt.span().data() == nullptr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+
+    std::swap(spSt, rhsSpSt);
+    assert(spSt.span().data() == arr);
+    assert(!spSt.span().empty());
+    assert(spSt.span().size() == 4);
+    assert(rhsSpSt.span().data() == nullptr);
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
+  }
+  // Mode: `in`
+  {
+    SpStream rhsSpSt{sp, std::ios_base::in};
+    assert(rhsSpSt.span().data() == arr);
+    assert(!rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 4);
+
+    SpStream spSt(std::span<CharT>{});
+    assert(spSt.span().data() == nullptr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+
+    std::swap(spSt, rhsSpSt);
+    assert(spSt.span().data() == arr);
+    assert(!spSt.span().empty());
+    assert(spSt.span().size() == 4);
+    assert(rhsSpSt.span().data() == nullptr);
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
+  }
+  // Mode `out`
+  {
+    SpStream rhsSpSt{sp, std::ios_base::out};
+    assert(rhsSpSt.span().data() == arr);
+    // Mode `out` counts read characters
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
+
+    SpStream spSt{std::span<CharT>{}};
+    assert(spSt.span().data() == nullptr);
+    // Mode `out` counts read characters
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+
+    std::swap(spSt, rhsSpSt);
+    assert(spSt.span().data() == arr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+    assert(rhsSpSt.span().data() == nullptr);
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
+  }
+  // Mode: multiple
+  {
+    SpStream rhsSpSt{sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary};
+    assert(rhsSpSt.span().data() == arr);
+    // Mode `out` counts read characters
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
+
+    SpStream spSt{std::span<CharT>{}};
+    assert(spSt.span().data() == nullptr);
+    // Mode `out` counts read characters
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+
+    std::swap(spSt, rhsSpSt);
+    assert(spSt.span().data() == arr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+    assert(rhsSpSt.span().data() == nullptr);
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
+  }
+  // Mode: `ate`
+  {
+    SpStream rhsSpSt{sp, std::ios_base::out | std::ios_base::ate};
+    assert(rhsSpSt.span().data() == arr);
+    assert(!rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 4);
+
+    SpStream spSt(std::span<CharT>{});
+    assert(spSt.span().data() == nullptr);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
+
+    std::swap(spSt, rhsSpSt);
+    assert(spSt.span().data() == arr);
+    assert(!spSt.span().empty());
+    assert(spSt.span().size() == 4);
+    assert(rhsSpSt.span().data() == nullptr);
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
+  }
+}
+
+int main(int, char**) {
+#ifndef TEST_HAS_NO_NASTY_STRING
+  test<nasty_char, nasty_char_traits>();
+#endif
+  test<char>();
+  test<char, constexpr_char_traits<char>>();
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  test<wchar_t>();
+  test<wchar_t, constexpr_char_traits<wchar_t>>();
+#endif
+
+  return 0;
+}
diff --git a/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.cons/assign.move.pass.cpp b/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.cons/assign.move.pass.cpp
index 8dd4eab2c86f5..2b9c3a38dea85 100644
--- a/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.cons/assign.move.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.cons/assign.move.pass.cpp
@@ -31,7 +31,11 @@ void test() {
   using SpStream = std::basic_ospanstream<CharT, TraitsT>;
 
   CharT arr[4];
+
   std::span<CharT> sp{arr};
+  assert(sp.data() == arr);
+  assert(!sp.empty());
+  assert(sp.size() == 4);
 
   // Mode: default (`in` | `out`)
   {
diff --git a/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.cons/ctor.move.pass.cpp b/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.cons/ctor.move.pass.cpp
index cdd625529264e..3c543397e4523 100644
--- a/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.cons/ctor.move.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.cons/ctor.move.pass.cpp
@@ -31,7 +31,11 @@ void test() {
   using SpStream = std::basic_ospanstream<CharT, TraitsT>;
 
   CharT arr[4];
+
   std::span<CharT> sp{arr};
+  assert(sp.data() == arr);
+  assert(!sp.empty());
+  assert(sp.size() == 4);
 
   // Mode: default (`in` | `out`)
   {
@@ -87,6 +91,10 @@ void test() {
   // Mode: multiple
   {
     SpStream rhsSpSt{sp, std::ios_base::in | std::ios_base::out | std::ios_base::binary};
+    assert(rhsSpSt.span().data() == arr);
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
+
     SpStream spSt{std::move(rhsSpSt)};
     assert(spSt.span().data() == arr);
     assert(spSt.span().empty());
diff --git a/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.cons/ctor.span.mode.pass.cpp b/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.cons/ctor.span.mode.pass.cpp
index 6d369945f8537..bc70fb4a440a7 100644
--- a/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.cons/ctor.span.mode.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.cons/ctor.span.mode.pass.cpp
@@ -19,6 +19,7 @@
 //                                ios_base::openmode which = ios_base::out | ios_base::in);
 
 #include <cassert>
+#include <concepts>
 #include <span>
 #include <spanstream>
 #include <utility>
@@ -48,7 +49,11 @@ void test() {
   using SpStream = std::basic_ospanstream<CharT, TraitsT>;
 
   CharT arr[4];
+
   std::span<CharT> sp{arr};
+  assert(sp.data() == arr);
+  assert(!sp.empty());
+  assert(sp.size() == 4);
 
   // Mode: default (`in` | `out`)
   {
diff --git a/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.members/span.span.pass.cpp b/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.members/span.span.pass.cpp
index 45411696e0d68..fab565d97a286 100644
--- a/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.members/span.span.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.members/span.span.pass.cpp
@@ -11,8 +11,8 @@
 // <spanstream>
 
 //   template<class charT, class traits = char_traits<charT>>
-//   class basic_spanstream
-//     : public basic_iostream<charT, traits> {
+//   class basic_ospanstream
+//     : public basic_ostream<charT, traits> {
 
 //     // [spanstream.members], members
 
@@ -28,7 +28,7 @@
 
 template <typename CharT, typename TraitsT = std::char_traits<CharT>>
 void test() {
-  using SpStream = std::basic_spanbuf<CharT, TraitsT>;
+  using SpStream = std::basic_ospanstream<CharT, TraitsT>;
 
   CharT arr[4];
 
@@ -39,7 +39,7 @@ void test() {
 
   // Mode: default (`in` | `out`)
   {
-    SpStream spSt;
+    SpStream spSt{std::span<CharT>{}};
     assert(spSt.span().data() == nullptr);
     assert(spSt.span().empty());
     assert(spSt.span().size() == 0);
@@ -52,19 +52,19 @@ void test() {
   }
   // Mode: `in`
   {
-    SpStream spSt{std::ios_base::in};
+    SpStream spSt{std::span<CharT>{}, std::ios_base::in};
     assert(spSt.span().data() == nullptr);
     assert(spSt.span().empty());
     assert(spSt.span().size() == 0);
 
     spSt.span(arr);
     assert(spSt.span().data() == arr);
-    assert(!spSt.span().empty());
-    assert(spSt.span().size() == 4);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
   }
   // Mode: `out`
   {
-    SpStream spSt{std::ios_base::out};
+    SpStream spSt{std::span<CharT>{}, std::ios_base::out};
     assert(spSt.span().data() == nullptr);
     assert(spSt.span().empty());
     assert(spSt.span().size() == 0);
@@ -77,7 +77,7 @@ void test() {
   }
   // Mode: multiple
   {
-    SpStream spSt{std::ios_base::in | std::ios_base::out | std::ios_base::binary};
+    SpStream spSt{std::span<CharT>{}, std::ios_base::in | std::ios_base::out | std::ios_base::binary};
     assert(spSt.span().data() == nullptr);
     assert(spSt.span().empty());
     assert(spSt.span().size() == 0);
@@ -90,7 +90,7 @@ void test() {
   }
   // Mode: `ate`
   {
-    SpStream spSt{std::ios_base::out | std::ios_base::ate};
+    SpStream spSt{std::span<CharT>{}, std::ios_base::out | std::ios_base::ate};
     assert(spSt.span().data() == nullptr);
     assert(spSt.span().empty());
     assert(spSt.span().size() == 0);
diff --git a/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.swap/swap.pass.cpp b/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.swap/swap.pass.cpp
index e6a7d2d457e20..9521118f27e3e 100644
--- a/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.swap/swap.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/ospanstream/ospanstream.swap/swap.pass.cpp
@@ -14,7 +14,7 @@
 //   class basic_ospanstream
 //     : public basic_ostream<charT, traits> {
 
-//    // [spanstream.swap], swap
+//    // [ospanstream.swap], swap
 //    void swap(basic_ospanstream& rhs);
 
 #include <cassert>
diff --git a/libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/assign.move.pass.cpp b/libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/assign.move.pass.cpp
index ac807b405b18a..2a1229445ac7e 100644
--- a/libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/assign.move.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/assign.move.pass.cpp
@@ -28,27 +28,31 @@
 
 template <typename CharT, typename TraitsT = std::char_traits<CharT>>
 void test() {
-  using SpStream = std::basic_ispanstream<CharT, TraitsT>;
+  using SpStream = std::basic_spanstream<CharT, TraitsT>;
 
   CharT arr[4];
+
   std::span<CharT> sp{arr};
+  assert(sp.data() == arr);
+  assert(!sp.empty());
+  assert(sp.size() == 4);
 
   // Mode: default (`in` | `out`)
   {
     SpStream rhsSpSt{sp};
     assert(rhsSpSt.span().data() == arr);
-    assert(!rhsSpSt.span().empty());
-    assert(rhsSpSt.span().size() == 4);
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
 
     SpStream spSt = std::move(rhsSpSt);
     assert(spSt.span().data() == arr);
-    assert(!spSt.span().empty());
-    assert(spSt.span().size() == 4);
+    assert(spSt.span().empty());
+    assert(spSt.span().size() == 0);
 
     // After move
     assert(rhsSpSt.span().data() == arr);
-    assert(!rhsSpSt.span().empty());
-    assert(rhsSpSt.span().size() == 4);
+    assert(rhsSpSt.span().empty());
+    assert(rhsSpSt.span().size() == 0);
   }
   // Mode: `in`
   {
diff --git a/libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/ctor.move.pass.cpp b/libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/ctor.move.pass.cpp
index 87ef4c06a8ff8..b70e6bf4c6b9c 100644
--- a/libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/ctor.move.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/ctor.move.pass.cpp
@@ -31,7 +31,11 @@ void test() {
   using SpStream = std::basic_spanstream<CharT, TraitsT>;
 
   CharT arr[4];
+
   std::span<CharT> sp{arr};
+  assert(sp.data() == arr);
+  assert(!sp.empty());
+  assert(sp.size() == 4);
 
   // Mode: default (`in` | `out`)
   {
diff --git a/libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/ctor.span.mode.pass.cpp b/libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/ctor.span.mode.pass.cpp
index 2a320bf9cca26..f0cab5c464617 100644
--- a/libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/ctor.span.mode.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/ctor.span.mode.pass.cpp
@@ -32,7 +32,7 @@
 
 template <typename CharT, typename TraitsT = std::char_traits<CharT>>
 void test_sfinae() {
-  using SpStream = std::basic_ispanstream<CharT, TraitsT>;
+  using SpStream = std::basic_spanstream<CharT, TraitsT>;
 
   // Mode
   static_assert(std::constructible_from<SpStream, const std::span<CharT>, std::ios_base::openmode>);
@@ -48,7 +48,11 @@ void test() {
   using SpStream = std::basic_spanstream<CharT, TraitsT>;
 
   CharT arr[4];
+  
   std::span<CharT> sp{arr};
+  assert(sp.data() == arr);
+  assert(!sp.empty());
+  assert(sp.size() == 4);
 
   // Mode: default (`in` | `out`)
   {
diff --git a/libcxx/test/std/input.output/span.streams/spanstream/spanstream.members/span.span.pass.cpp b/libcxx/test/std/input.output/span.streams/spanstream/spanstream.members/span.span.pass.cpp
index 45411696e0d68..77ac8dbfaa2e4 100644
--- a/libcxx/test/std/input.output/span.streams/spanstream/spanstream.members/span.span.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanstream/spanstream.members/span.span.pass.cpp
@@ -28,7 +28,7 @@
 
 template <typename CharT, typename TraitsT = std::char_traits<CharT>>
 void test() {
-  using SpStream = std::basic_spanbuf<CharT, TraitsT>;
+  using SpStream = std::basic_spanstream<CharT, TraitsT>;
 
   CharT arr[4];
 
@@ -39,7 +39,7 @@ void test() {
 
   // Mode: default (`in` | `out`)
   {
-    SpStream spSt;
+    SpStream spSt{std::span<CharT>{}};
     assert(spSt.span().data() == nullptr);
     assert(spSt.span().empty());
     assert(spSt.span().size() == 0);
@@ -52,7 +52,7 @@ void test() {
   }
   // Mode: `in`
   {
-    SpStream spSt{std::ios_base::in};
+    SpStream spSt{std::span<CharT>{}, std::ios_base::in};
     assert(spSt.span().data() == nullptr);
     assert(spSt.span().empty());
     assert(spSt.span().size() == 0);
@@ -64,7 +64,7 @@ void test() {
   }
   // Mode: `out`
   {
-    SpStream spSt{std::ios_base::out};
+    SpStream spSt{std::span<CharT>{}, std::ios_base::out};
     assert(spSt.span().data() == nullptr);
     assert(spSt.span().empty());
     assert(spSt.span().size() == 0);
@@ -77,7 +77,7 @@ void test() {
   }
   // Mode: multiple
   {
-    SpStream spSt{std::ios_base::in | std::ios_base::out | std::ios_base::binary};
+    SpStream spSt{std::span<CharT>{}, std::ios_base::in | std::ios_base::out | std::ios_base::binary};
     assert(spSt.span().data() == nullptr);
     assert(spSt.span().empty());
     assert(spSt.span().size() == 0);
@@ -90,7 +90,7 @@ void test() {
   }
   // Mode: `ate`
   {
-    SpStream spSt{std::ios_base::out | std::ios_base::ate};
+    SpStream spSt{std::span<CharT>{}, std::ios_base::out | std::ios_base::ate};
     assert(spSt.span().data() == nullptr);
     assert(spSt.span().empty());
     assert(spSt.span().size() == 0);

>From a9b08fe969f401a1832c856dbb3b4eb537f78f95 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Fri, 15 Mar 2024 20:59:03 +0200
Subject: [PATCH 51/56] Tests: fixed CI

---
 .../span.streams/ispanstream/ispanstream.cons/ctor.ros.pass.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/ctor.ros.pass.cpp b/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/ctor.ros.pass.cpp
index 5cec1de19ffb1..005e4a60f3d09 100644
--- a/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/ctor.ros.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/ispanstream/ispanstream.cons/ctor.ros.pass.cpp
@@ -56,7 +56,7 @@ void test() {
 
   // TODO:
   CharT arr[4];
-  
+
   ReadOnlySpan<CharT, 4> ros{arr};
 
   {

>From 08e016b9d42085ded00c10580bbfeadcc8dad4e8 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Fri, 15 Mar 2024 21:07:56 +0200
Subject: [PATCH 52/56] Tests: fixed CI

---
 .../spanstream/spanstream.cons/ctor.span.mode.pass.cpp          | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/ctor.span.mode.pass.cpp b/libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/ctor.span.mode.pass.cpp
index f0cab5c464617..3276a2a25dadc 100644
--- a/libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/ctor.span.mode.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanstream/spanstream.cons/ctor.span.mode.pass.cpp
@@ -48,7 +48,7 @@ void test() {
   using SpStream = std::basic_spanstream<CharT, TraitsT>;
 
   CharT arr[4];
-  
+
   std::span<CharT> sp{arr};
   assert(sp.data() == arr);
   assert(!sp.empty());

>From 68605d468394e1ddcd7d5970d8f5ca925a7f0d03 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Fri, 15 Mar 2024 23:15:44 +0200
Subject: [PATCH 53/56] Tests: updated `inherited.stream.ops.pass.cpp`

---
 libcxx/include/spanstream                     |  2 +-
 .../spanstream/inherited.stream.ops.pass.cpp  | 29 +++++++++++++++++--
 2 files changed, 28 insertions(+), 3 deletions(-)

diff --git a/libcxx/include/spanstream b/libcxx/include/spanstream
index 2b4b6b79d86fd..cac38447125d2 100644
--- a/libcxx/include/spanstream
+++ b/libcxx/include/spanstream
@@ -418,7 +418,7 @@ public:
 
   // [spanstream.swap], swap
 
-  void swap(basic_spanstream& __rhs) {
+  _LIBCPP_HIDE_FROM_ABI void swap(basic_spanstream& __rhs) {
     basic_iostream<_CharT, _Traits>::swap(__rhs);
     __sb_.swap(__rhs.__sb_);
   }
diff --git a/libcxx/test/std/input.output/span.streams/spanstream/inherited.stream.ops.pass.cpp b/libcxx/test/std/input.output/span.streams/spanstream/inherited.stream.ops.pass.cpp
index a03ff9d257d63..8e529c63cf6de 100644
--- a/libcxx/test/std/input.output/span.streams/spanstream/inherited.stream.ops.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanstream/inherited.stream.ops.pass.cpp
@@ -38,14 +38,22 @@ template <typename CharT, typename TraitsT = std::char_traits<CharT>>
 void test() {
   using SpStream = std::basic_spanstream<CharT, TraitsT>;
 
+  constexpr auto arrSize{30UZ};
+
   constexpr std::basic_string_view<CharT, TraitsT> sv{SV("zmt 94 hkt 82 pir 43vr")};
-  CharT arr[sv.size() + 1];
+  assert(sv.size() < arrSize);
+
+  CharT arr[arrSize]{};
   initialize_array(arr, sv);
+
   std::span<CharT> sp{arr};
 
   // Mode: default (`in` | `out`)
   {
     SpStream spSt(sp);
+    assert(spSt.span().size() == 0);
+
+    // Read from stream
     std::basic_string<CharT, TraitsT> str1;
     spSt >> str1;
     int i1;
@@ -66,7 +74,12 @@ void test() {
     assert(str3 == CS("pir"));
     assert(i3 == 43);
 
-    spSt << CS("year 2024");
+    // Write to stream
+    constexpr std::basic_string_view<CharT, TraitsT> sv1{SV("year 2024")};
+    spSt << sv1;
+    assert(spSt.span().size() == sv1.size());
+
+    // Read from stream
     spSt.seekg(0);
     std::basic_string<CharT, TraitsT> str4;
     spSt >> str4;
@@ -75,6 +88,18 @@ void test() {
 
     assert(str4 == CS("year"));
     assert(i4 == 2024);
+
+    // Write to stream
+    spSt << CS("94");
+    spSt << 84;
+    std::cout << spSt.span().size() << std::endl;
+    assert(spSt.span().size() == sv1.size() + 4);
+
+    // Write to stream with overflow
+    constexpr std::basic_string_view<CharT, TraitsT> sv2{
+        SV("This string should overflow! This string should overflow!")};
+    spSt << sv2;
+    assert(spSt.span().size() == arrSize);
   }
   // Mode: `in`
   {

>From 771c9cac4f93c7fc775fd33b16f94c3414ff42f4 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Sat, 16 Mar 2024 12:48:53 +0200
Subject: [PATCH 54/56] Tests: updated `inherited.stream.ops.pass.cpp`

---
 .../spanstream/inherited.stream.ops.pass.cpp     | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/libcxx/test/std/input.output/span.streams/spanstream/inherited.stream.ops.pass.cpp b/libcxx/test/std/input.output/span.streams/spanstream/inherited.stream.ops.pass.cpp
index 8e529c63cf6de..2cc754fbd3f6e 100644
--- a/libcxx/test/std/input.output/span.streams/spanstream/inherited.stream.ops.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanstream/inherited.stream.ops.pass.cpp
@@ -67,6 +67,7 @@ void test() {
     int i3;
     spSt >> i3;
 
+    assert(spSt.good());
     assert(str1 == CS("zmt"));
     assert(i1 == 94);
     assert(str2 == CS("hkt"));
@@ -77,7 +78,9 @@ void test() {
     // Write to stream
     constexpr std::basic_string_view<CharT, TraitsT> sv1{SV("year 2024")};
     spSt << sv1;
+
     assert(spSt.span().size() == sv1.size());
+    assert(spSt.good());
 
     // Read from stream
     spSt.seekg(0);
@@ -89,17 +92,28 @@ void test() {
     assert(str4 == CS("year"));
     assert(i4 == 2024);
 
+    spSt >> i4;
+    assert(spSt.fail());
+    spSt.clear();
+    assert(spSt.good());
+
     // Write to stream
     spSt << CS("94");
     spSt << 84;
-    std::cout << spSt.span().size() << std::endl;
+
+    assert(spSt.good());
     assert(spSt.span().size() == sv1.size() + 4);
+    std::basic_string<CharT, TraitsT> expectedStr1{spSt.span().data(), std::size_t{spSt.span().size()}};
+    assert(expectedStr1 == CS("year 20249484"));
 
     // Write to stream with overflow
     constexpr std::basic_string_view<CharT, TraitsT> sv2{
         SV("This string should overflow! This string should overflow!")};
     spSt << sv2;
     assert(spSt.span().size() == arrSize);
+    std::basic_string<CharT, TraitsT> expectedStr2{spSt.span().data(), std::size_t{spSt.span().size()}};
+    assert(expectedStr2 == CS("year 20249484This string shoul"));
+    assert(spSt.fail());
   }
   // Mode: `in`
   {

>From 37e3bcdb6fc1f86aaf6e3187be1b0bc7b7410677 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Sun, 17 Mar 2024 14:09:21 +0200
Subject: [PATCH 55/56] Tests: `stream.ops.pass.cpp`

---
 .../spanstream/inherited.stream.ops.pass.cpp  | 181 +++++++++++++++++-
 1 file changed, 175 insertions(+), 6 deletions(-)

diff --git a/libcxx/test/std/input.output/span.streams/spanstream/inherited.stream.ops.pass.cpp b/libcxx/test/std/input.output/span.streams/spanstream/inherited.stream.ops.pass.cpp
index 2cc754fbd3f6e..0744e7e4e47e9 100644
--- a/libcxx/test/std/input.output/span.streams/spanstream/inherited.stream.ops.pass.cpp
+++ b/libcxx/test/std/input.output/span.streams/spanstream/inherited.stream.ops.pass.cpp
@@ -51,6 +51,11 @@ void test() {
   // Mode: default (`in` | `out`)
   {
     SpStream spSt(sp);
+
+    assert(spSt);
+    assert(!spSt.bad());
+    assert(!spSt.fail());
+    assert(spSt.good());
     assert(spSt.span().size() == 0);
 
     // Read from stream
@@ -67,7 +72,6 @@ void test() {
     int i3;
     spSt >> i3;
 
-    assert(spSt.good());
     assert(str1 == CS("zmt"));
     assert(i1 == 94);
     assert(str2 == CS("hkt"));
@@ -75,11 +79,19 @@ void test() {
     assert(str3 == CS("pir"));
     assert(i3 == 43);
 
+    assert(spSt);
+    assert(!spSt.bad());
+    assert(!spSt.fail());
+    assert(spSt.good());
+
     // Write to stream
     constexpr std::basic_string_view<CharT, TraitsT> sv1{SV("year 2024")};
     spSt << sv1;
 
     assert(spSt.span().size() == sv1.size());
+    assert(spSt);
+    assert(!spSt.bad());
+    assert(!spSt.fail());
     assert(spSt.good());
 
     // Read from stream
@@ -93,15 +105,28 @@ void test() {
     assert(i4 == 2024);
 
     spSt >> i4;
+
+    assert(!spSt);
+    assert(!spSt.bad());
     assert(spSt.fail());
+    assert(!spSt.good());
+
     spSt.clear();
+
+    assert(spSt);
+    assert(!spSt.bad());
+    assert(!spSt.fail());
     assert(spSt.good());
 
     // Write to stream
     spSt << CS("94");
     spSt << 84;
 
+    assert(spSt);
+    assert(!spSt.bad());
+    assert(!spSt.fail());
     assert(spSt.good());
+
     assert(spSt.span().size() == sv1.size() + 4);
     std::basic_string<CharT, TraitsT> expectedStr1{spSt.span().data(), std::size_t{spSt.span().size()}};
     assert(expectedStr1 == CS("year 20249484"));
@@ -113,20 +138,164 @@ void test() {
     assert(spSt.span().size() == arrSize);
     std::basic_string<CharT, TraitsT> expectedStr2{spSt.span().data(), std::size_t{spSt.span().size()}};
     assert(expectedStr2 == CS("year 20249484This string shoul"));
+
+    assert(!spSt);
+    assert(spSt.bad());
     assert(spSt.fail());
+    assert(!spSt.good());
   }
+#if 0
   // Mode: `in`
   {
     SpStream spSt{sp, std::ios_base::in};
-    //TODO
-    (void)spSt;
-  }
+    assert(spSt);
+    assert(spSt.good());
+    assert(spSt.span().size() == arrSize);
+
+     std::basic_string<CharT, TraitsT> expectedStr0{spSt.span().data(), std::size_t{spSt.span().size()}};
+     std::cout << expectedStr0 << std::endl;
+
+    // // Read from stream
+    // std::basic_string<CharT, TraitsT> str1;
+    // spSt >> str1;
+    // int i1;
+    // spSt >> i1;
+    // std::basic_string<CharT, TraitsT> str2;
+    // spSt >> str2;
+    // int i2;
+    // spSt >> i2;
+    // std::basic_string<CharT, TraitsT> str3;
+    // spSt >> str3;
+    // int i3;
+    // spSt >> i3;
+
+    // assert(spSt.good());
+    // assert(str1 == CS("zmt"));
+    // assert(i1 == 94);
+    // assert(str2 == CS("hkt"));
+    // assert(i2 == 82);
+    // assert(str3 == CS("pir"));
+    // assert(i3 == 43);
+
+    // Write to stream
+    constexpr std::basic_string_view<CharT, TraitsT> sv1{SV("year 2024")};
+    spSt << sv1;
+
+    std::cout << spSt.span().size() << std::endl;
+    assert(spSt.span().size() == sv1.size());
+    assert(spSt.good());
+
+    // Read from stream
+    spSt.seekg(0);
+    std::basic_string<CharT, TraitsT> str4;
+    spSt >> str4;
+    int i4;
+    spSt >> i4;
+
+    assert(str4 == CS("year"));
+    assert(i4 == 2024);
+
+    spSt >> i4;
+    assert(spSt);
+    assert(!spSt.bad());
+    assert(spSt.fail());
+    assert(!spSt.good());
+
+     spSt.clear();
+    assert(spSt);
+    assert(!spSt.bad());
+    assert(!spSt.fail());
+    assert(spSt.good());
+    // Write to stream
+    spSt << CS("94");
+    spSt << 84;
+
+    assert(spSt);
+    assert(!spSt.bad());
+    assert(!spSt.fail());
+    assert(spSt.good());    assert(spSt.span().size() == sv1.size() + 4);
+    std::basic_string<CharT, TraitsT> expectedStr1{spSt.span().data(), std::size_t{spSt.span().size()}};
+    assert(expectedStr1 == CS("year 20249484"));
+
+    // Write to stream with overflow
+    constexpr std::basic_string_view<CharT, TraitsT> sv2{
+        SV("This string should overflow! This string should overflow!")};
+    spSt << sv2;
+    assert(spSt.span().size() == arrSize);
+    std::basic_string<CharT, TraitsT> expectedStr2{spSt.span().data(), std::size_t{spSt.span().size()}};
+    assert(expectedStr2 == CS("year 20249484This string shoul"));
+    assert(spSt);
+    assert(!spSt.bad());
+    assert(spSt.fail());
+    assert(!spSt.good());  }
   // Mode `out`
   {
     SpStream spSt{sp, std::ios_base::out};
-    //TODO
-    (void)spSt;
+    assert(spSt.span().size() == 0);
+
+    // Read from stream
+    std::basic_string<CharT, TraitsT> str1;
+    spSt >> str1;
+    int i1;
+    spSt >> i1;
+    std::basic_string<CharT, TraitsT> str2;
+    spSt >> str2;
+    int i2;
+    spSt >> i2;
+    std::basic_string<CharT, TraitsT> str3;
+    spSt >> str3;
+    int i3;
+    spSt >> i3;
+
+    assert(spSt.good());
+    assert(str1 == CS("zmt"));
+    assert(i1 == 94);
+    assert(str2 == CS("hkt"));
+    assert(i2 == 82);
+    assert(str3 == CS("pir"));
+    assert(i3 == 43);
+
+    // Write to stream
+    constexpr std::basic_string_view<CharT, TraitsT> sv1{SV("year 2024")};
+    spSt << sv1;
+
+    assert(spSt.span().size() == sv1.size());
+    assert(spSt.good());
+
+    // Read from stream
+    spSt.seekg(0);
+    std::basic_string<CharT, TraitsT> str4;
+    spSt >> str4;
+    int i4;
+    spSt >> i4;
+
+    assert(str4 == CS("year"));
+    assert(i4 == 2024);
+
+    spSt >> i4;
+    assert(spSt.fail());
+    spSt.clear();
+    assert(spSt.good());
+
+    // Write to stream
+    spSt << CS("94");
+    spSt << 84;
+
+    assert(spSt.good());
+    assert(spSt.span().size() == sv1.size() + 4);
+    std::basic_string<CharT, TraitsT> expectedStr1{spSt.span().data(), std::size_t{spSt.span().size()}};
+    assert(expectedStr1 == CS("year 20249484"));
+
+    // Write to stream with overflow
+    constexpr std::basic_string_view<CharT, TraitsT> sv2{
+        SV("This string should overflow! This string should overflow!")};
+    spSt << sv2;
+    assert(spSt.span().size() == arrSize);
+    std::basic_string<CharT, TraitsT> expectedStr2{spSt.span().data(), std::size_t{spSt.span().size()}};
+    assert(expectedStr2 == CS("year 20249484This string shoul"));
+    assert(spSt.fail());
   }
+#endif
 }
 
 int main(int, char**) {

>From 3dc0b733a308745bd249eaae1a2b63738fa6a874 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Fri, 19 Jul 2024 19:15:42 +0300
Subject: [PATCH 56/56] Updated Release Notes

---
 libcxx/docs/FeatureTestMacroTable.rst | 2 +-
 libcxx/docs/ReleaseNotes/19.rst       | 1 -
 libcxx/docs/ReleaseNotes/20.rst       | 2 +-
 libcxx/docs/Status/Cxx23Papers.csv    | 2 +-
 4 files changed, 3 insertions(+), 4 deletions(-)

diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst
index b548322b1b2b8..360693ea3d73c 100644
--- a/libcxx/docs/FeatureTestMacroTable.rst
+++ b/libcxx/docs/FeatureTestMacroTable.rst
@@ -376,7 +376,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 d797f9194ccbc..ac7d61b6ba856 100644
--- a/libcxx/docs/ReleaseNotes/19.rst
+++ b/libcxx/docs/ReleaseNotes/19.rst
@@ -50,7 +50,6 @@ Implemented Papers
 - P2591R5 - Concatenation of strings and string views
 - P2968R2 - Make ``std::ignore`` a first-class object
 - P2997R1 - Removing the common reference requirement from the indirectly invocable concepts (as DR against C++20)
-- P0448R4 - A ``strstream`` replacement using ``span<charT>`` as buffer
 - P2302R4 - ``std::ranges::contains``
 - P1659R3 - ``std::ranges::starts_with`` and ``std::ranges::ends_with``
 - P3029R1 - Better ``mdspan``'s CTAD
diff --git a/libcxx/docs/ReleaseNotes/20.rst b/libcxx/docs/ReleaseNotes/20.rst
index fb677b1667ddc..9f8c3943bd85b 100644
--- a/libcxx/docs/ReleaseNotes/20.rst
+++ b/libcxx/docs/ReleaseNotes/20.rst
@@ -38,7 +38,7 @@ What's New in Libc++ 20.0.0?
 Implemented Papers
 ------------------
 
-- TODO
+- 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 217787d65ced3..f7f510d11e711 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","|Partial|","19.0"
+"`P0448R4 <https://wg21.link/P0448R4>`__","LWG","A ``strstream`` replacement using ``span<charT>`` as buffer","June 2021","|Partial|","20.0"
 "`P1132R8 <https://wg21.link/P1132R8>`__","LWG","out_ptr - a scalable output pointer abstraction","June 2021","|Complete|","19.0"
 "`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|"



More information about the libcxx-commits mailing list