[libcxx-commits] [libcxx] r363968 - [libc++] Take 2: Implement CTAD for map and multimap

Louis Dionne via libcxx-commits libcxx-commits at lists.llvm.org
Thu Jun 20 12:32:00 PDT 2019


Author: ldionne
Date: Thu Jun 20 12:32:00 2019
New Revision: 363968

URL: http://llvm.org/viewvc/llvm-project?rev=363968&view=rev
Log:
[libc++] Take 2: Implement CTAD for map and multimap

This is a re-application of r362986 (which was reverted in r363688) with fixes
for the issue that caused it to be reverted.

Thanks to Arthur O'Dwyer for the patch.

Differential Revision: https://reviews.llvm.org/D58587

Added:
    libcxx/trunk/test/std/containers/associative/map/map.cons/deduct.fail.cpp
    libcxx/trunk/test/std/containers/associative/map/map.cons/deduct.pass.cpp
    libcxx/trunk/test/std/containers/associative/map/map.cons/deduct_const.pass.cpp
    libcxx/trunk/test/std/containers/associative/multimap/multimap.cons/deduct.fail.cpp
    libcxx/trunk/test/std/containers/associative/multimap/multimap.cons/deduct.pass.cpp
    libcxx/trunk/test/std/containers/associative/multimap/multimap.cons/deduct_const.pass.cpp
Modified:
    libcxx/trunk/include/iterator
    libcxx/trunk/include/map

Modified: libcxx/trunk/include/iterator
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/iterator?rev=363968&r1=363967&r2=363968&view=diff
==============================================================================
--- libcxx/trunk/include/iterator (original)
+++ libcxx/trunk/include/iterator Thu Jun 20 12:32:00 2019
@@ -538,6 +538,22 @@ struct __is_exactly_input_iterator
          __has_iterator_category_convertible_to<_Tp, input_iterator_tag>::value &&
         !__has_iterator_category_convertible_to<_Tp, forward_iterator_tag>::value> {};
 
+#ifndef _LIBCPP_HAS_NO_DEDUCTION_GUIDES
+template<class _InputIterator>
+using __iter_value_type = typename iterator_traits<_InputIterator>::value_type;
+
+template<class _InputIterator>
+using __iter_key_type = remove_const_t<typename iterator_traits<_InputIterator>::value_type::first_type>;
+
+template<class _InputIterator>
+using __iter_mapped_type = typename iterator_traits<_InputIterator>::value_type::second_type;
+
+template<class _InputIterator>
+using __iter_to_alloc_type = pair<
+    add_const_t<typename iterator_traits<_InputIterator>::value_type::first_type>,
+    typename iterator_traits<_InputIterator>::value_type::second_type>;
+#endif
+
 template<class _Category, class _Tp, class _Distance = ptrdiff_t,
          class _Pointer = _Tp*, class _Reference = _Tp&>
 struct _LIBCPP_TEMPLATE_VIS iterator

Modified: libcxx/trunk/include/map
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/map?rev=363968&r1=363967&r2=363968&view=diff
==============================================================================
--- libcxx/trunk/include/map (original)
+++ libcxx/trunk/include/map Thu Jun 20 12:32:00 2019
@@ -902,8 +902,8 @@ public:
     typedef _Key                                     key_type;
     typedef _Tp                                      mapped_type;
     typedef pair<const key_type, mapped_type>        value_type;
-    typedef _Compare                                 key_compare;
-    typedef _Allocator                               allocator_type;
+    typedef typename __identity<_Compare>::type      key_compare;
+    typedef typename __identity<_Allocator>::type    allocator_type;
     typedef value_type&                              reference;
     typedef const value_type&                        const_reference;
 
@@ -1465,6 +1465,32 @@ private:
 #endif
 };
 
+#ifndef _LIBCPP_HAS_NO_DEDUCTION_GUIDES
+template<class _InputIterator, class _Compare = less<__iter_key_type<_InputIterator>>,
+         class _Allocator = allocator<__iter_to_alloc_type<_InputIterator>>,
+         class = enable_if_t<!__is_allocator<_Compare>::value, void>,
+         class = enable_if_t<__is_allocator<_Allocator>::value, void>>
+map(_InputIterator, _InputIterator, _Compare = _Compare(), _Allocator = _Allocator())
+  -> map<__iter_key_type<_InputIterator>, __iter_mapped_type<_InputIterator>, _Compare, _Allocator>;
+
+template<class _Key, class _Tp, class _Compare = less<remove_const_t<_Key>>,
+         class _Allocator = allocator<pair<const _Key, _Tp>>,
+         class = enable_if_t<!__is_allocator<_Compare>::value, void>,
+         class = enable_if_t<__is_allocator<_Allocator>::value, void>>
+map(initializer_list<pair<_Key, _Tp>>, _Compare = _Compare(), _Allocator = _Allocator())
+  -> map<remove_const_t<_Key>, _Tp, _Compare, _Allocator>;
+
+template<class _InputIterator, class _Allocator,
+         class = enable_if_t<__is_allocator<_Allocator>::value, void>>
+map(_InputIterator, _InputIterator, _Allocator)
+  -> map<__iter_key_type<_InputIterator>, __iter_mapped_type<_InputIterator>,
+         less<__iter_key_type<_InputIterator>>, _Allocator>;
+
+template<class _Key, class _Tp, class _Allocator,
+         class = enable_if_t<__is_allocator<_Allocator>::value, void>>
+map(initializer_list<pair<_Key, _Tp>>, _Allocator)
+  -> map<remove_const_t<_Key>, _Tp, less<remove_const_t<_Key>>, _Allocator>;
+#endif
 
 #ifndef _LIBCPP_CXX03_LANG
 template <class _Key, class _Tp, class _Compare, class _Allocator>
