blob: 518634d3186521e696e59c7f04c2addd94e6816f [file] [log] [blame]
David Ghandehari60170302017-03-10 21:18:13 -08001/*
2 * Copyright 2017 Google Inc. All Rights Reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "nb/concurrent_map.h"
18#include "nb/hash.h"
19#include "nb/simple_thread.h"
20#include "testing/gtest/include/gtest/gtest.h"
21
22namespace nb {
23namespace {
24
25class CapturesIntValues {
26 public:
27 virtual void Visit(const int& key, const int& val) {
28 visited_values_.push_back(std::make_pair(key, val));
29 }
30
31 std::map<int, int> ToMap() const {
32 std::map<int, int> output;
33 output.insert(visited_values_.begin(), visited_values_.end());
34 return output;
35 }
36 std::vector<std::pair<int, int> > visited_values_;
37};
38
39TEST(ConcurrentMap, SetIfMissing) {
40 IntToIntConcurrentMap int_map;
41 ASSERT_FALSE(int_map.Has(1));
42 ASSERT_TRUE(int_map.SetIfMissing(1, -1));
43 ASSERT_TRUE(int_map.Has(1));
44 ASSERT_FALSE(int_map.SetIfMissing(1, -2)); // False because exists.
45
46 IntToIntConcurrentMap::EntryHandle entry_handle;
47
48 ASSERT_TRUE(int_map.Get(1, &entry_handle));
49 ASSERT_TRUE(entry_handle.Valid());
50 ASSERT_EQ(-1, entry_handle.Value());
51
52 // 2 is a missing key and doesn't exist.
53 ASSERT_FALSE(int_map.Get(2, &entry_handle));
54 ASSERT_FALSE(entry_handle.Valid());
55}
56
57TEST(ConcurrentMap, Set) {
58 IntToIntConcurrentMap int_map;
59 ASSERT_FALSE(int_map.Has(1));
60 int_map.Set(1, -1);
61 ASSERT_TRUE(int_map.Has(1));
62 int_map.Set(1, -2);
63
64 IntToIntConcurrentMap::EntryHandle entry_handle;
65
66 ASSERT_TRUE(int_map.Get(1, &entry_handle));
67 ASSERT_TRUE(entry_handle.Valid());
68 ASSERT_EQ(-2, entry_handle.Value()); // Value was replaced.
69}
70
71TEST(ConcurrentMap, GetOrCreate) {
72 IntToIntConcurrentMap int_map;
73
74 // Create a default mapping 1=>0, then reset the value to -2.
75 {
76 IntToIntConcurrentMap::EntryHandle entry_handle;
77
78 int_map.GetOrCreate(1, &entry_handle); // Does not exist prior.
79
80 ASSERT_TRUE(entry_handle.Valid()); // Value default created.
81 EXPECT_EQ(0, entry_handle.Value());
82 entry_handle.ValueMutable() = -2;
83 }
84
85 // Get the value again, expect it to be -2.
86 {
87 IntToIntConcurrentMap::EntryHandle entry_handle;
88
89 EXPECT_TRUE(int_map.Get(1, &entry_handle));
90 ASSERT_TRUE(entry_handle.Valid());
91 EXPECT_EQ(-2, entry_handle.Value());
92 }
93}
94
95TEST(ConcurrentMap, GetConst) {
96 IntToIntConcurrentMap int_map;
97 IntToIntConcurrentMap::ConstEntryHandle const_entry_handle;
98
99 EXPECT_FALSE(int_map.Get(1, &const_entry_handle));
100 EXPECT_FALSE(const_entry_handle.Valid());
101
102 EXPECT_TRUE(int_map.SetIfMissing(1, -1));
103
104 EXPECT_TRUE(int_map.Get(1, &const_entry_handle));
105 EXPECT_TRUE(const_entry_handle.Valid());
106 EXPECT_EQ(-1, const_entry_handle.Value());
107}
108
109TEST(ConcurrentMap, Remove) {
110 IntToIntConcurrentMap int_map;
111 int_map.Set(1, -1);
112 EXPECT_EQ(1, int_map.GetSize());
113
114 EXPECT_FALSE(int_map.Remove(2)); // Doesn't exist.
115 EXPECT_TRUE(int_map.Remove(1));
116 EXPECT_EQ(0, int_map.GetSize());
117 EXPECT_TRUE(int_map.IsEmpty());
118}
119
120TEST(ConcurrentMap, RemoveUsingHandle) {
121 IntToIntConcurrentMap int_map;
122 int_map.Set(1, -1);
123 int_map.Set(2, -2);
124 EXPECT_EQ(2, int_map.GetSize());
125
126 IntToIntConcurrentMap::EntryHandle entry_handle;
127 int_map.Get(2, &entry_handle);
128
129 int_map.Remove(&entry_handle);
130 EXPECT_EQ(1, int_map.GetSize());
131 EXPECT_TRUE(int_map.Has(1));
132 EXPECT_FALSE(int_map.Has(2));
133
134 int_map.Get(1, &entry_handle);
135 int_map.Remove(&entry_handle);
136 EXPECT_EQ(0, int_map.GetSize());
137}
138
139TEST(ConcurrentMap, Clear) {
140 IntToIntConcurrentMap int_map;
141 int_map.Set(1, -1);
142 int_map.Set(2, -2);
143
144 EXPECT_EQ(2, int_map.GetSize());
145 EXPECT_EQ(2, int_map.GetSize());
146
147 int_map.Clear();
148 EXPECT_TRUE(int_map.IsEmpty());
149 EXPECT_EQ(0, int_map.GetSize());
150}
151
152TEST(ConcurrentMap, ForEach) {
153 IntToIntConcurrentMap int_map;
154 int_map.Set(1, -1);
155 int_map.Set(2, -2);
156
157 CapturesIntValues captures_int_values;
158
159 int_map.ForEach(&captures_int_values);
160
161 std::map<int, int> std_int_map = captures_int_values.ToMap();
162 EXPECT_EQ(std_int_map[1], -1);
163 EXPECT_EQ(std_int_map[2], -2);
164}
165
166class InsertThread : public SimpleThread {
167 public:
168 InsertThread(int start_val, int end_val, IntToIntConcurrentMap* output)
169 : SimpleThread("InsertThread"),
170 test_ok_(true),
171 start_value_(start_val),
172 end_value_(end_val),
173 concurrent_map_(output) {}
174
175 virtual void Run() {
176 for (int i = start_value_; i < end_value_; ++i) {
177 if (!concurrent_map_->SetIfMissing(i, i)) {
178 test_ok_ = false;
179 }
180 }
181 }
182
183 bool test_ok_;
184 int start_value_;
185 int end_value_;
186 IntToIntConcurrentMap* concurrent_map_;
187};
188
189TEST(ConcurrentMap, MultiThreadTest) {
190 IntToIntConcurrentMap shared_int_map;
191 std::vector<InsertThread*> threads;
192
193 threads.push_back(new InsertThread(0, 5000, &shared_int_map));
194 threads.push_back(new InsertThread(5000, 10000, &shared_int_map));
195
196 for (int i = 0; i < threads.size(); ++i) {
197 threads[i]->Start();
198 }
199
200 for (int i = 0; i < threads.size(); ++i) {
201 threads[i]->Join();
202 EXPECT_TRUE(threads[i]->test_ok_);
203 delete threads[i];
204 }
205
206 threads.clear();
207
208 ASSERT_EQ(shared_int_map.GetSize(), 10000);
209
210 CapturesIntValues captures_int_values;
211
212 shared_int_map.ForEach(&captures_int_values);
213
214 std::map<int, int> std_int_map = captures_int_values.ToMap();
215
216 for (int i = 0; i < 10000; ++i) {
217 ASSERT_EQ(std_int_map[i], i);
218
219 IntToIntConcurrentMap::ConstEntryHandle const_entry_handle;
220 ASSERT_TRUE(shared_int_map.Get(i, &const_entry_handle));
221 ASSERT_TRUE(const_entry_handle.Valid());
222 ASSERT_EQ(i, const_entry_handle.Value());
223 }
224}
225
226} // namespace
227} // namespace nb