Commit 2372171d authored by Paul's avatar Paul
Browse files

Add simple eval test

parent f0c7f958
...@@ -5,6 +5,7 @@ project(rtglib) ...@@ -5,6 +5,7 @@ project(rtglib)
add_compile_options(-std=c++14) add_compile_options(-std=c++14)
add_library(rtg add_library(rtg
src/program.cpp
src/shape.cpp src/shape.cpp
) )
target_include_directories(rtg PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>) target_include_directories(rtg PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>)
......
#ifndef GUARD_RTGLIB_ARGUMENT_HPP
#define GUARD_RTGLIB_ARGUMENT_HPP
#include <rtg/shape.hpp>
#include <functional>
namespace rtg {
struct argument
{
std::function<char*()> data;
shape s;
template<class Visitor>
void visit(Visitor v) const
{
s.visit_type([&](auto as) {
v(as.from(data()));
});
}
};
}
#endif
#ifndef GUARD_RTGLIB_INSTRUCTION_HPP #ifndef GUARD_RTGLIB_INSTRUCTION_HPP
#define GUARD_RTGLIB_INSTRUCTION_HPP #define GUARD_RTGLIB_INSTRUCTION_HPP
#include <rtg/operand.hpp> #include <rtg/literal.hpp>
#include <rtg/shape.hpp> #include <rtg/shape.hpp>
#include <string>
namespace rtg { namespace rtg {
struct instruction struct instruction
{ {
unsigned int id; instruction() {}
instruction(std::string n, shape r, std::vector<instruction*> args)
: name(std::move(n)), result(std::move(r)), arguments(std::move(args))
{}
instruction(literal l)
: name("literal"), result(l.get_shape()), lit(std::move(l))
{}
std::string name; std::string name;
shape result; shape result;
std::vector<instruction*> arguments; std::vector<instruction*> arguments;
literal lit;
}; };
} }
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
#define GUARD_RTGLIB_LITERAL_HPP #define GUARD_RTGLIB_LITERAL_HPP
#include <rtg/shape.hpp> #include <rtg/shape.hpp>
#include <rtg/argument.hpp>
namespace rtg { namespace rtg {
...@@ -27,6 +28,10 @@ struct literal ...@@ -27,6 +28,10 @@ struct literal
std::copy(x.begin(), x.end(), reinterpret_cast<T*>(buffer.data())); std::copy(x.begin(), x.end(), reinterpret_cast<T*>(buffer.data()));
} }
literal(shape s, const char* x)
: buffer(x, x+s.bytes()), shape_(s)
{}
friend bool operator==(const literal& x, const literal& y) friend bool operator==(const literal& x, const literal& y)
{ {
bool result = x.buffer.empty() && y.buffer.empty(); bool result = x.buffer.empty() && y.buffer.empty();
...@@ -76,6 +81,15 @@ struct literal ...@@ -76,6 +81,15 @@ struct literal
return this->shape_; return this->shape_;
} }
argument get_argument() const
{
argument arg;
auto b = buffer;
arg.s = shape_;
arg.data = [b]() mutable { return b.data(); };
return arg;
}
private: private:
std::vector<char> buffer; std::vector<char> buffer;
shape shape_; shape shape_;
......
#ifndef GUARD_RTGLIB_OPERAND_HPP #ifndef GUARD_RTGLIB_OPERAND_HPP
#define GUARD_RTGLIB_OPERAND_HPP #define GUARD_RTGLIB_OPERAND_HPP
#include <string>
#include <functional> #include <functional>
#include <rtg/shape.hpp> #include <rtg/shape.hpp>
#include <rtg/argument.hpp>
namespace rtg { namespace rtg {
struct argument
{
void* data;
shape s;
};
struct operand struct operand
{ {
std::string name; std::string name;
......
#ifndef GUARD_RTGLIB_PROGRAM_HPP #ifndef GUARD_RTGLIB_PROGRAM_HPP
#define GUARD_RTGLIB_PROGRAM_HPP #define GUARD_RTGLIB_PROGRAM_HPP
#include <deque> #include <list>
#include <unordered_map> #include <unordered_map>
#include <rtg/instruction.hpp> #include <rtg/instruction.hpp>
#include <rtg/operand.hpp>
namespace rtg { namespace rtg {
struct program struct program
{ {
// A deque is used to keep references to an instruction stable template<class... Ts>
std::deque<instruction> instructions; instruction * add_instruction(std::string name, Ts*... args)
{
auto&& op = ops.at(name);
shape r = op.compute_shape({args->result...});
instructions.push_back({name, r, {args...}});
return std::addressof(instructions.back());
}
template<class... Ts>
instruction * add_literal(Ts&&... xs)
{
instructions.emplace_back(literal{std::forward<Ts>(xs)...});
return std::addressof(instructions.back());
}
template<class Op, class Shape>
void add_operator(std::string name, Op op, Shape s)
{
operand result;
result.name = name;
result.compute = op;
result.compute_shape = s;
ops.emplace(name, result);
}
literal eval() const;
private:
// A list is used to keep references to an instruction stable
std::list<instruction> instructions;
std::unordered_map<std::string, operand> ops; std::unordered_map<std::string, operand> ops;
......
#include <rtg/program.hpp>
#include <algorithm>
namespace rtg {
literal program::eval() const
{
std::unordered_map<const instruction*, argument> results;
argument result;
for(auto& ins:instructions)
{
if(ins.name == "literal")
{
result = ins.lit.get_argument();
}
else
{
auto&& op = ops.at(ins.name);
std::vector<argument> values(ins.arguments.size());
std::transform(ins.arguments.begin(), ins.arguments.end(), values.begin(), [&](instruction * i) {
return results.at(i);
});
result = op.compute(values);
}
results.emplace(std::addressof(ins), result);
}
return literal{result.s, result.data()};
}
}
#include <rtg/program.hpp>
#include <rtg/argument.hpp>
#include <rtg/shape.hpp>
#include "test.hpp"
int main() {
rtg::program p;
p.add_operator("sum",
[](std::vector<rtg::argument> args) {
rtg::argument result;
if(args.size() != 2) throw "Wrong args";
if(args[0].s != args[1].s) throw "Wrong args";
if(args[0].s.lens().size() != 1) throw "Wrong args";
if(args[0].s.lens().front() != 1) throw "Wrong args";
args[0].visit([&](auto x) {
args[1].visit([&](auto y) {
result = rtg::literal{x + y}.get_argument();
});
});
return result;
},
[](std::vector<rtg::shape> inputs) {
if(inputs.size() != 2) throw "Wrong inputs";
return inputs.front();
}
);
auto one = p.add_literal(1);
auto two = p.add_literal(2);
p.add_instruction("sum", one, two);
EXPECT(p.eval() == rtg::literal{3});
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment