17935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert/* 27935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ******************************************************************************* 37935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Copyright (C) 1996-2011, International Business Machines Corporation and * 47935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * others. All Rights Reserved. * 57935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ******************************************************************************* 67935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 77935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertpackage com.ibm.icu.impl; 87935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 97935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert/** 107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertpublic class CalendarCache 137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert{ 147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public CalendarCache() { 187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert makeArrays(arraySize); 197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private void makeArrays(int newSize) { 227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert keys = new long[newSize]; 237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert values = new long[newSize]; 247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int i = 0; i < newSize; i++) { 267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert values[i] = EMPTY; 277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert arraySize = newSize; 297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert threshold = (int)(arraySize * 0.75); 307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert size = 0; 317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public synchronized long get(long key) { 377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return values[findIndex(key)]; 387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public synchronized void put(long key, long value) 447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { 457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (size >= threshold) { 467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert rehash(); 477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int index = findIndex(key); 497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert keys[index] = key; 517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert values[index] = value; 527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert size++; 537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private final int findIndex(long key) { 567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int index = hash(key); 577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int delta = 0; 587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert while (values[index] != EMPTY && keys[index] != key) 607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { 617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (delta == 0) { 627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert delta = hash2(key); 637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert index = (index + delta) % arraySize; 657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return index; 677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private void rehash() 707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { 717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int oldSize = arraySize; 727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert long[] oldKeys = keys; 737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert long[] oldValues = values; 747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (pIndex < primes.length - 1) { 767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert arraySize = primes[++pIndex]; 777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert arraySize = arraySize * 2 + 1; 797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert size = 0; 817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert makeArrays(arraySize); 837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int i = 0; i < oldSize; i++) { 847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (oldValues[i] != EMPTY) { 857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert put(oldKeys[i], oldValues[i]); 867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Produce a uniformly-distributed hash value from an integer key. 937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * This is essentially a linear congruential random number generator 947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * that uses the key as its seed value. 957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private final int hash(long key) 977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { 987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int h = (int)((key * 15821 + 1) % arraySize); 997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (h < 0) { 1007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert h += arraySize; 1017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return h; 1037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private final int hash2(long key) { 1067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return arraySize - 2 - (int)(key % (arraySize-2) ); 1077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert static private final int primes[] = { // 5, 17, 31, 47, // for testing 1107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 61, 127, 509, 1021, 2039, 4093, 8191, 16381, 32749, 65521, 1117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 131071, 262139, 1127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert }; 1137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private int pIndex = 0; 1157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private int size = 0; 1167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private int arraySize = primes[pIndex]; 1177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private int threshold = (arraySize * 3) / 4; 1187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private long[] keys = new long[arraySize]; 1207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private long[] values = new long[arraySize]; 1217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 1237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 1247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 1257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert static public long EMPTY = Long.MIN_VALUE; 1267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert} 127