Skip to content

Commit c840cf5

Browse files
committed
Add support for rank
1 parent 1f2ccee commit c840cf5

11 files changed

+102
-3
lines changed

c_src/epqueue.cc

+36
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,17 @@ bool internal_remove(epqueue* q, queue_item* item)
4343
return q->queue->remove(item, item->heap_index);
4444
}
4545

46+
bool internal_rank(epqueue* q, queue_item* item, int32_t* rank)
47+
{
48+
CritScope ss(q->crit);
49+
50+
if(item->heap_index == -1)
51+
return false;
52+
53+
*rank = q->queue->rank(item->heap_index);
54+
return true;
55+
}
56+
4657
queue_item* internal_pop(epqueue* q)
4758
{
4859
CritScope ss(q->crit);
@@ -255,3 +266,28 @@ ERL_NIF_TERM nif_epqueue_peek(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[
255266

256267
return enif_make_tuple3(env, ATOMS.atomOk, bin_term, enif_make_int64(env, item->priority));
257268
}
269+
270+
ERL_NIF_TERM nif_epqueue_rank(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
271+
{
272+
UNUSED(argc);
273+
274+
epqueue_data* data = static_cast<epqueue_data*>(enif_priv_data(env));
275+
epqueue* inst = NULL;
276+
queue_item* item = NULL;
277+
278+
if(!enif_get_resource(env, argv[0], data->resPQueueInstance, reinterpret_cast<void**>(&inst)))
279+
return enif_make_badarg(env);
280+
281+
if(!is_owner(env, inst))
282+
return enif_make_badarg(env);
283+
284+
if(!enif_get_resource(env, argv[1], data->resPQueueItem, reinterpret_cast<void**>(&item)))
285+
return enif_make_badarg(env);
286+
287+
int32_t rank;
288+
289+
if(!internal_rank(inst, item, &rank))
290+
return make_error(env, ATOMS.atomNotFound);
291+
292+
return enif_make_tuple2(env, ATOMS.atomOk, enif_make_int(env, rank));
293+
}

c_src/epqueue.h

+1
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,6 @@ ERL_NIF_TERM nif_epqueue_insert(ErlNifEnv* env, int argc, const ERL_NIF_TERM arg
1010
ERL_NIF_TERM nif_epqueue_remove(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
1111
ERL_NIF_TERM nif_epqueue_pop(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
1212
ERL_NIF_TERM nif_epqueue_peek(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
13+
ERL_NIF_TERM nif_epqueue_rank(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
1314

1415
#endif // C_SRC_EPQUEUE_H_

c_src/epqueue_nif.cc

+4-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ const char kAtomTrue[] = "true";
1010
const char kAtomFalse[] = "false";
1111
const char kAtomUndefined[] = "undefined";
1212
const char kAtomGlobalLock[] = "global_lock";
13+
const char kAtomNotFound[] = "not_found";
1314

1415
atoms ATOMS;
1516

@@ -29,6 +30,7 @@ int on_nif_load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
2930
ATOMS.atomTrue = make_atom(env, kAtomTrue);
3031
ATOMS.atomFalse = make_atom(env, kAtomFalse);
3132
ATOMS.atomUndefined = make_atom(env, kAtomUndefined);
33+
ATOMS.atomNotFound = make_atom(env, kAtomNotFound);
3234

3335
ATOMS.atomGlobalLock = make_atom(env, kAtomGlobalLock);
3436

@@ -66,7 +68,8 @@ static ErlNifFunc nif_funcs[] =
6668
{"remove", 2, nif_epqueue_remove},
6769
{"pop", 1, nif_epqueue_pop},
6870
{"peek", 1, nif_epqueue_peek},
69-
{"size", 1, nif_epqueue_size}
71+
{"size", 1, nif_epqueue_size},
72+
{"rank", 2, nif_epqueue_rank},
7073
};
7174

7275
ERL_NIF_INIT(epqueue_nif, nif_funcs, on_nif_load, NULL, on_nif_upgrade, on_nif_unload)

c_src/epqueue_nif.h

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ struct atoms
1010
ERL_NIF_TERM atomTrue;
1111
ERL_NIF_TERM atomFalse;
1212
ERL_NIF_TERM atomUndefined;
13+
ERL_NIF_TERM atomNotFound;
1314

1415
ERL_NIF_TERM atomGlobalLock;
1516
};

c_src/nif_utils.cc

+5
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,8 @@ ERL_NIF_TERM make_error(ErlNifEnv* env, const char* error)
2525
{
2626
return enif_make_tuple2(env, ATOMS.atomError, make_binary(env, error, strlen(error)));
2727
}
28+
29+
ERL_NIF_TERM make_error(ErlNifEnv* env, ERL_NIF_TERM term)
30+
{
31+
return enif_make_tuple2(env, ATOMS.atomError, term);
32+
}

c_src/nif_utils.h

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
ERL_NIF_TERM make_atom(ErlNifEnv* env, const char* name);
77
ERL_NIF_TERM make_error(ErlNifEnv* env, const char* error);
8+
ERL_NIF_TERM make_error(ErlNifEnv* env, ERL_NIF_TERM term);
89
ERL_NIF_TERM make_binary(ErlNifEnv* env, const char* buff, size_t length);
910

1011
#endif // C_SRC_NIF_UTILS_H_

c_src/priority_queue.cc

+16
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,22 @@ void PriorityQueue::bubble_down(int pos)
125125
}
126126
}
127127

128+
int PriorityQueue::rank_r(int target_index, int cur_node_index)
129+
{
130+
if (cur_node_index >= length_)
131+
return 0;
132+
133+
// if the current node priority is <= target_node, it is part of the rank count
134+
if (less(cur_node_index, target_index))
135+
{
136+
int left_count = rank_r(target_index, left(cur_node_index));
137+
int right_count = rank_r(target_index, right(cur_node_index));
138+
return 1 + left_count + right_count;
139+
}
140+
141+
return 0;
142+
}
143+
128144
void PriorityQueue::bubble_up(int pos)
129145
{
130146
while (true)

c_src/priority_queue.h

+2
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,15 @@ class PriorityQueue
2020
void* pop() {return remove(0);}
2121
void* peek();
2222
int size() const { return length_;}
23+
int rank(int pos) {return rank_r(pos, 0)+1;}
2324

2425
private:
2526

2627
inline void set(int pos, void* item);
2728
inline void pos_swap(int pos1, int pos2);
2829
void bubble_down(int pos);
2930
void bubble_up(int pos);
31+
int rank_r(int x, int cur_node_index);
3032

3133
int capacity_;
3234
int length_;

src/epqueue.erl

+8-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
insert/3,
88
remove/2,
99
pop/1,
10-
peek/1
10+
peek/1,
11+
rank/2
1112
]).
1213

1314
-type error() :: badarg | {error, binary()}.
@@ -58,3 +59,9 @@ pop(QueueRef) ->
5859

5960
peek(QueueRef) ->
6061
epqueue_nif:peek(QueueRef).
62+
63+
-spec rank(queue_ref(), data_ref()) ->
64+
{ok, non_neg_integer()} | error().
65+
66+
rank(QueueRef, Ref) ->
67+
epqueue_nif:rank(QueueRef, Ref).

src/epqueue_nif.erl

+5-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
1010
insert/3,
1111
remove/2,
1212
pop/1,
13-
peek/1
13+
peek/1,
14+
rank/2
1415
]).
1516

1617
load_nif() ->
@@ -36,6 +37,9 @@ pop(_QueueRef) ->
3637
peek(_QueueRef) ->
3738
?NOT_LOADED.
3839

40+
rank(_QueueRef, _ItemRef) ->
41+
?NOT_LOADED.
42+
3943
% internals
4044

4145
get_priv_path(File) ->

test/integrity_test.erl

+23
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,26 @@ pop_test() ->
5858
?assertEqual({ok, 3, 3}, epqueue:pop(Q1)),
5959
?assertEqual({ok, 5, 5}, epqueue:pop(Q1)),
6060
ok.
61+
62+
rank_test() ->
63+
{ok, Q1} = epqueue:new([]),
64+
{ok, R1} = epqueue:insert(Q1, 3, 1),
65+
{ok, R2} = epqueue:insert(Q1, 5, 3),
66+
{ok, R3} = epqueue:insert(Q1, 1, 2),
67+
{ok, R4} = epqueue:insert(Q1, 1, 1),
68+
69+
?assertEqual({ok, 1}, epqueue:rank(Q1, R1)),
70+
?assertEqual({ok, 4}, epqueue:rank(Q1, R2)),
71+
?assertEqual({ok, 3}, epqueue:rank(Q1, R3)),
72+
?assertEqual({ok, 2}, epqueue:rank(Q1, R4)),
73+
74+
?assertEqual(true, epqueue:remove(Q1, R1)),
75+
?assertEqual({ok, 1}, epqueue:rank(Q1, R4)),
76+
77+
?assertEqual(true, epqueue:remove(Q1, R2)),
78+
?assertEqual(true, epqueue:remove(Q1, R3)),
79+
80+
?assertEqual({ok, 1}, epqueue:rank(Q1, R4)),
81+
?assertEqual(true, epqueue:remove(Q1, R4)),
82+
?assertEqual({error, not_found}, epqueue:rank(Q1, R4)),
83+
ok.

0 commit comments

Comments
 (0)