From b25dab9e6c7abba9a115adde7ca3259fb89a3124 Mon Sep 17 00:00:00 2001
From: Gerhard Raven <gerhard.raven@nikhef.nl>
Date: Tue, 15 Mar 2022 09:33:29 +0100
Subject: [PATCH] Extend IFileAccess interface with a `read` function

`IFileAccess;:read` returns an `optional<string>` with the content of the
requested file -- if it can be read. Otherwise it returns an 'empty'
optional.
---
 GaudiKernel/include/GaudiKernel/IFileAccess.h | 14 +++-
 .../include/GaudiKernel/ServiceHandle.h       |  4 +-
 GaudiUtils/src/component/FileReadTool.cpp     | 44 +++++++----
 GaudiUtils/src/component/FileReadTool.h       | 36 ---------
 GaudiUtils/src/component/VFSSvc.cpp           | 74 ++++++++++++++-----
 GaudiUtils/src/component/VFSSvc.h             | 70 ------------------
 6 files changed, 97 insertions(+), 145 deletions(-)
 delete mode 100644 GaudiUtils/src/component/FileReadTool.h
 delete mode 100644 GaudiUtils/src/component/VFSSvc.h

diff --git a/GaudiKernel/include/GaudiKernel/IFileAccess.h b/GaudiKernel/include/GaudiKernel/IFileAccess.h
index ae195089c7..07e438c884 100644
--- a/GaudiKernel/include/GaudiKernel/IFileAccess.h
+++ b/GaudiKernel/include/GaudiKernel/IFileAccess.h
@@ -15,6 +15,7 @@
 #include "GaudiKernel/IInterface.h"
 #include <istream>
 #include <memory>
+#include <optional>
 #include <string>
 #include <vector>
 
