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

            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        12466 :     bool writeHeader(const SumoXMLTag& rootElement) {
     200        12466 :         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       125874 :     void lf() {
     243       125874 :         getOStream() << "\n";
     244       125874 :     }
     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     33157933 :         PlainXMLFormatter::writeAttr(getOStream(), attr, val);
     256     12862829 :         return *this;
     257              :     }
     258              : 
     259              :     inline bool useAttribute(const SumoXMLAttr attr, SumoXMLAttrMask attributeMask) const {
     260     14866500 :         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     10461606 :     OutputDevice& writeOptionalAttr(const SumoXMLAttr attr, const T& val, long long int attributeMask) {
     272              :         assert((int)attr <= 63);
     273     10461606 :         if (attributeMask == 0 || useAttribute(attr, attributeMask)) {
     274     10455184 :             PlainXMLFormatter::writeAttr(getOStream(), attr, val);
     275              :         }
     276     10461606 :         return *this;
     277              :     }
     278              :     template <typename T>
     279     13644802 :     OutputDevice& writeOptionalAttr(const SumoXMLAttr attr, const T& val, SumoXMLAttrMask attributeMask) {
     280              :         assert((int)attr <= (int)attributeMask.size());
     281     27289604 :         if (attributeMask.none() || useAttribute(attr, attributeMask)) {
     282      9055890 :             PlainXMLFormatter::writeAttr(getOStream(), attr, val);
     283              :         }
     284     13644802 :         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     19010631 :         PlainXMLFormatter::writeAttr(getOStream(), attr, val);
     297     15627917 :         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       284122 :     OutputDevice& writeNonEmptyAttr(const SumoXMLAttr attr, const std::string& val) {
     307       284122 :         if (val != "" && val != "default") {
     308              :             writeAttr(attr, val);
     309              :         }
     310       284122 :         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         1106 :         myFormatter->writePreformattedTag(getOStream(), val);
     321         1058 :         return *this;
     322              :     }
     323              : 
     324              :     /// @brief writes padding (ignored for binary output)
     325              :     OutputDevice& writePadding(const std::string& val) {
     326        53719 :         myFormatter->writePadding(getOStream(), val);
     327        53719 :         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 bool progress = false);
     337              : 
     338              : 
     339              :     /** @brief Abstract output operator
     340              :      * @return The OutputDevice for further processing
     341              :      */
     342              :     template <class T>
     343     37244714 :     OutputDevice& operator<<(const T& t) {
     344     37244714 :         getOStream() << t;
     345     37244714 :         postWriteHook();
     346     37244714 :         return *this;
     347              :     }
     348              : 
     349              :     void flush() {
     350     15626939 :         getOStream().flush();
     351     15626939 :     }
     352              : 
     353              :     bool wroteHeader() const {
     354       240252 :         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 2.0-1