david-mollitor-db opened a new pull request, #58675:
URL: https://github.com/apache/spark/pull/58675

   ### What changes were proposed in this pull request?
   
   The trim overloads that take a set of trim characters — 
`trimLeft(UTF8String)` and `trimRight(UTF8String)`, with `trim(UTF8String)` 
delegating to both — allocate a throwaway `UTF8String` for every source 
character they examine. Each iteration calls `copyUTF8String(...)` (a `new 
byte[]` + `copyMemory` + `fromBytes`) only to pass that one character to 
`trimString.find(searchChar, 0)`. Trimming *k* leading/trailing characters does 
O(k) heap allocations.
   
   The character under test is already a byte range in this string's backing 
memory, so the membership check can read it directly. This factors `find` into 
a raw-bytes overload; the public method delegates to it (byte-for-byte the same 
scan):
   
   ```java
   public int find(UTF8String str, int start) {
     return find(str.base, str.offset, str.numBytes, start);
   }
   
   private int find(Object strBase, long strOffset, int strNumBytes, int start) 
{
     assert (strNumBytes > 0);
     while (start <= numBytes - strNumBytes) {
       if (ByteArrayMethods.arrayEquals(base, offset + start, strBase, 
strOffset, strNumBytes)) {
         return start;
       }
       start += 1;
     }
     return -1;
   }
   ```
   
   `trimLeft`/`trimRight` then compute the (clamped) code-point length and 
search the source bytes in place instead of building a `UTF8String`:
   
   ```java
   // trimLeft inner loop
   byte leadByte = this.getByte(searchIdx);
   int searchCharBytes = Math.min(numBytesForFirstByte(leadByte), numBytes - 
searchIdx);
   if (trimString.find(this.base, this.offset + searchIdx, searchCharBytes, 0) 
>= 0) {
     trimIdx += searchCharBytes;
   } else {
     break;
   }
   searchIdx += searchCharBytes;
   ```
   
   The `Math.min(width, remaining)` clamp reproduces `copyUTF8String`'s 
handling of a truncated trailing multi-byte leader exactly. `trimRight` gets 
the same substitution inside its existing right-to-left loop.
   
   The two `int[numBytes]` arrays `trimRight` builds up front are deliberately 
left in place — removing them would require a right-to-left walk that changes 
how truncated trailing multi-byte sequences are handled, a separate and riskier 
change.
   
   ### Why are the changes needed?
   
   For a leading/trailing run of *k* trim characters, the old code allocates 
*k* throwaway `UTF8String` objects (each a `byte[]` + wrapper) purely to run a 
membership check. Reading the source character's bytes in place turns O(k) 
allocations into O(1), reducing GC pressure on trim-heavy workloads at no cost 
to non-matching inputs.
   
   ### Does this PR introduce _any_ user-facing change?
   
   No. The needle bytes/length are identical to what `copyUTF8String` produced 
(same clamp) and `find` runs the same `arrayEquals` subsequence scan, so 
results are byte-for-byte identical, including empty `trimString` (nothing 
trimmed) and truncated trailing leaders. The set-membership semantics are 
unchanged.
   
   ### How was this patch tested?
   
   Existing `UTF8StringSuite` passes (51/51), including 
`trimBothWithTrimString`, `trimLeftWithTrimString`, and 
`trimRightWithTrimString` — which cover empty/single/multi-char trim sets, 
multi-byte characters, all- and nothing-trimmed, and mixed ASCII+multibyte. 
This is a behavior-preserving refactor, so no new tests were added.
   
   ### Was this patch authored or co-authored using generative AI tooling?
   
   Yes. Generated-by: Claude Code
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to