// Copyright (C) 2020-2024 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.

// You should have received a copy of the GNU General Public License along
// with this library; see the file COPYING3.  If not see
// <http://www.gnu.org/licenses/>.

// { dg-do run { target c++20 } }

#include <memory>
#include <sstream>
#include <testsuite_hooks.h>

template<typename S, typename T>
  concept streamable = requires (S& o, const T& p) { o << p; };

template<typename T, typename D>
  bool
  check(const std::unique_ptr<T, D>& p)
  {
    std::ostringstream ss1, ss2;
    ss1 << p;
    ss2 << p.get();
    return ss1.str() == ss2.str();
  }

void
test01()
{
  static_assert( streamable<std::ostream, std::unique_ptr<int>> );

  std::unique_ptr<int> p;
  VERIFY( check(p) );
  p = std::make_unique<int>();
  VERIFY( check(p) );
}

template<typename>
  struct deleter
  {
    struct pointer
    {
      pointer() { }
      pointer(std::nullptr_t) { }
      explicit operator bool() const { return false; }
      bool operator==(pointer) const { return true; }
    };

    void operator()(pointer) const { }
  };

template<typename C, typename Traits>
  int
  operator<<(std::basic_ostream<C, Traits>& o, typename deleter<C>::pointer&&)
  {
    o << C{'P'};
    return 1; // no requirement that this operator returns the stream
  }

template<typename D>
  using Unique_ptr = std::unique_ptr<typename D::pointer, D>;

static_assert( streamable<std::ostream, Unique_ptr<deleter<char>>> );
static_assert( ! streamable<std::ostream, Unique_ptr<deleter<wchar_t>>> );
#ifdef _GLIBCXX_USE_WCHAR_T
static_assert( ! streamable<std::wostream, Unique_ptr<deleter<char>>> );
static_assert( streamable<std::wostream, Unique_ptr<deleter<wchar_t>>> );
#endif

void
test02()
{
  Unique_ptr<deleter<char>> p;
  VERIFY( check(p) );
}

int
main()
{
  test01();
  test02();
}
