From 14a7ab1ce7ae4b05b4f56e7596bd289591d6e679 Mon Sep 17 00:00:00 2001
From: Martyn Gigg <martyn.gigg@stfc.ac.uk>
Date: Tue, 2 Jul 2013 12:47:01 +0100
Subject: [PATCH] Flip path/type map in HDFDescriptor. Refs #7263

Looking up paths is far more common so make that faster.
---
 .../DataHandling/src/LoadMuonNexus2.cpp       |  5 +-
 .../Kernel/inc/MantidKernel/HDFDescriptor.h   | 12 ++-
 .../Framework/Kernel/src/HDFDescriptor.cpp    | 91 ++++++++++++++-----
 3 files changed, 79 insertions(+), 29 deletions(-)

diff --git a/Code/Mantid/Framework/DataHandling/src/LoadMuonNexus2.cpp b/Code/Mantid/Framework/DataHandling/src/LoadMuonNexus2.cpp
index 0f477784753..fe2549066f2 100644
--- a/Code/Mantid/Framework/DataHandling/src/LoadMuonNexus2.cpp
+++ b/Code/Mantid/Framework/DataHandling/src/LoadMuonNexus2.cpp
@@ -505,11 +505,12 @@ namespace Mantid
       {
         NXRoot root(descriptor.filename());
         NXEntry entry = root.openFirstEntry();
+
         std::string versionField = "idf_version";
         if(upperIDF) versionField = "IDF_version";
 
-        if ( entry.getInt( versionField ) != 2 ) return 0;
-        std::string definition = entry.getString( "definition" );
+        if ( entry.getInt(versionField) != 2 ) return 0;
+        std::string definition = entry.getString("definition");
         if ( definition == "muonTD" || definition == "pulsedTD" )
         {
           // If all this succeeded then we'll assume this is an ISIS Muon NeXus file version 2
diff --git a/Code/Mantid/Framework/Kernel/inc/MantidKernel/HDFDescriptor.h b/Code/Mantid/Framework/Kernel/inc/MantidKernel/HDFDescriptor.h
index 13b2511e643..26f31b0a497 100644
--- a/Code/Mantid/Framework/Kernel/inc/MantidKernel/HDFDescriptor.h
+++ b/Code/Mantid/Framework/Kernel/inc/MantidKernel/HDFDescriptor.h
@@ -9,6 +9,11 @@
 #include <string>
 #include <utility>
 
+namespace NeXus
+{
+  class File;
+}
+
 namespace Mantid
 {
   namespace Kernel
@@ -90,6 +95,9 @@ namespace Mantid
 
       /// Initialize object with filename
       void initialize(const std::string& filename);
+      /// Walk the tree and cache the structure
+      void walkFile(::NeXus::File & file, const std::string & rootPath, const std::string & className,
+                    std::map<std::string, std::string> & pmap, int level);
 
       /// Full filename
       std::string m_filename;
@@ -99,8 +107,8 @@ namespace Mantid
       std::pair<std::string, std::string> m_firstEntryNameType;
       /// Root attributes
       std::set<std::string> m_rootAttrs;
-      /// Map of types to full path strings.
-      std::multimap<std::string, std::string> *m_typesToPaths;
+      /// Map of full path strings to types. Can check if path exists quickly
+      std::map<std::string, std::string> m_pathsToTypes;
     };
 
 
diff --git a/Code/Mantid/Framework/Kernel/src/HDFDescriptor.cpp b/Code/Mantid/Framework/Kernel/src/HDFDescriptor.cpp
index fb1d3dac585..70fd3d55160 100644
--- a/Code/Mantid/Framework/Kernel/src/HDFDescriptor.cpp
+++ b/Code/Mantid/Framework/Kernel/src/HDFDescriptor.cpp
@@ -8,7 +8,6 @@
 #include <Poco/Path.h>
 
 #include <cstring>
-#include <iostream>
 
 namespace Mantid
 {
@@ -100,7 +99,7 @@ namespace Mantid
      */
     HDFDescriptor::HDFDescriptor(const std::string & filename)
       : m_filename(), m_extension(), m_firstEntryNameType(),
-        m_rootAttrs(), m_typesToPaths(NULL)
+        m_rootAttrs(), m_pathsToTypes()
     {
       if(filename.empty())
       {
@@ -124,7 +123,6 @@ namespace Mantid
      */
     HDFDescriptor::~HDFDescriptor()
     {
-      delete m_typesToPaths;
     }
 
     /// Returns the name & type of the first entry in the file
@@ -148,12 +146,7 @@ namespace Mantid
      */
     bool HDFDescriptor::pathExists(const std::string& path) const
     {
-      auto iend = m_typesToPaths->end();
-      for(auto it = m_typesToPaths->begin(); it != iend; ++it)
-      {
-        if(path == it->second) return true;
-      }
-      return false;
+      return (m_pathsToTypes.find(path) != m_pathsToTypes.end());
     }
 
     /**
@@ -163,13 +156,12 @@ namespace Mantid
      */
     bool HDFDescriptor::pathOfTypeExists(const std::string& path, const std::string & type) const
     {
-      auto it = m_typesToPaths->lower_bound(type);
-      auto itend = m_typesToPaths->upper_bound(type);
-      for(; it != itend; ++it)
+      auto it = m_pathsToTypes.find(path);
+      if(it != m_pathsToTypes.end())
       {
-        if(it->second == path) return true;
+        return (it->second == type);
       }
-      return false;
+      else return false;
     }
 
     /**
@@ -178,10 +170,14 @@ namespace Mantid
      */
     bool HDFDescriptor::classTypeExists(const std::string & classType) const
     {
-      return (m_typesToPaths->find(classType) != m_typesToPaths->end());
+      auto iend = m_pathsToTypes.end();
+      for(auto it = m_pathsToTypes.begin(); it != iend; ++it)
+      {
+        if(classType == it->second) return true;
+      }
+      return false;
     }
 
-
     //---------------------------------------------------------------------------------------------------------------------------
     // HDFDescriptor private methods
     //---------------------------------------------------------------------------------------------------------------------------
@@ -195,20 +191,65 @@ namespace Mantid
       m_extension = "." + Poco::Path(filename).getExtension();
 
       ::NeXus::File file(this->filename());
-      auto attrInfos = file.getAttrInfos();
-      for(size_t i = 0; i < attrInfos.size(); ++i)
+
+      file.openPath("/");
+      m_rootAttrs.clear();
+      m_pathsToTypes.clear();
+      walkFile(file, "", "", m_pathsToTypes,0);
+    }
+
+    /**
+     * Cache the structure in the given maps
+     * @param file An open NeXus File object
+     * @param rootPath The current path that is open in the file
+     * @param className The class of the current open path
+     * @param tmap [Out] An output map filled with mappings of type->path
+     * @param pmap [Out] An output map filled with mappings of path->type
+     * @param level An integer defining the current level in the file
+     */
+    void HDFDescriptor::walkFile(::NeXus::File & file,const std::string & rootPath, const std::string & className,
+                                 std::map<std::string, std::string> & pmap, int level)
+    {
+      if (!rootPath.empty())
       {
-        m_rootAttrs.insert(attrInfos[i].name);
+        pmap.insert(std::make_pair(rootPath, className));
       }
-      auto entries = file.getEntries();
-      for(auto it = entries.begin(); it != entries.end(); ++it)
+      if(level == 0)
       {
-        if(it->second == "CDF0.0") continue;
-        m_firstEntryNameType = std::make_pair(it->first, it->second);
-        break;
+        auto attrInfos = file.getAttrInfos();
+        for(size_t i = 0; i < attrInfos.size(); ++i)
+        {
+          m_rootAttrs.insert(attrInfos[i].name);
+        }
       }
-      m_typesToPaths = file.getTypeMap();
+
+      auto dirents = file.getEntries();
+      auto itend = dirents.end();
+      for (auto it = dirents.begin(); it != itend; ++it)
+      {
+        const std::string & entryName = it->first;
+        const std::string & entryClass = it->second;
+        const std::string entryPath = rootPath + "/" + entryName;
+        if(entryClass == "SDS")
+        {
+          //tmap.insert(std::make_pair(entryClass, entryPath));
+          pmap.insert(std::make_pair(entryPath, entryClass));
+        }
+        else if(entryClass == "CDF0.0")
+        {
+          // Do nothing with this
+        }
+        else
+        {
+          if(level == 0) m_firstEntryNameType = (*it); //copy first entry name & type
+          file.openGroup(entryName, entryClass);
+          walkFile(file, entryPath, entryClass, pmap,level+1);
+        }
+      }
+      file.closeGroup();
     }
 
+
+
   } // namespace Kernel
 } // namespace Mantid
-- 
GitLab