瀏覽代碼

nif sameple code

master
SisMaker 5 年之前
父節點
當前提交
fd2cf4b19f
共有 19 個檔案被更改,包括 3509 行新增0 行删除
  1. +2
    -0
      .gitignore
  2. +266
    -0
      c_src/cbase64-erlang-nif/cbase64.c
  3. +9
    -0
      c_src/cbase64-erlang-nif/rebar.config
  4. +688
    -0
      c_src/mqtree/mqtree.c
  5. +12
    -0
      c_src/mqtree/rebar.config
  6. +1074
    -0
      c_src/mqtree/uthash.h
  7. +111
    -0
      c_src/nif_array/binary_tools.c
  8. +13
    -0
      c_src/nif_array/rebar.config
  9. +364
    -0
      c_src/nif_skiplist1/nif_skiplist.c
  10. +8
    -0
      c_src/nif_skiplist1/rebar.config
  11. +417
    -0
      c_src/nif_skiplist1/skiplist.c
  12. +55
    -0
      c_src/nif_skiplist1/skiplist.h
  13. +48
    -0
      src/nifSrc/cbase64_erlang_nif/cbase64.erl
  14. +184
    -0
      src/nifSrc/neural/neural.erl
  15. +16
    -0
      src/nifSrc/neural/neural_app.erl
  16. +31
    -0
      src/nifSrc/neural/neural_sup.erl
  17. +60
    -0
      src/nifSrc/nif_array/binary_tools.erl
  18. +70
    -0
      src/nifSrc/nif_skiplist1/nif.erl
  19. +81
    -0
      src/nifSrc/nif_skiplist1/skiplist.erl

+ 2
- 0
.gitignore 查看文件

@ -24,5 +24,7 @@ priv
cmake-build*
CMakeLists.txt
# nif compile temp file
*.pdb
*.d
compile_commands.json

+ 266
- 0
c_src/cbase64-erlang-nif/cbase64.c 查看文件

