Added concurrent execution primitive
This commit is contained in:
parent
7f73f3dcad
commit
07fa4f894a
@ -4,12 +4,14 @@
|
|||||||
#include <musique/interpreter/interpreter.hh>
|
#include <musique/interpreter/interpreter.hh>
|
||||||
#include <musique/try.hh>
|
#include <musique/try.hh>
|
||||||
|
|
||||||
#include <random>
|
|
||||||
#include <memory>
|
|
||||||
#include <iostream>
|
|
||||||
#include <unordered_set>
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
#include <future>
|
||||||
|
#include <iostream>
|
||||||
|
#include <latch>
|
||||||
|
#include <memory>
|
||||||
|
#include <random>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
#include <unordered_set>
|
||||||
|
|
||||||
/// Check if type has index method
|
/// Check if type has index method
|
||||||
template<typename T>
|
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
|
/// Execute blocks depending on condition
|
||||||
static Result<Value> builtin_if(Interpreter &i, std::span<Ast> args) {
|
static Result<Value> builtin_if(Interpreter &i, std::span<Ast> args) {
|
||||||
static constexpr auto guard = Guard<2> {
|
static constexpr auto guard = Guard<2> {
|
||||||
@ -1117,6 +1152,7 @@ void Interpreter::register_builtin_functions()
|
|||||||
global.force_define("call", builtin_call);
|
global.force_define("call", builtin_call);
|
||||||
global.force_define("ceil", apply_numeric_transform<&Number::ceil>);
|
global.force_define("ceil", apply_numeric_transform<&Number::ceil>);
|
||||||
global.force_define("chord", builtin_chord);
|
global.force_define("chord", builtin_chord);
|
||||||
|
global.force_define("concurrent", builtin_concurrent);
|
||||||
global.force_define("down", builtin_range<Range_Direction::Down>);
|
global.force_define("down", builtin_range<Range_Direction::Down>);
|
||||||
global.force_define("duration", builtin_duration);
|
global.force_define("duration", builtin_duration);
|
||||||
global.force_define("flat", builtin_flat);
|
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
|
/// Fills empty places in Note like octave and length with default values from context
|
||||||
Note fill(Note) const;
|
Note fill(Note) const;
|
||||||
|
|
||||||
|
std::shared_ptr<Context> parent = nullptr;
|
||||||
|
|
||||||
/// Converts length to seconds with current bpm
|
/// Converts length to seconds with current bpm
|
||||||
std::chrono::duration<float> length_to_duration(std::optional<Number> length) const;
|
std::chrono::duration<float> length_to_duration(std::optional<Number> length) const;
|
||||||
|
|
||||||
std::shared_ptr<Context> parent;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -10,6 +10,16 @@
|
|||||||
midi::Connection *Interpreter::midi_connection = nullptr;
|
midi::Connection *Interpreter::midi_connection = nullptr;
|
||||||
std::unordered_map<std::string, Intrinsic> Interpreter::operators {};
|
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`
|
/// Registers constants like `fn = full note = 1/1`
|
||||||
static inline void register_note_length_constants()
|
static inline void register_note_length_constants()
|
||||||
{
|
{
|
||||||
@ -47,9 +57,8 @@ Interpreter::Interpreter()
|
|||||||
register_builtin_functions();
|
register_builtin_functions();
|
||||||
}
|
}
|
||||||
|
|
||||||
Interpreter::~Interpreter()
|
Interpreter::Interpreter(Interpreter::Clone)
|
||||||
{
|
{
|
||||||
Env::global.reset();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<Value> Interpreter::eval(Ast &&ast)
|
Result<Value> Interpreter::eval(Ast &&ast)
|
||||||
|
@ -17,18 +17,25 @@ struct Interpreter
|
|||||||
static std::unordered_map<std::string, Intrinsic> operators;
|
static std::unordered_map<std::string, Intrinsic> operators;
|
||||||
|
|
||||||
/// Current environment (current scope)
|
/// Current environment (current scope)
|
||||||
std::shared_ptr<Env> env;
|
std::shared_ptr<Env> env = nullptr;
|
||||||
|
|
||||||
/// Context stack. `constext_stack.back()` is a current context.
|
/// Context stack. `constext_stack.back()` is a current context.
|
||||||
/// There is always at least one 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() = default;
|
||||||
Interpreter(Interpreter &&) = delete;
|
|
||||||
Interpreter(Interpreter const&) = delete;
|
Interpreter(Interpreter const&) = delete;
|
||||||
|
Interpreter(Interpreter &&) = default;
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct Clone {};
|
||||||
|
Interpreter(Clone);
|
||||||
|
public:
|
||||||
|
|
||||||
|
Interpreter clone() const;
|
||||||
|
|
||||||
/// Try to evaluate given program tree
|
/// Try to evaluate given program tree
|
||||||
Result<Value> eval(Ast &&ast);
|
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)
|
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 });
|
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)
|
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 });
|
send_message(*output, std::array { std::uint8_t(Note_Off + channel), note_number, velocity });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user