-
Notifications
You must be signed in to change notification settings - Fork 1
/
generator.inl
155 lines (137 loc) · 3.72 KB
/
generator.inl
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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
//
// Generator.cpp
// buffermanager
//
// Created by Simon Wagner on 10.06.13.
// Copyright (c) 2013 DBTUM. All rights reserved.
//
#include "Generator.hpp"
#include <ucontext.h>
#include <cassert>
#include <utility>
#include <iostream>
using namespace std;
template<typename GT>
GeneratorIterator<GT>::GeneratorIterator(Generator<GT>& generator, int64_t index)
: generator(generator), index(index)
{
value = nullptr;
// fetch the first value after initialisation
//might not fetch anythin, if no data is available
next();
}
template<typename GT>
bool GeneratorIterator<GT>::next()
{
if(index == END_INDEX)
{
return false; //if we are already at the end, do not fetch the next item
}
//fetch the next item
bool hasNext = generator.hasNext();
if(!hasNext)
{
//if we do not have a next item, set the index to END_INDEX
index = END_INDEX;
return false;
}
else
{
//if we do have an valid index fetch value from generator
//very inefficent, has someone a better idea how to handle this
//without allocating new objects each time we iterate
value = new GT(move(generator.next()));
return true;
}
}
template<typename GT>
GeneratorIterator<GT>& GeneratorIterator<GT>::operator++() //++GeneratorIterator
{
if(next()) index++; //advance the index, if we have fetched a new value
return *this;
}
template<typename GT>
GeneratorIterator<GT> GeneratorIterator<GT>::operator++(int) //GeneratorIterator++
{
GeneratorIterator tmp(*this);
++*this;
return tmp;
}
template<typename GT>
Generator<GT>::Generator(GeneratorRunCallback run)
: m_Run(run), m_state(GeneratorState::UNKNOWN)
{
//get the current context as starting point for the generator context
getcontext(&m_generatorContext);
//calculate the arguments for the generatorCallback
uint64_t generatorAdress = (uint64_t)this;
uint32_t upperHalf = (uint32_t)(generatorAdress >> 32);
uint32_t lowerHalf = (uint32_t)(generatorAdress & 0xFFFFFFFF);
//allocate stack for context
m_stackData = malloc(SIGSTKSZ);
stack_t stack;
stack.ss_size = SIGSTKSZ;
stack.ss_sp = m_stackData;
stack.ss_flags = 0;
m_generatorContext.uc_stack = stack;
//create the context
makecontext(&m_generatorContext, (void(*)())&(Generator::generatorCallback), 2, upperHalf, lowerHalf);
}
template<typename GT>
Generator<GT>::~Generator()
{
free(m_stackData);
}
template<typename GT>
void Generator<GT>::generatorCallback(uint32_t upperHalf, uint32_t lowerHalf)
{
uint64_t generatorAdress = (uint64_t)upperHalf << 32 | lowerHalf;
Generator* generator = (Generator*)(generatorAdress);
generator->m_Run(*generator);
generator->exit();
}
template<typename GT>
void Generator<GT>::yield(GT&& value)
{
m_Next = new GT(move(value));
m_state = GeneratorState::HAS_NEXT;
swapcontext(&m_generatorContext, &m_mainContext);
}
template<typename GT>
void Generator<GT>::exit()
{
if(m_state != GeneratorState::END)
{
m_state = GeneratorState::END;
setcontext(&m_mainContext);
}
}
template<typename GT>
GT Generator<GT>::next()
{
if(m_state == GeneratorState::UNKNOWN)
{
take();
}
assert(m_state == GeneratorState::HAS_NEXT);
m_state = GeneratorState::UNKNOWN;
GT&& return_value = move(*(this->m_Next));
delete this->m_Next;
return return_value;
}
template<typename GT>
bool Generator<GT>::hasNext()
{
if(m_state == GeneratorState::UNKNOWN)
{
take();
}
return m_state == GeneratorState::HAS_NEXT;
}
template<typename GT>
void Generator<GT>::take()
{
assert(m_state == GeneratorState::UNKNOWN);
swapcontext(&m_mainContext, &m_generatorContext);
assert(m_state == GeneratorState::HAS_NEXT || m_state == GeneratorState::END);
}