Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 10:10:50

0001 // @(#)root/base
0002 // Author: Philippe Canal 12/2015
0003 
0004 /*************************************************************************
0005  * Copyright (C) 1995-2015, Rene Brun and Fons Rademakers.               *
0006  * All rights reserved.                                                  *
0007  *                                                                       *
0008  * For the licensing terms see $ROOTSYS/LICENSE.                         *
0009  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
0010  *************************************************************************/
0011 
0012 #ifndef ROOT_StringConv
0013 #define ROOT_StringConv
0014 
0015 
0016 #include <string_view>
0017 #include "Rtypes.h"
0018 #include "RConfigure.h"
0019 #include <cmath>
0020 
0021 namespace ROOT {
0022 
0023    // Adapted from http://stackoverflow.com/questions/3758606/
0024    // how-to-convert-byte-size-into-human-readable-format-in-java
0025    // and http://agentzlerich.blogspot.com/2011/01/converting-to-and-from-human-readable.html
0026    // However those sources use the 'conventional' 'legacy' nomenclature,
0027    // rather than the official Standard Units.  See
0028    // http://physics.nist.gov/cuu/Units/binary.html
0029    // and http://www.dr-lex.be/info-stuff/bytecalc.html for example.
0030 
0031 ///////////////////////////////////////////////////////////////////////////////
0032 /// Return the size expressed in 'human readable' format.
0033 /// \param bytes the size in bytes to be converted
0034 /// \param si whether to use the SI units or not.
0035 /// \param coeff return the size expressed in the new unit.
0036 /// \param units return a pointer to the string representation of the new unit
0037 template <typename value_type>
0038 void ToHumanReadableSize(value_type bytes,
0039                          Bool_t si,
0040                          Double_t *coeff,
0041                          const char **units)
0042 {
0043    // Static lookup table of byte-based SI units
0044    static const char *const suffix[][2] =
0045    { { "B",  "B"   },
0046      { "KB", "KiB" },
0047      { "MB", "MiB" },
0048      { "GB", "GiB" },
0049      { "TB", "TiB" },
0050      { "EB", "EiB" },
0051      { "ZB", "ZiB" },
0052      { "YB", "YiB" } };
0053    value_type unit = si ? 1000 : 1024;
0054    int exp = 0;
0055    if (bytes == unit) {
0056       // On some 32bit platforms, the result of
0057       //    (int) (std::log(bytes) / std::log(unit)
0058       // in the case of bytes==unit ends up surprisingly to be zero
0059       // rather than one, so 'hard code' the result
0060       exp = 1;
0061    } else if (bytes > 0) {
0062       exp = std::min( (int) (std::log(bytes) / std::log(unit)),
0063                      (int) (sizeof(suffix) / sizeof(suffix[0]) - 1));
0064    }
0065    *coeff = bytes / std::pow(unit, exp);
0066    *units  = suffix[exp][!si];
0067 }
0068 
0069 enum class EFromHumanReadableSize {
0070    kSuccess,
0071    kParseFail,
0072    kOverflow
0073 };
0074 
0075 ///////////////////////////////////////////////////////////////////////////////
0076 /// Convert strings like the following into byte counts
0077 ///    5MB, 5 MB, 5M, 3.7GB, 123b, 456kB, 3.7GiB, 5MiB
0078 /// with some amount of forgiveness baked into the parsing.
0079 /// For this routine we use the official SI unit where the [i] is reserved
0080 /// for the 'legacy' power of two units.  1KB = 1000 bytes, 1KiB = 1024 bytes.
0081 /// \param str the string to be parsed
0082 /// \param value will be updated with the result if and only if the parse is successful and does not overflow for the type of value.
0083 /// \return return a EFromHumanReadableSize enum value indicating the success or failure of the parse.
0084 ///
0085 template <typename T>
0086 EFromHumanReadableSize FromHumanReadableSize(std::string_view str, T &value)
0087 {
0088    try {
0089       size_t cur, size = str.size();
0090       // Parse leading numeric factor
0091       const double coeff = stod(std::string(str.data(), str.size()), &cur);
0092 
0093       // Skip any intermediate white space
0094       while (cur<size && isspace(str[cur])) ++cur;
0095 
0096       // Read off first character which should be an SI prefix
0097       int exp = 0, unit = 1000;
0098 
0099       auto result = [coeff,&exp,&unit,&value]() {
0100          double v = exp ? coeff * std::pow(unit, exp / 3) : coeff;
0101          if (v < (double) std::numeric_limits<T>::max()) {
0102             value = (T)v;
0103             return EFromHumanReadableSize::kSuccess;
0104          } else {
0105             return EFromHumanReadableSize::kOverflow;
0106          }
0107       };
0108       if (cur==size) return result();
0109 
0110       switch (toupper(str[cur])) {
0111          case 'B':  exp =  0; break;
0112          case 'K':  exp =  3; break;
0113          case 'M':  exp =  6; break;
0114          case 'G':  exp =  9; break;
0115          case 'T':  exp = 12; break;
0116          case 'E':  exp = 15; break;
0117          case 'Z':  exp = 18; break;
0118          case 'Y':  exp = 21; break;
0119 
0120          default:   return EFromHumanReadableSize::kParseFail;
0121       }
0122       ++cur;
0123 
0124       // If an 'i' or 'I' is present use non-SI factor-of-1024 units
0125       if (cur<size && toupper(str[cur]) == 'I') {
0126          ++cur;
0127          unit = 1024;
0128       }
0129 
0130       if (cur==size) return result();
0131 
0132       // Next character must be one of B/empty/whitespace
0133       switch (toupper(str[cur])) {
0134          case 'B':
0135          case ' ':
0136          case '\t': ++cur;  break;
0137 
0138          case '\0': return result();
0139 
0140          default:   return EFromHumanReadableSize::kParseFail;
0141       }
0142 
0143       // Skip any remaining white space
0144       // while (cur<size && isspace(str[cur])) ++cur;
0145 
0146       // Do not:
0147       // Parse error on anything but a null terminator
0148       // if (cur<size) return -1;
0149 
0150       return result();
0151    } catch (...) {
0152       return EFromHumanReadableSize::kParseFail;
0153    }
0154 
0155 }
0156 
0157 } // namespace ROOT.
0158 
0159 #endif // ROOT_StringConv