diff --git a/include/boolinq/boolinq.h b/include/boolinq/boolinq.h index aece8de..5b63fb2 100644 --- a/include/boolinq/boolinq.h +++ b/include/boolinq/boolinq.h @@ -32,6 +32,7 @@ namespace boolinq { // struct LinqEndException {}; + struct LinqNonMutableException {}; enum BytesDirection { BytesFirstToLast, @@ -45,8 +46,11 @@ namespace boolinq { template class Linq { + std::function nextFunc; + std::function ref_nextFunc; S storage; + bool isMutable; public: typedef T value_type; @@ -55,7 +59,10 @@ namespace boolinq { { } - Linq(S storage, std::function nextFunc) : nextFunc(nextFunc), storage(storage) + Linq(S storage, std::function nextFunc) : nextFunc(nextFunc), ref_nextFunc([](S &) {return nullptr; }), storage(storage), isMutable(false) + { + } + Linq(S storage, std::function ref_nextFunc) : storage(storage), nextFunc([ref_nextFunc](S & s) {return *(T*)(ref_nextFunc(s)); }), ref_nextFunc(ref_nextFunc), isMutable(true) { } @@ -64,6 +71,12 @@ namespace boolinq { return nextFunc(storage); } + T* ref_next() + { + if (!isMutable) throw LinqNonMutableException(); + return (T*)ref_nextFunc(storage); + } + void for_each_i(std::function apply) const { Linq linq = *this; @@ -75,9 +88,32 @@ namespace boolinq { catch (LinqEndException &) {} } - void for_each(std::function apply) const + void mut_for_each_i(std::function apply) const + { + Linq linq = *this; + try { + for (int i = 0; ; i++) { + apply(*linq.ref_next(), i); + } + } + catch (LinqEndException&) {} + } + + void for_each(std::function apply) const + { + if (isMutable) + return mut_for_each_i([apply](T & value, int) { return apply(value); }); + else + return for_each_i([apply](T value, int) { return apply(value); }); + + } + + template::value,bool> = false> + void for_each(std::function apply) const { return for_each_i([apply](T value, int) { return apply(value); }); + } Linq, int>, T> where_i(std::function filter) const @@ -862,6 +898,71 @@ namespace boolinq { return from(container.cbegin(), container.cend()); } + template + Linq, typename std::iterator_traits::value_type> mut_from(const T& begin, const T& end) + { + return Linq, typename std::iterator_traits::value_type>( + std::make_pair(begin, end), + [](std::pair& pair) { + if (pair.first == pair.second) { + throw LinqEndException(); + } + return ((void*)&(*(pair.first++))); + } + ); + } + + template + Linq, typename std::iterator_traits::value_type> mut_from(const T& it, int n) + { + return mut_from(it, it + n); + } + + template + Linq, T> mut_from(T(&array)[N]) + { + return mut_from((const T*)(&array), (const T*)(&array) + N); + } + + template class TV, typename TT> + auto mut_from(const TV& container) + -> decltype(mut_from(container.cbegin(), container.cend())) + { + return mut_from(container.cbegin(), container.cend()); + } + + // std::list, std::vector, std::dequeue + template class TV, typename TT, typename TU> + auto mut_from(const TV& container) + -> decltype(mut_from(container.cbegin(), container.cend())) + { + return mut_from(container.cbegin(), container.cend()); + } + + // std::set + template class TV, typename TT, typename TS, typename TU> + auto mut_from(const TV& container) + -> decltype(mut_from(container.cbegin(), container.cend())) + { + return mut_from(container.cbegin(), container.cend()); + } + + // std::map + template class TV, typename TK, typename TT, typename TS, typename TU> + auto mut_from(const TV& container) + -> decltype(mut_from(container.cbegin(), container.cend())) + { + return mut_from(container.cbegin(), container.cend()); + } + + // std::array + template class TV, typename TT, size_t TL> + auto mut_from(const TV& container) + -> decltype(mut_from(container.cbegin(), container.cend())) + { + return mut_from(container.cbegin(), container.cend()); + } + template Linq, T> repeat(const T & value, int count) { return Linq, T>( @@ -894,4 +995,4 @@ namespace boolinq { } ); } -} +} \ No newline at end of file diff --git a/test/ForEachTest.cpp b/test/ForEachTest.cpp index fa3955f..2f351bb 100644 --- a/test/ForEachTest.cpp +++ b/test/ForEachTest.cpp @@ -46,3 +46,60 @@ TEST(ForEach, ThreeIntsSum) EXPECT_EQ(60, sum); } + + + +TEST(ForEach, Mutation_Struct) +{ + struct _Human { + + std::string name; + int age; + + std::string toString() { + + std:: stringstream s; + s << "- name : " << name << " age : " << age << " -"; + return s.str(); + } + + }; + _Human items[4] = { {"Albert",56}, + {"Heinrich",64}, + {"Renate",75}, + {"Anneliese",45} }; + + mut_from(items).for_each([](_Human& human) mutable {human.age += 1; }); + + EXPECT_EQ(items[0].age, 57); + EXPECT_EQ(items[1].age, 65); + EXPECT_EQ(items[2].age, 76); + EXPECT_EQ(items[3].age, 46); +} +TEST(ForEach, NonMutable_Struct) +{ + struct _Human { + + std::string name; + int age; + + std::string toString() { + + std::stringstream s; + s << "- name : " << name << " age : " << age << " -"; + return s.str(); + } + + }; + _Human items[4] = { {"Albert",56}, + {"Heinrich",64}, + {"Renate",75}, + {"Anneliese",45} }; + + from(items).for_each([](_Human& human) mutable {human.age += 1; }); + + EXPECT_EQ(items[0].age, 56); + EXPECT_EQ(items[1].age, 64); + EXPECT_EQ(items[2].age, 75); + EXPECT_EQ(items[3].age, 45); +} \ No newline at end of file