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::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
|
||||
|
@ -97,4 +97,7 @@ struct Interpreter::Incoming_Midi_Callbacks
|
||||
enum class Midi_Connection_Type { Output, Input };
|
||||
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
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <random>
|
||||
#include <memory>
|
||||
#include <iostream>
|
||||
#include <unordered_set>
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
/// 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
|
||||
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("floor", apply_numeric_transform<&Number::floor>);
|
||||
global.force_define("for", builtin_for);
|
||||
global.force_define("hash", builtin_hash);
|
||||
global.force_define("if", builtin_if);
|
||||
global.force_define("incoming", builtin_incoming);
|
||||
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("try", builtin_try);
|
||||
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("update", builtin_update);
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include <musique.hh>
|
||||
#include <musique_internal.hh>
|
||||
|
||||
#include <iomanip>
|
||||
|
||||
@ -277,3 +278,9 @@ std::string_view type_name(Token::Type type)
|
||||
}
|
||||
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_internal.hh>
|
||||
|
||||
#include <cmath>
|
||||
#include <numeric>
|
||||
#include <charconv>
|
||||
@ -332,3 +334,9 @@ Result<Number> Number::pow(Number n) const
|
||||
// We need to protect ourselfs against even roots of negative numbers.
|
||||
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_internal.hh>
|
||||
|
||||
#include <iostream>
|
||||
#include <numeric>
|
||||
|
||||
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::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_internal.hh>
|
||||
|
||||
#include <numeric>
|
||||
|
||||
/// Finds numeric value of note. This form is later used as in
|
||||
/// 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));
|
||||
}
|
||||
|
||||
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