Skip to content

Commit

Permalink
aws_hash_combine() (#618)
Browse files Browse the repository at this point in the history
* aws_hash_combine()

* remove type-punning

* Feedback. Unused params fix.

* clearer bit-shuffling intent
  • Loading branch information
graebm authored Apr 2, 2020
1 parent 092eae8 commit ec3e191
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 0 deletions.
3 changes: 3 additions & 0 deletions include/aws/common/hash_table.h
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,9 @@ uint64_t aws_hash_byte_cursor_ptr(const void *item);
AWS_COMMON_API
uint64_t aws_hash_ptr(const void *item);

AWS_COMMON_API
uint64_t aws_hash_combine(uint64_t item1, uint64_t item2);

/**
* Convenience eq callback for NULL-terminated C-strings
*/
Expand Down
8 changes: 8 additions & 0 deletions source/hash_table.c
Original file line number Diff line number Diff line change
Expand Up @@ -991,6 +991,14 @@ uint64_t aws_hash_ptr(const void *item) {
return ((uint64_t)b << 32) | c;
}

uint64_t aws_hash_combine(uint64_t item1, uint64_t item2) {
uint32_t b = item2 & 0xFFFFFFFF; /* LSB */
uint32_t c = item2 >> 32; /* MSB */

hashlittle2(&item1, sizeof(item1), &c, &b);
return ((uint64_t)b << 32) | c;
}

bool aws_hash_callback_c_str_eq(const void *a, const void *b) {
AWS_PRECONDITION(aws_c_string_is_valid(a));
AWS_PRECONDITION(aws_c_string_is_valid(b));
Expand Down
1 change: 1 addition & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ add_test_case(test_hash_table_eq)
add_test_case(test_hash_churn)
add_test_case(test_hash_table_cleanup_idempotent)
add_test_case(test_hash_table_byte_cursor_create_find)
add_test_case(test_hash_combine)

add_test_case(test_is_power_of_two)
add_test_case(test_round_up_to_power_of_two)
Expand Down
31 changes: 31 additions & 0 deletions tests/hash_table_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -1258,3 +1258,34 @@ static int s_test_hash_table_byte_cursor_create_find_fn(struct aws_allocator *al

return 0;
}

AWS_TEST_CASE(test_hash_combine, s_test_hash_combine_fn)
static int s_test_hash_combine_fn(struct aws_allocator *allocator, void *ctx) {
(void)allocator;
(void)ctx;

/* We're assuming that the underlying hashing function works well.
* This test just makes sure we hooked it up right for 2 64bit values */

uint64_t a = 0x123456789abcdef;
uint64_t b = 0xfedcba987654321;
uint64_t c = aws_hash_combine(a, b);

/* Sanity check */
ASSERT_TRUE(c != a);
ASSERT_TRUE(c != b);

/* Same inputs gets same results, right? */
ASSERT_UINT_EQUALS(c, aws_hash_combine(a, b));

/* Result spread across all bytes, right? */
uint8_t *c_bytes = (uint8_t *)&c;
for (size_t i = 0; i < sizeof(c); ++i) {
ASSERT_TRUE(c_bytes[i] != 0);
}

/* Hash should NOT be commutative */
ASSERT_TRUE(aws_hash_combine(a, b) != aws_hash_combine(b, a));

return 0;
}

0 comments on commit ec3e191

Please sign in to comment.