From 0fa128bbd0a53a3428fa2028b8754e15c9ef7c38 Mon Sep 17 00:00:00 2001 From: Andreas Hansson Date: Sat, 20 Sep 2014 17:17:49 -0400 Subject: [PATCH] base: Clean up redundant string functions and use C++11 This patch does a bit of housekeeping on the string helper functions and relies on the C++11 standard library where possible. It also does away with our custom string hash as an implementation is already part of the standard library. --- src/base/statistics.hh | 6 +- src/base/stats/text.cc | 8 +- src/base/str.cc | 272 ------------------------------------ src/base/str.hh | 116 +++++++++++---- src/cpu/o3/lsq_unit_impl.hh | 2 +- src/dev/uart8250.cc | 1 - src/sim/serialize.cc | 19 +-- 7 files changed, 97 insertions(+), 327 deletions(-) diff --git a/src/base/statistics.hh b/src/base/statistics.hh index 7e5f1f5b9..1b3d0fc54 100644 --- a/src/base/statistics.hh +++ b/src/base/statistics.hh @@ -741,7 +741,7 @@ class ScalarBase : public DataWrap class ProxyInfo : public ScalarInfo { public: - std::string str() const { return to_string(value()); } + std::string str() const { return std::to_string(value()); } size_type size() const { return 1; } bool check() const { return true; } void prepare() { } @@ -2170,7 +2170,7 @@ class ConstNode : public Node const VResult &result() const { return vresult; } Result total() const { return vresult[0]; }; size_type size() const { return 1; } - std::string str() const { return to_string(vresult[0]); } + std::string str() const { return std::to_string(vresult[0]); } }; template @@ -2200,7 +2200,7 @@ class ConstVectorNode : public Node size_type size = this->size(); std::string tmp = "("; for (off_type i = 0; i < size; i++) - tmp += csprintf("%s ",to_string(vresult[i])); + tmp += csprintf("%s ", std::to_string(vresult[i])); tmp += ")"; return tmp; } diff --git a/src/base/stats/text.cc b/src/base/stats/text.cc index 2c5b004be..efe43c602 100644 --- a/src/base/stats/text.cc +++ b/src/base/stats/text.cc @@ -284,7 +284,7 @@ VectorPrint::operator()(std::ostream &stream) const // the case where there are no subnames) and append it to the // base name. if (forceSubnames) - print.name = base + (havesub ? subnames[0] : to_string(0)); + print.name = base + (havesub ? subnames[0] : std::to_string(0)); print.value = vec[0]; print(stream); return; @@ -300,7 +300,7 @@ VectorPrint::operator()(std::ostream &stream) const if (havesub && (i >= subnames.size() || subnames[i].empty())) continue; - print.name = base + (havesub ? subnames[i] : to_string(i)); + print.name = base + (havesub ? subnames[i] : std::to_string(i)); print.desc = subdescs.empty() ? desc : subdescs[i]; print.update(vec[i], _total); @@ -355,7 +355,7 @@ DistPrint::DistPrint(const Text *text, const VectorDistInfo &info, int i) init(text, info); name = info.name + "_" + - (info.subnames[i].empty() ? (to_string(i)) : info.subnames[i]); + (info.subnames[i].empty() ? (std::to_string(i)) : info.subnames[i]); if (!info.subdescs[i].empty()) desc = info.subdescs[i]; @@ -605,7 +605,7 @@ Text::visit(const Vector2dInfo &info) } print.name = info.name + "_" + - (havesub ? info.subnames[i] : to_string(i)); + (havesub ? info.subnames[i] : std::to_string(i)); print.desc = info.desc; print.vec = yvec; print.total = total; diff --git a/src/base/str.cc b/src/base/str.cc index 45d3107b0..849bc8afa 100644 --- a/src/base/str.cc +++ b/src/base/str.cc @@ -28,14 +28,9 @@ * Authors: Nathan Binkert */ -#include -#include -#include -#include #include #include -#include "base/intmath.hh" #include "base/str.hh" using namespace std; @@ -106,270 +101,3 @@ tokenize(vector& v, const string &s, char token, bool ignore) v.push_back(s.substr(first)); } - -/** - * @todo This function will not handle the smallest negative decimal - * value for a signed type - */ - -template -inline bool -__to_number(string value, T &retval) -{ - static const T maxnum = ((T)-1); - static const bool sign = numeric_limits::is_signed; - static const int bits = numeric_limits::digits; - static const T hexmax = maxnum & (((T)1 << (bits - 4)) - 1); - static const T octmax = maxnum & (((T)1 << (bits - 3)) - 1); - static const T signmax = numeric_limits::max(); - static const T decmax = signmax / 10; - -#if 0 - cout << "maxnum = 0x" << hex << (unsigned long long)maxnum << "\n" - << "sign = 0x" << hex << (unsigned long long)sign << "\n" - << "hexmax = 0x" << hex << (unsigned long long)hexmax << "\n" - << "octmax = 0x" << hex << (unsigned long long)octmax << "\n" - << "signmax = 0x" << hex << (unsigned long long)signmax << "\n" - << "decmax = 0x" << hex << (unsigned long long)decmax << "\n"; -#endif - - eat_white(value); - - bool negative = false; - bool hex = false; - bool oct = false; - int last = value.size() - 1; - retval = 0; - int i = 0; - - char c = value[i]; - if (!isDec(c)) { - if (c == '-' && sign) - negative = true; - else - return false; - } - else { - retval += c - '0'; - if (last == 0) return true; - } - - if (c == '0') - oct = true; - - c = value[++i]; - if (oct) { - if (sign && negative) - return false; - - if (!isOct(c)) { - if (c == 'X' || c == 'x') { - hex = true; - oct = false; - } else - return false; - } - else - retval += c - '0'; - } else if (!isDec(c)) - goto multiply; - else { - if (sign && negative && c == '0') - return false; - - retval *= 10; - retval += c - '0'; - if (last == 1) { - if (sign && negative) retval = -retval; - return true; - } - } - - if (hex) { - if (last == 1) - return false; - - for (i = 2; i <= last ; i++) { - c = value[i]; - if (!isHex(c)) - return false; - - if (retval > hexmax) return false; - retval *= 16; - retval += hex2Int(c); - } - return true; - } else if (oct) { - for (i = 2; i <= last ; i++) { - c = value[i]; - if (!isOct(c)) - return false; - - if (retval > octmax) return false; - retval *= 8; - retval += (c - '0'); - } - return true; - } - - for (i = 2; i < last ; i++) { - c = value[i]; - if (!isDec(c)) - goto multiply; - - if (retval > decmax) return false; - bool atmax = retval == decmax; - retval *= 10; - retval += c - '0'; - if (atmax && retval < decmax) return false; - if (sign && (retval & ((T)1 << (sizeof(T) * 8 - 1)))) - return false; - } - - c = value[last]; - if (isDec(c)) { - - if (retval > decmax) return false; - bool atmax = retval == decmax; - retval *= 10; - retval += c - '0'; - if (atmax && retval < decmax) return false; - if (sign && negative) { - if ((retval & ((T)1 << (sizeof(T) * 8 - 1))) && - retval >= (T)-signmax) - return false; - retval = -retval; - } - else - if (sign && (retval & ((T)1 << ((sizeof(T) * 8) - 1)))) - return false; - return true; - } - - multiply: - signed long long mult = 1; - T val; - switch (c) { - case 'k': - case 'K': - if (i != last) return false; - mult = 1024; - val = signmax / mult; - break; - case 'm': - case 'M': - if (i != last) return false; - mult = 1024 * 1024; - val = signmax / mult; - break; - case 'g': - case 'G': - if (i != last) return false; - mult = 1024 * 1024 * 1024; - val = signmax / mult; - break; - case 'e': - case 'E': - if (i >= last) return false; - - mult = 0; - for (i++; i <= last; i++) { - c = value[i]; - if (!isDec(c)) - return false; - - mult *= 10; - mult += c - '0'; - } - - for (i = 0; i < mult; i++) { - if (retval > signmax / 10) - return false; - retval *= 10; - if (sign && (retval & ((T)1 << (sizeof(T) * 8 - 1)))) - return false; - } - if (sign && negative) { - if ((retval & ((T)1 << (sizeof(T) * 8 - 1))) && - retval >= (T)-signmax) - return false; - retval = -retval; - } - else - if (sign && (retval & ((T)1 << ((sizeof(T) * 8) - 1)))) - return false; - - return true; - - default: - return false; - } - - if (sign && negative) - return false; - - if (mult > (unsigned long long)signmax) - return false; - - if (retval > val) - return false; - - retval *= mult; - - return true; -} - -#define STN(type) \ -template<> \ -bool to_number(const string &value, type &retval) \ -{ return __to_number(value, retval); } - -STN(unsigned long long) -STN(signed long long) -STN(unsigned long) -STN(signed long) -STN(unsigned int) -STN(signed int) -STN(unsigned short) -STN(signed short) -STN(unsigned char) -STN(signed char) -STN(char) - -template<> -bool to_number(const string &value, bool &retval) -{ - string lowered = to_lower(value); - - if (value == "0") { - retval = false; - return true; - } - - if (value == "1"){ - retval = true; - return true; - } - - if (lowered == "false") { - retval = false; - return true; - } - - if (lowered == "true"){ - retval = true; - return true; - } - - if (lowered == "no") { - retval = false; - return true; - } - - if (lowered == "yes"){ - retval = true; - return true; - } - - return false; -} diff --git a/src/base/str.hh b/src/base/str.hh index b3f3153ec..d73058bc0 100644 --- a/src/base/str.hh +++ b/src/base/str.hh @@ -29,31 +29,16 @@ * Steve Reinhardt */ -#ifndef __STR_HH__ -#define __STR_HH__ +#ifndef __BASE_STR_HH__ +#define __BASE_STR_HH__ -#include #include -#include +#include +#include +#include #include #include -template class Hash; -template<> -class Hash { -public: - unsigned operator()(const std::string &s) { - std::string::const_iterator i = s.begin(); - std::string::const_iterator end = s.end(); - unsigned hash = 5381; - - while (i < end) - hash = ((hash << 5) + hash) + *i++; - - return hash; - } -}; - inline void eat_lead_white(std::string &s) { @@ -87,8 +72,8 @@ to_lower(const std::string &s) lower.reserve(len); - for (int i = 0; i < len; ++i) - lower.push_back(tolower(s[i])); + for (const auto &c : s) + lower.push_back(std::tolower(c)); return lower; } @@ -111,16 +96,87 @@ void tokenize(std::vector &vector, const std::string &s, char token, bool ign = true); -template bool -to_number(const std::string &value, T &retval); +/** + * @{ + * + * @name String to number helper functions for signed and unsigned + * integeral type, as well as floating-point types. + */ +template +typename std::enable_if::value && + std::is_signed::value, T>::type +__to_number(const std::string &value) +{ + // start big and narrow it down if needed, determine the base dynamically + long long r = std::stoll(value, nullptr, 0); + if (r < std::numeric_limits::min() || r > std::numeric_limits::max()) + throw std::out_of_range("Out of range"); + return static_cast(r); +} template -inline std::string -to_string(const T &value) +typename std::enable_if::value && + !std::is_signed::value, T>::type +__to_number(const std::string &value) { - std::stringstream str; - str << value; - return str.str(); + // start big and narrow it down if needed, determine the base dynamically + unsigned long long r = std::stoull(value, nullptr, 0); + if (r > std::numeric_limits::max()) + throw std::out_of_range("Out of range"); + return static_cast(r); +} + +template +typename std::enable_if::value, T>::type +__to_number(const std::string &value) +{ + // start big and narrow it down if needed + long double r = std::stold(value); + if (r < std::numeric_limits::min() || r > std::numeric_limits::max()) + throw std::out_of_range("Out of range"); + return static_cast(r); +} +/** @} */ + +/** + * Turn a string representation of a number, either integral or + * floating point, into an actual number. + * + * @param value The string representing the number + * @param retval The resulting value + * @return True if the parsing was successful + */ +template +inline bool +to_number(const std::string &value, T &retval) +{ + try { + retval = __to_number(value); + return true; + } catch (const std::out_of_range&) { + return false; + } catch (const std::invalid_argument&) { + return false; + } +} + +/** + * Turn a string representation of a boolean into a boolean value. + */ +inline bool +to_bool(const std::string &value, bool &retval) +{ + std::string s = to_lower(value); + + if (s == "true") { + retval = true; + return true; + } else if (s == "false") { + retval = false; + return true; + } + + return false; } // Put quotes around string arg if it contains spaces. @@ -172,4 +228,4 @@ startswith(const std::string &s, const std::string &prefix) } -#endif //__STR_HH__ +#endif //__BASE_STR_HH__ diff --git a/src/cpu/o3/lsq_unit_impl.hh b/src/cpu/o3/lsq_unit_impl.hh index b63a590fb..0be4f57c4 100644 --- a/src/cpu/o3/lsq_unit_impl.hh +++ b/src/cpu/o3/lsq_unit_impl.hh @@ -215,7 +215,7 @@ LSQUnit::name() const if (Impl::MaxThreads == 1) { return iewStage->name() + ".lsq"; } else { - return iewStage->name() + ".lsq.thread" + to_string(lsqID); + return iewStage->name() + ".lsq.thread" + std::to_string(lsqID); } } diff --git a/src/dev/uart8250.cc b/src/dev/uart8250.cc index dfaf9088d..40ee7d38f 100644 --- a/src/dev/uart8250.cc +++ b/src/dev/uart8250.cc @@ -36,7 +36,6 @@ #include #include "base/inifile.hh" -#include "base/str.hh" // for to_number #include "base/trace.hh" #include "config/the_isa.hh" #include "debug/Uart.hh" diff --git a/src/sim/serialize.cc b/src/sim/serialize.cc index 18af044d0..27bf87254 100644 --- a/src/sim/serialize.cc +++ b/src/sim/serialize.cc @@ -111,38 +111,25 @@ showParam(ostream &os, const unsigned char &value) } -// Use sscanf() for FP types as to_number() only handles integers template <> bool parseParam(const string &s, float &value) { - return (sscanf(s.c_str(), "%f", &value) == 1); + return to_number(s, value); } template <> bool parseParam(const string &s, double &value) { - return (sscanf(s.c_str(), "%lf", &value) == 1); + return to_number(s, value); } template <> bool parseParam(const string &s, bool &value) { - const string &ls = to_lower(s); - - if (ls == "true") { - value = true; - return true; - } - - if (ls == "false") { - value = false; - return true; - } - - return false; + return to_bool(s, value); } // Display bools as strings