GH-151: fix hash calculation for nested sets

Hash key construction of nested sets depended on the order in
which their elements are iterated, which varied even between sets
containing equivalent elements.  The iteration order is now sorted
by each element's hash value (or, on collision, by full key) such
that equivalent sets no longer hash differently.
This commit is contained in:
Jon Siwek 2019-01-18 20:54:22 -06:00
parent 5618b21cca
commit d86fb9f87a
3 changed files with 64 additions and 10 deletions

View file

@ -7,6 +7,9 @@
#include "Reporter.h"
#include "Func.h"
#include <vector>
#include <map>
CompositeHash::CompositeHash(TypeList* composite_type)
{
type = composite_type;
@ -174,12 +177,44 @@ char* CompositeHash::SingleValHash(int type_check, char* kp0,
{
int* kp = AlignAndPadType<int>(kp0);
TableVal* tv = v->AsTableVal();
ListVal* lv = tv->ConvertToList();
*kp = tv->Size();
kp1 = reinterpret_cast<char*>(kp+1);
for ( int i = 0; i < tv->Size(); ++i )
auto tbl = tv->AsTable();
auto it = tbl->InitForIteration();
ListVal* lv = new ListVal(TYPE_ANY);
struct HashKeyComparer {
bool operator()(const HashKey* a, const HashKey* b)
{
if ( a->Hash() != b->Hash() )
return a->Hash() < b->Hash();
if ( a->Size() != b->Size() )
return a->Size() < b->Size();
return strncmp(static_cast<const char*>(a->Key()),
static_cast<const char*>(b->Key()),
a->Size()) < 0;
}
};
std::map<HashKey*, int, HashKeyComparer> hashkeys;
HashKey* k;
auto idx = 0;
while ( tbl->NextEntry(k, it) )
{
Val* key = lv->Index(i);
hashkeys[k] = idx++;
lv->Append(tv->RecoverIndex(k));
}
for ( auto& kv : hashkeys )
delete kv.first;
for ( auto& kv : hashkeys )
{
auto idx = kv.second;
Val* key = lv->Index(idx);
if ( ! (kp1 = SingleValHash(type_check, kp1, key->Type(), key,
false)) )
{