#ifndef SEMQ_INTERNAL_H
#define SEMQ_INTERNAL_H
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include "semq.h"
#include "semq_platform.h"
#include "core/semq_dispatch.h"
#if defined(_MSC_VER)
#include <intrin.h>
typedef volatile long semqi_refcount_t;
static inline void semqi_ref_init(semqi_refcount_t* r) { *r = 1; }
static inline void semqi_ref_inc(semqi_refcount_t* r) { _InterlockedIncrement(r); }
static inline int semqi_ref_dec(semqi_refcount_t* r) { return _InterlockedDecrement(r) == 0; }
#elif !defined(__STDC_NO_ATOMICS__)
#include <stdatomic.h>
typedef atomic_int semqi_refcount_t;
static inline void semqi_ref_init(semqi_refcount_t* r) { atomic_init(r, 1); }
static inline void semqi_ref_inc(semqi_refcount_t* r) { atomic_fetch_add(r, 1); }
static inline int semqi_ref_dec(semqi_refcount_t* r) { return atomic_fetch_sub(r, 1) == 1; }
#else
#error "SEMQ requires atomic reference counting"
#endif
#define SEMQI_HEADER_BYTES 28u
#define SEMQI_FOOTER_BYTES 64u
#define SEMQI_S_OFFSET 6u
typedef struct {
uint32_t key_off;
uint32_t key_len;
uint32_t value_off;
uint32_t value_len;
} semqi_pair_index_t;
struct semq_encoding {
semqi_refcount_t refs;
semq_config_t config;
uint32_t bpv;
uint32_t units;
uint32_t id_kind;
uint64_t n;
uint8_t header[SEMQI_HEADER_BYTES];
uint8_t* ids;
uint64_t ids_len;
uint8_t* rows;
uint64_t rows_len;
uint8_t* manifest;
uint64_t manifest_len;
uint32_t n_pairs;
semqi_pair_index_t* pairs;
uint8_t footer[SEMQI_FOOTER_BYTES];
};
struct semq_codec {
semq_config_t config;
uint32_t bpv;
uint32_t units;
uint32_t phase_packed;
float max_magnitude;
semq_backend_kind_t kind;
const semq_backend_t* orbit;
const semq_phase_backend_t* phase;
const semq_quant_backend_t* quant;
float phase_rep[2u * 256u];
};
struct semq_floor {
semq_config_t config;
uint32_t id_kind;
uint8_t reference_id[32];
uint64_t nulls;
uint64_t changed_rows;
uint64_t total_rows;
uint64_t hamming;
uint64_t max_hamming;
uint64_t distinct_nulls;
};
semq_status_t semqi_floor_create(const semq_config_t* config, uint32_t id_kind, const uint8_t reference_id[32],
uint64_t nulls, uint64_t changed_rows, uint64_t total_rows, uint64_t hamming,
uint64_t max_hamming, uint64_t distinct_nulls, semq_floor_t** out,
semq_error_t* err);
struct semq_verdict {
uint32_t reasons;
uint64_t n_rows;
uint64_t* rows;
};
struct semq_diff {
semq_encoding_t* ref;
semq_encoding_t* cand;
uint64_t n_added;
uint64_t n_removed;
uint64_t n_changed;
uint64_t n_unchanged;
uint64_t* added;
uint64_t* removed;
uint64_t* changed_ref;
uint64_t* changed_cand;
uint64_t* hamming;
uint32_t n_mchanges;
semq_manifest_change_t* mchanges;
};
static inline semq_status_t semqi_fail(semq_error_t* err, semq_status_t status, uint64_t row,
uint64_t field, const char* message) {
if (err != NULL) {
err->status = (uint32_t)status;
err->which = (uint32_t)SEMQ_WHICH_NONE;
err->row = row;
err->field = field;
size_t i = 0u;
for (; i + 1u < sizeof(err->message) && message[i] != '\0'; i++) {
err->message[i] = message[i];
}
err->message[i] = '\0';
}
return status;
}
static inline semq_status_t semqi_fail_integrity(semq_error_t* err, semq_which_t which,
const char* message) {
const semq_status_t s = semqi_fail(err, SEMQ_ERR_INTEGRITY, SEMQ_NONE, SEMQ_NONE, message);
if (err != NULL) err->which = (uint32_t)which;
return s;
}
static inline void semqi_ok(semq_error_t* err) {
if (err != NULL) {
err->status = (uint32_t)SEMQ_OK;
err->which = (uint32_t)SEMQ_WHICH_NONE;
err->row = SEMQ_NONE;
err->field = SEMQ_NONE;
err->message[0] = '\0';
}
}
#define SEMQI_INVALID(err, row, field, msg) semqi_fail((err), SEMQ_ERR_INVALID_INPUT, (row), (field), (msg))
#define SEMQI_FORMAT(err, section, msg) semqi_fail((err), SEMQ_ERR_FORMAT, SEMQ_NONE, (uint64_t)(section), (msg))
#define SEMQI_NOMEM(err) semqi_fail((err), SEMQ_ERR_NOMEM, SEMQ_NONE, SEMQ_NONE, "allocation failed")
static inline uint16_t semqi_rd16(const uint8_t* p) { uint16_t v; memcpy(&v, p, 2u); return v; }
static inline uint32_t semqi_rd32(const uint8_t* p) { uint32_t v; memcpy(&v, p, 4u); return v; }
static inline uint64_t semqi_rd64(const uint8_t* p) { uint64_t v; memcpy(&v, p, 8u); return v; }
static inline void semqi_wr16(uint8_t* p, uint16_t v) { memcpy(p, &v, 2u); }
static inline void semqi_wr32(uint8_t* p, uint32_t v) { memcpy(p, &v, 4u); }
static inline void semqi_wr64(uint8_t* p, uint64_t v) { memcpy(p, &v, 8u); }
static inline int semqi_mul_ovf(uint64_t a, uint64_t b, uint64_t* out) {
if (a != 0u && b > UINT64_MAX / a) return 1;
*out = a * b;
return 0;
}
static inline int semqi_add_ovf(uint64_t a, uint64_t b, uint64_t* out) {
if (b > UINT64_MAX - a) return 1;
*out = a + b;
return 0;
}
static inline int semqi_too_big(uint64_t bytes) {
return bytes > (uint64_t)SIZE_MAX;
}
semq_status_t semqi_config_from_file(const uint8_t in[13], semq_config_t* out, semq_error_t* err);
const char* semqi_backend_name_for(semq_backend_kind_t kind, uint32_t op);
uint64_t semqi_find_u64(const semq_encoding_t* enc, uint64_t id);
uint64_t semqi_find_utf8(const semq_encoding_t* enc, const uint8_t* id, uint64_t len);
int semqi_id_cmp(const semq_encoding_t* a, uint64_t i, const semq_encoding_t* b, uint64_t j);
void semqi_id_at(const semq_encoding_t* e, uint64_t i, uint64_t* u, const uint8_t** p, uint64_t* l);
int semqi_mul_le(uint64_t a, uint64_t b, uint64_t c, uint64_t d);
int semqi_utf8_valid(const uint8_t* s, uint64_t len);
int semqi_cmp_bytes(const uint8_t* a, uint64_t alen, const uint8_t* b, uint64_t blen);
semq_status_t semqi_sort_ids(const semq_ids_t* ids, uint64_t** perm, semq_error_t* err);
semq_status_t semqi_manifest_build(const semq_pair_t* pairs, uint32_t n_pairs, uint8_t** section,
uint64_t* len, semq_error_t* err);
semq_status_t semqi_manifest_index(const uint8_t* section, uint64_t len, uint32_t* n_pairs,
semqi_pair_index_t** index, semq_error_t* err);
uint32_t semqi_bits_per_unit(const semq_config_t* cfg);
void semqi_unpack_row(const semq_config_t* cfg, const uint8_t* row, uint8_t* symbols);
int semqi_row_canonical(const semq_config_t* cfg, const uint8_t* row, uint64_t* unit);
semq_encoding_t* semqi_encoding_alloc(void);
semq_status_t semqi_encoding_finish(semq_encoding_t* enc, semq_error_t* err);
semq_status_t semqi_ids_section(const semq_ids_t* ids, const uint64_t* perm, uint8_t** section,
uint64_t* len, semq_error_t* err);
void* semqi_alloc(uint64_t bytes);
void* semqi_calloc(uint64_t count, uint64_t size);
void semqi_free(void* p);
#endif