Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added boolinq::mut_from and modified for each to be able to mutate #67

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 104 additions & 3 deletions include/boolinq/boolinq.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ namespace boolinq {
//

struct LinqEndException {};
struct LinqNonMutableException {};
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why can't utilize the same LinqEndException exception for this mutable case?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can utilize the same exception. You can remove the LinqNonMutableException completely.
But for Debugging and using the Lib I think it is cleaner to have a dedicated Exception.


enum BytesDirection {
BytesFirstToLast,
Expand All @@ -45,8 +46,11 @@ namespace boolinq {

template<typename S, typename T>
class Linq {

std::function<T(S &)> nextFunc;
std::function<void* (S &)> ref_nextFunc;
S storage;
bool isMutable;

public:
typedef T value_type;
Expand All @@ -55,7 +59,10 @@ namespace boolinq {
{
}

Linq(S storage, std::function<T(S &)> nextFunc) : nextFunc(nextFunc), storage(storage)
Linq(S storage, std::function<T(S &)> nextFunc) : nextFunc(nextFunc), ref_nextFunc([](S &) {return nullptr; }), storage(storage), isMutable(false)
{
}
Linq(S storage, std::function<void* (S &)> ref_nextFunc) : storage(storage), nextFunc([ref_nextFunc](S & s) {return *(T*)(ref_nextFunc(s)); }), ref_nextFunc(ref_nextFunc), isMutable(true)
{
}

Expand All @@ -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<void(T, int)> apply) const
{
Linq<S, T> linq = *this;
Expand All @@ -75,9 +88,32 @@ namespace boolinq {
catch (LinqEndException &) {}
}

void for_each(std::function<void(T)> apply) const
void mut_for_each_i(std::function<void(T &, int)> apply) const
{
Linq<S, T> linq = *this;
try {
for (int i = 0; ; i++) {
apply(*linq.ref_next(), i);
}
}
catch (LinqEndException&) {}
}

void for_each(std::function<void(T &)> 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<typename T,
typename = std::enable_if < std::is_lvalue_reference<T>::value,bool> = false>
void for_each(std::function<void(T const)> apply) const
{
return for_each_i([apply](T value, int) { return apply(value); });

}

Linq<std::tuple<Linq<S, T>, int>, T> where_i(std::function<bool(T, int)> filter) const
Expand Down Expand Up @@ -862,6 +898,71 @@ namespace boolinq {
return from(container.cbegin(), container.cend());
}

template<typename T>
Linq<std::pair<T, T>, typename std::iterator_traits<T>::value_type> mut_from(const T& begin, const T& end)
{
return Linq<std::pair<T, T>, typename std::iterator_traits<T>::value_type>(
std::make_pair(begin, end),
[](std::pair<T, T>& pair) {
if (pair.first == pair.second) {
throw LinqEndException();
}
return ((void*)&(*(pair.first++)));
}
);
}

template<typename T>
Linq<std::pair<T, T>, typename std::iterator_traits<T>::value_type> mut_from(const T& it, int n)
{
return mut_from(it, it + n);
}

template<typename T, int N>
Linq<std::pair<const T*, const T*>, T> mut_from(T(&array)[N])
{
return mut_from((const T*)(&array), (const T*)(&array) + N);
}

template<template<class> class TV, typename TT>
auto mut_from(const TV<TT>& container)
-> decltype(mut_from(container.cbegin(), container.cend()))
{
return mut_from(container.cbegin(), container.cend());
}

// std::list, std::vector, std::dequeue
template<template<class, class> class TV, typename TT, typename TU>
auto mut_from(const TV<TT, TU>& container)
-> decltype(mut_from(container.cbegin(), container.cend()))
{
return mut_from(container.cbegin(), container.cend());
}

// std::set
template<template<class, class, class> class TV, typename TT, typename TS, typename TU>
auto mut_from(const TV<TT, TS, TU>& container)
-> decltype(mut_from(container.cbegin(), container.cend()))
{
return mut_from(container.cbegin(), container.cend());
}

// std::map
template<template<class, class, class, class> class TV, typename TK, typename TT, typename TS, typename TU>
auto mut_from(const TV<TK, TT, TS, TU>& container)
-> decltype(mut_from(container.cbegin(), container.cend()))
{
return mut_from(container.cbegin(), container.cend());
}

// std::array
template<template<class, size_t> class TV, typename TT, size_t TL>
auto mut_from(const TV<TT, TL>& container)
-> decltype(mut_from(container.cbegin(), container.cend()))
{
return mut_from(container.cbegin(), container.cend());
}

template<typename T>
Linq<std::pair<T, int>, T> repeat(const T & value, int count) {
return Linq<std::pair<T, int>, T>(
Expand Down Expand Up @@ -894,4 +995,4 @@ namespace boolinq {
}
);
}
}
}
57 changes: 57 additions & 0 deletions test/ForEachTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}