Vectorized note creation

This commit is contained in:
Robert Bendun 2022-09-22 18:12:17 +02:00
parent 9fb1815e01
commit 973fbd62f7

View File

@ -504,55 +504,96 @@ Chord Chord::from(std::string_view source)
return chord; return chord;
} }
Result<Value> Chord::operator()(Interpreter&, std::vector<Value> args) Result<Value> Chord::operator()(Interpreter& interpreter, std::vector<Value> args)
{ {
std::vector<Value> array; std::vector<Value> array;
Chord *current = this; std::vector<Chord> current = { *this };
enum State { enum State {
Waiting_For_Octave, Waiting_For_Octave,
Waiting_For_Length, Waiting_For_Length,
Waiting_For_Note Waiting_For_Note
} state = Waiting_For_Octave; } state = Waiting_For_Octave;
for (auto &arg : args) { static constexpr auto guard = Guard<1> {
if (arg.type == Value::Type::Number) { .name = "note creation",
switch (state) { .possibilities = {
break; case Waiting_For_Octave: "(note:music [octave:number [duration:number]])+"
std::for_each(current->notes.begin(), current->notes.end(), }
[&arg](Note &n) { n.octave = arg.n.floor().as_int(); }); };
state = Waiting_For_Length;
continue;
break; case Waiting_For_Length: auto const next = [&state] {
std::for_each(current->notes.begin(), current->notes.end(), switch (state) {
[&arg](Note &n) { n.length = arg.n; }); break; case Waiting_For_Length: state = Waiting_For_Note;
state = Waiting_For_Note; break; case Waiting_For_Note: state = Waiting_For_Octave;
continue; break; case Waiting_For_Octave: state = Waiting_For_Length;
}
};
default: auto const update = [&state](Chord &chord, Value &arg) -> Result<void> {
return errors::Unsupported_Types_For { auto const resolve = [&chord](auto field, auto new_value) {
.type = errors::Unsupported_Types_For::Function, for (auto &note : chord.notes) {
.name = "note creation", (note.*field) = new_value;
.possibilities = {
"(note:music [octave:number [duration:number]])+"
}
};
} }
};
switch (state) {
break; case Waiting_For_Octave:
resolve(&Note::octave, arg.n.floor().as_int());
return {};
break; case Waiting_For_Length:
resolve(&Note::length, arg.n);
return {};
default:
return guard.yield_error();
}
};
for (auto &arg : args) {
if (is_indexable(arg.type)) {
if (state != Waiting_For_Length && state != Waiting_For_Octave) {
return guard.yield_error();
}
auto const ring_size = current.size();
for (usize i = 0; i < arg.size() && current.size() < arg.size(); ++i) {
current.push_back(current[i % ring_size]);
}
for (usize i = 0; i < current.size(); ++i) {
if (Value value = Try(arg.index(interpreter, i % arg.size())); value.type == Value::Type::Number) {
Try(update(current[i], value));
continue;
}
}
next();
continue;
}
if (arg.type == Value::Type::Number) {
for (auto &chord : current) {
Try(update(chord, arg));
}
next();
continue;
} }
if (arg.type == Value::Type::Music) { if (arg.type == Value::Type::Music) {
if (array.empty()) { std::transform(current.begin(), current.end(), std::back_inserter(array),
array.push_back(Value::from(std::move(*current))); [](Chord &c) { return Value::from(std::move(c)); });
} current.clear();
array.push_back(std::move(arg)); current.push_back(arg.chord);
current = &array.back().chord;
state = Waiting_For_Octave; state = Waiting_For_Octave;
} }
} }
return array.empty() std::transform(current.begin(), current.end(), std::back_inserter(array),
? Value::from(*current) [](Chord &c) { return Value::from(std::move(c)); });
: Value::from(Array{array});
assert(not array.empty(), "At least *this should be in this array");
return Value::from(Array{array});
} }
std::ostream& operator<<(std::ostream& os, Chord const& chord) std::ostream& operator<<(std::ostream& os, Chord const& chord)