@@ -28,12 +29,21 @@
 class GAUDI_API IFileAccess : virtual public IInterface {
 public:
   /// InterfaceID
-  DeclareInterfaceID( IFileAccess, 3, 0 );
+  DeclareInterfaceID( IFileAccess, 3, 1 );
 
   /// Find the URL and returns a unique_ptr to an input stream interface of an
   /// object that can be used to read from the file the URL is pointing to.
   /// Returns an empty pointer if the URL cannot be resolved.
-  virtual std::unique_ptr<std::istream> open( const std::string& url ) = 0;
+  virtual std::unique_ptr<std::istream> open( std::string const& url ) = 0;
+
+  /// Find the URL and returns an optional<string> to the content of
+  /// the file the URL is pointing to.
+  /// Returns an 'unengaged' optional if the URL cannot be resolved.
+  virtual std::optional<std::string> read( std::string const& url ) {
+    auto is = open( url );
+    if ( !is || !is->good() ) return std::nullopt;
+    return std::string{ std::istreambuf_iterator<char>{ *is }, std::istreambuf_iterator<char>{} };
+  }
 
   /// Protocols supported by the instance.
   virtual const std::vector<std::string>& protocols() const = 0;
diff --git a/GaudiKernel/include/GaudiKernel/ServiceHandle.h b/GaudiKernel/include/GaudiKernel/ServiceHandle.h
index 06d395be5e..93af3f82b6 100644
--- a/GaudiKernel/include/GaudiKernel/ServiceHandle.h
+++ b/GaudiKernel/include/GaudiKernel/ServiceHandle.h
@@ -77,9 +77,7 @@ public:
 
   /** Retrieve the Service. Release existing Service if needed.
       Function must be repeated here to avoid hiding the function retrieve( T*& ) */
-  StatusCode retrieve() const { // not really const, because it updates m_pObject
-    return GaudiHandle<T>::retrieve();
-  }
+  using GaudiHandle<T>::retrieve;
 
   //  /** Release the Service.
   //    Function must be repeated here to avoid hiding the function release( T*& ) */
diff --git a/GaudiUtils/src/component/FileReadTool.cpp b/GaudiUtils/src/component/FileReadTool.cpp
index b01f9add6b..573d6d1286 100644
--- a/GaudiUtils/src/component/FileReadTool.cpp
+++ b/GaudiUtils/src/component/FileReadTool.cpp
@@ -8,24 +8,36 @@
 * granted to it by virtue of its status as an Intergovernmental Organization        *
 * or submit itself to any jurisdiction.                                             *
 \***********************************************************************************/
-#include "FileReadTool.h"
+#include "GaudiKernel/AlgTool.h"
+#include "GaudiKernel/IFileAccess.h"
 #include <fstream>
 
-DECLARE_COMPONENT( FileReadTool )
+/** @class FileReadTool FileReadTool.h
+ *
+ *  Basic implementation of the IFileAccess interface.
+ *  This tool simply takes a path to a file as url and return the std::istream interface
+ *  of std::ifstream.
+ *
+ *  @author Marco Clemencic
+ *  @date 2008-01-18
+ */
+struct FileReadTool : extends<AlgTool, IFileAccess> {
+  /// Standard constructor
+  using extends::extends;
+
+  std::unique_ptr<std::istream> open( std::string const& url ) override {
+    // remove the optional "file://" from the beginning of the url
+    constexpr auto prefix = std::string_view{ "file://" };
+    return std::make_unique<std::ifstream>( url.compare( 0, prefix.size(), prefix ) == 0 ? url.substr( prefix.size() )
+                                                                                         : url );
+  }
 
-std::unique_ptr<std::istream> FileReadTool::open( const std::string& url ) {
-  // remove the optional "file://" from the beginning of the url
-  std::string path;
-  if ( url.compare( 0, 7, "file://" ) == 0 ) {
-    path = url.substr( 7 );
-  } else {
-    path = url;
+  /// Protocols supported by the instance.
+  const std::vector<std::string>& protocols() const override {
+    /// Vector of supported protocols.
+    static const std::vector<std::string> s_protocols = { { "file" } };
+    return s_protocols;
   }
-  return std::make_unique<std::ifstream>( path );
-}
+};
 
-const std::vector<std::string>& FileReadTool::protocols() const {
-  /// Vector of supported protocols.
-  static const std::vector<std::string> s_protocols = { { "file" } };
-  return s_protocols;
-}
+DECLARE_COMPONENT( FileReadTool )
diff --git a/GaudiUtils/src/component/FileReadTool.h b/GaudiUtils/src/component/FileReadTool.h
deleted file mode 100644
index bcc061e81b..0000000000
--- a/GaudiUtils/src/component/FileReadTool.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/***********************************************************************************\
-* (c) Copyright 1998-2019 CERN for the benefit of the LHCb and ATLAS collaborations *
-*                                                                                   *
-* This software is distributed under the terms of the Apache version 2 licence,     *
-* copied verbatim in the file "LICENSE".                                            *
-*                                                                                   *
-* In applying this licence, CERN does not waive the privileges and immunities       *
-* granted to it by virtue of its status as an Intergovernmental Organization        *
-* or submit itself to any jurisdiction.                                             *
-\***********************************************************************************/
-#ifndef _FILEREADTOOL_H
-#define _FILEREADTOOL_H
-
-#include "GaudiKernel/AlgTool.h"
-#include "GaudiKernel/IFileAccess.h"
-
-/** @class FileReadTool FileReadTool.h
- *
- *  Basic implementation of the IFileAccess interface.
- *  This tool simply takes a path to a file as url and return the std::istream interface
- *  of std::ifstream.
- *
- *  @author Marco Clemencic
- *  @date 2008-01-18
- */
-struct FileReadTool : extends<AlgTool, IFileAccess> {
-  /// Standard constructor
-  using extends::extends;
-
-  std::unique_ptr<std::istream> open( const std::string& url ) override;
-
-  /// Protocols supported by the instance.
-  const std::vector<std::string>& protocols() const override;
-};
-
-#endif // _FILEREADTOOL_H
diff --git a/GaudiUtils/src/component/VFSSvc.cpp b/GaudiUtils/src/component/VFSSvc.cpp
index a40b718ec1..85b29db6e7 100644
--- a/GaudiUtils/src/component/VFSSvc.cpp
+++ b/GaudiUtils/src/component/VFSSvc.cpp
@@ -8,11 +8,58 @@
 * granted to it by virtue of its status as an Intergovernmental Organization        *
 * or submit itself to any jurisdiction.                                             *
 \***********************************************************************************/
-#include "VFSSvc.h"
-
+#include "GaudiKernel/HashMap.h"
 #include "GaudiKernel/IAlgTool.h"
+#include "GaudiKernel/IFileAccess.h"
 #include "GaudiKernel/IToolSvc.h"
 #include "GaudiKernel/MsgStream.h"
+#include "GaudiKernel/Service.h"
+#include <list>
+
+/** @class VFSSvc VFSSvc.h
+ *
+ *  Simple service that allows to read files independently from the storage.
+ *  The service uses tools to resolve URLs and serve the files as input streams.
+ *  The basic implementations read from the filesystem, and simple extensions allow to
+ *  read from databases, web...
+ *
+ *  @author Marco Clemencic
+ *  @date   2008-01-18
+ */
+
+class VFSSvc : public extends<Service, IFileAccess> {
+public:
+  /// Inherited constructor
+  using extends::extends;
+  /// Initialize Service
+  StatusCode initialize() override;
+  /// Finalize Service
+  StatusCode finalize() override;
+
+  /// @see IFileAccess::open
+  std::unique_ptr<std::istream> open( std::string const& url ) override;
+
+  /// @see IFileAccess::protocols
+  const std::vector<std::string>& protocols() const override;
+
+private:
+  Gaudi::Property<std::vector<std::string>> m_urlHandlersNames{
+      this, "FileAccessTools", { { "FileReadTool" } }, "List of tools implementing the IFileAccess interface." };
+  Gaudi::Property<std::string> m_fallBackProtocol{ this, "FallBackProtocol", "file",
+                                                   "URL prefix to use if the prefix is not present." };
+
+  /// Protocols registered
+  std::vector<std::string> m_protocols;
+
+  /// Map of the tools handling the known protocols.
+  GaudiUtils::HashMap<std::string, std::vector<IFileAccess*>> m_urlHandlers;
+
+  /// Handle to the tool service.
+  SmartIF<IToolSvc> m_toolSvc;
+
+  /// List of acquired tools (needed to release them).
+  std::vector<IAlgTool*> m_acquiredTools;
+};
 
 DECLARE_COMPONENT( VFSSvc )
 
@@ -73,13 +120,13 @@ StatusCode VFSSvc::finalize() {
   return Service::finalize();
 }
 //------------------------------------------------------------------------------
-std::unique_ptr<std::istream> VFSSvc::open( const std::string& url ) {
+std::unique_ptr<std::istream> VFSSvc::open( std::string const& url ) {
   // get the url prefix endpos
   auto pos = url.find( "://" );
 
-  if ( std::string::npos == pos ) {
+  if ( url.npos == pos ) {
     // no url prefix, try fallback protocol
-    return VFSSvc::open( m_fallBackProtocol + "://" + url );
+    return VFSSvc::open( std::string{ m_fallBackProtocol }.append( "://" ).append( url ) );
   }
 
   const std::string url_prefix( url, 0, pos );
@@ -87,7 +134,7 @@ std::unique_ptr<std::istream> VFSSvc::open( const std::string& url ) {
   if ( handlers == m_urlHandlers.end() ) {
     // if we do not have a handler for the URL prefix,
     // use the fall back one
-    return VFSSvc::open( m_fallBackProtocol + url.substr( pos ) );
+    return VFSSvc::open( std::string{ m_fallBackProtocol }.append( url.substr( pos ) ) );
   }
 
   std::unique_ptr<std::istream> out; // this might help RVO
@@ -98,23 +145,14 @@ std::unique_ptr<std::istream> VFSSvc::open( const std::string& url ) {
   }
   return out;
 }
-//------------------------------------------------------------------------------
-namespace {
-  /// small helper to select  the first element of a pair
-  /// (e.g. the key of a map value type)
-  constexpr struct select1st_t {
-    template <typename S, typename T>
-    const S& operator()( const std::pair<S, T>& x ) const {
-      return x.first;
-    }
-  } select1st{};
-} // namespace
 
+//------------------------------------------------------------------------------
 const std::vector<std::string>& VFSSvc::protocols() const {
   if ( m_protocols.empty() ) {
     // prepare the list of handled protocols
     std::transform( m_urlHandlers.begin(), m_urlHandlers.end(),
-                    std::back_inserter( const_cast<VFSSvc*>( this )->m_protocols ), select1st );
+                    std::back_inserter( const_cast<VFSSvc*>( this )->m_protocols ),
+                    []( const auto& pair ) { return pair.first; } );
   }
   return m_protocols;
 }
diff --git a/GaudiUtils/src/component/VFSSvc.h b/GaudiUtils/src/component/VFSSvc.h
deleted file mode 100644
index c4417f4b67..0000000000
--- a/GaudiUtils/src/component/VFSSvc.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/***********************************************************************************\
-* (c) Copyright 1998-2019 CERN for the benefit of the LHCb and ATLAS collaborations *
-*                                                                                   *
-* This software is distributed under the terms of the Apache version 2 licence,     *
-* copied verbatim in the file "LICENSE".                                            *
-*                                                                                   *
-* In applying this licence, CERN does not waive the privileges and immunities       *
-* granted to it by virtue of its status as an Intergovernmental Organization        *
-* or submit itself to any jurisdiction.                                             *
-\***********************************************************************************/
-#ifndef GaudiSvc_VFSSvc_H
-#define GaudiSvc_VFSSvc_H 1
-
-// Include files
-#include "GaudiKernel/HashMap.h"
-#include "GaudiKernel/IFileAccess.h"
-#include "GaudiKernel/Service.h"
-
-#include <list>
-
-// Forward declarations
-class IToolSvc;
-class IAlgTool;
-
-/** @class VFSSvc VFSSvc.h
- *
- *  Simple service that allows to read files independently from the storage.
- *  The service uses tools to resolve URLs and serve the files as input streams.
- *  The basic implementations read from the filesystem, and simple extensions allow to
- *  read from databases, web...
- *
- *  @author Marco Clemencic
- *  @date   2008-01-18
- */
-
-class VFSSvc : public extends<Service, IFileAccess> {
-public:
-  /// Inherited constructor
-  using extends::extends;
-  /// Initialize Service
-  StatusCode initialize() override;
-  /// Finalize Service
-  StatusCode finalize() override;
-
-  /// @see IFileAccess::open
-  std::unique_ptr<std::istream> open( const std::string& url ) override;
-
-  /// @see IFileAccess::protocols
-  const std::vector<std::string>& protocols() const override;
-
-private:
-  Gaudi::Property<std::vector<std::string>> m_urlHandlersNames{
-      this, "FileAccessTools", { { "FileReadTool" } }, "List of tools implementing the IFileAccess interface." };
-  Gaudi::Property<std::string> m_fallBackProtocol{ this, "FallBackProtocol", "file",
-                                                   "URL prefix to use if the prefix is not present." };
-
-  /// Protocols registered
-  std::vector<std::string> m_protocols;
-
-  /// Map of the tools handling the known protocols.
-  GaudiUtils::HashMap<std::string, std::vector<IFileAccess*>> m_urlHandlers;
-
-  /// Handle to the tool service.
-  SmartIF<IToolSvc> m_toolSvc;
-
-  /// List of acquired tools (needed to release them).
-  std::vector<IAlgTool*> m_acquiredTools;
-};
-
-#endif
-- 
GitLab