mirror of
https://github.com/neovim/neovim.git
synced 2025-11-25 03:30:37 +00:00
Merge pull request #732 from tarruda/map-improvements
This commit is contained in:
@@ -2,6 +2,9 @@ src/nvim/indent.c
|
|||||||
src/nvim/indent.h
|
src/nvim/indent.h
|
||||||
src/nvim/log.c
|
src/nvim/log.c
|
||||||
src/nvim/log.h
|
src/nvim/log.h
|
||||||
|
src/nvim/map.c
|
||||||
|
src/nvim/map.h
|
||||||
|
src/nvim/map_defs.h
|
||||||
src/nvim/os/env.c
|
src/nvim/os/env.c
|
||||||
src/nvim/os/event.c
|
src/nvim/os/event.c
|
||||||
src/nvim/os/event_defs.h
|
src/nvim/os/event_defs.h
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ set(CONV_SRCS
|
|||||||
arabic.c
|
arabic.c
|
||||||
garray.c
|
garray.c
|
||||||
memory.c
|
memory.c
|
||||||
|
map.c
|
||||||
os/env.c
|
os/env.c
|
||||||
os/event.c
|
os/event.c
|
||||||
os/job.c
|
os/job.c
|
||||||
|
|||||||
@@ -9,27 +9,18 @@
|
|||||||
#include "nvim/window.h"
|
#include "nvim/window.h"
|
||||||
#include "nvim/memory.h"
|
#include "nvim/memory.h"
|
||||||
#include "nvim/eval.h"
|
#include "nvim/eval.h"
|
||||||
|
#include "nvim/map_defs.h"
|
||||||
|
#include "nvim/map.h"
|
||||||
#include "nvim/option.h"
|
#include "nvim/option.h"
|
||||||
#include "nvim/option_defs.h"
|
#include "nvim/option_defs.h"
|
||||||
|
|
||||||
#include "nvim/lib/khash.h"
|
|
||||||
|
|
||||||
|
|
||||||
#if defined(ARCH_64)
|
|
||||||
#define ptr_hash_func(key) kh_int64_hash_func(key)
|
|
||||||
#elif defined(ARCH_32)
|
|
||||||
#define ptr_hash_func(key) kh_int_hash_func(key)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
KHASH_INIT(Lookup, uintptr_t, char, 0, ptr_hash_func, kh_int_hash_equal)
|
|
||||||
|
|
||||||
/// Recursion helper for the `vim_to_object`. This uses a pointer table
|
/// Recursion helper for the `vim_to_object`. This uses a pointer table
|
||||||
/// to avoid infinite recursion due to cyclic references
|
/// to avoid infinite recursion due to cyclic references
|
||||||
///
|
///
|
||||||
/// @param obj The source object
|
/// @param obj The source object
|
||||||
/// @param lookup Lookup table containing pointers to all processed objects
|
/// @param lookup Lookup table containing pointers to all processed objects
|
||||||
/// @return The converted value
|
/// @return The converted value
|
||||||
static Object vim_to_object_rec(typval_T *obj, khash_t(Lookup) *lookup);
|
static Object vim_to_object_rec(typval_T *obj, Map(ptr_t) *lookup);
|
||||||
|
|
||||||
static bool object_to_vim(Object obj, typval_T *tv, Error *err);
|
static bool object_to_vim(Object obj, typval_T *tv, Error *err);
|
||||||
|
|
||||||
@@ -285,10 +276,10 @@ Object vim_to_object(typval_T *obj)
|
|||||||
{
|
{
|
||||||
Object rv;
|
Object rv;
|
||||||
// We use a lookup table to break out of cyclic references
|
// We use a lookup table to break out of cyclic references
|
||||||
khash_t(Lookup) *lookup = kh_init(Lookup);
|
Map(ptr_t) *lookup = map_new(ptr_t)();
|
||||||
rv = vim_to_object_rec(obj, lookup);
|
rv = vim_to_object_rec(obj, lookup);
|
||||||
// Free the table
|
// Free the table
|
||||||
kh_destroy(Lookup, lookup);
|
map_free(ptr_t)(lookup);
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -443,19 +434,18 @@ static bool object_to_vim(Object obj, typval_T *tv, Error *err)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Object vim_to_object_rec(typval_T *obj, khash_t(Lookup) *lookup)
|
static Object vim_to_object_rec(typval_T *obj, Map(ptr_t) *lookup)
|
||||||
{
|
{
|
||||||
Object rv = {.type = kObjectTypeNil};
|
Object rv = {.type = kObjectTypeNil};
|
||||||
|
|
||||||
if (obj->v_type == VAR_LIST || obj->v_type == VAR_DICT) {
|
if (obj->v_type == VAR_LIST || obj->v_type == VAR_DICT) {
|
||||||
int ret;
|
|
||||||
// Container object, add it to the lookup table
|
// Container object, add it to the lookup table
|
||||||
kh_put(Lookup, lookup, (uintptr_t)obj, &ret);
|
if (map_has(ptr_t)(lookup, obj)) {
|
||||||
if (!ret) {
|
|
||||||
// It's already present, meaning we alredy processed it so just return
|
// It's already present, meaning we alredy processed it so just return
|
||||||
// nil instead.
|
// nil instead.
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
map_put(ptr_t)(lookup, obj, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (obj->v_type) {
|
switch (obj->v_type) {
|
||||||
|
|||||||
148
src/nvim/map.c
148
src/nvim/map.c
@@ -8,84 +8,80 @@
|
|||||||
|
|
||||||
#include "nvim/lib/khash.h"
|
#include "nvim/lib/khash.h"
|
||||||
|
|
||||||
typedef struct {
|
#define cstr_t_hash kh_str_hash_func
|
||||||
void *ptr;
|
#define cstr_t_eq kh_str_hash_equal
|
||||||
} Value;
|
#define uint64_t_hash kh_int64_hash_func
|
||||||
|
#define uint64_t_eq kh_int64_hash_equal
|
||||||
|
#define uint32_t_hash kh_int_hash_func
|
||||||
|
#define uint32_t_eq kh_int_hash_equal
|
||||||
|
|
||||||
KHASH_MAP_INIT_STR(Map, Value)
|
#if defined(ARCH_64)
|
||||||
|
#define ptr_t_hash(key) uint64_t_hash((uint64_t)key)
|
||||||
|
#define ptr_t_eq(a, b) uint64_t_eq((uint64_t)a, (uint64_t)b)
|
||||||
|
#elif defined(ARCH_32)
|
||||||
|
#define ptr_t_hash(key) uint32_t_hash((uint32_t)key)
|
||||||
|
#define ptr_t_eq(a, b) uint32_t_eq((uint32_t)a, (uint32_t)b)
|
||||||
|
#endif
|
||||||
|
|
||||||
struct map {
|
|
||||||
khash_t(Map) *table;
|
|
||||||
};
|
|
||||||
|
|
||||||
Map *map_new()
|
#define MAP_IMPL(T) \
|
||||||
{
|
__KHASH_IMPL(T##_map,, T, void *, 1, T##_hash, T##_eq) \
|
||||||
Map *rv = xmalloc(sizeof(Map));
|
\
|
||||||
rv->table = kh_init(Map);
|
Map(T) *map_##T##_new() \
|
||||||
return rv;
|
{ \
|
||||||
}
|
Map(T) *rv = xmalloc(sizeof(Map(T))); \
|
||||||
|
rv->table = kh_init(T##_map); \
|
||||||
void map_free(Map *map)
|
return rv; \
|
||||||
{
|
} \
|
||||||
kh_clear(Map, map->table);
|
\
|
||||||
kh_destroy(Map, map->table);
|
void map_##T##_free(Map(T) *map) \
|
||||||
free(map);
|
{ \
|
||||||
}
|
kh_destroy(T##_map, map->table); \
|
||||||
|
free(map); \
|
||||||
void *map_get(Map *map, const char *key)
|
} \
|
||||||
{
|
\
|
||||||
khiter_t k;
|
void *map_##T##_get(Map(T) *map, T key) \
|
||||||
|
{ \
|
||||||
if ((k = kh_get(Map, map->table, key)) == kh_end(map->table)) {
|
khiter_t k; \
|
||||||
return NULL;
|
\
|
||||||
|
if ((k = kh_get(T##_map, map->table, key)) == kh_end(map->table)) { \
|
||||||
|
return NULL; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
return kh_val(map->table, k); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
bool map_##T##_has(Map(T) *map, T key) \
|
||||||
|
{ \
|
||||||
|
return kh_get(T##_map, map->table, key) != kh_end(map->table); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
void *map_##T##_put(Map(T) *map, T key, void *value) \
|
||||||
|
{ \
|
||||||
|
int ret; \
|
||||||
|
void *rv = NULL; \
|
||||||
|
khiter_t k = kh_put(T##_map, map->table, key, &ret); \
|
||||||
|
\
|
||||||
|
if (!ret) { \
|
||||||
|
rv = kh_val(map->table, k); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
kh_val(map->table, k) = value; \
|
||||||
|
return rv; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
void *map_##T##_del(Map(T) *map, T key) \
|
||||||
|
{ \
|
||||||
|
void *rv = NULL; \
|
||||||
|
khiter_t k; \
|
||||||
|
\
|
||||||
|
if ((k = kh_get(T##_map, map->table, key)) != kh_end(map->table)) { \
|
||||||
|
rv = kh_val(map->table, k); \
|
||||||
|
kh_del(T##_map, map->table, k); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
return rv; \
|
||||||
}
|
}
|
||||||
|
|
||||||
return kh_val(map->table, k).ptr;
|
MAP_IMPL(cstr_t)
|
||||||
}
|
MAP_IMPL(ptr_t)
|
||||||
|
|
||||||
bool map_has(Map *map, const char *key)
|
|
||||||
{
|
|
||||||
return map_get(map, key) != NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *map_put(Map *map, const char *key, void *value)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
void *rv = NULL;
|
|
||||||
khiter_t k = kh_put(Map, map->table, key, &ret);
|
|
||||||
Value val = {.ptr = value};
|
|
||||||
|
|
||||||
if (!ret) {
|
|
||||||
// key present, return the current value
|
|
||||||
rv = kh_val(map->table, k).ptr;
|
|
||||||
kh_del(Map, map->table, k);
|
|
||||||
}
|
|
||||||
|
|
||||||
kh_val(map->table, k) = val;
|
|
||||||
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *map_del(Map *map, const char *key)
|
|
||||||
{
|
|
||||||
void *rv = NULL;
|
|
||||||
khiter_t k;
|
|
||||||
|
|
||||||
if ((k = kh_get(Map, map->table, key)) != kh_end(map->table)) {
|
|
||||||
rv = kh_val(map->table, k).ptr;
|
|
||||||
kh_del(Map, map->table, k);
|
|
||||||
}
|
|
||||||
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
void map_foreach(Map *map, key_value_cb cb)
|
|
||||||
{
|
|
||||||
const char *key;
|
|
||||||
Value value;
|
|
||||||
|
|
||||||
kh_foreach(map->table, key, value, {
|
|
||||||
cb(map, (const char *)key, value.ptr);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// General-purpose string->pointer associative array with a simple API
|
|
||||||
#ifndef NVIM_MAP_H
|
#ifndef NVIM_MAP_H
|
||||||
#define NVIM_MAP_H
|
#define NVIM_MAP_H
|
||||||
|
|
||||||
@@ -6,52 +5,35 @@
|
|||||||
|
|
||||||
#include "nvim/map_defs.h"
|
#include "nvim/map_defs.h"
|
||||||
|
|
||||||
/// Creates a new `Map` instance
|
#define MAP_DECLS(T) \
|
||||||
///
|
KHASH_DECLARE(T##_map, T, void *) \
|
||||||
/// @return a pointer to the new instance
|
\
|
||||||
Map *map_new(void);
|
typedef struct { \
|
||||||
|
khash_t(T##_map) *table; \
|
||||||
|
} Map(T); \
|
||||||
|
\
|
||||||
|
Map(T) *map_##T##_new(void); \
|
||||||
|
void map_##T##_free(Map(T) *map); \
|
||||||
|
void *map_##T##_get(Map(T) *map, T key); \
|
||||||
|
bool map_##T##_has(Map(T) *map, T key); \
|
||||||
|
void* map_##T##_put(Map(T) *map, T key, void *value); \
|
||||||
|
void* map_##T##_del(Map(T) *map, T key);
|
||||||
|
|
||||||
/// Frees memory for a `Map` instance
|
MAP_DECLS(cstr_t)
|
||||||
///
|
MAP_DECLS(ptr_t)
|
||||||
/// @param map The `Map` instance
|
|
||||||
void map_free(Map *map);
|
|
||||||
|
|
||||||
/// Gets the value corresponding to a key in a `Map` instance
|
#define map_new(T) map_##T##_new
|
||||||
///
|
#define map_free(T) map_##T##_free
|
||||||
/// @param map The `Map` instance
|
#define map_get(T) map_##T##_get
|
||||||
/// @param key A key string
|
#define map_has(T) map_##T##_has
|
||||||
/// @return The value if the key exists in the map, or NULL if it doesn't
|
#define map_put(T) map_##T##_put
|
||||||
void *map_get(Map *map, const char *key);
|
#define map_del(T) map_##T##_del
|
||||||
|
|
||||||
/// Checks if a key exists in the map
|
#define map_foreach(map, key, value, block) \
|
||||||
///
|
kh_foreach(map->table, key, value, block)
|
||||||
/// @param map The `Map` instance
|
|
||||||
/// @param key A key string
|
|
||||||
/// @return true if the key exists, false otherwise
|
|
||||||
bool map_has(Map *map, const char *key);
|
|
||||||
|
|
||||||
/// Set the value corresponding to a key in a `Map` instance and returns
|
#define map_foreach_value(map, value, block) \
|
||||||
/// the old value.
|
kh_foreach_value(map->table, value, block)
|
||||||
///
|
|
||||||
/// @param map The `Map` instance
|
|
||||||
/// @param key A key string
|
|
||||||
/// @param value A value
|
|
||||||
/// @return The current value if exists or NULL otherwise
|
|
||||||
void *map_put(Map *map, const char *key, void *value);
|
|
||||||
|
|
||||||
/// Deletes the value corresponding to a key in a `Map` instance and returns
|
#endif // NVIM_MAP_H
|
||||||
/// the old value.
|
|
||||||
///
|
|
||||||
/// @param map The `Map` instance
|
|
||||||
/// @param key A key string
|
|
||||||
/// @return The current value if exists or NULL otherwise
|
|
||||||
void *map_del(Map *map, const char *key);
|
|
||||||
|
|
||||||
/// Iterates through each key/value pair in the map
|
|
||||||
///
|
|
||||||
/// @param map The `Map` instance
|
|
||||||
/// @param cb A function that will be called for each key/value
|
|
||||||
void map_foreach(Map *map, key_value_cb cb);
|
|
||||||
|
|
||||||
#endif /* NVIM_MAP_H */
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
#ifndef NVIM_MAP_DEFS_H
|
#ifndef NVIM_MAP_DEFS_H
|
||||||
#define NVIM_MAP_DEFS_H
|
#define NVIM_MAP_DEFS_H
|
||||||
|
|
||||||
typedef struct map Map;
|
|
||||||
|
|
||||||
/// Callback for iterating through each key/value pair in a map
|
#include "nvim/lib/khash.h"
|
||||||
///
|
|
||||||
/// @param map The `Map` instance
|
|
||||||
/// @param key A key string
|
|
||||||
/// @param value A value
|
|
||||||
typedef void (*key_value_cb)(Map *map, const char *key, void *value);
|
|
||||||
|
|
||||||
#endif /* NVIM_MAP_DEFS_H */
|
typedef const char * cstr_t;
|
||||||
|
typedef void * ptr_t;
|
||||||
|
|
||||||
|
#define Map(T) Map_##T
|
||||||
|
|
||||||
|
|
||||||
|
#endif // NVIM_MAP_DEFS_H
|
||||||
|
|
||||||
|
|||||||
@@ -43,16 +43,15 @@ typedef struct {
|
|||||||
} socket;
|
} socket;
|
||||||
} Server;
|
} Server;
|
||||||
|
|
||||||
static Map *servers = NULL;
|
static Map(cstr_t) *servers = NULL;
|
||||||
|
|
||||||
static void close_server(Map *map, const char *endpoint, void *server);
|
|
||||||
static void connection_cb(uv_stream_t *server, int status);
|
static void connection_cb(uv_stream_t *server, int status);
|
||||||
static void free_client(uv_handle_t *handle);
|
static void free_client(uv_handle_t *handle);
|
||||||
static void free_server(uv_handle_t *handle);
|
static void free_server(uv_handle_t *handle);
|
||||||
|
|
||||||
void server_init()
|
void server_init()
|
||||||
{
|
{
|
||||||
servers = map_new();
|
servers = map_new(cstr_t)();
|
||||||
|
|
||||||
if (!os_getenv("NEOVIM_LISTEN_ADDRESS")) {
|
if (!os_getenv("NEOVIM_LISTEN_ADDRESS")) {
|
||||||
char *listen_address = (char *)vim_tempname('s');
|
char *listen_address = (char *)vim_tempname('s');
|
||||||
@@ -70,7 +69,15 @@ void server_teardown()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
map_foreach(servers, close_server);
|
Server *server;
|
||||||
|
|
||||||
|
map_foreach_value(servers, server, {
|
||||||
|
if (server->type == kServerTypeTcp) {
|
||||||
|
uv_close((uv_handle_t *)&server->socket.tcp.handle, free_server);
|
||||||
|
} else {
|
||||||
|
uv_close((uv_handle_t *)&server->socket.pipe.handle, free_server);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void server_start(char *endpoint, ChannelProtocol prot)
|
void server_start(char *endpoint, ChannelProtocol prot)
|
||||||
@@ -81,7 +88,7 @@ void server_start(char *endpoint, ChannelProtocol prot)
|
|||||||
strncpy(addr, endpoint, sizeof(addr));
|
strncpy(addr, endpoint, sizeof(addr));
|
||||||
|
|
||||||
// Check if the server already exists
|
// Check if the server already exists
|
||||||
if (map_has(servers, addr)) {
|
if (map_has(cstr_t)(servers, addr)) {
|
||||||
EMSG2("Already listening on %s", addr);
|
EMSG2("Already listening on %s", addr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -167,7 +174,7 @@ void server_start(char *endpoint, ChannelProtocol prot)
|
|||||||
server->type = server_type;
|
server->type = server_type;
|
||||||
|
|
||||||
// Add the server to the hash table
|
// Add the server to the hash table
|
||||||
map_put(servers, addr, server);
|
map_put(cstr_t)(servers, addr, server);
|
||||||
}
|
}
|
||||||
|
|
||||||
void server_stop(char *endpoint)
|
void server_stop(char *endpoint)
|
||||||
@@ -178,7 +185,7 @@ void server_stop(char *endpoint)
|
|||||||
// Trim to `ADDRESS_MAX_SIZE`
|
// Trim to `ADDRESS_MAX_SIZE`
|
||||||
strncpy(addr, endpoint, sizeof(addr));
|
strncpy(addr, endpoint, sizeof(addr));
|
||||||
|
|
||||||
if ((server = map_get(servers, addr)) == NULL) {
|
if ((server = map_get(cstr_t)(servers, addr)) == NULL) {
|
||||||
EMSG2("Not listening on %s", addr);
|
EMSG2("Not listening on %s", addr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -189,7 +196,7 @@ void server_stop(char *endpoint)
|
|||||||
uv_close((uv_handle_t *)&server->socket.pipe.handle, free_server);
|
uv_close((uv_handle_t *)&server->socket.pipe.handle, free_server);
|
||||||
}
|
}
|
||||||
|
|
||||||
map_del(servers, addr);
|
map_del(cstr_t)(servers, addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void connection_cb(uv_stream_t *server, int status)
|
static void connection_cb(uv_stream_t *server, int status)
|
||||||
@@ -221,17 +228,6 @@ static void connection_cb(uv_stream_t *server, int status)
|
|||||||
channel_from_stream(client, srv->protocol);
|
channel_from_stream(client, srv->protocol);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void close_server(Map *map, const char *endpoint, void *srv)
|
|
||||||
{
|
|
||||||
Server *server = srv;
|
|
||||||
|
|
||||||
if (server->type == kServerTypeTcp) {
|
|
||||||
uv_close((uv_handle_t *)&server->socket.tcp.handle, free_server);
|
|
||||||
} else {
|
|
||||||
uv_close((uv_handle_t *)&server->socket.pipe.handle, free_server);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void free_client(uv_handle_t *handle)
|
static void free_client(uv_handle_t *handle)
|
||||||
{
|
{
|
||||||
free(handle);
|
free(handle);
|
||||||
|
|||||||
Reference in New Issue
Block a user