@@ -1637,8 +1663,8 @@ public:
     typedef _Key                                     key_type;
     typedef _Tp                                      mapped_type;
     typedef pair<const key_type, mapped_type>        value_type;
-    typedef _Compare                                 key_compare;
-    typedef _Allocator                               allocator_type;
+    typedef typename __identity<_Compare>::type      key_compare;
+    typedef typename __identity<_Allocator>::type    allocator_type;
     typedef value_type&                              reference;
     typedef const value_type&                        const_reference;
 
@@ -2090,6 +2116,33 @@ private:
     typedef unique_ptr<__node, _Dp> __node_holder;
 };
 
+#ifndef _LIBCPP_HAS_NO_DEDUCTION_GUIDES
+template<class _InputIterator, class _Compare = less<__iter_key_type<_InputIterator>>,
+         class _Allocator = allocator<__iter_to_alloc_type<_InputIterator>>,
+         class = enable_if_t<!__is_allocator<_Compare>::value, void>,
+         class = enable_if_t<__is_allocator<_Allocator>::value, void>>
+multimap(_InputIterator, _InputIterator, _Compare = _Compare(), _Allocator = _Allocator())
+  -> multimap<__iter_key_type<_InputIterator>, __iter_mapped_type<_InputIterator>, _Compare, _Allocator>;
+
+template<class _Key, class _Tp, class _Compare = less<remove_const_t<_Key>>,
+         class _Allocator = allocator<pair<const _Key, _Tp>>,
+         class = enable_if_t<!__is_allocator<_Compare>::value, void>,
+         class = enable_if_t<__is_allocator<_Allocator>::value, void>>
+multimap(initializer_list<pair<_Key, _Tp>>, _Compare = _Compare(), _Allocator = _Allocator())
+  -> multimap<remove_const_t<_Key>, _Tp, _Compare, _Allocator>;
+
+template<class _InputIterator, class _Allocator,
+         class = enable_if_t<__is_allocator<_Allocator>::value, void>>
+multimap(_InputIterator, _InputIterator, _Allocator)
+  -> multimap<__iter_key_type<_InputIterator>, __iter_mapped_type<_InputIterator>,
+         less<__iter_key_type<_InputIterator>>, _Allocator>;
+
+template<class _Key, class _Tp, class _Allocator,
+         class = enable_if_t<__is_allocator<_Allocator>::value, void>>
+multimap(initializer_list<pair<_Key, _Tp>>, _Allocator)
+  -> multimap<remove_const_t<_Key>, _Tp, less<remove_const_t<_Key>>, _Allocator>;
+#endif
+
 #ifndef _LIBCPP_CXX03_LANG
 template <class _Key, class _Tp, class _Compare, class _Allocator>
 multimap<_Key, _Tp, _Compare, _Allocator>::multimap(multimap&& __m, const allocator_type& __a)