@ -0,0 +1,266 @@
/* ex: ts=4 sw=4 et
*
* Copyright (c) 2011-2016 Sergey Urbanovich
* http://github.com/urbanserj/cbase64-erlang-nif
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "stdint.h"
#include "erl_nif.h"
#define min(X, Y) ((X) < (Y) ? (X) : (Y))
#define TIMESLICE 10
#define SPEEDUP 30
#define REDUCTIONS 2000
#define ITER (REDUCTIONS * SPEEDUP / TIMESLICE)
static const char cb64[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
inline void encodeblock(const uint8_t in[3], uint8_t out[4], size_t len)
{
out[0] = cb64[ (in[0] >> 2) & 0x3f ];
out[1] = cb64[ ((in[0] << 4) + (--len ? in[1] >> 4 : 0)) & 0x3f ];
out[2] = len ? cb64[ ((in[1] << 2) + (--len ? in[2] >> 6 : 0)) & 0x3f ] : '=';
out[3] = len ? cb64[ in[2] & 0x3f ] : '=';
}
static ERL_NIF_TERM encode(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
ERL_NIF_TERM tdst, tsrc;
ErlNifBinary src, dst;
if ( enif_inspect_binary(env, argv[0], &src) ) {
tsrc = argv[0];
} else if ( enif_inspect_iolist_as_binary(env, argv[0], &src) ) {
tsrc = enif_make_binary(env, &src);
} else {
return enif_make_badarg(env);
}
if (src.size == 0) {
return argv[0];
}
uint8_t *data;
size_t size = (src.size + 2) / 3 * 4;
if (argc == 1) {
data = enif_make_new_binary(env, size, &tdst);
} else {
tdst = argv[1];
if ( !enif_inspect_binary(env, argv[1], &dst) ) {
return enif_make_badarg(env);
}
data = dst.data;
}
int i = size / 4 - 1;
if (argc == 3) {
if ( !enif_get_int(env, argv[2], &i) ) {
return enif_make_badarg(env);
}
} else {
/* last block */
encodeblock(src.data + i * 3, data + i * 4, src.size - i * 3);
i--;
}
int reductions = 0;
for (; i >= 0; i--) {
encodeblock(src.data + i * 3, data + i * 4, 3);
reductions += 3;
if (reductions >= ITER) {
if (enif_consume_timeslice(env, TIMESLICE)) {
ERL_NIF_TERM schargv[3] = {tsrc, tdst, enif_make_int(env, i)};
return enif_schedule_nif(env, "encode", 0, &encode, 3, schargv);
}
reductions = 0;
}
}
return tdst;
}
#define DECODE_ERROR 0xff
#define DECODE_OK 0x00
#define B64(_) \
( (_) >= 'A' && (_) <= 'Z' ? 25 - 'Z' + (_) : \
(_) >= 'a' && (_) <= 'z' ? 51 - 'z' + (_) : \
(_) >= '0' && (_) <= '9' ? 61 - '9' + (_) : \
(_) == '+' ? 62 : (_) ? 63 : DECODE_ERROR )
static const int cd64[256] = {
B64( 0), B64( 1), B64( 2), B64( 3), B64( 4), B64( 5), B64( 6), B64( 7),
B64( 8), B64( 9), B64( 10), B64( 11), B64( 12), B64( 13), B64( 14), B64( 15),
B64( 16), B64( 17), B64( 18), B64( 19), B64( 20), B64( 21), B64( 22), B64( 23),
B64( 24), B64( 25), B64( 26), B64( 27), B64( 28), B64( 29), B64( 30), B64( 31),
B64( 32), B64( 33), B64( 34), B64( 35), B64( 36), B64( 37), B64( 38), B64( 39),
B64( 40), B64( 41), B64( 42), B64( 43), B64( 44), B64( 45), B64( 46), B64( 47),
B64( 48), B64( 49), B64( 50), B64( 51), B64( 52), B64( 53), B64( 54), B64( 55),
B64( 56), B64( 57), B64( 58), B64( 59), B64( 60), B64( 61), B64( 62), B64( 63),
B64( 64), B64( 65), B64( 66), B64( 67), B64( 68), B64( 69), B64( 70), B64( 71),
B64( 72), B64( 73), B64( 74), B64( 75), B64( 76), B64( 77), B64( 78), B64( 79),
B64( 80), B64( 81), B64( 82), B64( 83), B64( 84), B64( 85), B64( 86), B64( 87),
B64( 88), B64( 89), B64( 90), B64( 91), B64( 92), B64( 93), B64( 94), B64( 95),
B64( 96), B64( 97), B64( 98), B64( 99), B64(100), B64(101), B64(102), B64(103),
B64(104), B64(105), B64(106), B64(107), B64(108), B64(109), B64(110), B64(111),
B64(112), B64(113), B64(114), B64(115), B64(116), B64(117), B64(118), B64(119),
B64(120), B64(121), B64(122), B64(123), B64(124), B64(125), B64(126), B64(127),
B64(128), B64(129), B64(130), B64(131), B64(132), B64(133), B64(134), B64(135),
B64(136), B64(137), B64(138), B64(139), B64(140), B64(141), B64(142), B64(143),
B64(144), B64(145), B64(146), B64(147), B64(148), B64(149), B64(150), B64(151),
B64(152), B64(153), B64(154), B64(155), B64(156), B64(157), B64(158), B64(159),
B64(160), B64(161), B64(162), B64(163), B64(164), B64(165), B64(166), B64(167),
B64(168), B64(169), B64(170), B64(171), B64(172), B64(173), B64(174), B64(175),
B64(176), B64(177), B64(178), B64(179), B64(180), B64(181), B64(182), B64(183),
B64(184), B64(185), B64(186), B64(187), B64(188), B64(189), B64(190), B64(191),
B64(192), B64(193), B64(194), B64(195), B64(196), B64(197), B64(198), B64(199),
B64(200), B64(201), B64(202), B64(203), B64(204), B64(205), B64(206), B64(207),
B64(208), B64(209), B64(210), B64(211), B64(212), B64(213), B64(214), B64(215),
B64(216), B64(217), B64(218), B64(219), B64(220), B64(221), B64(222), B64(223),
B64(224), B64(225), B64(226), B64(227), B64(228), B64(229), B64(230), B64(231),
B64(232), B64(233), B64(234), B64(235), B64(236), B64(237), B64(238), B64(239),
B64(240), B64(241), B64(242), B64(243), B64(244), B64(245), B64(246), B64(247),
B64(248), B64(249), B64(250), B64(251), B64(252), B64(253), B64(254), B64(255)
};
inline uint8_t decodeblock(const uint8_t in[4], uint8_t out[3])
{
int code;
size_t it = 0;
unsigned int val = 0;
for (;it < 4; ++it) {
if ( (code = cd64[in[it]]) == DECODE_ERROR )
return DECODE_ERROR;
val = (val << 6) + code;
}
out[0] = (val >> 16) & 0xff;
out[1] = (val >> 8) & 0xff;
out[2] = val & 0xff;
return DECODE_OK;
}
inline uint8_t decodeblock_tail(const uint8_t in[4], uint8_t out[3])
{
int code;
size_t it = 0;
unsigned int val = 0;
if ( in[0] == '=' || in[1] == '=' ||
(in[2] == '=' && in[3] != '=') )
return DECODE_ERROR;
for (;it < 4; ++it) {
val <<= 6;
if ( in[it] == '=' )
continue;
if ( (code = cd64[in[it]]) == DECODE_ERROR )
return DECODE_ERROR;
val += code;
}
out[0] = (val >> 16) & 0xff;
if ( in[2] != '=' )
out[1] = (val >> 8) & 0xff;
if ( in[3] != '=' )
out[2] = val & 0xff;
return DECODE_OK;
}
static ERL_NIF_TERM decode(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
ERL_NIF_TERM tdst, tsrc;
ErlNifBinary src, dst;
if ( enif_inspect_binary(env, argv[0], &src) ) {
tsrc = argv[0];
} else if ( enif_inspect_iolist_as_binary(env, argv[0], &src) ) {
tsrc = enif_make_binary(env, &src);
} else {
return enif_make_badarg(env);
}
if (src.size == 0) {
return argv[0];
}
if (src.size % 4 != 0) {
return enif_make_badarg(env);
}
uint8_t *data;
size_t size =
src.size/4*3
- (src.data[src.size - 1] == '=' ? 1 : 0)
- (src.data[src.size - 2] == '=' ? 1 : 0);
if (argc == 1) {
data = enif_make_new_binary(env, size, &tdst);
} else {
tdst = argv[1];
if ( !enif_inspect_binary(env, argv[1], &dst) ) {
return enif_make_badarg(env);
}
data = dst.data;
}
int i = src.size / 4 - 1;
if (argc == 3) {
if ( !enif_get_int(env, argv[2], &i) ) {
return enif_make_badarg(env);
}
} else {
/* last block */
if ( decodeblock_tail(src.data + i*4, data + i*3) ) {
return enif_make_badarg(env);
}
i--;
}
int reductions = 0;
for (; i >= 0; i--) {
if ( decodeblock(src.data + i*4, data + i*3) ) {
return enif_make_badarg(env);
}
reductions += 4;
if (reductions >= ITER) {
if (enif_consume_timeslice(env, TIMESLICE)) {
ERL_NIF_TERM schargv[3] = {tsrc, tdst, enif_make_int(env, i)};
return enif_schedule_nif(env, "decode", 0, &decode, 3, schargv);
}
reductions = 0;
}
}
return tdst;
}
static ErlNifFunc nif_funcs[] =
{
{"encode", 1, encode},
{"decode", 1, decode}
};
ERL_NIF_INIT(cbase64, nif_funcs, NULL, NULL, NULL, NULL)

+ 9
- 0
c_src/cbase64-erlang-nif/rebar.config 查看文件

@ -0,0 +1,9 @@
{port_specs, [
{"../../priv/cbase64.so", ["*.c"]}
]}.
{port_env, [{".*", "CFLAGS", "$CFLAGS -Wall -O2"}]}.

+ 688
- 0
c_src/mqtree/mqtree.c 查看文件

