Skip to content
Snippets Groups Projects
Commit 96dfce74 authored by Georgiy Lebedev's avatar Georgiy Lebedev Committed by Vladimir Davydov
Browse files

msgpack: add alias dictionary to MsgPack object used during indexing

Add an optional dictionary field to MsgPack object which can be used during
indexing for aliasing string keys.

Needed for #7901

NO_CHANGELOG=<internal feature>
NO_DOC=<internal feature>
parent a82c2462
No related branches found
No related tags found
No related merge requests found
......@@ -80,6 +80,13 @@ struct luamp_object {
* Initially set to `LUA_NOREF`.
*/
int decoded_ref;
/**
* Translation table containing string key aliases. If present, used
* during indexation.
* Must use `lua_hash` as the hash function.
* Initially set to NULL.
*/
struct mh_strnu32_t *translation;
};
static const char luamp_object_typename[] = "msgpack.object";
......@@ -709,18 +716,22 @@ luamp_new_object(struct lua_State *L, size_t data_len)
obj->data = (char *)obj + sizeof(*obj);
obj->data_end = obj->data + data_len;
obj->decoded_ref = LUA_NOREF;
obj->translation = NULL;
luaL_getmetatable(L, luamp_object_typename);
lua_setmetatable(L, -2);
return obj;
}
void
luamp_push(struct lua_State *L, const char *data, const char *data_end)
luamp_push_with_translation(struct lua_State *L, const char *data,
const char *data_end,
struct mh_strnu32_t *translation)
{
size_t data_len = data_end - data;
struct luamp_object *obj = luamp_new_object(L, data_len);
memcpy((char *)obj->data, data, data_len);
assert(mp_check(&data, data_end) == 0 && data == data_end);
obj->translation = translation;
}
/**
......@@ -878,6 +889,25 @@ luamp_object_get(struct lua_State *L)
lua_pushvalue(L, -2);
/* Indexes the decoded MsgPack data and pops the key. */
lua_rawget(L, -2);
if (!lua_isnil(L, -1) || obj->translation == NULL ||
lua_type(L, -3) != LUA_TSTRING)
return 1;
size_t len;
const char *alias = lua_tolstring(L, -3, &len);
struct mh_strnu32_key_t key = {
.str = alias,
.len = len,
.hash = lua_hashstring(L, -3),
};
mh_int_t k = mh_strnu32_find(obj->translation, &key, NULL);
if (k != mh_end(obj->translation)) {
lua_pop(L, 1);
struct mh_strnu32_node_t *node =
mh_strnu32_node(obj->translation, k);
luaL_pushuint64(L, node->val);
lua_rawget(L, -2);
}
return 1;
}
......
......@@ -63,11 +63,22 @@ luamp_error(void *);
enum { LUAMP_ALLOC_FACTOR = 256 };
/**
* Pushes to the Lua stack a new msgpack object and stores the given msgpack
* data in it. The new object uses the default serializer for decoding.
* Pushes a new MsgPack object and stores the given MsgPack data in it.
* The new object uses the default serializer for decoding.
* Passes a translation table to the MsgPack object which contains aliases for
* string keys used during indexation.
* The translation table must use `lua_hash` as the hash function.
*/
void
luamp_push(struct lua_State *L, const char *data, const char *data_end);
luamp_push_with_translation(struct lua_State *L, const char *data,
const char *data_end,
struct mh_strnu32_t *translation);
static inline void
luamp_push(struct lua_State *L, const char *data, const char *data_end)
{
luamp_push_with_translation(L, data, data_end, NULL);
}
/**
* Returns a pointer to the msgpack data and writes the length of the data to
......
......@@ -107,10 +107,48 @@ test_translation_in_encoding(lua_State *L)
check_plan();
}
/**
* Checks that MsgPack object with dictionaries work correctly.
*/
static void
test_translation_in_indexation(struct lua_State *L)
{
plan(1);
header();
struct mh_strnu32_t *translation = mh_strnu32_new();
const char *alias = "alias";
uint32_t key = 0;
struct mh_strnu32_node_t node = {
.str = alias,
.len = strlen(alias),
.hash = lua_hash(alias, strlen(alias)),
.val = key,
};
mh_strnu32_put(translation, &node, NULL, NULL);
char buf[64];
char *w = mp_encode_map(buf, 1);
w = mp_encode_uint(w, key);
w = mp_encode_bool(w, true);
luamp_push_with_translation(L, buf, w, translation);
lua_getfield(L, -1, alias);
ok(lua_toboolean(L, -1), "string key is aliased");
lua_pop(L, 2);
lua_gc(L, LUA_GCCOLLECT, 0);
mh_strnu32_delete(translation);
footer();
check_plan();
}
int
main(void)
{
plan(1);
plan(2);
header();
struct lua_State *L = luaL_newstate();
......@@ -123,6 +161,7 @@ main(void)
lua_pop(L, 1);
test_translation_in_encoding(L);
test_translation_in_indexation(L);
fiber_free();
memory_free();
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment