Skip to content

Commit d85e43f

Browse files
committed
Fixed lazy_set and lazy_map ownership
1 parent c14c7b4 commit d85e43f

4 files changed

Lines changed: 126 additions & 90 deletions

File tree

include/map.h

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -73,15 +73,6 @@ class lazy_map
7373
};
7474
}
7575

76-
// Creates a lazy map by referring to an existing std::map source.
77-
// The referenced map must outlive this lazy map.
78-
explicit lazy_map(const std::map<TKey, TValue, TCompare>* map)
79-
{
80-
m_operation = [map](const std::function<void(const value_type&)>& consumer) {
81-
std::for_each(map->begin(), map->end(), consumer);
82-
};
83-
}
84-
8576
// Creates a lazy map by directly providing the deferred operation.
8677
// This constructor is mostly useful for composing lazy_map instances.
8778
explicit lazy_map(std::function<void(const std::function<void(const value_type&)>&)> operation)
@@ -617,7 +608,7 @@ class map
617608
// until a terminal operation, such as get() or reduce(), is called.
618609
[[nodiscard]] lazy_map<TKey, TValue, TCompare> lazy() const
619610
{
620-
return lazy_map<TKey, TValue, TCompare>(&m_map);
611+
return lazy_map<TKey, TValue, TCompare>(m_map);
621612
}
622613

623614
// Returns the begin iterator, useful for other standard library algorithms

include/set.h

Lines changed: 6 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -78,15 +78,6 @@ namespace fcpp {
7878
};
7979
}
8080

