1//===----------------------------------------------------------------------===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is dual licensed under the MIT and the University of Illinois Open
6// Source Licenses. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// UNSUPPORTED: c++98, c++03, c++11, c++14
11
12// <unordered_map>
13
14// class unordered_map
15
16// template <class... Args>
17//  pair<iterator, bool> try_emplace(const key_type& k, Args&&... args);          // C++17
18// template <class... Args>
19//  pair<iterator, bool> try_emplace(key_type&& k, Args&&... args);               // C++17
20// template <class... Args>
21//  iterator try_emplace(const_iterator hint, const key_type& k, Args&&... args); // C++17
22// template <class... Args>
23//  iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args);      // C++17
24
25#include <unordered_map>
26#include <cassert>
27#include <tuple>
28
29class Moveable
30{
31    Moveable(const Moveable&);
32    Moveable& operator=(const Moveable&);
33
34    int int_;
35    double double_;
36public:
37    Moveable() : int_(0), double_(0) {}
38    Moveable(int i, double d) : int_(i), double_(d) {}
39    Moveable(Moveable&& x)
40        : int_(x.int_), double_(x.double_)
41            {x.int_ = -1; x.double_ = -1;}
42    Moveable& operator=(Moveable&& x)
43        {int_ = x.int_; x.int_ = -1;
44         double_ = x.double_; x.double_ = -1;
45         return *this;
46        }
47
48    bool operator==(const Moveable& x) const
49        {return int_ == x.int_ && double_ == x.double_;}
50    bool operator<(const Moveable& x) const
51        {return int_ < x.int_ || (int_ == x.int_ && double_ < x.double_);}
52    size_t hash () const { return std::hash<int>()(int_) + std::hash<double>()(double_); }
53
54    int get() const {return int_;}
55    bool moved() const {return int_ == -1;}
56};
57
58namespace std {
59    template <> struct hash<Moveable> {
60        size_t operator () (const Moveable &m) const { return m.hash(); }
61    };
62}
63
64int main()
65{
66
67    { // pair<iterator, bool> try_emplace(const key_type& k, Args&&... args);
68        typedef std::unordered_map<int, Moveable> M;
69        typedef std::pair<M::iterator, bool> R;
70        M m;
71        R r;
72        for (int i = 0; i < 20; i += 2)
73            m.emplace (i, Moveable(i, (double) i));
74        assert(m.size() == 10);
75
76        Moveable mv1(3, 3.0);
77        for (int i=0; i < 20; i += 2)
78        {
79            r = m.try_emplace(i, std::move(mv1));
80            assert(m.size() == 10);
81            assert(!r.second);              // was not inserted
82            assert(!mv1.moved());           // was not moved from
83            assert(r.first->first == i);    // key
84        }
85
86        r = m.try_emplace(-1, std::move(mv1));
87        assert(m.size() == 11);
88        assert(r.second);                   // was inserted
89        assert(mv1.moved());                // was moved from
90        assert(r.first->first == -1);       // key
91        assert(r.first->second.get() == 3); // value
92
93        Moveable mv2(5, 3.0);
94        r = m.try_emplace(5, std::move(mv2));
95        assert(m.size() == 12);
96        assert(r.second);                   // was inserted
97        assert(mv2.moved());                // was moved from
98        assert(r.first->first == 5);        // key
99        assert(r.first->second.get() == 5); // value
100
101        Moveable mv3(-1, 3.0);
102        r = m.try_emplace(117, std::move(mv2));
103        assert(m.size() == 13);
104        assert(r.second);                    // was inserted
105        assert(mv2.moved());                 // was moved from
106        assert(r.first->first == 117);       // key
107        assert(r.first->second.get() == -1); // value
108    }
109
110    {  // pair<iterator, bool> try_emplace(key_type&& k, Args&&... args);
111        typedef std::unordered_map<Moveable, Moveable> M;
112        typedef std::pair<M::iterator, bool> R;
113        M m;
114        R r;
115        for (int i = 0; i < 20; i += 2)
116            m.emplace ( Moveable(i, (double) i), Moveable(i+1, (double) i+1));
117        assert(m.size() == 10);
118
119        Moveable mvkey1(2, 2.0);
120        Moveable mv1(4, 4.0);
121        r = m.try_emplace(std::move(mvkey1), std::move(mv1));
122        assert(m.size() == 10);
123        assert(!r.second);                 // was not inserted
124        assert(!mv1.moved());              // was not moved from
125        assert(!mvkey1.moved());           // was not moved from
126        assert(r.first->first == mvkey1);  // key
127
128        Moveable mvkey2(3, 3.0);
129        r = m.try_emplace(std::move(mvkey2), std::move(mv1));
130        assert(m.size() == 11);
131        assert(r.second);                   // was inserted
132        assert(mv1.moved());                // was moved from
133        assert(mvkey2.moved());             // was moved from
134        assert(r.first->first.get()  == 3); // key
135        assert(r.first->second.get() == 4); // value
136    }
137
138    {  // iterator try_emplace(const_iterator hint, const key_type& k, Args&&... args);
139        typedef std::unordered_map<int, Moveable> M;
140        M m;
141        M::iterator r;
142        for (int i = 0; i < 20; i += 2)
143            m.try_emplace ( i, Moveable(i, (double) i));
144        assert(m.size() == 10);
145        M::const_iterator it = m.find(2);
146
147        Moveable mv1(3, 3.0);
148        for (int i=0; i < 20; i += 2)
149        {
150            r = m.try_emplace(it, i, std::move(mv1));
151            assert(m.size() == 10);
152            assert(!mv1.moved());         // was not moved from
153            assert(r->first == i);        // key
154            assert(r->second.get() == i); // value
155        }
156
157        r = m.try_emplace(it, 3, std::move(mv1));
158        assert(m.size() == 11);
159        assert(mv1.moved());          // was moved from
160        assert(r->first == 3);        // key
161        assert(r->second.get() == 3); // value
162    }
163
164    {  // iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args);
165        typedef std::unordered_map<Moveable, Moveable> M;
166        M m;
167        M::iterator r;
168        for ( int i = 0; i < 20; i += 2 )
169            m.emplace ( Moveable(i, (double) i), Moveable(i+1, (double) i+1));
170        assert(m.size() == 10);
171        M::const_iterator it = std::next(m.cbegin());
172
173        Moveable mvkey1(2, 2.0);
174        Moveable mv1(4, 4.0);
175        r = m.try_emplace(it, std::move(mvkey1), std::move(mv1));
176        assert(m.size() == 10);
177        assert(!mv1.moved());        // was not moved from
178        assert(!mvkey1.moved());     // was not moved from
179        assert(r->first == mvkey1);  // key
180
181        Moveable mvkey2(3, 3.0);
182        r = m.try_emplace(it, std::move(mvkey2), std::move(mv1));
183        assert(m.size() == 11);
184        assert(mv1.moved());          // was moved from
185        assert(mvkey2.moved());       // was moved from
186        assert(r->first.get()  == 3); // key
187        assert(r->second.get() == 4); // value
188    }
189}
190