Browse Source

nif调整

master
SisMaker 5 years ago
parent
commit
04fcc5d486
119 changed files with 0 additions and 16956 deletions
  1. +0
    -442
      c_src/.enq/enq_nif.c
  2. +0
    -71
      c_src/.enq/fifo.h
  3. +0
    -63
      c_src/.enq/lifo.h
  4. +0
    -12
      c_src/.enq/rebar.config
  5. +0
    -688
      c_src/.mqtree/mqtree.c
  6. +0
    -12
      c_src/.mqtree/rebar.config
  7. +0
    -1074
      c_src/.mqtree/uthash.h
  8. +0
    -80
      c_src/bitmap_filter/bitmap_filter.c
  9. +0
    -30
      c_src/bitmap_filter/rebar.config
  10. +0
    -448
      c_src/bsn/bsn_ext.c
  11. +0
    -331
      c_src/bsn/bsn_int.c
  12. +0
    -448
      c_src/bsn/c_src/bsn_ext.c
  13. +0
    -331
      c_src/bsn/c_src/bsn_int.c
  14. +0
    -29
      c_src/bsn/rebar.config
  15. +0
    -843
      c_src/couchdb-khash2/hash.c
  16. +0
    -240
      c_src/couchdb-khash2/hash.h
  17. +0
    -658
      c_src/couchdb-khash2/khash.c
  18. +0
    -12
      c_src/couchdb-khash2/rebar.config
  19. +0
    -80
      c_src/enlfq/Makefile
  20. +0
    -3637
      c_src/enlfq/concurrentqueue.h
  21. +0
    -84
      c_src/enlfq/enlfq.cc
  22. +0
    -10
      c_src/enlfq/enlfq.h
  23. +0
    -57
      c_src/enlfq/enlfq_nif.cc
  24. +0
    -19
      c_src/enlfq/enlfq_nif.h
  25. +0
    -27
      c_src/enlfq/nif_utils.cc
  26. +0
    -6
      c_src/enlfq/nif_utils.h
  27. +0
    -7
      c_src/enlfq/rebar.config
  28. +0
    -172
      c_src/etsq/etsq.cpp
  29. +0
    -130
      c_src/etsq/etsq.h
  30. +0
    -7
      c_src/etsq/rebar.config
  31. +0
    -103
      c_src/gb_lru/binary.h
  32. +0
    -2394
      c_src/gb_lru/btree.h
  33. +0
    -349
      c_src/gb_lru/btree_container.h
  34. +0
    -130
      c_src/gb_lru/btree_map.h
  35. +0
    -619
      c_src/gb_lru/btreelru_nif.cpp
  36. +0
    -71
      c_src/gb_lru/erlterm.h
  37. +0
    -266
      c_src/gb_lru/lru.h
  38. +0
    -73
      c_src/gb_lru/murmurhash2.h
  39. +0
    -7
      c_src/gb_lru/rebar.config
  40. +0
    -90
      c_src/native_array/native_array_nif.c
  41. +0
    -7
      c_src/native_array/rebar.config
  42. +0
    -905
      c_src/neural/NeuralTable.cpp
  43. +0
    -121
      c_src/neural/NeuralTable.h
  44. +0
    -134
      c_src/neural/neural.cpp
  45. +0
    -46
      c_src/neural/neural_utils.cpp
  46. +0
    -9
      c_src/neural/neural_utils.h
  47. +0
    -14
      c_src/neural/rebar.config
  48. +0
    -111
      c_src/nif_array/binary_tools.c
  49. +0
    -13
      c_src/nif_array/rebar.config
  50. BIN
      priv/binary_tools.dll
  51. BIN
      priv/binary_tools.exp
  52. BIN
      priv/binary_tools.lib
  53. BIN
      priv/binary_tools.so
  54. BIN
      priv/bitmap_filter.dll
  55. BIN
      priv/bitmap_filter.exp
  56. BIN
      priv/bitmap_filter.lib
  57. BIN
      priv/bitmap_filter.so
  58. BIN
      priv/bsn_ext.dll
  59. BIN
      priv/bsn_ext.exp
  60. BIN
      priv/bsn_ext.lib
  61. BIN
      priv/bsn_ext.so
  62. BIN
      priv/bsn_int.dll
  63. BIN
      priv/bsn_int.exp
  64. BIN
      priv/bsn_int.lib
  65. BIN
      priv/bsn_int.so
  66. BIN
      priv/btreelru_nif.dll
  67. BIN
      priv/btreelru_nif.exp
  68. BIN
      priv/btreelru_nif.lib
  69. BIN
      priv/btreelru_nif.so
  70. BIN
      priv/cbase64.dll
  71. BIN
      priv/enlfq.dll
  72. BIN
      priv/enlfq.exp
  73. BIN
      priv/enlfq.lib
  74. BIN
      priv/enlfq.so
  75. BIN
      priv/epqueue_nif.dll
  76. BIN
      priv/etsq.dll
  77. BIN
      priv/etsq.exp
  78. BIN
      priv/etsq.lib
  79. BIN
      priv/etsq.so
  80. BIN
      priv/hqueue.dll
  81. BIN
      priv/khash.dll
  82. BIN
      priv/khash2.dll
  83. BIN
      priv/khash2.exp
  84. BIN
      priv/khash2.lib
  85. BIN
      priv/khash2.so
  86. BIN
      priv/mqtree.so
  87. BIN
      priv/native_array_nif.dll
  88. BIN
      priv/native_array_nif.exp
  89. BIN
      priv/native_array_nif.lib
  90. BIN
      priv/native_array_nif.so
  91. BIN
      priv/neural.dll
  92. BIN
      priv/neural.exp
  93. BIN
      priv/neural.lib
  94. BIN
      priv/neural.so
  95. BIN
      priv/nifArray.dll
  96. BIN
      priv/nifHashb.dll
  97. BIN
      priv/nifHashb.exp
  98. BIN
      priv/nifHashb.lib
  99. BIN
      priv/nif_skiplist.dll
  100. +0
    -20
      src/nifSrc/bitmap_filter/bitmap_filter.erl

+ 0
- 442
c_src/.enq/enq_nif.c View File

