001package org.cpsolver.ifs.assignment.context;
002
003import java.util.Arrays;
004import java.util.concurrent.locks.ReentrantReadWriteLock;
005
006import org.cpsolver.ifs.assignment.Assignment;
007import org.cpsolver.ifs.assignment.DefaultParallelAssignment;
008import org.cpsolver.ifs.model.Value;
009import org.cpsolver.ifs.model.Variable;
010
011
012/**
013 * A simple assignment context holder implementation used by the {@link DefaultParallelAssignment} class.
014 * {@link CanHoldContext} are used when possible, storing contexts in arrays, on the
015 * {@link DefaultParallelAssignment#getIndex()} position.
016 * 
017 * @see AssignmentContext
018 * @see AssignmentContextReference
019 * @see AssignmentContextHolder
020 * 
021 * @version IFS 1.3 (Iterative Forward Search)<br>
022 *          Copyright (C) 2014 Tomas Muller<br>
023 *          <a href="mailto:muller@unitime.org">muller@unitime.org</a><br>
024 *          <a href="http://muller.unitime.org">http://muller.unitime.org</a><br>
025 * <br>
026 *          This library is free software; you can redistribute it and/or modify
027 *          it under the terms of the GNU Lesser General Public License as
028 *          published by the Free Software Foundation; either version 3 of the
029 *          License, or (at your option) any later version. <br>
030 * <br>
031 *          This library is distributed in the hope that it will be useful, but
032 *          WITHOUT ANY WARRANTY; without even the implied warranty of
033 *          MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
034 *          Lesser General Public License for more details. <br>
035 * <br>
036 *          You should have received a copy of the GNU Lesser General Public
037 *          License along with this library; if not see <a href='http://www.gnu.org/licenses'>http://www.gnu.org/licenses</a>.
038 * @param <V> Variable
039 * @param <T> Value
040 **/
041public class DefaultParallelAssignmentContextHolder<V extends Variable<V, T>, T extends Value<V, T>> extends AssignmentContextHolderMap<V, T> {
042    private int iIndex = -1;
043    private final ReentrantReadWriteLock iLock = new ReentrantReadWriteLock();
044
045    public DefaultParallelAssignmentContextHolder(int threadIndex) {
046        iIndex = threadIndex;
047    }
048    
049    /**
050     * Returns contexts as an existing, big enough array.
051     * @param holder assignment context holder
052     * @return an initialized array of the appropriate assignment contexts
053     */
054    protected AssignmentContext[] getContexts(CanHoldContext holder) {
055        iLock.readLock().lock();
056        try {
057            AssignmentContext[] contexts = holder.getContext();
058            if (contexts != null && iIndex < contexts.length)
059                return contexts;
060        } finally {
061            iLock.readLock().unlock();
062        }
063        iLock.writeLock().lock();
064        try {
065            AssignmentContext[] contexts = holder.getContext();
066            if (contexts == null) {
067                contexts = new AssignmentContext[Math.max(10, 1 + iIndex)];
068                holder.setContext(contexts);
069            } else if (contexts.length <= iIndex) {
070                contexts = Arrays.copyOf(contexts, iIndex + 10);
071                holder.setContext(contexts);
072            }
073            return contexts;
074        } finally {
075            iLock.writeLock().unlock();
076        }
077    }
078    
079    @Override
080    @SuppressWarnings("unchecked")
081    public <U extends AssignmentContext> U getAssignmentContext(Assignment<V, T> assignment, AssignmentContextReference<V, T, U> reference) {
082        if (iIndex >= 0 && reference.getParent() instanceof CanHoldContext) {
083            AssignmentContext[] contexts = getContexts((CanHoldContext)reference.getParent());
084            AssignmentContext context = contexts[iIndex];
085            if (context != null) return (U) context;
086            
087            context = reference.getParent().createAssignmentContext(assignment);
088            contexts[iIndex] = context;
089            
090            return (U) context;
091        } else {
092            return super.getAssignmentContext(assignment, reference);
093        }
094    }
095    
096    @Override
097    public <C extends AssignmentContext> void clearContext(AssignmentContextReference<V, T, C> reference) {
098        if (iIndex >= 0 && reference.getParent() instanceof CanHoldContext) {
099            AssignmentContext[] contexts = getContexts((CanHoldContext)reference.getParent());
100            contexts[iIndex] = null;
101        } else {
102            super.clearContext(reference);
103        }
104    }
105}