Oxygen Engine
Modern C++ 3D Engine using OpenGL
Loading...
Searching...
No Matches
pipeline.h
1#ifndef OE_UTIL_PIPELINE_H
2#define OE_UTIL_PIPELINE_H
3
4#include <memory>
5#include <optional>
6
7namespace oe::detail
8{
9 template<typename Interface>
10 struct Implementation;
11}
12
13namespace oe::util
14{
15 template <typename Request, typename Response>
16 class Pipeline;
17
18 namespace pipeline
19 {
20 template <typename Request, typename Response>
21 class Handler
22 {
24
25 public:
26 virtual void init() {}
27 virtual void clean() {}
28
29 virtual ~Handler() {}
30
31 virtual Response handle(const Request& input) = 0;
32
33 Response next(const Request& input)
34 {
35 if (_next_handler != nullptr)
36 return _next_handler->handle(input);
37
38 // No next handler, return default Response
39 return _pipeline->getDefaultResponse();
40 }
41
42 protected:
43 ConcretePipeline* _pipeline = nullptr;
44
45 private:
46 Handler* _next_handler = nullptr;
47
48 friend ConcretePipeline;
49 };
50
56 template <typename Request, typename Response>
57 class LambdaHandler : public Handler<Request, Response>
58 {
59 using handler_function = Response (*)(const Request&, Handler<Request, Response>*);
60
61 public:
62 LambdaHandler(const handler_function& handler) : _handler(handler)
63 {}
64
65 Response handle(const Request& input) override
66 {
67 return _handler(input, this);
68 }
69
70 protected:
71 handler_function _handler;
72 };
73 }
74
103 template <typename Request, typename Response>
105 {
107 using handler_function = Response (*)(const std::string&, pipeline::Handler<Request, Response>*);
108
109 public:
115 template<class... Args>
116 Pipeline(Args&&... args) : _default_response(std::forward<Args>(args)...)
117 {
118
119 }
120
127 template <typename T, typename ...Args>
128 Pipeline& addPipe(const std::string& name, Args&& ...args)
129 {
130 std::unique_ptr<T> handler = std::make_unique<T>(std::forward<Args>(args)...);
131
132 handler->_pipeline = this;
133
134 _pipes.push_back(std::move(handler));
135
136 if (name != "")
137 _pipes_by_name[name] = _pipes.back().get();
138
139 _rebuildPipeOrder();
140
141 return *this;
142 }
143
148 void init()
149 {
150 for (auto& it : _pipes)
151 it->init();
152 }
153
158 void clean()
159 {
160 // Clean in reverse
161 for (auto it = _pipes.rbegin(); it != _pipes.rend(); ++it)
162 (*it)->clean();
163 }
164
168 Response run(const Request& request)
169 {
170 // Cannot use 'run' on an step-by-step pipe
171 assert(!_last_step_pipe);
172
173 if (_pipes.size() > 0)
174 {
175 #ifdef OE_UTIL_PIPELINE_RUN_BOTTOM_TO_TOP
176 return _pipes.back()->handle(request);
177 #else
178 return _pipes.front()->handle(request);
179 #endif
180
181 }
182
183 // No pipes, return default Response value
184 return _default_response;
185 }
186
187 Response getDefaultResponse() { return _default_response; }
188
194 template<class... Types>
195 void generateDefaultResponse(Types... args)
196 {
197 _default_response = {args...};
198 }
199
200 template <typename T>
201 T* getPipeByName(const std::string& name)
202 {
203 return static_cast<T*>(_pipes_by_name[name]);
204 }
205
206 void enableStepByStepMode()
207 {
208 _last_step_pipe.emplace(0);
209
210 for (auto it = _pipes.begin(); it != _pipes.end(); ++it)
211 {
212 (*it)->_next_handler = nullptr;
213 }
214 }
215
216 void disableStepByStepMode()
217 {
218 _last_step_pipe.reset();
219 _rebuildPipeOrder();
220 }
221
222 bool isStepByStepMode()
223 {
224 return (bool)_last_step_pipe;
225 }
226
227 std::pair<Response, bool> step(const Request& request)
228 {
229 // Cannot use 'step' on an linear pipe
230 assert(_last_step_pipe);
231
232 PipeHandler* pipe = _pipes[*_last_step_pipe].get();
233
234 ++(*_last_step_pipe);
235
236 bool has_more_pipes = _last_step_pipe < _pipes.size();
237
238 if (!has_more_pipes)
239 *_last_step_pipe = 0;
240
241 return {pipe->handle(request), has_more_pipes};
242 }
243
244 protected:
245 std::vector<std::unique_ptr<PipeHandler>> _pipes;
246 Response _default_response;
247
248 std::map<std::string, PipeHandler*> _pipes_by_name;
249
250 std::optional<int32_t> _last_step_pipe = std::nullopt;
251
252 void _rebuildPipeOrder()
253 {
254 #ifdef OE_UTIL_PIPELINE_RUN_BOTTOM_TO_TOP
255 PipeHandler* last_handler = _pipes.front();
256 last_handler->_next_handler = _pipes.size() > 1
257 ? *(*(_pipes.begin()+1))
258 : nullptr
259 ;
260
261 for (auto it = _pipes.begin()+1; it != _pipes.end(); ++it)
262 #else
263 PipeHandler* last_handler = _pipes.back().get();
264 last_handler->_next_handler = nullptr;
265
266 for (auto it = _pipes.rbegin()+1; it != _pipes.rend(); ++it)
267 #endif
268 {
269 (*it)->_next_handler = last_handler;
270 last_handler = it->get();
271 }
272 }
273 };
274}
275
276#endif
Definition pipeline.h:105
void init()
Definition pipeline.h:148
void generateDefaultResponse(Types... args)
Definition pipeline.h:195
Pipeline(Args &&... args)
Definition pipeline.h:116
void clean()
Definition pipeline.h:158
Pipeline & addPipe(const std::string &name, Args &&...args)
Definition pipeline.h:128
Response run(const Request &request)
Definition pipeline.h:168
Definition pipeline.h:22
Definition pipeline.h:58
Various utilities.
Definition byte_array.h:20