Registry

Header: libxs_reg.h

Thread-safe key-value store backed by a hash table with per-thread caching.

Configuration Macros

Macro Default Description
LIBXS_REGKEY_MAXSIZE 64 Maximum key size in bytes
LIBXS_REGISTRY_NBUCKETS 64 Initial hash-table buckets (power of two); registries grow dynamically
LIBXS_REGCACHE_NENTRIES 16 Thread-local cache entries per thread (power of two; 0 disables caching)

Types

typedef struct libxs_registry_t libxs_registry_t;   /* opaque */
typedef struct libxs_registry_info_t {
  size_t capacity, size, nbytes;
} libxs_registry_info_t;

Lifetime

libxs_registry_t* libxs_registry_create(void);

Create a new registry. Returns NULL in case of an error.

void libxs_registry_destroy(libxs_registry_t* registry);

Destroy a registry and release all entries.

libxs_lock_t* libxs_registry_lock(libxs_registry_t* registry);

Return a pointer to the registry's internal lock. The returned lock can be passed as the lock argument to other registry functions (e.g., to hold the lock across multiple operations).

Iteration

void* libxs_registry_begin(libxs_registry_t* registry,
  const void** key, size_t* cursor);
void* libxs_registry_next(libxs_registry_t* registry,
  const void** key, size_t* cursor);

Enumerate entries. Initialize *cursor to 0 before the first begin call. Each call returns the value pointer and writes the key pointer to *key, or returns NULL when iteration is complete.

Access

void* libxs_registry_set(libxs_registry_t* registry,
  const void* key, size_t key_size,
  const void* value_init, size_t value_size,
  libxs_lock_t* lock /* = NULL */);

Insert or update a key-value pair. The key must be binary-reproducible (zero-initialize padding). value_init may be NULL to defer initialization. Re-registering an existing key reallocates if the new value is larger. When lock is NULL the registry's internal lock is used. Returns a pointer to the stored value.

void* libxs_registry_get(const libxs_registry_t* registry,
  const void* key, size_t key_size,
  libxs_lock_t* lock /* = NULL */);

Look up a value by key. Returns NULL if not found.

int libxs_registry_get_copy(const libxs_registry_t* registry,
  const void* key, size_t key_size,
  void* value_out, size_t value_size,
  libxs_lock_t* lock /* = NULL */);

Thread-safe query: copies up to value_size bytes of the stored value into value_out under the lock. Unlike libxs_registry_get, the caller never receives a raw pointer into the registry's internal storage, making this safe under concurrent modifications. Returns non-zero if the key was found, zero otherwise.

int libxs_registry_has(libxs_registry_t* registry,
  const void* key, size_t key_size,
  libxs_lock_t* lock /* = NULL */);

Check whether a key exists. Non-zero if found.

size_t libxs_registry_value_size(libxs_registry_t* registry,
  const void* key, size_t key_size,
  libxs_lock_t* lock /* = NULL */);

Query the stored value size in bytes. Returns 0 if not found.

void libxs_registry_remove(libxs_registry_t* registry,
  const void* key, size_t key_size,
  libxs_lock_t* lock /* = NULL */);

Remove a key-value pair and release its memory.

int libxs_registry_extract(libxs_registry_t* registry,
  const void* key, size_t key_size,
  void* value_out, size_t value_size,
  libxs_lock_t* lock /* = NULL */);

Atomically retrieve and remove a key-value pair. Copies up to value_size bytes of the stored value into value_out (may be NULL to discard the value), then removes the entry and releases its memory. The lookup, copy, and removal are performed under a single lock hold, eliminating the race that exists when calling libxs_registry_get followed by libxs_registry_remove separately. Returns non-zero if the key was found, zero otherwise.

Serialization

int libxs_registry_save(const libxs_registry_t* registry,
  void* buffer, size_t* size);

Save the registry to a binary buffer. Pass buffer = NULL to query the required size (written to *size). On success, *size contains the number of bytes written. Returns EXIT_SUCCESS or EXIT_FAILURE.

libxs_registry_t* libxs_registry_load(const void* buffer, size_t size,
  void (*fixup)(void* value, const void* key, size_t key_size,
    size_t value_size, void* udata),
  void* udata /* = NULL */);

Load a registry from a binary buffer (previously produced by libxs_registry_save). Keys are materialized immediately. When fixup is NULL, values remain in the buffer and are accessed on demand via libxs_registry_get; the buffer must remain valid for the lifetime of the returned registry. When fixup is non-NULL, each value is heap-allocated immediately and the callback is invoked once per entry, allowing the caller to restore pointers or handles by key identity. Returns a new registry or NULL on failure.

Status

int libxs_registry_info(libxs_registry_t* registry,
  libxs_registry_info_t* info);

Query registry capacity, number of entries, and total bytes stored.