LCOV - code coverage report
Current view: top level - src/utils/iodevices - OutputDevice.h (source / functions) Hit Total Coverage
Test: lcov.info Lines: 32 35 91.4 %
Date: 2024-05-05 15:31:14 Functions: 74 81 91.4 %

          Line data    Source code
       1             : /****************************************************************************/
       2             : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3             : // Copyright (C) 2004-2024 German Aerospace Center (DLR) and others.
       4             : // This program and the accompanying materials are made available under the
       5             : // terms of the Eclipse Public License 2.0 which is available at
       6             : // https://www.eclipse.org/legal/epl-2.0/
       7             : // This Source Code may also be made available under the following Secondary
       8             : // Licenses when the conditions for such availability set forth in the Eclipse
       9             : // Public License 2.0 are satisfied: GNU General Public License, version 2
      10             : // or later which is available at
      11             : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
      12             : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
      13             : /****************************************************************************/
      14             : /// @file    OutputDevice.h
      15             : /// @author  Daniel Krajzewicz
      16             : /// @author  Jakob Erdmann
      17             : /// @author  Michael Behrisch
      18             : /// @author  Mario Krumnow
      19             : /// @date    2004
      20             : ///
      21             : // Static storage of an output device and its base (abstract) implementation
      22             : /****************************************************************************/
      23             : #pragma once
      24             : #include <config.h>
      25             : 
      26             : #include <string>
      27             : #include <map>
      28             : #include <cassert>
      29             : #include <utils/common/ToString.h>
      30             : #include <utils/xml/SUMOXMLDefinitions.h>
      31             : #include "PlainXMLFormatter.h"
      32             : 
      33             : 
      34             : // ===========================================================================
      35             : // class definitions
      36             : // ===========================================================================
      37             : /**
      38             :  * @class OutputDevice
      39             :  * @brief Static storage of an output device and its base (abstract) implementation
      40             :  *
      41             :  * OutputDevices are basically a capsule around an std::ostream, which give a
      42             :  *  unified access to sockets, files and stdout.
      43             :  *
      44             :  * Usually, an application builds as many output devices as needed. Each
      45             :  *  output device may also be used to save outputs from several sources
      46             :  *  (several detectors, for example). Building is done using OutputDevice::getDevice()
      47             :  *  what also parses the given output description in order to decide
      48             :  *  what kind of an OutputDevice shall be built. OutputDevices are
      49             :  *  closed via OutputDevice::closeAll(), normally called at the application's
      50             :  *  end.
      51             :  *
      52             :  * Although everything that can be written to a stream can also be written
      53             :  *  to an OutputDevice, there is special support for XML tags (remembering
      54             :  *  all open tags to close them at the end). OutputDevices are still lacking
      55             :  *  support for function pointers with the '<<' operator (no endl, use '\n').
      56             :  *  The most important method to implement in subclasses is getOStream,
      57             :  *  the most used part of the interface is the '<<' operator.
      58             :  *
      59             :  * The Boolean markers are used rarely and might get removed in future versions.
      60             :  */
      61             : class OutputDevice {
      62             : public:
      63             :     /// @name static access methods to OutputDevices
      64             :     /// @{
      65             : 
      66             :     /** @brief Returns the described OutputDevice
      67             :      *
      68             :      * Creates and returns the named device. "stdout" and "stderr" refer to the relevant console streams,
      69             :      * "hostname:port" initiates socket connection. Otherwise a filename
      70             :      * is assumed (where "nul" and "/dev/null" do what you would expect on both platforms).
      71             :      * If there already is a device with the same name this one is returned.
      72             :      *
      73             :      * @param[in] name The description of the output name/port/whatever
      74             :      * @return The corresponding (built or existing) device
      75             :      * @exception IOError If the output could not be built for any reason (error message is supplied)
      76             :      */
      77             :     static OutputDevice& getDevice(const std::string& name, bool usePrefix = true);
      78             : 
      79             : 
      80             :     /** @brief Creates the device using the output definition stored in the named option
      81             :      *
      82             :      * Creates and returns the device named by the option. Asks whether the option
      83             :      *  and retrieves the name from the option if so. Optionally the XML header
      84             :      *  gets written as well. Returns whether a device was created (option was set).
      85             :      *
      86             :      * Please note, that we do not have to consider the "application base" herein,
      87             :      *  because this call is only used to get file names of files referenced
      88             :      *  within XML-declarations of structures which paths already is aware of the
      89             :      *  cwd.
      90             :      *
      91             :      * @param[in] optionName  The name of the option to use for retrieving the output definition
      92             :      * @param[in] rootElement The root element to use (XML-output)
      93             :      * @param[in] schemaFile  The basename of the schema file to use (XML-output)
      94             :      * @return Whether a device was built (the option was set)
      95             :      * @exception IOError If the output could not be built for any reason (error message is supplied)
      96             :      */
      97             :     static bool createDeviceByOption(const std::string& optionName,
      98             :                                      const std::string& rootElement = "",
      99             :                                      const std::string& schemaFile = "");
     100             : 
     101             : 
     102             :     /** @brief Returns the device described by the option
     103             :      *
     104             :      * Returns the device named by the option. If the option is unknown, unset
     105             :      * or the device was not created before, InvalidArgument is thrown.
     106             :      *
     107             :      * Please note, that we do not have to consider the "application base" herein.
     108             :      *
     109             :      * @param[in] name The name of the option to use for retrieving the output definition
     110             :      * @return The corresponding (built or existing) device
     111             :      * @exception IOError If the output could not be built for any reason (error message is supplied)
     112             :      * @exception InvalidArgument If the option with the given name does not exist
     113             :      */
     114             :     static OutputDevice& getDeviceByOption(const std::string& name);
     115             : 
     116             :     /**  Flushes all registered devices
     117             :      */
     118             :     static void flushAll();
     119             : 
     120             :     /**  Closes all registered devices
     121             :      */
     122             :     static void closeAll(bool keepErrorRetrievers = false);
     123             :     /// @}
     124             : 
     125             : 
     126             :     /** @brief Helper method for string formatting
     127             :      *
     128             :      * @param[in] v The floating point value to be formatted
     129             :      * @param[in] precision the precision to achieve
     130             :      * @return The formatted string
     131             :      */
     132             :     static std::string realString(const double v, const int precision = gPrecision);
     133             : 
     134             : 
     135             : public:
     136             :     /// @name OutputDevice member methods
     137             :     /// @{
     138             : 
     139             :     /// @brief Constructor
     140             :     OutputDevice(const int defaultIndentation = 0, const std::string& filename = "");
     141             : 
     142             : 
     143             :     /// @brief Destructor
     144             :     virtual ~OutputDevice();
     145             : 
     146             : 
     147             :     /** @brief returns the information whether one can write into the device
     148             :      * @return Whether the device can be used (stream is good)
     149             :      */
     150             :     virtual bool ok();
     151             : 
     152             :     /** @brief returns the information whether the device will discard all output
     153             :      * @return Whether the device redirects to /dev/null
     154             :      */
     155           0 :     virtual bool isNull() {
     156           0 :         return false;
     157             :     }
     158             : 
     159             :     /// @brief get filename or suitable description of this device
     160             :     const std::string& getFilename();
     161             : 
     162             :     /** @brief Closes the device and removes it from the dictionary
     163             :      */
     164             :     void close();
     165             : 
     166             : 
     167             :     /** @brief Sets the precision or resets it to default
     168             :      * @param[in] precision The accuracy (number of digits behind '.') to set
     169             :      */
     170             :     void setPrecision(int precision = gPrecision);
     171             : 
     172             :     /// @brief return precision set on the device
     173             :     int precision();
     174             : 
     175             :     /** @brief Returns the precision of the underlying stream
     176             :      */
     177             :     int getPrecision() {
     178           0 :         return (int)getOStream().precision();
     179             :     }
     180             : 
     181             :     /** @brief Writes an XML header with optional configuration
     182             :      *
     183             :      * If something has been written (myXMLStack is not empty), nothing
     184             :      *  is written and false returned.
     185             :      *
     186             :      * @param[in] rootElement The root element to use
     187             :      * @param[in] schemaFile  The basename of the schema file to use
     188             :      * @param[in] attrs Additional attributes to save within the rootElement
     189             :      * @return Whether the header could be written (stack was empty)
     190             :      * @todo Describe what is saved
     191             :      */
     192             :     bool writeXMLHeader(const std::string& rootElement,
     193             :                         const std::string& schemaFile,
     194             :                         std::map<SumoXMLAttr, std::string> attrs = std::map<SumoXMLAttr, std::string>(),
     195             :                         bool includeConfig = true);
     196             : 
     197             : 
     198             :     template <typename E>
     199        5974 :     bool writeHeader(const SumoXMLTag& rootElement) {
     200        5974 :         return static_cast<PlainXMLFormatter*>(myFormatter)->writeHeader(getOStream(), rootElement);
     201             :     }
     202             : 
     203             : 
     204             :     /** @brief Opens an XML tag
     205             :      *
     206             :      * An indentation, depending on the current xml-element-stack size, is written followed
     207             :      *  by the given xml element ("<" + xmlElement)
     208             :      * The xml element is added to the stack, then.
     209             :      *
     210             :      * @param[in] xmlElement Name of element to open
     211             :      * @return The OutputDevice for further processing
     212             :      */
     213             :     OutputDevice& openTag(const std::string& xmlElement);
     214             : 
     215             : 
     216             :     /** @brief Opens an XML tag
     217             :      *
     218             :      * Helper method which finds the correct string before calling openTag.
     219             :      *
     220             :      * @param[in] xmlElement Id of the element to open
     221             :      * @return The OutputDevice for further processing
     222             :      */
     223             :     OutputDevice& openTag(const SumoXMLTag& xmlElement);
     224             : 
     225             : 
     226             :     /** @brief Closes the most recently opened tag and optionally adds a comment
     227             :      *
     228             :      * The topmost xml-element from the stack is written into the stream
     229             :      *  as a closing element. Depending on the formatter used
     230             :      *  this may be something like "</" + element + ">" or "/>" or
     231             :      *  nothing at all.
     232             :      *
     233             :      * @return Whether a further element existed in the stack and could be closed
     234             :      * @todo it is not verified that the topmost element was closed
     235             :      */
     236             :     bool closeTag(const std::string& comment = "");
     237             : 
     238             : 
     239             : 
     240             :     /** @brief writes a line feed if applicable
     241             :      */
     242      131275 :     void lf() {
     243      131275 :         getOStream() << "\n";
     244      131275 :     }
     245             : 
     246             : 
     247             :     /** @brief writes a named attribute
     248             :      *
     249             :      * @param[in] attr The attribute (name)
     250             :      * @param[in] val The attribute value
     251             :      * @return The OutputDevice for further processing
     252             :      */
     253             :     template <typename T>
     254             :     OutputDevice& writeAttr(const SumoXMLAttr attr, const T& val) {
     255    49559956 :         PlainXMLFormatter::writeAttr(getOStream(), attr, val);
     256    13746832 :         return *this;
     257             :     }
     258             : 
     259             :     inline bool useAttribute(const SumoXMLAttr attr, SumoXMLAttrMask attributeMask) const {
     260    14122629 :         return attributeMask.test(attr);
     261             :     }
     262             : 
     263             :     /** @brief writes a named attribute unless filtered
     264             :      *
     265             :      * @param[in] attr The attribute (name)
     266             :      * @param[in] val The attribute value
     267             :      * @param[in] attributeMask The filter that specifies whether the attribute shall be written
     268             :      * @return The OutputDevice for further processing
     269             :      */
     270             :     template <typename T>
     271    15601896 :     OutputDevice& writeOptionalAttr(const SumoXMLAttr attr, const T& val, long long int attributeMask) {
     272             :         assert((int)attr <= 63);
     273    15601896 :         if (attributeMask == 0 || useAttribute(attr, attributeMask)) {
     274    15595474 :             PlainXMLFormatter::writeAttr(getOStream(), attr, val);
     275             :         }
     276    15601896 :         return *this;
     277             :     }
     278             :     template <typename T>
     279    12895057 :     OutputDevice& writeOptionalAttr(const SumoXMLAttr attr, const T& val, SumoXMLAttrMask attributeMask) {
     280             :         assert((int)attr <= (int)attributeMask.size());
     281    25790114 :         if (attributeMask.none() || useAttribute(attr, attributeMask)) {
     282     8561622 :             PlainXMLFormatter::writeAttr(getOStream(), attr, val);
     283             :         }
     284    12895057 :         return *this;
     285             :     }
     286             : 
     287             : 
     288             :     /** @brief writes an arbitrary attribute
     289             :      *
     290             :      * @param[in] attr The attribute (name)
     291             :      * @param[in] val The attribute value
     292             :      * @return The OutputDevice for further processing
     293             :      */
     294             :     template <typename T>
     295             :     OutputDevice& writeAttr(const std::string& attr, const T& val) {
     296    28560167 :         PlainXMLFormatter::writeAttr(getOStream(), attr, val);
     297    24974919 :         return *this;
     298             :     }
     299             : 
     300             :     /** @brief writes a string attribute only if it is not the empty string and not the string "default"
     301             :      *
     302             :      * @param[in] attr The attribute (name)
     303             :      * @param[in] val The attribute value
     304             :      * @return The OutputDevice for further processing
     305             :      */
     306      454586 :     OutputDevice& writeNonEmptyAttr(const SumoXMLAttr attr, const std::string& val) {
     307      909172 :         if (val != "" && val != "default") {
     308             :             writeAttr(attr, val);
     309             :         }
     310      454586 :         return *this;
     311             :     }
     312             : 
     313             : 
     314             :     /** @brief writes a preformatted tag to the device but ensures that any
     315             :      * pending tags are closed
     316             :      * @param[in] val The preformatted data
     317             :      * @return The OutputDevice for further processing
     318             :      */
     319             :     OutputDevice& writePreformattedTag(const std::string& val) {
     320        1104 :         myFormatter->writePreformattedTag(getOStream(), val);
     321        1056 :         return *this;
     322             :     }
     323             : 
     324             :     /// @brief writes padding (ignored for binary output)
     325             :     OutputDevice& writePadding(const std::string& val) {
     326       70048 :         myFormatter->writePadding(getOStream(), val);
     327       70048 :         return *this;
     328             :     }
     329             : 
     330             :     /** @brief Retrieves a message to this device.
     331             :      *
     332             :      * Implementation of the MessageRetriever interface. Writes the given message to the output device.
     333             :      *
     334             :      * @param[in] msg The msg to write to the device
     335             :      */
     336             :     void inform(const std::string& msg, const char progress = 0);
     337             : 
     338             : 
     339             :     /** @brief Abstract output operator
     340             :      * @return The OutputDevice for further processing
     341             :      */
     342             :     template <class T>
     343    65554811 :     OutputDevice& operator<<(const T& t) {
     344    65554811 :         getOStream() << t;
     345    65554811 :         postWriteHook();
     346    65554810 :         return *this;
     347             :     }
     348             : 
     349             :     void flush() {
     350    15294720 :         getOStream().flush();
     351    15294720 :     }
     352             : 
     353             :     bool wroteHeader() const {
     354      400789 :         return myFormatter->wroteHeader();
     355             :     }
     356             : 
     357             : protected:
     358             :     /// @brief Returns the associated ostream
     359             :     virtual std::ostream& getOStream() = 0;
     360             : 
     361             : 
     362             :     /** @brief Called after every write access.
     363             :      *
     364             :      * Default implementation does nothing.
     365             :      */
     366             :     virtual void postWriteHook();
     367             : 
     368             : 
     369             : private:
     370             :     /// @brief map from names to output devices
     371             :     static std::map<std::string, OutputDevice*> myOutputDevices;
     372             : 
     373             :     /// @brief old console code page to restore after ending
     374             :     static int myPrevConsoleCP;
     375             : 
     376             : protected:
     377             :     const std::string myFilename;
     378             : 
     379             : private:
     380             :     /// @brief The formatter for XML
     381             :     OutputFormatter* const myFormatter;
     382             : 
     383             : private:
     384             :     /// @brief Invalidated copy constructor.
     385             :     OutputDevice(const OutputDevice&) = delete;
     386             : 
     387             :     /// @brief Invalidated assignment operator.
     388             :     OutputDevice& operator=(const OutputDevice&) = delete;
     389             : 
     390             : };

Generated by: LCOV version 1.14