Vectorized note creation
This commit is contained in:
parent
9fb1815e01
commit
973fbd62f7
103
src/value.cc
103
src/value.cc
@ -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 ¬e : 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)
|
||||||
|
Loading…
Reference in New Issue
Block a user