@ -1,442 +0,0 @@
#define _GNU_SOURCE
#include "erl_nif.h"
#include <assert.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <time.h>
// #include "fifo.h"
#include "lifo.h"
typedef struct {
ERL_NIF_TERM ok;
ERL_NIF_TERM error;
ERL_NIF_TERM fifo;
ERL_NIF_TERM lifo;
ERL_NIF_TERM ttl;
ERL_NIF_TERM max_size;
} atoms_t;
typedef struct {
ErlNifResourceType *queue;
atoms_t atoms;
} priv_t;
typedef struct {
union {
fifo_handle_t fifo;
lifo_handle_t lifo;
} handle;
ErlNifBinary data;
struct timespec added;
} item_t;
typedef enum {
QTYPE_FIFO = 0,
QTYPE_LIFO
} queue_type_t;
typedef struct queue {
union {
fifo_t fifo;
lifo_t lifo;
} queue;
uint64_t ttl;
uint64_t max_size;
void (*push) (struct queue *inst, item_t *item);
item_t* (*pop) (struct queue *inst);
void (*free) (struct queue *inst);
uint64_t (*size) (struct queue *inst);
void (*cleanup) (struct queue *inst);
} queue_t;
// returns tuple {error, atom()}
static inline ERL_NIF_TERM
make_error(ErlNifEnv* env, const char *error) {
priv_t *priv = (priv_t *) enif_priv_data(env);
return enif_make_tuple2(env, priv->atoms.error, enif_make_atom(env, error));
}
// returns time diff in milliseconds
static inline int64_t
tdiff(struct timespec *t2, struct timespec *t1) {
return (t2->tv_sec * 1000 + t2->tv_nsec / 1000000UL) -
(t1->tv_sec * 1000 + t1->tv_nsec / 1000000UL);
}
static inline void
gettime(struct timespec *tp) {
int rc = clock_gettime(CLOCK_MONOTONIC_RAW, tp);
assert(rc == 0);
}
/******************************************************************************/
/* FIFO callbacks */
/******************************************************************************/
static void
cleanup_fifo(queue_t *inst) {
struct timespec now;
gettime(&now);
for (;;) {
item_t *item = NULL;
__fifo_peak(&inst->queue.fifo, item, handle.fifo);
if (item == NULL)
return;
int64_t diff = tdiff(&now, &item->added);
if (diff < inst->ttl) {
return;
} else {
__fifo_pop(&inst->queue.fifo, item, handle.fifo);
enif_release_binary(&item->data);
enif_free(item);
}
}
}
static void
push_fifo(queue_t *inst, item_t *item) {
__fifo_push(&inst->queue.fifo, item, handle.fifo);
}
static item_t *
pop_fifo(queue_t *inst) {
item_t *item = NULL;
if (inst->ttl > 0) {
struct timespec now;
gettime(&now);
for (;;) {
__fifo_pop(&inst->queue.fifo, item, handle.fifo);
if (item == NULL)
return NULL;
int64_t diff = tdiff(&now, &item->added);
if (diff < inst->ttl) {
return item;
} else {
enif_release_binary(&item->data);
enif_free(item);
}
}
} else {
__fifo_pop(&inst->queue.fifo, item, handle.fifo);
}
return item;
}
static void
free_fifo(queue_t *inst) {
item_t *item;
for(;;) {
__fifo_pop(&inst->queue.fifo, item, handle.fifo);
if (item == NULL)
return;
enif_release_binary(&item->data);
enif_free(item);
}
}
static uint64_t
size_fifo(queue_t *inst) {
return fifo_length(&inst->queue.fifo);
}
/******************************************************************************/
/* LIFO callbacks */
/******************************************************************************/
static void
cleanup_lifo(queue_t *inst) {
struct timespec now;
gettime(&now);
for(;;) {
item_t *item = inst->queue.lifo.tail;
if (item == NULL)
return;
int64_t diff = tdiff(&now, &item->added);
if (diff < inst->ttl) {
return;
} else {
item_t *prev = item->handle.lifo.prev;
if (prev != NULL)
prev->handle.lifo.next = NULL;
inst->queue.lifo.tail = prev;
enif_release_binary(&item->data);
enif_free(item);
}
}
}
static void
push_lifo(queue_t *inst, item_t *item) {
__lifo_push(&inst->queue.lifo, item, handle.lifo);
}
static item_t *
pop_lifo(queue_t *inst) {
item_t *item = NULL;
if (inst->ttl > 0)
cleanup_lifo(inst);
__lifo_pop(&inst->queue.lifo, item, handle.lifo);
return item;
}
static void
free_lifo(queue_t *inst) {
item_t *item;
for(;;) {
__lifo_pop(&inst->queue.lifo, item, handle.lifo);
if (item == NULL)
return;
enif_release_binary(&item->data);
enif_free(item);
}
}
static uint64_t
size_lifo(queue_t *inst) {
return lifo_length(&inst->queue.lifo);
}
/******************************************************************************
** NIFs
*******************************************************************************/
static ERL_NIF_TERM
new_queue(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {
if (!enif_is_list(env, argv[0]))
return enif_make_badarg(env);
priv_t *priv = (priv_t *) enif_priv_data(env);
queue_type_t qtype = QTYPE_FIFO;
unsigned long ttl = 0;
unsigned long max_size = 0;
ERL_NIF_TERM settings_list = argv[0];
ERL_NIF_TERM head;
// parses proplist [fifo, lifo, {ttl, non_neg_integer()}, {max_size, non_neg_integer()}]
while(enif_get_list_cell(env, settings_list, &head, &settings_list))
{
const ERL_NIF_TERM *items;
int arity;
if (enif_is_atom(env, head)) {
if (enif_is_identical(head, priv->atoms.fifo)) {
qtype = QTYPE_FIFO;
} else if (enif_is_identical(head, priv->atoms.lifo)) {
qtype = QTYPE_LIFO;
} else {
return enif_make_badarg(env);
}
} else if (enif_get_tuple(env, head, &arity, &items) && arity == 2) {
if (enif_is_identical(items[0], priv->atoms.ttl)) {
if (!enif_get_ulong(env, items[1], &ttl)) {
return enif_make_badarg(env);
}
} else if (enif_is_identical(items[0], priv->atoms.max_size)) {
if (!enif_get_ulong(env, items[1], &max_size)) {
return enif_make_badarg(env);
}
} else {
return enif_make_badarg(env);
}
} else {
return enif_make_badarg(env);
}
}
queue_t *inst = (queue_t *) enif_alloc_resource(priv->queue, sizeof(*inst));
if (inst == NULL)
return make_error(env, "enif_alloc_resource");
inst->ttl = ttl;
inst->max_size = max_size;
switch (qtype) {
case QTYPE_FIFO:
fifo_init(&inst->queue.fifo);
inst->push = &push_fifo;
inst->pop = &pop_fifo;
inst->free = &free_fifo;
inst->size = &size_fifo;
inst->cleanup = &cleanup_fifo;
break;
case QTYPE_LIFO:
lifo_init(&inst->queue.lifo);
inst->push = &push_lifo;
inst->pop = &pop_lifo;
inst->free = &free_lifo;
inst->size = &size_lifo;
inst->cleanup = &cleanup_lifo;
break;
}
ERL_NIF_TERM result = enif_make_resource(env, inst);
enif_release_resource(inst);
return enif_make_tuple2(env, priv->atoms.ok, result);
}
static ERL_NIF_TERM
push_item(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {
priv_t *priv = (priv_t *) enif_priv_data(env);
queue_t *inst;
if (!enif_get_resource(env, argv[0], priv->queue, (void**) &inst))
return enif_make_badarg(env);
// todo: check an owner of the queue
ErlNifBinary bin;
if (!enif_inspect_binary(env, argv[1], &bin))
return enif_make_badarg(env);
if (inst->ttl > 0) {
inst->cleanup(inst);
}
if (inst->max_size > 0 && inst->size(inst) >= inst->max_size) {
return enif_make_tuple2(env, priv->atoms.error, priv->atoms.max_size);
}
item_t *item = (item_t *) enif_alloc(sizeof(*item));
if (item == NULL)
return make_error(env, "enif_alloc");
if (!enif_alloc_binary(bin.size, &item->data)) {
enif_free(item);
return make_error(env, "enif_alloc_binary");
}
memcpy(item->data.data, bin.data, bin.size);
if (inst->ttl > 0) {
gettime(&item->added);
}
inst->push(inst, item);
return priv->atoms.ok;
}
static ERL_NIF_TERM
pop_item(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {
priv_t *priv = (priv_t *) enif_priv_data(env);
queue_t *inst;
item_t *item;
if (!enif_get_resource(env, argv[0], priv->queue, (void**) &inst))
return enif_make_badarg(env);
// todo: check an owner of the queue
item = inst->pop(inst);
if (item == NULL)
return enif_make_list(env, 0);
ERL_NIF_TERM result = enif_make_binary(env, &item->data);
enif_free(item);
return enif_make_list1(env, result);
}
static ERL_NIF_TERM
queue_size(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {
priv_t *priv = (priv_t *) enif_priv_data(env);
queue_t *inst;
if (!enif_get_resource(env, argv[0], priv->queue, (void**) &inst))
return enif_make_badarg(env);
return enif_make_uint64(env, inst->size(inst));
}
/******************************************************************************
** NIF initialization
*******************************************************************************/
static void
enq_queue_free(ErlNifEnv* env, void* obj) {
queue_t *inst = obj;
inst->free(inst);
}
static priv_t *
make_priv(ErlNifEnv *env) {
priv_t *priv = enif_alloc(sizeof(*priv));
if (priv == NULL)
return NULL;
ErlNifResourceFlags flags = ERL_NIF_RT_CREATE | ERL_NIF_RT_TAKEOVER;
priv->queue = enif_open_resource_type(env, NULL, "enq_queue", enq_queue_free, flags, NULL);
priv->atoms.ok = enif_make_atom(env, "ok");
priv->atoms.error = enif_make_atom(env, "error");
priv->atoms.fifo = enif_make_atom(env, "fifo");
priv->atoms.lifo = enif_make_atom(env, "lifo");
priv->atoms.ttl = enif_make_atom(env, "ttl");
priv->atoms.max_size = enif_make_atom(env, "max_size");
return priv;
}
static int
enq_nif_load(ErlNifEnv *env, void **priv_data, ERL_NIF_TERM load_info) {
*priv_data = make_priv(env);
return 0;
}
static int
enq_nif_upgrade(ErlNifEnv *env, void **priv_data, void **old_priv_data, ERL_NIF_TERM load_info) {
*priv_data = make_priv(env);
return 0;
}
static ErlNifFunc enq_nif_funcs[] = {
{"new", 1, new_queue},
{"push", 2, push_item},
{"pop", 1, pop_item},
{"size", 1, queue_size},
};
ERL_NIF_INIT(enq_nif, enq_nif_funcs, enq_nif_load, NULL, enq_nif_upgrade, NULL)

+ 0
- 71
c_src/.enq/fifo.h View File

@ -1,71 +0,0 @@
#ifndef _FIFO_H
#define _FIFO_H
/* Main FIFO structure. Allocate memory for it yourself. */
typedef struct fifo_t {
void *head;
void *tail;
unsigned long long count;
} fifo_t;
typedef struct fifo_handle_t {
void *next;
} fifo_handle_t;
/* Initializes fifo structure. */
#define fifo_init(fifo) \
do { \
fifo_t *__q = fifo; \
__q->head = NULL; \
__q->tail = NULL; \
__q->count = 0; \
} while (0)
#define __fifo_push(fifo, p, h) \
do { \
fifo_t *__q = fifo; \
__typeof__ (p) e = p; \
e->h.next = NULL; \
if (__q->tail == NULL) { \
__q->head = e; \
} else { \
__typeof__ (e) t = __q->tail; \
t->h.next = e; \
} \
__q->tail = e; \
__q->count++; \
} while (0)
/* Puts an element to the queue. */
#define fifo_push(fifo, p) __fifo_push (fifo, p, fifo_handle)
#define __fifo_pop(fifo, p, h) \
do { \
fifo_t *__q = fifo; \
p = __q->head; \
if (p != NULL) { \
__q->count--; \
__q->head = p->h.next; \
if (__q->tail == p) \
__q->tail = NULL; \
} \
} while (0)
/* Pops the first element out of the queue. */
#define fifo_pop(fifo, p) __fifo_pop (fifo, p, fifo_handle)
#define __fifo_peak(fifo, p, h) \
do { \
p = (fifo)->head; \
} while (0)
/* Returns the first elemnt of the queue without removing. */
#define fifo_peak(fifo, p) __fifo_peak (fifo, p, fifo_handle)
/* Returns the length of the queue. */
#define fifo_length(fifo) ((fifo)->count)
/* Returns true if the queue is empty. */
#define fifo_empty(fifo) ((fifo)->count == 0)
#endif /* _FIFO_H */

+ 0
- 63
c_src/.enq/lifo.h View File

@ -1,63 +0,0 @@
#ifndef _LIFO_H
#define _LIFO_H
typedef struct lifo_t {
void *head;
void *tail;
unsigned long long count;
} lifo_t;
typedef struct lifo_handle_t {
void *next;
void *prev;
} lifo_handle_t;
#define lifo_init(lifo) \
do { \
lifo_t *__q = lifo; \
__q->head = NULL; \
__q->tail = NULL; \
__q->count = 0; \
} while (0)
#define __lifo_push(lifo, p, h) \
do { \
lifo_t *__q = lifo; \
__typeof__ (p) e = p; \
e->h.next = __q->head; \
e->h.prev = NULL; \
if (__q->head == NULL) { \
__q->tail = e; \
} else { \
__typeof__ (e) t = __q->head; \
t->h.prev = e; \
} \
__q->head = e; \
__q->count++; \
} while (0)
#define lifo_push(lifo, p) __lifo_push (lifo, p, lifo_handle)
#define __lifo_pop(lifo, p, h) \
do { \
lifo_t *__q = lifo; \
p = __q->head; \
if (p != NULL) { \
__q->count--; \
__q->head = p->h.next; \
if (__q->head != NULL) { \
__typeof__ (p) t = __q->head; \
t->h.prev = NULL; \
} else { \
__q->tail = NULL; \
} \
} \
} while (0)
#define lifo_pop(lifo, p) __lifo_pop (lifo, p, lifo_handle)
#define lifo_length(lifo) ((lifo)->count)
#define lifo_empty(lifo) ((lifo)->count == 0)
#endif /* _LIFO_H */

+ 0
- 12
c_src/.enq/rebar.config View File

@ -1,12 +0,0 @@
{port_specs, [
{"../../priv/enq_nif.so", ["*.c"]}
]}.
% {port_env, [
% {"LDFLAGS", "$ERL_LDFLAGS -lrt"},
% {"CFLAGS", "$CFLAGS --std=gnu99 -Wall -O3"}
% ]}.

+ 0
- 688
c_src/.mqtree/mqtree.c View File

@ -1,688 +0,0 @@
/*
* @author Evgeny Khramtsov <ekhramtsov@process-one.net>
* @copyright (C) 2002-2020 ProcessOne, SARL. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include <erl_nif.h>
#include <stdio.h>
#include <errno.h>
#include "uthash.h"
void __free(void *ptr, size_t size) {
enif_free(ptr);
}
#undef uthash_malloc
#undef uthash_free
#define uthash_malloc enif_alloc
#define uthash_free __free
/****************************************************************
* Structures/Globals definitions *
****************************************************************/
typedef struct __tree_t {
char *key;
char *val;
int refc;
struct __tree_t *sub;
UT_hash_handle hh;
} tree_t;
typedef struct {
tree_t *tree;
char *name;
ErlNifRWLock *lock;
} state_t;
typedef struct {
char *name;
state_t *state;
UT_hash_handle hh;
} registry_t;
static ErlNifResourceType *tree_state_t = NULL;
static registry_t *registry = NULL;
static ErlNifRWLock *registry_lock = NULL;
/****************************************************************
* MQTT Tree Manipulation *
****************************************************************/
tree_t *tree_new(char *key, size_t len) {
tree_t *tree = enif_alloc(sizeof(tree_t));
if (tree) {
memset(tree, 0, sizeof(tree_t));
if (key && len) {
tree->key = enif_alloc(len);
if (tree->key) {
memcpy(tree->key, key, len);
} else {
enif_free(tree);
tree = NULL;
}
}
}
return tree;
}
void tree_free(tree_t *t) {
tree_t *found, *iter;
if (t) {
enif_free(t->key);
enif_free(t->val);
HASH_ITER(hh, t->sub, found, iter) {
HASH_DEL(t->sub, found);
tree_free(found);
}
memset(t, 0, sizeof(tree_t));
enif_free(t);
}
}
void tree_clear(tree_t *root) {
tree_t *found, *iter;
HASH_ITER(hh, root->sub, found, iter) {
HASH_DEL(root->sub, found);
tree_free(found);
}
}
int tree_add(tree_t *root, char *path, size_t size) {
int i = 0;
size_t len;
tree_t *t = root;
tree_t *found, *new;
while (i<=size) {
len = strlen(path+i) + 1;
HASH_FIND_STR(t->sub, path+i, found);
if (found) {
i += len;
t = found;
} else {
new = tree_new(path+i, len);
if (new) {
HASH_ADD_STR(t->sub, key, new);
i += len;
t = new;
} else
return ENOMEM;
}
}
if (!t->val) {
t->val = enif_alloc(size+1);
if (t->val) {
t->val[size] = 0;
for (i=0; i<size; i++) {
char c = path[i];
t->val[i] = c ? c : '/';
}
} else
return ENOMEM;
}
t->refc++;
return 0;
}
int tree_del(tree_t *root, char *path, size_t i, size_t size) {
tree_t *found;
if (i<=size) {
HASH_FIND_STR(root->sub, path+i, found);
if (found) {
i += strlen(path+i) + 1;
int deleted = tree_del(found, path, i, size);
if (deleted) {
HASH_DEL(root->sub, found);
tree_free(found);
}
}
} else if (root->refc) {
root->refc--;
if (!root->refc) {
enif_free(root->val);
root->val = NULL;
}
}
return !root->refc && !root->sub;
}
void tree_size(tree_t *tree, size_t *size) {
tree_t *found, *iter;
HASH_ITER(hh, tree->sub, found, iter) {
if (found->refc) (*size)++;
tree_size(found, size);
}
}
int tree_refc(tree_t *tree, char *path, size_t i, size_t size) {
tree_t *found;
if (i<=size) {
HASH_FIND_STR(tree->sub, path+i, found);
if (found) {
i += strlen(path+i) + 1;
return tree_refc(found, path, i, size);
} else {
return 0;
}
} else
return tree->refc;
}
/****************************************************************
* Registration *
****************************************************************/
void delete_registry_entry(registry_t *entry) {
/* registry_lock must be RW-locked! */
HASH_DEL(registry, entry);
entry->state->name = NULL;
enif_release_resource(entry->state);
enif_free(entry->name);
enif_free(entry);
}
int register_tree(char *name, state_t *state) {
registry_t *entry, *found;
entry = enif_alloc(sizeof(registry_t));
if (!entry) return ENOMEM;
entry->name = enif_alloc(strlen(name) + 1);
if (!entry->name) {
free(entry);
return ENOMEM;
}
entry->state = state;
strcpy(entry->name, name);
enif_rwlock_rwlock(registry_lock);
HASH_FIND_STR(registry, name, found);
if (found) {
enif_rwlock_rwunlock(registry_lock);
enif_free(entry->name);
enif_free(entry);
return EINVAL;
} else {
if (state->name) {
/* Unregistering previously registered name */
HASH_FIND_STR(registry, state->name, found);
if (found)
delete_registry_entry(found);
}
enif_keep_resource(state);
HASH_ADD_STR(registry, name, entry);
state->name = entry->name;
enif_rwlock_rwunlock(registry_lock);
return 0;
}
}
int unregister_tree(char *name) {
registry_t *entry;
int ret;
enif_rwlock_rwlock(registry_lock);
HASH_FIND_STR(registry, name, entry);
if (entry) {
delete_registry_entry(entry);
ret = 0;
} else {
ret = EINVAL;
}
enif_rwlock_rwunlock(registry_lock);
return ret;
}
/****************************************************************
* NIF helpers *
****************************************************************/
static ERL_NIF_TERM cons(ErlNifEnv *env, char *str, ERL_NIF_TERM tail)
{
if (str) {
size_t len = strlen(str);
ERL_NIF_TERM head;
unsigned char *buf = enif_make_new_binary(env, len, &head);
if (buf) {
memcpy(buf, str, len);
return enif_make_list_cell(env, head, tail);
}
}
return tail;
}
static void match(ErlNifEnv *env, tree_t *root,
char *path, size_t i, size_t size, ERL_NIF_TERM *acc)
{
tree_t *found;
size_t len = 0;
if (i<=size) {
HASH_FIND_STR(root->sub, path+i, found);
if (found) {
len = strlen(path+i) + 1;
match(env, found, path, i+len, size, acc);
};
if (i || path[0] != '$') {
HASH_FIND_STR(root->sub, "+", found);
if (found) {
len = strlen(path+i) + 1;
match(env, found, path, i+len, size, acc);
}
HASH_FIND_STR(root->sub, "#", found);
if (found) {
*acc = cons(env, found->val, *acc);
}
}
} else {
*acc = cons(env, root->val, *acc);
HASH_FIND_STR(root->sub, "#", found);
if (found)
*acc = cons(env, found->val, *acc);
}
}
static void to_list(ErlNifEnv *env, tree_t *root, ERL_NIF_TERM *acc)
{
tree_t *found, *iter;
HASH_ITER(hh, root->sub, found, iter) {
if (found->val) {
size_t len = strlen(found->val);
ERL_NIF_TERM refc = enif_make_int(env, found->refc);
ERL_NIF_TERM val;
unsigned char *buf = enif_make_new_binary(env, len, &val);
if (buf) {
memcpy(buf, found->val, len);
*acc = enif_make_list_cell(env, enif_make_tuple2(env, val, refc), *acc);
}
};
to_list(env, found, acc);
}
}
static ERL_NIF_TERM dump(ErlNifEnv *env, tree_t *tree)
{
tree_t *found, *iter;
ERL_NIF_TERM tail, head;
tail = enif_make_list(env, 0);
HASH_ITER(hh, tree->sub, found, iter) {
head = dump(env, found);
tail = enif_make_list_cell(env, head, tail);
}
if (tree->key) {
ERL_NIF_TERM part, path;
part = enif_make_string(env, tree->key, ERL_NIF_LATIN1);
if (tree->val)
path = enif_make_string(env, tree->val, ERL_NIF_LATIN1);
else
path = enif_make_atom(env, "none");
return enif_make_tuple4(env, part, path, enif_make_int(env, tree->refc), tail);
} else
return tail;
}
static ERL_NIF_TERM raise(ErlNifEnv *env, int err)
{
switch (err) {
case ENOMEM:
return enif_raise_exception(env, enif_make_atom(env, "enomem"));
default:
return enif_make_badarg(env);
}
}
void prep_path(char *path, ErlNifBinary *bin) {
int i;
unsigned char c;
path[bin->size] = 0;
for (i=0; i<bin->size; i++) {
c = bin->data[i];
path[i] = (c == '/') ? 0 : c;
}
}
/****************************************************************
* Constructors/Destructors *
****************************************************************/
static state_t *init_tree_state(ErlNifEnv *env) {
state_t *state = enif_alloc_resource(tree_state_t, sizeof(state_t));
if (state) {
memset(state, 0, sizeof(state_t));
state->tree = tree_new(NULL, 0);
state->lock = enif_rwlock_create("mqtree_lock");
if (state->tree && state->lock)
return state;
else
enif_release_resource(state);
}
return NULL;
}
static void destroy_tree_state(ErlNifEnv *env, void *data) {
state_t *state = (state_t *) data;
if (state) {
tree_free(state->tree);
if (state->lock) enif_rwlock_destroy(state->lock);
}
memset(state, 0, sizeof(state_t));
}
/****************************************************************
* NIF definitions *
****************************************************************/
static int load(ErlNifEnv* env, void** priv, ERL_NIF_TERM max) {
registry_lock = enif_rwlock_create("mqtree_registry");
if (registry_lock) {
ErlNifResourceFlags flags = ERL_NIF_RT_CREATE | ERL_NIF_RT_TAKEOVER;
tree_state_t = enif_open_resource_type(env, NULL, "mqtree_state",
destroy_tree_state,
flags, NULL);
return 0;
}
return ENOMEM;
}
static void unload(ErlNifEnv* env, void* priv) {
if (registry_lock) {
enif_rwlock_destroy(registry_lock);
registry_lock = NULL;
}
}
static ERL_NIF_TERM new_0(ErlNifEnv* env, int argc,
const ERL_NIF_TERM argv[])
{
ERL_NIF_TERM result;
state_t *state = init_tree_state(env);
if (state) {
result = enif_make_resource(env, state);
enif_release_resource(state);
} else
result = raise(env, ENOMEM);
return result;
}
static ERL_NIF_TERM insert_2(ErlNifEnv* env, int argc,
const ERL_NIF_TERM argv[])
{
state_t *state;
ErlNifBinary path_bin;
if (!enif_get_resource(env, argv[0], tree_state_t, (void *) &state) ||
!enif_inspect_iolist_as_binary(env, argv[1], &path_bin))
return raise(env, EINVAL);
if (!path_bin.size)
return enif_make_atom(env, "ok");
char path[path_bin.size+1];
prep_path(path, &path_bin);
enif_rwlock_rwlock(state->lock);
int ret = tree_add(state->tree, path, path_bin.size);
enif_rwlock_rwunlock(state->lock);
if (!ret)
return enif_make_atom(env, "ok");
else
return raise(env, ret);
}
static ERL_NIF_TERM delete_2(ErlNifEnv* env, int argc,
const ERL_NIF_TERM argv[])
{
state_t *state;
ErlNifBinary path_bin;
if (!enif_get_resource(env, argv[0], tree_state_t, (void *) &state) ||
!enif_inspect_iolist_as_binary(env, argv[1], &path_bin))
return raise(env, EINVAL);
if (!path_bin.size)
return enif_make_atom(env, "ok");
char path[path_bin.size+1];
prep_path(path, &path_bin);
enif_rwlock_rwlock(state->lock);
tree_del(state->tree, path, 0, path_bin.size);
enif_rwlock_rwunlock(state->lock);
return enif_make_atom(env, "ok");
}
static ERL_NIF_TERM match_2(ErlNifEnv* env, int argc,
const ERL_NIF_TERM argv[])
{
state_t *state;
ErlNifBinary path_bin;
ERL_NIF_TERM result = enif_make_list(env, 0);
if (!enif_get_resource(env, argv[0], tree_state_t, (void *) &state) ||
!enif_inspect_iolist_as_binary(env, argv[1], &path_bin))
return raise(env, EINVAL);
if (!path_bin.size)
return result;
char path[path_bin.size+1];
prep_path(path, &path_bin);
enif_rwlock_rlock(state->lock);
match(env, state->tree, path, 0, path_bin.size, &result);
enif_rwlock_runlock(state->lock);
return result;
}
static ERL_NIF_TERM refc_2(ErlNifEnv* env, int argc,
const ERL_NIF_TERM argv[])
{
state_t *state;
ErlNifBinary path_bin;
if (!enif_get_resource(env, argv[0], tree_state_t, (void *) &state) ||
!enif_inspect_iolist_as_binary(env, argv[1], &path_bin))
return raise(env, EINVAL);
if (!path_bin.size)
return enif_make_int(env, 0);
char path[path_bin.size+1];
prep_path(path, &path_bin);
enif_rwlock_rlock(state->lock);
int refc = tree_refc(state->tree, path, 0, path_bin.size);
enif_rwlock_runlock(state->lock);
return enif_make_int(env, refc);
}
static ERL_NIF_TERM clear_1(ErlNifEnv* env, int argc,
const ERL_NIF_TERM argv[])
{
state_t *state;
if (!enif_get_resource(env, argv[0], tree_state_t, (void *) &state))
return raise(env, EINVAL);
enif_rwlock_rwlock(state->lock);
tree_clear(state->tree);
enif_rwlock_rwunlock(state->lock);
return enif_make_atom(env, "ok");
}
static ERL_NIF_TERM size_1(ErlNifEnv* env, int argc,
const ERL_NIF_TERM argv[])
{
state_t *state;
size_t size = 0;
if (!enif_get_resource(env, argv[0], tree_state_t, (void *) &state))
return raise(env, EINVAL);
enif_rwlock_rlock(state->lock);
tree_size(state->tree, &size);
enif_rwlock_runlock(state->lock);
return enif_make_uint64(env, (ErlNifUInt64) size);
}
static ERL_NIF_TERM is_empty_1(ErlNifEnv* env, int argc,
const ERL_NIF_TERM argv[])
{
state_t *state;
if (!enif_get_resource(env, argv[0], tree_state_t, (void *) &state))
return raise(env, EINVAL);
enif_rwlock_rlock(state->lock);
char *ret = state->tree->sub ? "false" : "true";
enif_rwlock_runlock(state->lock);
return enif_make_atom(env, ret);
}
static ERL_NIF_TERM to_list_1(ErlNifEnv* env, int argc,
const ERL_NIF_TERM argv[])
{
state_t *state;
ERL_NIF_TERM result = enif_make_list(env, 0);
if (!enif_get_resource(env, argv[0], tree_state_t, (void *) &state))
return raise(env, EINVAL);
enif_rwlock_rlock(state->lock);
to_list(env, state->tree, &result);
enif_rwlock_runlock(state->lock);
return result;
}
static ERL_NIF_TERM dump_1(ErlNifEnv* env, int argc,
const ERL_NIF_TERM argv[])
{
state_t *state;
if (!enif_get_resource(env, argv[0], tree_state_t, (void *) &state))
return raise(env, EINVAL);
enif_rwlock_rlock(state->lock);
ERL_NIF_TERM result = dump(env, state->tree);
enif_rwlock_runlock(state->lock);
return result;
}
static ERL_NIF_TERM register_2(ErlNifEnv* env, int argc,
const ERL_NIF_TERM argv[])
{
state_t *state;
unsigned int len;
int ret;
if (!enif_get_atom_length(env, argv[0], &len, ERL_NIF_LATIN1) ||
!enif_get_resource(env, argv[1], tree_state_t, (void *) &state))
return raise(env, EINVAL);
char name[len+1];
enif_get_atom(env, argv[0], name, len+1, ERL_NIF_LATIN1);
if (!strcmp(name, "undefined"))
return raise(env, EINVAL);
ret = register_tree(name, state);
if (ret)
return raise(env, ret);
else
return enif_make_atom(env, "ok");
}
static ERL_NIF_TERM unregister_1(ErlNifEnv* env, int argc,
const ERL_NIF_TERM argv[])
{
unsigned int len;
int ret;
if (!enif_get_atom_length(env, argv[0], &len, ERL_NIF_LATIN1))
return raise(env, EINVAL);
char name[len+1];
enif_get_atom(env, argv[0], name, len+1, ERL_NIF_LATIN1);
ret = unregister_tree(name);
if (ret)
return raise(env, ret);
else
return enif_make_atom(env, "ok");
}
static ERL_NIF_TERM whereis_1(ErlNifEnv* env, int argc,
const ERL_NIF_TERM argv[])
{
unsigned int len;
registry_t *entry;
ERL_NIF_TERM result;
if (!enif_get_atom_length(env, argv[0], &len, ERL_NIF_LATIN1))
return raise(env, EINVAL);
char name[len+1];
enif_get_atom(env, argv[0], name, len+1, ERL_NIF_LATIN1);
enif_rwlock_rlock(registry_lock);
HASH_FIND_STR(registry, name, entry);
if (entry)
result = enif_make_resource(env, entry->state);
else
result = enif_make_atom(env, "undefined");
enif_rwlock_runlock(registry_lock);
return result;
}
static ERL_NIF_TERM registered_0(ErlNifEnv* env, int argc,
const ERL_NIF_TERM argv[])
{
registry_t *entry, *iter;
ERL_NIF_TERM result = enif_make_list(env, 0);
enif_rwlock_rlock(registry_lock);
HASH_ITER(hh, registry, entry, iter) {
result = enif_make_list_cell(env, enif_make_atom(env, entry->name), result);
}
enif_rwlock_runlock(registry_lock);
return result;
}
static ErlNifFunc nif_funcs[] =
{
{"new", 0, new_0},
{"insert", 2, insert_2},
{"delete", 2, delete_2},
{"match", 2, match_2},
{"refc", 2, refc_2},
{"clear", 1, clear_1},
{"size", 1, size_1},
{"is_empty", 1, is_empty_1},
{"to_list", 1, to_list_1},
{"dump", 1, dump_1},
{"register", 2, register_2},
{"unregister", 1, unregister_1},
{"whereis", 1, whereis_1},
{"registered", 0, registered_0}
};
ERL_NIF_INIT(mqtree, nif_funcs, load, NULL, NULL, unload)

+ 0
- 12
c_src/.mqtree/rebar.config View File

@ -1,12 +0,0 @@
{port_specs, [
{"../../priv/mqtree.so", ["*.c"]}
]}.
{port_env, [
{"CFLAGS", "$CFLAGS -std=c99 -g -O2 -Wall"},
{"LDFLAGS", "$LDFLAGS -lpthread"}
]}.

+ 0
- 1074
c_src/.mqtree/uthash.h
File diff suppressed because it is too large
View File


+ 0
- 80
c_src/bitmap_filter/bitmap_filter.c View File

@ -1,80 +0,0 @@
#include <erl_nif.h>
/*
This function expects a list of list of tuples of type {int, _}.
It filters the tuples, using the first int field as a key,
and removing duplicating keys with precedence given the the order
in which they were seen (first given precedence).
*/
static ERL_NIF_TERM
bitmap_filter(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
size_t seen_forklift_id[3000] = { 0 };
if(argc != 1)
{
return enif_make_badarg(env);
}
if(!enif_is_list(env, argv[0]))
{
return enif_make_badarg(env);
}
ERL_NIF_TERM ret = enif_make_list(env, 0);
ERL_NIF_TERM outer_list = argv[0];
ERL_NIF_TERM inner_list;
ERL_NIF_TERM inner_head;
const ERL_NIF_TERM* tuple_elems;
int num_elems;
unsigned int key;
while(enif_get_list_cell(env, outer_list, &inner_list, &outer_list))
{
if(!enif_is_list(env, inner_list))
{
return enif_make_badarg(env);
}
while(enif_get_list_cell(env, inner_list, &inner_head, &inner_list))
{
if(!enif_get_tuple(env, inner_head, &num_elems, &tuple_elems))
{
return enif_make_badarg(env);
}
if(num_elems != 2)
{
return enif_make_badarg(env);
}
if(!enif_get_uint(env, tuple_elems[0], &key))
{
return enif_make_badarg(env);
}
if(key >= 3000)
{
return enif_make_badarg(env);
}
if(!seen_forklift_id[key])
{
seen_forklift_id[key] = 1;
ret = enif_make_list_cell(env, inner_head, ret);
}
}
}
return ret;
}
static ErlNifFunc nif_funcs[] =
{
{"filter", 1, bitmap_filter, 0}
};
ERL_NIF_INIT(bitmap_filter, nif_funcs, NULL, NULL, NULL, NULL)

+ 0
- 30
c_src/bitmap_filter/rebar.config View File

@ -1,30 +0,0 @@
{port_specs, [
{"../../priv/bitmap_filter.so", [
"*.c"
]}
]}.
%{port_specs, [{"../../priv/granderl.so", []}]}.
%% {port_env, [
%% {"(linux|solaris|freebsd|netbsd|openbsd|dragonfly|darwin|gnu)",
%% "CFLAGS", "$CFLAGS -Ic_src/ -g -Wall -flto -Werror -O3"},
%% {"(linux|solaris|freebsd|netbsd|openbsd|dragonfly|darwin|gnu)",
%% "CXXFLAGS", "$CXXFLAGS -Ic_src/ -g -Wall -flto -Werror -O3"},
%%
%% {"(linux|solaris|freebsd|netbsd|openbsd|dragonfly|darwin|gnu)",
%% "LDFLAGS", "$LDFLAGS -flto -lstdc++"},
%%
%% %% OS X Leopard flags for 64-bit
%% {"darwin9.*-64$", "CXXFLAGS", "-m64"},
%% {"darwin9.*-64$", "LDFLAGS", "-arch x86_64"},
%%
%% %% OS X Snow Leopard flags for 32-bit
%% {"darwin10.*-32$", "CXXFLAGS", "-m32"},
%% {"darwin10.*-32$", "LDFLAGS", "-arch i386"},
%%
%% {"win32", "CXXFLAGS", "$CXXFLAGS /O2 /DNDEBUG"}
%% ]}.

+ 0
- 448
c_src/bsn/bsn_ext.c View File

@ -1,448 +0,0 @@
#include "erl_nif.h"
ErlNifResourceType* bsn_type;
ERL_NIF_TERM ATOM_TRUE, ATOM_FALSE;
/*
typedef struct {
unsigned size;
unsigned char* data;
} ErlNifBinary;
*/
struct bsn_elem_struct {
ErlNifBinary bin;
struct bsn_elem_struct* next;
};
typedef struct bsn_elem_struct bsn_elem;
typedef bsn_elem* bsn_list;
typedef struct {
unsigned int count; /* count of elements */
unsigned int max; /* count of slots */
ErlNifMutex *mutex;
bsn_list* list;
} bsn_res;
inline static ERL_NIF_TERM bool_to_term(int value) {
return value ? ATOM_TRUE : ATOM_FALSE;
}
/* Calculate the sum of chars. */
unsigned int
private_hash(const ErlNifBinary* b, unsigned int max)
{
unsigned char* ptr;
unsigned int i, sum = 0;
ptr = b->data;
i = b->size;
for (; i; i--, ptr++)
sum += *ptr;
return sum % max;
}
inline void
private_clear_elem(bsn_elem* el)
{
enif_release_binary(&(el->bin));
enif_free(el);
}
inline void
private_chain_clear_all(bsn_elem* ptr)
{
bsn_elem* next;
while (ptr != NULL) {
next = ptr->next;
private_clear_elem(ptr);
ptr = next;
}
}
inline int
private_compare(ErlNifBinary* b1, ErlNifBinary* b2)
{
unsigned char* p1;
unsigned char* p2;
unsigned len;
if (b1->size != b2->size)
return 0;
p1 = b1->data;
p2 = b2->data;
len = b1->size;
while (len) {
if ((*p1) != (*p2))
return 0;
len--; p1++; p2++;
}
return 1;
}
/* Skip existing elements. If the element bin is not found, return last element.
* If el.bin == bin, return el. */
bsn_elem*
private_chain_shift(bsn_elem* ptr, ErlNifBinary* bin, int* num_ptr)
{
(*num_ptr)++;
if ((ptr) == NULL)
return ptr;
while (1) {
if (private_compare(&(ptr->bin), bin)) {
/* found an equal binary. Invert num */
(*num_ptr) *= -1;
return ptr;
}
if ((ptr->next) == NULL)
return ptr;
ptr = ptr->next;
(*num_ptr)++;
}
}
/* Append the element `el' to the chain `chain' */
void
private_chain_append(bsn_elem** chain, bsn_elem* el, int* num_ptr)
{
bsn_elem* last;
if ((*chain) == NULL) {
/* The new element is last */
*chain = el;
} else {
last = private_chain_shift(*chain, &(el->bin), num_ptr);
if ((*num_ptr) < 0) {
/* Element was already added. */
private_clear_elem(el);
} else {
last->next = el;
}
}
}
bsn_elem*
private_chain_shift_clear(bsn_elem** ptr, ErlNifBinary* bin, int* num_ptr)
{
bsn_elem** prev = NULL;
bsn_elem* el;
while ((*ptr) != NULL) {
if (private_compare(&((*ptr)->bin), bin)) {
(*num_ptr) *= -1;
/* found an equal binary. Delete elem. Invert num */
if (prev == NULL) {
el = *ptr;
(*ptr) = (*ptr)->next;
return el;
}
*prev = (*ptr)->next;
return *ptr;
}
prev = ptr;
el = *ptr;
ptr = (bsn_elem**) &(el->next);
(*num_ptr)++;
}
return NULL;
}
static ERL_NIF_TERM
bsn_new(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
unsigned int max;
bsn_list* ptr;
bsn_res* r;
if (!(enif_get_uint(env, argv[0], &max) && (max>0)))
return enif_make_badarg(env);
ptr = enif_alloc(sizeof(bsn_list) * max);
if (ptr == NULL)
return enif_make_badarg(env);
r = (bsn_res*) enif_alloc_resource(bsn_type, sizeof(bsn_res));
r->mutex = enif_mutex_create("Mutex for the BSN writer");
r->count = 0;
r->max = max;
r->list = ptr;
for (; max; max--, ptr++)
*ptr = NULL;
return enif_make_resource(env, r);
}
static ERL_NIF_TERM
bsn_add(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
ErlNifBinary bin;
bsn_res* r;
unsigned int pos;
int num = 0;
bsn_elem* elem_ptr;
if (!(enif_get_resource(env, argv[0], bsn_type, (void**) &r)
&& enif_inspect_binary(env, argv[1], &bin)))
return enif_make_badarg(env);
enif_realloc_binary(&bin, bin.size);
pos = private_hash(&bin, r->max);
elem_ptr = enif_alloc(sizeof(bsn_elem));
if (elem_ptr == NULL)
return enif_make_badarg(env);
elem_ptr->next = NULL;
elem_ptr->bin = bin;
enif_mutex_lock(r->mutex);
private_chain_append(&(r->list[pos]), elem_ptr, &num);
if (num >= 0)
(r->count)++;
enif_mutex_unlock(r->mutex);
/* Already added */
if (num < 0)
enif_release_binary(&(bin));
return enif_make_int(env, num);
}
static ERL_NIF_TERM
bsn_search(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
ErlNifBinary bin;
bsn_res* r;
unsigned int pos;
int num = 0;
if (!(enif_get_resource(env, argv[0], bsn_type, (void**) &r)
&& enif_inspect_binary(env, argv[1], &bin)))
return enif_make_badarg(env);
pos = private_hash(&bin, r->max);
enif_mutex_lock(r->mutex);
private_chain_shift(r->list[pos], &bin, &num);
enif_mutex_unlock(r->mutex);
return enif_make_int(env, num);
}
static ERL_NIF_TERM
bsn_clear(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
ErlNifBinary bin;
bsn_res* r;
unsigned int pos;
int num = 0;
bsn_elem* elem_ptr;
if (!(enif_get_resource(env, argv[0], bsn_type, (void**) &r)
&& enif_inspect_binary(env, argv[1], &bin)))
return enif_make_badarg(env);
pos = private_hash(&bin, r->max);
enif_mutex_lock(r->mutex);
elem_ptr = private_chain_shift_clear(&(r->list[pos]), &bin, &num);
if (elem_ptr != NULL) {
private_clear_elem(elem_ptr);
(r->count)--;
}
enif_mutex_unlock(r->mutex);
return enif_make_int(env, num);
}
static ERL_NIF_TERM
bsn_all_chain(ErlNifEnv* env, bsn_elem* e, ERL_NIF_TERM tail)
{
ERL_NIF_TERM head;
ErlNifBinary bin;
while (e != NULL) {
bin = e->bin;
enif_realloc_binary(&bin, bin.size);
head = enif_make_binary(env, &bin);
tail = enif_make_list_cell(env, head, tail);
e = e->next;
}
return tail;
}
static ERL_NIF_TERM
bsn_chains(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
bsn_res* r;
unsigned int max;
bsn_list* ptr;
ERL_NIF_TERM tail, head;
if (!enif_get_resource(env, argv[0], bsn_type, (void**) &r))
return enif_make_badarg(env);
tail = enif_make_list(env, 0);
ptr = r->list;
enif_mutex_lock(r->mutex);
max = r->max;
while (max) {
head = enif_make_list(env, 0);
head = bsn_all_chain(env, *ptr, head);
tail = enif_make_list_cell(env, head, tail);
ptr++;
max--;
}
enif_mutex_unlock(r->mutex);
return tail;
}
static ERL_NIF_TERM
bsn_all(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
bsn_res* r;
unsigned int max;
bsn_list* ptr;
ERL_NIF_TERM list;
if (!enif_get_resource(env, argv[0], bsn_type, (void**) &r))
return enif_make_badarg(env);
list = enif_make_list(env, 0);
ptr = r->list;
enif_mutex_lock(r->mutex);
max = r->max;
while (max) {
list = bsn_all_chain(env, *ptr, list);
ptr++;
max--;
}
enif_mutex_unlock(r->mutex);
return list;
}
static ERL_NIF_TERM
bsn_count(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
bsn_res* r;
if (!enif_get_resource(env, argv[0], bsn_type, (void**) &r))
return enif_make_badarg(env);
return enif_make_int(env, r->count);
}
static ERL_NIF_TERM
bsn_hash(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
ErlNifBinary bin;
unsigned int max;
if (!(enif_inspect_binary(env, argv[0], &bin)
&& enif_get_uint(env, argv[1], &max) && (max>0)))
return enif_make_badarg(env);
return enif_make_uint(env,
private_hash(&bin, max));
}
static ERL_NIF_TERM
bsn_compare(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
ErlNifBinary b1, b2;
if (!(enif_inspect_binary(env, argv[0], &b1)
&& enif_inspect_binary(env, argv[1], &b2)))
return enif_make_badarg(env);
return bool_to_term(private_compare(&b1, &b2));
}
void private_clear_all(bsn_res* r)
{
unsigned int max;
bsn_list* ptr;
max = r->max;
ptr = r->list;
while (max) {
private_chain_clear_all(*ptr);
ptr++;
max--;
}
}
void
bsn_type_dtor(ErlNifEnv* env, void* obj)
{
bsn_res* r = (bsn_res*) obj;
private_clear_all(r);
enif_mutex_destroy(r->mutex);
enif_free(r->list);
}
int
on_load(ErlNifEnv* env, void** priv, ERL_NIF_TERM info)
{
ATOM_TRUE = enif_make_atom(env, "true");
ATOM_FALSE = enif_make_atom(env, "false");
ErlNifResourceFlags flags = (ErlNifResourceFlags)(ERL_NIF_RT_CREATE |
ERL_NIF_RT_TAKEOVER);
bsn_type = enif_open_resource_type(env, NULL, "bsn_type",
bsn_type_dtor, flags, NULL);
if (bsn_type == NULL) return 1;
return 0;
}
int
on_upgrade(ErlNifEnv* env, void** priv, void** old_priv, ERL_NIF_TERM info)
{
return 0;
}
static ErlNifFunc nif_functions[] = {
{"new", 1, bsn_new},
{"add", 2, bsn_add},
{"all", 1, bsn_all},
{"chains", 1, bsn_chains},
{"in", 2, bsn_search},
{"clear", 2, bsn_clear},
{"count", 1, bsn_count},
{"hash", 2, bsn_hash},
{"compare", 2, bsn_compare},
};
ERL_NIF_INIT(bsn_ext, nif_functions, &on_load, &on_load, &on_upgrade, NULL);

+ 0
- 331
c_src/bsn/bsn_int.c View File

@ -1,331 +0,0 @@
#include "erl_nif.h"
ErlNifResourceType* bsn_type;
ERL_NIF_TERM ATOM_TRUE, ATOM_FALSE, ATOM_NO_MORE;
struct bsn_elem_struct {
ErlNifBinary bin;
unsigned int hash;
};
typedef struct bsn_elem_struct bsn_elem;
typedef struct {
unsigned int count; /* count of elements */
unsigned int max; /* count of slots */
ErlNifMutex *mutex;
bsn_elem* list;
unsigned int (*next_pos)
(void*, unsigned int, unsigned int);
} bsn_res;
inline static ERL_NIF_TERM bool_to_term(int value) {
return value ? ATOM_TRUE : ATOM_FALSE;
}
unsigned int next_pos_linear(bsn_res* r, unsigned int hash, unsigned int step) {
return (hash + step) % (r->max);
}
unsigned int next_pos_quadric(bsn_res* r, unsigned int hash, unsigned int step) {
return (hash + (step*step)) % (r->max);
}
/* Calculate the sum of chars. */
unsigned int
private_hash(const ErlNifBinary* b, unsigned int max)
{
unsigned char* ptr;
unsigned int i, sum = 0;
ptr = b->data;
i = b->size;
for (; i; i--, ptr++)
sum += *ptr;
return sum % max;
}
inline int
private_compare(ErlNifBinary* b1, ErlNifBinary* b2)
{
unsigned char* p1;
unsigned char* p2;
unsigned len;
if (b1->size != b2->size)
return 0;
p1 = b1->data;
p2 = b2->data;
len = b1->size;
while (len) {
if ((*p1) != (*p2))
return 0;
len--; p1++; p2++;
}
return 1;
}
static ERL_NIF_TERM
bsn_new(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
int max; /* This value will be set by a client:
if (max<0) -> use quadric algorithm */
bsn_elem* ptr;
bsn_res* r;
if (!enif_get_int(env, argv[0], &max) || (max == 0))
return enif_make_badarg(env);
r = (bsn_res*) enif_alloc_resource(bsn_type, sizeof(bsn_res));
r->mutex = enif_mutex_create("Mutex for the BSN writer");
r->count = 0;
/* Select an algorithm */
if (max>0) {
r->next_pos = &next_pos_linear;
} else if (max<0) {
r->next_pos = &next_pos_quadric;
max *= -1;
}
/* Now max is cells' count in the array. */
r->max = (unsigned int) max;
ptr = enif_alloc(sizeof(bsn_elem) * max);
if (ptr == NULL)
return enif_make_badarg(env);
r->list = ptr;
for (; max; max--, ptr++)
ptr->hash = r->max;
return enif_make_resource(env, r);
}
static ERL_NIF_TERM
bsn_add(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
ErlNifBinary bin;
bsn_res* r;
unsigned int pos, hash, max;
int num = 0;
bsn_elem* elem_ptr;
if (!(enif_get_resource(env, argv[0], bsn_type, (void**) &r)
&& enif_inspect_binary(env, argv[1], &bin)))
return enif_make_badarg(env);
enif_realloc_binary(&bin, bin.size);
hash = pos = private_hash(&bin, r->max);
enif_mutex_lock(r->mutex);
max = r->max;
while (num < max) {
elem_ptr = &(r->list[pos]);
/* Found free space */
if (elem_ptr->hash == max) {
elem_ptr->bin = bin;
elem_ptr->hash = hash;
break;
}
/* Found elem */
if ((elem_ptr->hash == hash)
&& private_compare(&bin, &(elem_ptr->bin))) {
num *= -1;
break;
}
pos = (r->next_pos)(r, hash, num);
num++;
}
if ((num >= 0) && (num < max))
(r->count)++;
enif_mutex_unlock(r->mutex);
/* Error: already added or owerflow */
if (!((num >= 0) && (num < max)))
enif_release_binary(&bin);
if (num >= max)
return ATOM_NO_MORE;
return enif_make_int(env, num);
}
static ERL_NIF_TERM
bsn_search(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
ErlNifBinary bin;
bsn_res* r;
unsigned int pos, max, hash;
int num = 1;
bsn_elem* elem_ptr;
if (!(enif_get_resource(env, argv[0], bsn_type, (void**) &r)
&& enif_inspect_binary(env, argv[1], &bin)))
return enif_make_badarg(env);
hash = pos = private_hash(&bin, r->max);
enif_mutex_lock(r->mutex);
max = r->max;
while (num < max) {
elem_ptr = &(r->list[pos]);
/* Found free space */
if (elem_ptr->hash == max) {
break;
}
/* Found elem */
if ((elem_ptr->hash == hash)
&& private_compare(&bin, &(elem_ptr->bin))) {
num *= -1;
break;
}
pos = (r->next_pos)(r, hash, num);
num++;
}
enif_mutex_unlock(r->mutex);
return enif_make_int(env, num);
}
static ERL_NIF_TERM
bsn_clear(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
return enif_make_badarg(env);
}
static ERL_NIF_TERM
bsn_all(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
bsn_res* r;
unsigned int max, pos = 0;
ERL_NIF_TERM head, tail;
ErlNifBinary bin;
bsn_elem* elem_ptr;
if (!enif_get_resource(env, argv[0], bsn_type, (void**) &r))
return enif_make_badarg(env);
tail = enif_make_list(env, 0);
enif_mutex_lock(r->mutex);
max = r->max;
elem_ptr = r->list;
do {
if (elem_ptr->hash != max) {
bin = elem_ptr->bin;
enif_realloc_binary(&bin, bin.size);
head = enif_make_binary(env, &bin);
tail = enif_make_list_cell(env, head, tail);
}
elem_ptr++;
pos++;
} while (pos < max);
enif_mutex_unlock(r->mutex);
return tail;
}
static ERL_NIF_TERM
bsn_count(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
bsn_res* r;
if (!enif_get_resource(env, argv[0], bsn_type, (void**) &r))
return enif_make_badarg(env);
return enif_make_int(env, r->count);
}
void private_clear_all(bsn_res* r)
{
unsigned int max, num;
bsn_elem* ptr;
num = max = r->max;
ptr = r->list;
while (num) {
if (ptr->hash != max) {
enif_release_binary(&(ptr->bin));
}
ptr++;
num--;
}
}
void
bsn_type_dtor(ErlNifEnv* env, void* obj)
{
bsn_res* r = (bsn_res*) obj;
private_clear_all(r);
enif_mutex_destroy(r->mutex);
enif_free(r->list);
}
int
on_load(ErlNifEnv* env, void** priv, ERL_NIF_TERM info)
{
ATOM_TRUE = enif_make_atom(env, "true");
ATOM_FALSE = enif_make_atom(env, "false");
ATOM_NO_MORE = enif_make_atom(env, "no_more");
ErlNifResourceFlags flags = (ErlNifResourceFlags)(ERL_NIF_RT_CREATE |
ERL_NIF_RT_TAKEOVER);
bsn_type = enif_open_resource_type(env, NULL, "bsn_type",
bsn_type_dtor, flags, NULL);
if (bsn_type == NULL) return 1;
return 0;
}
int
on_upgrade(ErlNifEnv* env, void** priv, void** old_priv, ERL_NIF_TERM info)
{
return 0;
}
static ErlNifFunc nif_functions[] = {
{"new", 1, bsn_new},
{"add", 2, bsn_add},
{"all", 1, bsn_all},
{"in", 2, bsn_search},
{"clear", 2, bsn_clear},
{"count", 1, bsn_count},
};
ERL_NIF_INIT(bsn_int, nif_functions, &on_load, &on_load, &on_upgrade, NULL);

+ 0
- 448
c_src/bsn/c_src/bsn_ext.c View File

@ -1,448 +0,0 @@
#include "erl_nif.h"
ErlNifResourceType* bsn_type;
ERL_NIF_TERM ATOM_TRUE, ATOM_FALSE;
/*
typedef struct {
unsigned size;
unsigned char* data;
} ErlNifBinary;
*/
struct bsn_elem_struct {
ErlNifBinary bin;
struct bsn_elem_struct* next;
};
typedef struct bsn_elem_struct bsn_elem;
typedef bsn_elem* bsn_list;
typedef struct {
unsigned int count; /* count of elements */
unsigned int max; /* count of slots */
ErlNifMutex *mutex;
bsn_list* list;
} bsn_res;
inline static ERL_NIF_TERM bool_to_term(int value) {
return value ? ATOM_TRUE : ATOM_FALSE;
}
/* Calculate the sum of chars. */
unsigned int
private_hash(const ErlNifBinary* b, unsigned int max)
{
unsigned char* ptr;
unsigned int i, sum = 0;
ptr = b->data;
i = b->size;
for (; i; i--, ptr++)
sum += *ptr;
return sum % max;
}
inline void
private_clear_elem(bsn_elem* el)
{
enif_release_binary(&(el->bin));
enif_free(el);
}
inline void
private_chain_clear_all(bsn_elem* ptr)
{
bsn_elem* next;
while (ptr != NULL) {
next = ptr->next;
private_clear_elem(ptr);
ptr = next;
}
}
inline int
private_compare(ErlNifBinary* b1, ErlNifBinary* b2)
{
unsigned char* p1;
unsigned char* p2;
unsigned len;
if (b1->size != b2->size)
return 0;
p1 = b1->data;
p2 = b2->data;
len = b1->size;
while (len) {
if ((*p1) != (*p2))
return 0;
len--; p1++; p2++;
}
return 1;
}
/* Skip existing elements. If the element bin is not found, return last element.
* If el.bin == bin, return el. */
bsn_elem*
private_chain_shift(bsn_elem* ptr, ErlNifBinary* bin, int* num_ptr)
{
(*num_ptr)++;
if ((ptr) == NULL)
return ptr;
while (1) {
if (private_compare(&(ptr->bin), bin)) {
/* found an equal binary. Invert num */
(*num_ptr) *= -1;
return ptr;
}
if ((ptr->next) == NULL)
return ptr;
ptr = ptr->next;
(*num_ptr)++;
}
}
/* Append the element `el' to the chain `chain' */
void
private_chain_append(bsn_elem** chain, bsn_elem* el, int* num_ptr)
{
bsn_elem* last;
if ((*chain) == NULL) {
/* The new element is last */
*chain = el;
} else {
last = private_chain_shift(*chain, &(el->bin), num_ptr);
if ((*num_ptr) < 0) {
/* Element was already added. */
private_clear_elem(el);
} else {
last->next = el;
}
}
}
bsn_elem*
private_chain_shift_clear(bsn_elem** ptr, ErlNifBinary* bin, int* num_ptr)
{
bsn_elem** prev = NULL;
bsn_elem* el;
while ((*ptr) != NULL) {
if (private_compare(&((*ptr)->bin), bin)) {
(*num_ptr) *= -1;
/* found an equal binary. Delete elem. Invert num */
if (prev == NULL) {
el = *ptr;
(*ptr) = (*ptr)->next;
return el;
}
*prev = (*ptr)->next;
return *ptr;
}
prev = ptr;
el = *ptr;
ptr = (bsn_elem**) &(el->next);
(*num_ptr)++;
}
return NULL;
}
static ERL_NIF_TERM
bsn_new(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
unsigned int max;
bsn_list* ptr;
bsn_res* r;
if (!(enif_get_uint(env, argv[0], &max) && (max>0)))
return enif_make_badarg(env);
ptr = enif_alloc(sizeof(bsn_list) * max);
if (ptr == NULL)
return enif_make_badarg(env);
r = (bsn_res*) enif_alloc_resource(bsn_type, sizeof(bsn_res));
r->mutex = enif_mutex_create("Mutex for the BSN writer");
r->count = 0;
r->max = max;
r->list = ptr;
for (; max; max--, ptr++)
*ptr = NULL;
return enif_make_resource(env, r);
}
static ERL_NIF_TERM
bsn_add(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
ErlNifBinary bin;
bsn_res* r;
unsigned int pos;
int num = 0;
bsn_elem* elem_ptr;
if (!(enif_get_resource(env, argv[0], bsn_type, (void**) &r)
&& enif_inspect_binary(env, argv[1], &bin)))
return enif_make_badarg(env);
enif_realloc_binary(&bin, bin.size);
pos = private_hash(&bin, r->max);
elem_ptr = enif_alloc(sizeof(bsn_elem));
if (elem_ptr == NULL)
return enif_make_badarg(env);
elem_ptr->next = NULL;
elem_ptr->bin = bin;
enif_mutex_lock(r->mutex);
private_chain_append(&(r->list[pos]), elem_ptr, &num);
if (num >= 0)
(r->count)++;
enif_mutex_unlock(r->mutex);
/* Already added */
if (num < 0)
enif_release_binary(&(bin));
return enif_make_int(env, num);
}
static ERL_NIF_TERM
bsn_search(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
ErlNifBinary bin;
bsn_res* r;
unsigned int pos;
int num = 0;
if (!(enif_get_resource(env, argv[0], bsn_type, (void**) &r)
&& enif_inspect_binary(env, argv[1], &bin)))
return enif_make_badarg(env);
pos = private_hash(&bin, r->max);
enif_mutex_lock(r->mutex);
private_chain_shift(r->list[pos], &bin, &num);
enif_mutex_unlock(r->mutex);
return enif_make_int(env, num);
}
static ERL_NIF_TERM
bsn_clear(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
ErlNifBinary bin;
bsn_res* r;
unsigned int pos;
int num = 0;
bsn_elem* elem_ptr;
if (!(enif_get_resource(env, argv[0], bsn_type, (void**) &r)
&& enif_inspect_binary(env, argv[1], &bin)))
return enif_make_badarg(env);
pos = private_hash(&bin, r->max);
enif_mutex_lock(r->mutex);
elem_ptr = private_chain_shift_clear(&(r->list[pos]), &bin, &num);
if (elem_ptr != NULL) {
private_clear_elem(elem_ptr);
(r->count)--;
}
enif_mutex_unlock(r->mutex);
return enif_make_int(env, num);
}
static ERL_NIF_TERM
bsn_all_chain(ErlNifEnv* env, bsn_elem* e, ERL_NIF_TERM tail)
{
ERL_NIF_TERM head;
ErlNifBinary bin;
while (e != NULL) {
bin = e->bin;
enif_realloc_binary(&bin, bin.size);
head = enif_make_binary(env, &bin);
tail = enif_make_list_cell(env, head, tail);
e = e->next;
}
return tail;
}
static ERL_NIF_TERM
bsn_chains(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
bsn_res* r;
unsigned int max;
bsn_list* ptr;
ERL_NIF_TERM tail, head;
if (!enif_get_resource(env, argv[0], bsn_type, (void**) &r))
return enif_make_badarg(env);
tail = enif_make_list(env, 0);
ptr = r->list;
enif_mutex_lock(r->mutex);
max = r->max;
while (max) {
head = enif_make_list(env, 0);
head = bsn_all_chain(env, *ptr, head);
tail = enif_make_list_cell(env, head, tail);
ptr++;
max--;
}
enif_mutex_unlock(r->mutex);
return tail;
}
static ERL_NIF_TERM
bsn_all(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
bsn_res* r;
unsigned int max;
bsn_list* ptr;
ERL_NIF_TERM list;
if (!enif_get_resource(env, argv[0], bsn_type, (void**) &r))
return enif_make_badarg(env);
list = enif_make_list(env, 0);
ptr = r->list;
enif_mutex_lock(r->mutex);
max = r->max;
while (max) {
list = bsn_all_chain(env, *ptr, list);
ptr++;
max--;
}
enif_mutex_unlock(r->mutex);
return list;
}
static ERL_NIF_TERM
bsn_count(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
bsn_res* r;
if (!enif_get_resource(env, argv[0], bsn_type, (void**) &r))
return enif_make_badarg(env);
return enif_make_int(env, r->count);
}
static ERL_NIF_TERM
bsn_hash(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
ErlNifBinary bin;
unsigned int max;
if (!(enif_inspect_binary(env, argv[0], &bin)
&& enif_get_uint(env, argv[1], &max) && (max>0)))
return enif_make_badarg(env);
return enif_make_uint(env,
private_hash(&bin, max));
}
static ERL_NIF_TERM
bsn_compare(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
ErlNifBinary b1, b2;
if (!(enif_inspect_binary(env, argv[0], &b1)
&& enif_inspect_binary(env, argv[1], &b2)))
return enif_make_badarg(env);
return bool_to_term(private_compare(&b1, &b2));
}
void private_clear_all(bsn_res* r)
{
unsigned int max;
bsn_list* ptr;
max = r->max;
ptr = r->list;
while (max) {
private_chain_clear_all(*ptr);
ptr++;
max--;
}
}
void
bsn_type_dtor(ErlNifEnv* env, void* obj)
{
bsn_res* r = (bsn_res*) obj;
private_clear_all(r);
enif_mutex_destroy(r->mutex);
enif_free(r->list);
}
int
on_load(ErlNifEnv* env, void** priv, ERL_NIF_TERM info)
{
ATOM_TRUE = enif_make_atom(env, "true");
ATOM_FALSE = enif_make_atom(env, "false");
ErlNifResourceFlags flags = (ErlNifResourceFlags)(ERL_NIF_RT_CREATE |
ERL_NIF_RT_TAKEOVER);
bsn_type = enif_open_resource_type(env, NULL, "bsn_type",
bsn_type_dtor, flags, NULL);
if (bsn_type == NULL) return 1;
return 0;
}
int
on_upgrade(ErlNifEnv* env, void** priv, void** old_priv, ERL_NIF_TERM info)
{
return 0;
}
static ErlNifFunc nif_functions[] = {
{"new", 1, bsn_new},
{"add", 2, bsn_add},
{"all", 1, bsn_all},
{"chains", 1, bsn_chains},
{"in", 2, bsn_search},
{"clear", 2, bsn_clear},
{"count", 1, bsn_count},
{"hash", 2, bsn_hash},
{"compare", 2, bsn_compare},
};
ERL_NIF_INIT(bsn_ext, nif_functions, &on_load, &on_load, &on_upgrade, NULL);

+ 0
- 331
c_src/bsn/c_src/bsn_int.c View File

@ -1,331 +0,0 @@
#include "erl_nif.h"
ErlNifResourceType* bsn_type;
ERL_NIF_TERM ATOM_TRUE, ATOM_FALSE, ATOM_NO_MORE;
struct bsn_elem_struct {
ErlNifBinary bin;
unsigned int hash;
};
typedef struct bsn_elem_struct bsn_elem;
typedef struct {
unsigned int count; /* count of elements */
unsigned int max; /* count of slots */
ErlNifMutex *mutex;
bsn_elem* list;
unsigned int (*next_pos)
(void*, unsigned int, unsigned int);
} bsn_res;
inline static ERL_NIF_TERM bool_to_term(int value) {
return value ? ATOM_TRUE : ATOM_FALSE;
}
unsigned int next_pos_linear(bsn_res* r, unsigned int hash, unsigned int step) {
return (hash + step) % (r->max);
}
unsigned int next_pos_quadric(bsn_res* r, unsigned int hash, unsigned int step) {
return (hash + (step*step)) % (r->max);
}
/* Calculate the sum of chars. */
unsigned int
private_hash(const ErlNifBinary* b, unsigned int max)
{
unsigned char* ptr;
unsigned int i, sum = 0;
ptr = b->data;
i = b->size;
for (; i; i--, ptr++)
sum += *ptr;
return sum % max;
}
inline int
private_compare(ErlNifBinary* b1, ErlNifBinary* b2)
{
unsigned char* p1;
unsigned char* p2;
unsigned len;
if (b1->size != b2->size)
return 0;
p1 = b1->data;
p2 = b2->data;
len = b1->size;
while (len) {
if ((*p1) != (*p2))
return 0;
len--; p1++; p2++;
}
return 1;
}
static ERL_NIF_TERM
bsn_new(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
int max; /* This value will be set by a client:
if (max<0) -> use quadric algorithm */
bsn_elem* ptr;
bsn_res* r;
if (!enif_get_int(env, argv[0], &max) || (max == 0))
return enif_make_badarg(env);
r = (bsn_res*) enif_alloc_resource(bsn_type, sizeof(bsn_res));
r->mutex = enif_mutex_create("Mutex for the BSN writer");
r->count = 0;
/* Select an algorithm */
if (max>0) {
r->next_pos = &next_pos_linear;
} else if (max<0) {
r->next_pos = &next_pos_quadric;
max *= -1;
}
/* Now max is cells' count in the array. */
r->max = (unsigned int) max;
ptr = enif_alloc(sizeof(bsn_elem) * max);
if (ptr == NULL)
return enif_make_badarg(env);
r->list = ptr;
for (; max; max--, ptr++)
ptr->hash = r->max;
return enif_make_resource(env, r);
}
static ERL_NIF_TERM
bsn_add(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
ErlNifBinary bin;
bsn_res* r;
unsigned int pos, hash, max;
int num = 0;
bsn_elem* elem_ptr;
if (!(enif_get_resource(env, argv[0], bsn_type, (void**) &r)
&& enif_inspect_binary(env, argv[1], &bin)))
return enif_make_badarg(env);
enif_realloc_binary(&bin, bin.size);
hash = pos = private_hash(&bin, r->max);
enif_mutex_lock(r->mutex);
max = r->max;
while (num < max) {
elem_ptr = &(r->list[pos]);
/* Found free space */
if (elem_ptr->hash == max) {
elem_ptr->bin = bin;
elem_ptr->hash = hash;
break;
}
/* Found elem */
if ((elem_ptr->hash == hash)
&& private_compare(&bin, &(elem_ptr->bin))) {
num *= -1;
break;
}
pos = (r->next_pos)(r, hash, num);
num++;
}
if ((num >= 0) && (num < max))
(r->count)++;
enif_mutex_unlock(r->mutex);
/* Error: already added or owerflow */
if (!((num >= 0) && (num < max)))
enif_release_binary(&bin);
if (num >= max)
return ATOM_NO_MORE;
return enif_make_int(env, num);
}
static ERL_NIF_TERM
bsn_search(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
ErlNifBinary bin;
bsn_res* r;
unsigned int pos, max, hash;
int num = 1;
bsn_elem* elem_ptr;
if (!(enif_get_resource(env, argv[0], bsn_type, (void**) &r)
&& enif_inspect_binary(env, argv[1], &bin)))
return enif_make_badarg(env);
hash = pos = private_hash(&bin, r->max);
enif_mutex_lock(r->mutex);
max = r->max;
while (num < max) {
elem_ptr = &(r->list[pos]);
/* Found free space */
if (elem_ptr->hash == max) {
break;
}
/* Found elem */
if ((elem_ptr->hash == hash)
&& private_compare(&bin, &(elem_ptr->bin))) {
num *= -1;
break;
}
pos = (r->next_pos)(r, hash, num);
num++;
}
enif_mutex_unlock(r->mutex);
return enif_make_int(env, num);
}
static ERL_NIF_TERM
bsn_clear(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
return enif_make_badarg(env);
}
static ERL_NIF_TERM
bsn_all(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
bsn_res* r;
unsigned int max, pos = 0;
ERL_NIF_TERM head, tail;
ErlNifBinary bin;
bsn_elem* elem_ptr;
if (!enif_get_resource(env, argv[0], bsn_type, (void**) &r))
return enif_make_badarg(env);
tail = enif_make_list(env, 0);
enif_mutex_lock(r->mutex);
max = r->max;
elem_ptr = r->list;
do {
if (elem_ptr->hash != max) {
bin = elem_ptr->bin;
enif_realloc_binary(&bin, bin.size);
head = enif_make_binary(env, &bin);
tail = enif_make_list_cell(env, head, tail);
}
elem_ptr++;
pos++;
} while (pos < max);
enif_mutex_unlock(r->mutex);
return tail;
}
static ERL_NIF_TERM
bsn_count(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
bsn_res* r;
if (!enif_get_resource(env, argv[0], bsn_type, (void**) &r))
return enif_make_badarg(env);
return enif_make_int(env, r->count);
}
void private_clear_all(bsn_res* r)
{
unsigned int max, num;
bsn_elem* ptr;
num = max = r->max;
ptr = r->list;
while (num) {
if (ptr->hash != max) {
enif_release_binary(&(ptr->bin));
}
ptr++;
num--;
}
}
void
bsn_type_dtor(ErlNifEnv* env, void* obj)
{
bsn_res* r = (bsn_res*) obj;
private_clear_all(r);
enif_mutex_destroy(r->mutex);
enif_free(r->list);
}
int
on_load(ErlNifEnv* env, void** priv, ERL_NIF_TERM info)
{
ATOM_TRUE = enif_make_atom(env, "true");
ATOM_FALSE = enif_make_atom(env, "false");
ATOM_NO_MORE = enif_make_atom(env, "no_more");
ErlNifResourceFlags flags = (ErlNifResourceFlags)(ERL_NIF_RT_CREATE |
ERL_NIF_RT_TAKEOVER);
bsn_type = enif_open_resource_type(env, NULL, "bsn_type",
bsn_type_dtor, flags, NULL);
if (bsn_type == NULL) return 1;
return 0;
}
int
on_upgrade(ErlNifEnv* env, void** priv, void** old_priv, ERL_NIF_TERM info)
{
return 0;
}
static ErlNifFunc nif_functions[] = {
{"new", 1, bsn_new},
{"add", 2, bsn_add},
{"all", 1, bsn_all},
{"in", 2, bsn_search},
{"clear", 2, bsn_clear},
{"count", 1, bsn_count},
};
ERL_NIF_INIT(bsn_int, nif_functions, &on_load, &on_load, &on_upgrade, NULL);

+ 0
- 29
c_src/bsn/rebar.config View File

@ -1,29 +0,0 @@
{port_specs, [
{"../../priv/bsn_ext.so", ["bsn_ext.c"]},
{"../../priv/bsn_int.so", ["bsn_int.c"]}
]}.
%{port_specs, [{"../../priv/granderl.so", []}]}.
%% {port_env, [
%% {"(linux|solaris|freebsd|netbsd|openbsd|dragonfly|darwin|gnu)",
%% "CFLAGS", "$CFLAGS -Ic_src/ -g -Wall -flto -Werror -O3"},
%% {"(linux|solaris|freebsd|netbsd|openbsd|dragonfly|darwin|gnu)",
%% "CXXFLAGS", "$CXXFLAGS -Ic_src/ -g -Wall -flto -Werror -O3"},
%%
%% {"(linux|solaris|freebsd|netbsd|openbsd|dragonfly|darwin|gnu)",
%% "LDFLAGS", "$LDFLAGS -flto -lstdc++"},
%%
%% %% OS X Leopard flags for 64-bit
%% {"darwin9.*-64$", "CXXFLAGS", "-m64"},
%% {"darwin9.*-64$", "LDFLAGS", "-arch x86_64"},
%%
%% %% OS X Snow Leopard flags for 32-bit
%% {"darwin10.*-32$", "CXXFLAGS", "-m32"},
%% {"darwin10.*-32$", "LDFLAGS", "-arch i386"},
%%
%% {"win32", "CXXFLAGS", "$CXXFLAGS /O2 /DNDEBUG"}
%% ]}.

+ 0
- 843
c_src/couchdb-khash2/hash.c View File

@ -1,843 +0,0 @@
/*
* Hash Table Data Type
* Copyright (C) 1997 Kaz Kylheku <kaz@ashi.footprints.net>
*
* Free Software License:
*
* All rights are reserved by the author, with the following exceptions:
* Permission is granted to freely reproduce and distribute this software,
* possibly in exchange for a fee, provided that this copyright notice appears
* intact. Permission is also granted to adapt this software to produce
* derivative works, as long as the modified versions carry this copyright
* notice and additional notices stating that the work has been modified.
* This source code may be translated into executable form and incorporated
* into proprietary software; there is no requirement for such software to
* contain a copyright notice related to this source.
*
* $Id: hash.c,v 1.36.2.11 2000/11/13 01:36:45 kaz Exp $
* $Name: kazlib_1_20 $
*/
#include <stdlib.h>
#include <stddef.h>
#include <assert.h>
#include <string.h>
#define HASH_IMPLEMENTATION
#include "hash.h"
#ifdef KAZLIB_RCSID
static const char rcsid[] = "$Id: hash.c,v 1.36.2.11 2000/11/13 01:36:45 kaz Exp $";
#endif
#define INIT_BITS 6
#define INIT_SIZE (1UL << (INIT_BITS)) /* must be power of two */
#define INIT_MASK ((INIT_SIZE) - 1)
#define next hash_next
#define key hash_key
#define data hash_data
#define hkey hash_hkey
#define table hash_table
#define nchains hash_nchains
#define nodecount hash_nodecount
#define maxcount hash_maxcount
#define highmark hash_highmark
#define lowmark hash_lowmark
#define compare hash_compare
#define function hash_function
#define allocnode hash_allocnode
#define freenode hash_freenode
#define context hash_context
#define mask hash_mask
#define dynamic hash_dynamic
#define table hash_table
#define chain hash_chain
static hnode_t *kl_hnode_alloc(void *context);
static void kl_hnode_free(hnode_t *node, void *context);
static hash_val_t hash_fun_default(const void *key);
static int hash_comp_default(const void *key1, const void *key2);
int hash_val_t_bit;
/*
* Compute the number of bits in the hash_val_t type. We know that hash_val_t
* is an unsigned integral type. Thus the highest value it can hold is a
* Mersenne number (power of two, less one). We initialize a hash_val_t
* object with this value and then shift bits out one by one while counting.
* Notes:
* 1. HASH_VAL_T_MAX is a Mersenne number---one that is one less than a power
* of two. This means that its binary representation consists of all one
* bits, and hence ``val'' is initialized to all one bits.
* 2. While bits remain in val, we increment the bit count and shift it to the
* right, replacing the topmost bit by zero.
*/
static void compute_bits(void)
{
hash_val_t val = HASH_VAL_T_MAX; /* 1 */
int bits = 0;
while (val) { /* 2 */
bits++;
val >>= 1;
}
hash_val_t_bit = bits;
}
/*
* Verify whether the given argument is a power of two.
*/
static int is_power_of_two(hash_val_t arg)
{
if (arg == 0)
return 0;
while ((arg & 1) == 0)
arg >>= 1;
return (arg == 1);
}
/*
* Compute a shift amount from a given table size
*/
static hash_val_t compute_mask(hashcount_t size)
{
assert (is_power_of_two(size));
assert (size >= 2);
return size - 1;
}
/*
* Initialize the table of pointers to null.
*/
static void clear_table(hash_t *hash)
{
hash_val_t i;
for (i = 0; i < hash->nchains; i++)
hash->table[i] = NULL;
}
/*
* Double the size of a dynamic table. This works as follows. Each chain splits
* into two adjacent chains. The shift amount increases by one, exposing an
* additional bit of each hashed key. For each node in the original chain, the
* value of this newly exposed bit will decide which of the two new chains will
* receive the node: if the bit is 1, the chain with the higher index will have
* the node, otherwise the lower chain will receive the node. In this manner,
* the hash table will continue to function exactly as before without having to
* rehash any of the keys.
* Notes:
* 1. Overflow check.
* 2. The new number of chains is twice the old number of chains.
* 3. The new mask is one bit wider than the previous, revealing a
* new bit in all hashed keys.
* 4. Allocate a new table of chain pointers that is twice as large as the
* previous one.
* 5. If the reallocation was successful, we perform the rest of the growth
* algorithm, otherwise we do nothing.
* 6. The exposed_bit variable holds a mask with which each hashed key can be
* AND-ed to test the value of its newly exposed bit.
* 7. Now loop over each chain in the table and sort its nodes into two
* chains based on the value of each node's newly exposed hash bit.
* 8. The low chain replaces the current chain. The high chain goes
* into the corresponding sister chain in the upper half of the table.
* 9. We have finished dealing with the chains and nodes. We now update
* the various bookeeping fields of the hash structure.
*/
static void grow_table(hash_t *hash)
{
hnode_t **newtable;
assert (2 * hash->nchains > hash->nchains); /* 1 */
newtable = realloc(hash->table,
sizeof *newtable * hash->nchains * 2); /* 4 */
if (newtable) { /* 5 */
hash_val_t mask = (hash->mask << 1) | 1; /* 3 */
hash_val_t exposed_bit = mask ^ hash->mask; /* 6 */
hash_val_t chain;
assert (mask != hash->mask);
for (chain = 0; chain < hash->nchains; chain++) { /* 7 */
hnode_t *low_chain = 0, *high_chain = 0, *hptr, *next;
for (hptr = newtable[chain]; hptr != 0; hptr = next) {
next = hptr->next;
if (hptr->hkey & exposed_bit) {
hptr->next = high_chain;
high_chain = hptr;
} else {
hptr->next = low_chain;
low_chain = hptr;
}
}
newtable[chain] = low_chain; /* 8 */
newtable[chain + hash->nchains] = high_chain;
}
hash->table = newtable; /* 9 */
hash->mask = mask;
hash->nchains *= 2;
hash->lowmark *= 2;
hash->highmark *= 2;
}
assert (kl_hash_verify(hash));
}
/*
* Cut a table size in half. This is done by folding together adjacent chains
* and populating the lower half of the table with these chains. The chains are
* simply spliced together. Once this is done, the whole table is reallocated
* to a smaller object.
* Notes:
* 1. It is illegal to have a hash table with one slot. This would mean that
* hash->shift is equal to hash_val_t_bit, an illegal shift value.
* Also, other things could go wrong, such as hash->lowmark becoming zero.
* 2. Looping over each pair of sister chains, the low_chain is set to
* point to the head node of the chain in the lower half of the table,
* and high_chain points to the head node of the sister in the upper half.
* 3. The intent here is to compute a pointer to the last node of the
* lower chain into the low_tail variable. If this chain is empty,
* low_tail ends up with a null value.
* 4. If the lower chain is not empty, we simply tack the upper chain onto it.
* If the upper chain is a null pointer, nothing happens.
* 5. Otherwise if the lower chain is empty but the upper one is not,
* If the low chain is empty, but the high chain is not, then the
* high chain is simply transferred to the lower half of the table.
* 6. Otherwise if both chains are empty, there is nothing to do.
* 7. All the chain pointers are in the lower half of the table now, so
* we reallocate it to a smaller object. This, of course, invalidates
* all pointer-to-pointers which reference into the table from the
* first node of each chain.
* 8. Though it's unlikely, the reallocation may fail. In this case we
* pretend that the table _was_ reallocated to a smaller object.
* 9. Finally, update the various table parameters to reflect the new size.
*/
static void shrink_table(hash_t *hash)
{
hash_val_t chain, nchains;
hnode_t **newtable, *low_tail, *low_chain, *high_chain;
assert (hash->nchains >= 2); /* 1 */
nchains = hash->nchains / 2;
for (chain = 0; chain < nchains; chain++) {
low_chain = hash->table[chain]; /* 2 */
high_chain = hash->table[chain + nchains];
for (low_tail = low_chain; low_tail && low_tail->next; low_tail = low_tail->next)
; /* 3 */
if (low_chain != 0) /* 4 */
low_tail->next = high_chain;
else if (high_chain != 0) /* 5 */
hash->table[chain] = high_chain;
else
assert (hash->table[chain] == NULL); /* 6 */
}
newtable = realloc(hash->table,
sizeof *newtable * nchains); /* 7 */
if (newtable) /* 8 */
hash->table = newtable;
hash->mask >>= 1; /* 9 */
hash->nchains = nchains;
hash->lowmark /= 2;
hash->highmark /= 2;
assert (kl_hash_verify(hash));
}
/*
* Create a dynamic hash table. Both the hash table structure and the table
* itself are dynamically allocated. Furthermore, the table is extendible in
* that it will automatically grow as its load factor increases beyond a
* certain threshold.
* Notes:
* 1. If the number of bits in the hash_val_t type has not been computed yet,
* we do so here, because this is likely to be the first function that the
* user calls.
* 2. Allocate a hash table control structure.
* 3. If a hash table control structure is successfully allocated, we
* proceed to initialize it. Otherwise we return a null pointer.
* 4. We try to allocate the table of hash chains.
* 5. If we were able to allocate the hash chain table, we can finish
* initializing the hash structure and the table. Otherwise, we must
* backtrack by freeing the hash structure.
* 6. INIT_SIZE should be a power of two. The high and low marks are always set
* to be twice the table size and half the table size respectively. When the
* number of nodes in the table grows beyond the high size (beyond load
* factor 2), it will double in size to cut the load factor down to about
* about 1. If the table shrinks down to or beneath load factor 0.5,
* it will shrink, bringing the load up to about 1. However, the table
* will never shrink beneath INIT_SIZE even if it's emptied.
* 7. This indicates that the table is dynamically allocated and dynamically
* resized on the fly. A table that has this value set to zero is
* assumed to be statically allocated and will not be resized.
* 8. The table of chains must be properly reset to all null pointers.
*/
hash_t *kl_hash_create(hashcount_t maxcount, hash_comp_t compfun,
hash_fun_t hashfun)
{
hash_t *hash;
if (hash_val_t_bit == 0) /* 1 */
compute_bits();
hash = malloc(sizeof *hash); /* 2 */
if (hash) { /* 3 */
hash->table = malloc(sizeof *hash->table * INIT_SIZE); /* 4 */
if (hash->table) { /* 5 */
hash->nchains = INIT_SIZE; /* 6 */
hash->highmark = INIT_SIZE * 2;
hash->lowmark = INIT_SIZE / 2;
hash->nodecount = 0;
hash->maxcount = maxcount;
hash->compare = compfun ? compfun : hash_comp_default;
hash->function = hashfun ? hashfun : hash_fun_default;
hash->allocnode = kl_hnode_alloc;
hash->freenode = kl_hnode_free;
hash->context = NULL;
hash->mask = INIT_MASK;
hash->dynamic = 1; /* 7 */
clear_table(hash); /* 8 */
assert (kl_hash_verify(hash));
return hash;
}
free(hash);
}
return NULL;
}
/*
* Select a different set of node allocator routines.
*/
void kl_hash_set_allocator(hash_t *hash, hnode_alloc_t al,
hnode_free_t fr, void *context)
{
assert (kl_hash_count(hash) == 0);
assert ((al == 0 && fr == 0) || (al != 0 && fr != 0));
hash->allocnode = al ? al : kl_hnode_alloc;
hash->freenode = fr ? fr : kl_hnode_free;
hash->context = context;
}
/*
* Free every node in the hash using the hash->freenode() function pointer, and
* cause the hash to become empty.
*/
void kl_hash_free_nodes(hash_t *hash)
{
hscan_t hs;
hnode_t *node;
kl_hash_scan_begin(&hs, hash);
while ((node = kl_hash_scan_next(&hs))) {
kl_hash_scan_delete(hash, node);
hash->freenode(node, hash->context);
}
hash->nodecount = 0;
clear_table(hash);
}
/*
* Obsolescent function for removing all nodes from a table,
* freeing them and then freeing the table all in one step.
*/
void kl_hash_free(hash_t *hash)
{
#ifdef KAZLIB_OBSOLESCENT_DEBUG
assert ("call to obsolescent function hash_free()" && 0);
#endif
kl_hash_free_nodes(hash);
kl_hash_destroy(hash);
}
/*
* Free a dynamic hash table structure.
*/
void kl_hash_destroy(hash_t *hash)
{
assert (hash_val_t_bit != 0);
assert (kl_hash_isempty(hash));
free(hash->table);
free(hash);
}
/*
* Initialize a user supplied hash structure. The user also supplies a table of
* chains which is assigned to the hash structure. The table is static---it
* will not grow or shrink.
* 1. See note 1. in hash_create().
* 2. The user supplied array of pointers hopefully contains nchains nodes.
* 3. See note 7. in hash_create().
* 4. We must dynamically compute the mask from the given power of two table
* size.
* 5. The user supplied table can't be assumed to contain null pointers,
* so we reset it here.
*/
hash_t *kl_hash_init(hash_t *hash, hashcount_t maxcount,
hash_comp_t compfun, hash_fun_t hashfun, hnode_t **table,
hashcount_t nchains)
{
if (hash_val_t_bit == 0) /* 1 */
compute_bits();
assert (is_power_of_two(nchains));
hash->table = table; /* 2 */
hash->nchains = nchains;
hash->nodecount = 0;
hash->maxcount = maxcount;
hash->compare = compfun ? compfun : hash_comp_default;
hash->function = hashfun ? hashfun : hash_fun_default;
hash->dynamic = 0; /* 3 */
hash->mask = compute_mask(nchains); /* 4 */
clear_table(hash); /* 5 */
assert (kl_hash_verify(hash));
return hash;
}
/*
* Reset the hash scanner so that the next element retrieved by
* hash_scan_next() shall be the first element on the first non-empty chain.
* Notes:
* 1. Locate the first non empty chain.
* 2. If an empty chain is found, remember which one it is and set the next
* pointer to refer to its first element.
* 3. Otherwise if a chain is not found, set the next pointer to NULL
* so that hash_scan_next() shall indicate failure.
*/
void kl_hash_scan_begin(hscan_t *scan, hash_t *hash)
{
hash_val_t nchains = hash->nchains;
hash_val_t chain;
scan->table = hash;
/* 1 */
for (chain = 0; chain < nchains && hash->table[chain] == 0; chain++)
;
if (chain < nchains) { /* 2 */
scan->chain = chain;
scan->next = hash->table[chain];
} else { /* 3 */
scan->next = NULL;
}
}
/*
* Retrieve the next node from the hash table, and update the pointer
* for the next invocation of hash_scan_next().
* Notes:
* 1. Remember the next pointer in a temporary value so that it can be
* returned.
* 2. This assertion essentially checks whether the module has been properly
* initialized. The first point of interaction with the module should be
* either hash_create() or hash_init(), both of which set hash_val_t_bit to
* a non zero value.
* 3. If the next pointer we are returning is not NULL, then the user is
* allowed to call hash_scan_next() again. We prepare the new next pointer
* for that call right now. That way the user is allowed to delete the node
* we are about to return, since we will no longer be needing it to locate
* the next node.
* 4. If there is a next node in the chain (next->next), then that becomes the
* new next node, otherwise ...
* 5. We have exhausted the current chain, and must locate the next subsequent
* non-empty chain in the table.
* 6. If a non-empty chain is found, the first element of that chain becomes
* the new next node. Otherwise there is no new next node and we set the
* pointer to NULL so that the next time hash_scan_next() is called, a null
* pointer shall be immediately returned.
*/
hnode_t *kl_hash_scan_next(hscan_t *scan)
{
hnode_t *next = scan->next; /* 1 */
hash_t *hash = scan->table;
hash_val_t chain = scan->chain + 1;
hash_val_t nchains = hash->nchains;
assert (hash_val_t_bit != 0); /* 2 */
if (next) { /* 3 */
if (next->next) { /* 4 */
scan->next = next->next;
} else {
while (chain < nchains && hash->table[chain] == 0) /* 5 */
chain++;
if (chain < nchains) { /* 6 */
scan->chain = chain;
scan->next = hash->table[chain];
} else {
scan->next = NULL;
}
}
}
return next;
}
/*
* Insert a node into the hash table.
* Notes:
* 1. It's illegal to insert more than the maximum number of nodes. The client
* should verify that the hash table is not full before attempting an
* insertion.
* 2. The same key may not be inserted into a table twice.
* 3. If the table is dynamic and the load factor is already at >= 2,
* grow the table.
* 4. We take the bottom N bits of the hash value to derive the chain index,
* where N is the base 2 logarithm of the size of the hash table.
*/
void kl_hash_insert(hash_t *hash, hnode_t *node, const void *key)
{
hash_val_t hkey, chain;
assert (hash_val_t_bit != 0);
assert (node->next == NULL);
assert (hash->nodecount < hash->maxcount); /* 1 */
assert (kl_hash_lookup(hash, key) == NULL); /* 2 */
if (hash->dynamic && hash->nodecount >= hash->highmark) /* 3 */
grow_table(hash);
hkey = hash->function(key);
chain = hkey & hash->mask; /* 4 */
node->key = key;
node->hkey = hkey;
node->next = hash->table[chain];
hash->table[chain] = node;
hash->nodecount++;
assert (kl_hash_verify(hash));
}
/*
* Find a node in the hash table and return a pointer to it.
* Notes:
* 1. We hash the key and keep the entire hash value. As an optimization, when
* we descend down the chain, we can compare hash values first and only if
* hash values match do we perform a full key comparison.
* 2. To locate the chain from among 2^N chains, we look at the lower N bits of
* the hash value by anding them with the current mask.
* 3. Looping through the chain, we compare the stored hash value inside each
* node against our computed hash. If they match, then we do a full
* comparison between the unhashed keys. If these match, we have located the
* entry.
*/
hnode_t *kl_hash_lookup(hash_t *hash, const void *key)
{
hash_val_t hkey, chain;
hnode_t *nptr;
hkey = hash->function(key); /* 1 */
chain = hkey & hash->mask; /* 2 */
for (nptr = hash->table[chain]; nptr; nptr = nptr->next) { /* 3 */
if (nptr->hkey == hkey && hash->compare(nptr->key, key) == 0)
return nptr;
}
return NULL;
}
/*
* Delete the given node from the hash table. Since the chains
* are singly linked, we must locate the start of the node's chain
* and traverse.
* Notes:
* 1. The node must belong to this hash table, and its key must not have
* been tampered with.
* 2. If this deletion will take the node count below the low mark, we
* shrink the table now.
* 3. Determine which chain the node belongs to, and fetch the pointer
* to the first node in this chain.
* 4. If the node being deleted is the first node in the chain, then
* simply update the chain head pointer.
* 5. Otherwise advance to the node's predecessor, and splice out
* by updating the predecessor's next pointer.
* 6. Indicate that the node is no longer in a hash table.
*/
hnode_t *kl_hash_delete(hash_t *hash, hnode_t *node)
{
hash_val_t chain;
hnode_t *hptr;
assert (kl_hash_lookup(hash, node->key) == node); /* 1 */
assert (hash_val_t_bit != 0);
if (hash->dynamic && hash->nodecount <= hash->lowmark
&& hash->nodecount > INIT_SIZE)
shrink_table(hash); /* 2 */
chain = node->hkey & hash->mask; /* 3 */
hptr = hash->table[chain];
if (hptr == node) { /* 4 */
hash->table[chain] = node->next;
} else {
while (hptr->next != node) { /* 5 */
assert (hptr != 0);
hptr = hptr->next;
}
assert (hptr->next == node);
hptr->next = node->next;
}
hash->nodecount--;
assert (kl_hash_verify(hash));
node->next = NULL; /* 6 */
return node;
}
int kl_hash_alloc_insert(hash_t *hash, const void *key, void *data)
{
hnode_t *node = hash->allocnode(hash->context);
if (node) {
kl_hnode_init(node, data);
kl_hash_insert(hash, node, key);
return 1;
}
return 0;
}
void kl_hash_delete_free(hash_t *hash, hnode_t *node)
{
kl_hash_delete(hash, node);
hash->freenode(node, hash->context);
}
/*
* Exactly like hash_delete, except does not trigger table shrinkage. This is to be
* used from within a hash table scan operation. See notes for hash_delete.
*/
hnode_t *kl_hash_scan_delete(hash_t *hash, hnode_t *node)
{
hash_val_t chain;
hnode_t *hptr;
assert (kl_hash_lookup(hash, node->key) == node);
assert (hash_val_t_bit != 0);
chain = node->hkey & hash->mask;
hptr = hash->table[chain];
if (hptr == node) {
hash->table[chain] = node->next;
} else {
while (hptr->next != node)
hptr = hptr->next;
hptr->next = node->next;
}
hash->nodecount--;
assert (kl_hash_verify(hash));
node->next = NULL;
return node;
}
/*
* Like hash_delete_free but based on hash_scan_delete.
*/
void kl_hash_scan_delfree(hash_t *hash, hnode_t *node)
{
kl_hash_scan_delete(hash, node);
hash->freenode(node, hash->context);
}
/*
* Verify whether the given object is a valid hash table. This means
* Notes:
* 1. If the hash table is dynamic, verify whether the high and
* low expansion/shrinkage thresholds are powers of two.
* 2. Count all nodes in the table, and test each hash value
* to see whether it is correct for the node's chain.
*/
int kl_hash_verify(hash_t *hash)
{
hashcount_t count = 0;
hash_val_t chain;
hnode_t *hptr;
if (hash->dynamic) { /* 1 */
if (hash->lowmark >= hash->highmark)
return 0;
if (!is_power_of_two(hash->highmark))
return 0;
if (!is_power_of_two(hash->lowmark))
return 0;
}
for (chain = 0; chain < hash->nchains; chain++) { /* 2 */
for (hptr = hash->table[chain]; hptr != 0; hptr = hptr->next) {
if ((hptr->hkey & hash->mask) != chain)
return 0;
count++;
}
}
if (count != hash->nodecount)
return 0;
return 1;
}
/*
* Test whether the hash table is full and return 1 if this is true,
* 0 if it is false.
*/
#undef kl_hash_isfull
int kl_hash_isfull(hash_t *hash)
{
return hash->nodecount == hash->maxcount;
}
/*
* Test whether the hash table is empty and return 1 if this is true,
* 0 if it is false.
*/
#undef kl_hash_isempty
int kl_hash_isempty(hash_t *hash)
{
return hash->nodecount == 0;
}
static hnode_t *kl_hnode_alloc(void *context)
{
return malloc(sizeof *kl_hnode_alloc(NULL));
}
static void kl_hnode_free(hnode_t *node, void *context)
{
free(node);
}
/*
* Create a hash table node dynamically and assign it the given data.
*/
hnode_t *kl_hnode_create(void *data)
{
hnode_t *node = malloc(sizeof *node);
if (node) {
node->data = data;
node->next = NULL;
}
return node;
}
/*
* Initialize a client-supplied node
*/
hnode_t *kl_hnode_init(hnode_t *hnode, void *data)
{
hnode->data = data;
hnode->next = NULL;
return hnode;
}
/*
* Destroy a dynamically allocated node.
*/
void kl_hnode_destroy(hnode_t *hnode)
{
free(hnode);
}
#undef kl_hnode_put
void kl_hnode_put(hnode_t *node, void *data)
{
node->data = data;
}
#undef kl_hnode_get
void *kl_hnode_get(hnode_t *node)
{
return node->data;
}
#undef kl_hnode_getkey
const void *kl_hnode_getkey(hnode_t *node)
{
return node->key;
}
#undef kl_hash_count
hashcount_t kl_hash_count(hash_t *hash)
{
return hash->nodecount;
}
#undef kl_hash_size
hashcount_t kl_hash_size(hash_t *hash)
{
return hash->nchains;
}
static hash_val_t hash_fun_default(const void *key)
{
static unsigned long randbox[] = {
0x49848f1bU, 0xe6255dbaU, 0x36da5bdcU, 0x47bf94e9U,
0x8cbcce22U, 0x559fc06aU, 0xd268f536U, 0xe10af79aU,
0xc1af4d69U, 0x1d2917b5U, 0xec4c304dU, 0x9ee5016cU,
0x69232f74U, 0xfead7bb3U, 0xe9089ab6U, 0xf012f6aeU,
};
const unsigned char *str = key;
hash_val_t acc = 0;
while (*str) {
acc ^= randbox[(*str + acc) & 0xf];
acc = (acc << 1) | (acc >> 31);
acc &= 0xffffffffU;
acc ^= randbox[((*str++ >> 4) + acc) & 0xf];
acc = (acc << 2) | (acc >> 30);
acc &= 0xffffffffU;
}
return acc;
}
static int hash_comp_default(const void *key1, const void *key2)
{
return strcmp(key1, key2);
}

+ 0
- 240
c_src/couchdb-khash2/hash.h View File

@ -1,240 +0,0 @@
/*
* Hash Table Data Type
* Copyright (C) 1997 Kaz Kylheku <kaz@ashi.footprints.net>
*
* Free Software License:
*
* All rights are reserved by the author, with the following exceptions:
* Permission is granted to freely reproduce and distribute this software,
* possibly in exchange for a fee, provided that this copyright notice appears
* intact. Permission is also granted to adapt this software to produce
* derivative works, as long as the modified versions carry this copyright
* notice and additional notices stating that the work has been modified.
* This source code may be translated into executable form and incorporated
* into proprietary software; there is no requirement for such software to
* contain a copyright notice related to this source.
*
* $Id: hash.h,v 1.22.2.7 2000/11/13 01:36:45 kaz Exp $
* $Name: kazlib_1_20 $
*/
#ifndef HASH_H
#define HASH_H
#include <limits.h>
#ifdef KAZLIB_SIDEEFFECT_DEBUG
#include "sfx.h"
#endif
/*
* Blurb for inclusion into C++ translation units
*/
#ifdef __cplusplus
extern "C" {
#endif
typedef unsigned long hashcount_t;
#define HASHCOUNT_T_MAX ULONG_MAX
typedef unsigned long hash_val_t;
#define HASH_VAL_T_MAX ULONG_MAX
extern int hash_val_t_bit;
#ifndef HASH_VAL_T_BIT
#define HASH_VAL_T_BIT ((int) hash_val_t_bit)
#endif
/*
* Hash chain node structure.
* Notes:
* 1. This preprocessing directive is for debugging purposes. The effect is
* that if the preprocessor symbol KAZLIB_OPAQUE_DEBUG is defined prior to the
* inclusion of this header, then the structure shall be declared as having
* the single member int __OPAQUE__. This way, any attempts by the
* client code to violate the principles of information hiding (by accessing
* the structure directly) can be diagnosed at translation time. However,
* note the resulting compiled unit is not suitable for linking.
* 2. This is a pointer to the next node in the chain. In the last node of a
* chain, this pointer is null.
* 3. The key is a pointer to some user supplied data that contains a unique
* identifier for each hash node in a given table. The interpretation of
* the data is up to the user. When creating or initializing a hash table,
* the user must supply a pointer to a function for comparing two keys,
* and a pointer to a function for hashing a key into a numeric value.
* 4. The value is a user-supplied pointer to void which may refer to
* any data object. It is not interpreted in any way by the hashing
* module.
* 5. The hashed key is stored in each node so that we don't have to rehash
* each key when the table must grow or shrink.
*/
typedef struct hnode_t {
#if defined(HASH_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG) /* 1 */
struct hnode_t *hash_next; /* 2 */
const void *hash_key; /* 3 */
void *hash_data; /* 4 */
hash_val_t hash_hkey; /* 5 */
#else
int hash_dummy;
#endif
} hnode_t;
/*
* The comparison function pointer type. A comparison function takes two keys
* and produces a value of -1 if the left key is less than the right key, a
* value of 0 if the keys are equal, and a value of 1 if the left key is
* greater than the right key.
*/
typedef int (*hash_comp_t)(const void *, const void *);
/*
* The hashing function performs some computation on a key and produces an
* integral value of type hash_val_t based on that key. For best results, the
* function should have a good randomness properties in *all* significant bits
* over the set of keys that are being inserted into a given hash table. In
* particular, the most significant bits of hash_val_t are most significant to
* the hash module. Only as the hash table expands are less significant bits
* examined. Thus a function that has good distribution in its upper bits but
* not lower is preferrable to one that has poor distribution in the upper bits
* but not the lower ones.
*/
typedef hash_val_t (*hash_fun_t)(const void *);
/*
* allocator functions
*/
typedef hnode_t *(*hnode_alloc_t)(void *);
typedef void (*hnode_free_t)(hnode_t *, void *);
/*
* This is the hash table control structure. It keeps track of information
* about a hash table, as well as the hash table itself.
* Notes:
* 1. Pointer to the hash table proper. The table is an array of pointers to
* hash nodes (of type hnode_t). If the table is empty, every element of
* this table is a null pointer. A non-null entry points to the first
* element of a chain of nodes.
* 2. This member keeps track of the size of the hash table---that is, the
* number of chain pointers.
* 3. The count member maintains the number of elements that are presently
* in the hash table.
* 4. The maximum count is the greatest number of nodes that can populate this
* table. If the table contains this many nodes, no more can be inserted,
* and the hash_isfull() function returns true.
* 5. The high mark is a population threshold, measured as a number of nodes,
* which, if exceeded, will trigger a table expansion. Only dynamic hash
* tables are subject to this expansion.
* 6. The low mark is a minimum population threshold, measured as a number of
* nodes. If the table population drops below this value, a table shrinkage
* will occur. Only dynamic tables are subject to this reduction. No table
* will shrink beneath a certain absolute minimum number of nodes.
* 7. This is the a pointer to the hash table's comparison function. The
* function is set once at initialization or creation time.
* 8. Pointer to the table's hashing function, set once at creation or
* initialization time.
* 9. The current hash table mask. If the size of the hash table is 2^N,
* this value has its low N bits set to 1, and the others clear. It is used
* to select bits from the result of the hashing function to compute an
* index into the table.
* 10. A flag which indicates whether the table is to be dynamically resized. It
* is set to 1 in dynamically allocated tables, 0 in tables that are
* statically allocated.
*/
typedef struct hash_t {
#if defined(HASH_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG)
struct hnode_t **hash_table; /* 1 */
hashcount_t hash_nchains; /* 2 */
hashcount_t hash_nodecount; /* 3 */
hashcount_t hash_maxcount; /* 4 */
hashcount_t hash_highmark; /* 5 */
hashcount_t hash_lowmark; /* 6 */
hash_comp_t hash_compare; /* 7 */
hash_fun_t hash_function; /* 8 */
hnode_alloc_t hash_allocnode;
hnode_free_t hash_freenode;
void *hash_context;
hash_val_t hash_mask; /* 9 */
int hash_dynamic; /* 10 */
#else
int hash_dummy;
#endif
} hash_t;
/*
* Hash scanner structure, used for traversals of the data structure.
* Notes:
* 1. Pointer to the hash table that is being traversed.
* 2. Reference to the current chain in the table being traversed (the chain
* that contains the next node that shall be retrieved).
* 3. Pointer to the node that will be retrieved by the subsequent call to
* hash_scan_next().
*/
typedef struct hscan_t {
#if defined(HASH_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG)
hash_t *hash_table; /* 1 */
hash_val_t hash_chain; /* 2 */
hnode_t *hash_next; /* 3 */
#else
int hash_dummy;
#endif
} hscan_t;
extern hash_t *kl_hash_create(hashcount_t, hash_comp_t, hash_fun_t);
extern void kl_hash_set_allocator(hash_t *, hnode_alloc_t, hnode_free_t, void *);
extern void kl_hash_destroy(hash_t *);
extern void kl_hash_free_nodes(hash_t *);
extern void kl_hash_free(hash_t *);
extern hash_t *kl_hash_init(hash_t *, hashcount_t, hash_comp_t,
hash_fun_t, hnode_t **, hashcount_t);
extern void kl_hash_insert(hash_t *, hnode_t *, const void *);
extern hnode_t *kl_hash_lookup(hash_t *, const void *);
extern hnode_t *kl_hash_delete(hash_t *, hnode_t *);
extern int kl_hash_alloc_insert(hash_t *, const void *, void *);
extern void kl_hash_delete_free(hash_t *, hnode_t *);
extern void kl_hnode_put(hnode_t *, void *);
extern void *kl_hnode_get(hnode_t *);
extern const void *kl_hnode_getkey(hnode_t *);
extern hashcount_t kl_hash_count(hash_t *);
extern hashcount_t kl_hash_size(hash_t *);
extern int kl_hash_isfull(hash_t *);
extern int kl_hash_isempty(hash_t *);
extern void kl_hash_scan_begin(hscan_t *, hash_t *);
extern hnode_t *kl_hash_scan_next(hscan_t *);
extern hnode_t *kl_hash_scan_delete(hash_t *, hnode_t *);
extern void kl_hash_scan_delfree(hash_t *, hnode_t *);
extern int kl_hash_verify(hash_t *);
extern hnode_t *kl_hnode_create(void *);
extern hnode_t *kl_hnode_init(hnode_t *, void *);
extern void kl_hnode_destroy(hnode_t *);
#if defined(HASH_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG)
#ifdef KAZLIB_SIDEEFFECT_DEBUG
#define kl_hash_isfull(H) (SFX_CHECK(H)->hash_nodecount == (H)->hash_maxcount)
#else
#define kl_hash_isfull(H) ((H)->hash_nodecount == (H)->hash_maxcount)
#endif
#define kl_hash_isempty(H) ((H)->hash_nodecount == 0)
#define kl_hash_count(H) ((H)->hash_nodecount)
#define kl_hash_size(H) ((H)->hash_nchains)
#define kl_hnode_get(N) ((N)->hash_data)
#define kl_hnode_getkey(N) ((N)->hash_key)
#define kl_hnode_put(N, V) ((N)->hash_data = (V))
#endif
#ifdef __cplusplus
}
#endif
#endif

+ 0
- 658
c_src/couchdb-khash2/khash.c View File

@ -1,658 +0,0 @@
// This file is part of khash released under the MIT license.
// See the LICENSE file for more information.
// Copyright 2013 Cloudant, Inc <support@cloudant.com>
#include <assert.h>
#include <string.h>
#include <stdint.h>
#include "erl_nif.h"
#include "hash.h"
#ifdef _WIN32
#define INLINE __inline
#else
#define INLINE inline
#endif
#define KHASH_VERSION 0
typedef struct
{
ERL_NIF_TERM atom_ok;
ERL_NIF_TERM atom_error;
ERL_NIF_TERM atom_value;
ERL_NIF_TERM atom_not_found;
ERL_NIF_TERM atom_end_of_table;
ERL_NIF_TERM atom_expired_iterator;
ErlNifResourceType* res_hash;
ErlNifResourceType* res_iter;
} khash_priv;
typedef struct
{
unsigned int hval;
ErlNifEnv* env;
ERL_NIF_TERM key;
ERL_NIF_TERM val;
} khnode_t;
typedef struct
{
int version;
unsigned int gen;
hash_t* h;
ErlNifPid p;
} khash_t;
typedef struct
{
int version;
unsigned int gen;
khash_t* khash;
hscan_t scan;
} khash_iter_t;
static INLINE ERL_NIF_TERM
make_atom(ErlNifEnv* env, const char* name)
{
ERL_NIF_TERM ret;
if(enif_make_existing_atom(env, name, &ret, ERL_NIF_LATIN1)) {
return ret;
}
return enif_make_atom(env, name);
}
static INLINE ERL_NIF_TERM
make_ok(ErlNifEnv* env, khash_priv* priv, ERL_NIF_TERM value)
{
return enif_make_tuple2(env, priv->atom_ok, value);
}
static INLINE ERL_NIF_TERM
make_error(ErlNifEnv* env, khash_priv* priv, ERL_NIF_TERM reason)
{
return enif_make_tuple2(env, priv->atom_error, reason);
}
static INLINE int
check_pid(ErlNifEnv* env, khash_t* khash)
{
ErlNifPid pid;
enif_self(env, &pid);
if(enif_compare(pid.pid, khash->p.pid) == 0) {
return 1;
}
return 0;
}
hnode_t*
khnode_alloc(void* ctx)
{
hnode_t* ret = (hnode_t*) enif_alloc(sizeof(hnode_t));
khnode_t* node = (khnode_t*) enif_alloc(sizeof(khnode_t));
memset(ret, '\0', sizeof(hnode_t));
memset(node, '\0', sizeof(khnode_t));
node->env = enif_alloc_env();
ret->hash_key = node;
return ret;
}
void
khnode_free(hnode_t* obj, void* ctx)
{
khnode_t* node = (khnode_t*) kl_hnode_getkey(obj);
enif_free_env(node->env);
enif_free(node);
enif_free(obj);
return;
}
int
khash_cmp_fun(const void* l, const void* r)
{
khnode_t* left = (khnode_t*) l;
khnode_t* right = (khnode_t*) r;
int cmp = enif_compare(left->key, right->key);
if(cmp < 0) {
return -1;
} else if(cmp == 0) {
return 0;
} else {
return 1;
}
}
hash_val_t
khash_hash_fun(const void* obj)
{
khnode_t* node = (khnode_t*) obj;
return (hash_val_t) node->hval;
}
static INLINE khash_t*
khash_create_int(ErlNifEnv* env, khash_priv* priv, ERL_NIF_TERM opts)
{
khash_t* khash = NULL;
assert(priv != NULL && "missing private data member");
khash = (khash_t*) enif_alloc_resource(priv->res_hash, sizeof(khash_t));
memset(khash, '\0', sizeof(khash_t));
khash->version = KHASH_VERSION;
khash->gen = 0;
khash->h = kl_hash_create(HASHCOUNT_T_MAX, khash_cmp_fun, khash_hash_fun);
if(khash->h == NULL ) {
enif_release_resource(khash);
return NULL;
}
kl_hash_set_allocator(khash->h, khnode_alloc, khnode_free, NULL);
enif_self(env, &(khash->p));
return khash;
}
static ERL_NIF_TERM
khash_new(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
khash_priv* priv = enif_priv_data(env);
khash_t* khash;
ERL_NIF_TERM ret;
if(argc != 1) {
return enif_make_badarg(env);
}
khash = khash_create_int(env, priv, argv[0]);
if(khash == NULL) {
return enif_make_badarg(env);
}
ret = enif_make_resource(env, khash);
enif_release_resource(khash);
return make_ok(env, priv, ret);
}
static void
khash_free(ErlNifEnv* env, void* obj)
{
khash_t* khash = (khash_t*) obj;
if(khash->h != NULL) {
kl_hash_free_nodes(khash->h);
kl_hash_destroy(khash->h);
}
return;
}
static ERL_NIF_TERM
khash_to_list(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
khash_priv* priv = (khash_priv*) enif_priv_data(env);
ERL_NIF_TERM ret = enif_make_list(env, 0);
khash_t* khash = NULL;
void* res = NULL;
hscan_t scan;
hnode_t* entry;
khnode_t* node;
ERL_NIF_TERM key;
ERL_NIF_TERM val;
ERL_NIF_TERM tuple;
if(argc != 1) {
return enif_make_badarg(env);
}
if(!enif_get_resource(env, argv[0], priv->res_hash, &res)) {
return enif_make_badarg(env);
}
khash = (khash_t*) res;
if(!check_pid(env, khash)) {
return enif_make_badarg(env);
}
kl_hash_scan_begin(&scan, khash->h);
while((entry = kl_hash_scan_next(&scan)) != NULL) {
node = (khnode_t*) kl_hnode_getkey(entry);
key = enif_make_copy(env, node->key);
val = enif_make_copy(env, node->val);
tuple = enif_make_tuple2(env, key, val);
ret = enif_make_list_cell(env, tuple, ret);
}
return ret;
}
static ERL_NIF_TERM
khash_clear(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
khash_priv* priv = enif_priv_data(env);
khash_t* khash = NULL;
void* res = NULL;
if(argc != 1) {
return enif_make_badarg(env);
}
if(!enif_get_resource(env, argv[0], priv->res_hash, &res)) {
return enif_make_badarg(env);
}
khash = (khash_t*) res;
if(!check_pid(env, khash)) {
return enif_make_badarg(env);
}
kl_hash_free_nodes(khash->h);
khash->gen += 1;
return priv->atom_ok;
}
static INLINE hnode_t*
khash_lookup_int(ErlNifEnv* env, uint32_t hv, ERL_NIF_TERM key, khash_t* khash)
{
khnode_t node;
node.hval = hv;
node.env = env;
node.key = key;
return kl_hash_lookup(khash->h, &node);
}
static ERL_NIF_TERM
khash_lookup(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
khash_priv* priv = enif_priv_data(env);
khash_t* khash = NULL;
void* res = NULL;
uint32_t hval;
hnode_t* entry;
khnode_t* node;
ERL_NIF_TERM ret;
if(argc != 3) {
return enif_make_badarg(env);
}
if(!enif_get_resource(env, argv[0], priv->res_hash, &res)) {
return enif_make_badarg(env);
}
khash = (khash_t*) res;
if(!check_pid(env, khash)) {
return enif_make_badarg(env);
}
if(!enif_get_uint(env, argv[1], &hval)) {
return enif_make_badarg(env);
}
entry = khash_lookup_int(env, hval, argv[2], khash);
if(entry == NULL) {
ret = priv->atom_not_found;
} else {
node = (khnode_t*) kl_hnode_getkey(entry);
ret = enif_make_copy(env, node->val);
ret = enif_make_tuple2(env, priv->atom_value, ret);
}
return ret;
}
static ERL_NIF_TERM
khash_get(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
khash_priv* priv = enif_priv_data(env);
khash_t* khash = NULL;
void* res = NULL;
uint32_t hval;
hnode_t* entry;
khnode_t* node;
ERL_NIF_TERM ret;
if(argc != 4) {
return enif_make_badarg(env);
}
if(!enif_get_resource(env, argv[0], priv->res_hash, &res)) {
return enif_make_badarg(env);
}
khash = (khash_t*) res;
if(!check_pid(env, khash)) {
return enif_make_badarg(env);
}
if(!enif_get_uint(env, argv[1], &hval)) {
return enif_make_badarg(env);
}
entry = khash_lookup_int(env, hval, argv[2], khash);
if(entry == NULL) {
ret = argv[3];
} else {
node = (khnode_t*) kl_hnode_getkey(entry);
ret = enif_make_copy(env, node->val);
}
return ret;
}
static ERL_NIF_TERM
khash_put(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
khash_priv* priv = enif_priv_data(env);
khash_t* khash = NULL;
void* res = NULL;
uint32_t hval;
hnode_t* entry;
khnode_t* node;
if(argc != 4) {
return enif_make_badarg(env);
}
if(!enif_get_resource(env, argv[0], priv->res_hash, &res)) {
return enif_make_badarg(env);
}
khash = (khash_t*) res;
if(!check_pid(env, khash)) {
return enif_make_badarg(env);
}
if(!enif_get_uint(env, argv[1], &hval)) {
return enif_make_badarg(env);
}
entry = khash_lookup_int(env, hval, argv[2], khash);
if(entry == NULL) {
entry = khnode_alloc(NULL);
node = (khnode_t*) kl_hnode_getkey(entry);
node->hval = hval;
node->key = enif_make_copy(node->env, argv[2]);
node->val = enif_make_copy(node->env, argv[3]);
kl_hash_insert(khash->h, entry, node);
} else {
node = (khnode_t*) kl_hnode_getkey(entry);
enif_clear_env(node->env);
node->key = enif_make_copy(node->env, argv[2]);
node->val = enif_make_copy(node->env, argv[3]);
}
khash->gen += 1;
return priv->atom_ok;
}
static ERL_NIF_TERM
khash_del(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
khash_priv* priv = enif_priv_data(env);
khash_t* khash = NULL;
void* res = NULL;
uint32_t hval;
hnode_t* entry;
ERL_NIF_TERM ret;
if(argc != 3) {
return enif_make_badarg(env);
}
if(!enif_get_resource(env, argv[0], priv->res_hash, &res)) {
return enif_make_badarg(env);
}
khash = (khash_t*) res;
if(!check_pid(env, khash)) {
return enif_make_badarg(env);
}
if(!enif_get_uint(env, argv[1], &hval)) {
return enif_make_badarg(env);
}
entry = khash_lookup_int(env, hval, argv[2], khash);
if(entry == NULL) {
ret = priv->atom_not_found;
} else {
kl_hash_delete_free(khash->h, entry);
ret = priv->atom_ok;
}
khash->gen += 1;
return ret;
}
static ERL_NIF_TERM
khash_size(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
khash_priv* priv = enif_priv_data(env);
khash_t* khash;
if(argc != 1) {
return enif_make_badarg(env);
}
if(!enif_get_resource(env, argv[0], priv->res_hash, (void*) &khash)) {
return enif_make_badarg(env);
}
if(!check_pid(env, khash)) {
return enif_make_badarg(env);
}
return enif_make_uint64(env, kl_hash_count(khash->h));
}
static ERL_NIF_TERM
khash_iter(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
khash_priv* priv = enif_priv_data(env);
khash_t* khash = NULL;
void* res = NULL;
khash_iter_t* iter;
ERL_NIF_TERM ret;
if(argc != 1) {
return enif_make_badarg(env);
}
if(!enif_get_resource(env, argv[0], priv->res_hash, &res)) {
return enif_make_badarg(env);
}
khash = (khash_t*) res;
if(!check_pid(env, khash)) {
return enif_make_badarg(env);
}
iter = (khash_iter_t*) enif_alloc_resource(
priv->res_iter, sizeof(khash_iter_t));
memset(iter, '\0', sizeof(khash_iter_t));
iter->version = KHASH_VERSION;
iter->gen = khash->gen;
iter->khash = khash;
kl_hash_scan_begin(&(iter->scan), iter->khash->h);
// The iterator needs to guarantee that the khash
// remains alive for the life of the iterator.
enif_keep_resource(khash);
ret = enif_make_resource(env, iter);
enif_release_resource(iter);
return make_ok(env, priv, ret);
}
static void
khash_iter_free(ErlNifEnv* env, void* obj)
{
khash_iter_t* iter = (khash_iter_t*) obj;
enif_release_resource(iter->khash);
}
static ERL_NIF_TERM
khash_iter_next(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
khash_priv* priv = enif_priv_data(env);
khash_iter_t* iter = NULL;
void* res = NULL;
hnode_t* entry;
khnode_t* node;
ERL_NIF_TERM key;
ERL_NIF_TERM val;
if(argc != 1) {
return enif_make_badarg(env);
}
if(!enif_get_resource(env, argv[0], priv->res_iter, &res)) {
return enif_make_badarg(env);
}
iter = (khash_iter_t*) res;
if(!check_pid(env, iter->khash)) {
return enif_make_badarg(env);
}
if(iter->gen != iter->khash->gen) {
return make_error(env, priv, priv->atom_expired_iterator);
}
entry = kl_hash_scan_next(&(iter->scan));
if(entry == NULL) {
return priv->atom_end_of_table;
}
node = (khnode_t*) kl_hnode_getkey(entry);
key = enif_make_copy(env, node->key);
val = enif_make_copy(env, node->val);
return enif_make_tuple2(env, key, val);
}
static int
load(ErlNifEnv* env, void** priv, ERL_NIF_TERM info)
{
int flags = ERL_NIF_RT_CREATE | ERL_NIF_RT_TAKEOVER;
ErlNifResourceType* res;
khash_priv* new_priv = (khash_priv*) enif_alloc(sizeof(khash_priv));
if(new_priv == NULL) {
return 1;
}
res = enif_open_resource_type(
env, NULL, "khash", khash_free, flags, NULL);
if(res == NULL) {
return 1;
}
new_priv->res_hash = res;
res = enif_open_resource_type(
env, NULL, "khash_iter", khash_iter_free, flags, NULL);
if(res == NULL) {
return 1;
}
new_priv->res_iter = res;
new_priv->atom_ok = make_atom(env, "ok");
new_priv->atom_error = make_atom(env, "error");
new_priv->atom_value = make_atom(env, "value");
new_priv->atom_not_found = make_atom(env, "not_found");
new_priv->atom_end_of_table = make_atom(env, "end_of_table");
new_priv->atom_expired_iterator = make_atom(env, "expired_iterator");
*priv = (void*) new_priv;
return 0;
}
static int
reload(ErlNifEnv* env, void** priv, ERL_NIF_TERM info)
{
return 0;
}
static int
upgrade(ErlNifEnv* env, void** priv, void** old_priv, ERL_NIF_TERM info)
{
return load(env, priv, info);
}
static void
unload(ErlNifEnv* env, void* priv)
{
enif_free(priv);
return;
}
static ErlNifFunc funcs[] = {
{"new", 1, khash_new},
{"to_list", 1, khash_to_list},
{"clear", 1, khash_clear},
{"lookup_int", 3, khash_lookup},
{"get_int", 4, khash_get},
{"put_int", 4, khash_put},
{"del_int", 3, khash_del},
{"size", 1, khash_size},
{"iter", 1, khash_iter},
{"iter_next", 1, khash_iter_next}
};
ERL_NIF_INIT(khash, funcs, &load, &reload, &upgrade, &unload);

+ 0
- 12
c_src/couchdb-khash2/rebar.config View File

@ -1,12 +0,0 @@
{port_specs, [
{"../../priv/khash2.so", ["*.c"]}
]}.
{port_env, [
% Development compilation
% {".*", "CFLAGS", "$CFLAGS -g -Wall -Werror -fPIC"}
% Production compilation
{"(linux|solaris|darwin|freebsd)", "CFLAGS", "$CFLAGS -Wall -Werror -DNDEBUG -O3"},
{"win32", "CFLAGS", "$CFLAGS /O2 /DNDEBUG /Wall"}
]}.

+ 0
- 80
c_src/enlfq/Makefile View File

@ -1,80 +0,0 @@
PROJECT = enlfq
CXXFLAGS = -std=c++11 -O2 -Wextra -Werror -Wno-missing-field-initializers -fno-rtti -fno-exceptions
LDLIBS = -lstdc++
# Based on c_src.mk from erlang.mk by Loic Hoguin <essen@ninenines.eu>
CURDIR := $(shell pwd)
BASEDIR := $(abspath $(CURDIR)/..)
PROJECT ?= $(notdir $(BASEDIR))
PROJECT := $(strip $(PROJECT))
ERTS_INCLUDE_DIR ?= $(shell erl -noshell -s init stop -eval "io:format(\"~ts/erts-~ts/include/\", [code:root_dir(), erlang:system_info(version)]).")
ERL_INTERFACE_INCLUDE_DIR ?= $(shell erl -noshell -s init stop -eval "io:format(\"~ts\", [code:lib_dir(erl_interface, include)]).")
ERL_INTERFACE_LIB_DIR ?= $(shell erl -noshell -s init stop -eval "io:format(\"~ts\", [code:lib_dir(erl_interface, lib)]).")
C_SRC_DIR = $(CURDIR)
C_SRC_OUTPUT ?= $(CURDIR)/../priv/$(PROJECT).so
# System type and C compiler/flags.
UNAME_SYS := $(shell uname -s)
ifeq ($(UNAME_SYS), Darwin)
CC ?= cc
CFLAGS ?= -O3 -std=c99 -arch x86_64 -finline-functions -Wall -Wmissing-prototypes
CXXFLAGS ?= -O3 -arch x86_64 -finline-functions -Wall
LDFLAGS ?= -arch x86_64 -flat_namespace -undefined suppress
else ifeq ($(UNAME_SYS), FreeBSD)
CC ?= cc
CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes
CXXFLAGS ?= -O3 -finline-functions -Wall
else ifeq ($(UNAME_SYS), Linux)
CC ?= gcc
CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes
CXXFLAGS ?= -O3 -finline-functions -Wall
endif
CFLAGS += -fPIC -I $(ERTS_INCLUDE_DIR) -I $(ERL_INTERFACE_INCLUDE_DIR)
CXXFLAGS += -fPIC -I $(ERTS_INCLUDE_DIR) -I $(ERL_INTERFACE_INCLUDE_DIR)
LDLIBS += -L $(ERL_INTERFACE_LIB_DIR) -lerl_interface -lei
LDFLAGS += -shared
# Verbosity.
c_verbose_0 = @echo " C " $(?F);
c_verbose = $(c_verbose_$(V))
cpp_verbose_0 = @echo " CPP " $(?F);
cpp_verbose = $(cpp_verbose_$(V))
link_verbose_0 = @echo " LD " $(@F);
link_verbose = $(link_verbose_$(V))
SOURCES := $(shell find $(C_SRC_DIR) -type f \( -name "*.c" -o -name "*.C" -o -name "*.cc" -o -name "*.cpp" \))
OBJECTS = $(addsuffix .o, $(basename $(SOURCES)))
COMPILE_C = $(c_verbose) $(CC) $(CFLAGS) $(CPPFLAGS) -c
COMPILE_CPP = $(cpp_verbose) $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c
$(C_SRC_OUTPUT): $(OBJECTS)
@mkdir -p $(BASEDIR)/priv/
$(link_verbose) $(CC) $(OBJECTS) $(LDFLAGS) $(LDLIBS) -o $(C_SRC_OUTPUT)
%.o: %.c
$(COMPILE_C) $(OUTPUT_OPTION) $<
%.o: %.cc
$(COMPILE_CPP) $(OUTPUT_OPTION) $<
%.o: %.C
$(COMPILE_CPP) $(OUTPUT_OPTION) $<
%.o: %.cpp
$(COMPILE_CPP) $(OUTPUT_OPTION) $<
clean:
@rm -f $(C_SRC_OUTPUT) $(OBJECTS)

+ 0
- 3637
c_src/enlfq/concurrentqueue.h
File diff suppressed because it is too large
View File


+ 0
- 84
c_src/enlfq/enlfq.cc View File

@ -1,84 +0,0 @@
#include "enlfq.h"
#include "enlfq_nif.h"
#include "nif_utils.h"
#include "concurrentqueue.h"
struct q_item {
ErlNifEnv *env;
ERL_NIF_TERM term;
};
struct squeue {
moodycamel::ConcurrentQueue<q_item> *queue;
};
void nif_enlfq_free(ErlNifEnv *, void *obj) {
squeue *inst = static_cast<squeue *>(obj);
if (inst != nullptr) {
q_item item;
while (inst->queue->try_dequeue(item)) {
enif_free_env(item.env);
}
delete inst->queue;
}
}
ERL_NIF_TERM nif_enlfq_new(ErlNifEnv *env, int, const ERL_NIF_TERM *) {
shared_data *data = static_cast<shared_data *>(enif_priv_data(env));
squeue *qinst = static_cast<squeue *>(enif_alloc_resource(data->resQueueInstance, sizeof(squeue)));
qinst->queue = new moodycamel::ConcurrentQueue<q_item>;
if (qinst == NULL)
return make_error(env, "enif_alloc_resource failed");
ERL_NIF_TERM term = enif_make_resource(env, qinst);
enif_release_resource(qinst);
return enif_make_tuple2(env, ATOMS.atomOk, term);
}
ERL_NIF_TERM nif_enlfq_push(ErlNifEnv *env, int, const ERL_NIF_TERM argv[]) {
shared_data *data = static_cast<shared_data *>(enif_priv_data(env));
squeue *inst;
if (!enif_get_resource(env, argv[0], data->resQueueInstance, (void **) &inst)) {
return enif_make_badarg(env);
}
q_item item;
item.env = enif_alloc_env();
item.term = enif_make_copy(item.env, argv[1]);
inst->queue->enqueue(item);
return ATOMS.atomTrue;
}
ERL_NIF_TERM nif_enlfq_pop(ErlNifEnv *env, int, const ERL_NIF_TERM argv[]) {
shared_data *data = static_cast<shared_data *>(enif_priv_data(env));
squeue *inst = NULL;
if (!enif_get_resource(env, argv[0], data->resQueueInstance, (void **) &inst)) {
return enif_make_badarg(env);
}
ERL_NIF_TERM term;
q_item item;
if (inst->queue->try_dequeue(item)) {
term = enif_make_copy(env, item.term);
enif_free_env(item.env);
return enif_make_tuple2(env, ATOMS.atomOk, term);
} else {
return ATOMS.atomEmpty;
}
}

+ 0
- 10
c_src/enlfq/enlfq.h View File

@ -1,10 +0,0 @@
#pragma once
#include "erl_nif.h"
extern "C" {
void nif_enlfq_free(ErlNifEnv *env, void *obj);
ERL_NIF_TERM nif_enlfq_new(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]);
ERL_NIF_TERM nif_enlfq_push(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]);
ERL_NIF_TERM nif_enlfq_pop(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]);
}

+ 0
- 57
c_src/enlfq/enlfq_nif.cc View File

@ -1,57 +0,0 @@
#include <string.h>
#include "enlfq_nif.h"
#include "enlfq.h"
#include "nif_utils.h"
const char kAtomOk[] = "ok";
const char kAtomError[] = "error";
const char kAtomTrue[] = "true";
//const char kAtomFalse[] = "false";
//const char kAtomUndefined[] = "undefined";
const char kAtomEmpty[] = "empty";
atoms ATOMS;
void open_resources(ErlNifEnv *env, shared_data *data) {
ErlNifResourceFlags flags = static_cast<ErlNifResourceFlags>(ERL_NIF_RT_CREATE | ERL_NIF_RT_TAKEOVER);
data->resQueueInstance = enif_open_resource_type(env, NULL, "enlfq_instance", nif_enlfq_free, flags, NULL);
}
int on_nif_load(ErlNifEnv *env, void **priv_data, ERL_NIF_TERM) {
ATOMS.atomOk = make_atom(env, kAtomOk);
ATOMS.atomError = make_atom(env, kAtomError);
ATOMS.atomTrue = make_atom(env, kAtomTrue);
// ATOMS.atomFalse = make_atom(env, kAtomFalse);
// ATOMS.atomUndefined = make_atom(env, kAtomUndefined);
ATOMS.atomEmpty = make_atom(env, kAtomEmpty);
shared_data *data = static_cast<shared_data *>(enif_alloc(sizeof(shared_data)));
open_resources(env, data);
*priv_data = data;
return 0;
}
void on_nif_unload(ErlNifEnv *, void *priv_data) {
shared_data *data = static_cast<shared_data *>(priv_data);
enif_free(data);
}
int on_nif_upgrade(ErlNifEnv *env, void **priv, void **, ERL_NIF_TERM) {
shared_data *data = static_cast<shared_data *>(enif_alloc(sizeof(shared_data)));
open_resources(env, data);
*priv = data;
return 0;
}
static ErlNifFunc nif_funcs[] =
{
{"new", 0, nif_enlfq_new},
{"push", 2, nif_enlfq_push},
{"pop", 1, nif_enlfq_pop}
};
ERL_NIF_INIT(enlfq, nif_funcs, on_nif_load, NULL, on_nif_upgrade, on_nif_unload)

+ 0
- 19
c_src/enlfq/enlfq_nif.h View File

@ -1,19 +0,0 @@
#pragma once
#include "erl_nif.h"
struct atoms
{
ERL_NIF_TERM atomOk;
ERL_NIF_TERM atomError;
ERL_NIF_TERM atomTrue;
// ERL_NIF_TERM atomFalse;
// ERL_NIF_TERM atomUndefined;
ERL_NIF_TERM atomEmpty;
};
struct shared_data
{
ErlNifResourceType* resQueueInstance;
};
extern atoms ATOMS;

+ 0
- 27
c_src/enlfq/nif_utils.cc View File

@ -1,27 +0,0 @@
#include "nif_utils.h"
#include "enlfq_nif.h"
#include <string.h>
ERL_NIF_TERM make_atom(ErlNifEnv* env, const char* name)
{
ERL_NIF_TERM ret;
if(enif_make_existing_atom(env, name, &ret, ERL_NIF_LATIN1))
return ret;
return enif_make_atom(env, name);
}
ERL_NIF_TERM make_binary(ErlNifEnv* env, const char* buff, size_t length)
{
ERL_NIF_TERM term;
unsigned char *destination_buffer = enif_make_new_binary(env, length, &term);
memcpy(destination_buffer, buff, length);
return term;
}
ERL_NIF_TERM make_error(ErlNifEnv* env, const char* error)
{
return enif_make_tuple2(env, ATOMS.atomError, make_binary(env, error, strlen(error)));
}

+ 0
- 6
c_src/enlfq/nif_utils.h View File

@ -1,6 +0,0 @@
#pragma once
#include "erl_nif.h"
ERL_NIF_TERM make_atom(ErlNifEnv* env, const char* name);
ERL_NIF_TERM make_error(ErlNifEnv* env, const char* error);
ERL_NIF_TERM make_binary(ErlNifEnv* env, const char* buff, size_t length);

+ 0
- 7
c_src/enlfq/rebar.config View File

@ -1,7 +0,0 @@
{port_specs, [
{"../../priv/enlfq.so", ["*.cc"]}
]}.

+ 0
- 172
c_src/etsq/etsq.cpp View File

@ -1,172 +0,0 @@
#include "etsq.h"
ErlNifRWLock *qinfo_map_rwlock;
QInfoMap qinfo_map;
// Function finds the queue from map and returns QueueInfo
// Not thread safe.
QueueInfo* get_q_info(char* name)
{
//std::cout<<"Info: "<< name<<std::endl;
QInfoMap::iterator iter = qinfo_map.find(name);
if (iter != qinfo_map.end())
{
//std::cout<<" Fetched ";
return iter->second;
}
return NULL;
}
void new_q(char* name)
{
//std::cout<<"Create: " << name<<std::endl;
WriteLock write_lock(qinfo_map_rwlock);
QueueInfo *queue_info = new QueueInfo(name);
qinfo_map.insert(QInfoMapPair(name, queue_info));
//std::cout<<"Created: " << name<<std::endl;
}
bool push(char* name, ErlTerm *erl_term)
{
QueueInfo *pqueue_info = NULL;
ReadLock read_lock(qinfo_map_rwlock);
if (NULL != (pqueue_info = get_q_info(name)))
{
Mutex mutex(pqueue_info->pmutex);
pqueue_info->queue.push(erl_term);
return true;
}
return false;
}
// Returns new ErlTerm. Caller should delete it
ErlTerm* pop(char* name, bool read_only)
{
QueueInfo *pqueue_info = NULL;
ReadLock read_lock(qinfo_map_rwlock);
if (NULL != (pqueue_info = get_q_info(name)))
{
Mutex mutex(pqueue_info->pmutex);
if (!pqueue_info->queue.empty())
{
ErlTerm *erl_term = pqueue_info->queue.front();
if(read_only)
{
return new ErlTerm(erl_term);
}
pqueue_info->queue.pop();
return erl_term;
}
return new ErlTerm("empty");
}
return NULL;
}
static ERL_NIF_TERM new_queue(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
int size = 100;
char *name = new char(size);
enif_get_atom(env, argv[0], name, size, ERL_NIF_LATIN1);
{
QueueInfo *pqueue_info = NULL;
ReadLock read_lock(qinfo_map_rwlock);
if (NULL != (pqueue_info = get_q_info(name)))
{
return enif_make_error(env, "already_exists");
}
}
new_q(name);
return enif_make_atom(env, "ok");
}
static ERL_NIF_TERM info(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
int size = 100;
char name[100];
enif_get_atom(env, argv[0], name, size, ERL_NIF_LATIN1);
int queue_size = 0;
{
QueueInfo *pqueue_info = NULL;
ReadLock read_lock(qinfo_map_rwlock);
if (NULL == (pqueue_info = get_q_info(name)))
return enif_make_badarg(env);
queue_size = pqueue_info->queue.size();
}
return enif_make_list2(env,
enif_make_tuple2(env, enif_make_atom(env, "name"), enif_make_atom(env, name)),
enif_make_tuple2(env, enif_make_atom(env, "size"), enif_make_int(env, queue_size)));
}
static ERL_NIF_TERM push_back(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
int size = 100;
char name[100];
enif_get_atom(env, argv[0], name, size, ERL_NIF_LATIN1);
ErlTerm *erl_term = new ErlTerm(argv[1]);
if (push(name, erl_term))
return enif_make_atom(env, "ok");
delete erl_term;
return enif_make_badarg(env);
}
static ERL_NIF_TERM pop_front(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
int size = 100;
char name[100];
enif_get_atom(env, argv[0], name, size, ERL_NIF_LATIN1);
ErlTerm *erl_term = NULL;
if (NULL == (erl_term = pop(name, false)))
return enif_make_badarg(env);
ERL_NIF_TERM return_term = enif_make_copy(env, erl_term->term);
delete erl_term;
return return_term;
}
static ERL_NIF_TERM get_front(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
int size = 100;
char name[100];
enif_get_atom(env, argv[0], name, size, ERL_NIF_LATIN1);
ErlTerm *erl_term = NULL;
if (NULL == (erl_term = pop(name, true)))
return enif_make_badarg(env);
ERL_NIF_TERM return_term = enif_make_copy(env, erl_term->term);
delete erl_term;
return return_term;
}
static int is_ok_load_info(ErlNifEnv* env, ERL_NIF_TERM load_info)
{
int i;
return enif_get_int(env, load_info, &i) && i == 1;
}
static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
{
if (!is_ok_load_info(env, load_info))
return -1;
qinfo_map_rwlock = enif_rwlock_create((char*)"qinfo");
return 0;
}
static int upgrade(ErlNifEnv* env, void** priv_data, void** old_priv_data, ERL_NIF_TERM load_info)
{
if (!is_ok_load_info(env, load_info))
return -1;
return 0;
}
static void unload(ErlNifEnv* env, void* priv_data)
{
enif_rwlock_destroy(qinfo_map_rwlock);
}
static ErlNifFunc nif_funcs[] = {
{"new", 1, new_queue},
{"info", 1, info},
{"push_back", 2, push_back},
{"pop_front", 1, pop_front},
{"get_front", 1, get_front}
};
ERL_NIF_INIT(etsq, nif_funcs, load, NULL, upgrade, unload)

+ 0
- 130
c_src/etsq/etsq.h View File

@ -1,130 +0,0 @@
/*
* etsq.h
*
* Created on: Mar 21, 2016
* Author: Vinod
*/
#ifndef ETSQ_H_
#define ETSQ_H_
#include <iostream> // std::cin, std::cout
#include <map> // std::map
#include <queue> // std::queue
#include <string.h>
#include "erl_nif.h"
#define enif_make_error(env, error) enif_make_tuple2(env, \
enif_make_atom(env, "error"), enif_make_atom(env, error))
struct cmp_str
{
bool operator()(char *a, char *b) const
{
return strcmp(a, b) < 0;
}
};
class ErlTerm
{
public:
ErlNifEnv *term_env;
ERL_NIF_TERM term;
public:
ErlTerm(ERL_NIF_TERM erl_nif_term)
{
term_env = enif_alloc_env();
this->term = enif_make_copy(term_env, erl_nif_term);
}
ErlTerm(ErlTerm *erl_term)
{
term_env = enif_alloc_env();
this->term = enif_make_copy(term_env, erl_term->term);
}
ErlTerm(int value)
{
term_env = enif_alloc_env();
this->term = enif_make_int(term_env, value);
}
ErlTerm(const char *error)
{
term_env = enif_alloc_env();
this->term = enif_make_error(term_env, error);
}
~ErlTerm()
{
enif_free_env(term_env);
term_env = NULL;
}
};
typedef std::queue<ErlTerm*> ErlQueue;
class QueueInfo
{
public:
ErlNifMutex* pmutex;
ErlQueue queue;
public:
QueueInfo(char* name)
{
pmutex = enif_mutex_create(name);
}
~QueueInfo()
{
enif_mutex_destroy(pmutex);
}
};
typedef std::map<char *, QueueInfo*, cmp_str> QInfoMap;
typedef std::pair<char *, QueueInfo*> QInfoMapPair;
// Class to handle Read lock
class ReadLock
{
ErlNifRWLock *pread_lock;
public:
ReadLock(ErlNifRWLock *pread_lock)
{
this->pread_lock = pread_lock;
enif_rwlock_rlock(this->pread_lock);
};
~ReadLock()
{
enif_rwlock_runlock(pread_lock);
};
};
// Class to handle Write lock
class WriteLock
{
ErlNifRWLock *pwrite_lock;
public:
WriteLock(ErlNifRWLock *pwrite_lock)
{
this->pwrite_lock = pwrite_lock;
enif_rwlock_rwlock(this->pwrite_lock);
};
~WriteLock()
{
enif_rwlock_rwunlock(pwrite_lock);
};
};
// Class to handle Mutex lock and unlock
class Mutex
{
ErlNifMutex *pmtx;
public:
Mutex(ErlNifMutex *pmtx)
{
this->pmtx = pmtx;
enif_mutex_lock(this->pmtx);
};
~Mutex()
{
enif_mutex_unlock(pmtx);
};
};
#endif /* ETSQ_H_ */

