Added concurrent execution primitive
This commit is contained in:
parent
7f73f3dcad
commit
07fa4f894a
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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 });
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user