/* * Copyright © 2010 by Ondrej Skalicka. All Rights Reserved */ package cz.cvut.felk.cig.jcop.problem; import java.util.LinkedList; import java.util.List; /** * Operation history is used to record which operations in which order were applied to get operation. * <p/> * Operation history has reference to parent operation history, but not to attributes itself. Nor does attributes has * reference to parent attributes. This is because garbage collector could faster free unused * configurations/operationHistories from memory. Every time attributes becomes unreachable from rest of code, it could * be freed, along with its operation history (usually). * * @author Ondrej Skalicka */ public class OperationHistory { /** * Operation used in this step of history */ protected Operation operation; /** * Preceding operationHistory, root has null */ protected OperationHistory parent; /** * Counter indicating order of this entry in history of attributes. * <p/> * Root has 0, each other child has its parent counter+1. */ protected long counter; /** * Actual size of history. * * This can vary from {@link #counter} if history has been empties. In such case, {@link #counter} remains unchanged, while * size is reset to zero. */ protected long size; /** * How many items are allowed in history at most. * * If this number is reached, history is emptied in order to free allocated memory. Constants {@link #LIMIT_DISABLED} * and {@link #LIMIT_UNLIMITED} are allowed values as well as any positive number. */ public static int limit = 1024; /** * No history is collected. * * Every configuration has only one OperationHistory element (with null {@link #parent}). */ public static final int LIMIT_DISABLED = 0; /** * History is never erased. * * Note that this can lead to huge memory overhead as single configuration can have as many as hundred million items in * history (which with about 32B for every OperationHistory object means several GB of memory). */ public static final int LIMIT_UNLIMITED = -1; /** * Constructs new OperationHistory without parent (eg. root) * * @param operation operation associated with OperationHistory */ public OperationHistory(Operation operation) { this.operation = operation; this.parent = null; this.counter = 0; this.size = 0; } /** * Creates new OperationHistory with parent (eg. node or leaf) * * @param operation operation associated with OperationHistory * @param parent parent OperationHistory */ public OperationHistory(Operation operation, OperationHistory parent) { this.operation = operation; this.counter = parent.getCounter() + 1; if (OperationHistory.limit >= 0 && parent.size >= OperationHistory.limit) { this.parent = null; this.size = 0; } else { this.parent = parent; this.size = parent.size + 1; } } /** * Returns operation history as string in format * <p/> * 0: firstOperation, 1: secondOperation ... n-1: lastOperation * * @return string representation of OperationHistory */ @Override public String toString() { String base = ""; if (this.parent != null) base = this.parent.toString(); return base + (this.parent == null ? "" : ", ") + this.counter + ":" + operation.toString(); } /** * Returns all parents (including this child) ordered from root to leaf (eg. in chronological order). * * @return list of all OperationHistory associated with this one */ public List<OperationHistory> getChronologicalList() { OperationHistory operationHistory = this; LinkedList<OperationHistory> operationHistoryList = new LinkedList<OperationHistory>(); do { operationHistoryList.addFirst(operationHistory); operationHistory = operationHistory.getParent(); } while (operationHistory != null); return operationHistoryList; } /** * Returns counter - starting from node with counter = 0, each child has counter incremented by 1. * * @return counter of node */ public long getCounter() { return counter; } public Operation getOperation() { return operation; } public OperationHistory getParent() { return parent; } }