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 )