+ 0
- 7
c_src/etsq/rebar.config View File

@ -1,7 +0,0 @@
{port_specs, [
{"../../priv/etsq.so", ["*.cpp"]}
]}.

+ 0
- 103
c_src/gb_lru/binary.h View File

@ -1,103 +0,0 @@
#include <iostream>
#include <algorithm>
#include <string.h>
class Binary {
public:
unsigned char *bin;
size_t size;
bool allocated;
Binary() : bin(NULL), size(0), allocated(false) { }
Binary(const char *data) {
bin = (unsigned char *) data;
size = strlen(data);
allocated = false;
}
Binary(const Binary &b) {
bin = b.bin;
size = b.size;
allocated = false;
}
~Binary() {
if (allocated) {
delete bin;
}
}
operator std::string() {
return (const char *) bin;
}
friend std::ostream & operator<<(std::ostream & str, Binary const &b) {
return str << b.bin;
}
bool operator<(const Binary &b) {
if(size < b.size) {
return true;
} else if (size > b.size) {
return false;
} else {
return memcmp(bin,b.bin,size) < 0;
}
}
bool operator<(Binary &b) {
if(size < b.size) {
return true;
} else if (size > b.size) {
return false;
} else {
return memcmp(bin,b.bin,size) < 0;
}
}
bool operator>(const Binary &b) {
if(size > b.size) {
return true;
} else if (size < b.size) {
return false;
} else {
return memcmp(bin,b.bin,size) > 0;
}
}
bool operator== (const Binary &b) {
if (size == b.size ) {
return memcmp(bin,b.bin, std::min(size, b.size)) == 0;
} else {
return false;
}
}
operator std::string() const {
return (const char*) bin;
}
Binary& set_data(const char *data) {
bin = (unsigned char *) data;
size = strlen(data);
return *this;
}
void copy(char *inbin, size_t insize) {
bin = (unsigned char *) operator new(insize);
allocated = true;
size = insize;
memcpy(bin, inbin, size);
}
};
inline bool operator < (const Binary &a, const Binary &b) {
if(a.size < b.size) {
return true;
} else if (a.size > b.size) {
return false;
} else {
return memcmp(a.bin,b.bin, std::min(a.size, b.size)) < 0;
}
}

