#include <limits>
#include <cmath>
#include <sstream>
+#include <string_view>
using std::ostringstream;
-long long strict_strtoll(const char *str, int base, std::string *err)
+long long strict_strtoll(const std::string_view str, int base, std::string *err)
{
+ ostringstream errStr;
+ if (auto invalid = str.find_first_not_of("0123456789-+");
+ invalid != std::string_view::npos ||
+ invalid == 0) {
+ errStr << "The option value '" << str << "' contains invalid digits";
+ *err = errStr.str();
+ return 0;
+ }
char *endptr;
- std::string errStr;
errno = 0; /* To distinguish success/failure after call (see man page) */
- long long ret = strtoll(str, &endptr, base);
+ long long ret = strtoll(str.data(), &endptr, base);
- if (endptr == str) {
- errStr = "Expected option value to be integer, got '";
- errStr.append(str);
- errStr.append("'");
- *err = errStr;
+ if (endptr == str.data()) {
+ errStr << "Expected option value to be integer, got '" << str << "'";
+ *err = errStr.str();
return 0;
}
if ((errno == ERANGE && (ret == LLONG_MAX || ret == LLONG_MIN))
|| (errno != 0 && ret == 0)) {
- errStr = "The option value '";
- errStr.append(str);
- errStr.append("'");
- errStr.append(" seems to be invalid");
- *err = errStr;
- return 0;
- }
- if (*endptr != '\0') {
- errStr = "The option value '";
- errStr.append(str);
- errStr.append("'");
- errStr.append(" contains invalid digits");
- *err = errStr;
+ errStr << "The option value '" << str << "' seems to be invalid";
+ *err = errStr.str();
return 0;
}
*err = "";
return ret;
}
-int strict_strtol(const char *str, int base, std::string *err)
+long long strict_strtoll(const char *str, int base, std::string *err)
{
- std::string errStr;
+ return strict_strtoll(std::string_view(str), base, err);
+}
+
+int strict_strtol(const std::string_view str, int base, std::string *err)
+{
+ ostringstream errStr;
long long ret = strict_strtoll(str, base, err);
if (!err->empty())
return 0;
if ((ret < INT_MIN) || (ret > INT_MAX)) {
- errStr = "The option value '";
- errStr.append(str);
- errStr.append("'");
- errStr.append(" seems to be invalid");
- *err = errStr;
+ errStr << "The option value '" << str << "' seems to be invalid";
+ *err = errStr.str();
return 0;
}
return static_cast<int>(ret);
}
-double strict_strtod(const char *str, std::string *err)
+int strict_strtol(const char *str, int base, std::string *err)
+{
+ return strict_strtol(std::string_view(str), base, err);
+}
+
+double strict_strtod(const std::string_view str, std::string *err)
{
char *endptr;
+ ostringstream oss;
errno = 0; /* To distinguish success/failure after call (see man page) */
- double ret = strtod(str, &endptr);
+ double ret = strtod(str.data(), &endptr);
if (errno == ERANGE) {
- ostringstream oss;
oss << "strict_strtod: floating point overflow or underflow parsing '"
<< str << "'";
*err = oss.str();
return 0.0;
}
if (endptr == str) {
- ostringstream oss;
oss << "strict_strtod: expected double, got: '" << str << "'";
*err = oss.str();
return 0;
}
if (*endptr != '\0') {
- ostringstream oss;
oss << "strict_strtod: garbage at end of string. got: '" << str << "'";
*err = oss.str();
return 0;
return ret;
}
-float strict_strtof(const char *str, std::string *err)
+double strict_strtod(const char *str, std::string *err)
+{
+ return strict_strtod(std::string_view(str), err);
+}
+
+float strict_strtof(const std::string_view str, std::string *err)
{
char *endptr;
+ ostringstream oss;
errno = 0; /* To distinguish success/failure after call (see man page) */
- float ret = strtof(str, &endptr);
+ float ret = strtof(str.data(), &endptr);
if (errno == ERANGE) {
- ostringstream oss;
oss << "strict_strtof: floating point overflow or underflow parsing '"
<< str << "'";
*err = oss.str();
return 0.0;
}
if (endptr == str) {
- ostringstream oss;
oss << "strict_strtof: expected float, got: '" << str << "'";
*err = oss.str();
return 0;
}
if (*endptr != '\0') {
- ostringstream oss;
oss << "strict_strtof: garbage at end of string. got: '" << str << "'";
*err = oss.str();
return 0;
return ret;
}
+float strict_strtof(const char *str, std::string *err)
+{
+ return strict_strtof(std::string_view(str), err);
+}
+
template<typename T>
-T strict_iec_cast(const char *str, std::string *err)
+T strict_iec_cast(const std::string_view str, std::string *err)
{
- std::string s(str);
- if (s.empty()) {
+ if (str.empty()) {
*err = "strict_iecstrtoll: value not specified";
return 0;
}
- char &u = s.back();
- // consume 'i' if present, fail if "Bi" is passed
- if ( u == 'i') {
- s.pop_back();
- u = s.back();
- if (u == 'B') {
- *err = "strict_iecstrtoll: illegal prefix \"Bi\"";
+ // get a view of the unit and of the value
+ std::string_view unit;
+ std::string_view n = str;
+ size_t u = str.find_first_not_of("0123456789-+");
+ int m = 0;
+ // deal with unit prefix is there is one
+ if (u != std::string_view::npos) {
+ n = str.substr(0, u);
+ unit = str.substr(u, str.length() - u);
+ // we accept both old si prefixes as well as the proper iec prefixes
+ // i.e. K, M, ... and Ki, Mi, ...
+ if (unit.back() == 'i') {
+ if (unit.front() == 'B') {
+ *err = "strict_iecstrtoll: illegal prefix \"Bi\"";
+ return 0;
+ }
+ }
+ if (unit.length() > 2) {
+ *err = "strict_iecstrtoll: illegal prefix (length > 2)";
return 0;
}
+ switch(unit.front()) {
+ case 'K':
+ m = 10;
+ break;
+ case 'M':
+ m = 20;
+ break;
+ case 'G':
+ m = 30;
+ break;
+ case 'T':
+ m = 40;
+ break;
+ case 'P':
+ m = 50;
+ break;
+ case 'E':
+ m = 60;
+ break;
+ case 'B':
+ break;
+ default:
+ *err = "strict_iecstrtoll: unit prefix not recognized";
+ return 0;
+ }
}
- int m = 0;
- if (u == 'B')
- m = 0;
- else if (u == 'K')
- m = 10;
- else if (u == 'M')
- m = 20;
- else if (u == 'G')
- m = 30;
- else if (u == 'T')
- m = 40;
- else if (u == 'P')
- m = 50;
- else if (u == 'E')
- m = 60;
- else
- m = -1;
-
- if (m >= 0)
- s.pop_back();
- else
- m = 0;
- long long ll = strict_strtoll(s.c_str(), 10, err);
+ long long ll = strict_strtoll(n, 10, err);
if (ll < 0 && !std::numeric_limits<T>::is_signed) {
*err = "strict_iecstrtoll: value should not be negative";
return 0;
}
if (static_cast<unsigned>(m) >= sizeof(T) * CHAR_BIT) {
*err = ("strict_iecstrtoll: the IEC prefix is too large for the designated "
- "type");
+ "type");
return 0;
}
using promoted_t = typename std::common_type<decltype(ll), T>::type;
return (ll << m);
}
+template int strict_iec_cast<int>(const std::string_view str, std::string *err);
+template long strict_iec_cast<long>(const std::string_view str, std::string *err);
+template long long strict_iec_cast<long long>(const std::string_view str, std::string *err);
+template uint64_t strict_iec_cast<uint64_t>(const std::string_view str, std::string *err);
+template uint32_t strict_iec_cast<uint32_t>(const std::string_view str, std::string *err);
+
+uint64_t strict_iecstrtoll(const std::string_view str, std::string *err)
+{
+ return strict_iec_cast<uint64_t>(str, err);
+}
+
+uint64_t strict_iecstrtoll(const char *str, std::string *err)
+{
+ return strict_iec_cast<uint64_t>(std::string_view(str), err);
+}
+
+template<typename T>
+T strict_iec_cast(const char *str, std::string *err)
+{
+ return strict_iec_cast<T>(std::string_view(str), err);
+}
+
template int strict_iec_cast<int>(const char *str, std::string *err);
template long strict_iec_cast<long>(const char *str, std::string *err);
template long long strict_iec_cast<long long>(const char *str, std::string *err);
template uint64_t strict_iec_cast<uint64_t>(const char *str, std::string *err);
template uint32_t strict_iec_cast<uint32_t>(const char *str, std::string *err);
-uint64_t strict_iecstrtoll(const char *str, std::string *err)
-{
- return strict_iec_cast<uint64_t>(str, err);
-}
-
template<typename T>
-T strict_si_cast(const char *str, std::string *err)
+T strict_si_cast(const std::string_view str, std::string *err)
{
- std::string s(str);
- if (s.empty()) {
+ if (str.empty()) {
*err = "strict_sistrtoll: value not specified";
return 0;
}
- char &u = s.back();
+ std::string_view n = str;
int m = 0;
- if (u == 'K')
- m = 3;
- else if (u == 'M')
- m = 6;
- else if (u == 'G')
- m = 9;
- else if (u == 'T')
- m = 12;
- else if (u == 'P')
- m = 15;
- else if (u == 'E')
- m = 18;
+ // deal with unit prefix is there is one
+ if (str.find_first_not_of("0123456789+-") != std::string_view::npos) {
+ const char &u = str.back();
+ if (u == 'K')
+ m = 3;
+ else if (u == 'M')
+ m = 6;
+ else if (u == 'G')
+ m = 9;
+ else if (u == 'T')
+ m = 12;
+ else if (u == 'P')
+ m = 15;
+ else if (u == 'E')
+ m = 18;
+ else if (u != 'B') {
+ *err = "strict_si_cast: unit prefix not recognized";
+ return 0;
+ }
- if (m >= 3)
- s.pop_back();
+ if (m >= 3)
+ n = str.substr(0, str.length() -1);
+ }
- long long ll = strict_strtoll(s.c_str(), 10, err);
+ long long ll = strict_strtoll(n, 10, err);
if (ll < 0 && !std::numeric_limits<T>::is_signed) {
*err = "strict_sistrtoll: value should not be negative";
return 0;
return (ll * pow (10, m));
}
-template int strict_si_cast<int>(const char *str, std::string *err);
-template long strict_si_cast<long>(const char *str, std::string *err);
-template long long strict_si_cast<long long>(const char *str, std::string *err);
-template uint64_t strict_si_cast<uint64_t>(const char *str, std::string *err);
-template uint32_t strict_si_cast<uint32_t>(const char *str, std::string *err);
+template int strict_si_cast<int>(const std::string_view str, std::string *err);
+template long strict_si_cast<long>(const std::string_view str, std::string *err);
+template long long strict_si_cast<long long>(const std::string_view str, std::string *err);
+template uint64_t strict_si_cast<uint64_t>(const std::string_view str, std::string *err);
+template uint32_t strict_si_cast<uint32_t>(const std::string_view str, std::string *err);
+
+uint64_t strict_sistrtoll(const std::string_view str, std::string *err)
+{
+ return strict_si_cast<uint64_t>(str, err);
+}
uint64_t strict_sistrtoll(const char *str, std::string *err)
{
return strict_si_cast<uint64_t>(str, err);
}
+
+template<typename T>
+T strict_si_cast(const char *str, std::string *err)
+{
+ return strict_si_cast<T>(std::string_view(str), err);
+}
+
+template int strict_si_cast<int>(const char *str, std::string *err);
+template long strict_si_cast<long>(const char *str, std::string *err);
+template long long strict_si_cast<long long>(const char *str, std::string *err);
+template uint64_t strict_si_cast<uint64_t>(const char *str, std::string *err);
+template uint32_t strict_si_cast<uint32_t>(const char *str, std::string *err);