EricWF created this revision.
EricWF added a reviewer: mclow.lists.
EricWF added subscribers: cfe-commits, Potatoswatter.

For more information see:

- https://llvm.org/bugs/show_bug.cgi?id=23841
- https://llvm.org/bugs/show_bug.cgi?id=24075

I hope you have as much fun reviewing as I did writing these insane tests!


https://reviews.llvm.org/D27612

Files:
  include/scoped_allocator
  
test/std/utilities/allocator.adaptor/allocator.adaptor.members/construct_pair.pass.cpp
  
test/std/utilities/allocator.adaptor/allocator.adaptor.members/construct_pair_const_lvalue_pair.pass.cpp
  
test/std/utilities/allocator.adaptor/allocator.adaptor.members/construct_pair_piecewise.pass.cpp
  
test/std/utilities/allocator.adaptor/allocator.adaptor.members/construct_pair_rvalue.pass.cpp
  
test/std/utilities/allocator.adaptor/allocator.adaptor.members/construct_pair_values.pass.cpp

Index: test/std/utilities/allocator.adaptor/allocator.adaptor.members/construct_pair_values.pass.cpp
===================================================================
--- /dev/null
+++ test/std/utilities/allocator.adaptor/allocator.adaptor.members/construct_pair_values.pass.cpp
@@ -0,0 +1,144 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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 U1, class U2, class Tp, class Vp>
+// void scoped_allocator_adaptor::construct(pair<U1, U2>*, Tp&&, Up&&)
+
+#include <scoped_allocator>
+#include <type_traits>
+#include <utility>
+#include <tuple>
+#include <cassert>
+#include <cstdlib>
+#include "uses_alloc_types.hpp"
+#include "controlled_allocators.hpp"
+
+
+void test_no_inner_alloc()
+{
+    using VoidAlloc = CountingAllocator<void>;
+    AllocController P;
+    {
+        using T = UsesAllocatorV1<VoidAlloc, 1>;
+        using U = UsesAllocatorV2<VoidAlloc, 1>;
+        using Pair = std::pair<T, U>;
+        int x = 42;
+        const int y = 101;
+        using Alloc = CountingAllocator<Pair>;
+        using SA = std::scoped_allocator_adaptor<Alloc>;
+        static_assert(std::uses_allocator<T, CountingAllocator<T> >::value, "");
+        Pair * ptr = (Pair*)std::malloc(sizeof(Pair));
+        Alloc CA(P);
+        SA A(CA);
+        A.construct(ptr, x, std::move(y));
+        assert(checkConstruct<int&>(ptr->first, UA_AllocArg, CA));
+        assert(checkConstruct<int const&&>(ptr->second, UA_AllocLast, CA));
+        assert((P.checkConstruct<std::piecewise_construct_t const&,
+                                 std::tuple<std::allocator_arg_t const&, SA&, int&>&&,
+                                 std::tuple<int const&&, SA&>&&
+              >(CA, ptr)));
+
+    }
+    P.reset();
+    {
+        using T = UsesAllocatorV3<VoidAlloc, 1>;
+        using U = NotUsesAllocator<VoidAlloc, 1>;
+        using Pair = std::pair<T, U>;
+        int x = 42;
+        const int y = 101;
+        using Alloc = CountingAllocator<Pair>;
+        using SA = std::scoped_allocator_adaptor<Alloc>;
+        static_assert(std::uses_allocator<T, CountingAllocator<T> >::value, "");
+        Pair * ptr = (Pair*)std::malloc(sizeof(Pair));
+        Alloc CA(P);
+        SA A(CA);
+        A.construct(ptr, std::move(x), y);
+        assert(checkConstruct<int&&>(ptr->first, UA_AllocArg, CA));
+        assert(checkConstruct<int const&>(ptr->second, UA_None));
+        assert((P.checkConstruct<std::piecewise_construct_t const&,
+                                 std::tuple<std::allocator_arg_t const&, SA&, int&&>&&,
+                                 std::tuple<int const&>&&
+                   >(CA, ptr)));
+        assert(P.construct_called == 1);
+    }
+}
+
+void test_with_inner_alloc()
+{
+    using VoidAlloc1 = CountingAllocator<void, 1>;
+    using VoidAlloc2 = CountingAllocator<void, 2>;
+
+    AllocController POuter;
+    AllocController PInner;
+    {
+        using T = UsesAllocatorV1<VoidAlloc2, 1>;
+        using U = UsesAllocatorV2<VoidAlloc2, 1>;
+        using Pair = std::pair<T, U>;
+        int x = 42;
+        int y = 101;
+        using Outer = CountingAllocator<Pair, 1>;
+        using Inner = CountingAllocator<Pair, 2>;
+        using SA = std::scoped_allocator_adaptor<Outer, Inner>;
+        using SAInner = std::scoped_allocator_adaptor<Inner>;
+        static_assert(!std::uses_allocator<T, Outer>::value, "");
+        static_assert(std::uses_allocator<T, Inner>::value, "");
+        Pair * ptr = (Pair*)std::malloc(sizeof(Pair));
+        Outer O(POuter);
+        Inner I(PInner);
+        SA A(O, I);
+        A.construct(ptr, x, std::move(y));
+        assert(checkConstruct<int&>(ptr->first, UA_AllocArg, I));
+        assert(checkConstruct<int &&>(ptr->second, UA_AllocLast));
+        assert((POuter.checkConstruct<std::piecewise_construct_t const&,
+                                 std::tuple<std::allocator_arg_t const&, SAInner&, int&>&&,
+                                 std::tuple<int &&, SAInner&>&&
+              >(O, ptr)));
+        A.destroy(ptr);
+        std::free(ptr);
+    }
+    PInner.reset();
+    POuter.reset();
+    {
+        using T = UsesAllocatorV3<VoidAlloc2, 1>;
+        using U = NotUsesAllocator<VoidAlloc2, 1>;
+        using Pair = std::pair<T, U>;
+        int x = 42;
+        const int y = 101;
+        using Outer = CountingAllocator<Pair, 1>;
+        using Inner = CountingAllocator<Pair, 2>;
+        using SA = std::scoped_allocator_adaptor<Outer, Inner>;
+        using SAInner = std::scoped_allocator_adaptor<Inner>;
+        static_assert(!std::uses_allocator<T, Outer>::value, "");
+        static_assert(std::uses_allocator<T, Inner>::value, "");
+        Pair * ptr = (Pair*)std::malloc(sizeof(Pair));
+        Outer O(POuter);
+        Inner I(PInner);
+        SA A(O, I);
+        A.construct(ptr, std::move(x), std::move(y));
+        assert(checkConstruct<int&&>(ptr->first, UA_AllocArg, I));
+        assert(checkConstruct<int const&&>(ptr->second, UA_None));
+        assert((POuter.checkConstruct<std::piecewise_construct_t const&,
+                                 std::tuple<std::allocator_arg_t const&, SAInner&, int&&>&&,
+                                 std::tuple<int const&&>&&
+              >(O, ptr)));
+        A.destroy(ptr);
+        std::free(ptr);
+    }
+}
+int main() {
+    test_no_inner_alloc();
+    test_with_inner_alloc();
+}
Index: test/std/utilities/allocator.adaptor/allocator.adaptor.members/construct_pair_rvalue.pass.cpp
===================================================================
--- /dev/null
+++ test/std/utilities/allocator.adaptor/allocator.adaptor.members/construct_pair_rvalue.pass.cpp
@@ -0,0 +1,152 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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 U1, class U2>
+// void scoped_allocator_adaptor::construct(pair<U1, U2>*, pair<T1, T2>&&)
+
+#include <scoped_allocator>
+#include <type_traits>
+#include <utility>
+#include <tuple>
+#include <cassert>
+#include <cstdlib>
+#include "uses_alloc_types.hpp"
+#include "controlled_allocators.hpp"
+
+
+void test_no_inner_alloc()
+{
+    using VoidAlloc = CountingAllocator<void>;
+    AllocController P;
+    {
+        using T = UsesAllocatorV1<VoidAlloc, 1>;
+        using U = UsesAllocatorV2<VoidAlloc, 1>;
+        using Pair = std::pair<T, U>;
+        using PairIn = std::pair<int&, int const&&>;
+        int x = 42;
+        const int y = 101;
+        using Alloc = CountingAllocator<Pair>;
+        using SA = std::scoped_allocator_adaptor<Alloc>;
+        static_assert(std::uses_allocator<T, CountingAllocator<T> >::value, "");
+        Pair * ptr = (Pair*)std::malloc(sizeof(Pair));
+        Alloc CA(P);
+        SA A(CA);
+        PairIn in(x, std::move(y));
+        A.construct(ptr, std::move(in));
+        assert(checkConstruct<int&>(ptr->first, UA_AllocArg, CA));
+        assert(checkConstruct<int const&&>(ptr->second, UA_AllocLast, CA));
+        assert((P.checkConstruct<std::piecewise_construct_t const&,
+                                 std::tuple<std::allocator_arg_t const&, SA&, int&>&&,
+                                 std::tuple<int const&&, SA&>&&
+              >(CA, ptr)));
+
+    }
+    P.reset();
+    {
+        using T = UsesAllocatorV3<VoidAlloc, 1>;
+        using U = NotUsesAllocator<VoidAlloc, 1>;
+        using Pair = std::pair<T, U>;
+        using PairIn = std::pair<int, int const&>;
+        int x = 42;
+        const int y = 101;
+        using Alloc = CountingAllocator<Pair>;
+        using SA = std::scoped_allocator_adaptor<Alloc>;
+        static_assert(std::uses_allocator<T, CountingAllocator<T> >::value, "");
+        Pair * ptr = (Pair*)std::malloc(sizeof(Pair));
+        Alloc CA(P);
+        SA A(CA);
+        PairIn in(x, y);
+        A.construct(ptr, std::move(in));
+        assert(checkConstruct<int&&>(ptr->first, UA_AllocArg, CA));
+        assert(checkConstruct<int const&>(ptr->second, UA_None));
+        assert((P.checkConstruct<std::piecewise_construct_t const&,
+                                 std::tuple<std::allocator_arg_t const&, SA&, int&&>&&,
+                                 std::tuple<int const&>&&
+                   >(CA, ptr)));
+        assert(P.construct_called == 1);
+    }
+}
+
+void test_with_inner_alloc()
+{
+    using VoidAlloc1 = CountingAllocator<void, 1>;
+    using VoidAlloc2 = CountingAllocator<void, 2>;
+
+    AllocController POuter;
+    AllocController PInner;
+    {
+        using T = UsesAllocatorV1<VoidAlloc2, 1>;
+        using U = UsesAllocatorV2<VoidAlloc2, 1>;
+        using Pair = std::pair<T, U>;
+        using PairIn = std::pair<int&, int const&&>;
+        int x = 42;
+        int y = 101;
+        using Outer = CountingAllocator<Pair, 1>;
+        using Inner = CountingAllocator<Pair, 2>;
+        using SA = std::scoped_allocator_adaptor<Outer, Inner>;
+        using SAInner = std::scoped_allocator_adaptor<Inner>;
+        static_assert(!std::uses_allocator<T, Outer>::value, "");
+        static_assert(std::uses_allocator<T, Inner>::value, "");
+        Pair * ptr = (Pair*)std::malloc(sizeof(Pair));
+        Outer O(POuter);
+        Inner I(PInner);
+        SA A(O, I);
+        PairIn in(x, std::move(y));
+        A.construct(ptr, std::move(in));
+        assert(checkConstruct<int&>(ptr->first, UA_AllocArg, I));
+        assert(checkConstruct<int const&&>(ptr->second, UA_AllocLast));
+        assert((POuter.checkConstruct<std::piecewise_construct_t const&,
+                                 std::tuple<std::allocator_arg_t const&, SAInner&, int&>&&,
+                                 std::tuple<int const&&, SAInner&>&&
+              >(O, ptr)));
+        A.destroy(ptr);
+        std::free(ptr);
+    }
+    PInner.reset();
+    POuter.reset();
+    {
+        using T = UsesAllocatorV3<VoidAlloc2, 1>;
+        using U = NotUsesAllocator<VoidAlloc2, 1>;
+        using Pair = std::pair<T, U>;
+        using PairIn = std::pair<int, int const &>;
+        int x = 42;
+        int y = 101;
+        using Outer = CountingAllocator<Pair, 1>;
+        using Inner = CountingAllocator<Pair, 2>;
+        using SA = std::scoped_allocator_adaptor<Outer, Inner>;
+        using SAInner = std::scoped_allocator_adaptor<Inner>;
+        static_assert(!std::uses_allocator<T, Outer>::value, "");
+        static_assert(std::uses_allocator<T, Inner>::value, "");
+        Pair * ptr = (Pair*)std::malloc(sizeof(Pair));
+        Outer O(POuter);
+        Inner I(PInner);
+        SA A(O, I);
+        PairIn in(x, y);
+        A.construct(ptr, std::move(in));
+        assert(checkConstruct<int&&>(ptr->first, UA_AllocArg, I));
+        assert(checkConstruct<int const&>(ptr->second, UA_None));
+        assert((POuter.checkConstruct<std::piecewise_construct_t const&,
+                                 std::tuple<std::allocator_arg_t const&, SAInner&, int&&>&&,
+                                 std::tuple<int const&>&&
+              >(O, ptr)));
+        A.destroy(ptr);
+        std::free(ptr);
+    }
+}
+int main() {
+    test_no_inner_alloc();
+    test_with_inner_alloc();
+}
Index: test/std/utilities/allocator.adaptor/allocator.adaptor.members/construct_pair_piecewise.pass.cpp
===================================================================
--- /dev/null
+++ test/std/utilities/allocator.adaptor/allocator.adaptor.members/construct_pair_piecewise.pass.cpp
@@ -0,0 +1,153 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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 U1, class U2, class ...Args1, class ...Args2>
+// void scoped_allocator_adaptor::construct(pair<U1, U2>*,
+//     piecewise_construct_t, tuple<Args1...>, tuple<Args2...>)
+
+#include <scoped_allocator>
+#include <type_traits>
+#include <utility>
+#include <tuple>
+#include <cassert>
+#include <cstdlib>
+#include "uses_alloc_types.hpp"
+#include "controlled_allocators.hpp"
+
+
+void test_no_inner_alloc()
+{
+    using VoidAlloc = CountingAllocator<void>;
+    AllocController P;
+    {
+        using T = UsesAllocatorV1<VoidAlloc, 1>;
+        using U = UsesAllocatorV2<VoidAlloc, 1>;
+        using Pair = std::pair<T, U>;
+        int x = 42;
+        const int y = 101;
+        using Alloc = CountingAllocator<Pair>;
+        using SA = std::scoped_allocator_adaptor<Alloc>;
+        static_assert(std::uses_allocator<T, CountingAllocator<T> >::value, "");
+        Pair * ptr = (Pair*)std::malloc(sizeof(Pair));
+        Alloc CA(P);
+        SA A(CA);
+        A.construct(ptr, std::piecewise_construct,
+                    std::forward_as_tuple(x),
+                    std::forward_as_tuple(std::move(y)));
+        assert(checkConstruct<int&>(ptr->first, UA_AllocArg, CA));
+        assert(checkConstruct<int const&&>(ptr->second, UA_AllocLast, CA));
+        assert((P.checkConstruct<std::piecewise_construct_t const&,
+                                 std::tuple<std::allocator_arg_t const&, SA&, int&>&&,
+                                 std::tuple<int const&&, SA&>&&
+              >(CA, ptr)));
+
+    }
+    P.reset();
+    {
+        using T = UsesAllocatorV3<VoidAlloc, 1>;
+        using U = NotUsesAllocator<VoidAlloc, 1>;
+        using Pair = std::pair<T, U>;
+        int x = 42;
+        const int y = 101;
+        using Alloc = CountingAllocator<Pair>;
+        using SA = std::scoped_allocator_adaptor<Alloc>;
+        static_assert(std::uses_allocator<T, CountingAllocator<T> >::value, "");
+        Pair * ptr = (Pair*)std::malloc(sizeof(Pair));
+        Alloc CA(P);
+        SA A(CA);
+        A.construct(ptr, std::piecewise_construct,
+                    std::forward_as_tuple(std::move(x)),
+                    std::forward_as_tuple(y));
+        assert(checkConstruct<int&&>(ptr->first, UA_AllocArg, CA));
+        assert(checkConstruct<int const&>(ptr->second, UA_None));
+        assert((P.checkConstruct<std::piecewise_construct_t const&,
+                                 std::tuple<std::allocator_arg_t const&, SA&, int&&>&&,
+                                 std::tuple<int const&>&&
+                   >(CA, ptr)));
+        assert(P.construct_called == 1);
+    }
+}
+
+void test_with_inner_alloc()
+{
+    using VoidAlloc1 = CountingAllocator<void, 1>;
+    using VoidAlloc2 = CountingAllocator<void, 2>;
+
+    AllocController POuter;
+    AllocController PInner;
+    {
+        using T = UsesAllocatorV1<VoidAlloc2, 1>;
+        using U = UsesAllocatorV2<VoidAlloc2, 1>;
+        using Pair = std::pair<T, U>;
+        int x = 42;
+        int y = 101;
+        using Outer = CountingAllocator<Pair, 1>;
+        using Inner = CountingAllocator<Pair, 2>;
+        using SA = std::scoped_allocator_adaptor<Outer, Inner>;
+        using SAInner = std::scoped_allocator_adaptor<Inner>;
+        static_assert(!std::uses_allocator<T, Outer>::value, "");
+        static_assert(std::uses_allocator<T, Inner>::value, "");
+        Pair * ptr = (Pair*)std::malloc(sizeof(Pair));
+        Outer O(POuter);
+        Inner I(PInner);
+        SA A(O, I);
+        A.construct(ptr, std::piecewise_construct,
+                    std::forward_as_tuple(x),
+                    std::forward_as_tuple(std::move(y)));
+        assert(checkConstruct<int&>(ptr->first, UA_AllocArg, I));
+        assert(checkConstruct<int &&>(ptr->second, UA_AllocLast));
+        assert((POuter.checkConstruct<std::piecewise_construct_t const&,
+                                 std::tuple<std::allocator_arg_t const&, SAInner&, int&>&&,
+                                 std::tuple<int &&, SAInner&>&&
+              >(O, ptr)));
+        A.destroy(ptr);
+        std::free(ptr);
+    }
+    PInner.reset();
+    POuter.reset();
+    {
+        using T = UsesAllocatorV3<VoidAlloc2, 1>;
+        using U = NotUsesAllocator<VoidAlloc2, 1>;
+        using Pair = std::pair<T, U>;
+        int x = 42;
+        const int y = 101;
+        using Outer = CountingAllocator<Pair, 1>;
+        using Inner = CountingAllocator<Pair, 2>;
+        using SA = std::scoped_allocator_adaptor<Outer, Inner>;
+        using SAInner = std::scoped_allocator_adaptor<Inner>;
+        static_assert(!std::uses_allocator<T, Outer>::value, "");
+        static_assert(std::uses_allocator<T, Inner>::value, "");
+        Pair * ptr = (Pair*)std::malloc(sizeof(Pair));
+        Outer O(POuter);
+        Inner I(PInner);
+        SA A(O, I);
+        A.construct(ptr, std::piecewise_construct,
+                    std::forward_as_tuple(std::move(x)),
+                    std::forward_as_tuple(std::move(y)));
+        assert(checkConstruct<int&&>(ptr->first, UA_AllocArg, I));
+        assert(checkConstruct<int const&&>(ptr->second, UA_None));
+        assert((POuter.checkConstruct<std::piecewise_construct_t const&,
+                                 std::tuple<std::allocator_arg_t const&, SAInner&, int&&>&&,
+                                 std::tuple<int const&&>&&
+              >(O, ptr)));
+        A.destroy(ptr);
+        std::free(ptr);
+    }
+}
+int main() {
+    test_no_inner_alloc();
+    test_with_inner_alloc();
+}
Index: test/std/utilities/allocator.adaptor/allocator.adaptor.members/construct_pair_const_lvalue_pair.pass.cpp
===================================================================
--- /dev/null
+++ test/std/utilities/allocator.adaptor/allocator.adaptor.members/construct_pair_const_lvalue_pair.pass.cpp
@@ -0,0 +1,152 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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 U1, class U2>
+// void scoped_allocator_adaptor::construct(pair<U1, U2>*, pair<T1, T2>const&)
+
+#include <scoped_allocator>
+#include <type_traits>
+#include <utility>
+#include <tuple>
+#include <cassert>
+#include <cstdlib>
+#include "uses_alloc_types.hpp"
+#include "controlled_allocators.hpp"
+
+
+void test_no_inner_alloc()
+{
+    using VoidAlloc = CountingAllocator<void>;
+    AllocController P;
+    {
+        using T = UsesAllocatorV1<VoidAlloc, 1>;
+        using U = UsesAllocatorV2<VoidAlloc, 1>;
+        using Pair = std::pair<T, U>;
+        using PairIn = std::pair<int&, int const&&>;
+        int x = 42;
+        const int y = 101;
+        using Alloc = CountingAllocator<Pair>;
+        using SA = std::scoped_allocator_adaptor<Alloc>;
+        static_assert(std::uses_allocator<T, CountingAllocator<T> >::value, "");
+        Pair * ptr = (Pair*)std::malloc(sizeof(Pair));
+        Alloc CA(P);
+        SA A(CA);
+        const PairIn in(x, std::move(y));
+        A.construct(ptr, in);
+        assert(checkConstruct<int&>(ptr->first, UA_AllocArg, CA));
+        assert(checkConstruct<int const&>(ptr->second, UA_AllocLast, CA));
+        assert((P.checkConstruct<std::piecewise_construct_t const&,
+                                 std::tuple<std::allocator_arg_t const&, SA&, int&>&&,
+                                 std::tuple<int const&, SA&>&&
+              >(CA, ptr)));
+
+    }
+    P.reset();
+    {
+        using T = UsesAllocatorV3<VoidAlloc, 1>;
+        using U = NotUsesAllocator<VoidAlloc, 1>;
+        using Pair = std::pair<T, U>;
+        using PairIn = std::pair<int, int const&>;
+        int x = 42;
+        const int y = 101;
+        using Alloc = CountingAllocator<Pair>;
+        using SA = std::scoped_allocator_adaptor<Alloc>;
+        static_assert(std::uses_allocator<T, CountingAllocator<T> >::value, "");
+        Pair * ptr = (Pair*)std::malloc(sizeof(Pair));
+        Alloc CA(P);
+        SA A(CA);
+        const PairIn in(x, y);
+        A.construct(ptr, in);
+        assert(checkConstruct<int const&>(ptr->first, UA_AllocArg, CA));
+        assert(checkConstruct<int const&>(ptr->second, UA_None));
+        assert((P.checkConstruct<std::piecewise_construct_t const&,
+                                 std::tuple<std::allocator_arg_t const&, SA&, int const&>&&,
+                                 std::tuple<int const&>&&
+                   >(CA, ptr)));
+        assert(P.construct_called == 1);
+    }
+}
+
+void test_with_inner_alloc()
+{
+    using VoidAlloc1 = CountingAllocator<void, 1>;
+    using VoidAlloc2 = CountingAllocator<void, 2>;
+
+    AllocController POuter;
+    AllocController PInner;
+    {
+        using T = UsesAllocatorV1<VoidAlloc2, 1>;
+        using U = UsesAllocatorV2<VoidAlloc2, 1>;
+        using Pair = std::pair<T, U>;
+        using PairIn = std::pair<int&, int const&&>;
+        int x = 42;
+        int y = 101;
+        using Outer = CountingAllocator<Pair, 1>;
+        using Inner = CountingAllocator<Pair, 2>;
+        using SA = std::scoped_allocator_adaptor<Outer, Inner>;
+        using SAInner = std::scoped_allocator_adaptor<Inner>;
+        static_assert(!std::uses_allocator<T, Outer>::value, "");
+        static_assert(std::uses_allocator<T, Inner>::value, "");
+        Pair * ptr = (Pair*)std::malloc(sizeof(Pair));
+        Outer O(POuter);
+        Inner I(PInner);
+        SA A(O, I);
+        const PairIn in(x, std::move(y));
+        A.construct(ptr, in);
+        assert(checkConstruct<int&>(ptr->first, UA_AllocArg, I));
+        assert(checkConstruct<int const&>(ptr->second, UA_AllocLast));
+        assert((POuter.checkConstruct<std::piecewise_construct_t const&,
+                                 std::tuple<std::allocator_arg_t const&, SAInner&, int&>&&,
+                                 std::tuple<int const&, SAInner&>&&
+              >(O, ptr)));
+        A.destroy(ptr);
+        std::free(ptr);
+    }
+    PInner.reset();
+    POuter.reset();
+    {
+        using T = UsesAllocatorV3<VoidAlloc2, 1>;
+        using U = NotUsesAllocator<VoidAlloc2, 1>;
+        using Pair = std::pair<T, U>;
+        using PairIn = std::pair<int, int const &>;
+        int x = 42;
+        int y = 101;
+        using Outer = CountingAllocator<Pair, 1>;
+        using Inner = CountingAllocator<Pair, 2>;
+        using SA = std::scoped_allocator_adaptor<Outer, Inner>;
+        using SAInner = std::scoped_allocator_adaptor<Inner>;
+        static_assert(!std::uses_allocator<T, Outer>::value, "");
+        static_assert(std::uses_allocator<T, Inner>::value, "");
+        Pair * ptr = (Pair*)std::malloc(sizeof(Pair));
+        Outer O(POuter);
+        Inner I(PInner);
+        SA A(O, I);
+        const PairIn in(x, y);
+        A.construct(ptr, in);
+        assert(checkConstruct<int const&>(ptr->first, UA_AllocArg, I));
+        assert(checkConstruct<int const&>(ptr->second, UA_None));
+        assert((POuter.checkConstruct<std::piecewise_construct_t const&,
+                                 std::tuple<std::allocator_arg_t const&, SAInner&, int const&>&&,
+                                 std::tuple<int const&>&&
+              >(O, ptr)));
+        A.destroy(ptr);
+        std::free(ptr);
+    }
+}
+int main() {
+    test_no_inner_alloc();
+    test_with_inner_alloc();
+}
Index: test/std/utilities/allocator.adaptor/allocator.adaptor.members/construct_pair.pass.cpp
===================================================================
--- /dev/null
+++ test/std/utilities/allocator.adaptor/allocator.adaptor.members/construct_pair.pass.cpp
@@ -0,0 +1,136 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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 U1, class U2>
+// void scoped_allocator_adaptor::construct(pair<U1, U2>*)
+
+#include <scoped_allocator>
+#include <type_traits>
+#include <utility>
+#include <tuple>
+#include <cassert>
+#include <cstdlib>
+#include "uses_alloc_types.hpp"
+#include "controlled_allocators.hpp"
+
+
+void test_no_inner_alloc()
+{
+    using VoidAlloc = CountingAllocator<void>;
+    AllocController P;
+    {
+        using T = UsesAllocatorV1<VoidAlloc, 0>;
+        using U = UsesAllocatorV2<VoidAlloc, 0>;
+        using Pair = std::pair<T, U>;
+        using Alloc = CountingAllocator<Pair>;
+        using SA = std::scoped_allocator_adaptor<Alloc>;
+        static_assert(std::uses_allocator<T, CountingAllocator<T> >::value, "");
+        Pair * ptr = (Pair*)std::malloc(sizeof(Pair));
+        Alloc CA(P);
+        SA A(CA);
+        A.construct(ptr);
+        assert(checkConstruct<>(ptr->first, UA_AllocArg, CA));
+        assert(checkConstruct<>(ptr->second, UA_AllocLast, CA));
+        assert((P.checkConstruct<std::piecewise_construct_t const&,
+                                 std::tuple<std::allocator_arg_t const&, SA&>&&,
+                                 std::tuple<SA&>&&
+              >(CA, ptr)));
+
+    }
+    P.reset();
+    {
+        using T = UsesAllocatorV3<VoidAlloc, 0>;
+        using U = NotUsesAllocator<VoidAlloc, 0>;
+        using Pair = std::pair<T, U>;
+        using Alloc = CountingAllocator<Pair>;
+        using SA = std::scoped_allocator_adaptor<Alloc>;
+        static_assert(std::uses_allocator<T, CountingAllocator<T> >::value, "");
+        Pair * ptr = (Pair*)std::malloc(sizeof(Pair));
+        Alloc CA(P);
+        SA A(CA);
+        A.construct(ptr);
+        assert(checkConstruct<>(ptr->first, UA_AllocArg, CA));
+        assert(checkConstruct<>(ptr->second, UA_None));
+        assert((P.checkConstruct<std::piecewise_construct_t const&,
+                                 std::tuple<std::allocator_arg_t const&, SA&>&&,
+                                 std::tuple<>&&
+                   >(CA, ptr)));
+        assert(P.construct_called == 1);
+    }
+}
+
+void test_with_inner_alloc()
+{
+    using VoidAlloc1 = CountingAllocator<void, 1>;
+    using VoidAlloc2 = CountingAllocator<void, 2>;
+
+    AllocController POuter;
+    AllocController PInner;
+    {
+        using T = UsesAllocatorV1<VoidAlloc2, 0>;
+        using U = UsesAllocatorV2<VoidAlloc2, 0>;
+        using Pair = std::pair<T, U>;
+        using Outer = CountingAllocator<Pair, 1>;
+        using Inner = CountingAllocator<Pair, 2>;
+        using SA = std::scoped_allocator_adaptor<Outer, Inner>;
+        using SAInner = std::scoped_allocator_adaptor<Inner>;
+        static_assert(!std::uses_allocator<T, Outer>::value, "");
+        static_assert(std::uses_allocator<T, Inner>::value, "");
+        Pair * ptr = (Pair*)std::malloc(sizeof(Pair));
+        Outer O(POuter);
+        Inner I(PInner);
+        SA A(O, I);
+        A.construct(ptr);
+        assert(checkConstruct<>(ptr->first, UA_AllocArg, I));
+        assert(checkConstruct<>(ptr->second, UA_AllocLast));
+        assert((POuter.checkConstruct<std::piecewise_construct_t const&,
+                                 std::tuple<std::allocator_arg_t const&, SAInner&>&&,
+                                 std::tuple<SAInner&>&&
+              >(O, ptr)));
+        A.destroy(ptr);
+        std::free(ptr);
+    }
+    PInner.reset();
+    POuter.reset();
+    {
+        using T = UsesAllocatorV3<VoidAlloc2, 0>;
+        using U = NotUsesAllocator<VoidAlloc2, 0>;
+        using Pair = std::pair<T, U>;
+        using Outer = CountingAllocator<Pair, 1>;
+        using Inner = CountingAllocator<Pair, 2>;
+        using SA = std::scoped_allocator_adaptor<Outer, Inner>;
+        using SAInner = std::scoped_allocator_adaptor<Inner>;
+        static_assert(!std::uses_allocator<T, Outer>::value, "");
+        static_assert(std::uses_allocator<T, Inner>::value, "");
+        Pair * ptr = (Pair*)std::malloc(sizeof(Pair));
+        Outer O(POuter);
+        Inner I(PInner);
+        SA A(O, I);
+        A.construct(ptr);
+        assert(checkConstruct<>(ptr->first, UA_AllocArg, I));
+        assert(checkConstruct<>(ptr->second, UA_None));
+        assert((POuter.checkConstruct<std::piecewise_construct_t const&,
+                                 std::tuple<std::allocator_arg_t const&, SAInner&>&&,
+                                 std::tuple<>&&
+              >(O, ptr)));
+        A.destroy(ptr);
+        std::free(ptr);
+    }
+}
+int main() {
+    test_no_inner_alloc();
+    test_with_inner_alloc();
+}
Index: include/scoped_allocator
===================================================================
--- include/scoped_allocator
+++ include/scoped_allocator
@@ -500,6 +500,56 @@
         void construct(_Tp* __p, _Args&& ...__args)
             {__construct(__uses_alloc_ctor<_Tp, inner_allocator_type, _Args...>(),
                          __p, _VSTD::forward<_Args>(__args)...);}
