Added concurrent execution primitive

This commit is contained in:
Robert Bendun 2022-11-22 01:16:38 +01:00
parent 7f73f3dcad
commit 07fa4f894a
5 changed files with 67 additions and 13 deletions

View File

@ -4,12 +4,14 @@
#include <musique/interpreter/interpreter.hh>
#include <musique/try.hh>
#include <random>
#include <memory>
#include <iostream>
#include <unordered_set>
#include <chrono>
#include <future>
#include <iostream>
#include <latch>
#include <memory>
#include <random>
#include <thread>
#include <unordered_set>
/// Check if type has index method
template<typename T>
@ -600,6 +602,39 @@ static Result<Value> builtin_scan(Interpreter &interpreter, std::vector<Value> a
};
}
static Result<Value> builtin_concurrent(Interpreter &interpreter, std::span<Ast> args)
{
auto const jobs_count = args.size();
std::vector<std::jthread> threads;
std::vector<std::future<Value>> futures;
std::optional<Error> error;
std::mutex mutex;
for (unsigned i = 0; i < jobs_count; ++i) {
futures.push_back(std::async(std::launch::async, [interpreter = interpreter.clone(), i, args, &mutex, &error]() mutable -> Value {
auto result = interpreter.eval((Ast)args[i]);
if (result.has_value()) {
return *std::move(result);
}
std::lock_guard guard{mutex};
if (!error) {
error = result.error();
}
return Value{};
}));
}
std::vector<Value> results;
for (auto& future : futures) {
if (error) {
return *error;
}
results.push_back(future.get());
}
return results;
}
/// Execute blocks depending on condition
static Result<Value> builtin_if(Interpreter &i, std::span<Ast> args) {
static constexpr auto guard = Guard<2> {
@ -1117,6 +1152,7 @@ void Interpreter::register_builtin_functions()
global.force_define("call", builtin_call);
global.force_define("ceil", apply_numeric_transform<&Number::ceil>);
global.force_define("chord", builtin_chord);
global.force_define("concurrent", builtin_concurrent);
global.force_define("down", builtin_range<Range_Direction::Down>);
global.force_define("duration", builtin_duration);
global.force_define("flat", builtin_flat);

View File

@ -22,10 +22,10 @@ struct Context
/// Fills empty places in Note like octave and length with default values from context
Note fill(Note) const;
std::shared_ptr<Context> parent = nullptr;
/// Converts length to seconds with current bpm
std::chrono::duration<float> length_to_duration(std::optional<Number> length) const;
std::shared_ptr<Context> parent;
};
#endif

View File

@ -10,6 +10,16 @@
midi::Connection *Interpreter::midi_connection = nullptr;
std::unordered_map<std::string, Intrinsic> Interpreter::operators {};
Interpreter Interpreter::clone() const
{
Interpreter interpreter(Clone{});
interpreter.default_action = default_action;
interpreter.env = env->enter();
interpreter.current_context = std::make_shared<Context>(*current_context);
interpreter.current_context->parent = current_context;
return interpreter;
}
/// Registers constants like `fn = full note = 1/1`
static inline void register_note_length_constants()
{
@ -47,9 +57,8 @@ Interpreter::Interpreter()
register_builtin_functions();
}
Interpreter::~Interpreter()
Interpreter::Interpreter(Interpreter::Clone)
{
Env::global.reset();
}
Result<Value> Interpreter::eval(Ast &&ast)

View File

@ -17,18 +17,25 @@ struct Interpreter
static std::unordered_map<std::string, Intrinsic> operators;
/// Current environment (current scope)
std::shared_ptr<Env> env;
std::shared_ptr<Env> env = nullptr;
/// Context stack. `constext_stack.back()` is a current context.
/// There is always at least one context
std::shared_ptr<Context> current_context;
std::shared_ptr<Context> current_context = nullptr;
std::function<std::optional<Error>(Interpreter&, Value)> default_action;
std::function<std::optional<Error>(Interpreter&, Value)> default_action = nullptr;
Interpreter();
~Interpreter();
Interpreter(Interpreter &&) = delete;
~Interpreter() = default;
Interpreter(Interpreter const&) = delete;
Interpreter(Interpreter &&) = default;
private:
struct Clone {};
Interpreter(Clone);
public:
Interpreter clone() const;
/// Try to evaluate given program tree
Result<Value> eval(Ast &&ast);

View File

@ -97,11 +97,13 @@ enum : std::uint8_t
void midi::Rt_Midi::send_note_on(uint8_t channel, uint8_t note_number, uint8_t velocity)
{
std::cout << "NOTE ON " << int(channel) << '\t' << int(note_number) << '\t' << int(velocity) << std::endl;
send_message(*output, std::array { std::uint8_t(Note_On + channel), note_number, velocity });
}
void midi::Rt_Midi::send_note_off(uint8_t channel, uint8_t note_number, uint8_t velocity)
{
std::cout << "NOTE OFF " << int(channel) << '\t' << int(note_number) << '\t' << int(velocity) << std::endl;
send_message(*output, std::array { std::uint8_t(Note_Off + channel), note_number, velocity });
}