Home > Software engineering >  How to do a sequential read in a lua table in c code
How to do a sequential read in a lua table in c code

Time:01-23

I have a lua table that I need to read sequentially, but the reading order is completely random

Table:

    MP_STATS = {
      ENABLE = true,
      NOBLOCK = false,
      RECOVERY = false,
      EXPERIENCE = true,
      ....
    }

Code example:

void read_test(void){
    lua_State *L;
    L = luaL_newstate();
    luaL_openlibs(L);

    if (luaL_loadfile(L, "test.lua") || lua_pcall(L, 0, 0, 0))
    {
        ShowError("Error reading 'test.lua'\n");
        return;
    }

    lua_getglobal(L, "MP_STATS");   
    lua_pushnil(L);
    while (lua_next(L, 1) != 0) {
        const char *name = lua_tostring(L, 2);
        
        if(check_exist_stats(name) == 0) {
            printf("Stats %s not exist.\n", name);
            lua_pop(L, 1);
            continue;
        }
        
        lua_getfield(L, lua_gettop(L), name);
        myvar = lua_toboolean(L, lua_gettop(L));
        lua_pop(L, 1);
        printf("%s\n", name);
    }

    lua_close(L);
    printf("Read test.lua complete.\n");

}

When I run the program I have the following reading order

First run:

MP_NOBLOCK
MP_ENABLE
MP_EXPERIENCE
MP_RECOVERY

Second run:

MP_RECOVERY
MP_ENABLE
MP_NOBLOCK
MP_EXPERIENCE

Third run:

MP_ENABLE
MP_NOBLOCK
MP_EXPERIENCE
MP_RECOVERY

What should I do for reading to be done in sequence?

CodePudding user response:

Non-sequence entries of Lua tables use the hash part - that is, the order of traversal depends on the hashes of the keys; it does not depend on the order of key-value pairs in your table constructor (your code). Newer Lua versions will "randomize" hashes to mitigate hash collision attacks. This is why you get a different order each time.

The "fix" is to either:

  1. Keep your current table structure, but add a second table local order = {"ENABLE", "NOBLOCK", "EXPERIENCE", "RECOVERY", ...} to remember the order of the keys. Then loop over this second table, which uses the "array part" in order using ipairs and use the values as keys for your current table structure.
  2. Switch to a "list" for your MP_STATS table and use said order table to look up keys for given indices.
  3. Switch to a "list" of "pairs" {key = "...", value = "..."} which can be iterated in-order using ipairs.

CodePudding user response:

Tables are associative arrays. Depending on the implementation, they may or may not provide a consistent ordering.

So does Lua use an implementation that returns a consistent ordering? As you already discovered, no. "The order in which the indices are enumerated is not specified, even for numeric indices", says the documentation for next.

Lua does not provide the elements in the (unspecified) order you desire, because it returns the elements in an arbitrary order.


Note that the order isn't random, merely arbitrary.

  •  Tags:  
  • clua
  • Related