+
+    template <class _T1, class _T2, class... _Args1, class... _Args2>
+    void construct(pair<_T1, _T2>* __p, piecewise_construct_t,
+                       tuple<_Args1...> __x, tuple<_Args2...> __y)
+    {
+        typedef __outermost<outer_allocator_type> _OM;
+        allocator_traits<typename _OM::type>::construct(
+            _OM()(outer_allocator()), __p, piecewise_construct
+          , __transform_tuple(
+              typename __uses_alloc_ctor<
+                  _T1, inner_allocator_type, _Args1...
+              >::type()
+            , _VSTD::move(__x)
+            , typename __make_tuple_indices<sizeof...(_Args1)>::type{}
+          )
+          , __transform_tuple(
+              typename __uses_alloc_ctor<
+                  _T2, inner_allocator_type, _Args2...
+              >::type()
+            , _VSTD::move(__y)
+            , typename __make_tuple_indices<sizeof...(_Args2)>::type{}
+          )
+        );
+    }
+
+    template <class _T1, class _T2>
+    void construct(pair<_T1, _T2>* __p)
+    { construct(__p, piecewise_construct, tuple<>{}, tuple<>{}); }
+
+    template <class _T1, class _T2, class _Up, class _Vp>
+    void construct(pair<_T1, _T2>* __p, _Up&& __x, _Vp&& __y) {
+        construct(__p, piecewise_construct,
+                  _VSTD::forward_as_tuple(_VSTD::forward<_Up>(__x)),
+                  _VSTD::forward_as_tuple(_VSTD::forward<_Vp>(__y)));
+    }
+
+    template <class _T1, class _T2, class _Up, class _Vp>
+    void construct(pair<_T1, _T2>* __p, const pair<_Up, _Vp>& __x) {
+        construct(__p, piecewise_construct,
+                  _VSTD::forward_as_tuple(__x.first),
+                  _VSTD::forward_as_tuple(__x.second));
+    }
+
+    template <class _T1, class _T2, class _Up, class _Vp>
+    void construct(pair<_T1, _T2>* __p, pair<_Up, _Vp>&& __x) {
+        construct(__p, piecewise_construct,
+                  _VSTD::forward_as_tuple(_VSTD::forward<_Up>(__x.first)),
+                  _VSTD::forward_as_tuple(_VSTD::forward<_Vp>(__x.second)));
+    }
+
     template <class _Tp>
         _LIBCPP_INLINE_VISIBILITY
         void destroy(_Tp* __p)
