Report benchmark durations in natural units
(and extended StringRef to be able to report utf8 char lengths
diff --git a/include/internal/catch_string.cpp b/include/internal/catch_string.cpp
index b18f5d1..73d9d77 100644
--- a/include/internal/catch_string.cpp
+++ b/include/internal/catch_string.cpp
@@ -64,6 +64,9 @@
     auto String::size() const noexcept -> size_type {
         return m_data->size;
     }
+    auto String::numberOfCharacters() const noexcept -> size_type {
+        return StringRef( *this ).numberOfCharacters();
+    }
     auto String::c_str() const noexcept -> char const* {
         return m_data->chars;
     }
diff --git a/include/internal/catch_string.h b/include/internal/catch_string.h
index 5fb477a..0455203 100644
--- a/include/internal/catch_string.h
+++ b/include/internal/catch_string.h
@@ -40,6 +40,8 @@
         
         auto empty() const noexcept -> bool;
         auto size() const noexcept -> size_type;
+        auto numberOfCharacters() const noexcept -> size_type;
+
         auto c_str() const noexcept -> char const*;
     };
     
diff --git a/include/internal/catch_stringref.cpp b/include/internal/catch_stringref.cpp
index 9572c56..44db685 100644
--- a/include/internal/catch_stringref.cpp
+++ b/include/internal/catch_stringref.cpp
@@ -136,7 +136,23 @@
     auto StringRef::size() const noexcept -> size_type {
         return m_size;
     }
