/*******************************************************************************
* Copyright (c) 2008, 2010 Wind River Systems, 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:
* Markus Schorn - initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.internal.core.pdom.dom.cpp;
import org.eclipse.cdt.core.dom.ast.ISemanticProblem;
import org.eclipse.cdt.core.dom.ast.IType;
import org.eclipse.cdt.core.dom.ast.IValue;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateArgument;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateParameterMap;
import org.eclipse.cdt.internal.core.dom.parser.ProblemType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPTemplateArgument;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPTemplateParameterMap;
import org.eclipse.cdt.internal.core.pdom.db.Database;
import org.eclipse.cdt.internal.core.pdom.dom.PDOMLinkage;
import org.eclipse.cdt.internal.core.pdom.dom.PDOMNode;
import org.eclipse.core.runtime.CoreException;
/**
* Collects methods to store an argument list in the database
*/
public class PDOMCPPTemplateParameterMap {
private static final int TYPE_OFFSET= 0;
private static final int VALUE_OFFSET= TYPE_OFFSET + Database.TYPE_SIZE;
private static final int NODE_SIZE = VALUE_OFFSET + Database.VALUE_SIZE;
/**
* Stores the given template parameter map in the database.
* @return the record by which the arguments can be referenced.
*/
public static long putMap(PDOMNode parent, ICPPTemplateParameterMap map) throws CoreException {
final PDOMLinkage linkage= parent.getLinkage();
final Database db= linkage.getDB();
Integer[] keys= map.getAllParameterPositions();
int keyLen= 0;
int dataSize= 2;
for (Integer key : keys) {
int delta= 2+4+NODE_SIZE;
ICPPTemplateArgument[] packExpansion= map.getPackExpansion(key);
if (packExpansion != null) {
delta+= (packExpansion.length-1) * NODE_SIZE;
}
if (dataSize+delta > Database.MAX_MALLOC_SIZE)
break;
dataSize += delta;
keyLen++;
}
final long block= db.malloc(dataSize);
long p= block;
db.putShort(p, (short)keyLen); p+=2;
for (final Integer paramId : keys) {
if (--keyLen < 0)
break;
db.putInt(p, paramId); p+=4;
final ICPPTemplateArgument arg = map.getArgument(paramId);
if (arg != null) {
db.putShort(p, (short) -1); p+=2;
storeArgument(db, linkage, p, arg); p+= NODE_SIZE;
} else {
final ICPPTemplateArgument[] args = map.getPackExpansion(paramId);
db.putShort(p, (short) args.length); p+=2;
for (ICPPTemplateArgument a : args) {
storeArgument(db, linkage, p, a); p+= NODE_SIZE;
}
}
}
assert p == block+dataSize;
return block;
}
private static void storeArgument(final Database db, final PDOMLinkage linkage, long p,
final ICPPTemplateArgument arg) throws CoreException {
if (arg.isNonTypeValue()) {
linkage.storeType(p + TYPE_OFFSET, arg.getTypeOfNonTypeValue());
linkage.storeValue(p + VALUE_OFFSET, arg.getNonTypeValue());
} else {
linkage.storeType(p + TYPE_OFFSET, arg.getTypeValue());
}
}
/**
* Clears the map in the database.
*/
public static void clearMap(PDOMNode parent, final int record) throws CoreException {
final PDOMLinkage linkage= parent.getLinkage();
final Database db= linkage.getDB();
long p= record;
final short len= db.getShort(p); p+= 2;
for (int i=0; i<len; i++) {
p+= 4; // parameter id
short packSize= db.getShort(p); p+= 2;
if (packSize == -1)
packSize= 1;
for (int j = 0; j < packSize; j++) {
linkage.storeType(p+TYPE_OFFSET, null);
linkage.storeValue(p+VALUE_OFFSET, null);
p+= NODE_SIZE;
}
}
db.free(record);
}
/**
* Restores the map from from the database.
*/
public static CPPTemplateParameterMap getMap(PDOMNode parent, long rec) throws CoreException {
final PDOMLinkage linkage= parent.getLinkage();
final Database db= linkage.getDB();
final short len= db.getShort(rec);
if (len == 0) {
return CPPTemplateParameterMap.EMPTY;
}
rec+=2;
CPPTemplateParameterMap result= new CPPTemplateParameterMap(len);
for (int i=0; i<len; i++) {
final int parPos= db.getInt(rec); rec+= 4;
short packSize= db.getShort(rec); rec+= 2;
if (packSize == -1) {
ICPPTemplateArgument arg = readArgument(rec, linkage, db); rec+= NODE_SIZE;
result.put(parPos, arg);
} else {
ICPPTemplateArgument[] packExpansion= new ICPPTemplateArgument[packSize];
for (int j = 0; j < packExpansion.length; j++) {
packExpansion[j]= readArgument(rec, linkage, db); rec+= NODE_SIZE;
}
result.put(parPos, packExpansion);
}
}
return result;
}
private static ICPPTemplateArgument readArgument(long rec, final PDOMLinkage linkage, final Database db)
throws CoreException {
IType type= linkage.loadType(rec + TYPE_OFFSET);
if (type == null) {
type= new ProblemType(ISemanticProblem.TYPE_NOT_PERSISTED);
}
IValue val= linkage.loadValue(rec + VALUE_OFFSET);
ICPPTemplateArgument arg;
if (val != null) {
arg= new CPPTemplateArgument(val, type);
} else {
arg= new CPPTemplateArgument(type);
}
return arg;
}
}