@@ -515,6 +565,7 @@
 
 private:
 
+
     template <class _OuterA2,
               class = typename enable_if<
                         is_constructible<outer_allocator_type, _OuterA2>::value
@@ -566,6 +617,36 @@
                 );
             }
 
+    template <class ..._Args, size_t ..._Idx>
+    _LIBCPP_INLINE_VISIBILITY
+    tuple<_Args&&...>
+    __transform_tuple(integral_constant<int, 0>, tuple<_Args...>&& __t,
+                      __tuple_indices<_Idx...>)
+    {
+        return _VSTD::forward_as_tuple(_VSTD::get<_Idx>(_VSTD::move(__t))...);
+    }
+
+    template <class ..._Args, size_t ..._Idx>
+    _LIBCPP_INLINE_VISIBILITY
+    tuple<allocator_arg_t const&, inner_allocator_type&, _Args&&...>
+    __transform_tuple(integral_constant<int, 1>, tuple<_Args...> && __t,
+                      __tuple_indices<_Idx...>)
+    {
+        using _Tup = tuple<allocator_arg_t const&, inner_allocator_type&, _Args&&...>;
+        return _Tup(allocator_arg, inner_allocator(),
+                    _VSTD::get<_Idx>(_VSTD::move(__t))...);
+    }
+
+    template <class ..._Args, size_t ..._Idx>
+    _LIBCPP_INLINE_VISIBILITY
+    tuple<_Args&&..., inner_allocator_type&>
+    __transform_tuple(integral_constant<int, 2>, tuple<_Args...> && __t,
+                      __tuple_indices<_Idx...>)
+    {
+        using _Tup = tuple<_Args&&..., inner_allocator_type&>;
+        return _Tup(_VSTD::get<_Idx>(_VSTD::move(__t))..., inner_allocator());
+    }
+
     template <class...> friend class __scoped_allocator_storage;
 };
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to