@ -0,0 +1,688 @@
/*
* @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)

+ 12
- 0
c_src/mqtree/rebar.config 查看文件

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

+ 1074
- 0
c_src/mqtree/uthash.h
文件差異過大導致無法顯示
查看文件


+ 111
- 0
c_src/nif_array/binary_tools.c 查看文件

@ -0,0 +1,111 @@
#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);

+ 13
- 0
c_src/nif_array/rebar.config 查看文件

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

+ 364
- 0
c_src/nif_skiplist1/nif_skiplist.c 查看文件

@ -0,0 +1,364 @@
//
// Created by fox on 2017/8/10.
//
#ifndef USENIF
#define USENIF 1
#endif
#include <string.h>
#include "erl_nif.h"
#include "skiplist.h"
// all pointer to skiplist would be stored here
static skiplist **p_array;
static size_t p_array_size = 0;
#define enif_get_value enif_get_int
#define enif_make_value enif_make_int
// store a new pointer
int store_new_pointer(skiplist *p)
{
if (p_array_size == 0) {
// init it
p_array_size = 2;
p_array = (skiplist **)icalloc(p_array_size * sizeof(skiplist *));
p_array[0] = p;
return 0;
}
// find the empty pos
for (int i = 0; i < p_array_size; ++i) {
if (p_array[i] == NULL) {
p_array[i] = p;
return i;
}
}
// reallocate array
size_t old_size = p_array_size;
p_array_size *= 2;
p_array = (skiplist **)realloc(p_array, sizeof(skiplist *) * p_array_size);
memset(p_array+old_size, 0, sizeof(skiplist *) * old_size);
p_array[old_size] = p;
return (int)old_size;
}
inline skiplist *get_pointer(ErlNifEnv* env, ERL_NIF_TERM arg);
skiplist *get_pointer(ErlNifEnv* env, ERL_NIF_TERM arg)
{
int index;
if (!enif_get_int(env, arg, &index))
return NULL;
if (0 <= index && index < p_array_size)
return p_array[index];
return NULL;
}
static ERL_NIF_TERM new(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
skiplist *list = skiplist_init();
int pointer_pos = store_new_pointer(list);
ERL_NIF_TERM res = enif_make_int(env, pointer_pos);
return res;
}
static ERL_NIF_TERM free1(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
int index;
if (!enif_get_int(env, argv[0], &index))
return enif_make_badarg(env);
if (index < 0 || index >= p_array_size)
return enif_make_badarg(env);
skiplist_free(p_array[index]);
p_array[index] = NULL;
ERL_NIF_TERM res;
enif_make_existing_atom(env, "ok", &res, ERL_NIF_LATIN1);
return res;
}
static ERL_NIF_TERM insert(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
skiplist *list = get_pointer(env, argv[0]);
if (!list)
return enif_make_badarg(env);
int score;
vtype value;
if (!enif_get_int(env, argv[1], &score))
return enif_make_badarg(env);
if (!enif_get_value(env, argv[2], &value))
return enif_make_badarg(env);
int res0 = skiplist_insert(list, score, value);
ERL_NIF_TERM res = enif_make_int(env, res0);
return res;
}
static ERL_NIF_TERM update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
skiplist *list = get_pointer(env, argv[0]);
if (!list)
return enif_make_badarg(env);
int score, old_score;
vtype value;
if (!enif_get_int(env, argv[1], &score))
return enif_make_badarg(env);
if (!enif_get_value(env, argv[2], &value))
return enif_make_badarg(env);
if (!enif_get_int(env, argv[3], &old_score))
return enif_make_badarg(env);
int res0 = skiplist_update(list, score, value, old_score);
ERL_NIF_TERM res = enif_make_int(env, res0);
return res;
}
static ERL_NIF_TERM delete(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
skiplist *list = get_pointer(env, argv[0]);
if (!list)
return enif_make_badarg(env);
int socre;
vtype value;
if (!enif_get_int(env, argv[1], &socre))
return enif_make_badarg(env);
if (!enif_get_value(env, argv[2], &value))
return enif_make_badarg(env);
int res0 = skiplist_delete(list, socre, value);
ERL_NIF_TERM res = enif_make_int(env, res0);
return res;
}
static ERL_NIF_TERM to_list(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
skiplist *list = get_pointer(env, argv[0]);
if (!list)
return enif_make_badarg(env);
snode *x = list->header->level[0].forward;
snode **nodes = (snode **)malloc(sizeof(snode *) * (list->size + 1));
while (x) {
*nodes = x;
++nodes;
x = x->level[0].forward;
}
ERL_NIF_TERM res = enif_make_list(env, 0);
for (int i = list->size-1; i >= 0; --i) {
--nodes;
ERL_NIF_TERM item = enif_make_tuple(
env,
2,
enif_make_int(env, (*nodes)->score),
enif_make_value(env, (*nodes)->value));
res = enif_make_list_cell(env, item, res);
}
free(nodes);
return res;
}
static ERL_NIF_TERM size1(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
skiplist *list = get_pointer(env, argv[0]);
if (!list)
return enif_make_badarg(env);
ERL_NIF_TERM res = enif_make_int(env, list->size);
return res;
}
// first index of the score
static ERL_NIF_TERM index_of_score(ErlNifEnv *env, int argc, const ERL_NIF_TERM *argv)
{
skiplist *list = get_pointer(env, argv[0]);
if (!list)
return enif_make_badarg(env);
int socre;
if (!enif_get_int(env, argv[1], &socre))
return enif_make_badarg(env);
int res0 = skiplist_index_of_score(list, socre);
ERL_NIF_TERM res = enif_make_int(env, res0);
return res;
}
static ERL_NIF_TERM at(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
skiplist *list = get_pointer(env, argv[0]);
if (!list)
return enif_make_badarg(env);
int index;
if (!enif_get_int(env, argv[1], &index))
return enif_make_badarg(env);
snode *x = skiplist_at(list, index);
ERL_NIF_TERM res;
if (x) {
res = enif_make_tuple(
env,
2,
enif_make_int(env, x->score),
enif_make_value(env, x->value));
} else {
enif_make_existing_atom(env, "error", &res, ERL_NIF_LATIN1);
}
return res;
}
static ERL_NIF_TERM range_by_score(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
skiplist *list = get_pointer(env, argv[0]);
if (!list)
return enif_make_badarg(env);
int score1, score2;
if (!enif_get_int(env, argv[1], &score1))
return enif_make_badarg(env);
if (!enif_get_int(env, argv[2], &score2))
return enif_make_badarg(env);
skiplist_search_ret res0;
skiplist_search(list, score1, &res0);
ERL_NIF_TERM ret_list = enif_make_list(env, 0);
for (snode *node = res0.node; node && node->score <= score2; node = node->level[0].forward) {
ret_list = enif_make_list_cell(env,
enif_make_tuple(env,
2,
enif_make_int(env, node->score),
enif_make_value(env, node->value)),
ret_list);
}
ERL_NIF_TERM ret_list1;
enif_make_reverse_list(env, ret_list, &ret_list1);
return enif_make_tuple(
env,
2,
enif_make_int(env, res0.index),
ret_list1);
}
static ERL_NIF_TERM range_1(
ErlNifEnv* env,
const ERL_NIF_TERM argv[],
ERL_NIF_TERM (*func_make_item)(ErlNifEnv *, snode *))
{
skiplist *list = get_pointer(env, argv[0]);
if (!list)
return enif_make_badarg(env);
int start, len;
if (!enif_get_int(env, argv[1], &start))
return enif_make_badarg(env);
if (!enif_get_int(env, argv[2], &len))
return enif_make_badarg(env);
int n = list->size - start + 1;
int alloc_size = n < len ? n : len;
ERL_NIF_TERM res = enif_make_list(env, 0);
if (alloc_size <= 0) {
return res;
}
snode **nodes = (snode **)malloc(sizeof(snode *) * (alloc_size + 1));
// get the nodes
snode *x = skiplist_at(list, start);
for (n = 0; n < alloc_size; n++) {
*nodes = x;
++nodes;
x = x->level[0].forward;
}
for (n = 0; n < alloc_size; n++) {
--nodes;
res = enif_make_list_cell(env, func_make_item(env, *nodes), res);
}
free(nodes);
return res;
}
inline static ERL_NIF_TERM range_make_item(ErlNifEnv* env, snode *node);
static ERL_NIF_TERM range_make_item(ErlNifEnv* env, snode *node)
{
return enif_make_value(env, node->value);
}
/* int p_list: identification of skiplist
* int start: >= 1, start index of skiplist
* int len: >= 1, max items to return
* return: [node]
*/
static ERL_NIF_TERM range(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
return range_1(env, argv, range_make_item);
}
inline static ERL_NIF_TERM range_with_score_make_item(ErlNifEnv* env, snode *node);
static ERL_NIF_TERM range_with_score_make_item(ErlNifEnv* env, snode *node)
{
return enif_make_tuple(
env,
2,
enif_make_int(env, node->score),
enif_make_value(env, node->value));
}
/* int p_list: identification of skiplist
* int start: >= 1, start index of skiplist
* int len: >= 1, max items to return
* return: [{score, node}]
*/
static ERL_NIF_TERM range_with_score(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
return range_1(env, argv, range_with_score_make_item);
}
static ErlNifFunc nif_funcs[] = {
{"new", 0, new},
{"free", 1, free1},
{"insert", 3, insert},
{"update", 4, update},
{"delete", 3, delete},
{"to_list", 1, to_list},
{"size", 1, size1},
{"index_of_score", 2, index_of_score},
{"at", 2, at},
{"range", 3, range},
{"range_with_score", 3, range_with_score},
{"range_by_score", 3, range_by_score},
};
ERL_NIF_INIT(skiplist, nif_funcs, NULL, NULL, NULL, NULL)

