All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.javanut.pronghorn.util.Appendables Maven / Gradle / Ivy

Go to download

Ring buffer based queuing utility for applications that require high performance and/or a small footprint. Well suited for embedded and stream based processing.

There is a newer version: 1.1.27
Show newest version
package com.javanut.pronghorn.util;

import java.io.IOException;
import java.util.Arrays;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.javanut.pronghorn.pipe.ChannelWriter;
import com.javanut.pronghorn.pipe.DataOutputBlobWriter;
import com.javanut.pronghorn.pipe.Pipe;

/**
 * 
 * Garbage free single pass utilities for building up text.
 * The API follows a fluent pattern where every method returns the same Appendable which was passed in.
 * 
 * TODO: as soon we we start building this code for Java 8 we muse use new UncheckedIOException(cause) instead of new RuntimeException();
 * 
 * @author Nathan Tippy
 *
 */
public class Appendables {
    
	private final static Logger logger = LoggerFactory.getLogger(Appendables.class);
	
    private final static char[] hBase = new char[] {'0','1','2','3','4','5','6','7','8','9',
    												'a','b','c','d','e','f'};
    
    
    private final static char[] base64 = new char[]{'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
    		                                        'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
    		                                        'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
    		                                        'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/'};
    
    private final static byte[] base64Inverse;
    
    static {
    	//populate inverse for base64 decode
    	base64Inverse = new byte[256];    	
    	Arrays.fill(base64Inverse, (byte)-1);
    	int i = base64.length;
    	while (--i>=0) {
    		base64Inverse[(int)	base64[i] ] = (byte)i;
    	}
    }

    
    
    public static  A appendArray(A target, char left, long[] a, char right) {
    	try {
	        if (a != null) {        
	            int iMax = a.length - 1;
	            if (iMax == -1) {
	                target.append(left).append(right);
	                return target;
	            }
	            target.append(left);
	            for (int i = 0; ; i++) {
	                appendValue(target,a[i]);
	                //target.append(Long.toString(a[i]));
	                if (i == iMax) {
	                    return (A) target.append(right);
	                }
	                target.append(", ");
	            } 
	        } else {
	            target.append("null");
	        
	        }
	        return target;
		} catch (IOException ex) {
			throw new RuntimeException(ex); 
		}
    }

    
    public static  A appendArray(A target, byte[] b) {
   		return appendArray(target, '[', b, ']', b.length);
    }
    
    public static  A appendArray(A target, char left, byte[] b, char right) {
   		return appendArray(target, left, b, right, b.length);
    }
        
    public static  A appendArray(A target, char left, byte[] b, char right, int bLength) {
		try {
		    	if (b != null) {        
		            int iMax = bLength - 1;
		            if (iMax == -1) {
		                target.append(left).append(right);
		                return target;
		            }
		            target.append(left);
		            for (int i = 0; ; i++) {
		                appendValue(target,b[i]);
		                //target.append(Integer.toString(a[i]));
		                if (i == iMax)
		                    return (A) target.append(right);
		                target.append(", ");
		            } 
		        } else {
		            target.append("null");        
		        }
		        return target;
		} catch (IOException ex) {
			throw new RuntimeException(ex); 
		}
    }
    
    public static  A appendArray(A target, byte[] b, int offset, int mask, int bLength) {
    	return appendArray(target,'[',b,offset,mask,']',bLength);
    }
    
    public static  A appendArray(A target, char left, byte[] b, int offset, int mask, char right, int bLength) {
	      try {
	    	if (b != null) {        
	            int iMax = bLength - 1;
	            if (iMax == -1) {
	                target.append(left).append(right);
	                return target;
	            }
	            target.append(left);
	            for (int i = 0; ; i++) {
	                appendValue(target,b[mask & (i+offset) ]);
	                //target.append(Integer.toString(a[i]));
	                if (i == iMax)
	                    return (A) target.append(right);
	                target.append(", ");
	            } 
	        } else {
	            target.append("null");
	        
	        }
	        return target;
	    } catch (IOException ex) {
			throw new RuntimeException(ex); 
		}
    }
    
