Current section
Files
Jump to
Current section
Files
c_src/nif/crc_resource.c
// -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; st-rulers: [132] -*-
// vim: ts=4 sw=4 ft=c++ et
#include "crc_resource.h"
static ErlNifResourceType *crc_resource_type = NULL;
static void
crc_resource_dtor(ErlNifEnv *env, void *obj)
{
if (obj == NULL) {
return;
}
crc_resource_t *resource = (void *)obj;
if (resource->parent != NULL) {
(void)enif_release_resource((void *)resource->parent);
resource->parent = NULL;
}
return;
}
int
crc_resource_load(ErlNifEnv *env, void **priv_data, ERL_NIF_TERM load_info)
{
/* Open resource type */
if (crc_resource_type == NULL) {
crc_resource_type =
enif_open_resource_type(env, NULL, "crc_resource", crc_resource_dtor, ERL_NIF_RT_CREATE | ERL_NIF_RT_TAKEOVER, NULL);
if (crc_resource_type == NULL) {
return -1;
}
}
return 0;
}
int
crc_resource_upgrade(ErlNifEnv *env, void **priv_data, void **old_priv_data, ERL_NIF_TERM load_info)
{
return crc_resource_load(env, priv_data, load_info);
}
void
crc_resource_unload(ErlNifEnv *env, void **priv_data)
{
crc_resource_type = NULL;
}
static crc_resource_t *
crc_resource_create_child(const crc_resource_t *parent, bool slow)
{
crc_resource_t *resource = NULL;
#define RESOURCE_CREATE_PARENT(type) \
do { \
crc_resource_##type##_t *p = (void *)enif_alloc_resource(crc_resource_type, sizeof(*p)); \
if (p == NULL) { \
return NULL; \
} \
(void)enif_keep_resource((void *)parent); \
p->parent = (void *)parent; \
p->model = (void *)parent->model; \
p->slow = slow; \
p->state.value = p->state.extra = 0; \
(void)crc_algorithm_init((void *)p->model, slow, &p->state); \
resource = (void *)p; \
} while (0)
switch (parent->model->bits) {
case 8: {
RESOURCE_CREATE_PARENT(uint8);
break;
} break;
case 16:
RESOURCE_CREATE_PARENT(uint16);
break;
case 32:
RESOURCE_CREATE_PARENT(uint32);
break;
case 64:
RESOURCE_CREATE_PARENT(uint64);
break;
default:
return NULL;
}
#undef RESOURCE_CREATE_PARENT
return resource;
}
static crc_resource_t *
crc_resource_create_reference(const crc_model_t *model, bool slow)
{
crc_resource_t *resource = NULL;
#define RESOURCE_CREATE_REFERENCE(type) \
do { \
crc_resource_##type##_t *p = (void *)enif_alloc_resource(crc_resource_type, sizeof(*p)); \
if (p == NULL) { \
return NULL; \
} \
p->parent = NULL; \
p->model = (void *)model; \
p->slow = slow; \
p->state.value = p->state.extra = 0; \
(void)crc_algorithm_init((void *)p->model, slow, &p->state); \
resource = (void *)p; \
} while (0)
switch (model->bits) {
case 8: {
RESOURCE_CREATE_REFERENCE(uint8);
break;
} break;
case 16:
RESOURCE_CREATE_REFERENCE(uint16);
break;
case 32:
RESOURCE_CREATE_REFERENCE(uint32);
break;
case 64:
RESOURCE_CREATE_REFERENCE(uint64);
break;
default:
return NULL;
}
#undef RESOURCE_CREATE_REFERENCE
return resource;
}
/* crc_resource_create/3 */
crc_resource_t *
crc_resource_create(const crc_resource_t *parent, const crc_model_t *model, bool slow)
{
if (model->root_keystring[0] != '\0') {
return crc_resource_create_reference(model, slow);
}
if (parent != NULL && parent->model == model) {
return crc_resource_create_child(parent, slow);
}
crc_resource_t *resource = NULL;
#define RESOURCE_CREATE_EMBED(type) \
do { \
crc_resource_embed_##type##_t *p = (void *)enif_alloc_resource(crc_resource_type, sizeof(*p)); \
if (p == NULL) { \
return NULL; \
} \
(void)memcpy(&p->model, model, sizeof(p->model)); \
p->super.parent = NULL; \
p->super.model = &p->model; \
p->model.super._link.next = p->model.super._link.prev = NULL; \
(void)crc_linklist_init_anchor(&p->model.super._link); \
p->super.slow = slow; \
p->super.state.value = p->super.state.extra = 0; \
(void)crc_algorithm_init((void *)p->super.model, slow, &p->super.state); \
resource = (void *)p; \
} while (0)
switch (model->bits) {
case 8:
RESOURCE_CREATE_EMBED(uint8);
break;
case 16:
RESOURCE_CREATE_EMBED(uint16);
break;
case 32:
RESOURCE_CREATE_EMBED(uint32);
break;
case 64:
RESOURCE_CREATE_EMBED(uint64);
break;
default:
return NULL;
}
#undef RESOURCE_CREATE_EMBED
return resource;
}
/* crc_resource_clone/1 */
crc_resource_t *
crc_resource_clone(const crc_resource_t *parent)
{
crc_resource_t *resource = NULL;
#define CRC_RESOURCE_CLONE_CALL(type) \
do { \
crc_resource_##type##_t *pp = (void *)parent; \
crc_resource_##type##_t *cp = (void *)enif_alloc_resource(crc_resource_type, sizeof(*cp)); \
if (cp == NULL) { \
return NULL; \
} \
(void)enif_keep_resource((void *)pp); \
cp->parent = (void *)parent; \
cp->model = (void *)parent->model; \
cp->slow = parent->slow; \
cp->state = pp->state; \
resource = (void *)cp; \
} while (0)
switch (parent->model->bits) {
case 8: {
CRC_RESOURCE_CLONE_CALL(uint8);
break;
} break;
case 16:
CRC_RESOURCE_CLONE_CALL(uint16);
break;
case 32:
CRC_RESOURCE_CLONE_CALL(uint32);
break;
case 64:
CRC_RESOURCE_CLONE_CALL(uint64);
break;
default:
return NULL;
}
#undef CRC_RESOURCE_CLONE_CALL
return resource;
}
/* crc_resource_get/3 */
int
crc_resource_get(ErlNifEnv *env, ERL_NIF_TERM resource_term, const crc_resource_t **resource)
{
if (resource != NULL) {
*resource = NULL;
}
const crc_resource_t *p = NULL;
if (!enif_get_resource(env, resource_term, crc_resource_type, (void **)&p)) {
return 0;
}
if (resource != NULL) {
*resource = p;
}
return 1;
}
int
crc_resource_update(const crc_resource_t *old_resource, const uint8_t *buf, size_t len, crc_resource_t **new_resource)
{
if (new_resource == NULL) {
return 0;
}
*new_resource = NULL;
crc_resource_t *resource = crc_resource_clone(old_resource);
if (resource == NULL) {
return 0;
}
if (!crc_resource_update_unsafe(resource, buf, len)) {
(void)enif_release_resource((void *)resource);
return 0;
}
*new_resource = resource;
return 1;
}
int
crc_resource_update_unsafe(crc_resource_t *resource, const uint8_t *buf, size_t len)
{
#define CRC_RESOURCE_UPDATE_CALL(type) \
do { \
crc_resource_##type##_t *r = (void *)resource; \
return crc_algorithm_update(resource->model, resource->slow, buf, len, (void *)&r->state); \
} while (0)
switch (resource->model->bits) {
case 8:
CRC_RESOURCE_UPDATE_CALL(uint8);
break;
case 16:
CRC_RESOURCE_UPDATE_CALL(uint16);
break;
case 32:
CRC_RESOURCE_UPDATE_CALL(uint32);
break;
case 64:
CRC_RESOURCE_UPDATE_CALL(uint64);
break;
default:
break;
}
#undef CRC_RESOURCE_UPDATE_CALL
return 0;
}
int
crc_resource_final(const crc_resource_t *resource, void *value)
{
int retval = 0;
#define CRC_RESOURCE_FINAL_CALL(type) \
do { \
crc_resource_##type##_t *r = (void *)resource; \
type##_t *new_value = (type##_t *)value; \
crc_model_state_##type##_t s_buff; \
crc_model_state_##type##_t *s = &s_buff; \
s_buff = r->state; \
retval = crc_algorithm_final(resource->model, resource->slow, (void *)s); \
if (retval) { \
*new_value = s->value; \
} \
} while (0)
switch (resource->model->bits) {
case 8:
CRC_RESOURCE_FINAL_CALL(uint8);
break;
case 16:
CRC_RESOURCE_FINAL_CALL(uint16);
break;
case 32:
CRC_RESOURCE_FINAL_CALL(uint32);
break;
case 64:
CRC_RESOURCE_FINAL_CALL(uint64);
break;
default:
break;
}
#undef CRC_RESOURCE_FINAL_CALL
return retval;
}