+ 8
- 0
c_src/nif_skiplist1/rebar.config 查看文件

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

+ 417
- 0
c_src/nif_skiplist1/skiplist.c 查看文件

@ -0,0 +1,417 @@
//
// Created by fox on 2017/10/10.
// Skip Lists: A Probabilistic Alternative to Balanced Trees
// indexable skip list
// duplicated score and node
#include <stdlib.h>
#include <stdio.h>
#include <limits.h>
#include <string.h>
#include "skiplist.h"
#include <time.h>
// from 0 to n
#define SKIPLIST_MAX_LEVEL 15
#define LEVEL_SIZE (SKIPLIST_MAX_LEVEL+1)
#define RAND_UNIFORM(x) (int)((double)rand() / RAND_MAX * (x))
/* Create a skiplist node with the specified number of levels. */
snode *skiplistCreateNode(int level, int score, vtype value) {
snode *zn =
(snode *)icalloc(sizeof(*zn)+level*sizeof(struct skiplistLevel));
zn->score = score;
zn->value = value;
return zn;
}
skiplist *skiplist_init(void)
{
time_t t;
srand((unsigned)(time(&t)));
snode *header = skiplistCreateNode(LEVEL_SIZE, INT_MAX, INT_MAX);
for (int i = 0; i < LEVEL_SIZE; ++i) {
header->level[i].span = 1;
}
skiplist *list = (skiplist *)imalloc(sizeof(skiplist));
list->header = header;
list->level = 0;
list->size = 0;
return list;
}
static int rand_level()
{
int level = 0;
while (rand() < RAND_MAX / 2 && level < SKIPLIST_MAX_LEVEL)
// while (arc4random() < INT_MAX && level < SKIPLIST_MAX_LEVEL)
level++;
return level;
}
// insert score,node into a skiplist, return 0
int skiplist_insert(skiplist *list, int score, vtype value)
{
snode **update = (snode **)imalloc(sizeof(snode*) * (list->level + 1));
unsigned int *fore_width = (unsigned int *)imalloc(sizeof(unsigned int) * (list->level + 1));
snode *x = list->header;
int i;
for (i = list->level; i >= 0; i--) {
fore_width[i] = 0;
while (x->level[i].forward && x->level[i].forward->score <= score) {
fore_width[i] += x->level[i].span;
x = x->level[i].forward;
}
update[i] = x;
}
// assert(x->score <= score);
int level = rand_level();
list->size = list->size+1;
x = skiplistCreateNode(level+1, score, value);
// the lowest layer is one by one
x->level[0].forward = update[0]->level[0].forward;
x->level[0].span = 1;
update[0]->level[0].forward = x;
unsigned int temp_width;
for (i = 1; i <= (list->level < level ? list->level : level); i++) {
temp_width = fore_width[i-1] + update[i-1]->level[i-1].span;
x->level[i].forward = update[i]->level[i].forward;
x->level[i].span = update[i]->level[i].span + 1 - temp_width;
update[i]->level[i].forward = x;
update[i]->level[i].span = temp_width;
}
if (level > list->level) {
// complete the new level
temp_width = fore_width[list->level] + update[list->level]->level[list->level].span;
for (i = list->level+1; i <= level; i++) {
list->header->level[i].span = temp_width;
list->header->level[i].forward = x;
x->level[i].forward = NULL;
x->level[i].span = list->size + 1 - temp_width;
}
list->level = level;
}
else {
// complete the unreached level
for (; i <= list->level; ++i) {
update[i]->level[i].span++;
}
}
ifree(update);
ifree(fore_width);
return 0;
}
int skiplist_update(skiplist *list, int score, vtype value, int old_score)
{
skiplist_delete(list, old_score, value);
return skiplist_insert(list, score, value);
}
// search score in skiplist.
// set the struct with index and first node if exists, otherwise set index 0
void skiplist_search(skiplist *list, int score, skiplist_search_ret *ret)
{
snode *x = list->header;
int temp_width = 1;
for (int i = list->level; i >= 0; i--) {
while (x->level[i].forward && x->level[i].forward->score < score) {
temp_width += x->level[i].span;
x = x->level[i].forward;
}
}
x = x->level[0].forward;
ret->index = temp_width;
ret->node = x;
}
// first index of score
int skiplist_index_of_score(skiplist *list, int score)
{
snode *x = list->header;
int temp_width = 1;
for (int i = list->level; i >= 0; i--) {
while (x->level[i].forward && x->level[i].forward->score < score) {
temp_width += x->level[i].span;
x = x->level[i].forward;
}
}
x = x->level[0].forward;
// check if existed score
if (x && x->score == score) {
return temp_width;
}
return 0;
}
// search skiplist by index. Return the node if exists, otherwise NULL
snode *skiplist_at(skiplist *list, int index)
{
snode *x = list->header;
for (int i = list->level; i >= 0; i--) {
while (x->level[i].forward) {
if (x->level[i].span == index) {
return x->level[i].forward;
}
if (x->level[i].span < index) {
index -= x->level[i].span;
x = x->level[i].forward;
}
else {
break;
}
}
}
return NULL;
}
static void skiplist_node_free(snode *x)
{
if (x) {
ifree(x);
}
}
// delete by score,node. Return 0 if success, 1 if fail.
int skiplist_delete(skiplist *list, int score, vtype value)
{
int i;
snode **update = (snode **)imalloc(sizeof(snode*) * (list->level + 1));
snode *x = list->header;
// find every level before the specified node
for (i = list->level; i >= 0; --i) {
while (1) {
if (!(x->level[i].forward) || x->level[i].forward->score > score) {
update[i] = x;
break;
}
if (x->level[i].forward->score < score) {
x = x->level[i].forward;
continue;
}
// find the first node with same score
int j;
update[i] = x;
for (j = i-1; j >= 0; --j) {
while (x->level[j].forward->score < score)
x = x->level[j].forward;
update[j] = x;
}
x = x->level[0].forward;
snode *x_start_search = x;
// find the first node with same score and node
while (x && x->value != value && x->score == score) {
x = x->level[0].forward;
}
if (x && x->score == score) {
// now x is the node to find
// find nodes for every level before the node to find
if (x == x_start_search) {
// done
i = 0;
break;
}
// j is used to judge if change the x_start_search
j = 0;
snode *iter;
for (; i >= 0; --i)
{
if (j) {
update[i] = x_start_search;
iter = x_start_search->level[0].forward;
} else{
iter = x_start_search;
}
while (iter != x) {
if (iter == update[i]->level[i].forward) {
j = 1;
x_start_search = iter;
iter = iter->level[0].forward;
update[i] = update[i]->level[i].forward;
continue;
}
iter = iter->level[0].forward;
}
}
i = 0;
break;
}
else {
// not found the node
ifree(update);
return 1;
}
}
}
if (x->score != score) {
// not found the node
ifree(update);
return 1;
}
for (i = 0; i <= list->level && update[i]->level[i].forward == x; i++) {
update[i]->level[i].forward = x->level[i].forward;
update[i]->level[i].span += x->level[i].span - 1;
}
for (; i <= list->level; i++) {
--(update[i]->level[i].span);
}
skiplist_node_free(x);
while (list->level > 0 && list->header->level[list->level].forward == NULL)
list->level--;
list->size--;
ifree(update);
return 0;
}
// ifree the skiplist
void skiplist_free(skiplist *list)
{
snode *current_node = list->header->level[0].forward;
while(current_node != NULL) {
snode *next_node = current_node->level[0].forward;
skiplist_node_free(current_node);
current_node = next_node;
}
ifree(list);
}
// print the skip list, just for test.
static void skiplist_dump(skiplist *list)
{
int *width = (int *)imalloc(sizeof(int) * (list->level + 1) * list->size);
memset(width, 0, sizeof(int) * (list->level + 1) * list->size);
snode **tempn = (snode **)imalloc(sizeof(snode*) * (list->level + 1));
int i = 0, j;
snode *x = list->header->level[0].forward;
for (j = 0; j <= list->level; ++j) {
tempn[j] = list->header->level[j].forward;
}
while (tempn[0] != NULL) {
for (j = 1; j <= list->level; ++j) {
if (tempn[j] == tempn[0]) {
width[list->size * j + i] = tempn[j]->level[j].span;
tempn[j] = tempn[j]->level[j].forward;
} else {
break;
}
}
tempn[0] = tempn[0]->level[0].forward;
++i;
}
for (j = list->level; j > 0; --j) {
for (i = 0; i < list->size; ++i) {
if (width[j * list->size + i] == 0)
printf(" ");
else
printf("%d ", width[j * list->size + i]);
}
printf("\n");
}
while (x != NULL) {
printf("%d:%d->", x->score, x->value);
x = x->level[0].forward;
}
printf("NIL\n");
ifree(width);
ifree(tempn);
}
void test_skiplist(void) {
time_t t;
srand((unsigned)(time(&t)));
int arr[][2] = { {3, 1}, {3,2}, {6,6}, {9,9}, {3, 3}, {1, 1}, {4, 4}, {8, 8}, {7, 7}, {5,5}}, i;
// int arr[] = { 3, 6, 9}, i;
skiplist_search_ret tempx;
skiplist *list = skiplist_init();
printf("search empty:--------------------\n");
skiplist_search(list, 5, &tempx);
if (tempx.index > 0) {
printf("error, found not existed item!\n");
}
printf("delete empty:--------------------\n");
skiplist_delete(list, 5, 2);
printf("Insert:--------------------\n");
for (i = 0; i < sizeof(arr) / sizeof(arr[0]); i++) {
skiplist_insert(list, arr[i][0], arr[i][1]);
}
skiplist_dump(list);
printf("search empty:--------------------\n");
skiplist_search(list, 5, &tempx);
printf("index = %d\n", tempx.index);
printf("Search by index:-----------\n");
int indexes[] = { 11, 3, 10 };
for (i = 0; i < sizeof(indexes) / sizeof(indexes[0]); i++) {
snode *tempnode = skiplist_at(list, indexes[i]);
if (tempnode) {
printf("index = %d, score = %d, value = %d\n", indexes[i], tempnode->score, tempnode->value);
} else {
printf("no index = %d\n", indexes[i]);
}
}
printf("Delete:--------------------\n");
skiplist_delete(list, 3, 2);
skiplist_delete(list, 3, 1);
skiplist_delete(list, 6, 6);
skiplist_dump(list);
clock_t start, finish;
start = clock();
for (i = 0; i < 30*1000; ++i) {
if (rand() < RAND_MAX / 5 * 3) {
skiplist_insert(list, RAND_UNIFORM(100), RAND_UNIFORM(20));
}
else {
skiplist_delete(list, RAND_UNIFORM(100), RAND_UNIFORM(20));
}
}
finish = clock();
double duration = (double)(finish - start) / CLOCKS_PER_SEC;
printf( "%f seconds\n", duration );
printf("Search:--------------------\n");
int keys[] = { 0, 3, 7, 100, 11 };
for (i = 0; i < sizeof(keys) / sizeof(keys[0]); i++) {
printf("index = %d, score = %d\n", skiplist_index_of_score(list, keys[i]), keys[i]);
}
skiplist_free(list);
};

