LCOV - code coverage report
Current view: top level - src/utils/iodevices - CSVFormatter.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 95.3 % 43 41
Test Date: 2026-07-26 16:30:20 Functions: 100.0 % 5 5

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2012-2026 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    CSVFormatter.cpp
      15              : /// @author  Michael Behrisch
      16              : /// @date    2025-06-12
      17              : ///
      18              : // An output formatter for CSV files
      19              : /****************************************************************************/
      20              : #include <config.h>
      21              : 
      22              : #ifdef HAVE_FMT
      23              : #include <fmt/ostream.h>
      24              : #include <fmt/ranges.h>
      25              : #endif
      26              : #include <utils/common/MsgHandler.h>
      27              : #include <utils/common/ToString.h>
      28              : #include "CSVFormatter.h"
      29              : 
      30              : 
      31              : // ===========================================================================
      32              : // member method definitions
      33              : // ===========================================================================
      34           41 : CSVFormatter::CSVFormatter(const std::string& columnNames, const char separator)
      35           41 :     : OutputFormatter(OutputFormatterType::CSV), myHeaderFormat(columnNames), mySeparator(separator) {
      36           41 :     if (myHeaderFormat == "none") {
      37            0 :         myWroteHeader = true;
      38              :     }
      39           41 : }
      40              : 
      41              : 
      42              : bool
      43           85 : CSVFormatter::writeXMLHeader(std::ostream& into, const std::string& rootElement,
      44              :                              const std::map<SumoXMLAttr, std::string>& attrs, bool /* writeMetadata */,
      45              :                              bool /* includeConfig */) {
      46           85 :     if (attrs.size() > 2) {
      47           13 :         myHaveRootAttrs = true;
      48           13 :         openTag(into, rootElement);
      49           52 :         for (const auto& a : attrs) {
      50           39 :             if (a.first != SUMO_ATTR_XMLNS && a.first != SUMO_ATTR_SCHEMA_LOCATION) {
      51           13 :                 writeAttr(into, a.first, a.second, false, false);
      52              :             }
      53              :         }
      54              :         return true;
      55              :     }
      56              :     return false;
      57              : }
      58              : 
      59              : 
      60              : void
      61         6580 : CSVFormatter::openTag(std::ostream& /* into */, const std::string& xmlElement) {
      62         6580 :     myXMLStack.push_back({xmlElement, (int)myValues.size()});
      63         6580 : }
      64              : 
      65              : 
      66              : void
      67        13528 : CSVFormatter::openTag(std::ostream& /* into */, const SumoXMLTag& xmlElement) {
      68        13528 :     myXMLStack.push_back({toString(xmlElement), (int)myValues.size()});
      69        13528 : }
      70              : 
      71              : 
      72              : bool
      73        20136 : CSVFormatter::closeTag(std::ostream& into, const std::string& /* comment */) {
      74        20136 :     if (myMaxDepth == 0) {
      75              :         // the auto detection case: the first closed tag determines the depth
      76            0 :         myMaxDepth = (int)myXMLStack.size();
      77              :     }
      78        20136 :     const bool eof = myXMLStack.empty() || (myHaveRootAttrs && myXMLStack.size() == 1);
      79        20136 :     if ((myMaxDepth == (int)myXMLStack.size() || eof) && !myWroteHeader) {
      80              :         // First complete row or EOF: write the header
      81           41 :         if (!myCheckColumns) {
      82           68 :             WRITE_WARNING("Column based formats are still experimental. Autodetection only works for homogeneous output.");
      83              :         }
      84           41 :         bool full = myHeaderFormat == "full";
      85           41 :         if (myHeaderFormat == "auto") {
      86           41 :             const std::set<std::string> uniq(myHeader.begin(), myHeader.end());
      87           41 :             full = uniq.size() < myHeader.size();
      88              :         }
      89              : #ifdef HAVE_FMT
      90              :         fmt::print(into, "{}\n", fmt::join(full ? myFullHeader : myHeader, std::string_view(&mySeparator, 1)));
      91              : #else
      92           82 :         into << joinToString(full ? myFullHeader : myHeader, mySeparator) << "\n";
      93              : #endif
      94           41 :         myWroteHeader = true;
      95              :     }
      96        20136 :     if (myNeedsWrite) {
      97        16013 :         myValues.resize(myHeader.size());
      98              : #ifdef HAVE_FMT
      99              :         const std::string row = fmt::format("{}", fmt::join(myValues, std::string_view(&mySeparator, 1)));
     100              : #else
     101        16013 :         const std::string row = joinToString(myValues, mySeparator);
     102              : #endif
     103        16013 :         myBufferedRows.emplace_back(row);
     104              :         mySeenAttrs.reset();
     105        16013 :         myNeedsWrite = false;
     106              :     }
     107        20136 :     if (myWroteHeader && !myBufferedRows.empty()) {
     108        17691 :         for (const std::string& row : myBufferedRows) {
     109        16013 :             into << row << '\n';
     110              :         }
     111              :         myBufferedRows.clear();
     112              :     }
     113        20136 :     if (!eof) {
     114        20095 :         if ((int)myValues.size() > myXMLStack.back().second) {
     115        19896 :             myValues.resize(myXMLStack.back().second);
     116              :         }
     117              :         myXMLStack.pop_back();
     118        20095 :         return true;
     119              :     }
     120              :     return false;
     121              : }
     122              : 
     123              : 
     124              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1