Skip to content

Instantly share code, notes, and snippets.

@Heimdell
Last active December 16, 2015 06:28
Show Gist options
  • Save Heimdell/5391469 to your computer and use it in GitHub Desktop.
Save Heimdell/5391469 to your computer and use it in GitHub Desktop.
Compile with `g++ -std=c++11 test.c++`. Use g++ of version 4.7.2 and... patience.
#ifndef AUTOWIRE_H
#define AUTOWIRE_H
#include <map>
#include <string>
#include <stdexcept>
using namespace std;
#include "singleton.h"
#include "interpolate.h"
template <class Key, class Value>
struct Autowire
{
typedef map<Key, Value> Map;
Autowire &assume(Key key, Value &&value) {
mapping[key] = value;
return *this;
}
Value &resolve(Key key) {
if (mapping.find(key) == mapping.end())
throw domain_error(intercalate(" ", "the key", key, "cannot be resolved"));
return mapping[key];
}
private:
Map mapping;
};
template <class Key, class Value>
Singleton<Autowire<Key, Value>> &wiring() { return single<Autowire<Key, Value>>(); }
#endif
#ifndef CONCAT_H
#define CONCAT_H
template <class CA, class CB>
CA &&concat(CA &&ca, CB &&cb) {
ca.insert(end(ca), begin(cb), end(cb));
return ca;
}
#endif
#ifndef CPU_H
#define CPU_H
#include "autowire.h"
#include "protocol.h"
template <class Definition, class Serialized>
using opcode = Autowire<Definition, function<Serialized (const Command<Definition> &)>>;
template <class Definition, class Serialized>
struct Cpu : public opcode<Definition, Serialized>
{
typedef Command<Definition> CommandType;
Serialized evaluate(const Command<Definition> & cmd) {
auto opc = this->resolve(cmd.definition);
return opc(cmd);
}
};
#endif
#ifndef INTERPOLATE_H
#define INTERPOLATE_H
#include <sstream>
#include <string>
using namespace std;
inline string _interpolate(stringstream &os) {
return os.str();
}
template <class Head, class... Tail>
string _interpolate(stringstream &os, Head head, Tail... tail) {
os << head;
return _interpolate(os, tail...);
}
template <class... Args>
string interpolate(Args... args) {
stringstream os;
return _interpolate(os, args...);
}
template <class... Args>
string line(Args... args) {
return interpolate(args..., "\n");
}
template <class Last>
string _intercalate(string, stringstream &os, Last last) {
os << last;
return os.str();
}
template <class Head, class... Tail>
string _intercalate(string sep, stringstream &os, Head head, Tail... tail) {
os << head << sep;
return _intercalate(sep, os, tail...);
}
template <class... Args>
string intercalate(string sep, Args... args) {
stringstream os;
return _intercalate(sep, os, args...);
}
#endif
#ifndef LABELLED_H
#define LABELLED_H
#if 0
template <class, class T>
struct Labelled
{
T * operator -> () { return &t; }
private:
T t;
};
#else
template <class, class T>
struct Labelled : public T { };
#endif
#define DECLARE_LABEL(Label) struct Label {};
DECLARE_LABEL(Default);
#endif
#ifndef PROTOCOL_H
#define PROTOCOL_H
#include <vector>
#include <tuple>
#include <list>
#include <functional>
using namespace std;
template <class Definition>
void complain_about_params_count(string type, Definition name, int has, int must);
template <class Definition>
struct Command {
Command(Definition definition,
vector<int> &&ints,
vector<float> &&floats,
vector<string> &&strings)
: definition(definition),
ints (ints),
floats (floats),
strings (strings)
{}
Definition definition;
vector<int> ints;
vector<float> floats;
vector<string> strings;
#define ASSERT_ARGCOUNT(type) \
void assert_##type##_args_count(int n) const { \
if (type##s.size() < n) \
complain_about_params_count(#type, definition, type##s.size(), n); \
}
ASSERT_ARGCOUNT(int);
ASSERT_ARGCOUNT(float);
ASSERT_ARGCOUNT(string);
};
template <class Definition>
inline void complain_about_params_count(string type, Definition name, int has, int must) {
throw runtime_error(
intercalate(" ",
"not enouth",
type,
"params in command",
name,
":",
"there is",
has,
"but must be at least",
must
)
);
}
#endif
#ifndef SINGLETON_H
#define SINGLETON_H
template <class T>
struct Singleton : public T {
static Singleton &instance() { return _instance; }
private:
static Singleton _instance;
Singleton() { }
Singleton(Singleton &&) = delete;
Singleton(const Singleton &) = delete;
};
template <class T>
Singleton<T> Singleton<T>::_instance;
template <class T>
Singleton<T> &single() { return Singleton<T>::instance(); }
#endif
#include "streamer.h"
#include <iostream>
int main() {
auto &streamer = single<Streamer<string, char>>();
typedef
decay<decltype(streamer)>
::type
::StreamCpu
::CommandType CMD;
auto &cpu = streamer.cpu();
cpu
.assume("add",
[](const CMD &cmd) {
cmd.assert_int_args_count(2);
return list<char>({
'+',
(char) ('0' + cmd.ints[0]),
(char) ('0' + cmd.ints[1])
});
})
.assume("nop",
[](const CMD &cmd) {
return list<char>({ 'X' });
})
.assume("echo",
[](const CMD &cmd) {
cmd.assert_string_args_count(1);
const string &&arg = cmd.strings[0].substr(0, 255);
list<char> mark = { '!' };
return concat(mark, interpolate(arg.size(), ">", arg));
})
;
list<CMD> commands = {
{ "add", {1, 2}, {}, {}},
{ "nop", {}, {}, {}},
{ "echo", {}, {}, {"hello, world"}}
};
list<char> packed = streamer.translate(commands);
string out;
concat(out, packed);
cout << out << endl;
}
#ifndef STREAMER_H
#define STREAMER_H
#include "cpu.h"
#include "labelled.h"
#include "concat.h"
#include <algorithm>
template <class Definition, class Cell, class Name = Default>
struct Streamer {
typedef Cpu<Definition, list<Cell>> StreamCpu;
typedef typename StreamCpu::CommandType StreamCommand;
template <class T>
using Stream = list<T>;
Singleton<Labelled<Name, StreamCpu>> &cpu() { return single<Labelled<Name, StreamCpu>>(); }
Stream<Cell> translate(Stream<StreamCommand> commands) {
auto &cpu = this->cpu();
Stream<Cell> out;
for_each(
begin(commands),
end (commands),
[&out, &cpu](StreamCommand command) {
list<Cell> part = cpu.evaluate(command);
out.insert(out.end(), part.begin(), part.end());
}
);
return out;
}
};
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment