aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/common/container.c81
-rw-r--r--src/common/container.h9
-rw-r--r--src/or/test.c61
3 files changed, 151 insertions, 0 deletions
diff --git a/src/common/container.c b/src/common/container.c
index 7795e514be..d8ce9d654b 100644
--- a/src/common/container.c
+++ b/src/common/container.c
@@ -461,6 +461,87 @@ smartlist_sort_strings(smartlist_t *sl)
smartlist_sort(sl, _compare_string_ptrs);
}
+#define LEFT_CHILD(i) ( ((i)+1)*2 - 1)
+#define RIGHT_CHILD(i) ( ((i)+1)*2 )
+#define PARENT(i) ( ((i)+1)/2 - 1)
+
+static INLINE void
+smartlist_heapify(smartlist_t *sl,
+ int (*compare)(const void *a, const void *b),
+ int idx)
+{
+ while (1) {
+ int left_idx = LEFT_CHILD(idx);
+ int best_idx;
+
+ if (left_idx >= sl->num_used)
+ return;
+ if (compare(sl->list[idx],sl->list[left_idx]) < 0)
+ best_idx = idx;
+ else
+ best_idx = left_idx;
+ if (left_idx+1 < sl->num_used &&
+ compare(sl->list[left_idx+1],sl->list[best_idx]) < 0)
+ best_idx = left_idx + 1;
+
+ if (best_idx == idx) {
+ return;
+ } else {
+ void *tmp = sl->list[idx];
+ sl->list[idx] = sl->list[best_idx];
+ sl->list[best_idx] = tmp;
+
+ idx = best_idx;
+ }
+ }
+}
+
+void
+smartlist_pqueue_add(smartlist_t *sl,
+ int (*compare)(const void *a, const void *b),
+ void *item)
+{
+ int idx;
+ smartlist_add(sl,item);
+
+ for (idx = sl->num_used - 1; idx; ) {
+ int parent = PARENT(idx);
+ if (compare(sl->list[idx], sl->list[parent]) < 0) {
+ void *tmp = sl->list[parent];
+ sl->list[parent] = sl->list[idx];
+ sl->list[idx] = tmp;
+ idx = parent;
+ } else {
+ return;
+ }
+ }
+}
+
+void *
+smartlist_pqueue_pop(smartlist_t *sl,
+ int (*compare)(const void *a, const void *b))
+{
+ void *top;
+ tor_assert(sl->num_used);
+
+ top = sl->list[0];
+ if (--sl->num_used) {
+ sl->list[0] = sl->list[sl->num_used];
+ smartlist_heapify(sl, compare, 0);
+ }
+ return top;
+}
+
+void
+smartlist_pqueue_assert_ok(smartlist_t *sl,
+ int (*compare)(const void *a, const void *b))
+{
+ int i;
+ for (i = sl->num_used - 1; i > 0; --i) {
+ tor_assert(compare(sl->list[PARENT(i)], sl->list[i]) <= 0);
+ }
+}
+
/** Helper: compare two DIGEST_LEN digests. */
static int
_compare_digests(const void **_a, const void **_b)
diff --git a/src/common/container.h b/src/common/container.h
index 1031a6ef13..0b5d0618af 100644
--- a/src/common/container.h
+++ b/src/common/container.h
@@ -38,6 +38,7 @@ int smartlist_string_num_isin(const smartlist_t *sl, int num);
int smartlist_overlap(const smartlist_t *sl1, const smartlist_t *sl2);
void smartlist_intersect(smartlist_t *sl1, const smartlist_t *sl2);
void smartlist_subtract(smartlist_t *sl1, const smartlist_t *sl2);
+
/* smartlist_choose() is defined in crypto.[ch] */
#ifdef DEBUG_SMARTLIST
/** Return the number of items in sl.
@@ -76,6 +77,14 @@ void smartlist_sort_digests(smartlist_t *sl);
void *smartlist_bsearch(smartlist_t *sl, const void *key,
int (*compare)(const void *key, const void **member));
+void smartlist_pqueue_add(smartlist_t *sl,
+ int (*compare)(const void *a, const void *b),
+ void *item);
+void *smartlist_pqueue_pop(smartlist_t *sl,
+ int (*compare)(const void *a, const void *b));
+void smartlist_pqueue_assert_ok(smartlist_t *sl,
+ int (*compare)(const void *a, const void *b));
+
#define SPLIT_SKIP_SPACE 0x01
#define SPLIT_IGNORE_BLANK 0x02
int smartlist_split_string(smartlist_t *sl, const char *str, const char *sep,
diff --git a/src/or/test.c b/src/or/test.c
index 3e18df9d33..4a258afb71 100644
--- a/src/or/test.c
+++ b/src/or/test.c
@@ -921,6 +921,66 @@ test_util(void)
smartlist_free(sl);
}
+static int
+_compare_strings_for_pqueue(const void *s1, const void *s2)
+{
+ return strcmp((const char*)s1, (const char*)s2);
+}
+
+static void
+test_pqueue(void)
+{
+ smartlist_t *sl;
+ int (*cmp)(const void *, const void*);
+#define OK() smartlist_pqueue_assert_ok(sl, cmp)
+
+ cmp = _compare_strings_for_pqueue;
+
+ sl = smartlist_create();
+ smartlist_pqueue_add(sl, cmp, "cows");
+ smartlist_pqueue_add(sl, cmp, "zebras");
+ smartlist_pqueue_add(sl, cmp, "fish");
+ smartlist_pqueue_add(sl, cmp, "frogs");
+ smartlist_pqueue_add(sl, cmp, "apples");
+ smartlist_pqueue_add(sl, cmp, "squid");//
+ smartlist_pqueue_add(sl, cmp, "daschunds");
+ smartlist_pqueue_add(sl, cmp, "eggplants");
+ smartlist_pqueue_add(sl, cmp, "weissbier");//
+ smartlist_pqueue_add(sl, cmp, "lobsters");
+ smartlist_pqueue_add(sl, cmp, "roquefort");//
+
+ OK();
+
+ test_eq(smartlist_len(sl), 11);
+ test_streq(smartlist_get(sl, 0), "apples");
+ test_streq(smartlist_pqueue_pop(sl, cmp), "apples");
+ test_eq(smartlist_len(sl), 10);
+ OK();
+ test_streq(smartlist_pqueue_pop(sl, cmp), "cows");
+ test_streq(smartlist_pqueue_pop(sl, cmp), "daschunds");
+ smartlist_pqueue_add(sl, cmp, "chinchillas");
+ OK();
+ smartlist_pqueue_add(sl, cmp, "fireflies");
+ OK();
+ test_streq(smartlist_pqueue_pop(sl, cmp), "chinchillas");
+ test_streq(smartlist_pqueue_pop(sl, cmp), "eggplants");
+ test_streq(smartlist_pqueue_pop(sl, cmp), "fireflies");
+ OK();
+ test_streq(smartlist_pqueue_pop(sl, cmp), "fish");
+ test_streq(smartlist_pqueue_pop(sl, cmp), "frogs");
+ test_streq(smartlist_pqueue_pop(sl, cmp), "lobsters");
+ test_streq(smartlist_pqueue_pop(sl, cmp), "roquefort");
+ OK();
+ test_eq(smartlist_len(sl), 3);
+ test_streq(smartlist_pqueue_pop(sl, cmp), "squid");
+ test_streq(smartlist_pqueue_pop(sl, cmp), "weissbier");
+ test_streq(smartlist_pqueue_pop(sl, cmp), "zebras");
+ test_eq(smartlist_len(sl), 0);
+ OK();
+#undef OK
+ smartlist_free(sl);
+}
+
static void
test_gzip(void)
{
@@ -1675,6 +1735,7 @@ main(int c, char**v)
test_util();
test_strmap();
test_control_formats();
+ test_pqueue();
puts("\n========================= Onion Skins =====================");
test_onion();
test_onion_handshake();