    public static  A appendHexArray(A target, char left, byte[] b, int offset, int mask, char right, int bLength) {
	      try {
	    	if (b != null) {        
	            int iMax = bLength - 1;
	            if (iMax == -1) {
	                target.append(left).append(right);
	                return target;
	            }
	            target.append(left);
	            for (int i = 0; ; i++) {
	            	
	            	appendFixedHexDigits(target, 0xFF&b[mask & (i+offset) ], 8);
	                //appendValue(target,b[mask & (i+offset) ]);
	                //target.append(Integer.toString(a[i]));
	                if (i == iMax)
	                    return (A) target.append(right);
	                target.append(", ");
	            } 
	        } else {
	            target.append("null");
	        
	        }
	        return target;
	    } catch (IOException ex) {
			throw new RuntimeException(ex); 
		}
    }
    
    

    public static  A appendArray(A target, char left, int[] b, long offset, int mask, char right, int bLength) {
	      try {
	    	if (b != null) {        
	            int iMax = bLength - 1;
	            if (iMax == -1) {
	                target.append(left).append(right);
	                return target;
	            }
	            target.append(left);
	            for (int i = 0; ; i++) {
	                appendValue(target,b[mask & (int)(i+offset) ]);
	                //target.append(Integer.toString(a[i]));
	                if (i == iMax)
	                    return (A) target.append(right);
	                target.append(", ");
	            } 
	        } else {
	            target.append("null");
	        
	        }
	        return target;
	    } catch (IOException ex) {
			throw new RuntimeException(ex); 
		}
   }
   
    public static  A appendHexArray(A target, char left, int[] b, long offset, int mask, char right, int bLength) {
	      try {
	    	if (b != null) {        
	            int iMax = bLength - 1;
	            if (iMax == -1) {
	                target.append(left).append(right);
	                return target;
	            }
	            target.append(left);
	            for (int i = 0; ; i++) {
	            	appendFixedHexDigits(target, 0xFFFFFFFF&b[mask & (int)(i+offset) ], 32);

	                if (i == iMax)
	                    return (A) target.append(right);
	                target.append(", ");
	            } 
	        } else {
	            target.append("null");
	        
	        }
	        return target;
	    } catch (IOException ex) {
			throw new RuntimeException(ex); 
		}
 }
    
    public static  A appendArray(A target, char left, int[] a, char right) {
	     try {
	    	if (a != null) {        
	            int iMax = a.length - 1;
	            if (iMax == -1) {
	                target.append(left).append(right);
	                return target;
	            }
	            target.append(left);
	            for (int i = 0; ; i++) {
	                appendValue(target,a[i]);
	                //target.append(Integer.toString(a[i]));
	                if (i == iMax)
	                    return (A) target.append(right);
	                target.append(", ");
	            } 
	        } else {
	            target.append("null");
	        
	        }
	        return target;
	    } catch (IOException ex) {
			throw new RuntimeException(ex); 
		}
    }
    
    public static  A appendArray(A target, char left, Object[] a, char right) {
	     try{
	    	if (a != null) {        
	            int iMax = a.length - 1;
	            if (iMax == -1) {
	                target.append(left).append(right);
	                return target;
	            }
	            target.append(left);
	            for (int i = 0; ; i++) {
	                target.append((a[i]).toString());
	                if (i == iMax)
	                    return (A) target.append(right);
	                target.append(", ");
	            } 
	        } else {
	            target.append("null");
	        
	        }
	        return target;
	    } catch (IOException ex) {
			throw new RuntimeException(ex); 
		}
    }
    
    public static  A appendValue(A target, CharSequence label, int value, CharSequence suffix) {
    	try {
	        appendValue(target,label, value);
	        target.append(suffix);
	        return target;
    	} catch (IOException ex) {
			throw new RuntimeException(ex); 
		}
    }
    
    
    public static  A appendValue(A target, CharSequence label, int value) {
    	try {
	        target.append(label);
	        return appendValue(target,value);
    	} catch (IOException ex) {
			throw new RuntimeException(ex); 
		}
    }

    static final int digits = 18;    		
    static final long tens = 1_000_000_000_000_000_000L;
    
    
    static final int digits_small = 6;   
    static final long tens_small = 1_000_000L;
    static final long tens_small_limit = tens_small*10;

