This commit is contained in:
2026-10-29 00:01:50 +01:00
parent 61bb403b08
commit 06f333caea
6 changed files with 586 additions and 163 deletions

View File

@@ -6,6 +6,7 @@
#include <chrono>
#include <unordered_map>
#include <iomanip>
#include <cstring>
#define HM_IMPLEMENTATION
#include "hm.h"
@@ -15,16 +16,16 @@ using namespace std::chrono;
typedef time_point<high_resolution_clock> time_p;
// Configuration
const int NUM_ELEMENTS = 1000000;
const size_t NUM_ELEMENTS = 1000000;
time_p now()
{
return high_resolution_clock::now();
}
double time_diff_nano(time_p end, time_p start)
double time_diff_ms(time_p end, time_p start)
{
return duration_cast<nanoseconds>(end - start).count() / 1e6;
return duration<double, std::milli>(end - start).count();
}
void print_div()
@@ -49,86 +50,85 @@ void print_row(const std::string& label, double hm_ms, double std_ms)
}
// Test with string key type
uint64_t hash_str(const void *buffer, size_t size)
{
(void)size;
const char *str = reinterpret_cast<const char*>(buffer);
uint64_t hash = (uint64_t)str;
return hash;
}
void test_str()
{
std::vector<std::string> key_pool;
std::vector<std::string> value_pool;
// Generate random strings to ensure we aren't just hashing "1", "2", "3"
for (int i = 0; i < NUM_ELEMENTS; ++i) {
for (size_t i = 0; i < NUM_ELEMENTS; ++i) {
key_pool.push_back("key_prefix_" + std::to_string(i) + "_suffix_" + std::to_string(rand() % 1000));
value_pool.push_back("value_" + std::to_string(i));
}
// --- Custom implementation ---
// Using 0 for sizes tells your library to treat them as NULL-terminated strings
HashMap hm = hm_create_ex(sizeof(const char *), 0, hash_str);
// Using 0 for sizes tells the library to treat them as NULL-terminated strings
HashMap hm = hm_create(0, 0);
// Insertion
auto start = now();
for (int i = 0; i < NUM_ELEMENTS; ++i) {
for (size_t i = 0; i < NUM_ELEMENTS; ++i) {
hm_put(&hm, key_pool[i].c_str(), value_pool[i].c_str());
}
auto end = now();
double custom_put = time_diff_nano(end, start);
double custom_put = time_diff_ms(end, start);
if (hm_count(&hm) != NUM_ELEMENTS) {
std::cerr << "Error in custom insertion!" << std::endl;
return;
}
// Lookup
start = now();
for (int i = 0; i < NUM_ELEMENTS; ++i) {
char* val = (char*)hm_get(&hm, key_pool[i].c_str());
if (!val) {
std::cerr << "Lookup error!" << std::endl;
for (size_t i = 0; i < NUM_ELEMENTS; ++i) {
const char* val = (const char*)hm_get(&hm, key_pool[i].c_str());
if (!val || strcmp(val, value_pool[i].c_str()) != 0) {
std::cerr << "Error in custom lookup!" << std::endl;
return;
}
}
end = now();
double custom_get = time_diff_nano(end, start);
double custom_get = time_diff_ms(end, start);
// Deletion
start = now();
for (int i = 0; i < NUM_ELEMENTS; ++i) {
for (size_t i = 0; i < NUM_ELEMENTS; ++i) {
hm_remove(&hm, key_pool[i].c_str());
}
end = now();
double custom_del = time_diff_nano(end, start);
double custom_del = time_diff_ms(end, start);
hm_free(&hm);
// --- Benchmark std::unordered_map ---
std::unordered_map<const char*, const char*> std_map;
std::unordered_map<std::string, std::string> std_map;
// Insertion
start = now();
for (int i = 0; i < NUM_ELEMENTS; ++i) {
std_map[key_pool[i].c_str()] = value_pool[i].c_str();
for (size_t i = 0; i < NUM_ELEMENTS; ++i) {
std_map[key_pool[i]] = value_pool[i];
}
end = now();
double std_put = time_diff_nano(end, start);
double std_put = time_diff_ms(end, start);
// Lookup
start = now();
for (int i = 0; i < NUM_ELEMENTS; ++i) {
auto it = std_map.find(key_pool[i].c_str());
if (it == std_map.end()) std::cerr << "Lookup error!" << std::endl;
for (size_t i = 0; i < NUM_ELEMENTS; ++i) {
auto it = std_map.find(key_pool[i]);
if (it == std_map.end() || it->second != value_pool[i]) {
std::cerr << "Error in std lookup!" << std::endl;
}
}
end = now();
double std_get = time_diff_nano(end, start);
double std_get = time_diff_ms(end, start);
// Deletion
start = now();
for (int i = 0; i < NUM_ELEMENTS; ++i) {
std_map.erase(key_pool[i].c_str());
for (size_t i = 0; i < NUM_ELEMENTS; ++i) {
std_map.erase(key_pool[i]);
}
end = now();
double std_del = time_diff_nano(end, start);
double std_del = time_diff_ms(end, start);
// Output Results
print_head();
@@ -143,7 +143,7 @@ void test_str()
uint64_t hash_int(const void *buffer, size_t size)
{
(void)size;
return *reinterpret_cast<const int*>(buffer);
return *reinterpret_cast<const unsigned int*>(buffer);
}
void test_int()
@@ -152,9 +152,9 @@ void test_int()
std::vector<int> keys(NUM_ELEMENTS);
std::vector<int> values(NUM_ELEMENTS);
for (int i = 0; i < NUM_ELEMENTS; ++i) {
keys[i] = i;
values[i] = i * 2;
for (size_t i = 0; i < NUM_ELEMENTS; ++i) {
keys[i] = static_cast<int>(i);
values[i] = static_cast<int>(i * 2);
}
// --- Custom implementation ---
@@ -162,15 +162,15 @@ void test_int()
// Insertion
auto start = now();
for (int i = 0; i < NUM_ELEMENTS; ++i) {
for (size_t i = 0; i < NUM_ELEMENTS; ++i) {
hm_put(&hm, &keys[i], &values[i]);
}
auto end = now();
double custom_put = time_diff_nano(end, start);
double custom_put = time_diff_ms(end, start);
// Lookup
start = now();
for (int i = 0; i < NUM_ELEMENTS; ++i) {
for (size_t i = 0; i < NUM_ELEMENTS; ++i) {
int* val = (int*)hm_get(&hm, &keys[i]);
if (!val || *val != values[i]) {
std::cerr << "Error in custom lookup!" << std::endl;
@@ -178,15 +178,15 @@ void test_int()
}
}
end = now();
double custom_get = time_diff_nano(end, start);
double custom_get = time_diff_ms(end, start);
// Deletion
start = now();
for (int i = 0; i < NUM_ELEMENTS; ++i) {
for (size_t i = 0; i < NUM_ELEMENTS; ++i) {
hm_remove(&hm, &keys[i]);
}
end = now();
double custom_del = time_diff_nano(end, start);
double custom_del = time_diff_ms(end, start);
hm_free(&hm);
@@ -195,30 +195,30 @@ void test_int()
// Insertion
start = now();
for (int i = 0; i < NUM_ELEMENTS; ++i) {
for (size_t i = 0; i < NUM_ELEMENTS; ++i) {
std_map[keys[i]] = values[i];
}
end = now();
double std_put = time_diff_nano(end, start);
double std_put = time_diff_ms(end, start);
// Lookup
start = now();
for (int i = 0; i < NUM_ELEMENTS; ++i) {
for (size_t i = 0; i < NUM_ELEMENTS; ++i) {
auto it = std_map.find(keys[i]);
if (it == std_map.end() || it->second != values[i]) {
std::cerr << "Error in std lookup!" << std::endl;
}
}
end = now();
double std_get = time_diff_nano(end, start);
double std_get = time_diff_ms(end, start);
// Deletion
start = now();
for (int i = 0; i < NUM_ELEMENTS; ++i) {
for (size_t i = 0; i < NUM_ELEMENTS; ++i) {
std_map.erase(keys[i]);
}
end = now();
double std_del = time_diff_nano(end, start);
double std_del = time_diff_ms(end, start);
// Output Results
print_head();