// @(#)root/base // Author: Philippe Canal 12/2015 /************************************************************************* * Copyright (C) 1995-2015, Rene Brun and Fons Rademakers. * * All rights reserved. * * * * For the licensing terms see $ROOTSYS/LICENSE. * * For the list of contributors see $ROOTSYS/README/CREDITS. * *************************************************************************/ #ifndef ROOT_StringConv #define ROOT_StringConv #include "RStringView.h" #include "Rtypes.h" #include "RConfigure.h" #include namespace ROOT { // Adapted from http://stackoverflow.com/questions/3758606/ // how-to-convert-byte-size-into-human-readable-format-in-java // and http://agentzlerich.blogspot.com/2011/01/converting-to-and-from-human-readable.html // However those sources use the 'conventional' 'legacy' nomenclature, // rather than the official Standrard Units. See // http://physics.nist.gov/cuu/Units/binary.html // and http://www.dr-lex.be/info-stuff/bytecalc.html for example. /////////////////////////////////////////////////////////////////////////////// /// Return the size expressed in 'human readeable' format. /// \param bytes the size in bytes to be converted /// \param si whether to use the SI units or not. /// \param coeff return the size expressed in the new unit. /// \param units return a pointer to the string representation of the new unit template void ToHumanReadableSize(value_type bytes, Bool_t si, Double_t *coeff, const char **units) { // Static lookup table of byte-based SI units static const char *const suffix[][2] = { { "B", "B" }, { "KB", "KiB" }, { "MB", "MiB" }, { "GB", "GiB" }, { "TB", "TiB" }, { "EB", "EiB" }, { "ZB", "ZiB" }, { "YB", "YiB" } }; unsigned int unit = si ? 1000 : 1024; int exp = 0; if (bytes == unit) { // On some 32bit platforms, the result of // (int) (std::log(bytes) / std::log(unit) // in the case of bytes==unit ends up surpringly to be zero // rather than one, so 'hard code' the result exp = 1; } else if (bytes > 0) { exp = std::min( (int) (std::log(bytes) / std::log(unit)), (int) (sizeof(suffix) / sizeof(suffix[0]) - 1)); } *coeff = bytes / std::pow(unit, exp); *units = suffix[exp][!si]; } enum class EFromHumanReadableSize { kSuccess, kParseFail, kOverflow }; /////////////////////////////////////////////////////////////////////////////// /// Convert strings like the following into byte counts /// 5MB, 5 MB, 5M, 3.7GB, 123b, 456kB, 3.7GiB, 5MiB /// with some amount of forgiveness baked into the parsing. /// For this routine we use the official SI unit where the [i] is reserved /// for the 'legacy' power of two units. 1KB = 1000 bytes, 1KiB = 1024 bytes. /// \param str the string to be parsed /// \param value will be updated with the result if and only if the parse is sucessfull and does not overflow for the type of value. /// \return return a EFromHumanReadableSize enum value indicating the success or failure of the parse. /// template EFromHumanReadableSize FromHumanReadableSize(std::string_view str, T &value) { try { size_t size = str.size(); size_t cur; // Parse leading numeric factor const double coeff = stod(str, &cur); // Skip any intermediate white space while (cur::max()) { value = (T)v; return EFromHumanReadableSize::kSuccess; } else { return EFromHumanReadableSize::kOverflow; } }; if (cur==size) return result(); switch (toupper(str[cur])) { case 'B': exp = 0; break; case 'K': exp = 3; break; case 'M': exp = 6; break; case 'G': exp = 9; break; case 'T': exp = 12; break; case 'E': exp = 15; break; case 'Z': exp = 18; break; case 'Y': exp = 21; break; default: return EFromHumanReadableSize::kParseFail; } ++cur; // If an 'i' or 'I' is present use non-SI factor-of-1024 units if (cur