diff --git a/src/main/java/de/unijena/cheminf/mortar/controller/FragmentationSettingsViewController.java b/src/main/java/de/unijena/cheminf/mortar/controller/FragmentationSettingsViewController.java index cc72f1f1..b77975f5 100644 --- a/src/main/java/de/unijena/cheminf/mortar/controller/FragmentationSettingsViewController.java +++ b/src/main/java/de/unijena/cheminf/mortar/controller/FragmentationSettingsViewController.java @@ -24,6 +24,7 @@ import de.unijena.cheminf.mortar.gui.views.SettingsView; import de.unijena.cheminf.mortar.message.Message; import de.unijena.cheminf.mortar.model.fragmentation.algorithm.IMoleculeFragmenter; +import de.unijena.cheminf.mortar.model.util.CollectionUtil; import javafx.beans.property.Property; import javafx.scene.Scene; import javafx.scene.control.Tab; @@ -85,7 +86,7 @@ public class FragmentationSettingsViewController { */ public FragmentationSettingsViewController(Stage aStage, IMoleculeFragmenter[] anArrayOfFragmenters, String aSelectedFragmenterAlgorithmName){ this.mainStage = aStage; - this.recentProperties = new HashMap<>(anArrayOfFragmenters.length); + this.recentProperties = new HashMap<>(CollectionUtil.calculateInitialHashCollectionCapacity(anArrayOfFragmenters.length)); this.fragmenters = anArrayOfFragmenters; this.selectedFragmenterName = aSelectedFragmenterAlgorithmName; this.openFragmentationSettingsView(); @@ -111,7 +112,7 @@ private void openFragmentationSettingsView(){ // this.addListener(); for (IMoleculeFragmenter tmpFragmenter : this.fragmenters) { - HashMap tmpRecentProperties = new HashMap<>(tmpFragmenter.settingsProperties().size()); + HashMap tmpRecentProperties = new HashMap<>(CollectionUtil.calculateInitialHashCollectionCapacity(tmpFragmenter.settingsProperties().size())); this.recentProperties.put(tmpFragmenter.getFragmentationAlgorithmName(), tmpRecentProperties); Tab tmpTab = this.settingsView.addTab(this.fragmentationSettingsViewStage, tmpFragmenter.getFragmentationAlgorithmName(), tmpFragmenter.settingsProperties(), diff --git a/src/main/java/de/unijena/cheminf/mortar/controller/HistogramViewController.java b/src/main/java/de/unijena/cheminf/mortar/controller/HistogramViewController.java index 977ae1d6..b0307d37 100644 --- a/src/main/java/de/unijena/cheminf/mortar/controller/HistogramViewController.java +++ b/src/main/java/de/unijena/cheminf/mortar/controller/HistogramViewController.java @@ -27,7 +27,7 @@ import de.unijena.cheminf.mortar.model.data.FragmentDataModel; import de.unijena.cheminf.mortar.model.data.MoleculeDataModel; import de.unijena.cheminf.mortar.model.depict.DepictionUtil; -import de.unijena.cheminf.mortar.model.util.ListUtil; +import de.unijena.cheminf.mortar.model.util.CollectionUtil; import javafx.beans.binding.Bindings; import javafx.beans.value.ObservableValue; @@ -269,7 +269,7 @@ private BarChart createHistogram(int aFragmentNumber, HistogramView aHistogramVi ArrayList tmpFullSmilesLength = new ArrayList<>(); String tmpSelectedData = (String) aHistogramView.getChooseDataComoBox().getValue(); if (tmpSelectedData.equals(Message.get("HistogramView.chooseDataComboBoxFragmentFrequency.text"))) { - ListUtil.sortGivenFragmentListByPropertyAndSortType(this.copyList, "absoluteFrequency", "ASCENDING"); + CollectionUtil.sortGivenFragmentListByPropertyAndSortType(this.copyList, "absoluteFrequency", "ASCENDING"); for (MoleculeDataModel tmpMoleculeData : this.copyList) { tmpFragmentData = (FragmentDataModel) tmpMoleculeData; if (tmpFragmentData.getUniqueSmiles().length() > aSmilesLength) { @@ -284,7 +284,7 @@ private BarChart createHistogram(int aFragmentNumber, HistogramView aHistogramVi tmpFrequencyList.add(tmpFragmentData.getAbsoluteFrequency()); } } else { - ListUtil.sortGivenFragmentListByPropertyAndSortType(this.copyList, "moleculeFrequency", "ASCENDING"); + CollectionUtil.sortGivenFragmentListByPropertyAndSortType(this.copyList, "moleculeFrequency", "ASCENDING"); for (MoleculeDataModel tmpMoleculeData : this.copyList) { tmpFragmentData = (FragmentDataModel) tmpMoleculeData; if (tmpFragmentData.getUniqueSmiles().length() > aSmilesLength) { diff --git a/src/main/java/de/unijena/cheminf/mortar/controller/MainViewController.java b/src/main/java/de/unijena/cheminf/mortar/controller/MainViewController.java index d5d888a2..c16dec3b 100644 --- a/src/main/java/de/unijena/cheminf/mortar/controller/MainViewController.java +++ b/src/main/java/de/unijena/cheminf/mortar/controller/MainViewController.java @@ -40,6 +40,7 @@ import de.unijena.cheminf.mortar.model.settings.SettingsContainer; import de.unijena.cheminf.mortar.model.util.BasicDefinitions; import de.unijena.cheminf.mortar.model.util.ChemUtil; +import de.unijena.cheminf.mortar.model.util.CollectionUtil; import de.unijena.cheminf.mortar.model.util.FileUtil; import de.unijena.cheminf.mortar.model.util.LogUtil; import javafx.application.Platform; @@ -239,7 +240,7 @@ public MainViewController(Stage aStage, MainView aMainView, String anAppDir) { // this.isImportRunningProperty = new SimpleBooleanProperty(false); this.isExportRunningProperty = new SimpleBooleanProperty(false); - this.mapOfFragmentDataModelLists = new HashMap<>(5); + this.mapOfFragmentDataModelLists = new HashMap<>(CollectionUtil.calculateInitialHashCollectionCapacity(5)); this.threadList = new CopyOnWriteArrayList(); this.addListener(); this.addFragmentationAlgorithmCheckMenuItems(); diff --git a/src/main/java/de/unijena/cheminf/mortar/controller/SettingsViewController.java b/src/main/java/de/unijena/cheminf/mortar/controller/SettingsViewController.java index ebeb9476..42993976 100644 --- a/src/main/java/de/unijena/cheminf/mortar/controller/SettingsViewController.java +++ b/src/main/java/de/unijena/cheminf/mortar/controller/SettingsViewController.java @@ -24,6 +24,7 @@ import de.unijena.cheminf.mortar.gui.views.SettingsView; import de.unijena.cheminf.mortar.message.Message; import de.unijena.cheminf.mortar.model.settings.SettingsContainer; +import de.unijena.cheminf.mortar.model.util.CollectionUtil; import javafx.application.Platform; import javafx.beans.property.Property; import javafx.scene.Scene; @@ -86,7 +87,7 @@ public SettingsViewController(Stage aStage, SettingsContainer aSettingsContainer this.mainStage = aStage; this.settingsContainer = aSettingsContainer; this.recentSettingsContainer = aSettingsContainer; - this.recentProperties = new HashMap<>(this.settingsContainer.settingsProperties().size()); + this.recentProperties = new HashMap<>(CollectionUtil.calculateInitialHashCollectionCapacity(this.settingsContainer.settingsProperties().size())); this.showSettingsView(); } // diff --git a/src/main/java/de/unijena/cheminf/mortar/gui/util/GuiUtil.java b/src/main/java/de/unijena/cheminf/mortar/gui/util/GuiUtil.java index 03af91b7..de0c6298 100644 --- a/src/main/java/de/unijena/cheminf/mortar/gui/util/GuiUtil.java +++ b/src/main/java/de/unijena/cheminf/mortar/gui/util/GuiUtil.java @@ -28,7 +28,7 @@ import de.unijena.cheminf.mortar.model.data.MoleculeDataModel; import de.unijena.cheminf.mortar.model.depict.DepictionUtil; import de.unijena.cheminf.mortar.model.settings.SettingsContainer; -import de.unijena.cheminf.mortar.model.util.ListUtil; +import de.unijena.cheminf.mortar.model.util.CollectionUtil; import javafx.scene.control.Alert; import javafx.scene.control.Button; import javafx.scene.control.ButtonType; @@ -212,7 +212,7 @@ public static void sortTableViewGlobally(SortEvent anEvent, Paginatio return; String tmpSortProp = ((PropertyValueFactory)((TableColumn) anEvent.getSource().getSortOrder().get(0)).cellValueFactoryProperty().getValue()).getProperty().toString(); TableColumn.SortType tmpSortType = ((TableColumn) anEvent.getSource().getSortOrder().get(0)).getSortType(); - ListUtil.sortGivenFragmentListByPropertyAndSortType(((IDataTableView)anEvent.getSource()).getItemsList(), tmpSortProp, tmpSortType.toString()); + CollectionUtil.sortGivenFragmentListByPropertyAndSortType(((IDataTableView)anEvent.getSource()).getItemsList(), tmpSortProp, tmpSortType.toString()); int fromIndex = tmpPagination.getCurrentPageIndex() * tmpRowsPerPage; int toIndex = Math.min(fromIndex + tmpRowsPerPage, ((IDataTableView)anEvent.getSource()).getItemsList().size()); anEvent.getSource().getItems().clear(); diff --git a/src/main/java/de/unijena/cheminf/mortar/model/fragmentation/FragmentationService.java b/src/main/java/de/unijena/cheminf/mortar/model/fragmentation/FragmentationService.java index 41742977..d39d8225 100644 --- a/src/main/java/de/unijena/cheminf/mortar/model/fragmentation/FragmentationService.java +++ b/src/main/java/de/unijena/cheminf/mortar/model/fragmentation/FragmentationService.java @@ -31,6 +31,7 @@ import de.unijena.cheminf.mortar.model.settings.SettingsContainer; import de.unijena.cheminf.mortar.model.util.BasicDefinitions; import de.unijena.cheminf.mortar.model.util.ChemUtil; +import de.unijena.cheminf.mortar.model.util.CollectionUtil; import de.unijena.cheminf.mortar.model.util.FileUtil; import de.unijena.cheminf.mortar.model.util.SimpleEnumConstantNameProperty; import de.unijena.cheminf.mortar.preference.BooleanPreference; @@ -1063,23 +1064,26 @@ private void updatePropertiesFromPreferences(List aPropertiesList, Pre * anything does not meet the requirements. */ private void checkFragmenters() throws Exception { - HashSet tmpAlgorithmNames = new HashSet<>(this.fragmenters.length + 6, 1.0f); + int tmpAlgorithmNamesSetInitCapacity = CollectionUtil.calculateInitialHashCollectionCapacity(this.fragmenters.length, + BasicDefinitions.DEFAULT_HASH_COLLECTION_LOAD_FACTOR); + HashSet tmpAlgorithmNamesSet = new HashSet<>(tmpAlgorithmNamesSetInitCapacity, BasicDefinitions.DEFAULT_HASH_COLLECTION_LOAD_FACTOR); for (IMoleculeFragmenter tmpFragmenter : this.fragmenters) { //algorithm name should be singleton and must be persistable String tmpAlgName = tmpFragmenter.getFragmentationAlgorithmName(); if (!PreferenceUtil.isValidName(tmpAlgName) || !SingleTermPreference.isValidContent(tmpAlgName)) { throw new Exception("Algorithm name " + tmpAlgName + " is invalid."); } - if (tmpAlgorithmNames.contains(tmpAlgName)) { + if (tmpAlgorithmNamesSet.contains(tmpAlgName)) { throw new Exception("Algorithm name " + tmpAlgName + " is used multiple times."); } else { - tmpAlgorithmNames.add(tmpAlgName); + tmpAlgorithmNamesSet.add(tmpAlgName); } //setting names must be singletons within the respective class //setting names and values must adhere to the preference input restrictions //setting values are only tested for their current state, not the entire possible input space! It is tested again at persistence List tmpSettingsList = tmpFragmenter.settingsProperties(); - HashSet tmpSettingNames = new HashSet<>(tmpSettingsList.size() + 6, 1.0f); + int tmpSettingNamesSetInitCapacity = CollectionUtil.calculateInitialHashCollectionCapacity(tmpSettingsList.size(), BasicDefinitions.DEFAULT_HASH_COLLECTION_LOAD_FACTOR); + HashSet tmpSettingNames = new HashSet<>(tmpSettingNamesSetInitCapacity, BasicDefinitions.DEFAULT_HASH_COLLECTION_LOAD_FACTOR); for (Property tmpSetting : tmpSettingsList) { if (!PreferenceUtil.isValidName(tmpSetting.getName())) { throw new Exception("Setting " + tmpSetting.getName() + " has an invalid name."); diff --git a/src/main/java/de/unijena/cheminf/mortar/model/fragmentation/FragmentationTask.java b/src/main/java/de/unijena/cheminf/mortar/model/fragmentation/FragmentationTask.java index cfefc5c2..d2931ab0 100644 --- a/src/main/java/de/unijena/cheminf/mortar/model/fragmentation/FragmentationTask.java +++ b/src/main/java/de/unijena/cheminf/mortar/model/fragmentation/FragmentationTask.java @@ -24,6 +24,7 @@ import de.unijena.cheminf.mortar.model.data.MoleculeDataModel; import de.unijena.cheminf.mortar.model.fragmentation.algorithm.IMoleculeFragmenter; import de.unijena.cheminf.mortar.model.util.ChemUtil; +import de.unijena.cheminf.mortar.model.util.CollectionUtil; import org.openscience.cdk.exception.CDKException; import org.openscience.cdk.interfaces.IAtomContainer; @@ -134,7 +135,7 @@ public Integer call() throws Exception{ continue; } List tmpFragmentsOfMolList = new ArrayList<>(tmpFragmentsList.size()); - HashMap tmpFragmentFrequenciesOfMoleculeMap = new HashMap<>(tmpFragmentsList.size()); + HashMap tmpFragmentFrequenciesOfMoleculeMap = new HashMap<>(CollectionUtil.calculateInitialHashCollectionCapacity(tmpFragmentsList.size())); for(IAtomContainer tmpFragment : tmpFragmentsList){ String tmpSmiles = ChemUtil.createUniqueSmiles(tmpFragment); if (tmpSmiles == null) { diff --git a/src/main/java/de/unijena/cheminf/mortar/model/fragmentation/algorithm/ErtlFunctionalGroupsFinderFragmenter.java b/src/main/java/de/unijena/cheminf/mortar/model/fragmentation/algorithm/ErtlFunctionalGroupsFinderFragmenter.java index c788e4e3..42089423 100644 --- a/src/main/java/de/unijena/cheminf/mortar/model/fragmentation/algorithm/ErtlFunctionalGroupsFinderFragmenter.java +++ b/src/main/java/de/unijena/cheminf/mortar/model/fragmentation/algorithm/ErtlFunctionalGroupsFinderFragmenter.java @@ -28,7 +28,9 @@ import de.unijena.cheminf.mortar.gui.util.GuiUtil; import de.unijena.cheminf.mortar.message.Message; import de.unijena.cheminf.mortar.model.io.Importer; +import de.unijena.cheminf.mortar.model.util.BasicDefinitions; import de.unijena.cheminf.mortar.model.util.ChemUtil; +import de.unijena.cheminf.mortar.model.util.CollectionUtil; import de.unijena.cheminf.mortar.model.util.SimpleEnumConstantNameProperty; import javafx.beans.property.Property; import javafx.beans.property.SimpleBooleanProperty; @@ -338,7 +340,11 @@ public static enum CycleFinderOption { * Constructor, all settings are initialised with their default values as declared in the respective public constants. */ public ErtlFunctionalGroupsFinderFragmenter() { - this.settingNameTooltipTextMap = new HashMap(10, 0.9f); + int tmpNumberOfSettingsForTooltipMapSize= 6; + int tmpInitialCapacityForSettingNameTooltipTextMap = CollectionUtil.calculateInitialHashCollectionCapacity( + tmpNumberOfSettingsForTooltipMapSize, + BasicDefinitions.DEFAULT_HASH_COLLECTION_LOAD_FACTOR); + this.settingNameTooltipTextMap = new HashMap(tmpInitialCapacityForSettingNameTooltipTextMap, BasicDefinitions.DEFAULT_HASH_COLLECTION_LOAD_FACTOR); this.fragmentSaturationSetting = new SimpleEnumConstantNameProperty(this, "Fragment saturation setting", IMoleculeFragmenter.FRAGMENT_SATURATION_OPTION_DEFAULT.name(), IMoleculeFragmenter.FragmentSaturationOption.class) { @Override @@ -805,7 +811,8 @@ public List fragmentMolecule(IAtomContainer aMolecule) this.logger.log(Level.WARNING, anException.toString(), anException); throw new IllegalArgumentException("Unexpected error at aromaticity detection: " + anException.toString()); } - HashMap tmpIdToAtomMap = new HashMap<>(tmpMoleculeClone.getAtomCount() + 1, 1); + int tmpInitialCapacityForIdToAtomMap = CollectionUtil.calculateInitialHashCollectionCapacity(tmpMoleculeClone.getAtomCount(), BasicDefinitions.DEFAULT_HASH_COLLECTION_LOAD_FACTOR); + HashMap tmpIdToAtomMap = new HashMap<>(tmpInitialCapacityForIdToAtomMap, BasicDefinitions.DEFAULT_HASH_COLLECTION_LOAD_FACTOR); for (int i = 0; i < tmpMoleculeClone.getAtomCount(); i++) { IAtom tmpAtom = tmpMoleculeClone.getAtom(i); tmpAtom.setProperty(ErtlFunctionalGroupsFinderFragmenter.INTERNAL_INDEX_PROPERTY_KEY, i); diff --git a/src/main/java/de/unijena/cheminf/mortar/model/fragmentation/algorithm/ScaffoldGeneratorFragmenter.java b/src/main/java/de/unijena/cheminf/mortar/model/fragmentation/algorithm/ScaffoldGeneratorFragmenter.java index 7c27b07a..cf9362ae 100644 --- a/src/main/java/de/unijena/cheminf/mortar/model/fragmentation/algorithm/ScaffoldGeneratorFragmenter.java +++ b/src/main/java/de/unijena/cheminf/mortar/model/fragmentation/algorithm/ScaffoldGeneratorFragmenter.java @@ -22,6 +22,8 @@ import de.unijena.cheminf.mortar.gui.util.GuiUtil; import de.unijena.cheminf.mortar.message.Message; +import de.unijena.cheminf.mortar.model.util.BasicDefinitions; +import de.unijena.cheminf.mortar.model.util.CollectionUtil; import de.unijena.cheminf.mortar.model.util.SimpleEnumConstantNameProperty; import de.unijena.cheminf.scaffoldGenerator.ScaffoldGenerator; import javafx.beans.property.Property; @@ -340,7 +342,11 @@ public static enum FragmentationTypeOption { */ public ScaffoldGeneratorFragmenter() { this.scaffoldGeneratorInstance = new ScaffoldGenerator(); - this.settingNameTooltipTextMap = new HashMap(16, 0.9f); + int tmpNumberOfSettingsForTooltipMapSize= 10; + int tmpInitialCapacityForSettingNameTooltipTextMap = CollectionUtil.calculateInitialHashCollectionCapacity( + tmpNumberOfSettingsForTooltipMapSize, + BasicDefinitions.DEFAULT_HASH_COLLECTION_LOAD_FACTOR); + this.settingNameTooltipTextMap = new HashMap(tmpInitialCapacityForSettingNameTooltipTextMap, BasicDefinitions.DEFAULT_HASH_COLLECTION_LOAD_FACTOR); this.fragmentSaturationSetting = new SimpleEnumConstantNameProperty(this, "Fragment saturation setting", IMoleculeFragmenter.FRAGMENT_SATURATION_OPTION_DEFAULT.name(), IMoleculeFragmenter.FragmentSaturationOption.class) { @Override diff --git a/src/main/java/de/unijena/cheminf/mortar/model/fragmentation/algorithm/SugarRemovalUtilityFragmenter.java b/src/main/java/de/unijena/cheminf/mortar/model/fragmentation/algorithm/SugarRemovalUtilityFragmenter.java index 98f040dd..22c2fbef 100644 --- a/src/main/java/de/unijena/cheminf/mortar/model/fragmentation/algorithm/SugarRemovalUtilityFragmenter.java +++ b/src/main/java/de/unijena/cheminf/mortar/model/fragmentation/algorithm/SugarRemovalUtilityFragmenter.java @@ -28,7 +28,9 @@ import de.unijena.cheminf.deglycosylation.SugarRemovalUtility; import de.unijena.cheminf.mortar.gui.util.GuiUtil; import de.unijena.cheminf.mortar.message.Message; +import de.unijena.cheminf.mortar.model.util.BasicDefinitions; import de.unijena.cheminf.mortar.model.util.ChemUtil; +import de.unijena.cheminf.mortar.model.util.CollectionUtil; import de.unijena.cheminf.mortar.model.util.SimpleEnumConstantNameProperty; import javafx.beans.property.Property; import javafx.beans.property.SimpleBooleanProperty; @@ -234,8 +236,12 @@ public static enum SRUFragmenterReturnedFragmentsOption { */ public SugarRemovalUtilityFragmenter() { this.sugarRUInstance = new SugarRemovalUtility(SilentChemObjectBuilder.getInstance()); - this.settings = new ArrayList<>(15); - this.settingNameTooltipTextMap = new HashMap<>(20, 0.9f); + int tmpNumberOfSettings = 15; + this.settings = new ArrayList<>(tmpNumberOfSettings); + int tmpInitialCapacityForSettingNameTooltipTextMap = CollectionUtil.calculateInitialHashCollectionCapacity( + tmpNumberOfSettings, + BasicDefinitions.DEFAULT_HASH_COLLECTION_LOAD_FACTOR); + this.settingNameTooltipTextMap = new HashMap<>(tmpInitialCapacityForSettingNameTooltipTextMap, BasicDefinitions.DEFAULT_HASH_COLLECTION_LOAD_FACTOR); this.returnedFragmentsSetting = new SimpleEnumConstantNameProperty(this, "Returned fragments setting", SugarRemovalUtilityFragmenter.RETURNED_FRAGMENTS_OPTION_DEFAULT.name(), SugarRemovalUtilityFragmenter.SRUFragmenterReturnedFragmentsOption.class) { @Override diff --git a/src/main/java/de/unijena/cheminf/mortar/model/settings/SettingsContainer.java b/src/main/java/de/unijena/cheminf/mortar/model/settings/SettingsContainer.java index edb17b31..6addcbb2 100644 --- a/src/main/java/de/unijena/cheminf/mortar/model/settings/SettingsContainer.java +++ b/src/main/java/de/unijena/cheminf/mortar/model/settings/SettingsContainer.java @@ -28,6 +28,7 @@ import de.unijena.cheminf.mortar.gui.util.GuiUtil; import de.unijena.cheminf.mortar.message.Message; import de.unijena.cheminf.mortar.model.util.BasicDefinitions; +import de.unijena.cheminf.mortar.model.util.CollectionUtil; import de.unijena.cheminf.mortar.model.util.FileUtil; import de.unijena.cheminf.mortar.model.util.SimpleEnumConstantNameProperty; import de.unijena.cheminf.mortar.preference.BooleanPreference; @@ -609,7 +610,11 @@ public void reloadGlobalSettings() { * to the list of settings for display to the user. */ private void initialiseSettings() { - this.settingNameTooltipTextMap = new HashMap(10, 0.9f); + int tmpNumberOfSettings = 8; + int tmpInitialCapacityForSettingNameTooltipTextMap = CollectionUtil.calculateInitialHashCollectionCapacity( + tmpNumberOfSettings, + BasicDefinitions.DEFAULT_HASH_COLLECTION_LOAD_FACTOR); + this.settingNameTooltipTextMap = new HashMap(tmpInitialCapacityForSettingNameTooltipTextMap, BasicDefinitions.DEFAULT_HASH_COLLECTION_LOAD_FACTOR); this.rowsPerPageSetting = new SimpleIntegerProperty(this, "Rows per page setting", SettingsContainer.ROWS_PER_PAGE_SETTING_DEFAULT) { @@ -752,15 +757,16 @@ private void checkSettings() throws Exception { //setting names and values must adhere to the preference input restrictions //setting values are only tested for their current state, not the entire possible input space! It is tested again at persistence List tmpSettingsList = this.settings; - HashSet tmpSettingNames = new HashSet<>(tmpSettingsList.size() + 6, 1.0f); + int tmpSettingNamesSetInitCapacity = CollectionUtil.calculateInitialHashCollectionCapacity(tmpSettingsList.size(), BasicDefinitions.DEFAULT_HASH_COLLECTION_LOAD_FACTOR); + HashSet tmpSettingNamesSet = new HashSet<>(tmpSettingNamesSetInitCapacity, BasicDefinitions.DEFAULT_HASH_COLLECTION_LOAD_FACTOR); for (Property tmpSetting : tmpSettingsList) { if (!PreferenceUtil.isValidName(tmpSetting.getName())) { throw new Exception("Setting " + tmpSetting.getName() + " has an invalid name."); } - if (tmpSettingNames.contains(tmpSetting.getName())) { + if (tmpSettingNamesSet.contains(tmpSetting.getName())) { throw new Exception("Setting name " + tmpSetting.getName() + " is used multiple times."); } else { - tmpSettingNames.add(tmpSetting.getName()); + tmpSettingNamesSet.add(tmpSetting.getName()); } if (tmpSetting instanceof SimpleBooleanProperty) { //nothing to do here, booleans cannot have invalid values diff --git a/src/main/java/de/unijena/cheminf/mortar/model/util/BasicDefinitions.java b/src/main/java/de/unijena/cheminf/mortar/model/util/BasicDefinitions.java index 274b430b..f5973925 100644 --- a/src/main/java/de/unijena/cheminf/mortar/model/util/BasicDefinitions.java +++ b/src/main/java/de/unijena/cheminf/mortar/model/util/BasicDefinitions.java @@ -186,5 +186,9 @@ public final class BasicDefinitions { * Default distance between image and text */ public static final int DEFAULT_IMAGE_TEXT_DISTANCE = 15; + /** + * Default load factor for HashMap and HashSet instances, defined based on default value given in the Java documentation. + */ + public static final float DEFAULT_HASH_COLLECTION_LOAD_FACTOR = 0.75f; // } \ No newline at end of file diff --git a/src/main/java/de/unijena/cheminf/mortar/model/util/ListUtil.java b/src/main/java/de/unijena/cheminf/mortar/model/util/CollectionUtil.java similarity index 64% rename from src/main/java/de/unijena/cheminf/mortar/model/util/ListUtil.java rename to src/main/java/de/unijena/cheminf/mortar/model/util/CollectionUtil.java index 32dd8d95..40cd7164 100644 --- a/src/main/java/de/unijena/cheminf/mortar/model/util/ListUtil.java +++ b/src/main/java/de/unijena/cheminf/mortar/model/util/CollectionUtil.java @@ -27,15 +27,15 @@ import java.util.List; /** - * Util class for lists. + * Util class for collections. * - * @author Felix Baensch - * @version 1.0.0.0 + * @author Felix Baensch, Jonas Schaub + * @version 1.0.1.0 */ -public final class ListUtil { +public final class CollectionUtil { // /** - * Sorts given list by property and sort type + * Sorts given list by property and sort type. * * @param aList List * @param aProperty String @@ -109,5 +109,45 @@ public static void sortGivenFragmentListByPropertyAndSortType(ListThe initial capacity multiplied with the load factor (= resize threshold) must be higher than the number of + * elements. + * + * @param aNumberOfElements number of elements supposed to be stored in the new HashMap or HashSet instance + * @param aLoadFactor load factor that is specified for the new HashMap or HashSet instance + * @return a suitable initial size for the new HashMap or HashSet instance that leads to a resize threshold that is slightly + * higher than the number of elements + * @throws IllegalArgumentException if the number of elements or the load factor is negative or equal to zero + * or if the load factor is greater than 1.0 + */ + public static int calculateInitialHashCollectionCapacity(int aNumberOfElements, float aLoadFactor) + throws IllegalArgumentException { + if (aNumberOfElements <= 0) { + throw new IllegalArgumentException("Number of elements needs to be higher than 0 but is " + aNumberOfElements); + } + if (aLoadFactor <= 0 || aLoadFactor > 1.0f) { + throw new IllegalArgumentException("Load factor must be higher than 0 and not bigger than 1.0 but is " + aLoadFactor); + } + float tmpInitialSize = (float) aNumberOfElements * (1.0f / aLoadFactor) + 2.0f; + return (int) tmpInitialSize; + } + // + /** + * Calculates a suitable initial size for instantiating a new HashMap or HashSet instance with the default load factor. + *
For more details, see {@link #calculateInitialHashCollectionCapacity(int, float) calculateInitialHashCollectionCapacity(int, float)}. + * + * + * @param aNumberOfElements number of elements supposed to be stored in the new HashMap or HashSet instance + * @return a suitable initial size for the new HashMap or HashSet instance that leads to a resize threshold that is slightly + * higher than the number of elements + * @throws IllegalArgumentException if the number of elements is negative or equal to zero + */ + public static int calculateInitialHashCollectionCapacity(int aNumberOfElements) throws IllegalArgumentException { + return CollectionUtil.calculateInitialHashCollectionCapacity(aNumberOfElements, BasicDefinitions.DEFAULT_HASH_COLLECTION_LOAD_FACTOR); + } //
} diff --git a/src/test/java/de/unijena/cheminf/mortar/model/util/CollectionUtilTest.java b/src/test/java/de/unijena/cheminf/mortar/model/util/CollectionUtilTest.java new file mode 100644 index 00000000..b50b2b98 --- /dev/null +++ b/src/test/java/de/unijena/cheminf/mortar/model/util/CollectionUtilTest.java @@ -0,0 +1,51 @@ +/* + * MORTAR - MOlecule fRagmenTAtion fRamework + * Copyright (C) 2023 Felix Baensch, Jonas Schaub (felix.baensch@w-hs.de, jonas.schaub@uni-jena.de) + * + * Source code is available at + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.unijena.cheminf.mortar.model.util; + +import org.junit.Assert; +import org.junit.Test; + +/** + * Test class for CollectionUtil routines. + */ +public class CollectionUtilTest { + /** + * Tests whether a few examples of number of elements and load factor pairs generate suitable initial capacities that + * lead to rehash thresholds higher than the number of elements using the specific calculation method from CollectionUtil. + */ + @Test + public void calculateInitialHashMapSizeTest() { + int[] tmpNumberOfElements = new int[]{10, 100, 4353456, 30}; + float[] tmpLoadFactor = new float[]{0.75f, 0.75f, 0.6f, 0.75f}; + int[] tmpExpectedInitialCapacity = new int[]{15, 135, 7255762, 42}; + for (int i = 0; i < tmpNumberOfElements.length; i++) { + int tmpCalculatedInitialHashMapCapacity = CollectionUtil.calculateInitialHashCollectionCapacity(tmpNumberOfElements[i], tmpLoadFactor[i]); + float tmpRehashThreshold = tmpCalculatedInitialHashMapCapacity * tmpLoadFactor[i]; + System.out.println("\nNumber of elements: " + tmpNumberOfElements[i]); + System.out.println("Load factor: " + tmpLoadFactor[i]); + System.out.println("Expected initial capacity ((int) n_elements * (1/lf) + 2): " + tmpExpectedInitialCapacity[i]); + System.out.println("Calculated initial capacity: " + tmpCalculatedInitialHashMapCapacity); + System.out.println("Rehash threshold (lf * initCap, must be higher than number of elements): " + tmpRehashThreshold); + Assert.assertTrue(tmpNumberOfElements[i] < tmpRehashThreshold); + Assert.assertEquals(tmpExpectedInitialCapacity[i], tmpCalculatedInitialHashMapCapacity); + } + } +} \ No newline at end of file