Simplify output of Times in a specific unit; see Time::As ()
authorPeter D. Barnes, Jr. <barnes26@llnl.gov>
Wed, 02 Apr 2014 18:47:04 -0700
changeset 10688 ad36a71c737c
parent 10687 1330d4ee94e8
child 10689 a506de747327
Simplify output of Times in a specific unit; see Time::As ()
RELEASE_NOTES
src/core/model/nstime.h
src/core/model/time.cc
src/core/test/time-test-suite.cc
--- a/RELEASE_NOTES	Sun Mar 23 19:08:54 2014 +0400
+++ b/RELEASE_NOTES	Wed Apr 02 18:47:04 2014 -0700
@@ -22,6 +22,7 @@
 New user-visible features
 -------------------------
 
+- Simplify output of Times in a specific unit; see Time::As ()
 - Enable selection of high precision int64x64_t implementation
   at configure time, for debugging purposes.
 - A new LTE MAC downlink scheduling algorithm named Channel and QoS
--- a/src/core/model/nstime.h	Sun Mar 23 19:08:54 2014 +0400
+++ b/src/core/model/nstime.h	Wed Apr 02 18:47:04 2014 -0700
@@ -33,6 +33,8 @@
 
 namespace ns3 {
 
+class TimeWithUnit;
+  
 /**
  * \ingroup core
  * \brief Simulation virtual time values and global simulation resolution.
@@ -488,6 +490,20 @@
     return Time (value);
   }
 
+  /**
+   * Attach a unit to a Time, to facilitate output in a specific unit.
+   *
+   * For example,
+   * \code
+   *   Time t (3.14e9);  // Pi seconds
+   *   std::cout << t.As (Time::MS) << std::endl;
+   * \code
+   * will print ``+3140.0ms``
+   *
+   * \param unit [in] The unit to use.
+   */
+  TimeWithUnit As (const enum Unit unit) const;
+
 private:
   /**
    * How to convert between other units and the current unit
@@ -1022,6 +1038,32 @@
   return MakeTimeChecker (min, Time::Max ());
 }
 
+/**
+ * \ingroup time
+ * \brief A Time with attached unit, to facilitate output in that unit.
+ */
+class TimeWithUnit
+{
+public:
+  /**
+   * Attach a unit to a Time
+   *
+   * \param [in] time The time.
+   * \param [in] unit The unit to use for output
+   */
+  TimeWithUnit (const Time time, const Time::Unit unit)
+    : m_time (time),
+      m_unit (unit)
+  { };
+
+private:
+  Time m_time;        //!< The time
+  Time::Unit m_unit;  //!< The unit to use in output
+
+  /// Output streamer
+  friend std::ostream & operator << (std::ostream & os, const TimeWithUnit & time);
+
+};  // class TimeWithUnit
 
 } // namespace ns3
 
--- a/src/core/model/time.cc	Sun Mar 23 19:08:54 2014 +0400
+++ b/src/core/model/time.cc	Wed Apr 02 18:47:04 2014 -0700
@@ -380,67 +380,53 @@
 }
 
 
+TimeWithUnit
+Time::As (const enum Unit unit) const
+{
+  return TimeWithUnit (*this, unit);
+}
+ 
+
 std::ostream&
 operator<< (std::ostream& os, const Time & time)
 {
+  os << time.As (Time::GetResolution ());
+  return os;
+}
+
+
+std::ostream &
+operator << (std::ostream & os, const TimeWithUnit & timeU)
+{
   std::string unit;
-  Time::Unit res = Time::GetResolution ();
-  switch (res)
+
+  switch (timeU.m_unit)
     {
-    case Time::S:
-      unit = "s";
-      break;
-    case Time::MS:
-      unit = "ms";
-      break;
-    case Time::US:
-      unit = "us";
-      break;
-    case Time::NS:
-      unit = "ns";
-      break;
-    case Time::PS:
-      unit = "ps";
-      break;
-    case Time::FS:
-      unit = "fs";
-      break;
-    case Time::MIN:
-      unit = "min";
-      break;
-    case Time::H:
-      unit = "h";
-      break;
-    case Time::D:
-      unit = "d";
-      break;
-    case Time::Y:
-      unit = "y";
-      break;
+    case Time::Y:    unit = "y";    break;
+    case Time::D:    unit = "d";    break;
+    case Time::H:    unit = "h";    break;
+    case Time::MIN:  unit = "min";  break;
+    case Time::S:    unit = "s";    break;
+    case Time::MS:   unit = "ms";   break;
+    case Time::US:   unit = "us";   break;
+    case Time::NS:   unit = "ns";   break;
+    case Time::PS:   unit = "ps";   break;
+    case Time::FS:   unit = "fs";   break;
+
     case Time::LAST:
+    default:
       NS_ABORT_MSG ("can't be reached");
       unit = "unreachable";
       break;
     }
-  int64_t v = time.ToInteger (res);
 
-  std::ios_base::fmtflags ff = os.flags ();
-
-  os << std::setw (0) << std::left;
-  { // See bug 1737:  gcc libstc++ 4.2 bug
-    if (v == 0)
-      {
-        os << '+';
-      }
-    else
-      {
-        os << std::showpos;
-      }
-  }
-  os << v << ".0" << unit;
-  os.flags (ff);  // Restore stream flags
+  int64x64_t v = timeU.m_time.To (timeU.m_unit);
+  os << v << unit;
+  
   return os;
 }
