container.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652
  1. /* Copyright 2003-2004 Roger Dingledine
  2. Copyright 2004-2005 Roger Dingledine, Nick Mathewson */
  3. /* See LICENSE for licensing information */
  4. /* $Id$ */
  5. const char container_c_id[] = "$Id$";
  6. #include "compat.h"
  7. #include "util.h"
  8. #include "log.h"
  9. #include "../or/tree.h"
  10. #include "container.h"
  11. #ifdef HAVE_CTYPE_H
  12. #include <ctype.h>
  13. #endif
  14. #include <stdlib.h>
  15. #include <string.h>
  16. #include <assert.h>
  17. /* =====
  18. * smartlist_t: a simple resizeable array abstraction.
  19. * ===== */
  20. /* All newly allocated smartlists have this capacity.
  21. */
  22. #define SMARTLIST_DEFAULT_CAPACITY 32
  23. #ifndef FAST_SMARTLIST
  24. struct smartlist_t {
  25. /** <b>list</b> has enough capacity to store exactly <b>capacity</b> elements
  26. * before it needs to be resized. Only the first <b>num_used</b> (\<=
  27. * capacity) elements point to valid data.
  28. */
  29. void **list;
  30. int num_used;
  31. int capacity;
  32. };
  33. #endif
  34. /** Allocate and return an empty smartlist.
  35. */
  36. smartlist_t *smartlist_create() {
  37. smartlist_t *sl = tor_malloc(sizeof(smartlist_t));
  38. sl->num_used = 0;
  39. sl->capacity = SMARTLIST_DEFAULT_CAPACITY;
  40. sl->list = tor_malloc(sizeof(void *) * sl->capacity);
  41. return sl;
  42. }
  43. /** Deallocate a smartlist. Does not release storage associated with the
  44. * list's elements.
  45. */
  46. void smartlist_free(smartlist_t *sl) {
  47. free(sl->list);
  48. free(sl);
  49. }
  50. /** Change the capacity of the smartlist to <b>n</b>, so that we can grow
  51. * the list up to <b>n</b> elements with no further reallocation or wasted
  52. * space. If <b>n</b> is less than or equal to the number of elements
  53. * currently in the list, reduce the list's capacity as much as
  54. * possible without losing elements.
  55. */
  56. void smartlist_set_capacity(smartlist_t *sl, int n) {
  57. if (n < sl->num_used)
  58. n = sl->num_used;
  59. if (sl->capacity != n) {
  60. sl->capacity = n;
  61. sl->list = tor_realloc(sl->list, sizeof(void*)*sl->capacity);
  62. }
  63. }
  64. /** Remove all elements from the list.
  65. */
  66. void smartlist_clear(smartlist_t *sl) {
  67. sl->num_used = 0;
  68. }
  69. /** Set the list's new length to <b>len</b> (which must be \<= the list's
  70. * current size). Remove the last smartlist_len(sl)-len elements from the
  71. * list.
  72. */
  73. void smartlist_truncate(smartlist_t *sl, int len)
  74. {
  75. tor_assert(len <= sl->num_used);
  76. sl->num_used = len;
  77. }
  78. /** Append element to the end of the list. */
  79. void smartlist_add(smartlist_t *sl, void *element) {
  80. if (sl->num_used >= sl->capacity) {
  81. int higher = sl->capacity * 2;
  82. tor_assert(higher > sl->capacity); /* detect overflow */
  83. sl->capacity = higher;
  84. sl->list = tor_realloc(sl->list, sizeof(void*)*sl->capacity);
  85. }
  86. sl->list[sl->num_used++] = element;
  87. }
  88. /** Append each element from S2 to the end of S1. */
  89. void smartlist_add_all(smartlist_t *sl, const smartlist_t *s2)
  90. {
  91. SMARTLIST_FOREACH(s2, void *, element, smartlist_add(sl, element));
  92. }
  93. /** Remove all elements E from sl such that E==element. Preserve
  94. * the order of any elements before E, but elements after E can be
  95. * rearranged.
  96. */
  97. void smartlist_remove(smartlist_t *sl, void *element) {
  98. int i;
  99. if (element == NULL)
  100. return;
  101. for (i=0; i < sl->num_used; i++)
  102. if (sl->list[i] == element) {
  103. sl->list[i] = sl->list[--sl->num_used]; /* swap with the end */
  104. i--; /* so we process the new i'th element */
  105. }
  106. }
  107. /** If there are any strings in sl equal to element, remove them.
  108. * Does not preserve order. */
  109. void
  110. smartlist_string_remove(smartlist_t *sl, const char *element)
  111. {
  112. int i;
  113. tor_assert(sl);
  114. tor_assert(element);
  115. for (i = 0; i < sl->num_used; ++i) {
  116. if (!strcmp(element, sl->list[i])) {
  117. sl->list[i] = sl->list[--sl->num_used]; /* swap with the end */
  118. i--; /* so we process the new i'th element */
  119. }
  120. }
  121. }
  122. /** Return true iff some element E of sl has E==element.
  123. */
  124. int smartlist_isin(const smartlist_t *sl, void *element) {
  125. int i;
  126. for (i=0; i < sl->num_used; i++)
  127. if (sl->list[i] == element)
  128. return 1;
  129. return 0;
  130. }
  131. int smartlist_string_isin(const smartlist_t *sl, const char *element) {
  132. int i;
  133. for (i=0; i < sl->num_used; i++)
  134. if (strcmp((const char*)sl->list[i],element)==0)
  135. return 1;
  136. return 0;
  137. }
  138. int smartlist_string_num_isin(const smartlist_t *sl, int num) {
  139. char buf[16];
  140. tor_snprintf(buf,sizeof(buf),"%d", num);
  141. return smartlist_string_isin(sl, buf);
  142. }
  143. /** Return true iff some element E of sl2 has smartlist_isin(sl1,E).
  144. */
  145. int smartlist_overlap(const smartlist_t *sl1, const smartlist_t *sl2) {
  146. int i;
  147. for (i=0; i < sl2->num_used; i++)
  148. if (smartlist_isin(sl1, sl2->list[i]))
  149. return 1;
  150. return 0;
  151. }
  152. /** Remove every element E of sl1 such that !smartlist_isin(sl2,E).
  153. * Does not preserve the order of sl1.
  154. */
  155. void smartlist_intersect(smartlist_t *sl1, const smartlist_t *sl2) {
  156. int i;
  157. for (i=0; i < sl1->num_used; i++)
  158. if (!smartlist_isin(sl2, sl1->list[i])) {
  159. sl1->list[i] = sl1->list[--sl1->num_used]; /* swap with the end */
  160. i--; /* so we process the new i'th element */
  161. }
  162. }
  163. /** Remove every element E of sl1 such that smartlist_isin(sl2,E).
  164. * Does not preserve the order of sl1.
  165. */
  166. void smartlist_subtract(smartlist_t *sl1, const smartlist_t *sl2) {
  167. int i;
  168. for (i=0; i < sl2->num_used; i++)
  169. smartlist_remove(sl1, sl2->list[i]);
  170. }
  171. #ifndef FAST_SMARTLIST
  172. /** Return the <b>idx</b>th element of sl.
  173. */
  174. void *smartlist_get(const smartlist_t *sl, int idx)
  175. {
  176. tor_assert(sl);
  177. tor_assert(idx>=0);
  178. tor_assert(idx < sl->num_used);
  179. return sl->list[idx];
  180. }
  181. /** Change the value of the <b>idx</b>th element of sl to <b>val</b>.
  182. */
  183. void smartlist_set(smartlist_t *sl, int idx, void *val)
  184. {
  185. tor_assert(sl);
  186. tor_assert(idx>=0);
  187. tor_assert(idx < sl->num_used);
  188. sl->list[idx] = val;
  189. }
  190. /** Return the number of items in sl.
  191. */
  192. int smartlist_len(const smartlist_t *sl)
  193. {
  194. return sl->num_used;
  195. }
  196. #endif
  197. /** Remove the <b>idx</b>th element of sl; if idx is not the last
  198. * element, swap the last element of sl into the <b>idx</b>th space.
  199. * Return the old value of the <b>idx</b>th element.
  200. */
  201. void smartlist_del(smartlist_t *sl, int idx)
  202. {
  203. tor_assert(sl);
  204. tor_assert(idx>=0);
  205. tor_assert(idx < sl->num_used);
  206. sl->list[idx] = sl->list[--sl->num_used];
  207. }
  208. /** Remove the <b>idx</b>th element of sl; if idx is not the last element,
  209. * moving all subsequent elements back one space. Return the old value
  210. * of the <b>idx</b>th element.
  211. */
  212. void smartlist_del_keeporder(smartlist_t *sl, int idx)
  213. {
  214. tor_assert(sl);
  215. tor_assert(idx>=0);
  216. tor_assert(idx < sl->num_used);
  217. --sl->num_used;
  218. if (idx < sl->num_used)
  219. memmove(sl->list+idx, sl->list+idx+1, sizeof(void*)*(sl->num_used-idx));
  220. }
  221. /** Insert the value <b>val</b> as the new <b>idx</b>th element of
  222. * <b>sl</b>, moving all items previously at <b>idx</b> or later
  223. * forward one space.
  224. */
  225. void smartlist_insert(smartlist_t *sl, int idx, void *val)
  226. {
  227. tor_assert(sl);
  228. tor_assert(idx>=0);
  229. tor_assert(idx <= sl->num_used);
  230. if (idx == sl->num_used) {
  231. smartlist_add(sl, val);
  232. } else {
  233. /* Ensure sufficient capacity */
  234. if (sl->num_used >= sl->capacity) {
  235. sl->capacity *= 2;
  236. sl->list = tor_realloc(sl->list, sizeof(void*)*sl->capacity);
  237. }
  238. /* Move other elements away */
  239. if (idx < sl->num_used)
  240. memmove(sl->list + idx + 1, sl->list + idx,
  241. sizeof(void*)*(sl->num_used-idx));
  242. sl->num_used++;
  243. sl->list[idx] = val;
  244. }
  245. }
  246. /**
  247. * Split a string <b>str</b> along all occurrences of <b>sep</b>,
  248. * adding the split strings, in order, to <b>sl</b>. If
  249. * <b>flags</b>&amp;SPLIT_SKIP_SPACE is true, remove initial and
  250. * trailing space from each entry. If
  251. * <b>flags</b>&amp;SPLIT_IGNORE_BLANK is true, remove any entries of
  252. * length 0. If max>0, divide the string into no more than <b>max</b>
  253. * pieces. If <b>sep</b> is NULL, split on any sequence of horizontal space.
  254. */
  255. int smartlist_split_string(smartlist_t *sl, const char *str, const char *sep,
  256. int flags, int max)
  257. {
  258. const char *cp, *end, *next;
  259. int n = 0;
  260. tor_assert(sl);
  261. tor_assert(str);
  262. cp = str;
  263. while (1) {
  264. if (flags&SPLIT_SKIP_SPACE) {
  265. while (TOR_ISSPACE(*cp)) ++cp;
  266. }
  267. if (max>0 && n == max-1) {
  268. end = strchr(cp,'\0');
  269. } else if (sep) {
  270. end = strstr(cp,sep);
  271. if (!end)
  272. end = strchr(cp,'\0');
  273. } else {
  274. for (end = cp; *end && *end != '\t' && *end != ' '; ++end)
  275. ;
  276. }
  277. if (!*end) {
  278. next = NULL;
  279. } else if (sep) {
  280. next = end+strlen(sep);
  281. } else {
  282. next = end+1;
  283. while (*next == '\t' || *next == ' ')
  284. ++next;
  285. }
  286. if (flags&SPLIT_SKIP_SPACE) {
  287. while (end > cp && TOR_ISSPACE(*(end-1)))
  288. --end;
  289. }
  290. if (end != cp || !(flags&SPLIT_IGNORE_BLANK)) {
  291. smartlist_add(sl, tor_strndup(cp, end-cp));
  292. ++n;
  293. }
  294. if (!next)
  295. break;
  296. cp = next;
  297. }
  298. return n;
  299. }
  300. /** Allocate and return a new string containing the concatenation of
  301. * the elements of <b>sl</b>, in order, separated by <b>join</b>. If
  302. * <b>terminate</b> is true, also terminate the string with <b>join</b>.
  303. * If <b>len_out</b> is not NULL, set <b>len_out</b> to the length of
  304. * the returned string. Requires that every element of <b>sl</b> is
  305. * NUL-terminated string.
  306. */
  307. char *smartlist_join_strings(smartlist_t *sl, const char *join,
  308. int terminate, size_t *len_out)
  309. {
  310. return smartlist_join_strings2(sl,join,strlen(join),terminate,len_out);
  311. }
  312. /** As smartlist_join_strings, but instead of separating/terminated with a
  313. * NUL-terminated string <b>join</b>, uses the <b>join_len</b>-byte sequence
  314. * at <b>join</b>. (Useful for generating a sequence of NUL-terminated
  315. * strings.)
  316. */
  317. char *smartlist_join_strings2(smartlist_t *sl, const char *join,
  318. size_t join_len, int terminate, size_t *len_out)
  319. {
  320. int i;
  321. size_t n = 0;
  322. char *r = NULL, *dst, *src;
  323. tor_assert(sl);
  324. tor_assert(join);
  325. for (i = 0; i < sl->num_used; ++i) {
  326. n += strlen(sl->list[i]);
  327. n += join_len;
  328. }
  329. if (!terminate) n -= join_len;
  330. dst = r = tor_malloc(n+1);
  331. for (i = 0; i < sl->num_used; ) {
  332. for (src = sl->list[i]; *src; )
  333. *dst++ = *src++;
  334. if (++i < sl->num_used || terminate) {
  335. memcpy(dst, join, join_len);
  336. dst += join_len;
  337. }
  338. }
  339. *dst = '\0';
  340. if (len_out)
  341. *len_out = dst-r;
  342. return r;
  343. }
  344. /* Splay-tree implementation of string-to-void* map
  345. */
  346. struct strmap_entry_t {
  347. SPLAY_ENTRY(strmap_entry_t) node;
  348. char *key;
  349. void *val;
  350. };
  351. struct strmap_t {
  352. SPLAY_HEAD(strmap_tree, strmap_entry_t) head;
  353. };
  354. static int compare_strmap_entries(struct strmap_entry_t *a,
  355. struct strmap_entry_t *b)
  356. {
  357. return strcmp(a->key, b->key);
  358. }
  359. SPLAY_PROTOTYPE(strmap_tree, strmap_entry_t, node, compare_strmap_entries);
  360. SPLAY_GENERATE(strmap_tree, strmap_entry_t, node, compare_strmap_entries);
  361. /** Create a new empty map from strings to void*'s.
  362. */
  363. strmap_t* strmap_new(void)
  364. {
  365. strmap_t *result;
  366. result = tor_malloc(sizeof(strmap_t));
  367. SPLAY_INIT(&result->head);
  368. return result;
  369. }
  370. /** Set the current value for <b>key</b> to <b>val</b>. Returns the previous
  371. * value for <b>key</b> if one was set, or NULL if one was not.
  372. *
  373. * This function makes a copy of <b>key</b> if necessary, but not of <b>val</b>.
  374. */
  375. void* strmap_set(strmap_t *map, const char *key, void *val)
  376. {
  377. strmap_entry_t *resolve;
  378. strmap_entry_t search;
  379. void *oldval;
  380. tor_assert(map);
  381. tor_assert(key);
  382. tor_assert(val);
  383. search.key = (char*)key;
  384. resolve = SPLAY_FIND(strmap_tree, &map->head, &search);
  385. if (resolve) {
  386. oldval = resolve->val;
  387. resolve->val = val;
  388. return oldval;
  389. } else {
  390. resolve = tor_malloc_zero(sizeof(strmap_entry_t));
  391. resolve->key = tor_strdup(key);
  392. resolve->val = val;
  393. SPLAY_INSERT(strmap_tree, &map->head, resolve);
  394. return NULL;
  395. }
  396. }
  397. /** Return the current value associated with <b>key</b>, or NULL if no
  398. * value is set.
  399. */
  400. void* strmap_get(strmap_t *map, const char *key)
  401. {
  402. strmap_entry_t *resolve;
  403. strmap_entry_t search;
  404. tor_assert(map);
  405. tor_assert(key);
  406. search.key = (char*)key;
  407. resolve = SPLAY_FIND(strmap_tree, &map->head, &search);
  408. if (resolve) {
  409. return resolve->val;
  410. } else {
  411. return NULL;
  412. }
  413. }
  414. /** Remove the value currently associated with <b>key</b> from the map.
  415. * Return the value if one was set, or NULL if there was no entry for
  416. * <b>key</b>.
  417. *
  418. * Note: you must free any storage associated with the returned value.
  419. */
  420. void* strmap_remove(strmap_t *map, const char *key)
  421. {
  422. strmap_entry_t *resolve;
  423. strmap_entry_t search;
  424. void *oldval;
  425. tor_assert(map);
  426. tor_assert(key);
  427. search.key = (char*)key;
  428. resolve = SPLAY_FIND(strmap_tree, &map->head, &search);
  429. if (resolve) {
  430. oldval = resolve->val;
  431. SPLAY_REMOVE(strmap_tree, &map->head, resolve);
  432. tor_free(resolve->key);
  433. tor_free(resolve);
  434. return oldval;
  435. } else {
  436. return NULL;
  437. }
  438. }
  439. /** Same as strmap_set, but first converts <b>key</b> to lowercase. */
  440. void* strmap_set_lc(strmap_t *map, const char *key, void *val)
  441. {
  442. /* We could be a little faster by using strcasecmp instead, and a separate
  443. * type, but I don't think it matters. */
  444. void *v;
  445. char *lc_key = tor_strdup(key);
  446. tor_strlower(lc_key);
  447. v = strmap_set(map,lc_key,val);
  448. tor_free(lc_key);
  449. return v;
  450. }
  451. /** Same as strmap_get, but first converts <b>key</b> to lowercase. */
  452. void* strmap_get_lc(strmap_t *map, const char *key)
  453. {
  454. void *v;
  455. char *lc_key = tor_strdup(key);
  456. tor_strlower(lc_key);
  457. v = strmap_get(map,lc_key);
  458. tor_free(lc_key);
  459. return v;
  460. }
  461. /** Same as strmap_remove, but first converts <b>key</b> to lowercase */
  462. void* strmap_remove_lc(strmap_t *map, const char *key)
  463. {
  464. void *v;
  465. char *lc_key = tor_strdup(key);
  466. tor_strlower(lc_key);
  467. v = strmap_remove(map,lc_key);
  468. tor_free(lc_key);
  469. return v;
  470. }
  471. /** Invoke fn() on every entry of the map, in order. For every entry,
  472. * fn() is invoked with that entry's key, that entry's value, and the
  473. * value of <b>data</b> supplied to strmap_foreach. fn() must return a new
  474. * (possibly unmodified) value for each entry: if fn() returns NULL, the
  475. * entry is removed.
  476. *
  477. * Example:
  478. * \code
  479. * static void* upcase_and_remove_empty_vals(const char *key, void *val,
  480. * void* data) {
  481. * char *cp = (char*)val;
  482. * if (!*cp) { // val is an empty string.
  483. * free(val);
  484. * return NULL;
  485. * } else {
  486. * for (; *cp; cp++)
  487. * *cp = toupper(*cp);
  488. * }
  489. * return val;
  490. * }
  491. * }
  492. *
  493. * ...
  494. *
  495. * strmap_foreach(map, upcase_and_remove_empty_vals, NULL);
  496. * \endcode
  497. */
  498. void strmap_foreach(strmap_t *map,
  499. void* (*fn)(const char *key, void *val, void *data),
  500. void *data)
  501. {
  502. strmap_entry_t *ptr, *next;
  503. tor_assert(map);
  504. tor_assert(fn);
  505. for (ptr = SPLAY_MIN(strmap_tree, &map->head); ptr != NULL; ptr = next) {
  506. /* This remove-in-place usage is specifically blessed in tree(3). */
  507. next = SPLAY_NEXT(strmap_tree, &map->head, ptr);
  508. ptr->val = fn(ptr->key, ptr->val, data);
  509. if (!ptr->val) {
  510. SPLAY_REMOVE(strmap_tree, &map->head, ptr);
  511. tor_free(ptr->key);
  512. tor_free(ptr);
  513. }
  514. }
  515. }
  516. /** return an <b>iterator</b> pointer to the front of a map.
  517. *
  518. * Iterator example:
  519. *
  520. * \code
  521. * // uppercase values in "map", removing empty values.
  522. *
  523. * strmap_iter_t *iter;
  524. * const char *key;
  525. * void *val;
  526. * char *cp;
  527. *
  528. * for (iter = strmap_iter_init(map); !strmap_iter_done(iter); ) {
  529. * strmap_iter_get(iter, &key, &val);
  530. * cp = (char*)val;
  531. * if (!*cp) {
  532. * iter = strmap_iter_next_rmv(iter);
  533. * free(val);
  534. * } else {
  535. * for (;*cp;cp++) *cp = toupper(*cp);
  536. * iter = strmap_iter_next(iter);
  537. * }
  538. * }
  539. * \endcode
  540. *
  541. */
  542. strmap_iter_t *strmap_iter_init(strmap_t *map)
  543. {
  544. tor_assert(map);
  545. return SPLAY_MIN(strmap_tree, &map->head);
  546. }
  547. /** Advance the iterator <b>iter</b> for map a single step to the next entry.
  548. */
  549. strmap_iter_t *strmap_iter_next(strmap_t *map, strmap_iter_t *iter)
  550. {
  551. tor_assert(map);
  552. tor_assert(iter);
  553. return SPLAY_NEXT(strmap_tree, &map->head, iter);
  554. }
  555. /** Advance the iterator <b>iter</b> a single step to the next entry, removing
  556. * the current entry.
  557. */
  558. strmap_iter_t *strmap_iter_next_rmv(strmap_t *map, strmap_iter_t *iter)
  559. {
  560. strmap_iter_t *next;
  561. tor_assert(map);
  562. tor_assert(iter);
  563. next = SPLAY_NEXT(strmap_tree, &map->head, iter);
  564. SPLAY_REMOVE(strmap_tree, &map->head, iter);
  565. tor_free(iter->key);
  566. tor_free(iter);
  567. return next;
  568. }
  569. /** Set *keyp and *valp to the current entry pointed to by iter.
  570. */
  571. void strmap_iter_get(strmap_iter_t *iter, const char **keyp, void **valp)
  572. {
  573. tor_assert(iter);
  574. tor_assert(keyp);
  575. tor_assert(valp);
  576. *keyp = iter->key;
  577. *valp = iter->val;
  578. }
  579. /** Return true iff iter has advanced past the last entry of map.
  580. */
  581. int strmap_iter_done(strmap_iter_t *iter)
  582. {
  583. return iter == NULL;
  584. }
  585. /** Remove all entries from <b>map</b>, and deallocate storage for those entries.
  586. * If free_val is provided, it is invoked on every value in <b>map</b>.
  587. */
  588. void
  589. strmap_free(strmap_t *map, void (*free_val)(void*))
  590. {
  591. strmap_entry_t *ent, *next;
  592. for (ent = SPLAY_MIN(strmap_tree, &map->head); ent != NULL; ent = next) {
  593. next = SPLAY_NEXT(strmap_tree, &map->head, ent);
  594. SPLAY_REMOVE(strmap_tree, &map->head, ent);
  595. tor_free(ent->key);
  596. if (free_val)
  597. free_val(ent->val);
  598. tor_free(ent);
  599. }
  600. tor_assert(SPLAY_EMPTY(&map->head));
  601. tor_free(map);
  602. }
  603. int strmap_isempty(strmap_t *map)
  604. {
  605. return SPLAY_EMPTY(&map->head);
  606. }