RFR (S) 8136500: Integer/Long getChars and stringSize should be more idiomatic

Peter Levart peter.levart at gmail.com
Tue Nov 24 17:11:45 UTC 2015



On 11/24/2015 05:50 PM, Ulf wrote:
> Hi,
>
> Am 24.11.2015 um 12:07 schrieb Aleksey Shipilev:
>> Thanks for reviews, Ivan, John, Sherman and Paul!
>>
>> I am pushing this change now.
>
> I know, I'm late, but have you ever tried? :
>
>     static void getChars(int i, int index, byte[] buf) {
>         // int q, r;        // superfluous
>         // int charPos = index;     // superfluous
>         boolean negative = i < 0;
>
>         // Generate two digits per iteration      // q and r are not 
> needed outside loop
>         for (int q, i = negative ? i : -i; <= -100; i = q) {
>             q = i / 100;
>             byte r = (byte)((q * 100 - i) & 0x7F);
>             // byte allows the compiler to use byte wide addressing 
> opcodes
>             // which have smaller footprint and are potentially faster
>             // .. & 0x7F may additionally save negative bound check
>             buf[(byte)(--index & 0x7F)] = DigitOnes[r];
>             buf[(byte)(--index & 0x7F)] = DigitTens[r];

...but index can be large and overflow byte range. Imagine concatenating 
into a String with target length > 127 ...

> }
>
>         // We know there are at most two digits left at this point.
>         byte q = (byte)i / 10;
>         buf[(byte)(--index & 0x7F)] = (byte)(q * 10 - i +'0');
>
>         // Whatever left is the remaining digit.
>         if (q < 0) {
>             buf[(byte)(--index & 0x7F)] = (byte)('0' - q);
>         }
>         if (negative) {
>             buf[(byte)(--index & 0x7F)] = (byte)'-';
>         }
>     }
>
> Additionally may try this:
> (saves some calculations, but adds array access, only 1 for more 
> frequent i < 10, otherwise 2)
>         // We know there are at most two digits left at this point.
>         byte r = (byte)(-i & 0x7F);
>         buf[(byte)(--index & 0x7F)] = DigitOnes[r];
>
>         // Whatever left is the remaining digit.
>         if (r >= 10) {
>             buf[(byte)(--index & 0x7F)] = DigitTens[r];
>         }
>         if (negative) {
>             buf[(byte)(--index & 0x7F)] = (byte)'-';
>         }
>
>
>> 2)
>> The lookup tables DigitTens and DigitOnes are always used together.
>> Packing them in an one table can save us one array access for the 
>> price of little arithmetic.
>>
>>     static final int[] TwoDigits = {
>>         ('0'<<16)+'0', ('0'<<16)+'1', ('0'<<16)+'2', ('0'<<16)+'3', 
>> ('0'<<16)+'4',
>>         ('0'<<16)+'5', ('0'<<16)+'6', ('0'<<16)+'7', ('0'<<16)+'8', 
>> ('0'<<16)+'9',
>>
>> ...
>>             int twoDig = TwoDigits[r];
>>             buf[--charPos] = (byte)twoDig;
>>             buf[--charPos] = (byte)(twoDig >> 16);
>> ...
>
> This could be done faster if using 1 "Unsafe putChar/Short()" instead 
> 2 buf[--charPos] + shift.
> ... and better use char/short[] to save footprint and the compiler 
> calculating the table offset with charPos<<1.
>
> Alternatively use byte[] TwoDigits = 
> useInternalCompactByteArrayOfString("00010203040506070809....")
>
> -Ulf
>




More information about the core-libs-dev mailing list