Hashing functions; builtins hash, uniq and unique
This commit is contained in:
parent
ab0ba8d4c8
commit
d77f844c81
@ -1099,4 +1099,9 @@ static constexpr bool is_callable(Value::Type type)
|
|||||||
Result<std::vector<Value>> flatten(Interpreter &i, std::span<Value>);
|
Result<std::vector<Value>> flatten(Interpreter &i, std::span<Value>);
|
||||||
Result<std::vector<Value>> flatten(Interpreter &i, std::vector<Value>);
|
Result<std::vector<Value>> flatten(Interpreter &i, std::vector<Value>);
|
||||||
|
|
||||||
|
template<> struct std::hash<Token> { std::size_t operator()(Token const&) const; };
|
||||||
|
template<> struct std::hash<Ast> { std::size_t operator()(Ast const&) const; };
|
||||||
|
template<> struct std::hash<Number> { std::size_t operator()(Number const&) const; };
|
||||||
|
template<> struct std::hash<Value> { std::size_t operator()(Value const&) const; };
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -97,4 +97,7 @@ struct Interpreter::Incoming_Midi_Callbacks
|
|||||||
enum class Midi_Connection_Type { Output, Input };
|
enum class Midi_Connection_Type { Output, Input };
|
||||||
Result<void> ensure_midi_connection_available(Interpreter&, Midi_Connection_Type, std::string_view operation_name);
|
Result<void> ensure_midi_connection_available(Interpreter&, Midi_Connection_Type, std::string_view operation_name);
|
||||||
|
|
||||||
|
constexpr std::size_t hash_combine(std::size_t lhs, std::size_t rhs) {
|
||||||
|
return lhs ^= rhs + 0x9e3779b9 + (lhs << 6) + (lhs >> 2);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include <random>
|
#include <random>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <unordered_set>
|
||||||
|
|
||||||
void Interpreter::register_callbacks()
|
void Interpreter::register_callbacks()
|
||||||
{
|
{
|
||||||
@ -601,6 +602,48 @@ static Result<Value> builtin_rotate(Interpreter &i, std::vector<Value> args)
|
|||||||
return Value::from(std::move(array));
|
return Value::from(std::move(array));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns unique collection of arguments
|
||||||
|
static Result<Value> builtin_unique(Interpreter &i, std::vector<Value> args)
|
||||||
|
{
|
||||||
|
auto array = Try(flatten(i, args));
|
||||||
|
std::unordered_set<Value> seen;
|
||||||
|
|
||||||
|
std::vector<Value> result;
|
||||||
|
for (auto &el : array) {
|
||||||
|
if (!seen.contains(el)) {
|
||||||
|
seen.insert(el);
|
||||||
|
result.push_back(std::move(el));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Value::from(std::move(result));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns arguments with all successive copies eliminated
|
||||||
|
static Result<Value> builtin_uniq(Interpreter &i, std::vector<Value> args)
|
||||||
|
{
|
||||||
|
auto array = Try(flatten(i, args));
|
||||||
|
|
||||||
|
std::optional<Value> previous;
|
||||||
|
std::vector<Value> result;
|
||||||
|
|
||||||
|
for (auto &el : array) {
|
||||||
|
if (previous && *previous == el)
|
||||||
|
continue;
|
||||||
|
result.push_back(el);
|
||||||
|
previous = std::move(el);
|
||||||
|
}
|
||||||
|
return Value::from(std::move(result));
|
||||||
|
}
|
||||||
|
|
||||||
|
static Result<Value> builtin_hash(Interpreter&, std::vector<Value> args)
|
||||||
|
{
|
||||||
|
return Value::from(Number(
|
||||||
|
std::accumulate(args.cbegin(), args.cend(), size_t(0), [](size_t h, Value const& v) {
|
||||||
|
return hash_combine(h, std::hash<Value>{}(v));
|
||||||
|
})
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
/// Build chord from arguments
|
/// Build chord from arguments
|
||||||
static Result<Value> builtin_chord(Interpreter &i, std::vector<Value> args)
|
static Result<Value> builtin_chord(Interpreter &i, std::vector<Value> args)
|
||||||
{
|
{
|
||||||
@ -714,6 +757,7 @@ void Interpreter::register_builtin_functions()
|
|||||||
global.force_define("flat", builtin_flat);
|
global.force_define("flat", builtin_flat);
|
||||||
global.force_define("floor", apply_numeric_transform<&Number::floor>);
|
global.force_define("floor", apply_numeric_transform<&Number::floor>);
|
||||||
global.force_define("for", builtin_for);
|
global.force_define("for", builtin_for);
|
||||||
|
global.force_define("hash", builtin_hash);
|
||||||
global.force_define("if", builtin_if);
|
global.force_define("if", builtin_if);
|
||||||
global.force_define("incoming", builtin_incoming);
|
global.force_define("incoming", builtin_incoming);
|
||||||
global.force_define("instrument", builtin_program_change);
|
global.force_define("instrument", builtin_program_change);
|
||||||
@ -738,6 +782,8 @@ void Interpreter::register_builtin_functions()
|
|||||||
global.force_define("sort", builtin_sort);
|
global.force_define("sort", builtin_sort);
|
||||||
global.force_define("try", builtin_try);
|
global.force_define("try", builtin_try);
|
||||||
global.force_define("typeof", builtin_typeof);
|
global.force_define("typeof", builtin_typeof);
|
||||||
|
global.force_define("uniq", builtin_uniq);
|
||||||
|
global.force_define("unique", builtin_unique);
|
||||||
global.force_define("up", builtin_range<Range_Direction::Up>);
|
global.force_define("up", builtin_range<Range_Direction::Up>);
|
||||||
global.force_define("update", builtin_update);
|
global.force_define("update", builtin_update);
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#include <musique.hh>
|
#include <musique.hh>
|
||||||
|
#include <musique_internal.hh>
|
||||||
|
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
|
|
||||||
@ -277,3 +278,9 @@ std::string_view type_name(Token::Type type)
|
|||||||
}
|
}
|
||||||
unreachable();
|
unreachable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::size_t std::hash<Token>::operator()(Token const& token) const
|
||||||
|
{
|
||||||
|
return hash_combine(std::hash<std::string_view>{}(token.source), size_t(token.type));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
#include <musique.hh>
|
#include <musique.hh>
|
||||||
|
#include <musique_internal.hh>
|
||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <numeric>
|
#include <numeric>
|
||||||
#include <charconv>
|
#include <charconv>
|
||||||
@ -332,3 +334,9 @@ Result<Number> Number::pow(Number n) const
|
|||||||
// We need to protect ourselfs against even roots of negative numbers.
|
// We need to protect ourselfs against even roots of negative numbers.
|
||||||
unimplemented();
|
unimplemented();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::size_t std::hash<Number>::operator()(Number const& value) const
|
||||||
|
{
|
||||||
|
std::hash<Number::value_type> h;
|
||||||
|
return hash_combine(h(value.num), h(value.den));
|
||||||
|
}
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
#include <musique.hh>
|
#include <musique.hh>
|
||||||
|
#include <musique_internal.hh>
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <numeric>
|
||||||
|
|
||||||
static Ast wrap_if_several(std::vector<Ast> &&ast, Ast(*wrapper)(std::vector<Ast>));
|
static Ast wrap_if_several(std::vector<Ast> &&ast, Ast(*wrapper)(std::vector<Ast>));
|
||||||
|
|
||||||
@ -616,3 +619,12 @@ void dump(Ast const& tree, unsigned indent)
|
|||||||
std::cout << std::flush;
|
std::cout << std::flush;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::size_t std::hash<Ast>::operator()(Ast const& value) const
|
||||||
|
{
|
||||||
|
auto h = std::hash<Token>{}(value.token);
|
||||||
|
h = std::accumulate(value.arguments.begin(), value.arguments.end(), h, [this](size_t h, Ast const& node) {
|
||||||
|
return hash_combine(h, operator()(node));
|
||||||
|
});
|
||||||
|
return hash_combine(size_t(value.type), h);
|
||||||
|
}
|
||||||
|
31
src/value.cc
31
src/value.cc
@ -1,4 +1,7 @@
|
|||||||
#include <musique.hh>
|
#include <musique.hh>
|
||||||
|
#include <musique_internal.hh>
|
||||||
|
|
||||||
|
#include <numeric>
|
||||||
|
|
||||||
/// Finds numeric value of note. This form is later used as in
|
/// Finds numeric value of note. This form is later used as in
|
||||||
/// note to midi resolution in formula octave * 12 + note_index
|
/// note to midi resolution in formula octave * 12 + note_index
|
||||||
@ -522,3 +525,31 @@ Result<std::vector<Value>> flatten(Interpreter &i, std::vector<Value> args)
|
|||||||
{
|
{
|
||||||
return flatten(i, std::span(args));
|
return flatten(i, std::span(args));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::size_t std::hash<Value>::operator()(Value const& value) const
|
||||||
|
{
|
||||||
|
size_t value_hash = 0;
|
||||||
|
switch (value.type) {
|
||||||
|
break; case Value::Type::Nil: value_hash = 0;
|
||||||
|
break; case Value::Type::Number: value_hash = std::hash<Number>{}(value.n);
|
||||||
|
break; case Value::Type::Symbol: value_hash = std::hash<std::string>{}(value.s);
|
||||||
|
break; case Value::Type::Bool: value_hash = std::hash<bool>{}(value.b);
|
||||||
|
break; case Value::Type::Intrinsic: value_hash = ptrdiff_t(value.intr);
|
||||||
|
break; case Value::Type::Block: value_hash = hash_combine(std::hash<Ast>{}(value.blk.body), value.blk.parameters.size());
|
||||||
|
|
||||||
|
break; case Value::Type::Array:
|
||||||
|
value_hash = std::accumulate(value.array.elements.begin(), value.array.elements.end(), value_hash, [this](size_t h, Value const& v) {
|
||||||
|
return hash_combine(h, operator()(v));
|
||||||
|
});
|
||||||
|
|
||||||
|
break; case Value::Type::Music:
|
||||||
|
value_hash = std::accumulate(value.chord.notes.begin(), value.chord.notes.end(), value_hash, [](size_t h, Note const& n) {
|
||||||
|
h = hash_combine(h, n.base);
|
||||||
|
h = hash_combine(h, std::hash<std::optional<Number>>{}(n.length));
|
||||||
|
h = hash_combine(h, std::hash<std::optional<i8>>{}(n.octave));
|
||||||
|
return h;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return hash_combine(value_hash, size_t(value.type));
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user