tags:

views:

79

answers:

2

Hi all, Mac OS X 10.5 compatibility, Lua 5.0 compatibility required (hence cannot use current batch of LuaObjc bridges.)

My lua script produces an indexed table containing tens of thousands of strings.

Basic problem: how to concat those strings with a newline separator, to one string, quickly?

Fly in ointment: even using garbage-collection friendly concat code (provided at stackoverflow) the results take far too long for this purpose. (10 seconds vs 1 minute for a brute force solution.)

Proposed solution: offload the job to Cocoa, where it can be done in a fraction of a second, using NSArray's -componentsJoinedByString method.

New fly in ointment: how to get table data from Lua to Cocoa?

The script calls a registered C function, passing it the table. The C function tries to grab the table on the stack:

// Get an NSArray of strings from the first argument on the stack (a table).
NSArray *strings = nsArrayFromIndexedTable(luaState, index_1Based);

...

// Given a simple table consisting of numbers or strings, returns an NSArray.
// Nested subtables are not followed.

NSArray * nsArrayFromIndexedTable(lua_State *L, int argIdx)
{
    // (Allegedly) stops GC.
    lua_setgcthreshold(L, INT_MAX);

    // Arg must be a table.
    luaL_checktype(L, argIdx, LUA_TTABLE);

    // Get num elements in table, build an array with that many.
    int count = luaL_getn(L, 1);

    NSMutableArray *array = [NSMutableArray arrayWithCapacity: count];

    int i;
    for (i = 1; i <= count; i++) {

        lua_rawgeti(L, argIdx, i);
        int valueType = lua_type(L, -1);
        id value = 0x00;

        if (valueType is_eq LUA_TNUMBER) {
            value = [NSNumber numberWithDouble:lua_tonumber(L, -1)];
        } else if (valueType is_eq LUA_TSTRING) {
            value = [NSString stringWithUTF8String:lua_tostring(L,  -1)];
        }

        if (value) {
            [array addObject:value];
        }
    }

    // Resume GC
    lua_setgcthreshold(L, 0);    // INTERMITTENT EXC_BAD_ACCESS CRASH HERE!!!!

    return array;
}

Problem: calling this function with a (very large) Lua table of strings (intermittently) results in a EXC_BAD_ACCESS.

Debugger results are sporadic; sometimes not providing anything useful, but I've been able to glean that:

  • If those Lua GC lines included, the crash happens at lua_setgcthreshold, near the end of the function.

  • But... if those Lua GC lines are commented out, the crash happens at [array addObject:value]

(NSZombieEnabled is on, but is not providing useful info.)

Any help is appreciated.

A: 

This:

int count = luaL_getn(L, 1);

Should be:

int count = luaL_getn(L, argIdx);    

So you may be getting an incorrect row count and scanning off the end of the table.

Graham Perks
Thanks Graham. I've made the change but alas, the problem still remains. It's dying in luaC_collectgarbage(). Cheers.
SirRatty
A: 

Maybe you grow your C stack too much. I am not familiar with Cocoa, but I guess that the Lua values need not be accessible all the time - the string should be copied into NSString. If it is so, try including a lua_pop(L, 1) at the end of the loop, to clean up the C stack and keep it from growing.

MiKy