/******************************************************************************* * Copyright (c) 2015, 2016 Google, Inc and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Stefan Xenos (Google) - Initial implementation *******************************************************************************/ package org.eclipse.jdt.internal.core.nd.field; import org.eclipse.jdt.internal.core.nd.Nd; import org.eclipse.jdt.internal.core.nd.NdNode; import org.eclipse.jdt.internal.core.nd.db.Database; /** * Represents a 1-to-0..1 relationship in a Nd database. */ public class FieldOneToOne<T extends NdNode> implements IField, IDestructableField, IRefCountedField { private int offset; public final Class<T> nodeType; FieldOneToOne<?> backPointer; private boolean pointsToOwner; /** * @param nodeType * @param backPointer */ private FieldOneToOne(Class<T> nodeType, FieldOneToOne<?> backPointer, boolean pointsToOwner) { this.nodeType = nodeType; if (backPointer != null) { if (backPointer.backPointer != null && backPointer.backPointer != this) { throw new IllegalArgumentException( "Attempted to construct a FieldOneToOne referring to a backpointer list that is already in use" //$NON-NLS-1$ + " by another field"); //$NON-NLS-1$ } backPointer.backPointer = this; } this.backPointer = backPointer; this.pointsToOwner = pointsToOwner; } public static <T extends NdNode, B extends NdNode> FieldOneToOne<T> create(StructDef<B> builder, Class<T> nodeType, FieldOneToOne<B> forwardPointer) { FieldOneToOne<T> result = new FieldOneToOne<T>(nodeType, forwardPointer, false); builder.add(result); builder.addDestructableField(result); return result; } public static <T extends NdNode, B extends NdNode> FieldOneToOne<T> createOwner(StructDef<B> builder, Class<T> nodeType, FieldOneToOne<B> forwardPointer) { FieldOneToOne<T> result = new FieldOneToOne<T>(nodeType, forwardPointer, true); builder.add(result); builder.addDestructableField(result); builder.addOwnerField(result); return result; } public T get(Nd nd, long address) { long ptr = nd.getDB().getRecPtr(address + this.offset); return NdNode.load(nd, ptr, this.nodeType); } public void put(Nd nd, long address, T target) { cleanup(nd, address); nd.getDB().putRecPtr(address + this.offset, target == null ? 0 : target.address); if (target == null && this.pointsToOwner) { nd.scheduleDeletion(address); } } @Override public void destruct(Nd nd, long address) { cleanup(nd, address); } private void cleanup(Nd nd, long address) { Database db = nd.getDB(); long ptr = db.getRecPtr(address + this.offset); if (ptr != 0) { db.putRecPtr(ptr + this.backPointer.offset, 0); // If we own our target, delete it if (this.backPointer.pointsToOwner) { nd.scheduleDeletion(ptr); } } } @Override public void setOffset(int offset) { this.offset = offset; } @Override public int getRecordSize() { return Database.PTR_SIZE; } @Override public boolean hasReferences(Nd nd, long address) { if (this.pointsToOwner) { long ptr = nd.getDB().getRecPtr(address + this.offset); return ptr != 0; } return false; } }