Added: libcxx/trunk/test/std/containers/associative/map/map.cons/deduct.fail.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/containers/associative/map/map.cons/deduct.fail.cpp?rev=363968&view=auto
==============================================================================
--- libcxx/trunk/test/std/containers/associative/map/map.cons/deduct.fail.cpp (added)
+++ libcxx/trunk/test/std/containers/associative/map/map.cons/deduct.fail.cpp Thu Jun 20 12:32:00 2019
@@ -0,0 +1,107 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// <map>
+// UNSUPPORTED: c++98, c++03, c++11, c++14
+// UNSUPPORTED: libcpp-no-deduction-guides
+// XFAIL: clang-6, apple-clang-9.0, apple-clang-9.1, apple-clang-10.0
+//  clang-6 gives different error messages.
+
+// template<class InputIterator,
+//          class Compare = less<iter-value-type<InputIterator>>,
+//          class Allocator = allocator<iter-value-type<InputIterator>>>
+// map(InputIterator, InputIterator,
+//          Compare = Compare(), Allocator = Allocator())
+//   -> map<iter-value-type<InputIterator>, Compare, Allocator>;
+// template<class Key, class Compare = less<Key>, class Allocator = allocator<Key>>
+// map(initializer_list<Key>, Compare = Compare(), Allocator = Allocator())
+//   -> map<Key, Compare, Allocator>;
+// template<class InputIterator, class Allocator>
+// map(InputIterator, InputIterator, Allocator)
+//   -> map<iter-value-type<InputIterator>, less<iter-value-type<InputIterator>>, Allocator>;
+// template<class Key, class Allocator>
+// map(initializer_list<Key>, Allocator)
+//   -> map<Key, less<Key>, Allocator>;
+
+#include <climits> // INT_MAX
+#include <functional>
+#include <map>
+#include <type_traits>
+
+struct NotAnAllocator {
+    friend bool operator<(NotAnAllocator, NotAnAllocator) { return false; }
+};
+
+using P = std::pair<int, long>;
+using PC = std::pair<const int, long>;
+
+int main(int, char**)
+{
+    {
+        // cannot deduce Key and T from nothing
+        std::map m; // expected-error{{no viable constructor or deduction guide for deduction of template arguments of 'map'}}
+    }
+    {
+        // cannot deduce Key and T from just (Compare)
+        std::map m(std::less<int>{});
+            // expected-error at -1{{no viable constructor or deduction guide for deduction of template arguments of 'map'}}
+    }
+    {
+        // cannot deduce Key and T from just (Compare, Allocator)
+        std::map m(std::less<int>{}, std::allocator<PC>{});
+            // expected-error at -1{{no viable constructor or deduction guide for deduction of template arguments of 'map'}}
+    }
+    {
+        // cannot deduce Key and T from just (Allocator)
+        std::map m(std::allocator<PC>{});
+            // expected-error at -1{{no viable constructor or deduction guide for deduction of template arguments of 'map'}}
+    }
+    {
+        // refuse to rebind the allocator if Allocator::value_type is not exactly what we expect
+        const P arr[] = { {1,1L}, {2,2L}, {3,3L} };
+        std::map m(arr, arr + 3, std::allocator<P>());
+            // expected-error-re at map:* {{static_assert failed{{( due to requirement '.*')?}} "Allocator::value_type must be same type as value_type"}}
+    }
+    {
+        // cannot convert from some arbitrary unrelated type
+        NotAnAllocator a;
+        std::map m(a); // expected-error{{no viable constructor or deduction guide for deduction of template arguments of 'map'}}
+    }
+    {
+        // cannot deduce that the inner braced things should be std::pair and not something else
+        std::map m{ {1,1L}, {2,2L}, {3,3L} };
+            // expected-error at -1{{no viable constructor or deduction guide for deduction of template arguments of 'map'}}
+    }
+    {
+        // cannot deduce that the inner braced things should be std::pair and not something else
+        std::map m({ {1,1L}, {2,2L}, {3,3L} }, std::less<int>());
+            // expected-error at -1{{no viable constructor or deduction guide for deduction of template arguments of 'map'}}
+    }
+    {
+        // cannot deduce that the inner braced things should be std::pair and not something else
+        std::map m({ {1,1L}, {2,2L}, {3,3L} }, std::less<int>(), std::allocator<PC>());
+            // expected-error at -1{{no viable constructor or deduction guide for deduction of template arguments of 'map'}}
+    }
+    {
+        // cannot deduce that the inner braced things should be std::pair and not something else
+        std::map m({ {1,1L}, {2,2L}, {3,3L} }, std::allocator<PC>());
+            // expected-error at -1{{no viable constructor or deduction guide for deduction of template arguments of 'map'}}
+    }
+    {
+        // since we have parens, not braces, this deliberately does not find the initializer_list constructor
+        std::map m(P{1,1L});
+            // expected-error at -1{{no viable constructor or deduction guide for deduction of template arguments of 'map'}}
+    }
+    {
+        // since we have parens, not braces, this deliberately does not find the initializer_list constructor
+        std::map m(PC{1,1L});
+            // expected-error at -1{{no viable constructor or deduction guide for deduction of template arguments of 'map'}}
+    }
+
+    return 0;
+}

