lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


> On 19 Oct 2023, at 19:16, Roberto Ierusalimschy <roberto@inf.puc-rio.br> wrote:
> 
>> There are a few things it'd be nice to be able to tell stock Lua are
>> static data it doesn't need to take a RAM copy of. C string literals
>> are another example, although caveat emptor would have to apply, as of
>> course even static data can stop being accessible if the code segment
>> is unloaded.
> 
> It is not difficult to have in Lua a kind of 'lua_pushliteral' for
> static strings, provided the string is "long" (at least 40 bytes).
> My question is, would that be useful? If an application is written to be
> small, would it have any significant number of long (or a few really
> long) strings?

My use-case was in embedded situations, where you might have things like bitmaps embedded in the ROM as a `static const char[]`, and then want to expose those to Lua as strings. Sure you could push them as lightuserdata instead, but then you lose the size information and your render function then needs to handle 2 different datatypes.

In embedded situations you frequently have more readonly memory than you do real RAM (at least, in the boards I tend to use it seems to be a common trend) so jumping through a few hoops to avoid putting things in RAM can be quite valuable. And things like bitmaps can be disproportionally large compared to the rest of the program's memory footprint (given that things like NodeMCU already ensure that the program code itself is in ROM not RAM).

Of course the minute you need to chop up the string you'll end up doing a copy, but things like bitmaps are fairly atomic and you rarely have to substring them (at least, not in Lua code, or if you do the substrings are short-lived).

Having a 'slice' string type for substrings of long strings would be an interesting thing to consider too, but that potentially complicates things more and I don't have such a concrete use-case for them. Seems like a thing I'd probably use though, if there was a string.slice() API alongside string.sub(), even if it does open up the possibility of making a net detriment if used incorrectly.

The other thing I've wished for, and actually wrote an implementation of for NodeMCU, was the ability to 2-phase construct strings rather like how luaL_Buffer works but without having an intermediate copy. That is, I know in advance how big the string will be, and wanted to allocate the memory for the string, fill in the data, and then commit it without needing an additional alloc. I think my solution was to make an API which malloc'd a buffer of sizeof(TString)+sz, return the pointer to the start of the data, then have an API to "commit" that buffer which filled in the rest of the TString data to make it a real Lua string and pushed it onto the stack. In hindsight maybe I could've altered the implementation of luaL_Buffer to achieve that, but in the end I made it a separate API. And supporting realloc wasn't that hard for the times when I didn't know the exact size in advance.

Ah, here's the implementation: see lapi.c in https://github.com/tomsci/nodemcu-firmware/commit/09bdc6c2f064862d364aeb80b9707ccd64a7d160 I should probably just have linked that rather than try to explain it! It was a hack and I never fully productised it but it did appreciably improve memory consumption and fragmentation in a few critical areas.

Cheers,

Tom