+static QTextStream& operator<<(QTextStream& stream, SIPrefix prefix)
+{
+ switch (prefix) {
+ case SIPrefix::yocto: return stream << 'y';
+ case SIPrefix::zepto: return stream << 'z';
+ case SIPrefix::atto: return stream << 'a';
+ case SIPrefix::femto: return stream << 'f';
+ case SIPrefix::pico: return stream << 'p';
+ case SIPrefix::nano: return stream << 'n';
+ case SIPrefix::micro: return stream << QChar(0x03BC);
+ case SIPrefix::milli: return stream << 'm';
+ case SIPrefix::kilo: return stream << 'k';
+ case SIPrefix::mega: return stream << 'M';
+ case SIPrefix::giga: return stream << 'G';
+ case SIPrefix::tera: return stream << 'T';
+ case SIPrefix::peta: return stream << 'P';
+ case SIPrefix::exa: return stream << 'E';
+ case SIPrefix::zetta: return stream << 'Z';
+ case SIPrefix::yotta: return stream << 'Y';
+
+ default: return stream;
+ }
+}
+
+int exponent(SIPrefix prefix)
+{
+ return 3 * (static_cast<int>(prefix) - static_cast<int>(SIPrefix::none));
+}
+
+static SIPrefix successor(SIPrefix prefix)
+{
+ assert(prefix != SIPrefix::yotta);
+ return static_cast<SIPrefix>(static_cast<int>(prefix) + 1);
+}
+
+// Insert the timestamp value into the stream in fixed-point notation
+// (and honor the precision)
+static QTextStream& operator<<(QTextStream& stream, const Timestamp& t)
+{
+ // The multiprecision types already have a function and a stream insertion
+ // operator to convert them to a string, however these functions abuse a
+ // precision value of zero to print all available decimal places instead of
+ // none, and the boost authors refuse to fix this because they don't want
+ // to break buggy code that relies on this bug.
+ // (https://svn.boost.org/trac/boost/ticket/10103)
+ // Therefore we have to work around the case where precision is zero.
+
+ int precision = stream.realNumberPrecision();
+
+ ostringstream ss;
+ ss << fixed;
+
+ if (stream.numberFlags() & QTextStream::ForceSign)
+ ss << showpos;
+
+ if (0 == precision)
+ ss << setprecision(1) << round(t);
+ else
+ ss << setprecision(precision) << t;
+
+ string str(ss.str());
+ if (0 == precision) {
+ // remove the separator and the unwanted decimal place
+ str.resize(str.size() - 2);
+ }
+
+ return stream << QString::fromStdString(str);
+}
+
+QString format_time_si(const Timestamp& v, SIPrefix prefix,
+ unsigned int precision, QString unit, bool sign)
+{
+ if (prefix == SIPrefix::unspecified) {
+ // No prefix given, calculate it
+
+ if (v.is_zero()) {
+ prefix = SIPrefix::none;
+ } else {
+ int exp = exponent(SIPrefix::yotta);
+ prefix = SIPrefix::yocto;
+ while ((fabs(v) * pow(Timestamp(10), exp)) > 999 &&
+ prefix < SIPrefix::yotta) {
+ prefix = successor(prefix);
+ exp -= 3;
+ }
+ }
+ }
+
+ assert(prefix >= SIPrefix::yocto);
+ assert(prefix <= SIPrefix::yotta);
+
+ const Timestamp multiplier = pow(Timestamp(10), -exponent(prefix));
+
+ QString s;
+ QTextStream ts(&s);
+ if (sign && !v.is_zero())
+ ts << forcesign;
+ ts << qSetRealNumberPrecision(precision) << (v * multiplier) << ' '
+ << prefix << unit;
+
+ return s;
+}