Skip to content

Commit 85ae4f7

Browse files
Address review feedback: extract helper function and simplify tests
1 parent 81c1bde commit 85ae4f7

2 files changed

Lines changed: 28 additions & 38 deletions

File tree

cpp/src/gandiva/precompiled/string_ops.cc

Lines changed: 24 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1966,6 +1966,22 @@ gdv_int32 evaluate_return_char_length(gdv_int32 text_len, gdv_int32 actual_text_
19661966
return return_char_length;
19671967
}
19681968

1969+
// Fill a buffer with repeated fill_text using O(log n) doubling strategy
1970+
FORCE_INLINE
1971+
void fill_buffer_with_pattern(gdv_binary dest, gdv_int32 total_fill_bytes,
1972+
const char* fill_text, gdv_int32 fill_text_len) {
1973+
gdv_int32 initial_copy = std::min(fill_text_len, total_fill_bytes);
1974+
memcpy(dest, fill_text, initial_copy);
1975+
gdv_int32 written = initial_copy;
1976+
while (written * 2 <= total_fill_bytes) {
1977+
memcpy(dest + written, dest, written);
1978+
written *= 2;
1979+
}
1980+
if (written < total_fill_bytes) {
1981+
memcpy(dest + written, dest, total_fill_bytes - written);
1982+
}
1983+
}
1984+
19691985
FORCE_INLINE
19701986
const char* lpad_utf8_int32_utf8(gdv_int64 context, const char* text, gdv_int32 text_len,
19711987
gdv_int32 return_length, const char* fill_text,
@@ -2000,7 +2016,7 @@ const char* lpad_utf8_int32_utf8(gdv_int64 context, const char* text, gdv_int32
20002016
// FAST PATH: Single-byte fill (most common - space padding)
20012017
if (fill_text_len == 1) {
20022018
gdv_int32 out_len_bytes = chars_to_pad + text_len;
2003-
char* ret =
2019+
gdv_binary ret =
20042020
reinterpret_cast<gdv_binary>(gdv_fn_context_arena_malloc(context, out_len_bytes));
20052021
if (ret == nullptr) {
20062022
gdv_fn_context_set_error_msg(context,
@@ -2017,28 +2033,17 @@ const char* lpad_utf8_int32_utf8(gdv_int64 context, const char* text, gdv_int32
20172033
// GENERAL PATH: Multi-byte fill - use evaluate_return_char_length for buffer size
20182034
gdv_int32 return_char_length = evaluate_return_char_length(
20192035
text_len, actual_text_len, return_length, fill_text, fill_text_len);
2020-
char* ret = reinterpret_cast<gdv_binary>(
2036+
gdv_binary ret = reinterpret_cast<gdv_binary>(
20212037
gdv_fn_context_arena_malloc(context, return_char_length));
20222038
if (ret == nullptr) {
20232039
gdv_fn_context_set_error_msg(context, "Could not allocate memory for output string");
20242040
*out_len = 0;
20252041
return "";
20262042
}
20272043

2028-
// Fill using doubling strategy (O(log n) memcpy calls)
2044+
// Fill padding region using doubling strategy, then append text
20292045
gdv_int32 total_fill_bytes = return_char_length - text_len;
2030-
// Copy only as much of fill_text as we need (may be less than fill_text_len)
2031-
gdv_int32 initial_copy = std::min(fill_text_len, total_fill_bytes);
2032-
memcpy(ret, fill_text, initial_copy);
2033-
gdv_int32 written = initial_copy;
2034-
while (written * 2 <= total_fill_bytes) {
2035-
memcpy(ret + written, ret, written);
2036-
written *= 2;
2037-
}
2038-
if (written < total_fill_bytes) {
2039-
memcpy(ret + written, ret, total_fill_bytes - written);
2040-
}
2041-
2046+
fill_buffer_with_pattern(ret, total_fill_bytes, fill_text, fill_text_len);
20422047
memcpy(ret + total_fill_bytes, text, text_len);
20432048
*out_len = return_char_length;
20442049
return ret;
@@ -2078,7 +2083,7 @@ const char* rpad_utf8_int32_utf8(gdv_int64 context, const char* text, gdv_int32
20782083
// FAST PATH: Single-byte fill (most common - space padding)
20792084
if (fill_text_len == 1) {
20802085
gdv_int32 out_len_bytes = chars_to_pad + text_len;
2081-
char* ret =
2086+
gdv_binary ret =
20822087
reinterpret_cast<gdv_binary>(gdv_fn_context_arena_malloc(context, out_len_bytes));
20832088
if (ret == nullptr) {
20842089
gdv_fn_context_set_error_msg(context,
@@ -2095,29 +2100,18 @@ const char* rpad_utf8_int32_utf8(gdv_int64 context, const char* text, gdv_int32
20952100
// GENERAL PATH: Multi-byte fill - use evaluate_return_char_length for buffer size
20962101
gdv_int32 return_char_length = evaluate_return_char_length(
20972102
text_len, actual_text_len, return_length, fill_text, fill_text_len);
2098-
char* ret = reinterpret_cast<gdv_binary>(
2103+
gdv_binary ret = reinterpret_cast<gdv_binary>(
20992104
gdv_fn_context_arena_malloc(context, return_char_length));
21002105
if (ret == nullptr) {
21012106
gdv_fn_context_set_error_msg(context, "Could not allocate memory for output string");
21022107
*out_len = 0;
21032108
return "";
21042109
}
21052110

2106-
// Copy text first, then fill using doubling strategy
2111+
// Copy text first, then fill padding region using doubling strategy
21072112
memcpy(ret, text, text_len);
21082113
gdv_int32 total_fill_bytes = return_char_length - text_len;
2109-
// Copy only as much of fill_text as we need (may be less than fill_text_len)
2110-
gdv_int32 initial_copy = std::min(fill_text_len, total_fill_bytes);
2111-
memcpy(ret + text_len, fill_text, initial_copy);
2112-
gdv_int32 written = initial_copy;
2113-
while (written * 2 <= total_fill_bytes) {
2114-
memcpy(ret + text_len + written, ret + text_len, written);
2115-
written *= 2;
2116-
}
2117-
if (written < total_fill_bytes) {
2118-
memcpy(ret + text_len + written, ret + text_len, total_fill_bytes - written);
2119-
}
2120-
2114+
fill_buffer_with_pattern(ret + text_len, total_fill_bytes, fill_text, fill_text_len);
21212115
*out_len = return_char_length;
21222116
return ret;
21232117
}

cpp/src/gandiva/precompiled/string_ops_test.cc

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1323,15 +1323,13 @@ TEST(TestStringOps, TestLpadString) {
13231323
EXPECT_EQ(out_len, 65535 * 4 + 1);
13241324
EXPECT_FALSE(ctx.has_error());
13251325
EXPECT_EQ(out_str[out_len - 1], 'x');
1326-
EXPECT_EQ(static_cast<unsigned char>(out_str[0]), 0xF0);
1327-
EXPECT_EQ(static_cast<unsigned char>(out_str[1]), 0x9F);
1328-
EXPECT_EQ(static_cast<unsigned char>(out_str[2]), 0x98);
1329-
EXPECT_EQ(static_cast<unsigned char>(out_str[3]), 0x80);
1326+
EXPECT_EQ(std::string_view(out_str, 4), "😀");
13301327

13311328
out_str = lpad_utf8_int32_utf8(ctx_ptr, "A", 1, 65536, "", 3, &out_len);
13321329
EXPECT_EQ(out_len, 65535 * 3 + 1);
13331330
EXPECT_FALSE(ctx.has_error());
13341331
EXPECT_EQ(out_str[out_len - 1], 'A');
1332+
EXPECT_EQ(std::string_view(out_str, 3), "");
13351333

13361334
out_str = lpad_utf8_int32_utf8(ctx_ptr, "X", 1, 2, ".", 1, &out_len);
13371335
EXPECT_EQ(std::string(out_str, out_len), ".X");
@@ -1496,15 +1494,13 @@ TEST(TestStringOps, TestRpadString) {
14961494
EXPECT_EQ(out_len, 1 + 65535 * 4);
14971495
EXPECT_FALSE(ctx.has_error());
14981496
EXPECT_EQ(out_str[0], 'x');
1499-
EXPECT_EQ(static_cast<unsigned char>(out_str[out_len - 4]), 0xF0);
1500-
EXPECT_EQ(static_cast<unsigned char>(out_str[out_len - 3]), 0x9F);
1501-
EXPECT_EQ(static_cast<unsigned char>(out_str[out_len - 2]), 0x98);
1502-
EXPECT_EQ(static_cast<unsigned char>(out_str[out_len - 1]), 0x80);
1497+
EXPECT_EQ(std::string_view(out_str + out_len - 4, 4), "😀");
15031498

15041499
out_str = rpad_utf8_int32_utf8(ctx_ptr, "A", 1, 65536, "", 3, &out_len);
15051500
EXPECT_EQ(out_len, 1 + 65535 * 3);
15061501
EXPECT_FALSE(ctx.has_error());
15071502
EXPECT_EQ(out_str[0], 'A');
1503+
EXPECT_EQ(std::string_view(out_str + out_len - 3, 3), "");
15081504

15091505
out_str = rpad_utf8_int32_utf8(ctx_ptr, "X", 1, 2, ".", 1, &out_len);
15101506
EXPECT_EQ(std::string(out_str, out_len), "X.");

0 commit comments

Comments
 (0)