diff --git a/src/lib/symbol-impl.cpp b/src/lib/symbol-impl.cpp index 1345ab795..3d06dcc35 100644 --- a/src/lib/symbol-impl.cpp +++ b/src/lib/symbol-impl.cpp @@ -67,10 +67,13 @@ namespace lib { size_t hash_value (Literal sym) { size_t hash=0; - const char *pos = sym; - size_t maxpos = STRING_MAX_RELEVANT; - for ( ; pos && --maxpos; ++pos) - hash_combine(hash, *pos); + if (sym) + { + const char *pos = sym; + size_t maxpos = STRING_MAX_RELEVANT; + for ( ; *pos && --maxpos; ++pos) + hash_combine(hash, *pos); + } return hash; } diff --git a/tests/lib/symbol-hashtable-test.cpp b/tests/lib/symbol-hashtable-test.cpp index 92fd43a34..2e74f7b3c 100644 --- a/tests/lib/symbol-hashtable-test.cpp +++ b/tests/lib/symbol-hashtable-test.cpp @@ -23,16 +23,18 @@ #include "lib/test/run.hpp" +#include "lib/test/test-helper.hpp" #include "lib/util.hpp" #include "lib/symbol.hpp" #include #include +#include #include -using util::isnil; using util::contains; +using util::isnil; @@ -67,6 +69,8 @@ namespace test{ void run (Arg) { + checkHashFunction(); + HTable table; ASSERT (isnil(table)); @@ -95,6 +99,63 @@ namespace test{ ASSERT (isnil (table[KEY5])); // adds a new empty value object as side effect ASSERT (5 == table.size()); } + + + void + checkHashFunction() + { + string random = randStr(STRING_MAX_RELEVANT+1); + + string copy1(random); + copy1[5] = '\0'; // truncate the c-String to 5 chars + + string copy2(random); + copy2[rand() % STRING_MAX_RELEVANT] = '*'; // modify a random position + + string copy3(copy2); + copy3[STRING_MAX_RELEVANT] = '*'; // modify behind observation limit + + Symbol l0; + Literal l51 (copy1.c_str()); + Literal l52 (random.substr(0,5).c_str()); + + Literal l_1 (random.c_str()); + Literal l_2 (copy2.c_str()); + Literal l_3 (copy3.c_str()); + + ASSERT (isnil (l0)); + ASSERT (l0 != l51); + ASSERT (l51 == l52); + + ASSERT (l51 != l_1); + ASSERT (l_1 != l_2); + ASSERT (l_2 == l_3); // difference not detected due to observation limit... + ASSERT (!std::strncmp (l_2, l_3, STRING_MAX_RELEVANT )); + ASSERT ( std::strncmp (l_2, l_3, STRING_MAX_RELEVANT+1)); + + size_t h0 = hash_value (l0); + size_t h51 = hash_value (l51); + size_t h52 = hash_value (l52); + size_t h_1 = hash_value (l_1); + size_t h_2 = hash_value (l_2); + size_t h_3 = hash_value (l_3); + + ASSERT (h0 == 0); + ASSERT (h51 != 0); + ASSERT (h52 != 0); + ASSERT (h_1 != 0); + ASSERT (h_2 != 0); + ASSERT (h_3 != 0); + + ASSERT (h51 == h52); // verify the hash function indeed stops at '\0' + ASSERT (h51 != h_1); // share a common prefix, but the hash differs + ASSERT (h_1 != h_2); // the single random modification is detected + ASSERT (h_2 == h_3); // because l_2 and l_3 differ behind the fixed observation limit + + ASSERT (h_1 == hash_value (l_1)); //reproducible + ASSERT (h_2 == hash_value (l_2)); + ASSERT (h_3 == hash_value (l_3)); + } }; LAUNCHER (SymbolHashtable_test, "function common");