diff --git a/src/CompHash.cc b/src/CompHash.cc index 6d3236ec2d..837fb15e8d 100644 --- a/src/CompHash.cc +++ b/src/CompHash.cc @@ -18,6 +18,42 @@ namespace zeek::detail { +// A comparison callable to assist with consistent iteration order over tables +// during reservation & writes. +struct HashKeyComparer + { + bool operator()(const std::unique_ptr& a, const std::unique_ptr& b) const + { + if ( a->Hash() != b->Hash() ) + return a->Hash() < b->Hash(); + if ( a->Size() != b->Size() ) + return a->Size() < b->Size(); + return memcmp(a->Key(), b->Key(), a->Size()) < 0; + } + }; + +using HashkeyMap = std::map, ListValPtr, HashKeyComparer>; +using HashkeyMapPtr = std::unique_ptr; + +// Helper that produces a table from HashKeys to the ListVal indexes into the +// table, that we can iterate over in sorted-Hashkey order. +const HashkeyMapPtr ordered_hashkeys(const TableVal* tv) + { + auto res = std::make_unique(); + auto tbl = tv->AsTable(); + auto idx = 0; + + for ( const auto& entry : *tbl ) + { + auto k = entry.GetHashKey(); + // Do we have to recreate here? Could we reuse the existing key? + auto lv = tv->RecreateIndex(*k); + res->insert_or_assign(std::move(k), lv); + } + + return res; + } + CompositeHash::CompositeHash(TypeListPtr composite_type) : type(std::move(composite_type)) { singleton_tag = TYPE_INTERNAL_ERROR; @@ -209,38 +245,11 @@ char* CompositeHash::SingleValHash(bool type_check, char* kp0, Type* bt, Val* v, *kp = tv->Size(); kp1 = reinterpret_cast(kp + 1); - auto tbl = tv->AsTable(); - auto lv = make_intrusive(TYPE_ANY); + auto hashkeys = ordered_hashkeys(tv); - struct HashKeyComparer + for ( auto& kv : *hashkeys ) { - bool operator()(const std::unique_ptr& a, - const std::unique_ptr& b) const - { - if ( a->Hash() != b->Hash() ) - return a->Hash() < b->Hash(); - if ( a->Size() != b->Size() ) - return a->Size() < b->Size(); - return strncmp(static_cast(a->Key()), - static_cast(b->Key()), - a->Size()) < 0; - } - }; - - std::map, int, HashKeyComparer> hashkeys; - auto idx = 0; - - for ( const auto& entry : *tbl ) - { - auto k = entry.GetHashKey(); - lv->Append(tv->RecreateIndex(*k)); - hashkeys[std::move(k)] = idx++; - } - - for ( auto& kv : hashkeys ) - { - auto idx = kv.second; - const auto& key = lv->Idx(idx); + auto key = kv.second; if ( ! (kp1 = SingleValHash(type_check, kp1, key->GetType().get(), key.get(), false)) ) @@ -541,11 +550,12 @@ int CompositeHash::SingleTypeKeySize(Type* bt, const Val* v, bool type_check, in return (optional && ! calc_static_size) ? sz : 0; sz = SizeAlign(sz, sizeof(int)); - TableVal* tv = const_cast(v->AsTableVal()); - auto lv = tv->ToListVal(); - for ( int i = 0; i < tv->Size(); ++i ) + auto tv = v->AsTableVal(); + auto hashkeys = ordered_hashkeys(tv); + + for ( auto& kv : *hashkeys ) { - const auto& key = lv->Idx(i); + auto key = kv.second; sz = SingleTypeKeySize(key->GetType().get(), key.get(), type_check, sz, false, calc_static_size); if ( ! sz ) @@ -553,7 +563,7 @@ int CompositeHash::SingleTypeKeySize(Type* bt, const Val* v, bool type_check, in if ( ! bt->IsSet() ) { - auto val = tv->FindOrDefault(key); + auto val = const_cast(tv)->FindOrDefault(key); sz = SingleTypeKeySize(val->GetType().get(), val.get(), type_check, sz, false, calc_static_size); if ( ! sz )