    001package org.cpsolver.ifs.assignment.context;
    002
    003import org.cpsolver.ifs.assignment.Assignment;
    004import org.cpsolver.ifs.assignment.InheritedAssignment;
    005import org.cpsolver.ifs.model.Value;
    006import org.cpsolver.ifs.model.Variable;
    007
    008/**
    009 * A variant of the {@link AssignmentContextHolderMap} that is used by the {@link InheritedAssignment}
    010 * class. If a {@link HasAssignmentContext} class implements the {@link CanInheritContext} interface,
    011 * this class will use the {@link CanInheritContext#inheritAssignmentContext(Assignment, AssignmentContext)} method
    012 * instead of the {@link HasAssignmentContext#createAssignmentContext(Assignment)} method to create
    013 * a new context.
    014 *
    015 * @see HasAssignmentContext
    016 * @see InheritedAssignment
    017 * @see CanInheritContext
    018 *
    019 * @author  Tomáš Müller
    020 * @version IFS 1.3 (Iterative Forward Search)<br>
    021 *          Copyright (C) 2014 Tomáš Müller<br>
    022 *          <a href="mailto:muller@unitime.org">muller@unitime.org</a><br>
    023 *          <a href="http://muller.unitime.org">http://muller.unitime.org</a><br>
    024 * <br>
    025 *          This library is free software; you can redistribute it and/or modify
    026 *          it under the terms of the GNU Lesser General Public License as
    027 *          published by the Free Software Foundation; either version 3 of the
    028 *          License, or (at your option) any later version. <br>
    029 * <br>
    030 *          This library is distributed in the hope that it will be useful, but
    031 *          WITHOUT ANY WARRANTY; without even the implied warranty of
    032 *          MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    033 *          Lesser General Public License for more details. <br>
    034 * <br>
    035 *          You should have received a copy of the GNU Lesser General Public
    036 *          License along with this library; if not see <a href='http://www.gnu.org/licenses'>http://www.gnu.org/licenses</a>.
    037 * @param <V> Variable
    038 * @param <T> Value
    039 **/
    040public class InheritedAssignmentContextHolder<V extends Variable<V, T>, T extends Value<V, T>> extends DefaultParallelAssignmentContextHolder<V, T> {
    041    private long iVersion;
    042
    043    public InheritedAssignmentContextHolder(int index, long version) {
    044        super(index);
    045        iVersion = version;
    046    }
    047
    048    /**
    049     * If the {@link AssignmentContextReference#getParent()} implements the {@link CanInheritContext} interface, this
    050     * method will use the {@link CanInheritContext#inheritAssignmentContext(Assignment, AssignmentContext)} instead of the
    051     * {@link HasAssignmentContext#createAssignmentContext(Assignment)} to create a new context.
    052     * @param assignment current assignment (must be {@link InheritedAssignment})
    053     * @param reference assignment context reference
    054     * @return assignment context for the given assignment and reference
    055     */
    056    @Override
    057    @SuppressWarnings("unchecked")
    058    public <U extends AssignmentContext> U getAssignmentContext(Assignment<V, T> assignment, AssignmentContextReference<V, T, U> reference) {
    059        if (iIndex >= 0 && iIndex < CanHoldContext.sMaxSize && reference.getParent() instanceof CanHoldContext) {
    060            AssignmentContext[] contexts = ((CanHoldContext)reference.getParent()).getContext();
    061
    062            VersionedContext<U> context = (VersionedContext<U>)contexts[iIndex];
    063            if (context == null) {
    064                context = new VersionedContext<U>();
    065                if (reference.getParent() instanceof CanInheritContext)
    066                    context.setContent(((CanInheritContext<V, T, U>)reference.getParent()).inheritAssignmentContext(assignment,
    067                            ((InheritedAssignment<V, T>)assignment).getParentAssignment().getAssignmentContext(reference)), iVersion);
    068                else
    069                    context.setContent(reference.getParent().createAssignmentContext(assignment), iVersion);
    070                contexts[iIndex] = context;
    071            } else if (!context.isCurrent(iVersion)) {
    072                if (reference.getParent() instanceof CanInheritContext)
    073                    context.setContent(((CanInheritContext<V, T, U>)reference.getParent()).inheritAssignmentContext(assignment,
    074                            ((InheritedAssignment<V, T>)assignment).getParentAssignment().getAssignmentContext(reference)), iVersion);
    075                else
    076                    context.setContent(reference.getParent().createAssignmentContext(assignment), iVersion);
    077            }
    078
    079            return context.getContent();
    080        } else {
    081            U context = (U) iContexts.get(reference.getIndex());
    082            if (context != null) return context;
    083
    084            if (reference.getParent() instanceof CanInheritContext)
    085                context = ((CanInheritContext<V, T, U>)reference.getParent()).inheritAssignmentContext(assignment,
    086                        ((InheritedAssignment<V, T>)assignment).getParentAssignment().getAssignmentContext(reference));
    087            else
    088                context = reference.getParent().createAssignmentContext(assignment);
    089            iContexts.put(reference.getIndex(), context);
    090
    091            return context;
    092        }
    093    }
    094
    095    public static class VersionedContext<U extends AssignmentContext> implements AssignmentContext {
    096        U iContent = null;
    097        long iContentVersion = -1;
    098
    099        VersionedContext() {}
    100
    101        public U getContent() {
    102            return iContent;
    103        }
    104
    105        public void setContent(U content, long version) {
    106            iContent = content;
    107            iContentVersion = version;
    108        }
    109
    110        public boolean isCurrent(long version) {
    111            return iContentVersion == version;
    112        }
    113    }
    114}