/*******************************************************************************
* Copyright (c) 2005, 2014 QNX Software Systems 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:
* QNX - Initial API and implementation
* Markus Schorn (Wind River Systems)
* Sergey Prigogin (Google)
*******************************************************************************/
package org.eclipse.cdt.internal.core.pdom.db;
import org.eclipse.cdt.core.dom.IPDOMVisitor;
import org.eclipse.cdt.internal.core.pdom.dom.PDOMLinkage;
import org.eclipse.cdt.internal.core.pdom.dom.PDOMNode;
import org.eclipse.core.runtime.CoreException;
/**
* Represents a linked list of PDOMNode records
* @author Doug Schaefer
*/
public class PDOMNodeLinkedList {
private long offset;
private PDOMLinkage linkage;
private boolean allowsNull;
private static final int FIRST_MEMBER = 0;
protected static final int RECORD_SIZE = 4;
public PDOMNodeLinkedList(PDOMLinkage linkage, long offset, boolean allowsNulls) {
this.offset = offset;
this.linkage = linkage;
this.allowsNull = allowsNulls;
}
/**
* Creates an object representing a linked list at the specified offset of the specified pdom.
* The linked list created may not hold null items
* @param linkage
* @param offset
*/
public PDOMNodeLinkedList(PDOMLinkage linkage, long offset) {
this(linkage, offset, false);
}
protected int getRecordSize() {
return RECORD_SIZE;
}
public void accept(IPDOMVisitor visitor) throws CoreException {
Database db = linkage.getDB();
long firstItem = db.getRecPtr(offset + FIRST_MEMBER);
if (firstItem == 0)
return;
long item = firstItem;
do {
PDOMNode node;
final long record= db.getRecPtr(item + ListItem.ITEM);
if (record == 0) {
if (!allowsNull) {
throw new NullPointerException();
}
node= null;
} else {
node= PDOMNode.load(linkage.getPDOM(), record);
}
if (visitor.visit(node) && node != null) {
node.accept(visitor);
}
visitor.leave(node);
} while ((item = db.getRecPtr(item + ListItem.NEXT)) != firstItem);
}
private ListItem getFirstMemberItem() throws CoreException {
Database db = linkage.getDB();
long item = db.getRecPtr(offset + FIRST_MEMBER);
return item != 0 ? new ListItem(db, item) : null;
}
/**
* Returns node at position {@code pos}. Not recommended to be used in a loop since
* such a loop would be more expensive that a single {@code accept(IPDOMVisitor)} call.
* @param pos A zero-based position in the list.
* @return The node at position {@code pos}, or {@code null} if no such node exists.
*/
public PDOMNode getNodeAt(int pos) throws CoreException {
Database db = linkage.getDB();
long firstItem = db.getRecPtr(offset + FIRST_MEMBER);
if (firstItem == 0) {
return null;
}
long item = firstItem;
do {
if (--pos < 0) {
long record = db.getRecPtr(item + ListItem.ITEM);
if (record == 0) {
if (!allowsNull) {
throw new NullPointerException();
}
return null;
} else {
return PDOMNode.load(linkage.getPDOM(), record);
}
}
} while ((item = db.getRecPtr(item + ListItem.NEXT)) != firstItem);
return null;
}
public void addMember(PDOMNode member) throws CoreException {
addMember(allowsNull && member==null ? 0 : member.getRecord());
}
protected void addMember(long record) throws CoreException {
Database db = linkage.getDB();
ListItem firstMember = getFirstMemberItem();
if (firstMember == null) {
firstMember = new ListItem(db);
firstMember.setItem(record);
firstMember.setNext(firstMember);
firstMember.setPrev(firstMember);
db.putRecPtr(offset + FIRST_MEMBER, firstMember.getRecord());
} else {
ListItem newMember = new ListItem(db);
newMember.setItem(record);
ListItem prevMember = firstMember.getPrev();
prevMember.setNext(newMember);
firstMember.setPrev(newMember);
newMember.setPrev(prevMember);
newMember.setNext(firstMember);
}
}
public void deleteListItems() throws CoreException {
ListItem item = getFirstMemberItem();
if (item != null) {
long firstRec= item.record;
do {
ListItem nextItem= item.getNext();
item.delete();
item= nextItem;
}
while (item.record != firstRec && item.record != 0);
}
}
}