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

#include <vector>

#ifndef __cpp_lib_constexpr_vector
# error "Feature test macro for constexpr vector is missing in <vector>"
#elif __cpp_lib_constexpr_vector != 201907L
# error "Feature test macro for constexpr vector has wrong value in <vector>"
#endif

#include <testsuite_hooks.h>
#include <testsuite_iterators.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;

  constexpr Alloc select_on_container_copy_construction() const
  { return Alloc(-1); }

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

namespace default_constructor_global_scope
{
  constexpr std::vector<int> v1;
  static_assert(v1.size() == 0);
  static_assert(v1.capacity() == 0);

  constexpr std::allocator<int> a;
  constexpr std::vector<int> v2(a);
  static_assert(v2.size() == 0);
  static_assert(v2.capacity() == 0);

  constexpr Alloc<int> aa(10);
  constexpr std::vector<int, Alloc<int>> v3(aa);
  static_assert(v3.size() == 0);
  static_assert(v3.capacity() == 0);
  static_assert(v3.get_allocator() == aa);
}

constexpr bool
default_constructor_function_scope()
{
  // vector()

  std::vector<int> v1;
  VERIFY(v1.size() == 0);
  VERIFY(v1.capacity() == 0);

  // vector(const Allocator&)

  const std::allocator<int> a;
  std::vector<int> v2(a);
  VERIFY(v2.size() == 0);
  VERIFY(v2.capacity() == 0);

  const Alloc<long> aa(10);
  std::vector<long, Alloc<long>> v3(aa);
  VERIFY(v3.size() == 0);
  VERIFY(v3.capacity() == 0);
  VERIFY(v3.get_allocator() == aa);

  return true;
}

static_assert( default_constructor_function_scope() );

constexpr bool
sequence_constructors()
{
  // vector(size_type, const Allocator& = Allocator())

  std::vector<int> v0(0);
  VERIFY(v0.size() == 0);

  std::vector<int> v1(1);
  VERIFY(v1.size() == 1);

  std::vector<int> v2(2);
  VERIFY(v2.size() == 2);

  std::vector<int> v50(50);
  VERIFY(v50.size() == 50);

  const std::allocator<int> a;
  std::vector<int> a0(0, a);
  VERIFY(a0.size() == 0);

  std::vector<int> a1(1, a);
  VERIFY(a1.size() == 1);

  std::vector<int> a2(2, a);
  VERIFY(a2.size() == 2);

  std::vector<int> a50(50, a);
  VERIFY(a50.size() == 50);

  const Alloc<long> la(10);
  std::vector<long, Alloc<long>> l0(0, la);
  VERIFY(l0.size() == 0);
  VERIFY(l0.get_allocator() == la);

  std::vector<long, Alloc<long>> l1(1, la);
  VERIFY(l1.size() == 1);
  VERIFY(l1.get_allocator() == la);

  std::vector<long, Alloc<long>> l2(2, la);
  VERIFY(l2.size() == 2);
  VERIFY(l2.get_allocator() == la);

  std::vector<long, Alloc<long>> l50(50, la);
  VERIFY(l50.size() == 50);
  VERIFY(l50.get_allocator() == la);

  // vector(size_type, const T&, const Allocator& = Allocator())

  std::vector<int> v3(3, 4);
  VERIFY(v3.size() == 3);
  VERIFY(v3[0] == 4 && v3[2] == 4);

  std::vector<int> a3(3, 5, a);
  VERIFY(a3.size() == 3);
  VERIFY(a3[0] == 5 && a3[2] == 5);

  std::vector<long, Alloc<long>> l3(3, 6, la);
  VERIFY(l3.size() == 3);
  VERIFY(l3[0] == 6 && l3[2] == 6);
  VERIFY(l3.get_allocator() == la);

  return true;
}

static_assert(sequence_constructors());