+ 55
- 0
c_src/nif_skiplist1/skiplist.h 查看文件

@ -0,0 +1,55 @@
//
// Created by fox on 2017/10/10.
//
#ifndef NIF_SKIPLIST_SKIPLIST_H
#define NIF_SKIPLIST_SKIPLIST_H
#ifdef USENIF
#define imalloc enif_alloc
#define icalloc enif_alloc
#define irealloc enif_realloc
#define ifree enif_free
#else
#define imalloc malloc
#define icalloc(x) calloc(x, 1)
#define irealloc realloc
#define ifree free
#endif
typedef int vtype;
typedef struct snode {
int score;
int value;
struct skiplistLevel {
struct snode *forward;
unsigned int span;
} level[];
} snode;
typedef struct skiplist {
int level;
int size;
struct snode *header;
} skiplist;
typedef struct skiplist_search_ret {
int index; // start from 1
snode *node;
} skiplist_search_ret;
void test_skiplist(void);
// functions
skiplist *skiplist_init(void);
void skiplist_free(skiplist *list);
int skiplist_insert(skiplist *list, int score, vtype value);
int skiplist_update(skiplist *list, int score, vtype value, int old_score);
int skiplist_delete(skiplist *list, int score, vtype value);
void skiplist_search(skiplist *list, int score, skiplist_search_ret *ret);
int skiplist_index_of_score(skiplist *list, int score);
snode *skiplist_at(skiplist *list, int index);
#endif //NIF_SKIPLIST_SKIPLIST_H

