StringUtil.h
``````#ifndef STRINGUTIL_H
#define STRINGUTIL_H 1

#include <cassert>
#include <iomanip>
#include <sstream>
#include <string>
#include <cmath>

/** Return the last character of s and remove it. */
static inline char chop(std::string& s)
{
assert(s.length() > 1);
unsigned back = s.length() - 1;
char c = s[back];
s.erase(back);
return c;
}

/** If the last character of s is c, remove it and return true. */
static inline bool chomp(std::string& s, char c = '\n')
{
unsigned back = s.length() - 1;
if (!s.empty() && s[back] == c) {
s.erase(back);
return true;
} else
return false;
}

/** Return the SI representation of n. */
static inline std::string toSI(double n)
{
std::ostringstream s;
s << std::setprecision(3);
if (n < 1e3)
s << n << ' ';
else if (n < 1e6)
s << n/1e3 << " k";
else if (n < 1e9)
s << n/1e6 << " M";
else if (n < 1e12)
s << n/1e9 << " G";
else
s << n/1e12 << " T";
return s.str();
}

/** Return the SI representation of a number in bytes. */
static inline std::string bytesToSI(size_t n)
{
std::ostringstream s;
s << std::setprecision(3);
if (n < 1024)
s << n;
else if (n < (1ULL<<20))
s << (double)n/(1ULL<<10) << "k";
else if (n < (1ULL<<30))
s << (double)n/(1ULL<<20) << "M";
else
s << (double)n/(1ULL<<30) << "G";
return s.str();
}

/**
* Convert a quantity with SI units to the equivalent floating
* point number.
*/
static inline double fromSI(std::istringstream& iss)
{
double size;
std::string units;

iss >> size;
if (iss.fail()) {
// not prefixed by a number
return 0;
}

iss >> units;
if (iss.fail() && iss.eof()) {
// no units given; clear fail flag
// and just return the number
iss.clear(std::ios::eofbit);
return size;
}

if (units.size() > 1) {
// unrecognized multichar suffix
iss.setstate(std::ios::failbit);
return 0;
}

switch(tolower(units[0])) {
case 'k':
size *= 1000ULL;
break;
case 'm':
size *= 1000ULL*1000;
break;
case 'g':
size *= 1000ULL*1000*1000;
break;
case 't':
size *= 1000ULL*1000*1000*1000;
break;
default:
iss.setstate(std::ios::failbit);
return 0;
}

return size;
}

/**
* Convert a quantity with SI units to the equivalent floating
* point number.
*/
static inline double fromSI(const std::string& str)
{
std::istringstream iss(str);
return fromSI(iss);
}

/** Return the engineering string representation of n. */
template <typename T>
static inline std::string toEng(T n)
{
std::ostringstream s;
s << std::setprecision(4);
if (n < 10000000)
s << n;
else if (n < 1e9)
s << n/1e6 << "e6";
else if (n < 1e12)
s << n/1e9 << "e9";
else
s << n/1e12 << "e12";
return s.str();
}

/** Return true if the second string is a prefix of the string s. */
template <size_t N>
bool startsWith(const std::string& s, const char (&prefix)[N])
{
size_t n = N - 1;
return s.size() > n && equal(s.begin(), s.begin() + n, prefix);
}

/** Return true if the second string is a suffix of the string s. */
template <size_t N>
bool endsWith(const std::string& s, const char (&suffix)[N])
{
size_t n = N - 1;
return s.size() > n && equal(s.end() - n, s.end(), suffix);
}

/** Return true if the second string is a suffix of the string s. */
static inline
bool endsWith(const std::string& s, const std::string& suffix)
{
size_t n = suffix.size();
return s.size() > n && equal(s.end() - n, s.end(),
suffix.begin());
}

static inline
bool isReadNamePair(const std::string& name1, const std::string& name2)
{
assert(!name1.empty() && !name2.empty());

if (name1 == name2)
return true;

if (endsWith(name1,"/1") && endsWith(name2,"/2")) {
int len1 = name1.length();
int len2 = name2.length();
assert(len1 > 2 && len2 > 2);
return name1.compare(0, len1-2, name2, 0, len2-2) == 0;
}

return false;
}

static inline size_t SIToBytes(std::istringstream& iss)
{
double size;
std::string units;

iss >> size;
if (iss.fail()) {
// not prefixed by a number
return 0;
}

iss >> units;
if (iss.fail() && iss.eof()) {
// no units given; clear fail flag
// and assume bytes
iss.clear(std::ios::eofbit);
return (size_t)ceil(size);
}

if (units.size() > 1) {
// unrecognized multichar suffix
iss.setstate(std::ios::failbit);
return 0;
}

switch(tolower(units[0])) {
case 'k':
size *= (size_t)1<<10;
break;
case 'm':
size *= (size_t)1<<20;
break;
case 'g':
size *= (size_t)1<<30;
break;
default:
iss.setstate(std::ios::failbit);
return 0;
}

return (size_t)ceil(size);
}

static inline size_t SIToBytes(const std::string& str)
{
std::istringstream iss(str);
return SIToBytes(iss);
}

#endif
``````