81-
// Creates a lazy set by referring to an existing std::set source.
82-
// The referenced set must outlive this lazy set.
83-
explicit lazy_set(const std::set<TKey, TCompare>* set)
84-
{
85-
m_operation = [set](const std::function<void(const TKey&)>& consumer) {
86-
std::for_each(set->begin(), set->end(), consumer);
87-
};
88-
}
89-
9081
// Creates a lazy set by directly providing the deferred operation.
9182
// This constructor is mostly useful for composing lazy_set instances.
9283
explicit lazy_set(std::function<void(const std::function<void(const TKey&)>&)> operation)
@@ -187,22 +178,7 @@ namespace fcpp {
187178
// diff -> fcpp::set<int>({1, 3, 8})
188179
[[nodiscard]] lazy_set difference_with(const set<TKey, TCompare>& other) const
189180
{
190-
const auto previous = m_operation;
191-
return lazy_set(
192-
[previous, &other](const std::function<void(const TKey&)>& consumer) {
193-
std::set<TKey, TCompare> current;
194-
previous([&current](const TKey& key) {
195-
current.insert(key);
196-
});
197-
198-
std::set<TKey, TCompare> diff;
199-
std::set_difference(current.begin(),
200-
current.end(),
201-
other.begin(),
202-
other.end(),
203-
std::inserter(diff, diff.begin()));
204-
std::for_each(diff.begin(), diff.end(), consumer);
205-
});
181+
return difference_with(lazy_set(std::set<TKey, TCompare>(other.begin(), other.end())));
206182
}
207183

208184
// Returns the lazy set of elements which belong to this lazy set but not in the std::set.
@@ -250,22 +226,7 @@ namespace fcpp {
250226
// combined -> fcpp::set<int>({1, 2, 3, 5, 7, 8, 10, 15, 17})
251227
[[nodiscard]] lazy_set union_with(const set<TKey, TCompare>& other) const
252228
{
253-
const auto previous = m_operation;
254-
return lazy_set(
255-
[previous, &other](const std::function<void(const TKey&)>& consumer) {
256-
std::set<TKey, TCompare> current;
257-
previous([&current](const TKey& key) {
258-
current.insert(key);
259-
});
260-
261-
std::set<TKey, TCompare> combined;
262-
std::set_union(current.begin(),
263-
current.end(),
264-
other.begin(),
265-
other.end(),
266-
std::inserter(combined, combined.begin()));
267-
std::for_each(combined.begin(), combined.end(), consumer);
268-
});
229+
return union_with(lazy_set(std::set<TKey, TCompare>(other.begin(), other.end())));
269230
}
270231

271232
// Returns the lazy set of elements which belong either to this lazy set or the std::set.
@@ -313,22 +274,7 @@ namespace fcpp {
313274
// combined -> fcpp::set<int>({2, 5, 7, 10})
314275
[[nodiscard]] lazy_set intersect_with(const set<TKey, TCompare>& other) const
315276
{
316-
const auto previous = m_operation;
317-
return lazy_set(
318-
[previous, &other](const std::function<void(const TKey&)>& consumer) {
319-
std::set<TKey, TCompare> current;
320-
previous([&current](const TKey& key) {
321-
current.insert(key);
322-
});
323-
324-
std::set<TKey, TCompare> intersection;
325-
std::set_intersection(current.begin(),
326-
current.end(),
327-
other.begin(),
328-
other.end(),
329-
std::inserter(intersection, intersection.begin()));
330-
std::for_each(intersection.begin(), intersection.end(), consumer);
331-
});
277+
return intersect_with(lazy_set(std::set<TKey, TCompare>(other.begin(), other.end())));
332278
}
333279

334280
// Returns the lazy set of elements which belong to both this lazy set and the std::set.
@@ -367,35 +313,15 @@ namespace fcpp {
367313
template <typename UKey, typename UCompare>
368314
[[nodiscard]] lazy_set<std::pair<TKey, UKey>> zip(const set<UKey, UCompare>& set) const
369315
{
370-
const auto previous = m_operation;
371-
return lazy_set<std::pair<TKey, UKey>>(
372-
[previous, &set](const std::function<void(const std::pair<TKey, UKey>&)>& consumer) {
373-
size_t index = 0;
374-
previous([&set, &consumer, &index](const TKey& key) {
375-
assert(index < set.size());
376-
consumer({key, set[index]});
377-
++index;
378-
});
379-
assert(index == set.size());
380-
});
316+
return zip(lazy_set<UKey, UCompare>(std::set<UKey, UCompare>(set.begin(), set.end())));
381317
}
382318

383319
// Performs the functional `zip` algorithm lazily.
384320
// The sizes of the two sets must be equal.
385321
template <typename UKey, typename UCompare>
386322
[[nodiscard]] lazy_set<std::pair<TKey, UKey>> zip(const std::set<UKey, UCompare>& set) const
387323
{
388-
const auto previous = m_operation;
389-
return lazy_set<std::pair<TKey, UKey>>(
390-
[previous, &set](const std::function<void(const std::pair<TKey, UKey>&)>& consumer) {
391-
auto it = set.begin();
392-
previous([&set, &it, &consumer](const TKey& key) {
393-
assert(it != set.end());
394-
consumer({key, *it});
395-
++it;
396-
});
397-
assert(it == set.end());
398-
});
324+
return zip(lazy_set<UKey, UCompare>(set));
399325
}
400326

401327
// Performs the functional `zip` algorithm lazily where duplicates are removed before zipping.
@@ -1082,7 +1008,7 @@ namespace fcpp {
10821008
// transformations until a terminal operation, such as get() or reduce(), is called.
10831009
[[nodiscard]] lazy_set<TKey, TCompare> lazy() const
10841010
{
1085-
return lazy_set<TKey, TCompare>(&m_set);
1011+
return lazy_set<TKey, TCompare>(m_set);
10861012
}
10871013

10881014
// Returns the begin iterator, useful for other standard library algorithms

tests/map_test.cc

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,32 @@ TEST(MapTest, LazyReduce)
314314
EXPECT_EQ(3, filter_call_count);
315315
}
316316

317+
TEST(MapTest, LazySourceCanOutliveFunctionalMap)
318+
{
319+
lazy_map<std::string, int> lazy_persons;
320+
{
321+
const map<std::string, int> persons({{"jake", 32}, {"mary", 26}, {"david", 40}});
322+
lazy_persons = persons
323+
.lazy()
324+
.filter([](const std::pair<const std::string, int>& element) {
325+
return element.second >= 32;
326+
});
327+
}
328+
329+
EXPECT_EQ((map<std::string, int>({{"david", 40}, {"jake", 32}})), lazy_persons.get());
330+
}
331+
332+
TEST(MapTest, LazySourceCanStartFromTemporaryFunctionalMap)
333+
{
334+
const auto lazy_persons = map<std::string, int>({{"jake", 32}, {"mary", 26}})
335+
.lazy()
336+
.map_to<char, int>([](const std::pair<const std::string, int>& element) {
337+
return std::make_pair(element.first[0], element.second);
338+
});
339+
340+
EXPECT_EQ((map<char, int>({{'j', 32}, {'m', 26}})), lazy_persons.get());
341+
}
342+
317343
TEST(MapTest, LazyMapToDuplicateKeysKeepsFirst)
318344
{
319345
const map<std::string, int> persons({{"anna", 28}, {"alex", 30}, {"david", 40}});

tests/set_test.cc

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -719,6 +719,66 @@ TEST(SetTest, LazyZipWithStdVector)
719719
EXPECT_EQ(expected, zipped);
720720
}
721721

722+
TEST(SetTest, LazySourceCanOutliveFunctionalSet)
723+
{
724+
lazy_set<int> lazy_numbers;
725+
{
726+
const set<int> numbers({1, 2, 3, 4});
727+
lazy_numbers = numbers
728+
.lazy()
729+
.filter([](const int& value) {
730+
return value > 2;
731+
});
732+
}
733+
734+
EXPECT_EQ(set<int>({3, 4}), lazy_numbers.get());
735+
}
736+
737+
TEST(SetTest, LazySourceCanStartFromTemporaryFunctionalSet)
738+
{
739+
const auto lazy_numbers = set<int>({1, 2, 3, 4})
740+
.lazy()
741+
.map<int>([](const int& value) {
742+
return value * 2;
743+
});
744+
745+
EXPECT_EQ(set<int>({2, 4, 6, 8}), lazy_numbers.get());
746+
}
747+
748+
TEST(SetTest, LazyZipWithTemporaryFunctionalSet)
749+
{
750+
const set<int> ages({25, 45, 30, 63});
751+
752+
const auto lazy_zipped = ages
753+
.lazy()
754+
.zip(set<std::string>({"Jake", "Bob", "Michael", "Philipp"}));
755+
756+
const auto expected = set<std::pair<int, std::string>>({
757+
std::pair<int, std::string>(25, "Bob"),
758+
std::pair<int, std::string>(30, "Jake"),
759+
std::pair<int, std::string>(45, "Michael"),
760+
std::pair<int, std::string>(63, "Philipp"),
761+
});
762+
EXPECT_EQ(expected, lazy_zipped.get());
763+
}
764+
765+
TEST(SetTest, LazyZipWithTemporaryStdSet)
766+
{
767+
const set<int> ages({25, 45, 30, 63});
768+
769+
const auto lazy_zipped = ages
770+
.lazy()
771+
.zip(std::set<std::string>({"Jake", "Bob", "Michael", "Philipp"}));
772+
773+
const auto expected = set<std::pair<int, std::string>>({
774+
std::pair<int, std::string>(25, "Bob"),
775+
std::pair<int, std::string>(30, "Jake"),
776+
std::pair<int, std::string>(45, "Michael"),
777+
std::pair<int, std::string>(63, "Philipp"),
778+
});
779+
EXPECT_EQ(expected, lazy_zipped.get());
780+
}
781+
722782
TEST(SetTest, LazyZipWithLazyVector)
723783
{
724784
const set<int> ages({25, 45, 30, 63});
@@ -849,6 +909,17 @@ TEST(SetTest, LazyDifferenceWithLazySet)
849909
EXPECT_EQ(6, map_call_count);
850910
}
851911

912+
TEST(SetTest, LazyDifferenceWithTemporaryFunctionalSet)
913+
{
914+
const set<int> set1({1, 2, 3, 5, 7, 8, 10});
915+
916+
const auto lazy_diff = set1
917+
.lazy()
918+
.difference_with(set<int>({2, 5, 7, 10, 15, 17}));
919+
920+
EXPECT_EQ(set<int>({1, 3, 8}), lazy_diff.get());
921+
}
922+
852923
TEST(SetTest, LazyUnionWithFunctionalSet)
853924
{
854925
const set<int> set1({1, 2, 3, 5, 7, 8, 10});
@@ -909,6 +980,17 @@ TEST(SetTest, LazyUnionWithLazySet)
909980
EXPECT_EQ(6, map_call_count);
910981
}
911982

983+
TEST(SetTest, LazyUnionWithTemporaryFunctionalSet)
984+
{
985+
const set<int> set1({1, 2, 3, 5, 7, 8, 10});
986+
987+
const auto lazy_combined = set1
988+
.lazy()
989+
.union_with(set<int>({2, 5, 7, 10, 15, 17}));
990+
991+
EXPECT_EQ(set<int>({1, 2, 3, 5, 7, 8, 10, 15, 17}), lazy_combined.get());
992+
}
993+
912994
TEST(SetTest, LazyIntersectionWithFunctionalSet)
913995
{
914996
const set<int> set1({1, 2, 3, 5, 7, 8, 10});
@@ -968,3 +1050,14 @@ TEST(SetTest, LazyIntersectionWithLazySet)
9681050
EXPECT_EQ(set<int>({3, 5, 7, 10}), intersection);
9691051
EXPECT_EQ(6, map_call_count);
9701052
}
1053+
1054+
TEST(SetTest, LazyIntersectionWithTemporaryFunctionalSet)
1055+
{
1056+
const set<int> set1({1, 2, 3, 5, 7, 8, 10});
1057+
1058+
const auto lazy_intersection = set1
1059+
.lazy()
1060+
.intersect_with(set<int>({2, 5, 7, 10, 15, 17}));
1061+
1062+
EXPECT_EQ(set<int>({2, 5, 7, 10}), lazy_intersection.get());
1063+
}

0 commit comments

Comments
 (0)