#include "lib/container/map.h"
#include "lib/ctime/di_ops.h"
#include "lib/defs/digest_sizes.h"
#include "lib/string/util_string.h"
#include "lib/malloc/malloc.h"
#include "lib/log/util_bug.h"
#include <stdlib.h>
#include <string.h>
#include "ext/ht.h"
#define DEFINE_MAP_STRUCTS(maptype, keydecl, prefix) \
typedef struct prefix ## entry_t { \
HT_ENTRY(prefix ## entry_t) node; \
void *val; \
keydecl; \
} prefix ## entry_t; \
struct maptype { \
HT_HEAD(prefix ## impl, prefix ## entry_t) head; \
}
DEFINE_MAP_STRUCTS(strmap_t, char *key, strmap_);
DEFINE_MAP_STRUCTS(digestmap_t, char key[DIGEST_LEN], digestmap_);
DEFINE_MAP_STRUCTS(digest256map_t, uint8_t key[DIGEST256_LEN], digest256map_);
static inline int
strmap_entries_eq(const strmap_entry_t *a, const strmap_entry_t *b)
{
return !strcmp(a->key, b->key);
}
static inline unsigned int
strmap_entry_hash(const strmap_entry_t *a)
{
return (unsigned) siphash24g(a->key, strlen(a->key));
}
static inline int
digestmap_entries_eq(const digestmap_entry_t *a, const digestmap_entry_t *b)
{
return tor_memeq(a->key, b->key, DIGEST_LEN);
}
static inline unsigned int
digestmap_entry_hash(const digestmap_entry_t *a)
{
return (unsigned) siphash24g(a->key, DIGEST_LEN);
}
static inline int
digest256map_entries_eq(const digest256map_entry_t *a,
const digest256map_entry_t *b)
{
return tor_memeq(a->key, b->key, DIGEST256_LEN);
}
static inline unsigned int
digest256map_entry_hash(const digest256map_entry_t *a)
{
return (unsigned) siphash24g(a->key, DIGEST256_LEN);
}
HT_PROTOTYPE(strmap_impl, strmap_entry_t, node, strmap_entry_hash,
strmap_entries_eq);
HT_GENERATE2(strmap_impl, strmap_entry_t, node, strmap_entry_hash,
strmap_entries_eq, 0.6, tor_reallocarray_, tor_free_);
HT_PROTOTYPE(digestmap_impl, digestmap_entry_t, node, digestmap_entry_hash,
digestmap_entries_eq);
HT_GENERATE2(digestmap_impl, digestmap_entry_t, node, digestmap_entry_hash,
digestmap_entries_eq, 0.6, tor_reallocarray_, tor_free_);
HT_PROTOTYPE(digest256map_impl, digest256map_entry_t, node,
digest256map_entry_hash,
digest256map_entries_eq);
HT_GENERATE2(digest256map_impl, digest256map_entry_t, node,
digest256map_entry_hash,
digest256map_entries_eq, 0.6, tor_reallocarray_, tor_free_);
#define strmap_entry_free(ent) \
FREE_AND_NULL(strmap_entry_t, strmap_entry_free_, (ent))
#define digestmap_entry_free(ent) \
FREE_AND_NULL(digestmap_entry_t, digestmap_entry_free_, (ent))
#define digest256map_entry_free(ent) \
FREE_AND_NULL(digest256map_entry_t, digest256map_entry_free_, (ent))
static inline void
strmap_entry_free_(strmap_entry_t *ent)
{
tor_free(ent->key);
tor_free(ent);
}
static inline void
digestmap_entry_free_(digestmap_entry_t *ent)
{
tor_free(ent);
}
static inline void
digest256map_entry_free_(digest256map_entry_t *ent)
{
tor_free(ent);
}
static inline void
strmap_assign_tmp_key(strmap_entry_t *ent, const char *key)
{
ent->key = (char*)key;
}
static inline void
digestmap_assign_tmp_key(digestmap_entry_t *ent, const char *key)
{
memcpy(ent->key, key, DIGEST_LEN);
}
static inline void
digest256map_assign_tmp_key(digest256map_entry_t *ent, const uint8_t *key)
{
memcpy(ent->key, key, DIGEST256_LEN);
}
static inline void
strmap_assign_key(strmap_entry_t *ent, const char *key)
{
ent->key = tor_strdup(key);
}
static inline void
digestmap_assign_key(digestmap_entry_t *ent, const char *key)
{
memcpy(ent->key, key, DIGEST_LEN);
}
static inline void
digest256map_assign_key(digest256map_entry_t *ent, const uint8_t *key)
{
memcpy(ent->key, key, DIGEST256_LEN);
}
#define IMPLEMENT_MAP_FNS(maptype, keytype, prefix) \
\
MOCK_IMPL(maptype *, \
prefix##_new,(void)) \
{ \
maptype *result; \
result = tor_malloc(sizeof(maptype)); \
HT_INIT(prefix##_impl, &result->head); \
return result; \
} \
\
\
void * \
prefix##_get(const maptype *map, const keytype key) \
{ \
prefix ##_entry_t *resolve; \
prefix ##_entry_t search; \
tor_assert(map); \
tor_assert(key); \
prefix ##_assign_tmp_key(&search, key); \
resolve = HT_FIND(prefix ##_impl, &map->head, &search); \
if (resolve) { \
return resolve->val; \
} else { \
return NULL; \
} \
} \
\
\
void * \
prefix##_set(maptype *map, const keytype key, void *val) \
{ \
prefix##_entry_t search; \
void *oldval; \
tor_assert(map); \
tor_assert(key); \
tor_assert(val); \
prefix##_assign_tmp_key(&search, key); \
\
\
\
\
\
HT_FIND_OR_INSERT_(prefix##_impl, node, prefix##_entry_hash, \
&(map->head), \
prefix##_entry_t, &search, ptr, \
{ \
\
oldval = (*ptr)->val; \
(*ptr)->val = val; \
return oldval; \
}, \
{ \
\
prefix##_entry_t *newent = \
tor_malloc_zero(sizeof(prefix##_entry_t)); \
prefix##_assign_key(newent, key); \
newent->val = val; \
HT_FOI_INSERT_(node, &(map->head), \
&search, newent, ptr); \
return NULL; \
}); \
} \
\
\
void * \
prefix##_remove(maptype *map, const keytype key) \
{ \
prefix##_entry_t *resolve; \
prefix##_entry_t search; \
void *oldval; \
tor_assert(map); \
tor_assert(key); \
prefix##_assign_tmp_key(&search, key); \
resolve = HT_REMOVE(prefix##_impl, &map->head, &search); \
if (resolve) { \
oldval = resolve->val; \
prefix##_entry_free(resolve); \
return oldval; \
} else { \
return NULL; \
} \
} \
\
\
int \
prefix##_size(const maptype *map) \
{ \
return HT_SIZE(&map->head); \
} \
\
\
int \
prefix##_isempty(const maptype *map) \
{ \
return HT_EMPTY(&map->head); \
} \
\
\
void \
prefix##_assert_ok(const maptype *map) \
{ \
tor_assert(!prefix##_impl_HT_REP_IS_BAD_(&map->head)); \
} \
\
\
MOCK_IMPL(void, \
prefix##_free_, (maptype *map, void (*free_val)(void*))) \
{ \
prefix##_entry_t **ent, **next, *this; \
if (!map) \
return; \
for (ent = HT_START(prefix##_impl, &map->head); ent != NULL; \
ent = next) { \
this = *ent; \
next = HT_NEXT_RMV(prefix##_impl, &map->head, ent); \
if (free_val) \
free_val(this->val); \
prefix##_entry_free(this); \
} \
tor_assert(HT_EMPTY(&map->head)); \
HT_CLEAR(prefix##_impl, &map->head); \
tor_free(map); \
} \
\
\
prefix##_iter_t * \
prefix##_iter_init(maptype *map) \
{ \
tor_assert(map); \
return HT_START(prefix##_impl, &map->head); \
} \
\
\
prefix##_iter_t * \
prefix##_iter_next(maptype *map, prefix##_iter_t *iter) \
{ \
tor_assert(map); \
tor_assert(iter); \
return HT_NEXT(prefix##_impl, &map->head, iter); \
} \
\
prefix##_iter_t * \
prefix##_iter_next_rmv(maptype *map, prefix##_iter_t *iter) \
{ \
prefix##_entry_t *rmv; \
tor_assert(map); \
tor_assert(iter); \
tor_assert(*iter); \
rmv = *iter; \
iter = HT_NEXT_RMV(prefix##_impl, &map->head, iter); \
prefix##_entry_free(rmv); \
return iter; \
} \
\
void \
prefix##_iter_get(prefix##_iter_t *iter, const keytype *keyp, \
void **valp) \
{ \
tor_assert(iter); \
tor_assert(*iter); \
tor_assert(keyp); \
tor_assert(valp); \
*keyp = (*iter)->key; \
*valp = (*iter)->val; \
} \
\
int \
prefix##_iter_done(prefix##_iter_t *iter) \
{ \
return iter == NULL; \
}
IMPLEMENT_MAP_FNS(strmap_t, char *, strmap)
IMPLEMENT_MAP_FNS(digestmap_t, char *, digestmap)
IMPLEMENT_MAP_FNS(digest256map_t, uint8_t *, digest256map)
void *
strmap_set_lc(strmap_t *map, const char *key, void *val)
{
void *v;
char *lc_key = tor_strdup(key);
tor_strlower(lc_key);
v = strmap_set(map,lc_key,val);
tor_free(lc_key);
return v;
}
void *
strmap_get_lc(const strmap_t *map, const char *key)
{
void *v;
char *lc_key = tor_strdup(key);
tor_strlower(lc_key);
v = strmap_get(map,lc_key);
tor_free(lc_key);
return v;
}
void *
strmap_remove_lc(strmap_t *map, const char *key)
{
void *v;
char *lc_key = tor_strdup(key);
tor_strlower(lc_key);
v = strmap_remove(map,lc_key);
tor_free(lc_key);
return v;
}