+ 0
- 2394
c_src/gb_lru/btree.h
File diff suppressed because it is too large
View File


+ 0
- 349
c_src/gb_lru/btree_container.h View File

@ -1,349 +0,0 @@
// Copyright 2013 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef UTIL_BTREE_BTREE_CONTAINER_H__
#define UTIL_BTREE_BTREE_CONTAINER_H__
#include <iosfwd>
#include <utility>
#include "btree.h"
namespace btree {
// A common base class for btree_set, btree_map, btree_multiset and
// btree_multimap.
template <typename Tree>
class btree_container {
typedef btree_container<Tree> self_type;
public:
typedef typename Tree::params_type params_type;
typedef typename Tree::key_type key_type;
typedef typename Tree::value_type value_type;
typedef typename Tree::key_compare key_compare;
typedef typename Tree::allocator_type allocator_type;
typedef typename Tree::pointer pointer;
typedef typename Tree::const_pointer const_pointer;
typedef typename Tree::reference reference;
typedef typename Tree::const_reference const_reference;
typedef typename Tree::size_type size_type;
typedef typename Tree::difference_type difference_type;
typedef typename Tree::iterator iterator;
typedef typename Tree::const_iterator const_iterator;
typedef typename Tree::reverse_iterator reverse_iterator;
typedef typename Tree::const_reverse_iterator const_reverse_iterator;
public:
// Default constructor.
btree_container(const key_compare &comp, const allocator_type &alloc)
: tree_(comp, alloc) {
}
// Copy constructor.
btree_container(const self_type &x)
: tree_(x.tree_) {
}
// Iterator routines.
iterator begin() { return tree_.begin(); }
const_iterator begin() const { return tree_.begin(); }
iterator end() { return tree_.end(); }
const_iterator end() const { return tree_.end(); }
reverse_iterator rbegin() { return tree_.rbegin(); }
const_reverse_iterator rbegin() const { return tree_.rbegin(); }
reverse_iterator rend() { return tree_.rend(); }
const_reverse_iterator rend() const { return tree_.rend(); }
// Lookup routines.
iterator lower_bound(const key_type &key) {
return tree_.lower_bound(key);
}
const_iterator lower_bound(const key_type &key) const {
return tree_.lower_bound(key);
}
iterator upper_bound(const key_type &key) {
return tree_.upper_bound(key);
}
const_iterator upper_bound(const key_type &key) const {
return tree_.upper_bound(key);
}
std::pair<iterator,iterator> equal_range(const key_type &key) {
return tree_.equal_range(key);
}
std::pair<const_iterator,const_iterator> equal_range(const key_type &key) const {
return tree_.equal_range(key);
}
// Utility routines.
void clear() {
tree_.clear();
}
void swap(self_type &x) {
tree_.swap(x.tree_);
}
void dump(std::ostream &os) const {
tree_.dump(os);
}
void verify() const {
tree_.verify();
}
// Size routines.
size_type size() const { return tree_.size(); }
size_type max_size() const { return tree_.max_size(); }
bool empty() const { return tree_.empty(); }
size_type height() const { return tree_.height(); }
size_type internal_nodes() const { return tree_.internal_nodes(); }
size_type leaf_nodes() const { return tree_.leaf_nodes(); }
size_type nodes() const { return tree_.nodes(); }
size_type bytes_used() const { return tree_.bytes_used(); }
static double average_bytes_per_value() {
return Tree::average_bytes_per_value();
}
double fullness() const { return tree_.fullness(); }
double overhead() const { return tree_.overhead(); }
bool operator==(const self_type& x) const {
if (size() != x.size()) {
return false;
}
for (const_iterator i = begin(), xi = x.begin(); i != end(); ++i, ++xi) {
if (*i != *xi) {
return false;
}
}
return true;
}
bool operator!=(const self_type& other) const {
return !operator==(other);
}
protected:
Tree tree_;
};
template <typename T>
inline std::ostream& operator<<(std::ostream &os, const btree_container<T> &b) {
b.dump(os);
return os;
}
// A common base class for btree_set and safe_btree_set.
template <typename Tree>
class btree_unique_container : public btree_container<Tree> {
typedef btree_unique_container<Tree> self_type;
typedef btree_container<Tree> super_type;
public:
typedef typename Tree::key_type key_type;
typedef typename Tree::value_type value_type;
typedef typename Tree::size_type size_type;
typedef typename Tree::key_compare key_compare;
typedef typename Tree::allocator_type allocator_type;
typedef typename Tree::iterator iterator;
typedef typename Tree::const_iterator const_iterator;
public:
// Default constructor.
btree_unique_container(const key_compare &comp = key_compare(),
const allocator_type &alloc = allocator_type())
: super_type(comp, alloc) {
}
// Copy constructor.
btree_unique_container(const self_type &x)
: super_type(x) {
}
// Range constructor.
template <class InputIterator>
btree_unique_container(InputIterator b, InputIterator e,
const key_compare &comp = key_compare(),
const allocator_type &alloc = allocator_type())
: super_type(comp, alloc) {
insert(b, e);
}
// Lookup routines.
iterator find(const key_type &key) {
return this->tree_.find_unique(key);
}
const_iterator find(const key_type &key) const {
return this->tree_.find_unique(key);
}
size_type count(const key_type &key) const {
return this->tree_.count_unique(key);
}
// Insertion routines.
std::pair<iterator,bool> insert(const value_type &x) {
return this->tree_.insert_unique(x);
}
iterator insert(iterator position, const value_type &x) {
return this->tree_.insert_unique(position, x);
}
template <typename InputIterator>
void insert(InputIterator b, InputIterator e) {
this->tree_.insert_unique(b, e);
}
// Deletion routines.
int erase(const key_type &key) {
return this->tree_.erase_unique(key);
}
// Erase the specified iterator from the btree. The iterator must be valid
// (i.e. not equal to end()). Return an iterator pointing to the node after
// the one that was erased (or end() if none exists).
iterator erase(const iterator &iter) {
return this->tree_.erase(iter);
}
void erase(const iterator &first, const iterator &last) {
this->tree_.erase(first, last);
}
};
// A common base class for btree_map and safe_btree_map.
template <typename Tree>
class btree_map_container : public btree_unique_container<Tree> {
typedef btree_map_container<Tree> self_type;
typedef btree_unique_container<Tree> super_type;
public:
typedef typename Tree::key_type key_type;
typedef typename Tree::data_type data_type;
typedef typename Tree::value_type value_type;
typedef typename Tree::mapped_type mapped_type;
typedef typename Tree::key_compare key_compare;
typedef typename Tree::allocator_type allocator_type;
private:
// A pointer-like object which only generates its value when
// dereferenced. Used by operator[] to avoid constructing an empty data_type
// if the key already exists in the map.
struct generate_value {
generate_value(const key_type &k)
: key(k) {
}
value_type operator*() const {
return std::make_pair(key, data_type());
}
const key_type &key;
};
public:
// Default constructor.
btree_map_container(const key_compare &comp = key_compare(),
const allocator_type &alloc = allocator_type())
: super_type(comp, alloc) {
}
// Copy constructor.
btree_map_container(const self_type &x)
: super_type(x) {
}
// Range constructor.
template <class InputIterator>
btree_map_container(InputIterator b, InputIterator e,
const key_compare &comp = key_compare(),
const allocator_type &alloc = allocator_type())
: super_type(b, e, comp, alloc) {
}
// Insertion routines.
data_type& operator[](const key_type &key) {
return this->tree_.insert_unique(key, generate_value(key)).first->second;
}
};
// A common base class for btree_multiset and btree_multimap.
template <typename Tree>
class btree_multi_container : public btree_container<Tree> {
typedef btree_multi_container<Tree> self_type;
typedef btree_container<Tree> super_type;
public:
typedef typename Tree::key_type key_type;
typedef typename Tree::value_type value_type;
typedef typename Tree::size_type size_type;
typedef typename Tree::key_compare key_compare;
typedef typename Tree::allocator_type allocator_type;
typedef typename Tree::iterator iterator;
typedef typename Tree::const_iterator const_iterator;
public:
// Default constructor.
btree_multi_container(const key_compare &comp = key_compare(),
const allocator_type &alloc = allocator_type())
: super_type(comp, alloc) {
}
// Copy constructor.
btree_multi_container(const self_type &x)
: super_type(x) {
}
// Range constructor.
template <class InputIterator>
btree_multi_container(InputIterator b, InputIterator e,
const key_compare &comp = key_compare(),
const allocator_type &alloc = allocator_type())
: super_type(comp, alloc) {
insert(b, e);
}
// Lookup routines.
iterator find(const key_type &key) {
return this->tree_.find_multi(key);
}
const_iterator find(const key_type &key) const {
return this->tree_.find_multi(key);
}
size_type count(const key_type &key) const {
return this->tree_.count_multi(key);
}
// Insertion routines.
iterator insert(const value_type &x) {
return this->tree_.insert_multi(x);
}
iterator insert(iterator position, const value_type &x) {
return this->tree_.insert_multi(position, x);
}
template <typename InputIterator>
void insert(InputIterator b, InputIterator e) {
this->tree_.insert_multi(b, e);
}
// Deletion routines.
int erase(const key_type &key) {
return this->tree_.erase_multi(key);
}
// Erase the specified iterator from the btree. The iterator must be valid
// (i.e. not equal to end()). Return an iterator pointing to the node after
// the one that was erased (or end() if none exists).
iterator erase(const iterator &iter) {
return this->tree_.erase(iter);
}
void erase(const iterator &first, const iterator &last) {
this->tree_.erase(first, last);
}
};
} // namespace btree
#endif // UTIL_BTREE_BTREE_CONTAINER_H__