Added: libcxx/trunk/test/std/containers/associative/map/map.cons/deduct.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/containers/associative/map/map.cons/deduct.pass.cpp?rev=363968&view=auto
==============================================================================
--- libcxx/trunk/test/std/containers/associative/map/map.cons/deduct.pass.cpp (added)
+++ libcxx/trunk/test/std/containers/associative/map/map.cons/deduct.pass.cpp Thu Jun 20 12:32:00 2019
@@ -0,0 +1,137 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// <map>
+// UNSUPPORTED: c++98, c++03, c++11, c++14
+// UNSUPPORTED: libcpp-no-deduction-guides
+
+// template<class InputIterator,
+//          class Compare = less<iter-value-type<InputIterator>>,
+//          class Allocator = allocator<iter-value-type<InputIterator>>>
+// map(InputIterator, InputIterator,
+//          Compare = Compare(), Allocator = Allocator())
+//   -> map<iter-value-type<InputIterator>, Compare, Allocator>;
+// template<class Key, class Compare = less<Key>, class Allocator = allocator<Key>>
+// map(initializer_list<Key>, Compare = Compare(), Allocator = Allocator())
+//   -> map<Key, Compare, Allocator>;
+// template<class InputIterator, class Allocator>
+// map(InputIterator, InputIterator, Allocator)
+//   -> map<iter-value-type<InputIterator>, less<iter-value-type<InputIterator>>, Allocator>;
+// template<class Key, class Allocator>
+// map(initializer_list<Key>, Allocator)
+//   -> map<Key, less<Key>, Allocator>;
+
+#include <algorithm> // std::equal
+#include <cassert>
+#include <climits> // INT_MAX
+#include <functional>
+#include <map>
+#include <type_traits>
+
+#include "test_allocator.h"
+
+using P = std::pair<int, long>;
+using PC = std::pair<const int, long>;
+
+int main(int, char**)
+{
+    {
+    const P arr[] = { {1,1L}, {2,2L}, {1,1L}, {INT_MAX,1L}, {3,1L} };
+    std::map m(std::begin(arr), std::end(arr));
+
+    ASSERT_SAME_TYPE(decltype(m), std::map<int, long>);
+    const PC expected_m[] = { {1,1L}, {2,2L}, {3,1L}, {INT_MAX,1L} };
+    assert(std::equal(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    }
+
+    {
+    const P arr[] = { {1,1L}, {2,2L}, {1,1L}, {INT_MAX,1L}, {3,1L} };
+    std::map m(std::begin(arr), std::end(arr), std::greater<int>());
+
+    ASSERT_SAME_TYPE(decltype(m), std::map<int, long, std::greater<int>>);
+    const PC expected_m[] = { {INT_MAX,1L}, {3,1L}, {2,2L}, {1,1L} };
+    assert(std::equal(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    }
+
+    {
+    const P arr[] = { {1,1L}, {2,2L}, {1,1L}, {INT_MAX,1L}, {3,1L} };
+    std::map m(std::begin(arr), std::end(arr), std::greater<int>(), test_allocator<PC>(0, 42));
+
+    ASSERT_SAME_TYPE(decltype(m), std::map<int, long, std::greater<int>, test_allocator<PC>>);
+    const PC expected_m[] = { {INT_MAX,1L}, {3,1L}, {2,2L}, {1,1L} };
+    assert(std::equal(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    assert(m.get_allocator().get_id() == 42);
+    }
+
+    {
+    std::map<int, long> source;
+    std::map m(source);
+    ASSERT_SAME_TYPE(decltype(m), decltype(source));
+    assert(m.size() == 0);
+    }
+
+    {
+    std::map<int, long> source;
+    std::map m{source};  // braces instead of parens
+    ASSERT_SAME_TYPE(decltype(m), decltype(source));
+    assert(m.size() == 0);
+    }
+
+    {
+    std::map<int, long> source;
+    std::map m(source, std::map<int, long>::allocator_type());
+    ASSERT_SAME_TYPE(decltype(m), decltype(source));
+    assert(m.size() == 0);
+    }
+
+    {
+    std::map m{ P{1,1L}, P{2,2L}, P{1,1L}, P{INT_MAX,1L}, P{3,1L} };
+
+    ASSERT_SAME_TYPE(decltype(m), std::map<int, long>);
+    const PC expected_m[] = { {1,1L}, {2,2L}, {3,1L}, {INT_MAX,1L} };
+    assert(std::equal(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    }
+
+    {
+    std::map m({ P{1,1L}, P{2,2L}, P{1,1L}, P{INT_MAX,1L}, P{3,1L} }, std::greater<int>());
+
+    ASSERT_SAME_TYPE(decltype(m), std::map<int, long, std::greater<int>>);
+    const PC expected_m[] = { {INT_MAX,1L}, {3,1L}, {2,2L}, {1,1L} };
+    assert(std::equal(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    }
+
+    {
+    std::map m({ P{1,1L}, P{2,2L}, P{1,1L}, P{INT_MAX,1L}, P{3,1L} }, std::greater<int>(), test_allocator<PC>(0, 43));
+
+    ASSERT_SAME_TYPE(decltype(m), std::map<int, long, std::greater<int>, test_allocator<PC>>);
+    const PC expected_m[] = { {INT_MAX,1L}, {3,1L}, {2,2L}, {1,1L} };
+    assert(std::equal(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    assert(m.get_allocator().get_id() == 43);
+    }
+
+    {
+    const P arr[] = { {1,1L}, {2,2L}, {1,1L}, {INT_MAX,1L}, {3,1L} };
+    std::map m(std::begin(arr), std::end(arr), test_allocator<PC>(0, 44));
+
+    ASSERT_SAME_TYPE(decltype(m), std::map<int, long, std::less<int>, test_allocator<PC>>);
+    const PC expected_m[] = { {1,1L}, {2,2L}, {3,1L}, {INT_MAX,1L} };
+    assert(std::equal(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    assert(m.get_allocator().get_id() == 44);
+    }
+
+    {
+    std::map m({ P{1,1L}, P{2,2L}, P{1,1L}, P{INT_MAX,1L}, P{3,1L} }, test_allocator<PC>(0, 45));
+
+    ASSERT_SAME_TYPE(decltype(m), std::map<int, long, std::less<int>, test_allocator<PC>>);
+    const PC expected_m[] = { {1,1L}, {2,2L}, {3,1L}, {INT_MAX,1L} };
+    assert(std::equal(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    assert(m.get_allocator().get_id() == 45);
+    }
+
+    return 0;
+}

Added: libcxx/trunk/test/std/containers/associative/map/map.cons/deduct_const.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/containers/associative/map/map.cons/deduct_const.pass.cpp?rev=363968&view=auto
==============================================================================
--- libcxx/trunk/test/std/containers/associative/map/map.cons/deduct_const.pass.cpp (added)
+++ libcxx/trunk/test/std/containers/associative/map/map.cons/deduct_const.pass.cpp Thu Jun 20 12:32:00 2019
@@ -0,0 +1,107 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// <map>
+// UNSUPPORTED: c++98, c++03, c++11, c++14
+// UNSUPPORTED: libcpp-no-deduction-guides
+
+// template<class InputIterator,
+//          class Compare = less<iter-value-type<InputIterator>>,
+//          class Allocator = allocator<iter-value-type<InputIterator>>>
+// map(InputIterator, InputIterator,
+//          Compare = Compare(), Allocator = Allocator())
+//   -> map<iter-value-type<InputIterator>, Compare, Allocator>;
+// template<class Key, class Compare = less<Key>, class Allocator = allocator<Key>>
+// map(initializer_list<Key>, Compare = Compare(), Allocator = Allocator())
+//   -> map<Key, Compare, Allocator>;
+// template<class InputIterator, class Allocator>
+// map(InputIterator, InputIterator, Allocator)
+//   -> map<iter-value-type<InputIterator>, less<iter-value-type<InputIterator>>, Allocator>;
+// template<class Key, class Allocator>
+// map(initializer_list<Key>, Allocator)
+//   -> map<Key, less<Key>, Allocator>;
+
+#include <algorithm> // std::equal
+#include <cassert>
+#include <climits> // INT_MAX
+#include <functional>
+#include <map>
+#include <type_traits>
+
+#include "test_allocator.h"
+
+using P = std::pair<int, long>;
+using PC = std::pair<const int, long>;
+using PCC = std::pair<const int, const long>;
+
+int main(int, char**)
+{
+    {
+    const PCC arr[] = { {1,1L}, {2,2L}, {1,1L}, {INT_MAX,1L}, {3,1L} };
+    std::map m(std::begin(arr), std::end(arr));
+
+    ASSERT_SAME_TYPE(decltype(m), std::map<int, const long>);
+    const PCC expected_m[] = { {1,1L}, {2,2L}, {3,1L}, {INT_MAX,1L} };
+    assert(std::equal(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    }
+
+    {
+    const PCC arr[] = { {1,1L}, {2,2L}, {1,1L}, {INT_MAX,1L}, {3,1L} };
+    std::map m(std::begin(arr), std::end(arr), std::greater<int>());
+
+    ASSERT_SAME_TYPE(decltype(m), std::map<int, const long, std::greater<int>>);
+    const PCC expected_m[] = { {INT_MAX,1L}, {3,1L}, {2,2L}, {1, 1L} };
+    assert(std::equal(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    }
+
+    {
+    const PCC arr[] = { {1,1L}, {2,2L}, {1,1L}, {INT_MAX,1L}, {3,1L} };
+    std::map m(std::begin(arr), std::end(arr), std::greater<int>(), test_allocator<PCC>(0, 42));
+
+    ASSERT_SAME_TYPE(decltype(m), std::map<int, const long, std::greater<int>, test_allocator<PCC>>);
+    const PCC expected_m[] = { {INT_MAX,1L}, {3,1L}, {2,2L}, {1, 1L} };
+    assert(std::equal(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    assert(m.get_allocator().get_id() == 42);
+    }
+
+    {
+    std::map m{ PC{1,1L}, PC{2,2L}, PC{1,1L}, PC{INT_MAX,1L}, PC{3,1L} };
+
+    ASSERT_SAME_TYPE(decltype(m), std::map<int, long>);
+    const PC expected_m[] = { {1, 1L}, {2,2L}, {3,1L}, {INT_MAX,1L} };
+    assert(std::equal(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    }
+
+    {
+    std::map m({ PC{1,1L}, PC{2,2L}, PC{1,1L}, PC{INT_MAX,1L}, PC{3,1L} }, std::greater<int>());
+
+    ASSERT_SAME_TYPE(decltype(m), std::map<int, long, std::greater<int>>);
+    const PC expected_m[] = { {INT_MAX,1L}, {3,1L}, {2,2L}, {1, 1L} };
+    assert(std::equal(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    }
+
+    {
+    std::map m({ PC{1,1L}, PC{2,2L}, PC{1,1L}, PC{INT_MAX,1L}, PC{3,1L} }, std::greater<int>(), test_allocator<PC>(0, 43));
+
+    ASSERT_SAME_TYPE(decltype(m), std::map<int, long, std::greater<int>, test_allocator<PC>>);
+    const PC expected_m[] = { {INT_MAX,1L}, {3,1L}, {2,2L}, {1, 1L} };
+    assert(std::equal(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    assert(m.get_allocator().get_id() == 43);
+    }
+
+    {
+    std::map m({ PC{1,1L}, PC{2,2L}, PC{1,1L}, PC{INT_MAX,1L}, PC{3,1L} }, test_allocator<PC>(0, 45));
+
+    ASSERT_SAME_TYPE(decltype(m), std::map<int, long, std::less<int>, test_allocator<PC>>);
+    const PC expected_m[] = { {1, 1L}, {2,2L}, {3,1L}, {INT_MAX,1L} };
+    assert(std::equal(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    assert(m.get_allocator().get_id() == 45);
+    }
+
+    return 0;
+}

Added: libcxx/trunk/test/std/containers/associative/multimap/multimap.cons/deduct.fail.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/containers/associative/multimap/multimap.cons/deduct.fail.cpp?rev=363968&view=auto
==============================================================================
--- libcxx/trunk/test/std/containers/associative/multimap/multimap.cons/deduct.fail.cpp (added)
+++ libcxx/trunk/test/std/containers/associative/multimap/multimap.cons/deduct.fail.cpp Thu Jun 20 12:32:00 2019
@@ -0,0 +1,107 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// <map>
+// UNSUPPORTED: c++98, c++03, c++11, c++14
+// UNSUPPORTED: libcpp-no-deduction-guides
+// XFAIL: clang-6, apple-clang-9.0, apple-clang-9.1, apple-clang-10.0
+//  clang-6 gives different error messages.
+
+// template<class InputIterator,
+//          class Compare = less<iter-value-type<InputIterator>>,
+//          class Allocator = allocator<iter-value-type<InputIterator>>>
+// multimap(InputIterator, InputIterator,
+//          Compare = Compare(), Allocator = Allocator())
+//   -> multimap<iter-value-type<InputIterator>, Compare, Allocator>;
+// template<class Key, class Compare = less<Key>, class Allocator = allocator<Key>>
+// multimap(initializer_list<Key>, Compare = Compare(), Allocator = Allocator())
+//   -> multimap<Key, Compare, Allocator>;
+// template<class InputIterator, class Allocator>
+// multimap(InputIterator, InputIterator, Allocator)
+//   -> multimap<iter-value-type<InputIterator>, less<iter-value-type<InputIterator>>, Allocator>;
+// template<class Key, class Allocator>
+// multimap(initializer_list<Key>, Allocator)
+//   -> multimap<Key, less<Key>, Allocator>;
+
+#include <climits> // INT_MAX
+#include <functional>
+#include <map>
+#include <type_traits>
+
+struct NotAnAllocator {
+    friend bool operator<(NotAnAllocator, NotAnAllocator) { return false; }
+};
+
+using P = std::pair<int, long>;
+using PC = std::pair<const int, long>;
+
+int main(int, char**)
+{
+    {
+        // cannot deduce Key and T from nothing
+        std::multimap m; // expected-error{{no viable constructor or deduction guide for deduction of template arguments of 'multimap'}}
+    }
+    {
+        // cannot deduce Key and T from just (Compare)
+        std::multimap m(std::less<int>{});
+            // expected-error at -1{{no viable constructor or deduction guide for deduction of template arguments of 'multimap'}}
+    }
+    {
+        // cannot deduce Key and T from just (Compare, Allocator)
+        std::multimap m(std::less<int>{}, std::allocator<PC>{});
+            // expected-error at -1{{no viable constructor or deduction guide for deduction of template arguments of 'multimap'}}
+    }
+    {
+        // cannot deduce Key and T from just (Allocator)
+        std::multimap m(std::allocator<PC>{});
+            // expected-error at -1{{no viable constructor or deduction guide for deduction of template arguments of 'multimap'}}
+    }
+    {
+        // refuse to rebind the allocator if Allocator::value_type is not exactly what we expect
+        const P arr[] = { {1,1L}, {2,2L}, {3,3L} };
+        std::multimap m(arr, arr + 3, std::allocator<P>());
+            // expected-error-re at map:* {{static_assert failed{{( due to requirement '.*')?}} "Allocator::value_type must be same type as value_type"}}
+    }
+    {
+        // cannot convert from some arbitrary unrelated type
+        NotAnAllocator a;
+        std::multimap m(a); // expected-error{{no viable constructor or deduction guide for deduction of template arguments of 'multimap'}}
+    }
+    {
+        // cannot deduce that the inner braced things should be std::pair and not something else
+        std::multimap m{ {1,1L}, {2,2L}, {3,3L} };
+            // expected-error at -1{{no viable constructor or deduction guide for deduction of template arguments of 'multimap'}}
+    }
+    {
+        // cannot deduce that the inner braced things should be std::pair and not something else
+        std::multimap m({ {1,1L}, {2,2L}, {3,3L} }, std::less<int>());
+            // expected-error at -1{{no viable constructor or deduction guide for deduction of template arguments of 'multimap'}}
+    }
+    {
+        // cannot deduce that the inner braced things should be std::pair and not something else
+        std::multimap m({ {1,1L}, {2,2L}, {3,3L} }, std::less<int>(), std::allocator<PC>());
+            // expected-error at -1{{no viable constructor or deduction guide for deduction of template arguments of 'multimap'}}
+    }
+    {
+        // cannot deduce that the inner braced things should be std::pair and not something else
+        std::multimap m({ {1,1L}, {2,2L}, {3,3L} }, std::allocator<PC>());
+            // expected-error at -1{{no viable constructor or deduction guide for deduction of template arguments of 'multimap'}}
+    }
+    {
+        // since we have parens, not braces, this deliberately does not find the initializer_list constructor
+        std::multimap m(P{1,1L});
+            // expected-error at -1{{no viable constructor or deduction guide for deduction of template arguments of 'multimap'}}
+    }
+    {
+        // since we have parens, not braces, this deliberately does not find the initializer_list constructor
+        std::multimap m(PC{1,1L});
+            // expected-error at -1{{no viable constructor or deduction guide for deduction of template arguments of 'multimap'}}
+    }
+
+    return 0;
+}

Added: libcxx/trunk/test/std/containers/associative/multimap/multimap.cons/deduct.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/containers/associative/multimap/multimap.cons/deduct.pass.cpp?rev=363968&view=auto
==============================================================================
--- libcxx/trunk/test/std/containers/associative/multimap/multimap.cons/deduct.pass.cpp (added)
+++ libcxx/trunk/test/std/containers/associative/multimap/multimap.cons/deduct.pass.cpp Thu Jun 20 12:32:00 2019
@@ -0,0 +1,137 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// <map>
+// UNSUPPORTED: c++98, c++03, c++11, c++14
+// UNSUPPORTED: libcpp-no-deduction-guides
+
+// template<class InputIterator,
+//          class Compare = less<iter-value-type<InputIterator>>,
+//          class Allocator = allocator<iter-value-type<InputIterator>>>
+// multimap(InputIterator, InputIterator,
+//          Compare = Compare(), Allocator = Allocator())
+//   -> multimap<iter-value-type<InputIterator>, Compare, Allocator>;
+// template<class Key, class Compare = less<Key>, class Allocator = allocator<Key>>
+// multimap(initializer_list<Key>, Compare = Compare(), Allocator = Allocator())
+//   -> multimap<Key, Compare, Allocator>;
+// template<class InputIterator, class Allocator>
+// multimap(InputIterator, InputIterator, Allocator)
+//   -> multimap<iter-value-type<InputIterator>, less<iter-value-type<InputIterator>>, Allocator>;
+// template<class Key, class Allocator>
+// multimap(initializer_list<Key>, Allocator)
+//   -> multimap<Key, less<Key>, Allocator>;
+
+#include <algorithm> // std::equal
+#include <cassert>
+#include <climits> // INT_MAX
+#include <functional>
+#include <map>
+#include <type_traits>
+
+#include "test_allocator.h"
+
+using P = std::pair<int, long>;
+using PC = std::pair<const int, long>;
+
+int main(int, char**)
+{
+    {
+    const P arr[] = { {1,1L}, {2,2L}, {1,1L}, {INT_MAX,1L}, {3,1L} };
+    std::multimap m(std::begin(arr), std::end(arr));
+
+    ASSERT_SAME_TYPE(decltype(m), std::multimap<int, long>);
+    const PC expected_m[] = { {1,1L}, {1,1L}, {2,2L}, {3,1L}, {INT_MAX,1L} };
+    assert(std::equal(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    }
+
+    {
+    const P arr[] = { {1,1L}, {2,2L}, {1,1L}, {INT_MAX,1L}, {3,1L} };
+    std::multimap m(std::begin(arr), std::end(arr), std::greater<int>());
+
+    ASSERT_SAME_TYPE(decltype(m), std::multimap<int, long, std::greater<int>>);
+    const PC expected_m[] = { {INT_MAX,1L}, {3,1L}, {2,2L}, {1,1L}, {1,1L} };
+    assert(std::equal(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    }
+
+    {
+    const P arr[] = { {1,1L}, {2,2L}, {1,1L}, {INT_MAX,1L}, {3,1L} };
+    std::multimap m(std::begin(arr), std::end(arr), std::greater<int>(), test_allocator<PC>(0, 42));
+
+    ASSERT_SAME_TYPE(decltype(m), std::multimap<int, long, std::greater<int>, test_allocator<PC>>);
+    const PC expected_m[] = { {INT_MAX,1L}, {3,1L}, {2,2L}, {1,1L}, {1,1L} };
+    assert(std::equal(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    assert(m.get_allocator().get_id() == 42);
+    }
+
+    {
+    std::multimap<int, long> source;
+    std::multimap m(source);
+    ASSERT_SAME_TYPE(decltype(m), decltype(source));
+    assert(m.size() == 0);
+    }
+
+    {
+    std::multimap<int, long> source;
+    std::multimap m{source};  // braces instead of parens
+    ASSERT_SAME_TYPE(decltype(m), decltype(source));
+    assert(m.size() == 0);
+    }
+
+    {
+    std::multimap<int, long> source;
+    std::multimap m(source, std::map<int, long>::allocator_type());
+    ASSERT_SAME_TYPE(decltype(m), decltype(source));
+    assert(m.size() == 0);
+    }
+
+    {
+    std::multimap m{ P{1,1L}, P{2,2L}, P{1,1L}, P{INT_MAX,1L}, P{3,1L} };
+
+    ASSERT_SAME_TYPE(decltype(m), std::multimap<int, long>);
+    const PC expected_m[] = { {1,1L}, {1,1L}, {2,2L}, {3,1L}, {INT_MAX,1L} };
+    assert(std::equal(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    }
+
+    {
+    std::multimap m({ P{1,1L}, P{2,2L}, P{1,1L}, P{INT_MAX,1L}, P{3,1L} }, std::greater<int>());
+
+    ASSERT_SAME_TYPE(decltype(m), std::multimap<int, long, std::greater<int>>);
+    const PC expected_m[] = { {INT_MAX,1L}, {3,1L}, {2,2L}, {1,1L}, {1,1L} };
+    assert(std::equal(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    }
+
+    {
+    std::multimap m({ P{1,1L}, P{2,2L}, P{1,1L}, P{INT_MAX,1L}, P{3,1L} }, std::greater<int>(), test_allocator<PC>(0, 43));
+
+    ASSERT_SAME_TYPE(decltype(m), std::multimap<int, long, std::greater<int>, test_allocator<PC>>);
+    const PC expected_m[] = { {INT_MAX,1L}, {3,1L}, {2,2L}, {1,1L}, {1,1L} };
+    assert(std::equal(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    assert(m.get_allocator().get_id() == 43);
+    }
+
+    {
+    const P arr[] = { {1,1L}, {2,2L}, {1,1L}, {INT_MAX,1L}, {3,1L} };
+    std::multimap m(std::begin(arr), std::end(arr), test_allocator<PC>(0, 44));
+
+    ASSERT_SAME_TYPE(decltype(m), std::multimap<int, long, std::less<int>, test_allocator<PC>>);
+    const PC expected_m[] = { {1,1L}, {1,1L}, {2,2L}, {3,1L}, {INT_MAX,1L} };
+    assert(std::equal(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    assert(m.get_allocator().get_id() == 44);
+    }
+
+    {
+    std::multimap m({ P{1,1L}, P{2,2L}, P{1,1L}, P{INT_MAX,1L}, P{3,1L} }, test_allocator<PC>(0, 45));
+
+    ASSERT_SAME_TYPE(decltype(m), std::multimap<int, long, std::less<int>, test_allocator<PC>>);
+    const PC expected_m[] = { {1,1L}, {1,1L}, {2,2L}, {3,1L}, {INT_MAX,1L} };
+    assert(std::equal(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    assert(m.get_allocator().get_id() == 45);
+    }
+
+    return 0;
+}

Added: libcxx/trunk/test/std/containers/associative/multimap/multimap.cons/deduct_const.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/containers/associative/multimap/multimap.cons/deduct_const.pass.cpp?rev=363968&view=auto
==============================================================================
--- libcxx/trunk/test/std/containers/associative/multimap/multimap.cons/deduct_const.pass.cpp (added)
+++ libcxx/trunk/test/std/containers/associative/multimap/multimap.cons/deduct_const.pass.cpp Thu Jun 20 12:32:00 2019
@@ -0,0 +1,107 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// <map>
+// UNSUPPORTED: c++98, c++03, c++11, c++14
+// UNSUPPORTED: libcpp-no-deduction-guides
+
+// template<class InputIterator,
+//          class Compare = less<iter-value-type<InputIterator>>,
+//          class Allocator = allocator<iter-value-type<InputIterator>>>
+// multimap(InputIterator, InputIterator,
+//          Compare = Compare(), Allocator = Allocator())
+//   -> multimap<iter-value-type<InputIterator>, Compare, Allocator>;
+// template<class Key, class Compare = less<Key>, class Allocator = allocator<Key>>
+// multimap(initializer_list<Key>, Compare = Compare(), Allocator = Allocator())
+//   -> multimap<Key, Compare, Allocator>;
+// template<class InputIterator, class Allocator>
+// multimap(InputIterator, InputIterator, Allocator)
+//   -> multimap<iter-value-type<InputIterator>, less<iter-value-type<InputIterator>>, Allocator>;
+// template<class Key, class Allocator>
+// multimap(initializer_list<Key>, Allocator)
+//   -> multimap<Key, less<Key>, Allocator>;
+
+#include <algorithm> // std::equal
+#include <cassert>
+#include <climits> // INT_MAX
+#include <functional>
+#include <map>
+#include <type_traits>
+
+#include "test_allocator.h"
+
+using P = std::pair<int, long>;
+using PC = std::pair<const int, long>;
+using PCC = std::pair<const int, const long>;
+
+int main(int, char**)
+{
+    {
+    const PCC arr[] = { {1,1L}, {2,2L}, {1,1L}, {INT_MAX,1L}, {3,1L} };
+    std::multimap m(std::begin(arr), std::end(arr));
+
+    ASSERT_SAME_TYPE(decltype(m), std::multimap<int, const long>);
+    const PCC expected_m[] = { {1,1L}, {1,1L}, {2,2L}, {3,1L}, {INT_MAX,1L} };
+    assert(std::equal(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    }
+
+    {
+    const PCC arr[] = { {1,1L}, {2,2L}, {1,1L}, {INT_MAX,1L}, {3,1L} };
+    std::multimap m(std::begin(arr), std::end(arr), std::greater<int>());
+
+    ASSERT_SAME_TYPE(decltype(m), std::multimap<int, const long, std::greater<int>>);
+    const PCC expected_m[] = { {INT_MAX,1L}, {3,1L}, {2,2L}, {1,1L}, {1,1L} };
+    assert(std::equal(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    }
+
+    {
+    const PCC arr[] = { {1,1L}, {2,2L}, {1,1L}, {INT_MAX,1L}, {3,1L} };
+    std::multimap m(std::begin(arr), std::end(arr), std::greater<int>(), test_allocator<PCC>(0, 42));
+
+    ASSERT_SAME_TYPE(decltype(m), std::multimap<int, const long, std::greater<int>, test_allocator<PCC>>);
+    const PCC expected_m[] = { {INT_MAX,1L}, {3,1L}, {2,2L}, {1,1L}, {1,1L} };
+    assert(std::equal(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    assert(m.get_allocator().get_id() == 42);
+    }
+
+    {
+    std::multimap m{ PC{1,1L}, PC{2,2L}, PC{1,1L}, PC{INT_MAX,1L}, PC{3,1L} };
+
+    ASSERT_SAME_TYPE(decltype(m), std::multimap<int, long>);
+    const PC expected_m[] = { {1,1L}, {1,1L}, {2,2L}, {3,1L}, {INT_MAX,1L} };
+    assert(std::equal(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    }
+
+    {
+    std::multimap m({ PC{1,1L}, PC{2,2L}, PC{1,1L}, PC{INT_MAX,1L}, PC{3,1L} }, std::greater<int>());
+
+    ASSERT_SAME_TYPE(decltype(m), std::multimap<int, long, std::greater<int>>);
+    const PC expected_m[] = { {INT_MAX,1L}, {3,1L}, {2,2L}, {1,1L}, {1,1L} };
+    assert(std::equal(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    }
+
+    {
+    std::multimap m({ PC{1,1L}, PC{2,2L}, PC{1,1L}, PC{INT_MAX,1L}, PC{3,1L} }, std::greater<int>(), test_allocator<PC>(0, 43));
+
+    ASSERT_SAME_TYPE(decltype(m), std::multimap<int, long, std::greater<int>, test_allocator<PC>>);
+    const PC expected_m[] = { {INT_MAX,1L}, {3,1L}, {2,2L}, {1,1L}, {1,1L} };
+    assert(std::equal(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    assert(m.get_allocator().get_id() == 43);
+    }
+
+    {
+    std::multimap m({ PC{1,1L}, PC{2,2L}, PC{1,1L}, PC{INT_MAX,1L}, PC{3,1L} }, test_allocator<PC>(0, 45));
+
+    ASSERT_SAME_TYPE(decltype(m), std::multimap<int, long, std::less<int>, test_allocator<PC>>);
+    const PC expected_m[] = { {1,1L}, {1,1L}, {2,2L}, {3,1L}, {INT_MAX,1L} };
+    assert(std::equal(m.begin(), m.end(), std::begin(expected_m), std::end(expected_m)));
+    assert(m.get_allocator().get_id() == 45);
+    }
+
+    return 0;
+}




More information about the libcxx-commits mailing list