Skip to content

Commit 289b295

Browse files
committed
Implemented ManyToMany bulk insert
1 parent f05ad6e commit 289b295

File tree

3 files changed

+231
-49
lines changed

3 files changed

+231
-49
lines changed

BinaryRelations/BinaryRelations.h

Lines changed: 95 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -285,15 +285,15 @@ template <typename LeftType, typename RightType> class OneToMany
285285
if(0 == pairs.size())
286286
return;
287287

288-
auto cmp = [](const Pair &a, const Pair &b)
288+
auto compare_left_then_right = [](const Pair &a, const Pair &b)
289289
{
290290
if(a.left < b.left) return true;
291291
if(b.left < a.left) return false;
292292
return a.right < b.right;
293293
};
294294

295295
std::vector<Pair> pairs_to_insert = pairs; // Deep copy...
296-
std::sort(pairs_to_insert.begin(), pairs_to_insert.end(), cmp); // ...so I can sort
296+
std::sort(pairs_to_insert.begin(), pairs_to_insert.end(), compare_left_then_right); // ...so I can sort
297297

298298
// ------------------------
299299

@@ -310,7 +310,7 @@ template <typename LeftType, typename RightType> class OneToMany
310310

311311
if (0 != pairs_to_erase.size())
312312
{
313-
std::sort(pairs_to_erase.begin(), pairs_to_erase.end(), cmp);
313+
std::sort(pairs_to_erase.begin(), pairs_to_erase.end(), compare_left_then_right);
314314

315315
std::vector<RightType> right_to_erase;
316316
auto end_it = pairs_to_erase.cend();
@@ -358,12 +358,12 @@ template <typename LeftType, typename RightType> class OneToMany
358358
}
359359