-        
+    auto StringRef::numberOfCharacters() const noexcept -> size_type {
+        size_type noChars = m_size;
+        // Make adjustments for uft encodings
+        for( size_type i=0; i < m_size; ++i ) {
+            char c = m_start[i];
+            if( ( c & 0b11000000 ) == 0b11000000 ) {
+                if( ( c & 0b11100000 ) == 0b11000000 )
+                    noChars--;
+                else if( ( c & 0b11110000 ) == 0b11100000 )
+                    noChars-=2;
+                else if( ( c & 0b11111000 ) == 0b11110000 )
+                    noChars-=3;
+            }
+        }
+        return noChars;
+    }
+
     auto operator + ( StringRef const& lhs, StringRef const& rhs ) -> String {
         StringBuilder buf;
         buf.reserve( lhs.size() + rhs.size() );
diff --git a/include/internal/catch_stringref.h b/include/internal/catch_stringref.h
index d7f1efb..55a99ae 100644
--- a/include/internal/catch_stringref.h
+++ b/include/internal/catch_stringref.h
@@ -56,6 +56,7 @@
     public: // named queries
         auto empty() const noexcept -> bool;
         auto size() const noexcept -> size_type;
+        auto numberOfCharacters() const noexcept -> size_type;
         auto c_str() const -> char const*;
         
     public: // substrings and searches
diff --git a/include/reporters/catch_reporter_console.cpp b/include/reporters/catch_reporter_console.cpp
index 8ba14f5..3325904 100644
--- a/include/reporters/catch_reporter_console.cpp
+++ b/include/reporters/catch_reporter_console.cpp
@@ -12,6 +12,7 @@
 #include "../internal/catch_console_colour.hpp"
 #include "../internal/catch_version.h"
 #include "../internal/catch_text.h"
+#include "../internal/catch_stringref.h"
 
 #include <cfloat>
 #include <cstdio>
@@ -82,6 +83,8 @@
 
         friend TablePrinter& operator << ( TablePrinter& tp, ColumnBreak ) {
             auto colStr = tp.m_oss.str();
+            // This takes account of utf8 encodings
+            auto strSize = Catch::StringRef( colStr.c_str(), colStr.size() ).numberOfCharacters();
             tp.m_oss.str("");
             tp.open();
             if( tp.m_currentColumn == static_cast<int>(tp.m_columnInfos.size()-1) ) {
@@ -93,8 +96,8 @@
             tp.m_currentColumn++;
 
             auto colInfo = tp.m_columnInfos[tp.m_currentColumn];
-            auto padding = ( colStr.size()+2 < static_cast<size_t>( colInfo.width ) )
-                ? std::string( colInfo.width-(colStr.size()+2), ' ' )
+            auto padding = ( strSize+2 < static_cast<size_t>( colInfo.width ) )
+                ? std::string( colInfo.width-(strSize+2), ' ' )
                 : std::string();
             if( colInfo.justification == ColumnInfo::Left )
                 tp.m_os << " " << colStr << padding << " |";
@@ -112,6 +115,79 @@
             return tp;
         }
     };
+
+    class Duration {
+        enum class Unit {
+            Auto,
+            Nanoseconds,
+            Microseconds,
+            Milliseconds,
+            Seconds,
+            Minutes
+        };
+        static const uint64_t s_nanosecondsInAMicrosecond = 1000;
+        static const uint64_t s_nanosecondsInAMillisecond = 1000*s_nanosecondsInAMicrosecond;
+        static const uint64_t s_nanosecondsInASecond = 1000*s_nanosecondsInAMillisecond;
+        static const uint64_t s_nanosecondsInAMinute = 60*s_nanosecondsInASecond;
+
+        uint64_t m_inNanoseconds;
+        Unit m_units;
+
+    public:
+        Duration( uint64_t inNanoseconds, Unit units = Unit::Auto )
+        :   m_inNanoseconds( inNanoseconds ),
+            m_units( units )
+        {
+            if( m_units == Unit::Auto ) {
+                if( m_inNanoseconds < s_nanosecondsInAMicrosecond )
+                    m_units = Unit::Nanoseconds;
+                else if( m_inNanoseconds < s_nanosecondsInAMillisecond )
+                    m_units = Unit::Microseconds;
+                else if( m_inNanoseconds < s_nanosecondsInASecond )
+                    m_units = Unit::Milliseconds;
+                else if( m_inNanoseconds < s_nanosecondsInAMinute )
+                    m_units = Unit::Seconds;
+                else
+                    m_units = Unit::Minutes;
+            }
+
+        }
+
+        auto value() const -> double {
+            switch( m_units ) {
+                case Unit::Microseconds:
+                    return m_inNanoseconds / static_cast<double>( s_nanosecondsInAMicrosecond );
+                case Unit::Milliseconds:
+                    return m_inNanoseconds / static_cast<double>( s_nanosecondsInAMillisecond );
+                case Unit::Seconds:
+                    return m_inNanoseconds / static_cast<double>( s_nanosecondsInASecond );
+                case Unit::Minutes:
+                    return m_inNanoseconds / static_cast<double>( s_nanosecondsInAMinute );
+                default:
+                    return static_cast<double>( m_inNanoseconds );
+            }
+        }
+        auto unitsAsString() const -> std::string {
+            switch( m_units ) {
+                case Unit::Nanoseconds:
+                    return "ns";
+                case Unit::Microseconds:
+                    return "µs";
+                case Unit::Milliseconds:
+                    return "ms";
+                case Unit::Seconds:
+                    return "s";
+                case Unit::Minutes:
+                    return "m";
+                default:
+                    return "** internal error **";
+            }
+
+        }
+        friend auto operator << ( std::ostream& os, Duration const& duration ) -> std::ostream& {
+            return os << duration.value() << " " << duration.unitsAsString();
+        }
+    };
 }
 
 namespace Catch {
@@ -123,10 +199,10 @@
         :   StreamingReporterBase( config ),
             m_tablePrinter( config.stream(),
                             {
-                                { "benchmark name", CATCH_CONFIG_CONSOLE_WIDTH-38, ColumnInfo::Left },
+                                { "benchmark name", CATCH_CONFIG_CONSOLE_WIDTH-42, ColumnInfo::Left },
                                 { "iters", 8, ColumnInfo::Right },
-                                { "elapsed ns", 12, ColumnInfo::Right },
-                                { "average", 12, ColumnInfo::Right }
+                                { "elapsed ns", 14, ColumnInfo::Right },
+                                { "average", 14, ColumnInfo::Right }
                             } )
         {}
         ~ConsoleReporter() override;
@@ -199,11 +275,11 @@
             }
         }
         void benchmarkEnded( BenchmarkStats const& stats ) override {
-            // !TBD: report average times in natural units?
+            Duration average( stats.elapsedTimeInNanoseconds/stats.iterations );
             m_tablePrinter
                     << stats.iterations << ColumnBreak()
                     << stats.elapsedTimeInNanoseconds << ColumnBreak()
-                    << stats.elapsedTimeInNanoseconds/stats.iterations << " ns" << ColumnBreak();
+                    << average << ColumnBreak();
         }
 
         void testCaseEnded( TestCaseStats const& _testCaseStats ) override {