/*
* Copyright (c) 2013 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
*/
package org.eclipse.cdt.internal.qt.core.pdom;
import org.eclipse.cdt.internal.core.pdom.db.Database;
import org.eclipse.core.runtime.CoreException;
/**
* A utility class for storing a fixed-size list of fixed-size elements into the Database.
*/
@SuppressWarnings("restriction")
public class QtPDOMArray<T> {
private static int offsetInitializer = 0;
protected static enum Field {
Count(Database.INT_SIZE),
Data(0); // The size of the block is provided at runtime.
public final int offset;
private Field(int sizeof) {
this.offset = offsetInitializer;
offsetInitializer += sizeof;
}
public long getRecord(long baseRec) {
return baseRec + offset;
}
}
private final QtPDOMLinkage linkage;
private final IQtPDOMCodec<T> codec;
private long record;
public QtPDOMArray(QtPDOMLinkage linkage, IQtPDOMCodec<T> codec, long record) {
this.linkage = linkage;
this.codec = codec;
this.record = record;
}
public QtPDOMArray(QtPDOMLinkage linkage, IQtPDOMCodec<T> codec, T[] array) throws CoreException {
this.linkage = linkage;
this.codec = codec;
this.record = 0;
set(array);
}
public long getRecord() {
return record;
}
/**
* Return array that is stored in the database. Return null if the receiver is not initialized.
*/
public T[] get() throws CoreException {
if (record == 0)
return null;
int count = linkage.getDB().getInt(Field.Count.getRecord(record));
long elementRec = Field.Data.getRecord(record);
T[] array = codec.allocArray(count);
for(int i = 0; i < count; ++i, elementRec += codec.getElementSize())
array[i] = codec.decode(linkage, elementRec);
return array;
}
/**
* Store the given array into the database. This may change the storage location of the
* receiver.
* @param array The array of elements that should be stored. Setting the value to null is
* equivalent to calling {@link #delete()}, which clears all storage.
*/
public long set(T[] array) throws CoreException {
if (array == null)
return delete();
// Initialize the receiver if needed.
if (record == 0) {
record = linkage.getDB().malloc(Field.Data.offset + (array.length * codec.getElementSize()));
linkage.getDB().putInt(Field.Count.getRecord(record), array.length);
} else {
// Check if the storage block needs to be resized.
int count = linkage.getDB().getInt(Field.Count.getRecord(record));
if (count != array.length) {
linkage.getDB().free(record);
record = linkage.getDB().malloc(Field.Data.offset + (array.length * codec.getElementSize()));
linkage.getDB().putInt(Field.Count.getRecord(record), array.length);
}
}
// Write the new content into the database.
long elementRec = Field.Data.getRecord(record);
for(int i = 0; i < array.length; ++i, elementRec += codec.getElementSize())
codec.encode(linkage, elementRec, array[i]);
return record;
}
/**
* Release all storage used by the receiver and its elements.
*/
public long delete() throws CoreException {
// If the receiver is already empty, then there is nothing else to do.
if (record == 0)
return record;
// Otherwise get the size of the stored array and delete each element.
int count = linkage.getDB().getInt(Field.Count.getRecord(record));
if (count > 0) {
long elementRec = Field.Data.getRecord(record);
for(int i = 0; i < count; ++i, elementRec += codec.getElementSize())
codec.encode(linkage, elementRec, null);
}
// Finally, release the entire record.
linkage.getDB().free(record);
record = 0;
return record;
}
}