From 81b48107a7904ff5c2752401ed55f7a7085cc663 Mon Sep 17 00:00:00 2001 From: advik Date: Thu, 28 Mar 2024 20:32:51 +0530 Subject: [PATCH 1/5] Faster string repeat algorithm --- src/libasr/runtime/lfortran_intrinsics.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/libasr/runtime/lfortran_intrinsics.c b/src/libasr/runtime/lfortran_intrinsics.c index 1381e97022..87533789cc 100644 --- a/src/libasr/runtime/lfortran_intrinsics.c +++ b/src/libasr/runtime/lfortran_intrinsics.c @@ -2129,7 +2129,6 @@ LFORTRAN_API int32_t _lpython_bit_length8(int64_t num) //repeat str for n time LFORTRAN_API void _lfortran_strrepeat(char** s, int32_t n, char** dest) { - int cntr = 0; char trmn = '\0'; int s_len = strlen(*s); int trmn_size = sizeof(trmn); @@ -2137,13 +2136,22 @@ LFORTRAN_API void _lfortran_strrepeat(char** s, int32_t n, char** dest) if (f_len < 0) f_len = 0; char* dest_char = (char*)malloc(f_len+trmn_size); - for (int i = 0; i < n; i++) { - for (int j = 0; j < s_len; j++) { - dest_char[cntr] = (*s)[j]; - cntr++; + + if (s_len == 1) { + memset(dest_char, *(*s), n); + } else { + memcpy(dest_char, *s, s_len); + int chars_copied = s_len; + int copy_length; + while (chars_copied < f_len) { + copy_length = (chars_copied <= f_len-chars_copied) + ? chars_copied : f_len-chars_copied; + memcpy(dest_char+chars_copied, dest_char, copy_length); + chars_copied += copy_length; } } - dest_char[cntr] = trmn; + + dest_char[f_len] = trmn; *dest = &(dest_char[0]); } From d76d2eaffa267d68b9bbccab5d555708f9b75179 Mon Sep 17 00:00:00 2001 From: advik Date: Thu, 28 Mar 2024 22:38:54 +0530 Subject: [PATCH 2/5] Optimize `_lfortran_strcpy` --- src/libasr/runtime/lfortran_intrinsics.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/libasr/runtime/lfortran_intrinsics.c b/src/libasr/runtime/lfortran_intrinsics.c index 87533789cc..49536e77a6 100644 --- a/src/libasr/runtime/lfortran_intrinsics.c +++ b/src/libasr/runtime/lfortran_intrinsics.c @@ -1976,12 +1976,14 @@ LFORTRAN_API void _lfortran_strcpy(char** x, char *y, int8_t free_target) *x = (char*) malloc((strlen(y) + 1) * sizeof(char)); _lfortran_string_init(strlen(y) + 1, *x); // } - for (size_t i = 0; i < strlen(*x); i++) { - if (i < strlen(y)) { - x[0][i] = y[i]; - } else { - x[0][i] = ' '; - } + size_t y_len = strlen(y); + size_t x_len = strlen(*x); + size_t i = 0; + for (; i < x_len && i < y_len; i++) { + x[0][i] = y[i]; + } + for (; i < x_len; i++) { + x[0][i] = ' '; } } From 7d2080c0bac4d30f88bb9f374e4b2e73f12e7545 Mon Sep 17 00:00:00 2001 From: advik Date: Thu, 28 Mar 2024 20:32:51 +0530 Subject: [PATCH 3/5] Faster string repeat algorithm --- src/libasr/runtime/lfortran_intrinsics.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/libasr/runtime/lfortran_intrinsics.c b/src/libasr/runtime/lfortran_intrinsics.c index 36bbbcb683..b3207fa207 100644 --- a/src/libasr/runtime/lfortran_intrinsics.c +++ b/src/libasr/runtime/lfortran_intrinsics.c @@ -2129,7 +2129,6 @@ LFORTRAN_API int32_t _lpython_bit_length8(int64_t num) //repeat str for n time LFORTRAN_API void _lfortran_strrepeat(char** s, int32_t n, char** dest) { - int cntr = 0; char trmn = '\0'; int s_len = strlen(*s); int trmn_size = sizeof(trmn); @@ -2137,13 +2136,22 @@ LFORTRAN_API void _lfortran_strrepeat(char** s, int32_t n, char** dest) if (f_len < 0) f_len = 0; char* dest_char = (char*)malloc(f_len+trmn_size); - for (int i = 0; i < n; i++) { - for (int j = 0; j < s_len; j++) { - dest_char[cntr] = (*s)[j]; - cntr++; + + if (s_len == 1) { + memset(dest_char, *(*s), n); + } else { + memcpy(dest_char, *s, s_len); + int chars_copied = s_len; + int copy_length; + while (chars_copied < f_len) { + copy_length = (chars_copied <= f_len-chars_copied) + ? chars_copied : f_len-chars_copied; + memcpy(dest_char+chars_copied, dest_char, copy_length); + chars_copied += copy_length; } } - dest_char[cntr] = trmn; + + dest_char[f_len] = trmn; *dest = &(dest_char[0]); } From d6645f5ae1abb264914dffaafb2b0c5596b7d533 Mon Sep 17 00:00:00 2001 From: advik Date: Thu, 28 Mar 2024 22:38:54 +0530 Subject: [PATCH 4/5] Optimize `_lfortran_strcpy` --- src/libasr/runtime/lfortran_intrinsics.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/libasr/runtime/lfortran_intrinsics.c b/src/libasr/runtime/lfortran_intrinsics.c index b3207fa207..ce6c6901a4 100644 --- a/src/libasr/runtime/lfortran_intrinsics.c +++ b/src/libasr/runtime/lfortran_intrinsics.c @@ -1976,12 +1976,14 @@ LFORTRAN_API void _lfortran_strcpy(char** x, char *y, int8_t free_target) *x = (char*) malloc((strlen(y) + 1) * sizeof(char)); _lfortran_string_init(strlen(y) + 1, *x); // } - for (size_t i = 0; i < strlen(*x); i++) { - if (i < strlen(y)) { - x[0][i] = y[i]; - } else { - x[0][i] = ' '; - } + size_t y_len = strlen(y); + size_t x_len = strlen(*x); + size_t i = 0; + for (; i < x_len && i < y_len; i++) { + x[0][i] = y[i]; + } + for (; i < x_len; i++) { + x[0][i] = ' '; } } From 130ca484203ff7878c92958be398d8f24e8bc952 Mon Sep 17 00:00:00 2001 From: advik Date: Thu, 4 Apr 2024 01:01:09 +0530 Subject: [PATCH 5/5] Added stress test for repeat --- integration_tests/test_str_01.py | 1 + 1 file changed, 1 insertion(+) diff --git a/integration_tests/test_str_01.py b/integration_tests/test_str_01.py index 5b5307fbb5..a889a85d83 100644 --- a/integration_tests/test_str_01.py +++ b/integration_tests/test_str_01.py @@ -59,6 +59,7 @@ def test_str_repeat(): assert a*2*3 == "XyzXyzXyzXyzXyzXyz" assert 3*a*3 == "XyzXyzXyzXyzXyzXyzXyzXyzXyz" assert a*-1 == "" + assert len(a*(10**6)) == (3 * 10 ** 6) def test_str_join(): a: str