Permalink
Browse files

Restore old-fashioned unsafe format as "format_raw", for those rare

times when you must have every last feature of printf, including those
that tinyformat doesn't handle (and are willing to trade type safety and
expandability to do it).

What do you know, we need this for Strutil::memformat and Strutil::timeintervalformat!

Which we didn't notice because we had no unit tests for them, which I also have
now added.
  • Loading branch information...
1 parent 30ac930 commit 1f9bdb763f4663f42a911e1b4e2546b4040e88ce @lgritz lgritz committed Apr 21, 2012
Showing with 64 additions and 8 deletions.
  1. +10 −1 src/include/strutil.h
  2. +28 −1 src/libOpenImageIO/strutil_test.cpp
  3. +26 −6 src/libutil/strutil.cpp
View
11 src/include/strutil.h
@@ -89,8 +89,17 @@ namespace Strutil {
TINYFORMAT_WRAP_FORMAT (std::string, format, /**/,
std::ostringstream msg;, msg, return msg.str();)
+/// Return a std::string formatted from printf-like arguments. Like the
+/// real sprintf, this is not guaranteed type-safe and is not extensible
+/// like format(). You would only want to use this instead of the safe
+/// format() in rare situations where you really need to use obscure
+/// printf features that aren't supported by tinyformat.
+std::string DLLPUBLIC format_raw (const char *fmt, ...)
+ OPENIMAGEIO_PRINTF_ARGS(1,2);
+
/// Return a std::string formatted from printf-like arguments -- passed
-/// already as a va_list.
+/// already as a va_list. Like vsprintf, this is not guaranteed
+/// type-safe and is not extensible like format().
std::string DLLPUBLIC vformat (const char *fmt, va_list ap)
OPENIMAGEIO_PRINTF_ARGS(1,0);
View
29 src/libOpenImageIO/strutil_test.cpp
@@ -28,11 +28,36 @@
(This is the Modified BSD License)
*/
-#include "imageio.h"
+#include "strutil.h"
#include "unittest.h"
OIIO_NAMESPACE_USING;
+
+
+void test_memformat ()
+{
+ OIIO_CHECK_EQUAL (Strutil::memformat (15), "15 B");
+ OIIO_CHECK_EQUAL (Strutil::memformat (15LL*1024), "15 KB");
+ OIIO_CHECK_EQUAL (Strutil::memformat (15LL*1024*1024), "15.0 MB");
+ OIIO_CHECK_EQUAL (Strutil::memformat (15LL*1024*1024*1024), "15.0 GB");
+ OIIO_CHECK_EQUAL (Strutil::memformat (15LL*1024*1024+200000), "15.2 MB");
+ OIIO_CHECK_EQUAL (Strutil::memformat (15LL*1024*1024+200000, 3), "15.191 MB");
+}
+
+
+
+void test_timeintervalformat ()
+{
+ OIIO_CHECK_EQUAL (Strutil::timeintervalformat (15.321), "15.3s");
+ OIIO_CHECK_EQUAL (Strutil::timeintervalformat (150.321), "2m 30.3s");
+ OIIO_CHECK_EQUAL (Strutil::timeintervalformat (15000.321), "4h 10m 0.3s");
+ OIIO_CHECK_EQUAL (Strutil::timeintervalformat (150000.321), "1d 17h 40m 0.3s");
+ OIIO_CHECK_EQUAL (Strutil::timeintervalformat (150.321, 2), "2m 30.32s");
+}
+
+
+
void test_get_rest_arguments ()
{
int ret;
@@ -111,6 +136,8 @@ void test_escape_sequences ()
int main (int argc, char *argv[])
{
+ test_memformat ();
+ test_timeintervalformat ();
test_get_rest_arguments ();
test_escape_sequences ();
View
32 src/libutil/strutil.cpp
@@ -48,6 +48,18 @@ OIIO_NAMESPACE_ENTER
{
std::string
+Strutil::format_raw (const char *fmt, ...)
+{
+ va_list ap;
+ va_start (ap, fmt);
+ std::string buf = vformat (fmt, ap);
+ va_end (ap);
+ return buf;
+}
+
+
+
+std::string
Strutil::vformat (const char *fmt, va_list ap)
{
// Allocate a buffer on the stack that's big enough for us almost
@@ -115,7 +127,11 @@ Strutil::memformat (off_t bytes, int digits)
// Just bytes, don't bother with decimalization
return format ("%lld B", (long long)bytes);
}
- return format ("%1.*f %s", digits, d, units);
+ // N.B. We use format_raw below because format() (due to its
+ // dependence on 'tinyformat') does not support variable precision.
+ // If tinyformat is extended to handle this, we will no longer
+ // need format_raw.
+ return format_raw ("%1.*f %s", digits, d, units);
}
@@ -135,13 +151,17 @@ Strutil::timeintervalformat (double secs, int digits)
int m = (int) floor (secs / mins);
secs = fmod (secs, mins);
if (d)
- out += format ("%dd ", d);
- if (h || d)
- out += format ("%2dh ", h);
+ out += format ("%dd %dh ", d, h);
+ else if (h)
+ out += format ("%dh ", h);
+ // N.B. We use format_raw below because format() (due to its
+ // dependence on 'tinyformat') does not support variable precision.
+ // If tinyformat is extended to handle this, we will no longer
+ // need format_raw.
if (m || h || d)
- out += format ("%dm %1.*fs", m, digits, secs);
+ out += format_raw ("%dm %1.*fs", m, digits, secs);
else
- out += format ("%1.*fs", digits, secs);
+ out += format_raw ("%1.*fs", digits, secs);
return out;
}

0 comments on commit 1f9bdb7

Please sign in to comment.