diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2019-04-26 11:24:39 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2019-04-26 11:24:39 -0300 |
commit | b36e26f51b117df98f0f5376f352c2381df3025f (patch) | |
tree | 08746cdf1eb94110e4cf92e5b9ca9e98020e8514 /lobject.c | |
parent | 969b8c1f14f69c1406f00df3b5f375a9efb7b78f (diff) | |
download | lua-b36e26f51b117df98f0f5376f352c2381df3025f.tar.gz lua-b36e26f51b117df98f0f5376f352c2381df3025f.tar.bz2 lua-b36e26f51b117df98f0f5376f352c2381df3025f.zip |
Some more small improvements to 'luaO_pushvfstring'
Details:
- counter 'pushed' moved to the struct 'BuffFS'
- new auxiliar function 'getbuff' to build strings directly on
the buffer.
Diffstat (limited to 'lobject.c')
-rw-r--r-- | lobject.c | 122 |
1 files changed, 68 insertions, 54 deletions
@@ -392,126 +392,144 @@ void luaO_tostring (lua_State *L, TValue *obj) { | |||
392 | } | 392 | } |
393 | 393 | ||
394 | 394 | ||
395 | /* size for buffer used by 'luaO_pushvfstring' */ | 395 | /* size for buffer space used by 'luaO_pushvfstring' */ |
396 | #define BUFVFS 400 | 396 | #define BUFVFS 400 |
397 | 397 | ||
398 | /* buffer used by 'luaO_pushvfstring' */ | 398 | /* buffer used by 'luaO_pushvfstring' */ |
399 | typedef struct BuffFS { | 399 | typedef struct BuffFS { |
400 | int blen; /* length of partial string in 'buff' */ | 400 | int pushed; /* number of string pieces already on the stack */ |
401 | char buff[BUFVFS]; /* holds last part of the result */ | 401 | int blen; /* length of partial string in 'space' */ |
402 | char space[BUFVFS]; /* holds last part of the result */ | ||
402 | } BuffFS; | 403 | } BuffFS; |
403 | 404 | ||
404 | 405 | ||
405 | static void pushstr (lua_State *L, const char *str, size_t l) { | 406 | /* |
407 | ** Push given string to the stack, as part of the buffer. If the stack | ||
408 | ** is almost full, join all partial strings in the stack into one. | ||
409 | */ | ||
410 | static void pushstr (lua_State *L, BuffFS *buff, const char *str, size_t l) { | ||
406 | setsvalue2s(L, L->top, luaS_newlstr(L, str, l)); | 411 | setsvalue2s(L, L->top, luaS_newlstr(L, str, l)); |
407 | L->top++; | 412 | L->top++; |
413 | buff->pushed++; | ||
414 | if (buff->pushed > 1 && L->top + 2 > L->stack_last) { | ||
415 | luaV_concat(L, buff->pushed); /* join all partial results into one */ | ||
416 | buff->pushed = 1; | ||
417 | } | ||
408 | } | 418 | } |
409 | 419 | ||
410 | 420 | ||
411 | /* | 421 | /* |
412 | ** empty the buffer into the stack | 422 | ** empty the buffer space into the stack |
413 | */ | 423 | */ |
414 | static void clearbuff (lua_State *L, BuffFS *buff) { | 424 | static void clearbuff (lua_State *L, BuffFS *buff) { |
415 | pushstr(L, buff->buff, buff->blen); /* push buffer */ | 425 | pushstr(L, buff, buff->space, buff->blen); /* push buffer contents */ |
416 | buff->blen = 0; /* buffer now is empty */ | 426 | buff->blen = 0; /* space now is empty */ |
417 | } | 427 | } |
418 | 428 | ||
419 | 429 | ||
420 | /* | 430 | /* |
421 | ** Add 'str' to the buffer. It buffer has no enough space, | 431 | ** Get a space of size 'sz' in the buffer. If buffer has not enough |
422 | ** empty the buffer. If string is still larger than the buffer, | 432 | ** space, empty it. 'sz' must fit in an empty space. |
423 | ** push the string directly to the stack. Return number of items | ||
424 | ** pushed. | ||
425 | */ | 433 | */ |
426 | static int addstr2buff (lua_State *L, BuffFS *buff, const char *str, | 434 | static char *getbuff (lua_State *L, BuffFS *buff, size_t sz) { |
427 | size_t slen) { | 435 | lua_assert(buff->blen <= BUFVFS); lua_assert(sz <= BUFVFS); |
428 | int pushed = 0; /* number of items pushed to the stack */ | 436 | if (sz > BUFVFS - cast_sizet(buff->blen)) /* string does not fit? */ |
429 | lua_assert(buff->blen <= BUFVFS); | ||
430 | if (slen > BUFVFS - cast_sizet(buff->blen)) { /* string does not fit? */ | ||
431 | clearbuff(L, buff); | 437 | clearbuff(L, buff); |
432 | pushed = 1; | 438 | return buff->space + buff->blen; |
433 | if (slen >= BUFVFS) { /* string still does not fit into buffer? */ | 439 | } |
434 | pushstr(L, str, slen); /* push string */ | 440 | |
435 | return 2; | 441 | |
436 | } | 442 | #define addsize(b,sz) ((b)->blen += (sz)) |
443 | |||
444 | |||
445 | /* | ||
446 | ** Add 'str' to the buffer. If string is larger than the buffer space, | ||
447 | ** push the string directly to the stack. | ||
448 | */ | ||
449 | static void addstr2buff (lua_State *L, BuffFS *buff, const char *str, | ||
450 | size_t slen) { | ||
451 | if (slen <= BUFVFS) { /* does string fit into buffer? */ | ||
452 | char *bf = getbuff(L, buff, slen); | ||
453 | memcpy(bf, str, slen); /* add string to buffer */ | ||
454 | addsize(buff, slen); | ||
455 | } | ||
456 | else { /* string larger than buffer */ | ||
457 | clearbuff(L, buff); /* string comes after buffer's content */ | ||
458 | pushstr(L, buff, str, slen); /* push string */ | ||
437 | } | 459 | } |
438 | memcpy(buff->buff + buff->blen, str, slen); /* add string to buffer */ | ||
439 | buff->blen += slen; | ||
440 | return pushed; | ||
441 | } | 460 | } |
442 | 461 | ||
443 | 462 | ||
444 | /* | 463 | /* |
445 | ** Add a number to the buffer; return number of strings pushed into | 464 | ** Add a number to the buffer. |
446 | ** the stack. (At most one, to free buffer space.) | ||
447 | */ | 465 | */ |
448 | static int addnum2buff (lua_State *L, BuffFS *buff, TValue *num) { | 466 | static void addnum2buff (lua_State *L, BuffFS *buff, TValue *num) { |
449 | char numbuff[MAXNUMBER2STR]; | 467 | char *numbuff = getbuff(L, buff, MAXNUMBER2STR); |
450 | size_t len = tostringbuff(num, numbuff); /* format number into 'numbuff' */ | 468 | size_t len = tostringbuff(num, numbuff); /* format number into 'numbuff' */ |
451 | return addstr2buff(L, buff, numbuff, len); | 469 | addsize(buff, len); |
452 | } | 470 | } |
453 | 471 | ||
454 | 472 | ||
455 | /* | 473 | /* |
456 | ** this function handles only '%d', '%c', '%f', '%p', and '%s' | 474 | ** this function handles only '%d', '%c', '%f', '%p', '%s', and '%%' |
457 | conventional formats, plus Lua-specific '%I' and '%U' | 475 | conventional formats, plus Lua-specific '%I' and '%U' |
458 | */ | 476 | */ |
459 | const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) { | 477 | const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) { |
460 | BuffFS buff; /* holds last part of the result */ | 478 | BuffFS buff; /* holds last part of the result */ |
461 | int pushed = 0; /* number of strings in the stack to concatenate */ | ||
462 | const char *e; /* points to next '%' */ | 479 | const char *e; /* points to next '%' */ |
463 | buff.blen = 0; | 480 | buff.pushed = buff.blen = 0; |
464 | while ((e = strchr(fmt, '%')) != NULL) { | 481 | while ((e = strchr(fmt, '%')) != NULL) { |
465 | pushed += addstr2buff(L, &buff, fmt, e - fmt); /* add 'fmt' up to '%' */ | 482 | addstr2buff(L, &buff, fmt, e - fmt); /* add 'fmt' up to '%' */ |
466 | switch (*(e + 1)) { /* conversion specifier */ | 483 | switch (*(e + 1)) { /* conversion specifier */ |
467 | case 's': { /* zero-terminated string */ | 484 | case 's': { /* zero-terminated string */ |
468 | const char *s = va_arg(argp, char *); | 485 | const char *s = va_arg(argp, char *); |
469 | if (s == NULL) s = "(null)"; | 486 | if (s == NULL) s = "(null)"; |
470 | pushed += addstr2buff(L, &buff, s, strlen(s)); | 487 | addstr2buff(L, &buff, s, strlen(s)); |
471 | break; | 488 | break; |
472 | } | 489 | } |
473 | case 'c': { /* an 'int' as a character */ | 490 | case 'c': { /* an 'int' as a character */ |
474 | /* if non-printable character, print its code */ | 491 | /* if non-printable character, print its code */ |
475 | char bf[10]; | 492 | char *bf = getbuff(L, &buff, 10); |
476 | int c = va_arg(argp, int); | 493 | int c = va_arg(argp, int); |
477 | int l = (lisprint(c)) ? l_sprintf(bf, sizeof(bf), "%c", c) | 494 | int len = (lisprint(c)) ? l_sprintf(bf, 10, "%c", c) |
478 | : l_sprintf(bf, sizeof(bf), "<\\%u>", c); | 495 | : l_sprintf(bf, 10, "<\\%u>", c); |
479 | pushed += addstr2buff(L, &buff, bf, l); | 496 | addsize(&buff, len); |
480 | break; | 497 | break; |
481 | } | 498 | } |
482 | case 'd': { /* an 'int' */ | 499 | case 'd': { /* an 'int' */ |
483 | TValue num; | 500 | TValue num; |
484 | setivalue(&num, va_arg(argp, int)); | 501 | setivalue(&num, va_arg(argp, int)); |
485 | pushed += addnum2buff(L, &buff, &num); | 502 | addnum2buff(L, &buff, &num); |
486 | break; | 503 | break; |
487 | } | 504 | } |
488 | case 'I': { /* a 'lua_Integer' */ | 505 | case 'I': { /* a 'lua_Integer' */ |
489 | TValue num; | 506 | TValue num; |
490 | setivalue(&num, cast(lua_Integer, va_arg(argp, l_uacInt))); | 507 | setivalue(&num, cast(lua_Integer, va_arg(argp, l_uacInt))); |
491 | pushed += addnum2buff(L, &buff, &num); | 508 | addnum2buff(L, &buff, &num); |
492 | break; | 509 | break; |
493 | } | 510 | } |
494 | case 'f': { /* a 'lua_Number' */ | 511 | case 'f': { /* a 'lua_Number' */ |
495 | TValue num; | 512 | TValue num; |
496 | setfltvalue(&num, cast_num(va_arg(argp, l_uacNumber))); | 513 | setfltvalue(&num, cast_num(va_arg(argp, l_uacNumber))); |
497 | pushed += addnum2buff(L, &buff, &num); | 514 | addnum2buff(L, &buff, &num); |
498 | break; | 515 | break; |
499 | } | 516 | } |
500 | case 'p': { /* a pointer */ | 517 | case 'p': { /* a pointer */ |
501 | char bf[3 * sizeof(void*) + 8]; /* should be enough space for '%p' */ | 518 | const int sz = 3 * sizeof(void*) + 8; /* enough space for '%p' */ |
519 | char *bf = getbuff(L, &buff, sz); | ||
502 | void *p = va_arg(argp, void *); | 520 | void *p = va_arg(argp, void *); |
503 | int l = l_sprintf(bf, sizeof(bf), "%p", p); | 521 | int len = l_sprintf(bf, sz, "%p", p); |
504 | pushed += addstr2buff(L, &buff, bf, l); | 522 | addsize(&buff, len); |
505 | break; | 523 | break; |
506 | } | 524 | } |
507 | case 'U': { /* a 'long' as a UTF-8 sequence */ | 525 | case 'U': { /* a 'long' as a UTF-8 sequence */ |
508 | char bf[UTF8BUFFSZ]; | 526 | char bf[UTF8BUFFSZ]; |
509 | int l = luaO_utf8esc(bf, va_arg(argp, long)); | 527 | int len = luaO_utf8esc(bf, va_arg(argp, long)); |
510 | pushed += addstr2buff(L, &buff, bf + UTF8BUFFSZ - l, l); | 528 | addstr2buff(L, &buff, bf + UTF8BUFFSZ - len, len); |
511 | break; | 529 | break; |
512 | } | 530 | } |
513 | case '%': { | 531 | case '%': { |
514 | pushed += addstr2buff(L, &buff, "%", 1); | 532 | addstr2buff(L, &buff, "%", 1); |
515 | break; | 533 | break; |
516 | } | 534 | } |
517 | default: { | 535 | default: { |
@@ -519,16 +537,12 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) { | |||
519 | *(e + 1)); | 537 | *(e + 1)); |
520 | } | 538 | } |
521 | } | 539 | } |
522 | if (pushed > 1 && L->top + 2 > L->stack_last) { /* no free stack space? */ | ||
523 | luaV_concat(L, pushed); /* join all partial results into one */ | ||
524 | pushed = 1; | ||
525 | } | ||
526 | fmt = e + 2; /* skip '%' and the specifier */ | 540 | fmt = e + 2; /* skip '%' and the specifier */ |
527 | } | 541 | } |
528 | pushed += addstr2buff(L, &buff, fmt, strlen(fmt)); /* rest of 'fmt' */ | 542 | addstr2buff(L, &buff, fmt, strlen(fmt)); /* rest of 'fmt' */ |
529 | clearbuff(L, &buff); /* empty buffer into the stack */ | 543 | clearbuff(L, &buff); /* empty buffer into the stack */ |
530 | if (pushed > 0) | 544 | if (buff.pushed > 1) |
531 | luaV_concat(L, pushed + 1); /* join all partial results */ | 545 | luaV_concat(L, buff.pushed); /* join all partial results */ |
532 | return svalue(s2v(L->top - 1)); | 546 | return svalue(s2v(L->top - 1)); |
533 | } | 547 | } |
534 | 548 | ||