    public static  A appendDecimalValue(A target, long m, byte e) {
    	
    	
    	long value = m;    	
    	int g = -e;
    	boolean useParensForNeg = false;
    	
    	try {    		
	        
	        boolean isNegative = value<0;
	        if (isNegative) {
	        	if (useParensForNeg) {
	        		target.append("(-");
	        	} else {
	        		target.append("-");
	        	}
	        	
	            value = -value;
	        }
	        
	        long nextValue = value;
	        int orAll = 0; //this is to remove the leading zeros
	        
	        long temp = Math.abs(value);
		    if (temp int appendZeros(A target, int f) throws IOException {
		while (f>0) {
			target.append('0');
			f--;
		}
		return f;
	}

	
	private static char[]dv = new char[] {'0','1','2','3','4','5','6','7','8','9'};
	
	
	private static  void decimalValueCollecting(A target, int digits, long tens, int g,
																		long nextValue, int orAll) throws IOException {
		
		boolean isFirst = true;
		while (tens>1) {
			
		    int digit = (int)(nextValue/tens);
		    nextValue = nextValue%tens;
		    orAll |= digit;
		    if (0!=orAll || digits void decimalValueCollecting(ChannelWriter writer, int digits, long tens, int g,
			long nextValue, int orAll) throws IOException {

		boolean isFirst = true;
		while (tens > 1) {

			int digit = (int) (nextValue / tens);
			nextValue = nextValue % tens;
			orAll |= digit;
			if (0 != orAll || digits < g) {
				writer.writeByte(dv[digit]);// (char)('0'+digit));
				isFirst = false;
			}

			if (digits == g) {
				if (isFirst) {
					writer.writeByte('0');// leading zero
				}
				writer.writeByte('.');
				isFirst = false;
			}

			tens /= 10;
			digits--;

		}
		writer.writeByte(dv[(int) nextValue]);// (char)('0'+nextValue));
	}
    
    public static  A appendValue(A target, int value) {    	
    	return appendValue(target, value, true);
    }

	public static  A appendValue(final A target, int value, final boolean useNegPara) {
				
		//////////////////////////////
		//can be optimized due to knowing the target type
		//////////////////////////////
		if (target instanceof AppendableByteWriter) {
			AppendableByteWriter dataOutputBlobWriter = (AppendableByteWriter)target;
			if (value>=0 ) {	    
				if (value<10) {
					dataOutputBlobWriter.writeByte(('0'+(int)value));
					return target;
				} else if (value<100) {
					dataOutputBlobWriter.writeByte(('0'+((int)value/10)));
					dataOutputBlobWriter.writeByte(('0'+((int)value%10)));
					return target;
				} else if (value<1000) {
					dataOutputBlobWriter.writeByte(('0'+((int)value/100)));
					dataOutputBlobWriter.writeByte(('0'+(((int)value%100)/10)));
					dataOutputBlobWriter.writeByte(('0'+((int)value%10)));
					return target;
				} else if (value<10000) {
					dataOutputBlobWriter.writeByte(('0'+((int)value/1000)));
					dataOutputBlobWriter.writeByte(('0'+(((int)value%1000)/100)));
					dataOutputBlobWriter.writeByte(('0'+(((int)value%100)/10)));
					dataOutputBlobWriter.writeByte(('0'+((int)value%10)));
					return target;
				}
			}
			if (dataOutputBlobWriter instanceof DataOutputBlobWriter) {			
				DataOutputBlobWriter.appendLongAsText((DataOutputBlobWriter)dataOutputBlobWriter, value, useNegPara);
			}  else {
				if (dataOutputBlobWriter instanceof AppendableBuilder) {
					AppendableBuilder.appendLongAsText((AppendableBuilder)dataOutputBlobWriter, value, useNegPara);
				} else {
					return slowAppendValue(target, value, useNegPara); //TODO: speed up as other methods.. 
				}
			}
	    	return target;
		} else {		
			return slowAppendValue(target, value, useNegPara);
		}
	}


	private static  A slowAppendValue(final A target, int value, final boolean useNegPara) {
		try {
		    int tens = 1000000000;
		    
		    boolean isNegative = value<0;
		    if (isNegative) {
		        //special case which can not be rendered here.
		        if (value==Integer.MIN_VALUE) {
		            return appendValue(target,(long)value);
		        }
		        if (useNegPara) {
		        	target.append('(');
		        }
		        target.append('-');
		        value = -value;
		    }
		    
		    int nextValue = value;
		    int orAll = 0; //this is to remove the leading zeros
		    while (tens>1) {
		        int digit = nextValue/tens;
		        orAll |= digit;
		        if (0!=orAll) {
		            target.append((char)('0'+digit));
		        }
		        nextValue = nextValue%tens;
		        tens /= 10;
		    }
		    target.append((char)('0'+nextValue));
		    if (isNegative && useNegPara) {
		        target.append(')');
		    }
		    return target;
		} catch (IOException ex) {
			throw new RuntimeException(ex); 
		}
	}
    
    public static  A appendHexDigits(A target, int value) {
     try{
    	return (A) appendHexDigitsRaw(target.append("0x"), value);
     } catch (IOException ex) {
		throw new RuntimeException(ex); 
     }
    }
    
    public static  A appendHexDigitsRaw(A target, int value) {
		try {
		        int bits = 32 - Integer.numberOfLeadingZeros(value);
		        
		        //round up to next group of 4
		        bits = ((bits+3)>>2)<<2;
		        
		        int nextValue = value;
		        int orAll = 0; //this is to remove the leading zeros
		        while (bits>4) {
		            bits -= 4;            
		            int digit = nextValue>>>bits;
		            orAll |= digit;
		            if (0!=orAll) {
		                target.append(hBase[digit]);            
		            }
		            nextValue =  ((1<>>bits]);
		        
		        return target;
		} catch (IOException ex) {
			throw new RuntimeException(ex); 
		}
    }
    
    public static  A appendValue(A target, CharSequence label, long value, CharSequence suffix) {
	    try {	
	        appendValue(target,label, value);
	        target.append(suffix);
	        return target;
	    } catch (IOException ex) {
			throw new RuntimeException(ex); 
		}
    }
    
    
    public static  A appendValue(A target, CharSequence label, long value) {
    	try {
    		target.append(label);
    		return appendValue(target,value);
    	} catch (IOException ex) {
			throw new RuntimeException(ex); 
		}
    }
    
    public static int appendedLength(long value) {
    	int result = value<0?3:0;
    	value = Math.abs(value);
    	
    	while (value > 0) {
    		result++;
    		value = value/10;
    	}
    	
    	return result;
    }
    
  
    
    
    public static  A appendValue(A target, long value) {
    	return customNegAppendValue(target, value, true);
    }

    public static  A appendValue(A target, long value, boolean useNegPara) {
    	return customNegAppendValue(target, value, useNegPara);
    }

    
	private static  A customNegAppendValue(A target, long value, boolean useNegPara) {
		
		if (target instanceof AppendableByteWriter){
			AppendableByteWriter dataOutputBlobWriter = (AppendableByteWriter)target;
			//////////////////////////////
			//can be optimized due to knowing the target type
			//////////////////////////////
	    	if (value>=0) {	    
	    		if (value<10) {
					dataOutputBlobWriter.writeByte(('0'+(int)value));
	    			return target;
	    		} else if (value<100) {
	    			dataOutputBlobWriter.writeByte(('0'+((int)value/10)));
	    			dataOutputBlobWriter.writeByte(('0'+((int)value%10)));
	    			return target;
	    		} else if (value<1000) {
	    			dataOutputBlobWriter.writeByte(('0'+((int)value/100)));
	    			dataOutputBlobWriter.writeByte(('0'+(((int)value%100)/10)));
	    			dataOutputBlobWriter.writeByte(('0'+((int)value%10)));
	    			return target;
	    		} else if (value<10000) {
	    			dataOutputBlobWriter.writeByte(('0'+((int)value/1000)));
	    			dataOutputBlobWriter.writeByte(('0'+(((int)value%1000)/100)));
	    			dataOutputBlobWriter.writeByte(('0'+(((int)value%100)/10)));
	    			dataOutputBlobWriter.writeByte(('0'+((int)value%10)));
	    			return target;
	    		}
	    		
	    	}
	    	if (dataOutputBlobWriter instanceof DataOutputBlobWriter) {			
				DataOutputBlobWriter.appendLongAsText((DataOutputBlobWriter)dataOutputBlobWriter, value, useNegPara);
			}  else {
				if (dataOutputBlobWriter instanceof AppendableBuilder) {
					AppendableBuilder.appendLongAsText((AppendableBuilder)dataOutputBlobWriter, value, useNegPara);
				} else {
					return slowAppendValue(target, value, useNegPara); //TODO: speed up as other methods.. 
				}
			}
	    	return target;
		} else {
	    	/////////////////////////////    	
	    	return slowAppendValue(target, value, useNegPara);
		}
	}

	private static  A slowAppendValue(A target, long value, boolean useNegPara) {
		try {
	        long tens = 1000000000000000000L;
	        
	        boolean isNegative = value<0;
	        if (isNegative) {
	        	if (useNegPara) {
	        		target.append('(');
	        	}
	            target.append('-');
	            value = -value;
	        }
	        
	        long nextValue = value;
	        int orAll = 0; //this is to remove the leading zeros
	        while (tens>1) {
	            int digit = (int)(nextValue/tens);
	            nextValue = nextValue%tens;
	            orAll |= digit;
	            if (0!=orAll) {
	            	target.append((char)('0'+digit));	            
	            }
	            tens /= 10;
	        }
	        target.append((char)('0'+nextValue));
	        if (isNegative && useNegPara) {
	            target.append(')');
	        }
	        return target;
    	} catch (IOException ex) {
			throw new RuntimeException(ex); 
		}
	}
    
    public static  A appendHexDigits(A target, long value) {
        try{
        	return (A) appendHexDigitsRaw(target.append("0x"), value);
        } catch (IOException ex) {
        	throw new RuntimeException(ex); 
        }
     }
    
    public static  A appendHexDigitsRaw(A target, long value) {
        try {
	        int bits = 64-Long.numberOfLeadingZeros(value);
	        
	        //round up to next group of 4
	        bits = ((bits+3)>>2)<<2;
	
	        long nextValue = value;
	        int orAll = 0; //this is to remove the leading zeros
	        while (bits>4) {
	            bits -= 4;            
	            int digit = (int)(0xF&(nextValue>>>bits));
	            orAll |= digit;
	            if (0!=orAll) {
	                target.append(hBase[digit]);            
	            }
	            nextValue =  ((1L<>>bits)]);
	        
	        return target;
    	} catch (IOException ex) {
    		throw new RuntimeException(ex); 
    	}
    }
    
    public static  A appendFixedHexDigits(A target, long value, int bits) {
    	
    	value = value & ((1L<>2)<<2;
	        
	        target.append("0x");
	        long nextValue = value;
	        while (bits>4) {            
	            bits -= 4;
	            target.append(hBase[(int)(0xF&(nextValue>>>bits))]);            
	            nextValue =  ((1L<>>bits))]);
	        
	        return target;
    	} catch (IOException ex) {
    		throw new RuntimeException(ex); 
    	}
    }
    
    /*
     * 
     * In order to render a number like 42 with exactly 2 places the tests argument must be set to 10, likewise 042 would require 100
     */
    public static  A appendFixedDecimalDigits(A target, int value, int tens) {

    	try {
	        if (value<0) {
	            target.append('-');
	            value = -value;
	        }
	        
	        int nextValue = value;
	        while (tens>1) {
	            target.append((char)('0'+(nextValue/tens)));
	            nextValue = nextValue%tens;
	            tens /= 10;
	        }
	        target.append((char)('0'+nextValue));
	        
	        return target;
    	} catch (IOException ex) {
    		
    		throw new RuntimeException(ex); 
    	}
    }
    
    public static  A appendFixedDecimalDigits(A target, long value, int tens) {

    	try {
	        if (value<0) {
	            target.append('-');
	            value = -value;
	        }
	        
	        long nextValue = value;
	        while (tens>1) {
	            target.append((char)('0'+(nextValue/tens)));
	            nextValue = nextValue%tens;
	            tens /= 10;
	        }
	        target.append((char)('0'+nextValue));
	        
	        return target;
    	} catch (IOException ex) {
    		
    		throw new RuntimeException(ex); 
    	}
    }
    
    /*
     * 
     * In order to render an 8 bit number the bits must be set to 8. note that bits can only be in units of 4.
     */
    public static  A appendFixedHexDigits(A target, int value, int bits) {

    	//value = value & ((1<>2)<<2;
	        
	        target.append("0x");
	        int nextValue = value;
	        while (bits>4) {            
	            bits -= 4;
	            target.append(hBase[nextValue>>>bits]);            
	            nextValue =  ((1<>>bits]);
	        
	        return target;
		} catch (IOException ex) {
			throw new RuntimeException(ex); 
		}
    }

    
    public static  A appendClass(A target, Class clazz, Class clazzParam) {
    	try {
    		return (A) target.append(clazz.getSimpleName()).append('<').append(clazzParam.getSimpleName()).append("> ");
    	} catch (IOException ex) {
			throw new RuntimeException(ex); 
		}
    }
    
    public static  A appendStaticCall(A target, Class clazz, String method) {
    	try {
    		return (A) target.append(clazz.getSimpleName()).append('.').append(method).append('(');
    	} catch (IOException ex) {
			throw new RuntimeException(ex); 
		}
    }
    
    public static StringBuilder truncate(StringBuilder builder) {
        builder.setLength(0);
        return builder;
    }

    //copy the sequence but skip every instance of the provided skip chars
    public static  A appendAndSkip(A target, CharSequence source, CharSequence skip) {
        return appendAndSkipImpl(target, source, skip, skip.length(), source.length(), 0, 0);    
    }

    private static  A appendAndSkipImpl(A target, CharSequence source, CharSequence skip, int skipLen, int sourceLen, int j, int i) {

	        for(; i A appendBase64Encoded(A target, byte[] backing, int pos, int len, int mask) {
        //  https://en.wikipedia.org/wiki/Base64
    	try {
	    	int accumulator = 0;
	    	int i = 0;
	    	int shift = -6;
	    	int count = 0;
	    	while (i < len) {
	    		
	    		shift+=8; // 2 4 (we now have 10)
	    		accumulator = (accumulator<<8) | (0xFF&backing[mask & pos++]);
	    		i++;
	    
				while (shift >= 0) {
					int index = 0x3F&(accumulator>>shift);
					
					if (index<62) {
						target.append(base64[index]);
					} else {
						if (index==62) {
							assert(base64[index]=='+');
							target.append("%2B");
						} else {
							assert(base64[index]=='/');
							target.append("%2F");
						}
					}
		
					shift -= 6; //took top 6 now shift is at -4, 
					count++;
				}   		
	    	}
	    	
	    	if (shift<0) {//last letter.
	    		
	    		shift+=8; 
	    		accumulator = (accumulator<<8) | (0xFF&0);
	    		i++;
	    		
	    		while (shift > 0) {    			
	    			int index = 0x3F&(accumulator>>shift);
					
					if (index<62) {
						target.append(base64[index]);
					} else {
						if (index==62) {
							assert(base64[index]=='+');
							target.append("%2B");
						} else {
							assert(base64[index]=='/');
							target.append("%2F");
						}
					}
	    			shift -= 6; //took top 6 now shift is at -4,
	    			count++;
	    		} 
	    		
	    	}
	    	//NOTE: could and should be optimized.
	        while ((count & 0x03) != 0) {
	        	target.append("%3D");
	        	count++;
	        }
	    
	    	return target;
    	} catch (IOException ioex) {
    		throw new RuntimeException(ioex);
    	}
    }
    
    ///ERROR, this method may add an extra A=== on the end... TODO: urgent need test and fix method.
    
    @Deprecated
    public static  A appendBase64(A target, byte[] backing, int pos, int len, int mask) {
        //  https://en.wikipedia.org/wiki/Base64
    	try {
    		
    		assert(Integer.lowestOneBit(mask+1) == mask+1) : "mask must be all ones but found "+Integer.toBinaryString(mask);
    		
	    	int accumulator = 0;
	    	int i = 0;
	    	int shift = -6;
	    	int count = 0;
	    	while (i < len) {
	    		
	    		shift+=8; // 2 4 (we now have 10)
	    		accumulator = (accumulator<<8) | (0xFF&backing[mask & pos++]);
	    		i++;
	    
				while (shift >= 0) {
					target.append(base64[0x3F&(accumulator>>shift)]);
					shift -= 6; //took top 6 now shift is at -4, 
					count++;
				}   		
	    	}
	    	
	    	if (shift<0) {//last letter.
	    		
	    		shift+=8; 
	    		accumulator = (accumulator<<8) | (0xFF&0);
	    		i++;
	    		
	    		while (shift > 0) {    			
	    			target.append(base64[0x3F&(accumulator>>shift)]);
	    			shift -= 6; //took top 6 now shift is at -4,
	    			count++;
	    		} 
	    		
	    	}
	    	//NOTE: could and should be optimized.
	        while ((count & 0x03) != 0) {
	        	target.append('=');
	        	count++;
	        }
	    
	    	return target;
    	} catch (IOException ioex) {
    		throw new RuntimeException(ioex);
    	}
    }
        

	public static int decodeBase64(byte[] source, int sourceIdx, int sourceLen, int sourceMask, 
								   byte[] target, int targetIdx, int targetMask) {

		int accumulator = 0;
		int bitsAvail = 0;
		int t = targetIdx;
		int i = sourceLen;
		while (--i >= 0) {

			byte b = base64Inverse[source[sourceMask & sourceIdx++]];
			if (b >= 0) {

				// roll in 6 bits at a time
				accumulator = (accumulator << 6) | (0x3F & b);
				bitsAvail += 6;

				while (bitsAvail > 8) {

					bitsAvail -= 8;
					target[targetMask & t++] = (byte) (accumulator >> bitsAvail);

				}
				// Note the xtra bits < 8 are not used on the very last cycle

			} else {
				if (i > 0) {
					logger.info("invlid value found in base64 encoding");
					return -1; // can not decode
				} else {
					// last block, nothing to do.
				}
			}
		}

		return t - targetIdx;

	}
    public static  A appendUTF8(A target, byte[] backing, int pos, int len, int mask) {
    	try {
    		assert(len>=0) : "length: "+len;
    		assert((mask == Integer.MAX_VALUE) || (len=0) : "length: "+len;
		assert((mask == Integer.MAX_VALUE) || (len=target.length() || target.charAt(tPos++) != ((char)charAndPos) ) {
            	return false;
            }
        }
        return true;
	
    }
    
	public static CharSequence[] split(CharSequence text, char c) {
		return split(0,0,0,text,c);
	}
	
	private static CharSequence[] split(int pos, int start, int depth, final CharSequence text, final char c) {
		CharSequence[] result;
		while (pos A  appendEpochTime(A target, long msTime) {
		 try {
			 appendFixedDecimalDigits(
			 appendFixedDecimalDigits(
			 appendFixedDecimalDigits(
					 appendValue(target, (msTime/(60L*60_000L))).append(':')
					  ,(msTime/60_000L)%60L,10).append(':')
			          ,(msTime/1000L)%60L,10).append('.')
			          ,msTime%1000L,100);
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
		 
		 
		 return target;
	}

	public static  A appendNearestTimeUnit(A target, long nsValue, String postfix) {
		appendNearestTimeUnit(target, nsValue);
		try {
			target.append(postfix);
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
		return target;
	}

	public static  A appendNearestTimeUnit(A target, long nsValue) {
		try {
			if (nsValue<7_000) {
				appendFixedDecimalDigits(target, nsValue, 1000).append(" ns");
			} else if (nsValue<7_000_000){
				appendFixedDecimalDigits(target, nsValue/1_000,1000).append(" µs");
			} else if (nsValue<7_000_000_000L){
				appendFixedDecimalDigits(target, nsValue/1_000_000,1000).append(" ms");				
			} else if (nsValue<90_000_000_000L){
				appendFixedDecimalDigits(target, nsValue/1_000_000_000L,100).append(" sec");
			} else if (nsValue<(120L*60_000_000_000L)){
				appendFixedDecimalDigits(target, nsValue/60_000_000_000L,100).append(" min");
			} else {
				appendValue(target, nsValue/(60L*60_000_000_000L)).append(" hr");
			}
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
		return target;
	}

	private static final String[] htmlEntities = buildHTMLEntities();
	private static final byte[][] httpEntitiesUTF8 = encodeUTF8(buildHTMLEntities());
	
	/**
	 * @param target Appendable for encoded data
	 * @param source CharSequence source text to be encoded
	 * @return the target Apppendable for more data to be added.
	 */
	public static  A appendHTMLEntityEscaped(A target, CharSequence source) {	
		if (target instanceof AppendableByteWriter) {
			appendHTMLEntityEscaped1(source, (AppendableByteWriter)target);
			return target;
		} else {
			return appendHTMLEntityEscaped2(target, source);
		}
	}

	private static void appendHTMLEntityEscaped1(final CharSequence source, final AppendableByteWriter abw) {
		final int len = source.length();
		for(int i = 0; i=64 || null == (entity = httpEntitiesUTF8[(int)at])) {
				abw.append(at);
			} else {
				abw.write(entity);
			}
		}
	}


	private static  A appendHTMLEntityEscaped2(A target, CharSequence source) {
		try {
			String entity = null;
			for(int i = 0; i=64 || null == (entity = htmlEntities[(int)at])) {
					target.append(at);
				} else {
					target.append(entity);					
				}
			}		
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
				
		return target;
	}


	private static byte[][] encodeUTF8(String[] input) {
		byte[][] result = new byte[input.length][];
		int i = input.length;
		while (--i>=0) {
			result[i] = null==input[i]?null:input[i].getBytes();
		}
		return result;
	}


	private static String[] buildHTMLEntities() {
		if (null!=htmlEntities) {
			return htmlEntities;
		} else {
			String[] result = new String[64];
			
			result['<'] = "<";
			result['>'] = ">";		
			result['&'] = "&";
			result['"'] = """;		
			result['\''] = "'";
					
			return result;
		}
	}

	
	
	private final static long[] tensDivisor = buildTensDivisorArray();
	
    private static long[] buildTensDivisorArray() {
    	long tens = 1000000000000000000L;
    	int c = 0;
    	long[] result = new long[20];
    	while (tens>0) {
    		//System.out.println("pos "+c+" has "+tens);
    		
    		result[c++] = tens;
    		tens = tens/10;
    	}
    	assert(c==result.length-1) : "found "+c+" expected "+result.length;
   
    	return result;
    }
    
    private final static char[] onesChars = buildChars(1000, 1);
    private final static char[] tensChars = buildChars(1000, 10);
    private final static char[] thousChars = buildChars(1000, 100);

    
    private static char[] buildChars(int total, int run) {
    	char[] result = new char[total];
    	int c = 0;
    	int v = 0;
    	while (c=0) {
    			result[c++] = value;
    		}
    		if ('9' == value) {
    			v=0;
    		}
    	}    	
    	return result;
    }
    

	public static int longToChars(long value, boolean useNegPara, final byte[] localBuffer, final int mask,
			int activePos) {
		boolean isNegative = value<0;
		if (isNegative) {
			if (useNegPara) {
				localBuffer[mask & activePos++] = (byte) '(';
			}
			localBuffer[mask & activePos++] = (byte) '-';
		    value = -value;
		}
		
		long nextValue = value;//at this point the value is absolute
		int orAll = 0; 
		int t = value <=  Integer.MAX_VALUE ? (value<=10000? 14: 8): 2;//skip high end if smaller value

		activePos = collectDigitChars(localBuffer, mask, activePos, nextValue, orAll, t);
		
		
		if (isNegative && useNegPara) {
			localBuffer[mask & activePos++] = (byte) ')';
		}
		return activePos;
	}
	

	private static int collectDigitChars(final byte[] localBuffer, final int mask,
											int activePos, long nextValue,
											int orAll, int t) {
		long tens;
		while (t!=tensDivisor.length && (tens=tensDivisor[t++])>=1) {
			t+=2;
		    int digit  = (int)(nextValue/tens);
		    nextValue  = nextValue%tens;
		    
		    char c;
		    orAll |= ((c=thousChars[digit])-'0');//this is to remove the leading zeros
		    if (0!=orAll) {
		    	localBuffer[mask & activePos++] = (byte)c;
		    }

		    orAll |= ((c=tensChars[digit])-'0');//this is to remove the leading zeros
		    if (0!=orAll) {
		    	localBuffer[mask & activePos++] = (byte)c;
		    }

		    orAll |= ((c=onesChars[digit])-'0');//this is to remove the leading zeros
		    if (0!=orAll) {
		    	localBuffer[mask & activePos++] = (byte)c;
		    }
		    
		}
		localBuffer[mask & activePos++] = (byte)onesChars[(int)nextValue];
		return activePos;
	}
	
	//TODO: add nearestMemoryUnit  B, K, M, G, T, P
    
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy