-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathgenerators.h
More file actions
136 lines (126 loc) · 3.02 KB
/
generators.h
File metadata and controls
136 lines (126 loc) · 3.02 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
#ifndef _GENERATORS_H_
#define _GENERATORS_H_
#include<exception>
#include<functional>
#include<pthread.h>
namespace generator_utils {
// Needed because pthreads wants a raw C function
void* invoke_callback(void* callback) {
(*static_cast<std::function<void()>*>(callback))();
return NULL;
}
template<typename T>
class ForLooping {
private:
T* gen;
public:
ForLooping(T* _gen) : gen(_gen) {};
ForLooping<T>& operator++() {
++(*gen);
return *this;
}
typename T::Output operator*(){
return **gen;
}
operator bool() const{
return gen && *gen;
}
operator T&() {
return *gen;
}
bool operator!=(const ForLooping<T>& oth) {
return static_cast<bool>(*this) != static_cast<bool>(oth);
}
};
}
template<typename Heart>
class Gen;
template<typename OutputT>
class GeneratorHeart {
private:
OutputT value;
bool hasOutputted;
pthread_mutex_t* mutex;
bool abort;
class AbortException : public std::exception {};
public:
typedef OutputT Output;
template<typename T>
friend class Gen;
GeneratorHeart() : hasOutputted(false), abort(false) {}
void yield(OutputT v) {
value = v;
hasOutputted = true;
while(hasOutputted) {
pthread_mutex_unlock(mutex);
pthread_yield();
pthread_mutex_lock(mutex);
}
if (abort) {
throw AbortException();
}
}
};
template<typename Heart>
class Gen {
private:
std::function<void()> callback;
Heart heart;
pthread_mutex_t mutex;
pthread_t thread;
bool done;
public:
typedef typename Heart::Output Output;
template<typename... ARGS>
Gen(ARGS... args) {
// Sanity checks for input
if (false) {
GeneratorHeart<Output>* just_checking = &heart;
heart.run(args...);
}
done = false;
// Use bind instead of capture because capture does not get along with parameter packs
callback=std::bind([&](Gen<Heart>* gen, ARGS... args){ gen->threadmain(args...); }, this, args...);
pthread_mutex_init(&this->mutex, NULL);
pthread_mutex_lock(&this->mutex);
heart.mutex = &this->mutex;
pthread_create (&this->thread, NULL, generator_utils::invoke_callback, static_cast<void*>(&callback));
++(*this);
}
~Gen() {
if (!done) {
heart.abort = true;
++(*this);
}
pthread_mutex_destroy(&this->mutex);
}
template<typename... ARGS>
void threadmain(ARGS... args) {
pthread_mutex_lock(&this->mutex);
try {
heart.run(args...);
} catch (typename Heart::AbortException ex) {}
done = true;
pthread_mutex_unlock(&this->mutex);
pthread_exit(NULL);
}
operator bool() {
return !done;
}
Gen<Heart>& operator++() {
heart.hasOutputted = false;
while(!heart.hasOutputted && !done){
pthread_mutex_unlock(&mutex);
pthread_yield();
pthread_mutex_lock(&mutex);
}
return *this;
}
Output operator*() {
return heart.value;
}
typedef generator_utils::ForLooping<Gen<Heart>> ForLooping;
ForLooping begin() { return ForLooping(this); }
ForLooping end() { return ForLooping(NULL); }
};
#endif // _GENERATORS_H_