/*
* Copyright (c) 2007 BUSINESS OBJECTS SOFTWARE LIMITED
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of Business Objects nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* ModuleSourceMetrics.java
* Creation date: (Apr 14, 2005)
* By: Jawright
*/
package org.openquark.cal.compiler;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.openquark.cal.internal.serialization.ModuleSerializationTags;
import org.openquark.cal.internal.serialization.RecordInputStream;
import org.openquark.cal.internal.serialization.RecordOutputStream;
import org.openquark.cal.internal.serialization.RecordInputStream.RecordHeaderInfo;
/**
* This class contains source metrics associated with a single module. It
* aggregates the raw metric data stored in the FunctionEntities of a module.
*
* Currently, only statistics that "occur" in the module are recorded; those that
* occur in visible modules are not. So, for example, the reference frequency of
* Prelude.add in module Foo refers only to the number of times gems in Foo refer to
* Prelude.add; references in module Bar are not included, even if Foo includes Bar.
*
* Creation date: (Apr 14, 2005)
* @author Jawright
*/
class ModuleSourceMetrics {
// Serialization schema for use with record stream serialization.
private static final int serializationSchema = 0;
/** The ModuleTypeInfo object describing the module that this object holds metrics for */
private ModuleTypeInfo moduleTypeInfo;
/**
* Map from QualifiedName of a gem K (visible from the current module) to the number
* of references to K that occur within functions defined in the current module.
*/
private final Map<QualifiedName, Integer> gemToLocalReferenceFrequencyMap = new HashMap<QualifiedName, Integer>();
/**
* Construct a ModuleSourceMetrics object for the module represented
* by moduleTypeInfo.
* NOTE: This constructor assumes that the module and its imports have already been
* successfully compiled.
* @param moduleTypeInfo ModuleTypeInfo for a module to compute
*/
ModuleSourceMetrics(ModuleTypeInfo moduleTypeInfo) {
if (moduleTypeInfo == null) {
throw new NullPointerException("moduleTypeInfo must not be null in ModuleSourceMetrics constructor");
}
this.moduleTypeInfo = moduleTypeInfo;
computeLocalReferenceMetrics();
}
/**
* Parameterless construction for the static load method
*
*/
private ModuleSourceMetrics() {
}
/**
* Use the raw data contained in the EnvEntities of the current module to
* fill gemToLocalReferenceFrequencyMap.
*/
private void computeLocalReferenceMetrics() {
int numFunctions = moduleTypeInfo.getNFunctions();
for (int i = 0; i < numFunctions; i++) {
Map<QualifiedName, Integer> dependeeToFrequencyMap = moduleTypeInfo.getNthFunction(i).getDependeeToFrequencyMap();
for (final Map.Entry<QualifiedName, Integer> entry : dependeeToFrequencyMap.entrySet()) {
QualifiedName dependeeName = entry.getKey();
Integer newCount = entry.getValue();
Integer existingCount = gemToLocalReferenceFrequencyMap.get(dependeeName);
if (existingCount != null) {
gemToLocalReferenceFrequencyMap.put(dependeeName, Integer.valueOf(existingCount.intValue() + newCount.intValue()));
} else {
gemToLocalReferenceFrequencyMap.put(dependeeName, newCount);
}
}
}
}
/**
* @return Map from the name of a visible gem to the number
* of times that it is referenced in the body of some function in this module.
*/
Map<QualifiedName, Integer> getGemToLocalReferenceFrequencyMap() {
return Collections.unmodifiableMap(gemToLocalReferenceFrequencyMap);
}
void write(RecordOutputStream s) throws IOException {
s.startRecord(ModuleSerializationTags.MODULE_SOURCE_METRICS, serializationSchema);
s.writeInt(gemToLocalReferenceFrequencyMap.size());
for (final QualifiedName key : gemToLocalReferenceFrequencyMap.keySet()) {
Integer frequency = gemToLocalReferenceFrequencyMap.get(key);
s.writeQualifiedName(key);
s.writeInt(frequency.intValue());
}
s.endRecord();
}
static ModuleSourceMetrics load(RecordInputStream s, ModuleTypeInfo moduleTypeInfo, CompilerMessageLogger msgLogger) throws IOException {
// Look for Record header.
RecordHeaderInfo rhi = s.findRecord(ModuleSerializationTags.MODULE_SOURCE_METRICS);
if(rhi == null) {
throw new IOException("Unable to find ForeignFunctionInfo record header.");
}
DeserializationHelper.checkSerializationSchema(rhi.getSchema(), serializationSchema, moduleTypeInfo.getModuleName(), "ModuleSourceMetrics", msgLogger);
ModuleSourceMetrics metrics = new ModuleSourceMetrics();
// moduleTypeInfo
metrics.moduleTypeInfo = moduleTypeInfo;
// gemToLocalReferenceFrequencyMap
int numReferenceFrequencyEntries = s.readInt();
for (int i = 0; i < numReferenceFrequencyEntries; i++) {
QualifiedName key = s.readQualifiedName();
Integer frequency = Integer.valueOf(s.readInt());
metrics.gemToLocalReferenceFrequencyMap.put(key, frequency);
}
s.skipRestOfRecord();
return metrics;
}
}