+ 0
- 130
c_src/gb_lru/btree_map.h View File

@ -1,130 +0,0 @@
// Copyright 2013 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// A btree_map<> implements the STL unique sorted associative container
// interface and the pair associative container interface (a.k.a map<>) using a
// btree. A btree_multimap<> implements the STL multiple sorted associative
// container interface and the pair associtive container interface (a.k.a
// multimap<>) using a btree. See btree.h for details of the btree
// implementation and caveats.
#ifndef UTIL_BTREE_BTREE_MAP_H__
#define UTIL_BTREE_BTREE_MAP_H__
#include <algorithm>
#include <functional>
#include <memory>
#include <string>
#include <utility>
#include "btree.h"
#include "btree_container.h"
namespace btree {
// The btree_map class is needed mainly for its constructors.
template <typename Key, typename Value,
typename Compare = std::less<Key>,
typename Alloc = std::allocator<std::pair<const Key, Value> >,
int TargetNodeSize = 256>
class btree_map : public btree_map_container<
btree<btree_map_params<Key, Value, Compare, Alloc, TargetNodeSize> > > {
typedef btree_map<Key, Value, Compare, Alloc, TargetNodeSize> self_type;
typedef btree_map_params<
Key, Value, Compare, Alloc, TargetNodeSize> params_type;
typedef btree<params_type> btree_type;
typedef btree_map_container<btree_type> super_type;
public:
typedef typename btree_type::key_compare key_compare;
typedef typename btree_type::allocator_type allocator_type;
public:
// Default constructor.
btree_map(const key_compare &comp = key_compare(),
const allocator_type &alloc = allocator_type())
: super_type(comp, alloc) {
}
// Copy constructor.
btree_map(const self_type &x)
: super_type(x) {
}
// Range constructor.
template <class InputIterator>
btree_map(InputIterator b, InputIterator e,
const key_compare &comp = key_compare(),
const allocator_type &alloc = allocator_type())
: super_type(b, e, comp, alloc) {
}
};
template <typename K, typename V, typename C, typename A, int N>
inline void swap(btree_map<K, V, C, A, N> &x,
btree_map<K, V, C, A, N> &y) {
x.swap(y);
}
// The btree_multimap class is needed mainly for its constructors.
template <typename Key, typename Value,
typename Compare = std::less<Key>,
typename Alloc = std::allocator<std::pair<const Key, Value> >,
int TargetNodeSize = 256>
class btree_multimap : public btree_multi_container<
btree<btree_map_params<Key, Value, Compare, Alloc, TargetNodeSize> > > {
typedef btree_multimap<Key, Value, Compare, Alloc, TargetNodeSize> self_type;
typedef btree_map_params<
Key, Value, Compare, Alloc, TargetNodeSize> params_type;
typedef btree<params_type> btree_type;
typedef btree_multi_container<btree_type> super_type;
public:
typedef typename btree_type::key_compare key_compare;
typedef typename btree_type::allocator_type allocator_type;
typedef typename btree_type::data_type data_type;
typedef typename btree_type::mapped_type mapped_type;
public:
// Default constructor.
btree_multimap(const key_compare &comp = key_compare(),
const allocator_type &alloc = allocator_type())
: super_type(comp, alloc) {
}
// Copy constructor.
btree_multimap(const self_type &x)
: super_type(x) {
}
// Range constructor.
template <class InputIterator>
btree_multimap(InputIterator b, InputIterator e,
const key_compare &comp = key_compare(),
const allocator_type &alloc = allocator_type())
: super_type(b, e, comp, alloc) {
}
};
template <typename K, typename V, typename C, typename A, int N>
inline void swap(btree_multimap<K, V, C, A, N> &x,
btree_multimap<K, V, C, A, N> &y) {
x.swap(y);
}
} // namespace btree
#endif // UTIL_BTREE_BTREE_MAP_H__

