/* * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, * CA 95054 USA or visit www.sun.com if you need additional information or * have any questions. */ package org.visage.runtime.sequence; import org.visage.runtime.VisageObject; public abstract class BoundForOverVaryingAbstract<T, PT> extends BoundFor<T, PT> { protected int[] cumulatedLengths; private int cacheIndex; private int cachePart; public BoundForOverVaryingAbstract(VisageObject container, int forVarNum, int inductionSeqVarNum, boolean dependsOnIndex) { super(container, forVarNum, inductionSeqVarNum, dependsOnIndex); } /** Get the size of part ipart. */ protected abstract int size(int ipart); /** Get the j'th item of part ipart. */ protected abstract T get(int ipart, int j); public int size() { initializeIfNeeded(); if (state != BOUND_FOR_STATE_PARTS_STABLE || pendingTriggers > 0) { return cumLength(numParts); } else { return sizeAtLastTrigger; } } @Override protected int decacheLengths() { cachePart = 0; int previousSize = sizeAtLastTrigger; if (cumulatedLengths == null || cumulatedLengths.length < numParts || cumulatedLengths.length > (numParts+10)) { cumulatedLengths = new int[numParts]; } sizeAtLastTrigger = calculateCumLength(numParts, cumulatedLengths); return previousSize; } private int calculateCumLength(int ipart, int[] lengths) { inWholesaleUpdate = true; int sum = 0; for (int ips = 0; ips < ipart; ++ips) { sum += size(ips); if (lengths != null) { cumulatedLengths[ips] = sum; } } inWholesaleUpdate = false; return sum; } protected int cumLength(int ipart) { if (ipart <= 0) { return 0; } else if (state != BOUND_FOR_STATE_PARTS_STABLE || pendingTriggers > 0) { // Calculate without touching cache return calculateCumLength(ipart, null); } else { return cumulatedLengths[ipart - 1]; } } protected int cachedCumLength(int ipart) { if (ipart <= 0) { return 0; } else { return cumulatedLengths[ipart - 1]; } } public T get(int index) { initializeIfNeeded(); if (index < 0) return null; int i = 0; int cumPrev = 0; if (state != BOUND_FOR_STATE_PARTS_STABLE || pendingTriggers > 0) { // Calculate without touching cache for (;; i++) { if (i >= numParts) { return null; } int cum = cumLength(i + 1); if (index < cum) { return get(i, index - cumPrev); } cumPrev = cum; } } // FIXME - should use binary search if not in cache. if (index >= cacheIndex) { i = cachePart; cumPrev = cumLength(i); } for (;; i++) { if (i >= numParts) return null; int cum = cumLength(i+1); if (index < cum) { cachePart = i; cacheIndex = cumPrev; return get(i, index-cumPrev); } cumPrev = cum; } } }