360360
// Insert them in one go
361-
auto r2l_it = m_LeftToRight.find(left);
362-
if (r2l_it != m_LeftToRight.end())
361+
auto l2r_it = m_LeftToRight.find(left);
362+
if (l2r_it != m_LeftToRight.end())
363363
{
364-
auto *v = r2l_it->second;
365-
auto temp = *v;
366-
insertIntoSortedVector(&temp, &right_to_insert, v);
364+
auto l2r_vec = l2r_it->second;
365+
auto temp = *l2r_vec; // Deep copy
366+
insertIntoSortedVector(&temp, &right_to_insert, l2r_vec);
367367
}
368368
else
369369
{
@@ -459,15 +459,15 @@ template <typename LeftType, typename RightType> class OneToMany
459459
if(0 == pairs.size())
460460
return;
461461

462-
auto cmp = [](const Pair &a, const Pair &b)
462+
auto compare_left_then_right = [](const Pair &a, const Pair &b)
463463
{
464464
if(a.left < b.left) return true;
465465
if(b.left < a.left) return false;
466466
return a.right < b.right;
467467
};
468468

469469
std::vector<Pair> pairs_to_erase = pairs; // Deep copy...
470-
std::sort(pairs_to_erase.begin(), pairs_to_erase.end(), cmp); // ...so I can sort
470+
std::sort(pairs_to_erase.begin(), pairs_to_erase.end(), compare_left_then_right); // ...so I can sort
471471

472472
std::vector<RightType> right_to_erase;
473473
auto end_it = pairs_to_erase.cend();
@@ -785,9 +785,92 @@ template <typename LeftType, typename RightType> class ManyToMany
785785
*/
786786
void insert(const std::vector<Pair> &pairs) noexcept
787787
{
788-
for (auto pair : pairs)
788+
if(0 == pairs.size())
789+
return;
790+
791+
auto compare_left_then_right = [](const Pair &a, const Pair &b)
789792
{
790-
insert(pair);
793+
if(a.left < b.left) return true;
794+
if(b.left < a.left) return false;
795+
return a.right < b.right;
796+
};
797+
798+
auto compare_right_then_left = [](const Pair &a, const Pair &b)
799+
{
800+
if(a.right < b.right) return true;
801+
if(b.right < a.right) return false;
802+
return a.left < b.left;
803+
};
804+
805+
std::vector<Pair> pairs_to_insert = pairs; // Deep copy...
806+
807+
// ------------------------
808+
809+
std::sort(pairs_to_insert.begin(), pairs_to_insert.end(), compare_left_then_right); // ...so I can sort
810+
811+
std::vector<RightType> right_to_insert;
812+
auto it_end = pairs_to_insert.cend();
813+
for (auto it = pairs_to_insert.cbegin(); it != it_end; )
814+
{
815+
// Collect all right values that have the same left value
816+
right_to_insert.clear();
817+
auto left = it->left;
818+
while(it != it_end && it->left == left)
819+
{
820+
right_to_insert.push_back(it->right);
821+
it++;
822+
}
823+
824+
// Insert them in one go
825+
auto l2r_it = m_LeftToRight.find(left);
826+
if (l2r_it != m_LeftToRight.end())
827+
{
828+
auto l2r_vec = l2r_it->second;
829+
auto temp = *l2r_vec;
830+
m_Count -= l2r_vec->size();
831+
insertIntoSortedVector(&temp, &right_to_insert, l2r_vec);
832+
m_Count += l2r_vec->size();
833+
}
834+
else
835+
{
836+
// insert new value
837+
auto l2r_vec = new std::vector<RightType>(right_to_insert);
838+
m_LeftToRight[left] = l2r_vec;
839+
m_Count += l2r_vec->size();
840+
}
841+
}
842+
843+
// ------------------------
844+
845+
std::sort(pairs_to_insert.begin(), pairs_to_insert.end(), compare_right_then_left);
846+
847+
std::vector<LeftType> left_to_insert;
848+
it_end = pairs_to_insert.cend();
849+
for (auto it = pairs_to_insert.cbegin(); it != it_end; )
850+
{
851+
// Collect all right values that have the same left value
852+
left_to_insert.clear();
853+
auto right = it->right;
854+
while(it != it_end && it->right == right)
855+
{
856+
left_to_insert.push_back(it->left);
857+
it++;
858+
}
859+
860+
// Insert them in one go
861+
auto r2l_it = m_RightToLeft.find(right);
862+
if (r2l_it != m_RightToLeft.end())
863+
{
864+
auto r2l_vec = r2l_it->second;
865+
auto temp = *r2l_vec;
866+
insertIntoSortedVector(&temp, &left_to_insert, r2l_vec);
867+
}
868+
else
869+
{
870+
// insert new value
871+
auto r2l_vec = new std::vector<LeftType>(left_to_insert);
872+
m_RightToLeft[right] = r2l_vec;
873+
}
791874
}
792875
}
793876

TestManyToMany.h

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,3 +129,101 @@ UTEST(TestManyToMany, AllRight)
129129

130130
ASSERT_EQ(count, 4);
131131
}
132+
133+
UTEST(TestManyToMany, BulkInsert)
134+
{
135+
ManyToMany<int, std::string> m2m;
136+
m2m.insert(1, "apple");
137+
m2m.insert(1, "apricot");
138+
m2m.insert(1, "avocado");
139+
140+
m2m.insert(2, "banana");
141+
m2m.insert(2, "blueberry");
142+
m2m.insert(2, "blackberry");
143+
144+
m2m.insert(3, "cherry");
145+
m2m.insert(3, "coconut");
146+
m2m.insert(3, "clementine");
147+
148+
std::vector<ManyToMany<int, std::string>::Pair> vec;
149+
// Add to existing left value
150+
vec.push_back(ManyToMany<int, std::string>::Pair(3, "crabapple"));
151+
vec.push_back(ManyToMany<int, std::string>::Pair(3, "cashew"));
152+
// Completely new left right pairs
153+
vec.push_back(ManyToMany<int, std::string>::Pair(10, "date"));
154+
vec.push_back(ManyToMany<int, std::string>::Pair(10, "dewberry"));
155+
// Existing right values, steal them
156+
vec.push_back(ManyToMany<int, std::string>::Pair(10, "apricot"));
157+
vec.push_back(ManyToMany<int, std::string>::Pair(10, "banana"));
158+
vec.push_back(ManyToMany<int, std::string>::Pair(20, "avocado"));
159+
vec.push_back(ManyToMany<int, std::string>::Pair(20, "apple"));
160+
161+
m2m.insert(vec);
162+
163+
ASSERT_EQ(m2m.count(), 13);
164+
//ASSERT_TRUE(isValid(m2m));
165+
166+
ASSERT_FALSE(m2m.contains(1, "apple"));
167+
ASSERT_FALSE(m2m.contains(1, "apricot"));
168+
ASSERT_FALSE(m2m.contains(1, "avocado"));
169+
ASSERT_FALSE(m2m.contains(2, "banana"));
170+
171+
ASSERT_TRUE(m2m.contains(2, "blueberry"));
172+
ASSERT_TRUE(m2m.contains(2, "blackberry"));
173+
ASSERT_TRUE(m2m.contains(3, "cherry"));
174+
ASSERT_TRUE(m2m.contains(3, "coconut"));
175+
ASSERT_TRUE(m2m.contains(3, "clementine"));
176+
177+
ASSERT_TRUE(m2m.contains(3, "crabapple"));
178+
ASSERT_TRUE(m2m.contains(3, "cashew"));
179+
ASSERT_TRUE(m2m.contains(10, "date"));
180+
ASSERT_TRUE(m2m.contains(10, "dewberry"));
181+
ASSERT_TRUE(m2m.contains(10, "apricot"));
182+
ASSERT_TRUE(m2m.contains(10, "banana"));
183+
ASSERT_TRUE(m2m.contains(20, "avocado"));
184+
ASSERT_TRUE(m2m.contains(20, "apple"));
185+
}
186+
187+
//UTEST(TestManyToMany, BulkErase)
188+
//{
189+
// ManyToMany<int, std::string> mtm;
190+
// mtm.insert(1, "apple");
191+
// mtm.insert(1, "apricot");
192+
// mtm.insert(1, "avocado");
193+
//
194+
// mtm.insert(2, "banana");
195+
// mtm.insert(2, "blueberry");
196+
// mtm.insert(2, "blackberry");
197+
//
198+
// mtm.insert(3, "cherry");
199+
// mtm.insert(3, "coconut");
200+
// mtm.insert(3, "clementine");
201+
//
202+
// std::vector<ManyToMany<int, std::string>::Pair> vec;
203+
// // Erase all of left=1
204+
// vec.push_back(ManyToMany<int, std::string>::Pair(1, "apple"));
205+
// vec.push_back(ManyToMany<int, std::string>::Pair(1, "apricot"));
206+
// vec.push_back(ManyToMany<int, std::string>::Pair(1, "avocado"));
207+
// // Erase some of left=2
208+
// vec.push_back(ManyToMany<int, std::string>::Pair(2, "banana"));
209+
// vec.push_back(ManyToMany<int, std::string>::Pair(2, "blueberry"));
210+
// // This pair is not in the set
211+
// vec.push_back(ManyToMany<int, std::string>::Pair(1000, "zucchini"));
212+
//
213+
// mtm.erase(vec);
214+
//
215+
// ASSERT_EQ(mtm.count(), 4);
216+
// //ASSERT_TRUE(isValid(mtm));
217+
//
218+
// ASSERT_FALSE(mtm.contains(1, "apple"));
219+
// ASSERT_FALSE(mtm.contains(1, "apricot"));
220+
// ASSERT_FALSE(mtm.contains(1, "avocado"));
221+
// ASSERT_FALSE(mtm.contains(2, "banana"));
222+
// ASSERT_FALSE(mtm.contains(2, "blueberry"));
223+
//
224+
// ASSERT_TRUE(mtm.contains(2, "blackberry"));
225+
// ASSERT_TRUE(mtm.contains(3, "cherry"));
226+
// ASSERT_TRUE(mtm.contains(3, "coconut"));
227+
// ASSERT_TRUE(mtm.contains(3, "clementine"));
228+
//}
229+

