2
0
Эх сурвалжийг харах

From Lua 5.2: Add string.rep(s, n, sep).

Mike Pall 13 жил өмнө
parent
commit
2f5ed5d0df

+ 34 - 8
src/lib_string.c

@@ -86,22 +86,48 @@ LJLIB_ASM(string_sub)		LJLIB_REC(string_range 1)
 LJLIB_ASM(string_rep)
 {
   GCstr *s = lj_lib_checkstr(L, 1);
-  int32_t len = (int32_t)s->len;
   int32_t k = lj_lib_checkint(L, 2);
-  int64_t tlen = (int64_t)k * len;
+  GCstr *sep = lj_lib_optstr(L, 3);
+  int32_t len = (int32_t)s->len;
+  global_State *g = G(L);
+  int64_t tlen;
   const char *src;
   char *buf;
-  if (k <= 0) return FFH_RETRY;
-  if (tlen > LJ_MAX_STR)
-    lj_err_caller(L, LJ_ERR_STROV);
-  buf = lj_str_needbuf(L, &G(L)->tmpbuf, (MSize)tlen);
-  if (len <= 1) return FFH_RETRY;  /* ASM code only needed buffer resize. */
+  if (k <= 0) {
+  empty:
+    setstrV(L, L->base-1, &g->strempty);
+    return FFH_RES(1);
+  }
+  if (sep) {
+    tlen = (int64_t)len + sep->len;
+    if (tlen > LJ_MAX_STR)
+      lj_err_caller(L, LJ_ERR_STROV);
+    tlen *= k;
+    if (tlen > LJ_MAX_STR)
+      lj_err_caller(L, LJ_ERR_STROV);
+  } else {
+    tlen = (int64_t)k * len;
+    if (tlen > LJ_MAX_STR)
+      lj_err_caller(L, LJ_ERR_STROV);
+  }
+  if (tlen == 0) goto empty;
+  buf = lj_str_needbuf(L, &g->tmpbuf, (MSize)tlen);
   src = strdata(s);
+  if (sep) {
+    tlen -= sep->len;  /* Ignore trailing separator. */
+    if (k > 1) {  /* Paste one string and one separator. */
+      int32_t i;
+      i = 0; while (i < len) *buf++ = src[i++];
+      src = strdata(sep); len = sep->len;
+      i = 0; while (i < len) *buf++ = src[i++];
+      src = g->tmpbuf.buf; len += s->len; k--;  /* Now copy that k-1 times. */
+    }
+  }
   do {
     int32_t i = 0;
     do { *buf++ = src[i++]; } while (i < len);
   } while (--k > 0);
-  setstrV(L, L->base-1, lj_str_new(L, G(L)->tmpbuf.buf, (size_t)tlen));
+  setstrV(L, L->base-1, lj_str_new(L, g->tmpbuf.buf, (size_t)tlen));
   return FFH_RES(1);
 }
 

+ 1 - 1
src/vm_arm.dasc

@@ -1778,7 +1778,7 @@ static void build_subroutines(BuildCtx *ctx)
   |  ldrd CARG12, [BASE]
   |   ldrd CARG34, [BASE, #8]
   |    cmp NARGS8:RC, #16
-  |    blo ->fff_fallback
+  |    bne ->fff_fallback		// Exactly 2 arguments
   |  checktp CARG2, LJ_TSTR
   |   checktpeq CARG4, LJ_TISNUM
   |   bne ->fff_fallback

+ 1 - 1
src/vm_mips.dasc

@@ -1696,7 +1696,7 @@ static void build_subroutines(BuildCtx *ctx)
   |.ffunc string_rep			// Only handle the 1-char case inline.
   |  ffgccheck
   |  lw TMP0, HI(BASE)
-  |   sltiu AT, NARGS8:RC, 16
+  |   addiu AT, NARGS8:RC, -16		// Exactly 2 arguments.
   |  lw CARG4, 8+HI(BASE)
   |   lw STR:CARG1, LO(BASE)
   |  addiu TMP0, TMP0, -LJ_TSTR

+ 1 - 1
src/vm_ppc.dasc

@@ -2127,7 +2127,7 @@ static void build_subroutines(BuildCtx *ctx)
   |.else
   |    lfd FARG2, 8(BASE)
   |.endif
-  |  blt ->fff_fallback
+  |  bne ->fff_fallback			// Exactly 2 arguments.
   |  checkstr TMP0; bne ->fff_fallback
   |.if DUALNUM
   |  checknum CARG4; bne ->fff_fallback

+ 1 - 1
src/vm_ppcspe.dasc

@@ -1630,7 +1630,7 @@ static void build_subroutines(BuildCtx *ctx)
   |  cmplwi NARGS8:RC, 16
   |   evldd CARG1, 0(BASE)
   |   evldd CARG2, 8(BASE)
-  |  blt ->fff_fallback
+  |  bne ->fff_fallback			// Exactly 2 arguments.
   |  checknum CARG2
   |  checkfail ->fff_fallback
   |  checkstr STR:CARG1

+ 2 - 1
src/vm_x86.dasc

@@ -2437,8 +2437,9 @@ static void build_subroutines(BuildCtx *ctx)
   |  xor RC, RC				// Zero length. Any ptr in RB is ok.
   |  jmp <4
   |
-  |.ffunc_2 string_rep			// Only handle the 1-char case inline.
+  |.ffunc string_rep			// Only handle the 1-char case inline.
   |  ffgccheck
+  |  cmp NARGS:RD, 2+1; jne ->fff_fallback	// Exactly 2 arguments.
   |  cmp dword [BASE+4], LJ_TSTR;  jne ->fff_fallback
   |  cmp dword [BASE+12], LJ_TISNUM
   |  mov STR:RB, [BASE]