(root)/
gcc-13.2.0/
libstdc++-v3/
testsuite/
23_containers/
vector/
bool/
modifiers/
assign/
constexpr.cc
// { dg-options "-std=gnu++20" }
// { dg-do compile { target c++20 } }
// { dg-xfail-if "not supported" { debug_mode } }

#include <vector>
#include <testsuite_hooks.h>

template<typename T>
struct Alloc : std::allocator<T>
{
  using std::allocator<T>::allocator;

  constexpr explicit Alloc(int p) : personality(p) { }

  template<typename U>
    constexpr Alloc(const Alloc<U>& a) : personality(a.personality) { }

  int personality = 0;

  using propagate_on_container_move_assignment = std::false_type;

  constexpr bool operator==(const Alloc& a) const noexcept
  { return personality == a.personality; }
};

constexpr std::size_t
capacity_for(std::size_t n)
{
  std::size_t N = std::vector<bool>(1).capacity();
  if (auto r = n % N)
    return n - r + N;
  return n;
}

constexpr bool
copy_assign()
{
  // vector::operator=(const vector&)

  std::vector<bool> v1, v2;
  v1 = v1;
  v2 = v1;
  VERIFY(v2.size() == 0);
  VERIFY(v2.capacity() == 0);

  for (int i = 0; i < 10; ++i)
    v1.push_back(i);
  v2 = v1;
  VERIFY(v2.size() == 10);
  v2.reserve(50);
  v1.push_back(1);
  v2 = v1;
  VERIFY(v2.size() == 11);
  VERIFY(v2.capacity() == capacity_for(50));

  std::vector<bool, Alloc<bool>> va1(Alloc<bool>(1)), va2(Alloc<bool>(2));
  va2 = va1;
  VERIFY( va2.get_allocator().personality == 2 );
  va1.push_back(999);
  va2 = va1;
  VERIFY( va2.get_allocator().personality == 2 );

  return true;
}

static_assert( copy_assign() );

constexpr bool
move_assign()
{
  // vector::operator=(const vector&)

  std::vector<bool> v1, v2;
  v1 = std::move(v1);
  v2 = std::move(v1);
  VERIFY(v2.size() == 0);
  VERIFY(v2.capacity() == 0);

  for (int i = 0; i < 10; ++i)
    v1.push_back(i);
  v2 = std::move(v1);
  VERIFY(v2.size() == 10);
  v2.reserve(50);
  v1.push_back(1);
  v2 = std::move(v1);
  VERIFY(v2.size() == 1);
  VERIFY(v1.capacity() == 0);
  VERIFY(v2.capacity() == capacity_for(1));

  std::vector<bool, Alloc<bool>> va1(Alloc<bool>(1)), va2(Alloc<bool>(2));
  va2 = std::move(va1);
  VERIFY( va2.get_allocator().personality == 2 );
  va1.push_back(9);
  va1.push_back(99);
  va1.push_back(999);
  va1.push_back(9999);
  va2 = std::move(va1);
  va2 = std::move(va1);
  VERIFY( va2.get_allocator().personality == 2 );

  return true;
}

static_assert( move_assign() );

constexpr bool
initializer_list_assign()
{
  std::vector<bool> v1;
  v1 = {1, 0, 1};
  VERIFY( v1.size() == 3 );
  VERIFY( v1.capacity() == capacity_for(3) );
  v1 = {1, 0};
  VERIFY( v1.size() == 2 );
  VERIFY( v1.capacity() == capacity_for(3) );
  v1 = {1, 1, 0, 1, 1, 1, 0, 1, 1};
  VERIFY( v1.size() == 9 );
  VERIFY( v1.capacity() == capacity_for(9) );

  std::vector<bool, Alloc<bool>> va1(Alloc<bool>(111));
  va1 = {1, 0, 0};
  VERIFY( va1.get_allocator().personality == 111 );

  return true;
}

static_assert( initializer_list_assign() );

constexpr bool
assign_iterator_range()
{
  std::vector<bool> v;

  int arr[] = { 1, 2, 3, 4 };
  v.assign(arr, arr+3);
  VERIFY( v.size() == 3 );
  v.reserve(5);
  v.assign(arr, arr+3);
  VERIFY( v.capacity() == capacity_for(5) );

  struct input_iterator
  {
    using iterator_category = std::input_iterator_tag;
    using value_type = bool;
    using pointer = const bool*;
    using reference = bool;
    using difference_type = int;

    constexpr input_iterator() : val(0) { }
    constexpr input_iterator(int i) : val(i) { }

    constexpr input_iterator& operator++() { --val; return *this; }
    constexpr input_iterator operator++(int) { return {val--}; }

    constexpr bool operator*() const { return val % 2; }
    constexpr const bool* operator->() const { return nullptr; }

    constexpr bool operator==(const input_iterator&) const = default;

    int val;
  };

  v.assign(input_iterator(9), input_iterator());
  VERIFY( v.size() == 9 );

  return true;
}

static_assert( assign_iterator_range() );

constexpr bool
assign_value()
{
  std::vector<bool> v1;
  v1.assign(3, 8);
  VERIFY( v1.size() == 3 );
  VERIFY( v1.capacity() == capacity_for(3) );
  v1.assign(2, 9);
  VERIFY( v1.size() == 2 );
  VERIFY( v1.capacity() == capacity_for(3) );
  v1.assign(9, 10);
  VERIFY( v1.size() == 9 );
  VERIFY( v1.capacity() == capacity_for(9) );

  std::vector<bool, Alloc<bool>> va1(Alloc<bool>(111));
  va1.assign(2, 9);
  VERIFY( va1.size() == 2 );
  VERIFY( va1.get_allocator().personality == 111 );

  return true;
}

static_assert( assign_value() );

constexpr bool
assign_initializer_list()
{
  std::vector<bool> v1;
  v1.assign({0, 1, 0});
  VERIFY( v1.size() == 3 );
  VERIFY( v1.capacity() == capacity_for(3) );
  v1.assign({1, 0});
  VERIFY( v1.size() == 2 );
  VERIFY( v1.capacity() == capacity_for(3) );
  v1.assign({1, 0, 0, 1, 1, 0, 0, 1, 1});
  VERIFY( v1.size() == 9 );
  VERIFY( v1.capacity() == capacity_for(9) );

  std::vector<bool, Alloc<bool>> va1(Alloc<bool>(111));
  va1.assign({1, 1, 1});
  VERIFY( va1.get_allocator().personality == 111 );

  return true;
}

static_assert( assign_initializer_list() );