{
map_base *m = *(map_base **)luaL_checkudata(L, 1, "map");
const char *key = luaL_checkstring(L, 2);
- void *value = map_get(m, key);
+ void *value = m->_get(key);
if (!value)
return 0;
lua_getiuservalue(L, 1, 1);
const char *key = luaL_checkstring(L, 2);
luaL_checkany(L, 3);
if (lua_isnil(L, 3)) {
- (void)map_set(m, key, 0, 0);
+ (void)m->_set(key, 0, 0);
return 0;
}
lua_getiuservalue(L, 1, 1);
switch (lua_tointeger(L, -1)) {
case MAPTYPE_STRINGSET:
- (void)map_set(m, key, key, 0);
+ (void)m->_set(key, key, 0);
break;
case MAPTYPE_CLIENT: {
void **p = (void **)luaL_checkudata(L, 3, "client");
- (void)map_set(m, key, *p, 0);
+ (void)m->_set(key, *p, 0);
break;
}
case MAPTYPE_CHANNEL: {
void **p = (void **)luaL_checkudata(L, 3, "channel");
- (void)map_set(m, key, *p, 0);
+ (void)m->_set(key, *p, 0);
break;
}
}
}
static int map_iter_next(lua_State *L)
{
- map_iter_t *it = (map_iter_t *)luaL_checkudata(L, 1, "map_iter");
- lua_getiuservalue(L, 1, 2);
- const char *key = (const char *)lua_touserdata(L, -1);
- lua_pop(L, 1);
- void *value;
- if (!map_foriter(it, &key, &value))
+ map_base::iter *it = (map_base::iter *)luaL_checkudata(L, 1, "map_iter");
+ auto [key, value] = it->next();
+ if (!value)
return 0;
- lua_pushlightuserdata(L, (void *)key);
- lua_setiuservalue(L, 1, 2);
lua_getiuservalue(L, 1, 1);
switch (lua_tointeger(L, -1)) {
case MAPTYPE_STRINGSET:
{
map_base *m = *(map_base **)luaL_checkudata(L, 1, "map");
lua_pushcfunction(L, map_iter_next);
- map_iter_t *it = (map_iter_t *)lua_newuserdatauv(L, sizeof(map_iter_t), 2);
+ map_base::iter *it = (map_base::iter *)lua_newuserdatauv(L, sizeof(map_base::iter), 1);
memset(it, 0, sizeof(*it));
it->root = m;
luaL_setmetatable(L, "map_iter");
lua_getiuservalue(L, 1, 1);
lua_setiuservalue(L, -2, 1);
- lua_pushlightuserdata(L, 0);
- lua_setiuservalue(L, -2, 2);
lua_pushnil(L);
return 3;
}
free(chan->name);
free(chan->topic);
free(chan->topic_who);
- map_free(&chan->members);
- map_free(&chan->o);
- map_free(&chan->v);
- map_free(&chan->listb);
- map_free(&chan->liste);
- map_free(&chan->listI);
- map_free(&chan->listq);
- map_free(&chan->listwo);
- map_free(&chan->listwv);
- map_free(&chan->invitees);
+ chan->members.clear();
+ chan->o.clear();
+ chan->v.clear();
+ chan->listb.clear();
+ chan->liste.clear();
+ chan->listI.clear();
+ chan->listq.clear();
+ chan->listwo.clear();
+ chan->listwv.clear();
+ chan->invitees.clear();
free(chan->chankey);
free(chan);
}
/* free any persistent channels */
for (auto chan : channel_map.pop_view())
channel_kill(chan);
- map_free(&client_map);
- map_free(&channel_map);
- map_free(&autojoin);
+ client_map.clear();
+ channel_map.clear();
+ autojoin.clear();
if (fchanlog)
fclose(fchanlog);
return 0;
*found = 0;
return lo;
}
-void *map_get(map_base *root, const char *key)
+void *map_base::_get(const char *key)
{
int found;
- int i = ent_find(root, key, &found);
- return found ? root->ptr[i].value : 0;
+ int i = ent_find(this, key, &found);
+ return found ? ptr[i].value : 0;
}
-int map_set(map_base *root, const char *key, const void *value, void **oldvalue)
+int map_base::_set(const char *key, const void *value, void **oldvalue)
{
int found;
- int i = ent_find(root, key, &found);
+ int i = ent_find(this, key, &found);
if (found) {
if (oldvalue)
- *oldvalue = root->ptr[i].value;
+ *oldvalue = ptr[i].value;
if (!value) {
- free(root->ptr[i].key);
- memmove(root->ptr+i, root->ptr+i+1, sizeof(struct map_value)*(root->len-(i+1)));
- root->len--;
+ free(ptr[i].key);
+ memmove(ptr+i, ptr+i+1, sizeof(struct map_value)*(len-(i+1)));
+ len--;
} else {
- root->ptr[i].value = (void *)value;
+ ptr[i].value = (void *)value;
}
} else {
if (oldvalue)
*oldvalue = 0;
if (value) {
- if (root->len == root->cap) {
- int ncap = root->cap ? root->cap*2 : 2;
- struct map_value *nptr = (struct map_value *)realloc(root->ptr, sizeof(struct map_value)*ncap);
+ if (len == cap) {
+ int ncap = cap ? cap*2 : 2;
+ struct map_value *nptr = (struct map_value *)realloc(ptr, sizeof(struct map_value)*ncap);
if (!nptr)
return -1;
- root->ptr = nptr;
- root->cap = ncap;
+ ptr = nptr;
+ cap = ncap;
}
int slen = strlen(key)+1;
char *nkey = (char *)malloc(slen);
if (!nkey)
return -1;
memcpy(nkey, key, slen);
- memmove(root->ptr+i+1, root->ptr+i, sizeof(struct map_value)*(root->len-i));
- root->len++;
- root->ptr[i].key = nkey;
- root->ptr[i].value = (void *)value;
+ memmove(ptr+i+1, ptr+i, sizeof(struct map_value)*(len-i));
+ len++;
+ ptr[i].key = nkey;
+ ptr[i].value = (void *)value;
}
}
return 0;
}
-void map_free(map_base *root)
+void map_base::clear()
{
- while (root->len) {
- free(root->ptr[--root->len].key);
+ while (len) {
+ free(ptr[--len].key);
}
- free(root->ptr);
- root->ptr = 0;
- root->len = root->cap = 0;
-}
-int map_foriter(map_iter_t *it, const char **outkey, void *outvalue)
-{
- if (it->index == it->root->len)
- return 0;
- if (outkey)
- *outkey = it->root->ptr[it->index].key;
- if (outvalue)
- *(void **)outvalue = it->root->ptr[it->index].value;
- it->index++;
- return 1;
+ free(ptr);
+ ptr = 0;
+ len = cap = 0;
}
#ifndef MAP_H_
#define MAP_H_
-#include <stddef.h>
-#if defined(__has_c_attribute)
-# if __has_c_attribute(nodiscard)
-# define NODISCARD [[nodiscard]]
-# else
-# define NODISCARD
-# endif
-#else
-# define NODISCARD
-#endif
-
-/* all complexity is in terms of n = number of elements */
-struct map_value {
- char *key;
- void *value;
-};
-struct map_base {
- struct map_value *ptr;
- size_t len, cap;
-};
-typedef struct map_iter {
- map_base *root;
- size_t index;
-} map_iter_t;
+#include <stdlib.h>
+#include <utility>
+#include <iterator>
/* A map abstract data type with following properties:
* - keys are lexicographically-sorted unique NUL-terminated strings
* A map is created by allocating and zero-initializing an object of type
* map_t. All map functions take a pointer to map_t.
*/
-
-/* Return the associated value for a given key.
- * Dynarr complexity: O(log n) */
-void *map_get(map_base *root, const char *key);
-/* Associate a new value with a given key.
- * Returns 0 on success, -1 on allocation error.
- * If oldvalue is not NULL, it receives the old value of key.
- * No allocation failures on value = NULL.
- * Dynarr complexity: O(n) */
-NODISCARD int map_set(map_base *root, const char *key, const void *value, void **oldvalue);
-/* Removes all keys from the map and frees any associated memory.
- * The map_t is reset to zero-initialized state and can be used again.
- * Dynarr complexity: O(n) */
-void map_free(map_base *root);
-
-/* Iterate over a map.
- *
- * Do not modify the map while iterating.
- * Don't modify *outkey or what it points to, and don't rely on it's lifetime
- * being longer than one iteration.
- * outvalue is actually a void**, but for implicit casting reasons it's void*.
- * Both outkey and outvalue can be specified as NULL.
- * Returns 0 on end of iteration, 1 otherwise.
- */
-NODISCARD int map_foriter(map_iter_t *f, const char **outkey, void *outvalue);
-
-#include <utility>
-#include <iterator>
-#include <stdlib.h>
-struct client_data;
-struct channel;
+struct map_value {
+ char *key;
+ void *value;
+};
+struct map_base {
+ struct map_value *ptr;
+ size_t len, cap;
+ /* Return the associated value for a given key.
+ * Dynarr complexity: O(log n) */
+ void *_get(const char *key);
+ /* Associate a new value with a given key.
+ * Returns 0 on success, -1 on allocation error.
+ * If oldvalue is not NULL, it receives the old value of key.
+ * No allocation failures on value = NULL.
+ * Dynarr complexity: O(n) */
+ [[nodiscard]] int _set(const char *key, const void *value, void **oldvalue);
+ /* Removes all keys from the map and frees any associated memory.
+ * The map_t is reset to zero-initialized state and can be used again.
+ * Dynarr complexity: O(n) */
+ void clear();
+ /* Iterate over a map.
+ * Do not modify the map while iterating.
+ */
+ struct iter {
+ map_base *root;
+ size_t index;
+ auto next() {
+ map_value kv{0, 0};
+ if (index < root->len)
+ kv = root->ptr[index++];
+ return std::make_pair(kv.key, kv.value);
+ }
+ };
+};
template<typename T, typename V>
struct map_base2 : map_base {
auto pop_view() {
return reverse{*this};
}
- void clear() {
- map_free(this);
- }
size_t size() {
return len;
}
}
public:
bool has(V v) {
- return !!map_get(this, T::to_key(v));
+ return !!_get(T::to_key(v));
}
bool add(V v) {
void *old;
- if (map_set(this, T::to_key(v), v, &old) == -1)
+ if (_set(T::to_key(v), v, &old) == -1)
abort();
return !old;
}
bool remove(V v) {
void *old;
- (void)map_set(this, T::to_key(v), 0, &old);
+ (void)_set(T::to_key(v), 0, &old);
return !!old;
}
V get(const char *k) {
- return (V)map_get(this, k);
+ return (V)_get(k);
}
};
+struct client_data;
struct clientmap : map_base2<clientmap, struct client_data *> {
void rename(struct client_data *v, const char *newk) {
- if (remove(v) && map_set(this, newk, v, 0) == -1)
+ if (remove(v) && _set(newk, v, 0) == -1)
abort();
}
};
+struct channel;
struct channelmap : map_base2<channelmap, struct channel *> {
};
struct stringset : map_base2<stringset, const char *> {
for (auto chan : cl->invites)
chan->invitees.remove(cl);
}
- map_free(&cl->channels);
- map_free(&cl->invites);
- map_free(&cl->monitor);
+ cl->channels.clear();
+ cl->invites.clear();
+ cl->monitor.clear();
killConnectionPart2(cl);
}
void killConnectionPart2(struct client_data *cl)