package railo.runtime.type; import java.io.Externalizable; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; import java.util.Date; import railo.commons.digest.WangJenkins; import railo.commons.lang.SizeOf; import railo.commons.lang.StringUtil; import railo.runtime.exp.CasterException; import railo.runtime.exp.PageException; import railo.runtime.op.Castable; import railo.runtime.op.Caster; import railo.runtime.op.Operator; import railo.runtime.op.date.DateCaster; import railo.runtime.type.Collection.Key; import railo.runtime.type.dt.DateTime; public class KeyImpl implements Collection.Key,Castable,Comparable,Sizeable,Externalizable,WangJenkins { private static final long serialVersionUID = -8864844181140115609L; // do not change private static final long[] byteTable = createLookupTable(); private static final long HSTART = 0xBB40E64DA205B064L; private static final long HMULT = 7664345821815920749L; //private boolean intern; private String key; private transient String lcKey; private transient String ucKey; private transient int wjh; private transient int sfm=-1; private transient long h64; public KeyImpl() { // DO NOT USE, JUST FOR UNSERIALIZE } private static final long[] createLookupTable() { long[] _byteTable = new long[256]; long h = 0x544B2FBACAAF1684L; for (int i = 0; i < 256; i++) { for (int j = 0; j < 31; j++) { h = (h >>> 7) ^ h; h = (h << 11) ^ h; h = (h >>> 10) ^ h; } _byteTable[i] = h; } return _byteTable; } private static final long createHash64(CharSequence cs) { long h = HSTART; final long hmult = HMULT; final long[] ht = byteTable; final int len = cs.length(); for (int i = 0; i < len; i++) { char ch = cs.charAt(i); h = (h * hmult) ^ ht[ch & 0xff]; h = (h * hmult) ^ ht[(ch >>> 8) & 0xff]; } return h; } @Override public int wangJenkinsHash() { if(wjh==0) { int h = hashCode(); h += (h << 15) ^ 0xffffcd7d; h ^= (h >>> 10); h += (h << 3); h ^= (h >>> 6); h += (h << 2) + (h << 14); wjh= h ^ (h >>> 16); } return wjh; } public int slotForMap() { if(sfm == -1) { int h = 0; h ^= hashCode(); h ^= (h >>> 20) ^ (h >>> 12); sfm = h ^ (h >>> 7) ^ (h >>> 4); } return sfm; } public void writeExternal(ObjectOutput out) throws IOException { out.writeObject(key); } public void readExternal(ObjectInput in) throws IOException,ClassNotFoundException { key=(String) in.readObject(); ucKey=key.toUpperCase(); h64=createHash64(ucKey); } public KeyImpl(String key) { this.key=key; this.ucKey=key.toUpperCase(); h64=createHash64(ucKey); } /** * for dynamic loading of key objects * @param string * @return */ public static Collection.Key init(String key) { //return KeyConstants.getKey(key); //if(KeyConstants.getFieldName(key)!=null)print.ds(key); return new KeyImpl(key); } public static Collection.Key _const(String key) { //return KeyConstants.getKey(key); //if(KeyConstants.getFieldName(key)!=null)print.ds(key); return new KeyImpl(key); } public synchronized static Collection.Key getInstance(String key) { //return KeyConstants.getKey(key); //if(KeyConstants.getFieldName(key)!=null)print.ds(key); return new KeyImpl(key); } public synchronized static Collection.Key intern(String key) { //return KeyConstants.getKey(key); //if(KeyConstants.getFieldName(key)!=null)print.ds(key); return new KeyImpl(key); } @Override public char charAt(int index) { return key.charAt(index); } @Override public char lowerCharAt(int index) { return getLowerString().charAt(index); } public char upperCharAt(int index) { return ucKey.charAt(index); } @Override public String getLowerString() { if(lcKey==null)lcKey=StringUtil.toLowerCase(key); return lcKey; } public String getUpperString() { return ucKey; } @Override public String toString() { return key; } @Override public String getString() { return key; } @Override public boolean equals(Object other) { if(this==other) return true; if(other instanceof KeyImpl) { return hash()==((KeyImpl)other).hash(); } if(other instanceof String) { return key.equalsIgnoreCase((String)other); } if(other instanceof Key) { return ucKey.equalsIgnoreCase(((Key)other).getUpperString()); } return false; } @Override public boolean equalsIgnoreCase(Key other) { if(this==other) return true; if(other instanceof KeyImpl) { return h64==((KeyImpl)other).h64;//return lcKey.equals((((KeyImpl)other).lcKey)); } return ucKey.equalsIgnoreCase(other.getLowerString()); } @Override public int hashCode() { return ucKey.hashCode(); } // FUTURE add to interface public long hash() { return h64; } @Override public int getId() {// set to deprecated, use instead hash() return hashCode(); } @Override public boolean castToBooleanValue() throws PageException { return Caster.toBooleanValue(key); } @Override public Boolean castToBoolean(Boolean defaultValue) { return Caster.toBoolean(key,defaultValue); } @Override public DateTime castToDateTime() throws PageException { return Caster.toDatetime(key,null); } @Override public DateTime castToDateTime(DateTime defaultValue) { return DateCaster.toDateAdvanced(key,true,null,defaultValue); } @Override public double castToDoubleValue() throws PageException { return Caster.toDoubleValue(key); } @Override public double castToDoubleValue(double defaultValue) { return Caster.toDoubleValue(key,defaultValue); } @Override public String castToString() throws PageException { return key; } @Override public String castToString(String defaultValue) { return key; } @Override public int compareTo(boolean b) throws PageException { return Operator.compare(key, b); } @Override public int compareTo(DateTime dt) throws PageException { return Operator.compare(key, (Date)dt); } @Override public int compareTo(double d) throws PageException { return Operator.compare(key, d); } @Override public int compareTo(String str) throws PageException { return Operator.compare(key, str); } public int compareTo(Object o) { try { return Operator.compare(key, o); } catch (PageException e) { ClassCastException cce = new ClassCastException(e.getMessage()); cce.setStackTrace(e.getStackTrace()); throw cce; } } public static Array toUpperCaseArray(Key[] keys) { ArrayImpl arr=new ArrayImpl(); for(int i=0;i<keys.length;i++) { arr._append(((KeyImpl)keys[i]).getUpperString()); } return arr; } public static Array toLowerCaseArray(Key[] keys) { ArrayImpl arr=new ArrayImpl(); for(int i=0;i<keys.length;i++) { arr._append(((KeyImpl)keys[i]).getLowerString()); } return arr; } public static Array toArray(Key[] keys) { ArrayImpl arr=new ArrayImpl(); for(int i=0;i<keys.length;i++) { arr._append(((KeyImpl)keys[i]).getString()); } return arr; } public static String toUpperCaseList(Key[] array, String delimiter) { if(array.length==0) return ""; StringBuffer sb=new StringBuffer(((KeyImpl)array[0]).getUpperString()); if(delimiter.length()==1) { char c=delimiter.charAt(0); for(int i=1;i<array.length;i++) { sb.append(c); sb.append(((KeyImpl)array[i]).getUpperString()); } } else { for(int i=1;i<array.length;i++) { sb.append(delimiter); sb.append(((KeyImpl)array[i]).getUpperString()); } } return sb.toString(); } public static String toList(Key[] array, String delimiter) { if(array.length==0) return ""; StringBuilder sb=new StringBuilder(((KeyImpl)array[0]).getString()); if(delimiter.length()==1) { char c=delimiter.charAt(0); for(int i=1;i<array.length;i++) { sb.append(c); sb.append((array[i]).getString()); } } else { for(int i=1;i<array.length;i++) { sb.append(delimiter); sb.append((array[i]).getString()); } } return sb.toString(); } public static String toLowerCaseList(Key[] array, String delimiter) { if(array.length==0) return ""; StringBuffer sb=new StringBuffer(((KeyImpl)array[0]).getLowerString()); if(delimiter.length()==1) { char c=delimiter.charAt(0); for(int i=1;i<array.length;i++) { sb.append(c); sb.append(((KeyImpl)array[i]).getLowerString()); } } else { for(int i=1;i<array.length;i++) { sb.append(delimiter); sb.append(((KeyImpl)array[i]).getLowerString()); } } return sb.toString(); } public static Collection.Key toKey(Object obj, Collection.Key defaultValue) { if(obj instanceof Collection.Key) return (Collection.Key) obj; String str = Caster.toString(obj,null); if(str==null) return defaultValue; return init(str); } public static Collection.Key toKey(Object obj) throws CasterException { if(obj instanceof Collection.Key) return (Collection.Key) obj; String str = Caster.toString(obj,null); if(str==null) throw new CasterException(obj,Collection.Key.class); return init(str); } public long sizeOf() { return SizeOf.size(this.key)+ SizeOf.size(this.lcKey)+ SizeOf.size(this.ucKey)+ SizeOf.REF_SIZE; } @Override public int length() { return key.length(); } public static Key[] toKeyArray(String[] arr) { if(arr==null) return null; Key[] keys=new Key[arr.length]; for(int i=0;i<keys.length;i++){ keys[i]=init(arr[i]); } return keys; } }