+ 48
- 0
src/nifSrc/cbase64_erlang_nif/cbase64.erl 查看文件

@ -0,0 +1,48 @@
%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
%% ex: ts=4 sw=4 et
%% Copyright (c) 2011-2016 Sergey Urbanovich
%% http://github.com/urbanserj/cbase64-erlang-nif
%%
%% Permission is hereby granted, free of charge, to any person obtaining a copy
%% of this software and associated documentation files (the "Software"), to deal
%% in the Software without restriction, including without limitation the rights
%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
%% copies of the Software, and to permit persons to whom the Software is
%% furnished to do so, subject to the following conditions:
%%
%% The above copyright notice and this permission notice shall be included in
%% all copies or substantial portions of the Software.
%%
%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
%% THE SOFTWARE.
-module(cbase64).
-export([encode/1, decode/1]).
-on_load(on_load/0).
on_load() ->
BaseDir =
case code:priv_dir(?MODULE) of
{error, bad_name} ->
EbinDir = filename:dirname(code:which(?MODULE)),
AppPath = filename:dirname(EbinDir),
filename:join(AppPath, "priv");
Dir ->
Dir
end,
SoName = filename:join(BaseDir, atom_to_list(?MODULE)),
erlang:load_nif(SoName, 0).
-spec encode(binary() | iolist()) -> binary().
encode(_Data) ->
erlang:nif_error(not_loaded, [{module, ?MODULE}, {line, ?LINE}]).
-spec decode(binary() | iolist()) -> binary().
decode(_Data) ->
erlang:nif_error(not_loaded, [{module, ?MODULE}, {line, ?LINE}]).

+ 184
- 0
src/nifSrc/neural/neural.erl 查看文件

@ -0,0 +1,184 @@
-module(neural).
-export([new/2, empty/1, drain/1, dump/1, % Table operations
garbage/1, garbage_size/1,
key_pos/1]).
-export([lookup/2]). % Getters
-export([insert/2, insert_new/2, delete/2]). % Setters
-export([increment/3, unshift/3, shift/3, swap/3]). % Delta operations
-on_load(init/0).
-record(table_opts, {
keypos = 1 :: integer()
}).
-define(nif_stub, nif_stub_error(?LINE)).
nif_stub_error(Line) ->
erlang:nif_error({nif_not_loaded,module,?MODULE,line,Line}).
-ifdef(TEST).
-include_lib("eunit/include/eunit.hrl").
-endif.
init() ->
PrivDir = case code:priv_dir(?MODULE) of
{error, bad_name} ->
EbinDir = filename:dirname(code:which(?MODULE)),
AppPath = filename:dirname(EbinDir),
filename:join(AppPath, "priv");
Path ->
Path
end,
erlang:load_nif(filename:join(PrivDir, ?MODULE), 0).
new(Table, Opts) ->
new(Table, Opts, #table_opts{}).
new(Table, [{key_pos, KeyPos}|Opts], TableOpts) ->
new(Table, Opts, TableOpts#table_opts{keypos = KeyPos});
new(Table, [], _TableOpts = #table_opts{keypos = KeyPos}) when is_integer(KeyPos) ->
make_table(Table, KeyPos).
make_table(_Table, _KeyPos) ->
?nif_stub.
insert(Table, Object) when is_atom(Table), is_tuple(Object) ->
Key = element(key_pos(Table), Object),
insert(Table, erlang:phash2(Key), Object).
insert(_Table, _Key, _Object) ->
?nif_stub.
insert_new(Table, Object) when is_atom(Table), is_tuple(Object) ->
Key = element(key_pos(Table), Object),
insert_new(Table, erlang:phash2(Key), Object).
insert_new(_Table, _Key, _Object) ->
?nif_stub.
increment(Table, Key, Value) when is_integer(Value) ->
[N] = increment(Table, Key, [{key_pos(Table) + 1, Value}]),
N;
increment(Table, Key, Op = {Position, Value}) when is_integer(Position), is_integer(Value) ->
[N] = increment(Table, Key, [Op]),
N;
increment(Table, Key, Op = [_|_]) when is_atom(Table) ->
case lists:all(fun is_incr_op/1, Op) of
true ->
lists:reverse(do_increment(Table, erlang:phash2(Key), Op));
false ->
error(badarg)
end.
shift(Table, Key, Value) when is_integer(Value) ->
[R] = shift(Table, Key, [{key_pos(Table) + 1, Value}]),
R;
shift(Table, Key, Op = {Position, Value}) when is_integer(Position), is_integer(Value) ->
[R] = shift(Table, Key, [Op]),
R;
shift(Table, Key, Op = [_|_]) when is_atom(Table) ->
case lists:all(fun is_shift_op/1, Op) of
true ->
lists:reverse(do_shift(Table, erlang:phash2(Key), Op));
false ->
error(badarg)
end.
unshift(Table, Key, Op = {Position, Value}) when is_integer(Position), is_list(Value) ->
[R] = unshift(Table, Key, [Op]),
R;
unshift(Table, Key, Op = [_|_]) when is_atom(Table) ->
case lists:all(fun is_unshift_op/1, Op) of
true ->
lists:reverse(do_unshift(Table, erlang:phash2(Key), Op), []);
false ->
error(badarg)
end.
swap(Table, Key, Op = {Position, _Value}) when is_integer(Position) ->
[R] = swap(Table, Key, [Op]),
R;
swap(Table, Key, Op = [_|_]) when is_atom(Table) ->
case lists:all(fun is_swap_op/1, Op) of
true ->
lists:reverse(do_swap(Table, erlang:phash2(Key), Op));
false ->
error(badarg)
end.
is_incr_op({P,V}) when is_integer(P), is_integer(V) -> true;
is_incr_op(_) -> false.
is_shift_op({P,V}) when is_integer(P), is_integer(V) -> true;
is_shift_op(_) -> false.
is_unshift_op({P,L}) when is_integer(P), is_list(L) -> true;
is_unshift_op(_) -> false.
is_swap_op({P,V}) when is_integer(P) -> true;
is_swap_op(_) -> false.
do_increment(_Table, _Key, _Op) ->
?nif_stub.
do_shift(_Table, _Key, _Op) ->
?nif_stub.
do_unshift(_Table, _Key, _Op) ->
?nif_stub.
do_swap(_Table, _Key, _Op) ->
?nif_stub.
lookup(Table, Key) when is_atom(Table) ->
do_fetch(Table, erlang:phash2(Key)).
do_fetch(_Table, _Key) ->
?nif_stub.
delete(Table, Key) when is_atom(Table) ->
do_delete(Table, erlang:phash2(Key)).
do_delete(_Table, _key) ->
?nif_stub.
garbage(_Table) ->
?nif_stub.
garbage_size(_Table) ->
?nif_stub.
empty(_Table) ->
?nif_stub.
drain(Table) ->
'$neural_batch_wait' = do_drain(Table),
wait_batch_response().
do_drain(_Table) ->
?nif_stub.
dump(Table) ->
'$neural_batch_wait' = do_dump(Table),
wait_batch_response().
do_dump(_Table) ->
?nif_stub.
key_pos(_Table) ->
?nif_stub.
wait_batch_response() ->
receive
{'$neural_batch_response', Response} -> Response
end.
%% ===================================================================
%% EUnit tests
%% ===================================================================
-ifdef(TEST).
basic_test() ->
{ok, Ref} = new(),
?assertEqual(ok, myfunction(Ref)).
-endif.

+ 16
- 0
src/nifSrc/neural/neural_app.erl 查看文件

@ -0,0 +1,16 @@
-module(neural_app).
-behaviour(application).
%% Application callbacks
-export([start/2, stop/1]).
%% ===================================================================
%% Application callbacks
%% ===================================================================
start(_StartType, _StartArgs) ->
neural_sup:start_link().
stop(_State) ->
ok.

+ 31
- 0
src/nifSrc/neural/neural_sup.erl 查看文件

@ -0,0 +1,31 @@
-module(neural_sup).
-behaviour(supervisor).
%% API
-export([start_link/0]).
%% Supervisor callbacks
-export([init/1]).
%% Helper macro for declaring children of supervisor
-define(CHILD(I, Type), {I, {I, start_link, []}, permanent, 5000, Type, [I]}).
%% ===================================================================
%% API functions
%% ===================================================================
start_link() ->
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
%% ===================================================================
%% Supervisor callbacks
%% ===================================================================
init([]) ->
{ok, {
{one_for_one, 5, 10},
[]
}}.

+ 60
- 0
src/nifSrc/nif_array/binary_tools.erl 查看文件

@ -0,0 +1,60 @@
-module(binary_tools).
-compile(export_all).
-on_load(init/0).
-define(nif_stub, nif_stub_error(?LINE)).
nif_stub_error(Line) ->
erlang:nif_error({nif_not_loaded,module,?MODULE,line,Line}).
-ifdef(TEST).
-include_lib("eunit/include/eunit.hrl").
-endif.
init() ->
PrivDir = case code:priv_dir(?MODULE) of
{error, bad_name} ->
EbinDir = filename:dirname(code:which(?MODULE)),
AppPath = filename:dirname(EbinDir),
filename:join(AppPath, "priv");
Path ->
Path
end,
erlang:load_nif(filename:join(PrivDir, ?MODULE), 0).
get_bin_address(_Ref) ->
?nif_stub.
new_array(_Size) ->
?nif_stub.
size_array(_Bin) ->
?nif_stub.
put_array(_Pos, _Value, _Bin) ->
?nif_stub.
get_array(_Pos, _Bin) ->
?nif_stub.
test() ->
List = lists:seq(1, 10000),
A = new_array(10000),
EA = array:from_list(List),
[put_array(S - 1, S, A) || S <- List], %array begin from 0,list begin from 1
G = [random:uniform(9999) || _ <- List],
{LT, LR} = timer:tc(fun()-> [lists:nth(Pos, List) || Pos <- G] end),
{AT, AR} = timer:tc(fun()-> [get_array(Pos - 1, A) || Pos <- G] end),
{EAT, EAR} = timer:tc(fun()-> [array:get(Pos - 1, EA) || Pos <- G] end),
LR = AR,
LR = EAR,
io:format("List random nth : ~p~n", [LT]),
io:format("Array random get : ~p~n", [AT]),
io:format("Erlang Array random get : ~p~n", [EAT]).
%% ===================================================================
%% EUnit tests
%% ===================================================================

+ 70
- 0
src/nifSrc/nif_skiplist1/nif.erl 查看文件

@ -0,0 +1,70 @@
%%%-------------------------------------------------------------------
%%% @author fox
%%% @copyright (C) 2017, <COMPANY>
%%% @doc
%%% nif
%%% @end
%%% Created : 16. 2017 16:05
%%%-------------------------------------------------------------------
-module(nif).
-author("fox").
%% API
-export([init/0, test/0]).
init() ->
skiplist:init("./nif_skiplist"),
ok.
test() ->
init(),
A = skiplist:new(),
skiplist:insert(A, 10, 10),
skiplist:insert(A, 5, 5),
skiplist:insert(A, 8, 8),
skiplist:insert(A, 1, 1),
skiplist:insert(A, 4, 4),
skiplist:insert(A, 7, 7),
io:format("~p~n", [skiplist:to_list(A)]),
skiplist:delete(A, 7, 7),
io:format("~p~n", [skiplist:to_list(A)]),
io:format("get=~p~n", [skiplist:index_of_score(A, 5)]),
io:format("get=~p~n", [skiplist:index_of_score(A, 6)]),
io:format("get=~p~n", [skiplist:index_of_score(A, 15)]),
io:format("at=~p~n", [skiplist:at(A, 1)]),
io:format("at=~p~n", [skiplist:at(A, 5)]),
io:format("at=~p~n", [skiplist:at(A, 6)]),
io:format("range=~p~n", [skiplist:range(A, 1, 10)]),
io:format("range=~p~n", [skiplist:range(A, 2, 3)]),
io:format("range=~p~n", [skiplist:range(A, 8, 10)]),
io:format("range_with_score=~p~n", [skiplist:range_with_score(A, 1, 10)]),
io:format("range_with_score=~p~n", [skiplist:range_with_score(A, 2, 3)]),
io:format("range_with_score=~p~n", [skiplist:range_with_score(A, 8, 10)]),
erlang:statistics(wall_clock),
loop_test(30*1000, A),
{_, Time} = erlang:statistics(wall_clock),
io:format("time=~p~n", [Time]),
%% io:format("range_by_score=~p~n", [skiplist:range_by_score(A, -10, 10)]),
%% io:format("range_by_score=~p~n", [skiplist:range_by_score(A, 2, 3)]),
io:format("range_by_score=~p~n", [skiplist:range_by_score(A, 101, 10)]),
skiplist:free(A).
loop_test(0, _) ->
ok;
loop_test(N, L) ->
case rand:uniform(500) < 300 of
true ->
skiplist:insert(L, rand:uniform(100), rand:uniform(20));
_ ->
skiplist:delete(L, rand:uniform(100), rand:uniform(20))
end,
loop_test(N - 1, L).

+ 81
- 0
src/nifSrc/nif_skiplist1/skiplist.erl 查看文件

@ -0,0 +1,81 @@
%%%-------------------------------------------------------------------
%%% @author fox
%%% @copyright (C) 2017, <COMPANY>
%%% @doc
%%% indexable skip list, can insert duplicated value
%%% @end
%%% Created : 16. 2017 14:16
%%%-------------------------------------------------------------------
-module(skiplist).
-author("fox").
%% API
-export([
init/1,
new/0, free/1,
insert/3, delete/3, update/4,
to_list/1,
range/3, range_with_score/3, range_by_score/3,
index_of_score/2, at/2,
size/1]).
-type skiplist() :: non_neg_integer().
-type score() :: integer().
-type value() :: integer().
-spec init(Path) -> ok | Error when
Path :: string(),
Error :: any().
init(Path) ->
erlang:load_nif(Path, 0).
-spec new() -> skiplist().
new() ->
erlang:nif_error(undef).
-spec free(skiplist()) -> ok.
free(_List) ->
erlang:nif_error(undef).
-spec insert(skiplist(), score(), value()) -> 0.
insert(_List, _Score, _Value) ->
erlang:nif_error(undef).
-spec delete(skiplist(), score(), value()) ->
0 | 1. %% 0 success, 1 fail
delete(_List, _Score, _Value) ->
erlang:nif_error(undef).
-spec update(skiplist(), score(), value(), score()) -> 0.
update(_List, _Score, _Value, _OldScore) ->
erlang:nif_error(undef).
-spec to_list(skiplist()) -> [{score(), value()}].
to_list(_List) ->
erlang:nif_error(undef).
-spec size(skiplist()) -> non_neg_integer().
size(_List) ->
erlang:nif_error(undef).
-spec index_of_score(skiplist(), score()) -> non_neg_integer().
index_of_score(_List, _Score) ->
erlang:nif_error(undef).
-spec at(skiplist(), non_neg_integer()) -> error | {score(), value()}.
at(_List, _Index) ->
erlang:nif_error(undef).
-spec range(skiplist(), non_neg_integer(), non_neg_integer()) -> [value()].
range(_List, _Start, _Len) ->
erlang:nif_error(undef).
-spec range_with_score(skiplist(), non_neg_integer(), non_neg_integer()) ->
[{score(), value()}].
range_with_score(_List, _Start, _Len) ->
erlang:nif_error(undef).
-spec range_by_score(skiplist(), score(), score()) ->
{StartIndex :: non_neg_integer(), [{score(), value()}]}.
range_by_score(_List, _Score1, _Score2) ->
erlang:nif_error(undef).

Loading…
取消
儲存