TestOneToMany.h

Lines changed: 38 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,44 @@ bool isValid(const OneToMany<LeftType, RightType>& otm)
109109
return 0 == right_set.size();
110110
}
111111

112+
UTEST(TestOneToMany, AllLeft)
113+
{
114+
OneToMany<int, std::string> otm;
115+
otm.insert(1, "apple");
116+
otm.insert(1, "banana");
117+
otm.insert(1, "cherry");
118+
otm.insert(2, "date");
119+
otm.insert(3, "elderberry");
120+
121+
int count = 0;
122+
for (auto p : otm.allLeft())
123+
{
124+
(void)p; // Shut up compiler
125+
count += 1;
126+
}
127+
128+
ASSERT_EQ(count, 3);
129+
}
130+
131+
UTEST(TestOneToMany, AllRight)
132+
{
133+
OneToMany<int, std::string> otm;
134+
otm.insert(1, "apple");
135+
otm.insert(1, "banana");
136+
otm.insert(1, "cherry");
137+
otm.insert(2, "date");
138+
otm.insert(3, "elderberry");
139+
140+
int count = 0;
141+
for (auto p : otm.allRight())
142+
{
143+
(void)p; // Shut up compiler
144+
count += 1;
145+
}
146+
147+
ASSERT_EQ(count, 5);
148+
}
149+
112150
UTEST(TestOneToMany, BulkInsert)
113151
{
114152
OneToMany<int, std::string> otm;
@@ -206,40 +244,3 @@ UTEST(TestOneToMany, BulkErase)
206244
ASSERT_TRUE(otm.contains(3, "clementine"));
207245
}
208246

209-
UTEST(TestOneToMany, AllLeft)
210-
{
211-
OneToMany<int, std::string> otm;
212-
otm.insert(1, "apple");
213-
otm.insert(1, "banana");
214-
otm.insert(1, "cherry");
215-
otm.insert(2, "date");
216-
otm.insert(3, "elderberry");
217-
218-
int count = 0;
219-
for (auto p : otm.allLeft())
220-
{
221-
(void)p; // Shut up compiler
222-
count += 1;
223-
}
224-
225-
ASSERT_EQ(count, 3);
226-
}
227-
228-
UTEST(TestOneToMany, AllRight)
229-
{
230-
OneToMany<int, std::string> otm;
231-
otm.insert(1, "apple");
232-
otm.insert(1, "banana");
233-
otm.insert(1, "cherry");
234-
otm.insert(2, "date");
235-
otm.insert(3, "elderberry");
236-
237-
int count = 0;
238-
for (auto p : otm.allRight())
239-
{
240-
(void)p; // Shut up compiler
241-
count += 1;
242-
}
243-
244-
ASSERT_EQ(count, 5);
245-
}

0 commit comments

Comments
 (0)