+ 0
- 619
c_src/gb_lru/btreelru_nif.cpp View File

@ -1,619 +0,0 @@
#include <string>
#include <iostream>
#include <vector>
#include "erl_nif.h"
#include "erlterm.h"
#include "lru.h"
using namespace std;
namespace { /* anonymous namespace starts */
typedef struct _obj_resource {
bool allocated;
void *object;
ErlNifMutex *emtx;
} object_resource;
ErlNifResourceFlags resource_flags = (ErlNifResourceFlags)(ERL_NIF_RT_CREATE | ERL_NIF_RT_TAKEOVER);
ErlNifResourceType* lruResource;
ErlNifResourceType* iteratorResource;
/* atoms */
ERL_NIF_TERM atom_ok;
ERL_NIF_TERM atom_key;
ERL_NIF_TERM atom_error;
ERL_NIF_TERM atom_invalid;
ERL_NIF_TERM atom_value;
ERL_NIF_TERM atom_max_size;
ERL_NIF_TERM atom_tab;
ERL_NIF_TERM atom_lru_old;
void lru_dtor(ErlNifEnv* env, void *lru);
void iterator_dtor(ErlNifEnv* env, void *it);
int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info){
lruResource = enif_open_resource_type(env,
"btreelru_nif",
"lru",
lru_dtor,
resource_flags,
NULL);
iteratorResource = enif_open_resource_type(env,
"btreelru_nif",
"iterator",
iterator_dtor,
resource_flags,
NULL);
atom_ok = enif_make_atom(env, "ok");
atom_key = enif_make_atom(env, "key");
atom_error = enif_make_atom(env, "error");
atom_invalid = enif_make_atom(env, "invalid");
atom_value = enif_make_atom(env, "value");
atom_max_size = enif_make_atom(env, "max_size");
atom_tab = enif_make_atom(env, "tab");
atom_lru_old = enif_make_atom(env, "lru_old");
return 0;
}
int reload(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info){
return 0;
}
int upgrade(ErlNifEnv* env, void** priv_data, void** old_priv_data,ERL_NIF_TERM load_info){
return 0;
}
void lru_dtor(ErlNifEnv* env, void* _lru_btree) {
object_resource *lru_btree = (object_resource*) _lru_btree;
if (lru_btree->allocated)
delete (LRUBtree<ErlTerm,ErlTerm>*) lru_btree->object;
}
void iterator_dtor(ErlNifEnv* env, void* _lru_iterator) {
object_resource *lru_iterator = (object_resource*) _lru_iterator;
if (lru_iterator->allocated)
delete (LRUBtree<ErlTerm,ErlTerm>::iterator*) lru_iterator->object;
}
void node_free(LRUBtree<ErlTerm,ErlTerm> *bt_lru, LRUNode<ErlTerm,ErlTerm> *node) {
enif_free_env((ErlNifEnv*)node->kvenv);
return;
}
void node_kickout(LRUBtree<ErlTerm,ErlTerm> *bt_lru, LRUNode<ErlTerm,ErlTerm> *node, void *currenv) {
ErlNifEnv *env = (ErlNifEnv *) currenv;
if (bt_lru->pid_set) {
enif_send(env, &bt_lru->pid, NULL, enif_make_tuple3(env, atom_lru_old, node->key.t, node->data.t));
}
return;
}
ERL_NIF_TERM next(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {
object_resource *lru;
LRUBtree<ErlTerm,ErlTerm> *bt_lru;
LRUNode<ErlTerm,ErlTerm> *node;
ErlTerm key;
ErlTerm value;
if (argc != 2) {
return enif_make_badarg(env);
}
if (!enif_get_resource(env, argv[0], lruResource, (void **) &lru)) {
return enif_make_badarg(env);
}
bt_lru = (LRUBtree<ErlTerm,ErlTerm> *) lru->object;
key.t = argv[1];
node = bt_lru->get(key);
if (!node)
return enif_make_tuple2(env, atom_error, atom_invalid);
node = node->next;
if (!node)
return enif_make_tuple2(env, atom_error, atom_invalid);
key.t = enif_make_copy(env, node->key.t);
value.t = enif_make_copy(env, node->data.t);
return enif_make_tuple2(env, key.t, value.t);
}
ERL_NIF_TERM prev(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {
object_resource *lru;
LRUBtree<ErlTerm,ErlTerm> *bt_lru;
LRUNode<ErlTerm,ErlTerm> *node;
ErlTerm key;
ErlTerm value;
if (argc != 2) {
return enif_make_badarg(env);
}
if (!enif_get_resource(env, argv[0], lruResource, (void **) &lru)) {
return enif_make_badarg(env);
}
bt_lru = (LRUBtree<ErlTerm,ErlTerm> *) lru->object;
key.t = argv[1];
node = bt_lru->get(key);
if (!node)
return enif_make_tuple2(env, atom_error, atom_invalid);
node = node->prev;
if (!node)
return enif_make_tuple2(env, atom_error, atom_invalid);
key.t = enif_make_copy(env, node->key.t);
value.t = enif_make_copy(env, node->data.t);
return enif_make_tuple2(env, key.t, value.t);
}
ERL_NIF_TERM create(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {
unsigned long max_size;
object_resource *lru;
LRUBtree<ErlTerm,ErlTerm> *bt_lru;
ERL_NIF_TERM lru_term;
/* get max_size */
if (enif_get_ulong(env, argv[0], &max_size) < 1){
return enif_make_tuple2(env, atom_error, atom_max_size);
}
if (!(bt_lru = new LRUBtree<ErlTerm,ErlTerm>(max_size, node_free, node_kickout))) {
return enif_make_tuple2(env, atom_error, enif_make_atom(env, "alloction"));
}
lru = (object_resource *) enif_alloc_resource(lruResource, sizeof(object_resource));
lru->object = bt_lru;
lru->allocated = true;
lru_term = enif_make_resource(env, lru);
enif_release_resource(lru);
return enif_make_tuple2(env, atom_ok, lru_term);
}
ERL_NIF_TERM seek(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {
object_resource *lru;
object_resource *it;
LRUBtree<ErlTerm,ErlTerm> *bt_lru;
LRUBtree<ErlTerm,ErlTerm>::iterator *bt_it_;
LRUBtree<ErlTerm,ErlTerm>::iterator bt_it;
ErlTerm key;
ERL_NIF_TERM it_term;
ERL_NIF_TERM kv;
if (!enif_get_resource(env, argv[0], lruResource, (void **) &lru)) {
return enif_make_badarg(env);
}
key.t = argv[1];
bt_lru = (LRUBtree<ErlTerm,ErlTerm> *)lru->object;
bt_it = bt_lru->bmap.lower_bound(key);
if ( bt_it == bt_lru->bmap.end() ) {
return enif_make_tuple2(env, atom_error, atom_invalid);
}
bt_it_ = new LRUBtree<ErlTerm,ErlTerm>::iterator;
*bt_it_ = bt_it;
it = (object_resource *) enif_alloc_resource(iteratorResource, sizeof(object_resource));
it->object = bt_it_;
it->allocated = true;
it_term = enif_make_resource(env, it);
enif_release_resource(it);
kv = enif_make_tuple2(env, bt_it->second->key.t, bt_it->second->data.t);
return enif_make_tuple2(env, kv, it_term);
}
ERL_NIF_TERM iterate_next(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {
object_resource *lru;
object_resource *it;
LRUBtree<ErlTerm,ErlTerm>::iterator *bt_it_;
LRUBtree<ErlTerm,ErlTerm> *bt_lru;
ERL_NIF_TERM kv;
if (!enif_get_resource(env, argv[0], lruResource, (void **) &lru)) {
return enif_make_badarg(env);
}
if (!enif_get_resource(env, argv[1], iteratorResource, (void **) &it)) {
return enif_make_badarg(env);
}
bt_lru = (LRUBtree<ErlTerm,ErlTerm> *)lru->object;
bt_it_ = (LRUBtree<ErlTerm,ErlTerm>::iterator *) it->object;
if (bt_it_ == NULL)
return enif_make_tuple2(env, atom_error, atom_invalid);
(*bt_it_)++;
if ( *bt_it_ == bt_lru->bmap.end() ) {
it->allocated = false;
delete bt_it_;
it->object = NULL;
return enif_make_tuple2(env, atom_error, atom_invalid);
}
kv = enif_make_tuple2(env, (*bt_it_)->second->key.t, (*bt_it_)->second->data.t);
return enif_make_tuple2(env, atom_ok, kv);
}
ERL_NIF_TERM close(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {
object_resource *lru;
LRUBtree<ErlTerm,ErlTerm> *bt_lru;
if (argc != 1) {
return enif_make_badarg(env);
}
if (!enif_get_resource(env, argv[0], lruResource, (void **) &lru)) {
return enif_make_badarg(env);
}
bt_lru = (LRUBtree<ErlTerm,ErlTerm> *)lru->object;
lru->allocated = false;
delete bt_lru;
return atom_ok;
}
ERL_NIF_TERM read(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {
object_resource *lru;
LRUBtree<ErlTerm,ErlTerm> *bt_lru;
LRUNode<ErlTerm,ErlTerm> *node;
ErlTerm key;
ERL_NIF_TERM kv;
if (argc != 2) {
return enif_make_badarg(env);
}
if (!enif_get_resource(env, argv[0], lruResource, (void **) &lru)) {
return enif_make_badarg(env);
}
bt_lru = (LRUBtree<ErlTerm,ErlTerm> *) lru->object;
key.t = argv[1];
node = bt_lru->get(key);
if (!node)
return enif_make_tuple2(env, atom_error, atom_invalid);
kv = enif_make_tuple2(env, enif_make_copy(env, node->key.t), enif_make_copy(env, node->data.t));
return enif_make_tuple2(env, atom_ok, kv);
}
ERL_NIF_TERM remove(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {
object_resource *lru;
LRUBtree<ErlTerm,ErlTerm> *bt_lru;
ErlTerm key;
if (argc != 2) {
return enif_make_badarg(env);
}
if (!enif_get_resource(env, argv[0], lruResource, (void **) &lru)) {
return enif_make_badarg(env);
}
bt_lru = (LRUBtree<ErlTerm,ErlTerm> *) lru->object;
key.t = argv[1];
bt_lru->erase(key);
return atom_ok;
}
ERL_NIF_TERM oldest(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {
object_resource *lru;
LRUBtree<ErlTerm,ErlTerm> *bt_lru;
LRUNode<ErlTerm,ErlTerm> *node;
ERL_NIF_TERM key;
ERL_NIF_TERM value;
if (argc != 1) {
return enif_make_badarg(env);
}
if (!enif_get_resource(env, argv[0], lruResource, (void **) &lru)) {
return enif_make_badarg(env);
}
bt_lru = (LRUBtree<ErlTerm,ErlTerm> *) lru->object;
node = bt_lru->getOldest();
if (!node)
return enif_make_tuple2(env, atom_error, atom_invalid);
key = enif_make_copy(env, node->key.t);
value = enif_make_copy(env, node->data.t);
return enif_make_tuple2(env, key, value);
}
ERL_NIF_TERM latest(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {
object_resource *lru;
LRUBtree<ErlTerm,ErlTerm> *bt_lru;
LRUNode<ErlTerm,ErlTerm> *node;
ERL_NIF_TERM key;
ERL_NIF_TERM value;
if (argc != 1) {
return enif_make_badarg(env);
}
if (!enif_get_resource(env, argv[0], lruResource, (void **) &lru)) {
return enif_make_badarg(env);
}
bt_lru = (LRUBtree<ErlTerm,ErlTerm> *) lru->object;
// last is "last in" in the lru
node = bt_lru->getLatest();
if (!node)
return enif_make_tuple2(env, atom_error, atom_invalid);
key = enif_make_copy(env, node->key.t);
value = enif_make_copy(env, node->data.t);
return enif_make_tuple2(env, key, value);
}
ERL_NIF_TERM last(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {
object_resource *lru;
LRUBtree<ErlTerm,ErlTerm> *bt_lru;
LRUNode<ErlTerm,ErlTerm> *node;
ERL_NIF_TERM key;
ERL_NIF_TERM value;
if (argc != 1) {
return enif_make_badarg(env);
}
if (!enif_get_resource(env, argv[0], lruResource, (void **) &lru)) {
return enif_make_badarg(env);
}
bt_lru = (LRUBtree<ErlTerm,ErlTerm> *) lru->object;
node = bt_lru->bmap.rbegin()->second;
if (!node)
return enif_make_tuple2(env, atom_error, atom_invalid);
key = enif_make_copy(env, node->key.t);
value = enif_make_copy(env, node->data.t);
return enif_make_tuple2(env, key, value);
}
ERL_NIF_TERM first(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {
object_resource *lru;
LRUBtree<ErlTerm,ErlTerm> *bt_lru;
LRUNode<ErlTerm,ErlTerm> *node;
ERL_NIF_TERM key;
ERL_NIF_TERM value;
if (argc != 1) {
return enif_make_badarg(env);
}
if (!enif_get_resource(env, argv[0], lruResource, (void **) &lru)) {
return enif_make_badarg(env);
}
bt_lru = (LRUBtree<ErlTerm,ErlTerm> *) lru->object;
node = bt_lru->bmap.begin()->second;
if (!node)
return enif_make_tuple2(env, atom_error, atom_invalid);
key = enif_make_copy(env, node->key.t);
value = enif_make_copy(env, node->data.t);
return enif_make_tuple2(env, key, value);
}
ERL_NIF_TERM write(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {
object_resource *lru;
LRUBtree<ErlTerm,ErlTerm> *bt_lru;
ErlTerm key;
ErlTerm value;
ErlNifEnv *kv_env;
size_t size;
if (argc != 3) {
return enif_make_badarg(env);
}
if (!enif_get_resource(env, argv[0], lruResource, (void **) &lru)) {
return enif_make_badarg(env);
}
bt_lru = (LRUBtree<ErlTerm, ErlTerm> *) lru->object;
kv_env = enif_alloc_env();
key.t = enif_make_copy(kv_env, argv[1]);
value.t = enif_make_copy(kv_env, argv[2]);
/* do not use the size of term
size = enif_size_term(key.t);
size += enif_size_term(value.t);
*/
/* size based on entries */
size = 1;
bt_lru->put(key, value, kv_env, env, size);
return atom_ok;
}
ERL_NIF_TERM register_pid(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {
object_resource *lru;
LRUBtree<ErlTerm,ErlTerm> *bt_lru;
if (argc != 2) {
return enif_make_badarg(env);
}
if (!enif_get_resource(env, argv[0], lruResource, (void **) &lru)) {
return enif_make_badarg(env);
}
bt_lru = (LRUBtree<ErlTerm,ErlTerm> *) lru->object;
if (!enif_get_local_pid(env, argv[1], &(bt_lru->pid))) {
return enif_make_badarg(env);
}
bt_lru->pid_set = true;
return atom_ok;
}
ERL_NIF_TERM unregister_pid(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {
object_resource *lru;
LRUBtree<ErlTerm,ErlTerm> *bt_lru;
if (argc != 1) {
return enif_make_badarg(env);
}
if (!enif_get_resource(env, argv[0], lruResource, (void **) &lru)) {
return enif_make_badarg(env);
}
bt_lru = (LRUBtree<ErlTerm,ErlTerm> *) lru->object;
bt_lru->pid_set = false;
return atom_ok;
}
ERL_NIF_TERM get_registered_pid(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {
object_resource *lru;
LRUBtree<ErlTerm,ErlTerm> *bt_lru;
if (argc != 1) {
return enif_make_badarg(env);
}
if (!enif_get_resource(env, argv[0], lruResource, (void **) &lru)) {
return enif_make_badarg(env);
}
bt_lru = (LRUBtree<ErlTerm,ErlTerm> *) lru->object;
if (!bt_lru->pid_set) {
return enif_make_tuple2(env, atom_error, atom_invalid);
}
return enif_make_pid(env, &(bt_lru->pid));
}
ERL_NIF_TERM get_size(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {
object_resource *lru;
LRUBtree<ErlTerm,ErlTerm> *bt_lru;
if (argc != 1) {
return enif_make_badarg(env);
}
if (!enif_get_resource(env, argv[0], lruResource, (void **) &lru)) {
return enif_make_badarg(env);
}
bt_lru = (LRUBtree<ErlTerm,ErlTerm> *) lru->object;
return enif_make_ulong(env, bt_lru->getSize());
}
ERL_NIF_TERM get_max_size(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {
object_resource *lru;
LRUBtree<ErlTerm,ErlTerm> *bt_lru;
if (argc != 1) {
return enif_make_badarg(env);
}
if (!enif_get_resource(env, argv[0], lruResource, (void **) &lru)) {
return enif_make_badarg(env);
}
bt_lru = (LRUBtree<ErlTerm,ErlTerm> *) lru->object;
return enif_make_ulong(env, bt_lru->getMaxSize());
}
ERL_NIF_TERM set_max_size(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {
object_resource *lru;
unsigned long max_size;
LRUBtree<ErlTerm,ErlTerm> *bt_lru;
if (argc != 2) {
return enif_make_badarg(env);
}
if (!enif_get_resource(env, argv[0], lruResource, (void **) &lru)) {
return enif_make_badarg(env);
}
/* get max_size */
if (enif_get_ulong(env, argv[1], &max_size) < 1){
return enif_make_tuple2(env, atom_error, atom_max_size);
}
bt_lru = (LRUBtree<ErlTerm,ErlTerm> *) lru->object;
bt_lru->setMaxSize(max_size);
return atom_ok;
}
ErlNifFunc nif_funcs[] = {
{"create", 1, create},
{"close", 1, close, ERL_NIF_DIRTY_JOB_IO_BOUND},
{"register_pid", 2, register_pid},
{"unregister_pid", 1, unregister_pid},
{"get_registered_pid", 1, get_registered_pid},
{"get_size", 1, get_size},
{"get_max_size", 1, get_max_size},
{"set_max_size", 2, set_max_size},
{"oldest", 1, oldest},
{"latest", 1, latest},
{"last", 1, last},
{"first", 1, first},
{"read", 2, read},
{"next", 2, next},
{"prev", 2, prev},
{"seek", 2, seek},
{"iterate_next", 2, iterate_next},
{"remove", 2, remove},
{"write", 3, write}
};
} /* anonymouse namespace ends */
ERL_NIF_INIT(btree_lru, nif_funcs, load, reload, upgrade, NULL)

+ 0
- 71
c_src/gb_lru/erlterm.h View File

@ -1,71 +0,0 @@
#include "erl_nif.h"
class ErlTerm {
public:
ERL_NIF_TERM t;
static void *operator new(size_t size) {
return enif_alloc(size);
}
static void operator delete(void *block) {
enif_free(block);
}
bool operator< (const ErlTerm &term) {
if (enif_compare(t, term.t) < 0)
return true;
return false;
}
bool operator< (ErlTerm &term) {
if (enif_compare(t, term.t) < 0)
return true;
return false;
}
bool operator> (const ErlTerm &term) {
if (enif_compare(t, term.t) > 0)
return true;
return false;
}
bool operator> (ErlTerm &term) {
if (enif_compare(t, term.t) > 0)
return true;
return false;
}
bool operator== (const ErlTerm &term) {
if (enif_compare(t, term.t) == 0)
return true;
return false;
}
bool operator== (ErlTerm &term) {
if (enif_compare(t, term.t) == 0)
return true;
return false;
}
};
inline bool operator < (const ErlTerm &a, const ErlTerm &b) {
if (enif_compare(a.t, b.t) < 0)
return true;
return false;
}
#if 0
// extend std::hash to understand ErlTerm used by hashmap not btree
namespace std {
template <>
struct hash<ErlTerm>
{
size_t operator()(const ErlTerm& term) const
{
return (size_t) enif_hash_term(term.t);
}
};
}
#endif

+ 0
- 266
c_src/gb_lru/lru.h View File

@ -1,266 +0,0 @@
#include "btree_map.h"
#include <algorithm>
#include <iostream>
#include "murmurhash2.h"
#include "binary.h"
#include "erl_nif.h"
// extend std::hash to understand Binary type
namespace std {
template <>
struct hash<Binary>
{
size_t operator()(const Binary& b) const
{
return MurmurHash2(b.bin, b.size, 4242);
}
};
}
template <typename K, typename V>
struct LRUNode
{
K key;
V data;
void *kvenv;
LRUNode<K,V> *prev;
LRUNode<K,V> *next;
size_t size;
LRUNode(void *kvenv = NULL, size_t size=0) : kvenv(kvenv), prev(NULL), next(NULL), size(size) { }
/*
static void *LRUNode<ErlTerm,ErlTerm>::operator new(size_t size) {
return enif_alloc(size);
}
static void operator delete(void *block) {
enif_free(block);
}
*/
void printChain() {
LRUNode<K,V>* node;
int i=11;
std::cout << "(";
for(node = this; node && i; node = node->next, i--) {
std::cout << node->key << " -> ";
}
if (node) {
std::cout << " loop detection end ";
} else {
std::cout << " end ";
}
std::cout << ")" << std::endl;
}
void printNextPrevKey() {
std::cout << "(";
printNextKey();
printPrevKey();
std::cout << ")";
}
void printNextKey() {
if (next) {
std::cout << "next key " << next->key << " ";
}
}
void printPrevKey() {
if (prev) {
std::cout << "prev key " << prev->key << " ";
}
}
};
template <class K,class V>
class LRUBtree {
private:
LRUNode<K,V> *oldest;
LRUNode<K,V> *latest;
unsigned long size;
unsigned long max_size;
void (*node_free)(LRUBtree<K,V> *lru, LRUNode<K,V> *node);
void (*node_kickout)(LRUBtree<K,V> *lru, LRUNode<K,V> *node, void *call_env);
typedef btree::btree_map<K, LRUNode<K,V>*> LRUBtree_map;
public:
LRUBtree_map bmap;
bool pid_set = false;
ErlNifPid pid;
typedef typename LRUBtree_map::iterator iterator;
typedef typename LRUBtree_map::reverse_iterator reverse_iterator;
void printLatest() {
if (latest) {
std::cout << " latest " << latest->key;
} else {
std::cout << " no data in lru ";
}
}
private:
LRUNode<K,V>* erase(LRUNode<K,V> *node) {
if (node->next) {
node->next->prev = node->prev;
}
if (node->prev) {
node->prev->next = node->next;
}
if (node == oldest) {
oldest = node->prev;
}
if (node == latest) {
latest = node->next;
}
if (node_free) {
node_free(this, node);
}
node->next = NULL;
node->prev = NULL;
return node;
}
void printOldest() {
if(oldest) {
std::cout << " oldest " << oldest->key;
} else {
std::cout << " no data in lru ";
}
}
void check_size(void *call_env) {
if (size > max_size) {
if (oldest) { // remove check if oldest exist and rely on max_size always being positive
if (node_kickout)
node_kickout(this, oldest, call_env);
erase(oldest->key);
}
}
}
#define SIZE_100MB 100*1024*1024
public:
LRUBtree(unsigned long max_size = SIZE_100MB,
void (*node_free)(LRUBtree<K,V> *lru, LRUNode<K,V> *node) = NULL,
void (*node_kickout)(LRUBtree<K,V> *lru, LRUNode<K,V> *node, void *call_env) = NULL)
: oldest(NULL), latest(NULL), size(0), max_size(max_size), node_free(node_free),
node_kickout(node_kickout) { }
~LRUBtree() {
LRUNode<K,V> *node;
LRUNode<K,V> *next;
node = latest;
while(node) {
if (node_free) {
node_free(this, node);
}
next = node->next;
delete node;
node = next;
}
}
void printSize() {
std::cout << "size " << size << std::endl;
}
unsigned long getSize() {
return size;
}
unsigned long getMaxSize() {
return max_size;
}
void setMaxSize(unsigned long max_size) {
this->max_size = max_size;
}
void erase(K key) {
LRUNode<K,V> *node;
if ((node = bmap[key])) {
erase(node);
bmap.erase(key);
size -= node->size;
delete node;
}
}
inline void put(K key, V data,
void *kvenv = NULL, void *call_env = NULL,
size_t size = 1) {
LRUNode<K,V> *node;
this->size += size;
check_size(call_env);
// overwrite already existing key
if ((node = bmap[key])) {
this->size -= node->size;
erase(node);
node->kvenv = kvenv;
node->next = latest;
node->size = size;
if (node->next) {
node->next->prev = node;
}
if (!oldest) {
oldest = node;
}
latest = node;
node->key = key;
node->data = data;
}
else if (!oldest) {
node = new LRUNode<K,V>;
node->key = key;
node->data = data;
node->kvenv = kvenv;
node->size = size;
oldest = node;
latest = node;
bmap[node->key] = node;
}
else {
node = new LRUNode<K,V>;
node->key = key;
node->data = data;
node->kvenv = kvenv;
node->size = size;
latest->prev = node;
node->next = latest;
latest = node;
bmap[node->key] = node;
}
}
LRUNode<K,V>* get(K key) {
return bmap[key];
}
LRUNode<K,V>* getOldest() {
return oldest;
}
LRUNode<K,V>* getLatest() {
return latest;
}
LRUNode<K,V>* getNext(LRUNode<K,V> *node) {
return node->next;
}
LRUNode<K,V>* getPrev(LRUNode<K,V> *node) {
return node->prev;
}
};

+ 0
- 73
c_src/gb_lru/murmurhash2.h View File

@ -1,73 +0,0 @@
//-----------------------------------------------------------------------------
// MurmurHash2, by Austin Appleby
// Note - This code makes a few assumptions about how your machine behaves -
// 1. We can read a 4-byte value from any address without crashing
// 2. sizeof(int) == 4
// And it has a few limitations -
// 1. It will not wo
//
// rk incrementally.
// 2. It will not produce the same results on little-endian and big-endian
// machines.
unsigned int MurmurHash2 ( const void * key, int len, unsigned int seed )
{
// 'm' and 'r' are mixing constants generated offline.
// They're not really 'magic', they just happen to work well.
const unsigned int m = 0x5bd1e995;
const int r = 24;
// Initialize the hash to a 'random' value
unsigned int h = seed ^ len;
// Mix 4 bytes at a time into the hash
const unsigned char * data = (const unsigned char *)key;
while(len >= 4)
{
unsigned int k = *(unsigned int *)data;
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
data += 4;
len -= 4;
}
// Handle the last few bytes of the input array
switch(len)
{
case 3: h ^= data[2] << 16;
case 2: h ^= data[1] << 8;
case 1: h ^= data[0];
h *= m;
};
// Do a few final mixes of t
//
//
//
// he hash to ensure the last few
// bytes are well-incorporated.
h ^= h >> 13;
h *= m;
h ^= h >> 15;
return h;
}

+ 0
- 7
c_src/gb_lru/rebar.config View File

@ -1,7 +0,0 @@
{port_specs, [
{"../../priv/btreelru_nif.so", ["btreelru_nif.cpp"]}
]}.

+ 0
- 90
c_src/native_array/native_array_nif.c View File

@ -1,90 +0,0 @@
#include "erl_nif.h"
#define A_OK(env) enif_make_atom(env, "ok")
#define assert_badarg(S, Env) if (! S) { return enif_make_badarg(env); }
static ErlNifResourceType* array_handle = NULL;
static void array_handle_cleanup(ErlNifEnv* env, void* arg) {}
static int load(ErlNifEnv* env, void** priv, ERL_NIF_TERM load_info)
{
ErlNifResourceFlags flags = ERL_NIF_RT_CREATE | ERL_NIF_RT_TAKEOVER;
array_handle = enif_open_resource_type(env, "native_array_nif", "array_handle",
&array_handle_cleanup, flags, 0);
// , 1000array
*priv = enif_alloc(1000 * sizeof(void*));
return 0;
}
static void unload(ErlNifEnv* env, void* priv)
{
enif_free(priv);
}
static ERL_NIF_TERM new_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
//
int refindex;
assert_badarg(enif_get_int(env, argv[0], &refindex), env);
// length
unsigned long length;
assert_badarg(enif_get_ulong(env, argv[1], &length), env);
//
// unsigned char* ref = enif_alloc_resource(array_handle, length);
unsigned char* ref = enif_alloc(length);
//
*((unsigned char**)enif_priv_data(env) + refindex) = ref;
return A_OK(env);
}
static ERL_NIF_TERM get_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
// ref
int refindex;
assert_badarg(enif_get_int(env, argv[0], &refindex), env);
unsigned char* ref = *((unsigned char**)enif_priv_data(env) + refindex);
assert_badarg(ref, env);
// offset
unsigned long offset;
assert_badarg(enif_get_ulong(env, argv[1], &offset), env);
return enif_make_int(env, (int)(*(ref + offset - 1)));
}
static ERL_NIF_TERM put_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
// ref
int refindex;
assert_badarg(enif_get_int(env, argv[0], &refindex), env);
unsigned char* ref = *((unsigned char**)enif_priv_data(env) + refindex);
// offset
unsigned long offset;
assert_badarg(enif_get_ulong(env, argv[1], &offset), env);
// newval
unsigned int newval;
assert_badarg(enif_get_uint(env, argv[2], &newval), env);
//
*(ref + offset - 1) = (unsigned char)newval;
return A_OK(env);
}
static ERL_NIF_TERM delete_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
// ref
int refindex;
assert_badarg(enif_get_int(env, argv[0], &refindex), env);
unsigned char* ref = *((unsigned char**)enif_priv_data(env) + refindex);
//enif_release_resource(ref);
enif_free(ref);
return A_OK(env);
}
static ErlNifFunc nif_funcs[] = {
{"new", 2, new_nif},
{"get", 2, get_nif},
{"put", 3, put_nif},
{"delete", 1, delete_nif},
};
ERL_NIF_INIT(native_array, nif_funcs, &load, NULL, NULL, &unload)

+ 0
- 7
c_src/native_array/rebar.config View File

@ -1,7 +0,0 @@
{port_specs, [
{"../../priv/native_array_nif.so", ["*.c"]}
]}.

+ 0
- 905
c_src/neural/NeuralTable.cpp View File

@ -1,905 +0,0 @@
#include "NeuralTable.h"
/* !!!! A NOTE ON KEYS !!!!
* Keys should be integer values passed from the erlang emulator,
* and should be generated by a hashing function. There is no easy
* way to hash an erlang term from a NIF, but ERTS is more than
* capable of doing so.
*
* Additionally, this workaround means that traditional collision
* handling mechanisms for hash tables will not work without
* special consideration. For instance, to compare keys as you
* would by storing linked lists, you must retrieve the stored
* tuple and call enif_compare or enif_is_identical on the key
* elements of each tuple.
*/
table_set NeuralTable::tables;
atomic<bool> NeuralTable::running(true);
ErlNifMutex *NeuralTable::table_mutex;
NeuralTable::NeuralTable(unsigned int kp) {
for (int i = 0; i < BUCKET_COUNT; ++i) {
ErlNifEnv *env = enif_alloc_env();
env_buckets[i] = env;
locks[i] = enif_rwlock_create("neural_table");
garbage_cans[i] = 0;
reclaimable[i] = enif_make_list(env, 0);
}
start_gc();
start_batch();
key_pos = kp;
}
NeuralTable::~NeuralTable() {
stop_batch();
stop_gc();
for (int i = 0; i < BUCKET_COUNT; ++i) {
enif_rwlock_destroy(locks[i]);
enif_free_env(env_buckets[i]);
}
}
/* ================================================================
* MakeTable
* Allocates a new table, assuming a unique atom identifier. This
* table is stored in a static container. All interactions with
* the table must be performed through the static class API.
*/
ERL_NIF_TERM NeuralTable::MakeTable(ErlNifEnv *env, ERL_NIF_TERM name, ERL_NIF_TERM key_pos) {
char *atom;
string key;
unsigned int len = 0,
pos = 0;
ERL_NIF_TERM ret;
// Allocate space for the name of the table
enif_get_atom_length(env, name, &len, ERL_NIF_LATIN1);
atom = (char*)enif_alloc(len + 1);
// Fetch the value of the atom and store it in a string (because I can, that's why)
enif_get_atom(env, name, atom, len + 1, ERL_NIF_LATIN1);
key = atom;
// Deallocate that space
enif_free(atom);
// Get the key position value
enif_get_uint(env, key_pos, &pos);
enif_mutex_lock(table_mutex);
if (NeuralTable::tables.find(key) != NeuralTable::tables.end()) {
// Table already exists? Bad monkey!
ret = enif_make_badarg(env);
} else {
// All good. Make the table
NeuralTable::tables[key] = new NeuralTable(pos);
ret = enif_make_atom(env, "ok");
}
enif_mutex_unlock(table_mutex);
return ret;
}
/* ================================================================
* GetTable
* Retrieves a handle to the table referenced by name, assuming
* such a table exists. If not, throw badarg.
*/
NeuralTable* NeuralTable::GetTable(ErlNifEnv *env, ERL_NIF_TERM name) {
char *atom = NULL;
string key;
unsigned len = 0;
NeuralTable *ret = NULL;
table_set::const_iterator it;
// Allocate space for the table name
enif_get_atom_length(env, name, &len, ERL_NIF_LATIN1);
atom = (char*)enif_alloc(len + 1);
// Copy the table name into a string
enif_get_atom(env, name, atom, len + 1, ERL_NIF_LATIN1);
key = atom;
// Deallocate that space
enif_free(atom);
// Look for the table and return its pointer if found
it = NeuralTable::tables.find(key);
if (it != NeuralTable::tables.end()) {
ret = it->second;
}
return ret;
}
/* ================================================================
* Insert
* Inserts a tuple into the table with key.
*/
ERL_NIF_TERM NeuralTable::Insert(ErlNifEnv *env, ERL_NIF_TERM table, ERL_NIF_TERM key, ERL_NIF_TERM object) {
NeuralTable *tb;
ERL_NIF_TERM ret, old;
unsigned long int entry_key = 0;
// Grab table or bail.
tb = GetTable(env, table);
if (tb == NULL) {
return enif_make_badarg(env);
}
// Get key value.
enif_get_ulong(env, key, &entry_key);
// Lock the key.
tb->rwlock(entry_key);
// Attempt to lookup the value. If nonempty, increment
// discarded term counter and return a copy of the
// old value
if (tb->find(entry_key, old)) {
tb->reclaim(entry_key, old);
ret = enif_make_tuple2(env, enif_make_atom(env, "ok"), enif_make_copy(env, old));
} else {
ret = enif_make_atom(env, "ok");
}
// Write that shit out
tb->put(entry_key, object);
// Oh, and unlock the key if you would.
tb->rwunlock(entry_key);
return ret;
}
/* ================================================================
* InsertNew
* Inserts a tuple into the table with key, assuming there is not
* a value with key already. Returns true if there was no value
* for key, or false if there was.
*/
ERL_NIF_TERM NeuralTable::InsertNew(ErlNifEnv *env, ERL_NIF_TERM table, ERL_NIF_TERM key, ERL_NIF_TERM object) {
NeuralTable *tb;
ERL_NIF_TERM ret, old;
unsigned long int entry_key = 0;
// Get the table or bail
tb = GetTable(env, table);
if (tb == NULL) {
return enif_make_badarg(env);
}
// Get the key value
enif_get_ulong(env, key, &entry_key);
// Get write lock for the key
tb->rwlock(entry_key);
if (tb->find(entry_key, old)) {
// Key was found. Return false and do not insert
ret = enif_make_atom(env, "false");
} else {
// Key was not found. Return true and insert
tb->put(entry_key, object);
ret = enif_make_atom(env, "true");
}
// Release write lock for the key
tb->rwunlock(entry_key);
return ret;
}
/* ================================================================
* Increment
* Processes a list of update operations. Each operation specifies
* a position in the stored tuple to update and an integer to add
* to it.
*/
ERL_NIF_TERM NeuralTable::Increment(ErlNifEnv *env, ERL_NIF_TERM table, ERL_NIF_TERM key, ERL_NIF_TERM ops) {
NeuralTable *tb;
ERL_NIF_TERM ret, old;
ERL_NIF_TERM it;
unsigned long int entry_key = 0;
// Get table handle or bail
tb = GetTable(env, table);
if (tb == NULL) {
return enif_make_badarg(env);
}
// Get key value
enif_get_ulong(env, key, &entry_key);
// Acquire read/write lock for key
tb->rwlock(entry_key);
// Try to read the value as it is
if (tb->find(entry_key, old)) {
// Value exists
ERL_NIF_TERM op_cell;
const ERL_NIF_TERM *tb_tpl;
const ERL_NIF_TERM *op_tpl;
ERL_NIF_TERM *new_tpl;
ErlNifEnv *bucket_env = tb->get_env(entry_key);
unsigned long int pos = 0;
long int incr = 0;
unsigned int ops_length = 0;
int op_arity = 0,
tb_arity = 0;
// Expand tuple to work on elements
enif_get_tuple(bucket_env, old, &tb_arity, &tb_tpl);
// Allocate space for a copy the contents of the table
// tuple and copy it in. All changes are to be made to
// the copy of the tuple.
new_tpl = (ERL_NIF_TERM*)enif_alloc(sizeof(ERL_NIF_TERM) * tb_arity);
memcpy(new_tpl, tb_tpl, sizeof(ERL_NIF_TERM) * tb_arity);
// Create empty list cell for return value.
ret = enif_make_list(env, 0);
// Set iterator to first cell of ops
it = ops;
while(!enif_is_empty_list(env, it)) {
long int value = 0;
enif_get_list_cell(env, it, &op_cell, &it); // op_cell = hd(it), it = tl(it)
enif_get_tuple(env, op_cell, &op_arity, &op_tpl); // op_arity = tuple_size(op_cell), op_tpl = [TplPos1, TplPos2]
enif_get_ulong(env, op_tpl[0], &pos); // pos = (uint64)op_tpl[0]
enif_get_long(env, op_tpl[1], &incr); // incr = (uint64)op_tpl[1]
// Is the operation trying to modify a nonexistant
// position?
if (pos <= 0 || pos > tb_arity) {
ret = enif_make_badarg(env);
goto bailout;
}
// Is the operation trying to add to a value that's
// not a number?
if (!enif_is_number(bucket_env, new_tpl[pos - 1])) {
ret = enif_make_badarg(env);
goto bailout;
}
// Update the value stored in the tuple.
enif_get_long(env, new_tpl[pos - 1], &value);
tb->reclaim(entry_key, new_tpl[pos - 1]);
new_tpl[pos - 1] = enif_make_long(bucket_env, value + incr);
// Copy the new value to the head of the return list
ret = enif_make_list_cell(env, enif_make_copy(env, new_tpl[pos - 1]), ret);
}
tb->put(entry_key, enif_make_tuple_from_array(bucket_env, new_tpl, tb_arity));
// Bailout allows cancelling the update opertion
// in case something goes wrong. It must always
// come after tb->put and before enif_free and
// rwunlock
bailout:
enif_free(new_tpl);
} else {
ret = enif_make_badarg(env);
}
// Release the rwlock for entry_key
tb->rwunlock(entry_key);
return ret;
}
/* ================================================================
* Unshift
* Processes a list of update operations. Each update operation is
* a tuple specifying the position of a list in the stored value to
* update and a list of values to append. Elements are shifted from
* the input list to the stored list, so:
*
* unshift([a,b,c,d]) results in [d,c,b,a]
*/
ERL_NIF_TERM NeuralTable::Unshift(ErlNifEnv *env, ERL_NIF_TERM table, ERL_NIF_TERM key, ERL_NIF_TERM ops) {
NeuralTable *tb;
ERL_NIF_TERM ret, old, it;
unsigned long int entry_key;
ErlNifEnv *bucket_env;
tb = GetTable(env, table);
if (tb == NULL) {
return enif_make_badarg(env);
}
enif_get_ulong(env, key, &entry_key);
tb->rwlock(entry_key);
bucket_env = tb->get_env(entry_key);
if (tb->find(entry_key, old)) {
const ERL_NIF_TERM *old_tpl,
*op_tpl;
ERL_NIF_TERM *new_tpl;
int tb_arity = 0,
op_arity = 0;
unsigned long pos = 0;
unsigned int new_length = 0;
ERL_NIF_TERM op,
unshift,
copy_it,
copy_val;
enif_get_tuple(bucket_env, old, &tb_arity, &old_tpl);
new_tpl = (ERL_NIF_TERM*)enif_alloc(sizeof(ERL_NIF_TERM) * tb_arity);
memcpy(new_tpl, old_tpl, sizeof(ERL_NIF_TERM) * tb_arity);
it = ops;
ret = enif_make_list(env, 0);
while (!enif_is_empty_list(env, it)) {
// Examine the operation.
enif_get_list_cell(env, it, &op, &it); // op = hd(it), it = tl(it)
enif_get_tuple(env, op, &op_arity, &op_tpl); // op_arity = tuple_size(op), op_tpl = [TplPos1, TplPos2]
enif_get_ulong(env, op_tpl[0], &pos); // Tuple position to modify
unshift = op_tpl[1]; // Values to unshfit
// Argument 1 of the operation tuple is position;
// make sure it's within the bounds of the tuple
// in the table.
if (pos <= 0 || pos > tb_arity) {
ret = enif_make_badarg(env);
goto bailout;
}
// Make sure we were passed a list of things to push
// onto the posth element of the entry
if (!enif_is_list(env, unshift)) {
ret = enif_make_badarg(env);
}
// Now iterate over unshift, moving its values to
// the head of new_tpl[pos - 1] one by one
copy_it = unshift;
while (!enif_is_empty_list(env, copy_it)) {
enif_get_list_cell(env, copy_it, &copy_val, &copy_it);
new_tpl[pos - 1] = enif_make_list_cell(bucket_env, enif_make_copy(bucket_env, copy_val), new_tpl[pos - 1]);
}
enif_get_list_length(bucket_env, new_tpl[pos - 1], &new_length);
ret = enif_make_list_cell(env, enif_make_uint(env, new_length), ret);
}
tb->put(entry_key, enif_make_tuple_from_array(bucket_env, new_tpl, tb_arity));
bailout:
enif_free(new_tpl);
} else {
ret = enif_make_badarg(env);
}
tb->rwunlock(entry_key);
return ret;
}
ERL_NIF_TERM NeuralTable::Shift(ErlNifEnv *env, ERL_NIF_TERM table, ERL_NIF_TERM key, ERL_NIF_TERM ops) {
NeuralTable *tb;
ERL_NIF_TERM ret, old, it;
unsigned long int entry_key;
ErlNifEnv *bucket_env;
tb = GetTable(env, table);
if (tb == NULL) {
return enif_make_badarg(env);
}
enif_get_ulong(env, key, &entry_key);
tb->rwlock(entry_key);
bucket_env = tb->get_env(entry_key);
if (tb->find(entry_key, old)) {
const ERL_NIF_TERM *old_tpl;
const ERL_NIF_TERM *op_tpl;
ERL_NIF_TERM *new_tpl;
int tb_arity = 0,
op_arity = 0;
unsigned long pos = 0,
count = 0;
ERL_NIF_TERM op, list, shifted, reclaim;
enif_get_tuple(bucket_env, old, &tb_arity, &old_tpl);
new_tpl = (ERL_NIF_TERM*)enif_alloc(tb_arity * sizeof(ERL_NIF_TERM));
memcpy(new_tpl, old_tpl, sizeof(ERL_NIF_TERM) * tb_arity);
it = ops;
ret = enif_make_list(env, 0);
reclaim = enif_make_list(bucket_env, 0);
while(!enif_is_empty_list(env, it)) {
enif_get_list_cell(env, it, &op, &it);
enif_get_tuple(env, op, &op_arity, &op_tpl);
enif_get_ulong(env, op_tpl[0], &pos);
enif_get_ulong(env, op_tpl[1], &count);
if (pos <= 0 || pos > tb_arity) {
ret = enif_make_badarg(env);
goto bailout;
}
if (!enif_is_list(env, new_tpl[pos -1])) {
ret = enif_make_badarg(env);
goto bailout;
}
shifted = enif_make_list(env, 0);
if (count > 0) {
ERL_NIF_TERM copy_it = new_tpl[pos - 1],
val;
int i = 0;
while (i < count && !enif_is_empty_list(bucket_env, copy_it)) {
enif_get_list_cell(bucket_env, copy_it, &val, &copy_it);
++i;
shifted = enif_make_list_cell(env, enif_make_copy(env, val), shifted);
reclaim = enif_make_list_cell(env, val, reclaim);
}
new_tpl[pos - 1] = copy_it;
} else if (count < 0) {
ERL_NIF_TERM copy_it = new_tpl[pos - 1],
val;
while (!enif_is_empty_list(bucket_env, copy_it)) {
enif_get_list_cell(bucket_env, copy_it, &val, &copy_it);
shifted = enif_make_list_cell(env, enif_make_copy(env, val), shifted);
reclaim = enif_make_list_cell(env, val, reclaim);
}
new_tpl[pos - 1] = copy_it;
}
ret = enif_make_list_cell(env, shifted, ret);
}
tb->put(entry_key, enif_make_tuple_from_array(bucket_env, new_tpl, tb_arity));
tb->reclaim(entry_key, reclaim);
bailout:
enif_free(new_tpl);
} else {
ret = enif_make_badarg(env);
}
tb->rwunlock(entry_key);
return ret;
}
ERL_NIF_TERM NeuralTable::Swap(ErlNifEnv *env, ERL_NIF_TERM table, ERL_NIF_TERM key, ERL_NIF_TERM ops) {
NeuralTable *tb;
ERL_NIF_TERM ret, old, it;
unsigned long int entry_key;
ErlNifEnv *bucket_env;
tb = GetTable(env, table);
if (tb == NULL) {
return enif_make_badarg(env);
}
enif_get_ulong(env, key, &entry_key);
tb->rwlock(entry_key);
bucket_env = tb->get_env(entry_key);
if (tb->find(entry_key, old)) {
const ERL_NIF_TERM *old_tpl;
const ERL_NIF_TERM *op_tpl;
ERL_NIF_TERM *new_tpl;
int tb_arity = 0,
op_arity = 0;
unsigned long pos = 0;
ERL_NIF_TERM op, list, shifted, reclaim;
enif_get_tuple(bucket_env, old, &tb_arity, &old_tpl);
new_tpl = (ERL_NIF_TERM*)enif_alloc(tb_arity * sizeof(ERL_NIF_TERM));
memcpy(new_tpl, old_tpl, sizeof(ERL_NIF_TERM) * tb_arity);
it = ops;
ret = enif_make_list(env, 0);
reclaim = enif_make_list(bucket_env, 0);
while (!enif_is_empty_list(env, it)) {
enif_get_list_cell(env, it, &op, &it);
enif_get_tuple(env, op, &op_arity, &op_tpl);
enif_get_ulong(env, op_tpl[0], &pos);
if (pos <= 0 || pos > tb_arity) {
ret = enif_make_badarg(env);
goto bailout;
}
reclaim = enif_make_list_cell(bucket_env, new_tpl[pos - 1], reclaim);
ret = enif_make_list_cell(env, enif_make_copy(env, new_tpl[pos -1]), ret);
new_tpl[pos - 1] = enif_make_copy(bucket_env, op_tpl[1]);
}
tb->put(entry_key, enif_make_tuple_from_array(bucket_env, new_tpl, tb_arity));
tb->reclaim(entry_key, reclaim);
bailout:
enif_free(new_tpl);
} else {
ret = enif_make_badarg(env);
}
tb->rwunlock(entry_key);
return ret;
}
ERL_NIF_TERM NeuralTable::Delete(ErlNifEnv *env, ERL_NIF_TERM table, ERL_NIF_TERM key) {
NeuralTable *tb;
ERL_NIF_TERM val, ret;
unsigned long int entry_key;
tb = GetTable(env, table);
if (tb == NULL) { return enif_make_badarg(env); }
enif_get_ulong(env, key, &entry_key);
tb->rwlock(entry_key);
if (tb->erase(entry_key, val)) {
tb->reclaim(entry_key, val);
ret = enif_make_copy(env, val);
} else {
ret = enif_make_atom(env, "undefined");
}
tb->rwunlock(entry_key);
return ret;
}
ERL_NIF_TERM NeuralTable::Empty(ErlNifEnv *env, ERL_NIF_TERM table) {
NeuralTable *tb;
int n = 0;
tb = GetTable(env, table);
if (tb == NULL) { return enif_make_badarg(env); }
// First, lock EVERY bucket. We want this to be an isolated operation.
for (n = 0; n < BUCKET_COUNT; ++n) {
enif_rwlock_rwlock(tb->locks[n]);
}
// Now clear the table
for (n = 0; n < BUCKET_COUNT; ++n) {
tb->hash_buckets[n].clear();
enif_clear_env(tb->env_buckets[n]);
tb->garbage_cans[n] = 0;
tb->reclaimable[n] = enif_make_list(tb->env_buckets[n], 0);
}
// Now unlock every bucket.
for (n = 0; n < BUCKET_COUNT; ++n) {
enif_rwlock_rwunlock(tb->locks[n]);
}
return enif_make_atom(env, "ok");
}
ERL_NIF_TERM NeuralTable::Get(ErlNifEnv *env, ERL_NIF_TERM table, ERL_NIF_TERM key) {
NeuralTable *tb;
ERL_NIF_TERM ret, val;
unsigned long int entry_key;
// Acquire table handle, or quit if the table doesn't exist.
tb = GetTable(env, table);
if (tb == NULL) { return enif_make_badarg(env); }
// Get key value
enif_get_ulong(env, key, &entry_key);
// Lock the key
tb->rlock(entry_key);
// Read current value
if (!tb->find(entry_key, val)) {
ret = enif_make_atom(env, "undefined");
} else {
ret = enif_make_copy(env, val);
}
tb->runlock(entry_key);
return ret;
}
ERL_NIF_TERM NeuralTable::Dump(ErlNifEnv *env, ERL_NIF_TERM table) {
NeuralTable *tb = GetTable(env, table);
ErlNifPid self;
ERL_NIF_TERM ret;
if (tb == NULL) { return enif_make_badarg(env); }
enif_self(env, &self);
tb->add_batch_job(self, &NeuralTable::batch_dump);
return enif_make_atom(env, "$neural_batch_wait");
}
ERL_NIF_TERM NeuralTable::Drain(ErlNifEnv *env, ERL_NIF_TERM table) {
NeuralTable *tb = GetTable(env, table);
ErlNifPid self;
int ret;
if (tb == NULL) { return enif_make_badarg(env); }
enif_self(env, &self);
tb->add_batch_job(self, &NeuralTable::batch_drain);
return enif_make_atom(env, "$neural_batch_wait");
}
ERL_NIF_TERM NeuralTable::GetKeyPosition(ErlNifEnv *env, ERL_NIF_TERM table) {
NeuralTable *tb = GetTable(env, table);
if (tb == NULL) { return enif_make_badarg(env); }
return enif_make_uint(env, tb->key_pos);
}
ERL_NIF_TERM NeuralTable::GarbageCollect(ErlNifEnv *env, ERL_NIF_TERM table) {
NeuralTable *tb = GetTable(env, table);
if (tb == NULL) { return enif_make_badarg(env); }
enif_cond_signal(tb->gc_cond);
return enif_make_atom(env, "ok");
}
ERL_NIF_TERM NeuralTable::GarbageSize(ErlNifEnv *env, ERL_NIF_TERM table) {
NeuralTable *tb = GetTable(env, table);
unsigned long int size = 0;
if (tb == NULL) { return enif_make_badarg(env); }
size = tb->garbage_size();
return enif_make_ulong(env, size);
}
void* NeuralTable::DoGarbageCollection(void *table) {
NeuralTable *tb = (NeuralTable*)table;
enif_mutex_lock(tb->gc_mutex);
while (running.load(memory_order_acquire)) {
while (running.load(memory_order_acquire) && tb->garbage_size() < RECLAIM_THRESHOLD) {
enif_cond_wait(tb->gc_cond, tb->gc_mutex);
}
tb->gc();
}
enif_mutex_unlock(tb->gc_mutex);
return NULL;
}
void* NeuralTable::DoReclamation(void *table) {
const int max_eat = 5;
NeuralTable *tb = (NeuralTable*)table;
int i = 0, c = 0, t = 0;;
ERL_NIF_TERM tl, hd;
ErlNifEnv *env;
while (running.load(memory_order_acquire)) {
for (i = 0; i < BUCKET_COUNT; ++i) {
c = 0;
t = 0;
tb->rwlock(i);
env = tb->get_env(i);
tl = tb->reclaimable[i];
while (c++ < max_eat && !enif_is_empty_list(env, tl)) {
enif_get_list_cell(env, tl, &hd, &tl);
tb->garbage_cans[i] += estimate_size(env, hd);
t += tb->garbage_cans[i];
}
tb->rwunlock(i);
if (t >= RECLAIM_THRESHOLD) {
enif_cond_signal(tb->gc_cond);
}
}
#ifdef _WIN32
Sleep(50);
#else
usleep(50000);
#endif
}
return NULL;
}
void* NeuralTable::DoBatchOperations(void *table) {
NeuralTable *tb = (NeuralTable*)table;
enif_mutex_lock(tb->batch_mutex);
while (running.load(memory_order_acquire)) {
while (running.load(memory_order_acquire) && tb->batch_jobs.empty()) {
enif_cond_wait(tb->batch_cond, tb->batch_mutex);
}
BatchJob job = tb->batch_jobs.front();
(tb->*job.fun)(job.pid);
tb->batch_jobs.pop();
}
enif_mutex_unlock(tb->batch_mutex);
return NULL;
}
void NeuralTable::start_gc() {
int ret;
gc_mutex = enif_mutex_create("neural_table_gc");
gc_cond = enif_cond_create("neural_table_gc");
ret = enif_thread_create("neural_garbage_collector", &gc_tid, NeuralTable::DoGarbageCollection, (void*)this, NULL);
if (ret != 0) {
printf("[neural_gc] Can't create GC thread. Error Code: %d\r\n", ret);
}
// Start the reclaimer after the garbage collector.
ret = enif_thread_create("neural_reclaimer", &rc_tid, NeuralTable::DoReclamation, (void*)this, NULL);
if (ret != 0) {
printf("[neural_gc] Can't create reclamation thread. Error Code: %d\r\n", ret);
}
}
void NeuralTable::stop_gc() {
enif_cond_signal(gc_cond);
// Join the reclaimer before the garbage collector.
enif_thread_join(rc_tid, NULL);
enif_thread_join(gc_tid, NULL);
}
void NeuralTable::start_batch() {
int ret;
batch_mutex = enif_mutex_create("neural_table_batch");
batch_cond = enif_cond_create("neural_table_batch");
ret = enif_thread_create("neural_batcher", &batch_tid, NeuralTable::DoBatchOperations, (void*)this, NULL);
if (ret != 0) {
printf("[neural_batch] Can't create batch thread. Error Code: %d\r\n", ret);
}
}
void NeuralTable::stop_batch() {
enif_cond_signal(batch_cond);
enif_thread_join(batch_tid, NULL);
}
void NeuralTable::put(unsigned long int key, ERL_NIF_TERM tuple) {
ErlNifEnv *env = get_env(key);
hash_buckets[GET_BUCKET(key)][key] = enif_make_copy(env, tuple);
}
ErlNifEnv* NeuralTable::get_env(unsigned long int key) {
return env_buckets[GET_BUCKET(key)];
}
bool NeuralTable::find(unsigned long int key, ERL_NIF_TERM &ret) {
hash_table *bucket = &hash_buckets[GET_BUCKET(key)];
hash_table::iterator it = bucket->find(key);
if (bucket->end() == it) {
return false;
} else {
ret = it->second;
return true;
}
}
bool NeuralTable::erase(unsigned long int key, ERL_NIF_TERM &val) {
hash_table *bucket = &hash_buckets[GET_BUCKET(key)];
hash_table::iterator it = bucket->find(key);
bool ret = false;
if (it != bucket->end()) {
ret = true;
val = it->second;
bucket->erase(it);
}
return ret;
}
void NeuralTable::add_batch_job(ErlNifPid pid, BatchFunction fun) {
BatchJob job;
job.pid = pid;
job.fun = fun;
enif_mutex_lock(batch_mutex);
batch_jobs.push(job);
enif_mutex_unlock(batch_mutex);
enif_cond_signal(batch_cond);
}
void NeuralTable::batch_drain(ErlNifPid pid) {
ErlNifEnv *env = enif_alloc_env();
ERL_NIF_TERM msg, value;
value = enif_make_list(env, 0);
for (int i = 0; i < BUCKET_COUNT; ++i) {
enif_rwlock_rwlock(locks[i]);
for (hash_table::iterator it = hash_buckets[i].begin(); it != hash_buckets[i].end(); ++it) {
value = enif_make_list_cell(env, enif_make_copy(env, it->second), value);
}
enif_clear_env(env_buckets[i]);
hash_buckets[i].clear();
garbage_cans[i] = 0;
reclaimable[i] = enif_make_list(env_buckets[i], 0);
enif_rwlock_rwunlock(locks[i]);
}
msg = enif_make_tuple2(env, enif_make_atom(env, "$neural_batch_response"), value);
enif_send(NULL, &pid, env, msg);
enif_free_env(env);
}
void NeuralTable::batch_dump(ErlNifPid pid) {
ErlNifEnv *env = enif_alloc_env();
ERL_NIF_TERM msg, value;
value = enif_make_list(env, 0);
for (int i = 0; i < BUCKET_COUNT; ++i) {
enif_rwlock_rlock(locks[i]);
for (hash_table::iterator it = hash_buckets[i].begin(); it != hash_buckets[i].end(); ++it) {
value = enif_make_list_cell(env, enif_make_copy(env, it->second), value);
}
enif_rwlock_runlock(locks[i]);
}
msg = enif_make_tuple2(env, enif_make_atom(env, "$neural_batch_response"), value);
enif_send(NULL, &pid, env, msg);
enif_free_env(env);
}
void NeuralTable::reclaim(unsigned long int key, ERL_NIF_TERM term) {
int bucket = GET_BUCKET(key);
ErlNifEnv *env = get_env(key);
reclaimable[bucket] = enif_make_list_cell(env, term, reclaimable[bucket]);
}
void NeuralTable::gc() {
ErlNifEnv *fresh = NULL,
*old = NULL;
hash_table *bucket = NULL;
hash_table::iterator it;
unsigned int gc_curr = 0;
for (; gc_curr < BUCKET_COUNT; ++gc_curr) {
bucket = &hash_buckets[gc_curr];
old = env_buckets[gc_curr];
fresh = enif_alloc_env();
enif_rwlock_rwlock(locks[gc_curr]);
for (it = bucket->begin(); it != bucket->end(); ++it) {
it->second = enif_make_copy(fresh, it->second);
}
garbage_cans[gc_curr] = 0;
env_buckets[gc_curr] = fresh;
reclaimable[gc_curr] = enif_make_list(fresh, 0);
enif_free_env(old);
enif_rwlock_rwunlock(locks[gc_curr]);
}
}
unsigned long int NeuralTable::garbage_size() {
unsigned long int size = 0;
for (int i = 0; i < BUCKET_COUNT; ++i) {
enif_rwlock_rlock(locks[i]);
size += garbage_cans[i];
enif_rwlock_runlock(locks[i]);
}
return size;
}

+ 0
- 121
c_src/neural/NeuralTable.h View File

@ -1,121 +0,0 @@
#ifndef NEURALTABLE_H
#define NEURALTABLE_H
#include "erl_nif.h"
#include "neural_utils.h"
#include <string>
#include <stdio.h>
#include <string.h>
#include <unordered_map>
#include <queue>
#include <atomic>
#ifdef _WIN32
#include <windows.h>
#include <io.h>
#include <process.h>
#else
#include <unistd.h>
#endif
#define BUCKET_COUNT 64
#define BUCKET_MASK (BUCKET_COUNT - 1)
#define GET_BUCKET(key) key & BUCKET_MASK
#define GET_LOCK(key) key & BUCKET_MASK
#define RECLAIM_THRESHOLD 1048576
using namespace std;
class NeuralTable;
typedef unordered_map<string, NeuralTable*> table_set;
typedef unordered_map<unsigned long int, ERL_NIF_TERM> hash_table;
typedef void (NeuralTable::*BatchFunction)(ErlNifPid pid);
class NeuralTable {
public:
static ERL_NIF_TERM MakeTable(ErlNifEnv *env, ERL_NIF_TERM name, ERL_NIF_TERM keypos);
static ERL_NIF_TERM Insert(ErlNifEnv *env, ERL_NIF_TERM table, ERL_NIF_TERM key, ERL_NIF_TERM object);
static ERL_NIF_TERM InsertNew(ErlNifEnv *env, ERL_NIF_TERM table, ERL_NIF_TERM key, ERL_NIF_TERM object);
static ERL_NIF_TERM Delete(ErlNifEnv *env, ERL_NIF_TERM table, ERL_NIF_TERM key);
static ERL_NIF_TERM Empty(ErlNifEnv *env, ERL_NIF_TERM table);
static ERL_NIF_TERM Get(ErlNifEnv *env, ERL_NIF_TERM table, ERL_NIF_TERM key);
static ERL_NIF_TERM Increment(ErlNifEnv *env, ERL_NIF_TERM table, ERL_NIF_TERM key, ERL_NIF_TERM ops);
static ERL_NIF_TERM Shift(ErlNifEnv *env, ERL_NIF_TERM table, ERL_NIF_TERM key, ERL_NIF_TERM ops);
static ERL_NIF_TERM Unshift(ErlNifEnv *env, ERL_NIF_TERM table, ERL_NIF_TERM key, ERL_NIF_TERM ops);
static ERL_NIF_TERM Swap(ErlNifEnv *env, ERL_NIF_TERM table, ERL_NIF_TERM key, ERL_NIF_TERM ops);
static ERL_NIF_TERM Dump(ErlNifEnv *env, ERL_NIF_TERM table);
static ERL_NIF_TERM Drain(ErlNifEnv *env, ERL_NIF_TERM table);
static ERL_NIF_TERM GetKeyPosition(ErlNifEnv *env, ERL_NIF_TERM table);
static ERL_NIF_TERM GarbageCollect(ErlNifEnv *env, ERL_NIF_TERM table);
static ERL_NIF_TERM GarbageSize(ErlNifEnv *env, ERL_NIF_TERM table);
static NeuralTable* GetTable(ErlNifEnv *env, ERL_NIF_TERM name);
static void* DoGarbageCollection(void *table);
static void* DoBatchOperations(void *table);
static void* DoReclamation(void *table);
static void Initialize() {
table_mutex = enif_mutex_create("neural_table_maker");
}
static void Shutdown() {
running = false;
table_set::iterator it(tables.begin());
while (it != tables.end()) {
delete it->second;
tables.erase(it);
it = tables.begin();
}
enif_mutex_destroy(table_mutex);
}
void rlock(unsigned long int key) { enif_rwlock_rlock(locks[GET_LOCK(key)]); }
void runlock(unsigned long int key) { enif_rwlock_runlock(locks[GET_LOCK(key)]); }
void rwlock(unsigned long int key) { enif_rwlock_rwlock(locks[GET_LOCK(key)]); }
void rwunlock(unsigned long int key) { enif_rwlock_rwunlock(locks[GET_LOCK(key)]); }
ErlNifEnv *get_env(unsigned long int key);
bool erase(unsigned long int key, ERL_NIF_TERM &ret);
bool find(unsigned long int key, ERL_NIF_TERM &ret);
void put(unsigned long int key, ERL_NIF_TERM tuple);
void batch_dump(ErlNifPid pid);
void batch_drain(ErlNifPid pid);
void start_gc();
void stop_gc();
void start_batch();
void stop_batch();
void gc();
void reclaim(unsigned long int key, ERL_NIF_TERM reclaim);
unsigned long int garbage_size();
void add_batch_job(ErlNifPid pid, BatchFunction fun);
protected:
static table_set tables;
static atomic<bool> running;
static ErlNifMutex *table_mutex;
struct BatchJob {
ErlNifPid pid;
BatchFunction fun;
};
NeuralTable(unsigned int kp);
~NeuralTable();
unsigned int garbage_cans[BUCKET_COUNT];
hash_table hash_buckets[BUCKET_COUNT];
ErlNifEnv *env_buckets[BUCKET_COUNT];
ERL_NIF_TERM reclaimable[BUCKET_COUNT];
ErlNifRWLock *locks[BUCKET_COUNT];
ErlNifCond *gc_cond;
ErlNifMutex *gc_mutex;
ErlNifTid gc_tid;
ErlNifTid rc_tid;
ErlNifCond *batch_cond;
ErlNifMutex *batch_mutex;
queue<BatchJob> batch_jobs;
ErlNifTid batch_tid;
unsigned int key_pos;
};
#endif

+ 0
- 134
c_src/neural/neural.cpp View File

@ -1,134 +0,0 @@
#include "erl_nif.h"
#include "NeuralTable.h"
#include <stdio.h>
// Prototypes
static ERL_NIF_TERM neural_new(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM neural_put(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM neural_put_new(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM neural_increment(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM neural_unshift(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM neural_shift(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM neural_swap(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM neural_get(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM neural_delete(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM neural_garbage(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM neural_garbage_size(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM neural_empty(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM neural_drain(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM neural_dump(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM neural_key_pos(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]);
static ErlNifFunc nif_funcs[] =
{
{"make_table", 2, neural_new},
{"do_fetch", 2, neural_get},
{"do_delete", 2, neural_delete},
{"do_dump", 1, neural_dump},
{"do_drain", 1, neural_drain},
{"empty", 1, neural_empty},
{"insert", 3, neural_put},
{"insert_new", 3, neural_put_new},
{"do_increment", 3, neural_increment},
{"do_unshift", 3, neural_unshift},
{"do_shift", 3, neural_shift},
{"do_swap", 3, neural_swap},
{"garbage", 1, neural_garbage},
{"garbage_size", 1, neural_garbage_size},
{"key_pos", 1, neural_key_pos}
};
static ERL_NIF_TERM neural_key_pos(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
// This function is directly exposed, so no strict guards or patterns protecting us.
if (argc != 1 || !enif_is_atom(env, argv[0])) { return enif_make_badarg(env); }
return NeuralTable::GetKeyPosition(env, argv[0]);
}
static ERL_NIF_TERM neural_new(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
return NeuralTable::MakeTable(env, argv[0], argv[1]);
}
static ERL_NIF_TERM neural_put(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
return NeuralTable::Insert(env, argv[0], argv[1], argv[2]);
}
static ERL_NIF_TERM neural_put_new(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
return NeuralTable::InsertNew(env, argv[0], argv[1], argv[2]);
}
static ERL_NIF_TERM neural_increment(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
if (!enif_is_atom(env, argv[0]) || !enif_is_number(env, argv[1]) || !enif_is_list(env, argv[2])) {
return enif_make_badarg(env);
}
return NeuralTable::Increment(env, argv[0], argv[1], argv[2]);
}
static ERL_NIF_TERM neural_shift(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
return NeuralTable::Shift(env, argv[0], argv[1], argv[2]);
}
static ERL_NIF_TERM neural_unshift(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
return NeuralTable::Unshift(env, argv[0], argv[1], argv[2]);
}
static ERL_NIF_TERM neural_swap(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]){
return NeuralTable::Swap(env, argv[0], argv[1], argv[2]);
}
static ERL_NIF_TERM neural_get(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
return NeuralTable::Get(env, argv[0], argv[1]);
}
static ERL_NIF_TERM neural_delete(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
return NeuralTable::Delete(env, argv[0], argv[1]);
}
static ERL_NIF_TERM neural_empty(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
if (!enif_is_atom(env, argv[0])) { return enif_make_badarg(env); }
return NeuralTable::Empty(env, argv[0]);
}
static ERL_NIF_TERM neural_dump(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
if (!enif_is_atom(env, argv[0])) { return enif_make_badarg(env); }
return NeuralTable::Dump(env, argv[0]);
}
static ERL_NIF_TERM neural_drain(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
if (!enif_is_atom(env, argv[0])) { return enif_make_badarg(env); }
return NeuralTable::Drain(env, argv[0]);
}
static ERL_NIF_TERM neural_garbage(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
if (!enif_is_atom(env, argv[0])) { return enif_make_badarg(env); }
return NeuralTable::GarbageCollect(env, argv[0]);
}
static ERL_NIF_TERM neural_garbage_size(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
if (!enif_is_atom(env, argv[0])) { return enif_make_badarg(env); }
return NeuralTable::GarbageSize(env, argv[0]);
}
static void neural_resource_cleanup(ErlNifEnv* env, void* arg)
{
/* Delete any dynamically allocated memory stored in neural_handle */
/* neural_handle* handle = (neural_handle*)arg; */
}
static int on_load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
{
NeuralTable::Initialize();
return 0;
}
static void on_unload(ErlNifEnv *env, void *priv_data) {
NeuralTable::Shutdown();
}
ERL_NIF_INIT(neural, nif_funcs, &on_load, NULL, NULL, &on_unload);

+ 0
- 46
c_src/neural/neural_utils.cpp View File

@ -1,46 +0,0 @@
#include "neural_utils.h"
unsigned long int estimate_size(ErlNifEnv *env, ERL_NIF_TERM term) {
if (enif_is_atom(env, term)) {
return WORD_SIZE;
}
// Treating all numbers like longs.
if (enif_is_number(env, term)) {
return 2 * WORD_SIZE;
}
if (enif_is_binary(env, term)) {
ErlNifBinary bin;
enif_inspect_binary(env, term, &bin);
return bin.size + (6 * WORD_SIZE);
}
if (enif_is_list(env, term)) {
unsigned long int size = 0;
ERL_NIF_TERM it, curr;
it = term;
size += WORD_SIZE;
while (!enif_is_empty_list(env, it)) {
enif_get_list_cell(env, it, &curr, &it);
size += estimate_size(env, curr) + WORD_SIZE;
}
return size;
}
if (enif_is_tuple(env, term)) {
unsigned long int size = 0;
const ERL_NIF_TERM *tpl;
int arity;
enif_get_tuple(env, term, &arity, &tpl);
for (int i = 0; i < arity; ++i) {
size += estimate_size(env, tpl[i]);
}
return size;
}
// Return 1 word by default
return WORD_SIZE;
}

+ 0
- 9
c_src/neural/neural_utils.h View File

@ -1,9 +0,0 @@
#ifndef NEURAL_UTILS_H
#define NEURAL_UTILS_H
#include "erl_nif.h"
#define WORD_SIZE sizeof(int)
unsigned long int estimate_size(ErlNifEnv *env, ERL_NIF_TERM term);
#endif

+ 0
- 14
c_src/neural/rebar.config View File

@ -1,14 +0,0 @@
{port_specs, [
{"../../priv/neural.so", ["*.cpp"]}
]}.
{port_env, [
{".*", "CXXFLAGS", "$CXXFLAGS -std=c++11 -O3"},
{".*", "LDFLAGS", "$LDFLAGS -lstdc++ -shared"}
]}.

+ 0
- 111
c_src/nif_array/binary_tools.c View File

@ -1,111 +0,0 @@
#include "erl_nif.h"
#include <stdio.h>
#include <string.h>
static ErlNifResourceType* test_RESOURCE = NULL;
// Prototypes
static ERL_NIF_TERM get_bin_address(ErlNifEnv* env, int argc,
const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM new_array(ErlNifEnv* env, int argc,
const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM size_array(ErlNifEnv* env, int argc,
const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM put_array(ErlNifEnv* env, int argc,
const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM get_array(ErlNifEnv* env, int argc,
const ERL_NIF_TERM argv[]);
static ErlNifFunc nif_funcs[] =
{
{"get_bin_address", 1, get_bin_address},
{"new_array", 1, new_array},
{"size_array", 1, size_array},
{"put_array", 3, put_array},
{"get_array", 2, get_array}
};
static ERL_NIF_TERM get_bin_address(ErlNifEnv* env, int argc,
const ERL_NIF_TERM argv[])
{
ErlNifBinary bin;
enif_inspect_binary(env, argv[0], &bin);
char buf[256];
sprintf(buf, "bin: size=%zu, ptr=%p", bin.size, bin.data);
return enif_make_string(env, buf, ERL_NIF_LATIN1);
}
static ERL_NIF_TERM new_array(ErlNifEnv* env, int argc,
const ERL_NIF_TERM argv[])
{
ErlNifBinary bin;
unsigned long size;
// unsigned char* data;
enif_get_ulong(env, argv[0], &size);
// enif_inspect_binary(env, argv[1], &bin);
enif_alloc_binary(size * sizeof(long), &bin);
return enif_make_binary(env, &bin);
}
static ERL_NIF_TERM size_array(ErlNifEnv* env, int argc,
const ERL_NIF_TERM argv[])
{
ErlNifBinary bin;
enif_inspect_binary(env, argv[0], &bin);
return enif_make_int64(env, bin.size);
}
static ERL_NIF_TERM put_array(ErlNifEnv* env, int argc,
const ERL_NIF_TERM argv[])
{
ErlNifBinary bin;
unsigned long* array;
unsigned long pos, value;
enif_get_ulong(env, argv[0], &pos);
enif_get_ulong(env, argv[1], &value);
enif_inspect_binary(env, argv[2], &bin);
array = (unsigned long*)bin.data;
array[pos] = value;
return enif_make_atom(env, "ok");
}
static ERL_NIF_TERM get_array(ErlNifEnv* env, int argc,
const ERL_NIF_TERM argv[])
{
ErlNifBinary bin;
unsigned long* array;
unsigned long pos;
enif_get_ulong(env, argv[0], &pos);
enif_inspect_binary(env, argv[1], &bin);
array = (unsigned long*)bin.data;
return enif_make_int64(env, *(array + pos));
}
static void test_resource_cleanup(ErlNifEnv* env, void* arg)
{
/* Delete any dynamically allocated memory stored in test_handle */
/* test_handle* handle = (test_handle*)arg; */
}
static int on_load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
{
ErlNifResourceFlags flags = ERL_NIF_RT_CREATE | ERL_NIF_RT_TAKEOVER;
ErlNifResourceType* rt = enif_open_resource_type(env, NULL,
"test_resource",
&test_resource_cleanup,
flags, NULL);
if (rt == NULL)
return -1;
test_RESOURCE = rt;
return 0;
}
ERL_NIF_INIT(binary_tools, nif_funcs, &on_load, NULL, NULL, NULL);

+ 0
- 13
c_src/nif_array/rebar.config View File

@ -1,13 +0,0 @@
{port_specs, [
{"../../priv/binary_tools.so", ["*.c"]}
]}.
{port_env, [
{"linux", "CFLAGS", "$CFLAGS -Wall -O2 -Wpointer-sign"}
]}.

BIN
priv/binary_tools.dll View File


BIN
priv/binary_tools.exp View File


BIN
priv/binary_tools.lib View File


BIN
priv/binary_tools.so View File


BIN
priv/bitmap_filter.dll View File


BIN
priv/bitmap_filter.exp View File


BIN
priv/bitmap_filter.lib View File


BIN
priv/bitmap_filter.so View File


BIN
priv/bsn_ext.dll View File


BIN
priv/bsn_ext.exp View File


BIN
priv/bsn_ext.lib View File


BIN
priv/bsn_ext.so View File


BIN
priv/bsn_int.dll View File


BIN
priv/bsn_int.exp View File


BIN
priv/bsn_int.lib View File


BIN
priv/bsn_int.so View File


BIN
priv/btreelru_nif.dll View File


BIN
priv/btreelru_nif.exp View File


BIN
priv/btreelru_nif.lib View File


BIN
priv/btreelru_nif.so View File


BIN
priv/cbase64.dll View File


BIN
priv/enlfq.dll View File


BIN
priv/enlfq.exp View File


BIN
priv/enlfq.lib View File


BIN
priv/enlfq.so View File


BIN
priv/epqueue_nif.dll View File


BIN
priv/etsq.dll View File


BIN
priv/etsq.exp View File


BIN
priv/etsq.lib View File


BIN
priv/etsq.so View File


BIN
priv/hqueue.dll View File


BIN
priv/khash.dll View File


BIN
priv/khash2.dll View File


BIN
priv/khash2.exp View File


BIN
priv/khash2.lib View File


BIN
priv/khash2.so View File


BIN
priv/mqtree.so View File


BIN
priv/native_array_nif.dll View File


BIN
priv/native_array_nif.exp View File


BIN
priv/native_array_nif.lib View File


BIN
priv/native_array_nif.so View File


BIN
priv/neural.dll View File


BIN
priv/neural.exp View File


BIN
priv/neural.lib View File


BIN
priv/neural.so View File


BIN
priv/nifArray.dll View File


BIN
priv/nifHashb.dll View File


BIN
priv/nifHashb.exp View File


BIN
priv/nifHashb.lib View File


BIN
priv/nif_skiplist.dll View File


+ 0
- 20
src/nifSrc/bitmap_filter/bitmap_filter.erl View File

@ -1,20 +0,0 @@
-module(bitmap_filter).
-export([init/0, filter/1]).
-on_load(init/0).
init() ->
PrivDir = case code:priv_dir(?MODULE) of
{error, _} ->
EbinDir = filename:dirname(code:which(?MODULE)),
AppPath = filename:dirname(EbinDir),
filename:join(AppPath, "priv");
Path ->
Path
end,
erlang:load_nif(filename:join(PrivDir, "bitmap_filter"), 0).
% Hack - overriden by init, which is called in on_load.
% I couldn't find another way that the compiler or code load didn't complain about.
filter(DefaultArgs) ->
DefaultArgs.

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save