* [committed] libstdc++: Implement std::spanstream for C++23
@ 2021-11-13 11:46 Jonathan Wakely
0 siblings, 0 replies; only message in thread
From: Jonathan Wakely @ 2021-11-13 11:46 UTC (permalink / raw)
To: libstdc++, gcc-patches
The tests are just the two small examples from the proposal, so more
tests are definitely needed. They can wait for stage 3 though. Tested
powerpc64le-linux, pushed to trunk.
This implements the <spanstream> header, as proposed for C++23 by P0448R4.
libstdc++-v3/ChangeLog:
* include/Makefile.am: Add spanstream header.
* include/Makefile.in: Regenerate.
* include/precompiled/stdc++.h: Add spanstream header.
* include/std/version (__cpp_lib_spanstream): Define.
* include/std/spanstream: New file.
* testsuite/27_io/spanstream/1.cc: New test.
* testsuite/27_io/spanstream/version.cc: New test.
---
libstdc++-v3/include/Makefile.am | 1 +
libstdc++-v3/include/Makefile.in | 1 +
libstdc++-v3/include/precompiled/stdc++.h | 6 +-
libstdc++-v3/include/std/spanstream | 446 ++++++++++++++++++
libstdc++-v3/include/std/version | 3 +
libstdc++-v3/testsuite/27_io/spanstream/1.cc | 53 +++
.../testsuite/27_io/spanstream/version.cc | 10 +
7 files changed, 519 insertions(+), 1 deletion(-)
create mode 100644 libstdc++-v3/include/std/spanstream
create mode 100644 libstdc++-v3/testsuite/27_io/spanstream/1.cc
create mode 100644 libstdc++-v3/testsuite/27_io/spanstream/version.cc
diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am
index 0e43f147591..25a8d9c8a41 100644
--- a/libstdc++-v3/include/Makefile.am
+++ b/libstdc++-v3/include/Makefile.am
@@ -76,6 +76,7 @@ std_headers = \
${std_srcdir}/shared_mutex \
${std_srcdir}/source_location \
${std_srcdir}/span \
+ ${std_srcdir}/spanstream \
${std_srcdir}/sstream \
${std_srcdir}/syncstream \
${std_srcdir}/stack \
diff --git a/libstdc++-v3/include/precompiled/stdc++.h b/libstdc++-v3/include/precompiled/stdc++.h
index d2601d7859d..e1c10e612e8 100644
--- a/libstdc++-v3/include/precompiled/stdc++.h
+++ b/libstdc++-v3/include/precompiled/stdc++.h
@@ -133,7 +133,7 @@
#include <variant>
#endif
-#if __cplusplus > 201703L
+#if __cplusplus >= 202002L
#include <barrier>
#include <bit>
#include <compare>
@@ -151,3 +151,7 @@
#include <syncstream>
#include <version>
#endif
+
+#if __cplusplus > 202002L
+#include <spanstream>
+#endif
diff --git a/libstdc++-v3/include/std/spanstream b/libstdc++-v3/include/std/spanstream
new file mode 100644
index 00000000000..240866ff26f
--- /dev/null
+++ b/libstdc++-v3/include/std/spanstream
@@ -0,0 +1,446 @@
+// Streams based on std::span -*- C++ -*-
+
+// Copyright The GNU Toolchain Authors.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file spanstream
+ * This is a Standard C++ Library header.
+ */
+
+#ifndef _GLIBCXX_SPANSTREAM
+#define _GLIBCXX_SPANSTREAM 1
+
+#pragma GCC system_header
+
+#if __cplusplus > 202002L
+#include <span>
+#include <streambuf>
+#include <istream>
+#include <ostream>
+#include <bits/ranges_base.h>
+
+#if __cpp_lib_span
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+#define __cpp_lib_spanstream 202106L
+
+template<typename _CharT, typename _Traits = char_traits<_CharT>>
+ class basic_spanbuf
+ : public basic_streambuf<_CharT, _Traits>
+ {
+ using __streambuf_type = 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.ctor], constructors
+ basic_spanbuf() : basic_spanbuf(ios_base::in | ios_base::out)
+ { }
+
+ explicit
+ basic_spanbuf(ios_base::openmode __which)
+ : __streambuf_type(), _M_mode(__which)
+ { }
+
+ explicit
+ basic_spanbuf(std::span<_CharT> __s,
+ ios_base::openmode __which = ios_base::in | ios_base::out)
+ : __streambuf_type(), _M_mode(__which)
+ { span(__s); }
+
+ basic_spanbuf(const basic_spanbuf&) = delete;
+
+ /// Move constructor. In this implementation `rhs` is left unchanged.
+ basic_spanbuf(basic_spanbuf&& __rhs)
+ : __streambuf_type(__rhs), _M_mode(__rhs._M_mode)
+ { span(__rhs._M_buf); }
+
+ // [spanbuf.assign], assignment and swap
+ basic_spanbuf& operator=(const basic_spanbuf&) = delete;
+
+ basic_spanbuf&
+ operator=(basic_spanbuf&& __rhs)
+ {
+ basic_spanbuf(std::move(__rhs))->swap(*this);
+ return *this;
+ }
+
+ void
+ swap(basic_spanbuf& __rhs)
+ {
+ __streambuf_type::swap(__rhs);
+ std::swap(_M_mode, __rhs._M_mode);
+ std::swap(_M_buf, __rhs._M_buf);
+ }
+
+ // [spanbuf.members], member functions
+ std::span<_CharT>
+ span() const noexcept
+ {
+ if (_M_mode & ios_base::out)
+ return {this->pbase(), this->pptr()};
+ else
+ return _M_buf;
+ }
+
+ void
+ span(std::span<_CharT> __s) noexcept
+ {
+ _M_buf = __s;
+ if (_M_mode & ios_base::out)
+ {
+ this->setp(__s.data(), __s.data() + __s.size());
+ if (_M_mode & ios_base::ate)
+ this->pbump(__s.size());
+ }
+ if (_M_mode & ios_base::in)
+ this->setg(__s.data(), __s.data(), __s.data() + __s.size());
+ }
+
+ protected:
+ // [spanbuf.virtuals], overridden virtual functions
+ basic_streambuf<_CharT, _Traits>*
+ setbuf(_CharT* __s, streamsize __n) override
+ {
+ span({__s, __n});
+ return this;
+ }
+
+ pos_type
+ seekoff(off_type __off, ios_base::seekdir __way,
+ ios_base::openmode __which = ios_base::in | ios_base::out) override
+ {
+ pos_type __ret = pos_type(off_type(-1));
+
+ if (__way == ios_base::beg)
+ {
+ if (0 <= __off && __off <= _M_buf.size())
+ {
+ if (__which & ios_base::in)
+ this->setg(this->eback(), this->eback() + __off, this->egptr());
+
+ if (__which & ios_base::out)
+ {
+ this->setp(this->pbase(), this->epptr());
+ this->pbump(__off);
+ }
+
+ __ret = pos_type(__off);
+ }
+ }
+ else
+ {
+ off_type __base;
+ __which &= (ios_base::in|ios_base::out);
+
+ if (__which == ios_base::out)
+ __base = this->pptr() - this->pbase();
+ else if (__way == ios_base::cur)
+ {
+ if (__which == ios_base::in)
+ __base = this->gptr() - this->eback();
+ else
+ return __ret;
+ }
+ else if (__way == ios_base::end)
+ __base = _M_buf.size();
+
+ if (__builtin_add_overflow(__base, __off, &__off))
+ return __ret;
+
+ if (__off < 0 || __off > _M_buf.size())
+ return __ret;
+
+ if (__which & ios_base::in)
+ this->setg(this->eback(), this->eback() + __off, this->egptr());
+
+ if (__which & ios_base::out)
+ {
+ this->setp(this->pbase(), this->epptr());
+ this->pbump(__off);
+ }
+
+ __ret = pos_type(__off);
+
+ }
+ return __ret;
+ }
+
+ 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 _M_mode;
+ std::span<_CharT> _M_buf;
+ };
+
+template<typename _CharT, typename _Traits>
+ inline void
+ swap(basic_spanbuf<_CharT, _Traits>& __x,
+ basic_spanbuf<_CharT, _Traits>& __y)
+ { __x.swap(__y); }
+
+using spanbuf = basic_spanbuf<char>;
+using wspanbuf = basic_spanbuf<wchar_t>;
+
+template<typename _CharT, typename _Traits = char_traits<_CharT>>
+ class basic_ispanstream
+ : public basic_istream<_CharT, _Traits>
+ {
+ using __istream_type = 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.ctor], constructors
+ explicit
+ basic_ispanstream(std::span<_CharT> __s,
+ ios_base::openmode __which = ios_base::in)
+ : __istream_type(std::__addressof(_M_sb)),
+ _M_sb(__s, __which | ios_base::in)
+ { }
+
+ basic_ispanstream(const basic_ispanstream&) = delete;
+
+ basic_ispanstream(basic_ispanstream&& __rhs)
+ : __istream_type(std::move(__rhs)), _M_sb(std::move(__rhs._M_sb))
+ {
+ __istream_type::set_rdbuf(std::addressof(_M_sb));
+ }
+
+ template<typename _Ros>
+ requires ranges::borrowed_range<_Ros>
+ && (!convertible_to<_Ros, std::span<_CharT>>)
+ && convertible_to<_Ros, std::span<const _CharT>>
+ explicit
+ basic_ispanstream(_Ros&& __s)
+ : __istream_type(std::__addressof(_M_sb)),
+ _M_sb(ios_base::in)
+ {
+ std::span<const _CharT> __sp(std::forward<_Ros>(__s));
+ _M_sb.span({const_cast<_CharT*>(__sp.data()), __sp.size()});
+ }
+
+ // [ispanstream.assign], assignment and swap
+ basic_ispanstream& operator=(const basic_ispanstream&) = delete;
+ basic_ispanstream& operator=(basic_ispanstream&& __rhs) = default;
+
+ void
+ swap(basic_ispanstream& __rhs)
+ {
+ __istream_type::swap(__rhs);
+ _M_sb.swap(__rhs._M_sb);
+ }
+
+ // [ispanstream.members], member functions
+ basic_spanbuf<_CharT, _Traits>*
+ rdbuf() const noexcept
+ {
+ return const_cast<basic_spanbuf<_CharT, _Traits>*>(std::__addressof(_M_sb));
+ }
+
+ std::span<const _CharT>
+ span() const noexcept
+ { return _M_sb.span(); }
+
+ void
+ span(std::span<_CharT> __s) noexcept
+ { return _M_sb.span(__s); }
+
+ template<typename _Ros>
+ requires ranges::borrowed_range<_Ros>
+ && (!convertible_to<_Ros, std::span<_CharT>>)
+ && convertible_to<_Ros, std::span<const _CharT>>
+ void
+ span(_Ros&& __s) noexcept
+ {
+ std::span<const _CharT> __sp(std::forward<_Ros>(__s));
+ _M_sb.span({const_cast<_CharT*>(__sp.data()), __sp.size()});
+ }
+
+ private:
+ basic_spanbuf<_CharT, _Traits> _M_sb;
+ };
+
+template<typename _CharT, typename _Traits>
+ inline void
+ swap(basic_ispanstream<_CharT, _Traits>& __x,
+ basic_ispanstream<_CharT, _Traits>& __y)
+ { __x.swap(__y); }
+
+using ispanstream = basic_ispanstream<char>;
+using wispanstream = basic_ispanstream<wchar_t>;
+
+template<typename _CharT, typename _Traits = char_traits<_CharT>>
+ class basic_ospanstream
+ : public basic_ostream<_CharT, _Traits>
+ {
+ using __ostream_type = 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.ctor], constructors
+ explicit
+ basic_ospanstream(std::span<_CharT> __s,
+ ios_base::openmode __which = ios_base::out)
+ : __ostream_type(std::__addressof(_M_sb)),
+ _M_sb(__s, __which | ios_base::in)
+ { }
+
+ basic_ospanstream(const basic_ospanstream&) = delete;
+
+ basic_ospanstream(basic_ospanstream&& __rhs)
+ : __ostream_type(std::move(__rhs)), _M_sb(std::move(__rhs._M_sb))
+ {
+ __ostream_type::set_rdbuf(std::addressof(_M_sb));
+ }
+
+ // [ospanstream.assign], assignment and swap
+ basic_ospanstream& operator=(const basic_ospanstream&) = delete;
+ basic_ospanstream& operator=(basic_ospanstream&& __rhs) = default;
+
+ void
+ swap(basic_ospanstream& __rhs)
+ {
+ __ostream_type::swap(__rhs);
+ _M_sb.swap(__rhs._M_sb);
+ }
+
+ // [ospanstream.members], member functions
+ basic_spanbuf<_CharT, _Traits>*
+ rdbuf() const noexcept
+ {
+ return const_cast<basic_spanbuf<_CharT, _Traits>*>(std::__addressof(_M_sb));
+ }
+
+ std::span<_CharT>
+ span() const noexcept
+ { return _M_sb.span(); }
+
+ void
+ span(std::span<_CharT> __s) noexcept
+ { return _M_sb.span(__s); }
+
+ private:
+ basic_spanbuf<_CharT, _Traits> _M_sb;
+ };
+
+template<typename _CharT, typename _Traits>
+ inline void
+ swap(basic_ospanstream<_CharT, _Traits>& __x,
+ basic_ospanstream<_CharT, _Traits>& __y)
+ { __x.swap(__y); }
+
+using ospanstream = basic_ospanstream<char>;
+using wospanstream = basic_ospanstream<wchar_t>;
+
+template<typename _CharT, typename _Traits = char_traits<_CharT>>
+ class basic_spanstream
+ : public basic_iostream<_CharT, _Traits>
+ {
+ using __iostream_type = 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.ctor], constructors
+ explicit
+ basic_spanstream(std::span<_CharT> __s,
+ ios_base::openmode __which = ios_base::out | ios_base::in)
+ : __iostream_type(std::__addressof(_M_sb)),
+ _M_sb(__s, __which)
+ { }
+
+ basic_spanstream(const basic_spanstream&) = delete;
+
+ basic_spanstream(basic_spanstream&& __rhs)
+ : __iostream_type(std::move(__rhs)), _M_sb(std::move(__rhs._M_sb))
+ {
+ __iostream_type::set_rdbuf(std::addressof(_M_sb));
+ }
+
+ // [spanstream.assign], assignment and swap
+ basic_spanstream& operator=(const basic_spanstream&) = delete;
+ basic_spanstream& operator=(basic_spanstream&& __rhs) = default;
+
+ void
+ swap(basic_spanstream& __rhs)
+ {
+ __iostream_type::swap(__rhs);
+ _M_sb.swap(__rhs._M_sb);
+ }
+
+ // [spanstream.members], members
+ basic_spanbuf<_CharT, _Traits>*
+ rdbuf() const noexcept
+ {
+ return const_cast<basic_spanbuf<_CharT, _Traits>*>(std::__addressof(_M_sb));
+ }
+
+ std::span<_CharT>
+ span() const noexcept
+ { return _M_sb.span(); }
+
+ void
+ span(std::span<_CharT> __s) noexcept
+ { return _M_sb.span(__s); }
+
+ private:
+ basic_spanbuf<_CharT, _Traits> _M_sb;
+ };
+
+template<typename _CharT, typename _Traits>
+ inline void
+ swap(basic_spanstream<_CharT, _Traits>& __x,
+ basic_spanstream<_CharT, _Traits>& __y)
+ { __x.swap(__y); }
+
+using spanstream = basic_spanstream<char>;
+using wspanstream = basic_spanstream<wchar_t>;
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+#endif // __cpp_lib_span
+#endif // C++23
+#endif // _GLIBCXX_SPANSTREAM
diff --git a/libstdc++-v3/include/std/version b/libstdc++-v3/include/std/version
index 0a7b28abee6..0930de82efa 100644
--- a/libstdc++-v3/include/std/version
+++ b/libstdc++-v3/include/std/version
@@ -296,6 +296,9 @@
# define __cpp_lib_monadic_optional 202110L
#endif
#define __cpp_lib_move_only_function 202110L
+#if __cpp_lib_span
+# define __cpp_lib_spanstream 202106L
+#endif
#define __cpp_lib_string_contains 202011L
#if _GLIBCXX_USE_CXX11_ABI // Only supported with cxx11-abi
# define __cpp_lib_string_resize_and_overwrite 202110L
diff --git a/libstdc++-v3/testsuite/27_io/spanstream/1.cc b/libstdc++-v3/testsuite/27_io/spanstream/1.cc
new file mode 100644
index 00000000000..b66ee60ec92
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/spanstream/1.cc
@@ -0,0 +1,53 @@
+// { dg-options "-std=gnu++23" }
+// { dg-do run { target c++23 } }
+
+#include <spanstream>
+
+#ifndef __cpp_lib_spanstream
+# error "Feature-test macro for spanstream missing in <spanstream>"
+#elif __cpp_lib_spanstream != 202106L
+# error "Feature-test macro for spanstream has wrong value in <spanstream>"
+#endif
+
+#include <testsuite_hooks.h>
+
+using std::ispanstream;
+using std::ospanstream;
+using std::span;
+
+void
+test_input()
+{
+ // reading input from a fixed pre-arranged character buffer
+ char input[] = "10 20 30";
+ ispanstream is{span<char>{input}};
+ int i;
+ is >> i;
+ VERIFY(10 == i);
+ is >> i;
+ VERIFY(20 == i);
+ is >> i;
+ VERIFY(30 == i);
+ is >>i;
+ VERIFY(!is);
+}
+
+void
+test_output()
+{
+ // writing to a fixed pre-arranged character buffer
+ char output[30]{}; // zero-initialize array
+ ospanstream os{span<char>{output}};
+ os << 10 << 20 << 30;
+ auto const sp = os.span();
+ VERIFY(6 == sp.size());
+ VERIFY("102030" == std::string(sp.data(), sp.size()));
+ VERIFY(static_cast<void*>(output) == sp.data()); // no copying of underlying data!
+ VERIFY("102030" == std::string(output)); // initialization guaranteed NUL termination
+}
+
+int main()
+{
+ test_input();
+ test_output();
+}
diff --git a/libstdc++-v3/testsuite/27_io/spanstream/version.cc b/libstdc++-v3/testsuite/27_io/spanstream/version.cc
new file mode 100644
index 00000000000..62617550493
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/spanstream/version.cc
@@ -0,0 +1,10 @@
+// { dg-options "-std=gnu++23" }
+// { dg-do compile { target c++23 } }
+
+#include <version>
+
+#ifndef __cpp_lib_spanstream
+# error "Feature-test macro for spanstream missing in <version>"
+#elif __cpp_lib_spanstream != 202106L
+# error "Feature-test macro for spanstream has wrong value in <version>"
+#endif
--
2.31.1
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2021-11-13 11:47 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-11-13 11:46 [committed] libstdc++: Implement std::spanstream for C++23 Jonathan Wakely
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).