#ifndef RAY_STR_H
#define RAY_STR_H
#include <rayforce.h>
#include <string.h>
typedef union {
struct { uint32_t len; char data[12]; };
struct { uint32_t len_; char prefix[4];
uint32_t pool_off; uint32_t _pad; };
} ray_str_t;
#define RAY_STR_INLINE_MAX 12
static inline bool ray_str_is_inline(const ray_str_t* s) {
return s->len <= RAY_STR_INLINE_MAX;
}
static inline const char* ray_str_t_ptr(const ray_str_t* s, const char* pool_base) {
if (s->len == 0) return "";
if (ray_str_is_inline(s)) return s->data;
assert(pool_base != NULL && "ray_str_t_ptr: pooled string requires non-NULL pool_base");
return pool_base + s->pool_off;
}
static inline bool ray_str_t_eq(const ray_str_t* a, const char* pool_a,
const ray_str_t* b, const char* pool_b) {
if (a->len != b->len) return false;
if (a->len == 0) return true;
if (ray_str_is_inline(a)) {
return memcmp(a->data, b->data, a->len) == 0;
}
if (memcmp(a->prefix, b->prefix, 4) != 0) return false;
return memcmp(pool_a + a->pool_off, pool_b + b->pool_off, a->len) == 0;
}
static inline int ray_str_t_cmp(const ray_str_t* a, const char* pool_a,
const ray_str_t* b, const char* pool_b) {
const char* pa = ray_str_t_ptr(a, pool_a);
const char* pb = ray_str_t_ptr(b, pool_b);
uint32_t min_len = a->len < b->len ? a->len : b->len;
int r = memcmp(pa, pb, min_len);
if (r != 0) return r;
return (a->len > b->len) - (a->len < b->len);
}
static inline uint64_t ray_str_t_hash(const ray_str_t* s, const char* pool_base) {
if (s->len == 0) return 0x9E3779B97F4A7C15ULL;
if (!ray_str_is_inline(s)) {
assert(pool_base != NULL && "ray_str_t_hash: pooled string requires non-NULL pool_base");
}
const char* p = ray_str_is_inline(s) ? s->data : pool_base + s->pool_off;
uint64_t h = 0xcbf29ce484222325ULL;
for (uint32_t i = 0; i < s->len; i++) {
h ^= (uint64_t)(unsigned char)p[i];
h *= 0x100000001b3ULL;
}
return h;
}
#endif