LCOV - code coverage report
Current view: top level - core - string.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 73 89 82.0 %
Date: 2024-04-28 01:25:40 Functions: 21 24 87.5 %

          Line data    Source code
       1             : // SPDX-License-Identifier: BSD-3-Clause
       2             : // Copyright (c) 2023 Scipp contributors (https://github.com/scipp)
       3             : /// @file
       4             : /// @author Simon Heybrock
       5             : #include <chrono>
       6             : #include <iomanip>
       7             : #include <mutex>
       8             : #include <sstream>
       9             : 
      10             : #include "scipp/units/unit.h"
      11             : 
      12             : #include "scipp/core/dimensions.h"
      13             : #include "scipp/core/except.h"
      14             : #include "scipp/core/slice.h"
      15             : #include "scipp/core/string.h"
      16             : #include "scipp/core/time_point.h"
      17             : 
      18             : namespace scipp::core {
      19             : 
      20          12 : std::ostream &operator<<(std::ostream &os, const Dimensions &dims) {
      21          12 :   return os << to_string(dims);
      22             : }
      23             : 
      24         158 : std::ostream &operator<<(std::ostream &os, const scipp::index_pair &index) {
      25         158 :   return os << to_string(index);
      26             : }
      27             : 
      28        1082 : std::string to_string(const Dimensions &dims) {
      29        1082 :   if (dims.empty())
      30         294 :     return "()";
      31         788 :   std::string s = "(";
      32        1768 :   for (int32_t i = 0; i < scipp::size(dims.shape()); ++i)
      33        1960 :     s += to_string(dims.labels()[i]) + ": " + std::to_string(dims.shape()[i]) +
      34         980 :          ", ";
      35         788 :   s.resize(s.size() - 2);
      36         788 :   s += ")";
      37         788 :   return s;
      38         788 : }
      39             : 
      40           0 : std::string labels_to_string(const Dimensions &dims) {
      41           0 :   if (dims.empty())
      42           0 :     return "()";
      43           0 :   std::string s = "(";
      44           0 :   for (const auto &dim : dims.labels())
      45           0 :     s += to_string(dim) + ", ";
      46           0 :   s.resize(s.size() - 2);
      47           0 :   s += ")";
      48           0 :   return s;
      49           0 : }
      50             : 
      51         340 : std::string to_string(const Sizes &sizes) {
      52         340 :   std::string repr("Sizes[");
      53        1227 :   for (const auto &dim : sizes)
      54         547 :     repr += to_string(dim) + ":" + std::to_string(sizes[dim]) + ", ";
      55         340 :   repr += "]";
      56         340 :   return repr;
      57           0 : }
      58             : 
      59          27 : const std::string &to_string(const std::string &s) { return s; }
      60           0 : std::string_view to_string(const std::string_view &s) { return s; }
      61           0 : std::string to_string(const char *s) { return std::string(s); }
      62             : 
      63          76 : std::string to_string(const bool b) { return b ? "True" : "False"; }
      64             : 
      65        3895 : std::string to_string(const DType dtype) {
      66        3895 :   return dtypeNameRegistry().at(dtype);
      67             : }
      68             : 
      69         104 : std::string to_string(const Slice &slice) {
      70         144 :   std::string end = slice.end() >= 0 ? ", " + std::to_string(slice.end()) : "";
      71         208 :   return "Slice(" + to_string(slice.dim()) + ", " +
      72         520 :          std::to_string(slice.begin()) + end + ')';
      73         104 : }
      74             : 
      75         158 : std::string to_string(const scipp::index_pair &index) {
      76         316 :   return '(' + std::to_string(index.first) + ", " +
      77         474 :          std::to_string(index.second) + ')';
      78             : }
      79             : 
      80        4208 : std::map<DType, std::string> &dtypeNameRegistry() {
      81        4208 :   static std::map<DType, std::string> registry;
      82        4208 :   return registry;
      83             : }
      84             : 
      85             : namespace {
      86           5 : template <class Ratio> constexpr int64_t num_digits() {
      87             :   static_assert(Ratio::num == 1 || Ratio::num % 10 == 0);
      88             :   static_assert(Ratio::den == 1 || Ratio::den % 10 == 0);
      89             :   static_assert(Ratio::den > Ratio::num);
      90           5 :   int64_t result = 0;
      91          32 :   for (std::size_t i = Ratio::num; i < Ratio::den; i *= 10) {
      92          27 :     ++result;
      93             :   }
      94           5 :   return result;
      95             : }
      96             : 
      97             : // For synchronizing access to gmtime because its return value is shared.
      98             : std::mutex gmtime_mutex;
      99             : 
     100          17 : void put_time(std::ostream &os, const std::time_t time_point,
     101             :               const bool include_time) {
     102          17 :   std::lock_guard guard_{gmtime_mutex};
     103          17 :   const std::tm *tm = std::gmtime(&time_point);
     104          17 :   if (include_time)
     105          17 :     os << std::put_time(tm, "%FT%T");
     106             :   else
     107           0 :     os << std::put_time(tm, "%F");
     108          17 : }
     109             : 
     110             : template <class Rep, class Period>
     111          17 : std::string to_string(const std::chrono::duration<Rep, Period> &duration) {
     112             :   using Clock = std::chrono::system_clock;
     113             : 
     114          17 :   std::ostringstream oss;
     115             : 
     116             : #ifdef _WIN32
     117             :   // Windows' time functions (e.g. gmtime) don't support datetimes before 1970.
     118             :   if (duration < std::chrono::duration<Rep, Period>::zero()) {
     119             :     return "(datetime before 1970, cannot format)";
     120             :   }
     121             : #endif
     122             : 
     123             :   // Cast to seconds to be independent of clock precision.
     124             :   // Sub-second digits are formatted manually.
     125          17 :   put_time(oss,
     126          17 :            Clock::to_time_t(Clock::time_point{
     127          17 :                std::chrono::duration_cast<std::chrono::seconds>(duration)}),
     128             :            true);
     129             :   if constexpr (std::ratio_less_v<Period, std::ratio<1, 1>>) {
     130           5 :     oss << '.' << std::setw(num_digits<Period>()) << std::setfill('0')
     131           5 :         << (duration.count() % (Period::den / Period::num));
     132             :   }
     133          34 :   return oss.str();
     134          17 : }
     135             : } // namespace
     136             : 
     137          20 : std::string to_iso_date(const scipp::core::time_point &item,
     138             :                         const units::Unit &unit) {
     139          20 :   if (unit == units::ns) {
     140           2 :     return to_string(std::chrono::nanoseconds{item.time_since_epoch()});
     141          19 :   } else if (unit == units::s) {
     142          16 :     return to_string(std::chrono::seconds{item.time_since_epoch()});
     143          11 :   } else if (unit == units::us) {
     144           4 :     return to_string(std::chrono::microseconds{item.time_since_epoch()});
     145           9 :   } else if (unit == units::Unit(llnl::units::precise::ms)) {
     146           4 :     return to_string(std::chrono::milliseconds{item.time_since_epoch()});
     147           7 :   } else if (unit == units::Unit(llnl::units::precise::min)) {
     148           4 :     return to_string(std::chrono::minutes{item.time_since_epoch()});
     149           5 :   } else if (unit == units::Unit(llnl::units::precise::hr)) {
     150           4 :     return to_string(std::chrono::hours{item.time_since_epoch()});
     151           3 :   } else if (unit == units::Unit(llnl::units::precise::day) ||
     152           6 :              unit == units::Unit("month") || unit == units::Unit("year")) {
     153           0 :     throw except::UnitError("Printing of time points with units greater than "
     154           0 :                             "hours is not yet implemented.");
     155             :   }
     156           3 :   throw except::UnitError("Cannot display time point, unsupported unit: " +
     157           6 :                           to_string(unit));
     158             : }
     159             : } // namespace scipp::core

Generated by: LCOV version 1.14