+
+
 std::istream& operator>> (std::istream& is, Time & time)
 {
   std::string value;
--- a/src/core/test/time-test-suite.cc	Sun Mar 23 19:08:54 2014 +0400
+++ b/src/core/test/time-test-suite.cc	Wed Apr 02 18:47:04 2014 -0700
@@ -19,7 +19,14 @@
  * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
  * TimeStep support by Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>
  */
+
+#include <iomanip>
+#include <iostream>
+#include <string>
+#include <sstream>
+
 #include "ns3/nstime.h"
+#include "ns3/int64x64.h"
 #include "ns3/test.h"
 
 using namespace ns3;
@@ -150,13 +157,90 @@
 {
 }
 
+
+class TimeIntputOutputTestCase : public TestCase
+{
+public:
+  TimeIntputOutputTestCase ();
+private:
+  virtual void DoRun (void);
+  void Check (const std::string & str);
+};
+
+TimeIntputOutputTestCase::TimeIntputOutputTestCase ()
+  : TestCase ("Input,output from,to strings")
+{
+}
+
+void
+TimeIntputOutputTestCase::Check (const std::string & str)
+{
+  std::stringstream ss (str);
+  Time time;
+  ss >> time;
+  ss << time;
+  bool pass = (str == ss.str ()); 
+
+  std::cout << GetParent ()->GetName () << " InputOutput: "
+            << (pass ? "pass " : "FAIL ")
+            << "\"" << str << "\"";
+  if (!pass)
+    {
+      std::cout << ", got " << ss.str ();
+    }
+  std::cout << std::endl;
+}
+
+void
+TimeIntputOutputTestCase::DoRun (void)
+{
+  std::cout << std::endl;
+  std::cout << GetParent ()->GetName () << " InputOutput: " << GetName ()
+	    << std::endl;
+  
+  Check ("2ns");
+  Check ("+3.1us");
+  Check ("-4.2ms");
+  Check ("5.3s");
+  Check ("6.4min");
+  Check ("7.5h");
+  Check ("8.6d");
+  Check ("10.8y");
+
+  Time t (3.141592654e9);  // Pi seconds
+  
+  std::cout << GetParent ()->GetName () << " InputOutput: "
+            << "example: raw:   " << t
+            << std::endl;
+  
+  std::cout << GetParent ()->GetName () << " InputOutput: "
+            << std::fixed << std::setprecision (9)
+            << "example: in s:  " << t.As (Time::S)
+            << std::endl;
+    
+  std::cout << GetParent ()->GetName () << " InputOutput: "
+            << std::setprecision (6)
+            << "example: in ms: " << t.As (Time::MS)
+            << std::endl;
+
+  std::cout << GetParent ()->GetName () << " InputOutput: "
+            << "example: Get ns: " << t.GetNanoSeconds ()
+            << std::endl;
+
+  std::cout << std::endl;
+}
+    
 static class TimeTestSuite : public TestSuite
 {
 public:
   TimeTestSuite ()
     : TestSuite ("time", UNIT)
   {
+    AddTestCase (new TimesWithSignsTestCase (), TestCase::QUICK);
+    AddTestCase (new TimeIntputOutputTestCase (), TestCase::QUICK);
+    // This should be last, since it changes the resolution
     AddTestCase (new TimeSimpleTestCase (), TestCase::QUICK);
-    AddTestCase (new TimesWithSignsTestCase (), TestCase::QUICK);
   }
 } g_timeTestSuite;
+
+