text: //===----------------------------------------------------------------------===//
  //
  //                     The LLVM Compiler Infrastructure
  //
  // This file is dual licensed under the MIT and the University of Illinois Open
  // Source Licenses. See LICENSE.TXT for details.
  //
  //===----------------------------------------------------------------------===//
  
  // UNSUPPORTED: c++98, c++03
  
  // <scoped_allocator>
  
  // template <class OtherAlloc, class ...InnerAlloc>
  //   class scoped_allocator_adaptor
  
  // template <class T, class ...Args>
  // void scoped_allocator_adaptor::construct(T*, Args&&...)
  
  #include <scoped_allocator>
  #include <type_traits>
  #include <utility>
  #include <tuple>
  #include <cassert>
  #include <cstdlib>
  #include "uses_alloc_types.hpp"
  #include "controlled_allocators.hpp"
  
  // — If uses_allocator_v<T, inner_allocator_type> is false and
  //   is_constructible_v<T, Args...> is true, calls
  //   OUTERMOST_ALLOC_TRAITS(*this)::construct(
  //      OUTERMOST (*this), p, std::forward<Args>(args)...).
  void test_bullet_one() {
      using VoidAlloc2 = CountingAllocator<void, 2>;
  
      AllocController POuter;
      AllocController PInner;
      {
          using T = NotUsesAllocator<VoidAlloc2, 3>;
          using Outer = CountingAllocator<T, 1>;
          using Inner = CountingAllocator<T, 2>;
          using SA = std::scoped_allocator_adaptor<Outer, Inner>;
          static_assert(!std::uses_allocator<T, Outer>::value, "");
          static_assert(!std::uses_allocator<T, Inner>::value, "");
          T* ptr = (T*)::operator new(sizeof(T));
          Outer O(POuter);
          Inner I(PInner);
          SA A(O, I);
          int x = 42;
          int const& cx = x;
          A.construct(ptr, x, cx, std::move(x));
          assert((checkConstruct<int&, int const&, int&&>(*ptr, UA_None)));
          assert((POuter.checkConstruct<int&, int const&, int&&>(O, ptr)));
          A.destroy(ptr);
          ::operator delete((void*)ptr);
      }
      PInner.reset();
      POuter.reset();
  }
  
  
  // Otherwise, if uses_allocator_v<T, inner_allocator_type> is true and
  // is_constructible_v<T, allocator_arg_t, inner_allocator_type&, Args...> is
  // true, calls OUTERMOST_ALLOC_TRAITS(*this)::construct(OUTERMOST (*this), p,
  //     allocator_arg, inner_allocator(), std::forward<Args>(args)...).
  void test_bullet_two() {
      using VoidAlloc2 = CountingAllocator<void, 2>;
  
      AllocController POuter;
      AllocController PInner;
      {
          using T = UsesAllocatorV1<VoidAlloc2, 3>;
          using Outer = CountingAllocator<T, 1>;
          using Inner = CountingAllocator<T, 2>;
          using SA = std::scoped_allocator_adaptor<Outer, Inner>;
          static_assert(!std::uses_allocator<T, Outer>::value, "");
          static_assert(std::uses_allocator<T, Inner>::value, "");
          T* ptr = (T*)::operator new(sizeof(T));
          Outer O(POuter);
          Inner I(PInner);
          SA A(O, I);
          int x = 42;
          int const& cx = x;
          A.construct(ptr, x, cx, std::move(x));
          assert((checkConstruct<int&, int const&, int&&>(*ptr, UA_AllocArg, I)));
          assert((POuter.checkConstruct<std::allocator_arg_t const&,
                     SA::inner_allocator_type&, int&, int const&, int&&>(O, ptr)));
          A.destroy(ptr);
          ::operator delete((void*)ptr);
      }
      PInner.reset();
      POuter.reset();
  }
  
  // Otherwise, if uses_allocator_v<T, inner_allocator_type> is true and
  // is_constructible_v<T, Args..., inner_allocator_type&> is true, calls
  // OUTERMOST_ALLOC_TRAITS(*this)::construct(OUTERMOST (*this), p,
  //   std::forward<Args>(args)..., inner_allocator()).
  void test_bullet_three() {
      using VoidAlloc2 = CountingAllocator<void, 2>;
  
      AllocController POuter;
      AllocController PInner;
      {
          using T = UsesAllocatorV2<VoidAlloc2, 3>;
          using Outer = CountingAllocator<T, 1>;
          using Inner = CountingAllocator<T, 2>;
          using SA = std::scoped_allocator_adaptor<Outer, Inner>;
          static_assert(!std::uses_allocator<T, Outer>::value, "");
          static_assert(std::uses_allocator<T, Inner>::value, "");
          T* ptr = (T*)::operator new(sizeof(T));
          Outer O(POuter);
          Inner I(PInner);
          SA A(O, I);
          int x = 42;
          int const& cx = x;
          A.construct(ptr, x, cx, std::move(x));
          assert((checkConstruct<int&, int const&, int&&>(*ptr, UA_AllocLast, I)));
          assert((POuter.checkConstruct<
                     int&, int const&, int&&,
                     SA::inner_allocator_type&>(O, ptr)));
          A.destroy(ptr);
          ::operator delete((void*)ptr);
      }
      PInner.reset();
      POuter.reset();
  }
  
  int main() {
      test_bullet_one();
      test_bullet_two();
      test_bullet_three();
  }
  