Skip to content

Commit

Permalink
Change interface to require Input and Output types.
Browse files Browse the repository at this point in the history
  • Loading branch information
asoffer committed Jan 25, 2024
1 parent b37dcdd commit 0999d33
Show file tree
Hide file tree
Showing 21 changed files with 414 additions and 288 deletions.
13 changes: 5 additions & 8 deletions examples/fibonacci.cc
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,11 @@ jasmin::Program<RecursiveInstructions> FibonacciRecursive() {
}

struct UpdateFibonacci : jasmin::Instruction<UpdateFibonacci> {
static void consume(std::span<jasmin::Value, 3> values,
std::span<jasmin::Value, 3> out) {
auto n = values[0];
auto a = values[1];
auto b = values[2];
out[0] = static_cast<uint64_t>(n.as<uint64_t>() - 1);
out[1] = b;
out[2] = a.as<uint64_t>() + b.as<uint64_t>();
static void consume(jasmin::Input<uint64_t, uint64_t, uint64_t> in,
jasmin::Output<uint64_t, uint64_t, uint64_t> out) {
out.set<0>(in.get<0>() - 1);
out.set<1>(in.get<2>());
out.set<2>(in.get<1>() + in.get<2>());
}
};

Expand Down
19 changes: 9 additions & 10 deletions examples/function_state.cc
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,8 @@
// before this one.

struct PrintCString : jasmin::Instruction<PrintCString> {
static void consume(std::span<jasmin::Value, 1> values,
std::span<jasmin::Value, 0>) {
std::fputs(values[0].as<char const *>(), stdout);
static void consume(jasmin::Input<char const *> in, jasmin::Output<>) {
std::fputs(in.get<0>(), stdout);
}
};

Expand All @@ -31,26 +30,26 @@ struct Queue {

struct PushQueue : jasmin::Instruction<PushQueue> {
using function_state = Queue;
static void execute(function_state &state, std::span<jasmin::Value, 0>,
std::span<jasmin::Value, 0>, char const *cstr) {
static void execute(function_state &state, jasmin::Input<>, jasmin::Output<>,
char const *cstr) {
state.queue.push(cstr);
}
};

struct PopQueue : jasmin::Instruction<PopQueue> {
using function_state = Queue;

static void execute(function_state &state, std::span<jasmin::Value, 0>,
std::span<jasmin::Value, 1> out) {
out[0] = state.queue.front();
static void execute(function_state &state, jasmin::Input<>,
jasmin::Output<char const *> out) {
out.set<0>(state.queue.front());
state.queue.pop();
}
};

struct RotateQueue : jasmin::Instruction<RotateQueue> {
using function_state = Queue;
static void execute(function_state &state, std::span<jasmin::Value, 0>,
std::span<jasmin::Value, 0>) {
static void execute(function_state &state, jasmin::Input<>,
jasmin::Output<>) {
char const *top = state.queue.front();
state.queue.pop();
state.queue.push(top);
Expand Down
10 changes: 4 additions & 6 deletions examples/hello_world.cc
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,8 @@ struct PrintCString : jasmin::Instruction<PrintCString> {
// Jasmin knows that exactly one value should be popped off the stack, and
// that that one value is a `const char *` because it inspects the parameters
// of the function named `consume`.
static void consume(std::span<jasmin::Value, 1> values,
std::span<jasmin::Value, 0>) {
std::fputs(values[0].as<char const *>(), stdout);
static void consume(jasmin::Input<char const *> in, jasmin::Output<>) {
std::fputs(in.get<0>(), stdout);
}
};

Expand Down Expand Up @@ -66,14 +65,13 @@ struct ReadIntegerFromStdIn : jasmin::Instruction<ReadIntegerFromStdIn> {
// Just as with `PrintCString`, from the signature of `execute`, Jasmin
// deduces that this instruction reads no values from the stack but writes a
// single value of type `int` (the return type).
static void execute(std::span<jasmin::Value, 0>,
std::span<jasmin::Value, 1> out) {
static void execute(jasmin::Input<>, jasmin::Output<int> out) {
int result;
std::scanf("%d", &result);
// Note: This function is not robust as it does nothing to validate that the
// provided value was a valid integer. The author of an instruction is
// responsible for handling this sort of error-checking for themselves.
out[0] = result;
out.set<0>(result);
}
};

Expand Down
42 changes: 42 additions & 0 deletions jasmin/core/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,33 @@ cc_test(
],
)

cc_library(
name = "input",
hdrs = ["input.h"],
visibility = ["//visibility:public"],
deps = [
":value",
"@nth_cc//nth/meta:sequence",
"@nth_cc//nth/meta:type",
],
)

cc_test(
name = "input_test",
srcs = ["input_test.cc"],
deps = [
":input",
"@nth_cc//nth/test:main",
],
)

cc_library(
name = "instruction",
hdrs = ["instruction.h"],
visibility = ["//visibility:public"],
deps = [
":input",
":output",
":value",
"//jasmin/core/internal:function_base",
"//jasmin/core/internal:function_state",
Expand Down Expand Up @@ -97,6 +119,26 @@ cc_test(
],
)

cc_library(
name = "output",
hdrs = ["output.h"],
visibility = ["//visibility:public"],
deps = [
":value",
"@nth_cc//nth/meta:sequence",
"@nth_cc//nth/meta:type",
],
)

cc_test(
name = "output_test",
srcs = ["output_test.cc"],
deps = [
":output",
"@nth_cc//nth/test:main",
],
)

cc_library(
name = "program",
hdrs = ["program.h"],
Expand Down
5 changes: 2 additions & 3 deletions jasmin/core/function_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,8 @@ namespace jasmin {
namespace {

struct PushImmediateBool : jasmin::Instruction<PushImmediateBool> {
static constexpr void execute(std::span<Value, 0>, std::span<Value, 1> out,
bool b) {
out[0] = b;
static constexpr void execute(Input<>, Output<bool> out, bool b) {
out.set<0>(b);
}
};

Expand Down
30 changes: 25 additions & 5 deletions jasmin/core/input.h
Original file line number Diff line number Diff line change
@@ -1,24 +1,44 @@
#ifndef JASMIN_CORE_INPUT_H
#define JASMIN_CORE_INPUT_H

#include <tuple>

#include "jasmin/core/value.h"
#include "nth/meta/sequence.h"
#include "nth/meta/type.h"

namespace jasmin {
namespace internal {
struct InputBase {};
} // namespace internal

template <typename... Ts>
struct in {
requires((std::constructible_from<Value, Ts> and ...)) //
struct Input : internal::InputBase {
static constexpr int count = sizeof...(Ts);

explicit constexpr Input(Value const *ptr) : ptr_(ptr) {}

template <int N>
auto get() {
return (ptr_ + N * sizeof(Value))
->as<nth::type_t<types.template get<N>()>>();
constexpr auto get() {
return ptr_[N].as<nth::type_t<types.template get<N>()>>();
}

private:
static constexpr auto types = nth::type_sequence<Ts...>;
Value *ptr_;
Value const *ptr_;
};

} // namespace jasmin

template <typename... Ts>
struct std::tuple_size<::jasmin::Input<Ts...>>
: std::integral_constant<size_t, sizeof...(Ts)> {};

template <size_t N, typename... Ts>
struct std::tuple_element<N, ::jasmin::Input<Ts...>> {
using type =
decltype(std::declval<::jasmin::Input<Ts...>>().template get<N>());
};

#endif // JASMIN_CORE_INPUT_H
35 changes: 35 additions & 0 deletions jasmin/core/input_test.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#include "jasmin/core/input.h"

#include "nth/test/test.h"

namespace jasmin {
namespace {

static_assert(Input<>::count == 0);
static_assert(Input<int>::count == 1);
static_assert(Input<int, bool>::count == 2);
static_assert(Input<int, int>::count == 2);

NTH_TEST("input/single") {
Value vs[1];
vs[0] = 3;
Input<int> input(vs);
NTH_EXPECT(input.get<0>() == 3);
auto [n] = input;
NTH_EXPECT(n == 3);
}

NTH_TEST("input/multiple") {
Value vs[2];
vs[0] = 3;
vs[1] = true;
Input<int, bool> input(vs);
NTH_EXPECT(input.get<0>() == 3);
NTH_EXPECT(input.get<1>());
auto [n, b] = input;
NTH_EXPECT(n == 3);
NTH_EXPECT(b);
}

} // namespace
} // namespace jasmin
Loading

0 comments on commit 0999d33

Please sign in to comment.