Data-HashMap
view release on metacpan or search on metacpan
hashmap_generic.h view on Meta::CPAN
/*
* hashmap_generic.h â Macro-template for type-specialized hashmaps.
*
* Before including this file, define:
* HM_PREFIX â function name prefix (e.g., hashmap_ii)
* HM_NODE_TYPE â node struct name
* HM_MAP_TYPE â map struct name
*
* Key type (choose one):
* HM_KEY_IS_INT â define for integer keys
* (leave undefined for string keys: char* + uint32_t len + uint32_t hash)
*
* Value type (choose one):
* HM_VALUE_IS_STR â define for string values (char* + uint32_t len)
* HM_VALUE_IS_SV â define for opaque pointer values (void*, refcounted externally)
* (leave undefined for integer values)
*
* Integer width (optional, defaults to int64_t):
* HM_INT_TYPE â integer type (int32_t or int64_t)
* HM_INT_MIN â minimum value (sentinel: empty key)
* HM_INT_MAX â maximum value (for overflow checks)
*
* Optional:
* HM_HAS_COUNTERS â define to generate incr/decr functions (int values only)
*/
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
/* ---- Macro helpers ---- */
#define HM_PASTE2(a, b) a##_##b
#define HM_PASTE(a, b) HM_PASTE2(a, b)
#define HM_FN(name) HM_PASTE(HM_PREFIX, name)
/* ---- Integer type defaults ---- */
#ifndef HM_INT_TYPE
#define HM_INT_TYPE int64_t
#define HM_INT_MIN INT64_MIN
#define HM_INT_MAX INT64_MAX
#endif
/* ---- Branch prediction ---- */
#ifndef HM_LIKELY
#if defined(__GNUC__) || defined(__clang__)
#define HM_LIKELY(x) __builtin_expect(!!(x), 1)
#define HM_UNLIKELY(x) __builtin_expect(!!(x), 0)
#else
#define HM_LIKELY(x) (x)
#define HM_UNLIKELY(x) (x)
#endif
#endif
/* ---- TTL timestamp helper ---- */
/* Compute expiry timestamp, clamping to 1 if the addition wraps to 0.
* expires_at==0 is the sentinel for "no expiry", so we must avoid it. */
#ifndef HM_EXPIRY_AT_DEFINED
#define HM_EXPIRY_AT_DEFINED
static inline uint32_t hm_expiry_at(uint32_t ttl) {
uint32_t e = (uint32_t)time(NULL) + ttl;
return e ? e : 1;
}
#endif
/* Shared TTL check at slot `idx`: if entry has an expires_at set and it is
* in the past, call the variant's expire_at() and return false from the
* enclosing function. `may_compact` tells expire_at whether to trigger
* compaction (false for read paths, true for write paths so compaction
* can happen while the lock is held). Defined once; HM_FN() in the body
* is expanded at each call site to the current variant's symbol.
*/
#ifndef HM_TTL_CHECK_EXPIRED_DEFINED
#define HM_TTL_CHECK_EXPIRED_DEFINED
#define HM_TTL_CHECK_EXPIRED(map, idx, may_compact) do { \
if (HM_UNLIKELY((map)->expires_at && (map)->expires_at[idx]) && \
(uint32_t)time(NULL) > (map)->expires_at[idx]) { \
HM_FN(expire_at)((map), (idx), (may_compact)); \
return false; \
} \
} while (0)
#endif
/* Compaction policy after a tombstone is created: compact when dead slots
* exceed 25% capacity or outnumber live entries. Centralized so future
* threshold tuning touches one macro. */
#ifndef HM_MAYBE_COMPACT_DEFINED
#define HM_MAYBE_COMPACT_DEFINED
( run in 0.511 second using v1.01-cache-2.11-cpan-483215c6ad5 )