constexpr bool
iterator_range_constructor()
{
  // vector(InputIterator, InputIterator, const Allocator& = Allocator())

  short range[3] = { 1, 2, 3 };

  std::vector<int> v0(std::begin(range), std::end(range));
  VERIFY(v0.size() == std::size(range));
  VERIFY(v0[0] == 1 && v0[1] == 2 && v0[2] == 3);

  const Alloc<long> a(5);
  std::vector<long, Alloc<long>> l0(std::begin(range), std::end(range), a);
  VERIFY(l0.size() == std::size(range));
  VERIFY(l0.get_allocator() == a);
  VERIFY(l0[0] == 1 && l0[1] == 2 && l0[2] == 3);

  struct input_iterator
  {
    using iterator_category = std::input_iterator_tag;
    using value_type = int;
    using pointer = const int*;
    using reference = int;
    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 int operator*() const { return val; }
    constexpr const int* operator->() const { return &val; }

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

    int val;
  };

  std::vector<int> v1(input_iterator(3), input_iterator());
  VERIFY(v1.size() == 3);
  VERIFY(v1[0] == 3 && v1[1] == 2 && v1[2] == 1);

  std::vector<long, Alloc<long>> l1(input_iterator(2), input_iterator(), a);
  VERIFY(l1.size() == 2);
  VERIFY(l1.get_allocator() == a);
  VERIFY(l1[0] == 2 && l1[1] == 1);

  return true;
}

static_assert(iterator_range_constructor());

constexpr bool
initializer_list_constructor()
{
  // vector(initializer_list<T>, const Allocator& = Allocator())

  std::vector<int> v0({ 1, 2, 3 });
  VERIFY(v0.size() == 3);
  VERIFY(v0[0] == 1 && v0[1] == 2 && v0[2] == 3);

  const Alloc<long> a(5);
  std::vector<long, Alloc<long>> l0({ 1, 2, 3 }, a);
  VERIFY(l0.size() == 3);
  VERIFY(l0.get_allocator() == a);

  return true;
}

static_assert(initializer_list_constructor());

constexpr bool
copy_constructor()
{
  const std::vector<int> v0({ 1, 2, 3 });
  const std::vector<long, Alloc<long>> l0({ 4, 5, 6 });

  // vector(const vector&)

  std::vector<int> v1(v0);
  VERIFY( v1.size() == v0.size() );
  VERIFY( v1[0] == v0[0] && v1[1] == v0[1] && v1[2] == v0[2] );
  VERIFY( v1.get_allocator() == v0.get_allocator() );

  const Alloc<short> as(6);
  std::vector<short, Alloc<short>> s1(3, short(2), as);
  std::vector<short, Alloc<short>> s2(s1);
  VERIFY( s2.size() == s1.size() );
  VERIFY( s2.get_allocator().personality == -1 );

  // vector(const vector&, const Allocator&)

  const Alloc<long> a(6);
  std::vector<long, Alloc<long>> l1(l0, a);
  VERIFY( l1.size() == l0.size() );
  VERIFY( l1[0] == l0[0] && l1[1] == l0[1] && l1[2] == l0[2] );
  VERIFY( l1.get_allocator() == a );
  VERIFY( l1.get_allocator() != l0.get_allocator() );

  return true;
}

static_assert(copy_constructor());

constexpr bool
move_constructor()
{
  const std::vector<int> v0({ 1, 2, 3 });
  const std::vector<long, Alloc<long>> l0({ 4, 5, 6 });

  // vector(const vector&)

  std::vector<int> v1(v0);
  std::vector<int> v2(std::move(v1));
  VERIFY( v2.size() == v0.size() );
  VERIFY( v1.empty() );
  VERIFY( v2[0] == v0[0] && v2[1] == v0[1] && v2[2] == v0[2] );
  VERIFY( v2.get_allocator() == v0.get_allocator() );

  // vector(const vector&, const Allocator&)

  const Alloc<long> a(6);
  std::vector<long, Alloc<long>> l1(l0);
  std::vector<long, Alloc<long>> l2(std::move(l1), a);
  VERIFY( l2.size() == l0.size() );
  VERIFY( l2[0] == l0[0] && l2[1] == l0[1] && l2[2] == l0[2] );
  VERIFY( l2.get_allocator() == a );
  VERIFY( l2.get_allocator() != l0.get_allocator() );

  std::vector<long, Alloc<long>> l3(std::move(l2), a);
  VERIFY( l3.size() == l0.size() );
  VERIFY( l3[0] == l0[0] && l3[1] == l0[1] && l3[2] == l0[2] );
  VERIFY( l3.get_allocator() == a );
  VERIFY( l3.get_allocator() == l2.get_allocator() );

  return true;
}

static_assert(move_constructor());