Created
March 13, 2018 15:47
-
-
Save Klowner/68eda17e9f5e649ba76da18d87dcfd82 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// (C) 2018 Mark Riedesel <mark@klowner.com> | |
// http://sensible.website/posts/serializing-tasks-with-c++-metaprogramming/ | |
// The following code is licensed under the MIT license. | |
#include <cstdint> | |
#include <cstring> | |
#include <iostream> | |
using CommandId = uint16_t; | |
struct Stream { | |
Stream() | |
: write_pos(0) | |
, read_pos(0) | |
{ | |
memset(&buffer, 0, sizeof(buffer)); | |
} | |
int write(void *_src, size_t _bytes) { | |
if (write_pos + _bytes < capacity) { | |
memcpy(&buffer[write_pos], _src, _bytes); | |
write_pos += _bytes; | |
return _bytes; // return number of byte written | |
} | |
return 0; // failure | |
} | |
int read(void *_dst, size_t _bytes) { | |
if (read_pos + _bytes < capacity) { | |
memcpy(_dst, &buffer[read_pos], _bytes); | |
read_pos += _bytes; | |
return _bytes; // return number of bytes read | |
} | |
return 0; // failure | |
} | |
CommandId getNextCommandId() const { | |
CommandId id; | |
memcpy(&id, &buffer[read_pos], sizeof(id)); | |
return id; | |
} | |
static constexpr const size_t capacity { 1024 }; | |
uint8_t buffer[capacity]; | |
size_t write_pos; | |
size_t read_pos; | |
}; | |
struct CommandType { | |
enum Enum { | |
End = 0, | |
CallTask, | |
}; | |
}; | |
using TaskFunctionPtr = void(*)(Stream&); | |
struct CallTaskCommand { | |
CommandId type; | |
TaskFunctionPtr function_ptr; | |
}; | |
// Tasks | |
struct task_a { | |
int execute(int foo, int bar) { | |
std::cout << "executing task_a with args: " << foo << ' ' << bar << '\n'; | |
return foo * bar; | |
} | |
}; | |
struct task_b { | |
int execute(int foo, int bar, int baz) { | |
std::cout << "executing task_b with args: " << foo << ' ' << bar << ' ' << baz << '\n'; | |
return foo * bar * baz; | |
} | |
}; | |
template <typename A> | |
inline A task_decode_arg(Stream &_stream) { | |
A arg; | |
_stream.read(&arg, sizeof(A)); | |
std::cout << "decoding: " << arg << '\n'; | |
return arg; | |
} | |
template <typename T, typename ...Args> | |
void task_decode(Stream &_stream) { | |
T instance; | |
instance.execute(task_decode_arg<Args>(_stream) ...); | |
} | |
template <typename T, typename Head> | |
inline void constexpr task_encode_r(Stream &stream, Head &&_head) { | |
std::cout << "encoding: " << _head << '\n'; | |
stream.write(&_head, sizeof(Head)); | |
} | |
template <typename T, typename Head, typename ...Tail> | |
inline void constexpr task_encode_r(Stream &stream, Head &&_head, Tail &&..._tail) { | |
task_encode_r<T>(stream, _tail...); | |
task_encode_r<T>(stream, _head); | |
} | |
template <typename T, typename ...Args> | |
void constexpr task_encode(Stream &_stream, Args &&..._args) { | |
CallTaskCommand call_task; | |
call_task.type = CommandType::CallTask; | |
call_task.function_ptr = &task_decode<T, Args...>; | |
_stream.write(&call_task, sizeof(CallTaskCommand)); | |
task_encode_r<T>(_stream, _args...); | |
} | |
void execute(Stream &_stream) { | |
CommandId command_type; | |
while ((command_type = _stream.getNextCommandId()) != CommandType::End) { | |
switch(command_type) { | |
case CommandType::CallTask: { | |
CallTaskCommand cmd; | |
_stream.read(&cmd, sizeof(CallTaskCommand)); | |
cmd.function_ptr(_stream); | |
} break; | |
case CommandType::End: | |
default: | |
return; | |
} | |
} | |
} | |
void test() { | |
Stream stream; | |
std::cout << "recording phase..." << '\n'; | |
task_encode<task_a>(stream, 1, 2); | |
task_encode<task_b>(stream, 4, 5, 6); | |
std::cout << "\nexecution phase..." << '\n'; | |
for (int i = 0; i < 4; i++) { | |
std::cout << "execute iteration " << i << '\n'; | |
stream.read_pos = 0; | |
execute(stream); | |
} | |
} | |
int main() { | |
test(); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment