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