mirror of
https://gcc.gnu.org/git/gcc.git
synced 2026-02-22 12:00:03 -05:00
As explained in LWG 3600, we never implemented a C++0x change that made the copy constructor of std::istream_iterator defined as defaulted. That would be an ABI break, so the resolution of LWG 3600 is to not require it to be trivial, but just constexpr and conditionally noexcept. This applies that resolution. libstdc++-v3/ChangeLog: * include/bits/stream_iterator.h (istream_iterator): Add constexpr to copy constructor, as per LWG 3600. * testsuite/24_iterators/istream_iterator/cons/constexpr.cc: Check copy construction.
275 lines
8.2 KiB
C++
275 lines
8.2 KiB
C++
// Stream iterators
|
|
|
|
// Copyright (C) 2001-2023 Free Software Foundation, Inc.
|
|
//
|
|
// 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 bits/stream_iterator.h
|
|
* This is an internal header file, included by other library headers.
|
|
* Do not attempt to use it directly. @headername{iterator}
|
|
*/
|
|
|
|
#ifndef _STREAM_ITERATOR_H
|
|
#define _STREAM_ITERATOR_H 1
|
|
|
|
#pragma GCC system_header
|
|
|
|
#include <iosfwd>
|
|
#include <bits/move.h>
|
|
#include <bits/stl_iterator_base_types.h>
|
|
#include <debug/debug.h>
|
|
|
|
namespace std _GLIBCXX_VISIBILITY(default)
|
|
{
|
|
_GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|
|
|
/**
|
|
* @addtogroup iterators
|
|
* @{
|
|
*/
|
|
|
|
// Ignore warnings about std::iterator.
|
|
#pragma GCC diagnostic push
|
|
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
|
|
|
/// Provides input iterator semantics for streams.
|
|
template<typename _Tp, typename _CharT = char,
|
|
typename _Traits = char_traits<_CharT>, typename _Dist = ptrdiff_t>
|
|
class istream_iterator
|
|
: public iterator<input_iterator_tag, _Tp, _Dist, const _Tp*, const _Tp&>
|
|
{
|
|
public:
|
|
typedef _CharT char_type;
|
|
typedef _Traits traits_type;
|
|
typedef basic_istream<_CharT, _Traits> istream_type;
|
|
|
|
private:
|
|
istream_type* _M_stream;
|
|
_Tp _M_value;
|
|
// This bool becomes false at end-of-stream. It should be sufficient to
|
|
// check _M_stream != nullptr instead, but historically we did not set
|
|
// _M_stream to null when reaching the end, so we need to keep this flag.
|
|
bool _M_ok;
|
|
|
|
public:
|
|
/// Construct end of input stream iterator.
|
|
_GLIBCXX_CONSTEXPR istream_iterator()
|
|
_GLIBCXX_NOEXCEPT_IF(is_nothrow_default_constructible<_Tp>::value)
|
|
: _M_stream(0), _M_value(), _M_ok(false) {}
|
|
|
|
/// Construct start of input stream iterator.
|
|
istream_iterator(istream_type& __s)
|
|
: _M_stream(std::__addressof(__s)), _M_ok(true)
|
|
{ _M_read(); }
|
|
|
|
_GLIBCXX_CONSTEXPR
|
|
istream_iterator(const istream_iterator& __obj)
|
|
_GLIBCXX_NOEXCEPT_IF(is_nothrow_copy_constructible<_Tp>::value)
|
|
: _M_stream(__obj._M_stream), _M_value(__obj._M_value),
|
|
_M_ok(__obj._M_ok)
|
|
{ }
|
|
|
|
#if __cplusplus > 201703L && __cpp_lib_concepts
|
|
constexpr
|
|
istream_iterator(default_sentinel_t)
|
|
noexcept(is_nothrow_default_constructible_v<_Tp>)
|
|
: istream_iterator() { }
|
|
#endif
|
|
|
|
#if __cplusplus >= 201103L
|
|
istream_iterator& operator=(const istream_iterator&) = default;
|
|
~istream_iterator() = default;
|
|
#endif
|
|
|
|
_GLIBCXX_NODISCARD
|
|
const _Tp&
|
|
operator*() const _GLIBCXX_NOEXCEPT
|
|
{
|
|
__glibcxx_requires_cond(_M_ok,
|
|
_M_message(__gnu_debug::__msg_deref_istream)
|
|
._M_iterator(*this));
|
|
return _M_value;
|
|
}
|
|
|
|
_GLIBCXX_NODISCARD
|
|
const _Tp*
|
|
operator->() const _GLIBCXX_NOEXCEPT
|
|
{ return std::__addressof((operator*())); }
|
|
|
|
istream_iterator&
|
|
operator++()
|
|
{
|
|
__glibcxx_requires_cond(_M_ok,
|
|
_M_message(__gnu_debug::__msg_inc_istream)
|
|
._M_iterator(*this));
|
|
_M_read();
|
|
return *this;
|
|
}
|
|
|
|
istream_iterator
|
|
operator++(int)
|
|
{
|
|
__glibcxx_requires_cond(_M_ok,
|
|
_M_message(__gnu_debug::__msg_inc_istream)
|
|
._M_iterator(*this));
|
|
istream_iterator __tmp = *this;
|
|
_M_read();
|
|
return __tmp;
|
|
}
|
|
|
|
private:
|
|
bool
|
|
_M_equal(const istream_iterator& __x) const _GLIBCXX_NOEXCEPT
|
|
{
|
|
// Ideally this would just return _M_stream == __x._M_stream,
|
|
// but code compiled with old versions never sets _M_stream to null.
|
|
return (_M_ok == __x._M_ok) && (!_M_ok || _M_stream == __x._M_stream);
|
|
}
|
|
|
|
void
|
|
_M_read()
|
|
{
|
|
if (_M_stream && !(*_M_stream >> _M_value))
|
|
{
|
|
_M_stream = 0;
|
|
_M_ok = false;
|
|
}
|
|
}
|
|
|
|
/// Return true if the iterators refer to the same stream,
|
|
/// or are both at end-of-stream.
|
|
_GLIBCXX_NODISCARD
|
|
friend bool
|
|
operator==(const istream_iterator& __x, const istream_iterator& __y)
|
|
_GLIBCXX_NOEXCEPT
|
|
{ return __x._M_equal(__y); }
|
|
|
|
#if __cpp_impl_three_way_comparison < 201907L
|
|
/// Return true if the iterators refer to different streams,
|
|
/// or if one is at end-of-stream and the other is not.
|
|
_GLIBCXX_NODISCARD
|
|
friend bool
|
|
operator!=(const istream_iterator& __x, const istream_iterator& __y)
|
|
_GLIBCXX_NOEXCEPT
|
|
{ return !__x._M_equal(__y); }
|
|
#endif
|
|
|
|
#if __cplusplus > 201703L && __cpp_lib_concepts
|
|
[[nodiscard]]
|
|
friend bool
|
|
operator==(const istream_iterator& __i, default_sentinel_t) noexcept
|
|
{ return !__i._M_stream; }
|
|
#endif
|
|
};
|
|
|
|
/**
|
|
* @brief Provides output iterator semantics for streams.
|
|
*
|
|
* This class provides an iterator to write to an ostream. The type Tp is
|
|
* the only type written by this iterator and there must be an
|
|
* operator<<(Tp) defined.
|
|
*
|
|
* @tparam _Tp The type to write to the ostream.
|
|
* @tparam _CharT The ostream char_type.
|
|
* @tparam _Traits The ostream char_traits.
|
|
*/
|
|
template<typename _Tp, typename _CharT = char,
|
|
typename _Traits = char_traits<_CharT> >
|
|
class ostream_iterator
|
|
: public iterator<output_iterator_tag, void, void, void, void>
|
|
{
|
|
public:
|
|
///@{
|
|
/// Public typedef
|
|
#if __cplusplus > 201703L
|
|
using difference_type = ptrdiff_t;
|
|
#endif
|
|
typedef _CharT char_type;
|
|
typedef _Traits traits_type;
|
|
typedef basic_ostream<_CharT, _Traits> ostream_type;
|
|
///@}
|
|
|
|
private:
|
|
ostream_type* _M_stream;
|
|
const _CharT* _M_string;
|
|
|
|
public:
|
|
/// Construct from an ostream.
|
|
ostream_iterator(ostream_type& __s) _GLIBCXX_NOEXCEPT
|
|
: _M_stream(std::__addressof(__s)), _M_string(0) {}
|
|
|
|
/**
|
|
* Construct from an ostream.
|
|
*
|
|
* The delimiter string @a c is written to the stream after every Tp
|
|
* written to the stream. The delimiter is not copied, and thus must
|
|
* not be destroyed while this iterator is in use.
|
|
*
|
|
* @param __s Underlying ostream to write to.
|
|
* @param __c CharT delimiter string to insert.
|
|
*/
|
|
ostream_iterator(ostream_type& __s, const _CharT* __c) _GLIBCXX_NOEXCEPT
|
|
: _M_stream(std::__addressof(__s)), _M_string(__c) { }
|
|
|
|
/// Copy constructor.
|
|
ostream_iterator(const ostream_iterator& __obj) _GLIBCXX_NOEXCEPT
|
|
: _M_stream(__obj._M_stream), _M_string(__obj._M_string) { }
|
|
|
|
#if __cplusplus >= 201103L
|
|
ostream_iterator& operator=(const ostream_iterator&) = default;
|
|
#endif
|
|
|
|
/// Writes @a value to underlying ostream using operator<<. If
|
|
/// constructed with delimiter string, writes delimiter to ostream.
|
|
ostream_iterator&
|
|
operator=(const _Tp& __value)
|
|
{
|
|
__glibcxx_requires_cond(_M_stream != 0,
|
|
_M_message(__gnu_debug::__msg_output_ostream)
|
|
._M_iterator(*this));
|
|
*_M_stream << __value;
|
|
if (_M_string)
|
|
*_M_stream << _M_string;
|
|
return *this;
|
|
}
|
|
|
|
_GLIBCXX_NODISCARD
|
|
ostream_iterator&
|
|
operator*() _GLIBCXX_NOEXCEPT
|
|
{ return *this; }
|
|
|
|
ostream_iterator&
|
|
operator++() _GLIBCXX_NOEXCEPT
|
|
{ return *this; }
|
|
|
|
ostream_iterator&
|
|
operator++(int) _GLIBCXX_NOEXCEPT
|
|
{ return *this; }
|
|
};
|
|
#pragma GCC diagnostic pop
|
|
|
|
/// @} group iterators
|
|
|
|
_GLIBCXX_END_NAMESPACE_VERSION
|
|
} // namespace
|
|
|
|
#endif
|