allow serialization/deserialization for debugging output
authorMathieu Lacage <mathieu.lacage@sophia.inria.fr>
Fri, 13 Aug 2010 13:30:14 +0200
changeset 6566 eb0098cd929c
parent 6565 f5596043913c
child 6567 cdde0c732669
allow serialization/deserialization for debugging output
src/simulator/high-precision-128.cc
src/simulator/high-precision-128.h
src/simulator/high-precision-cairo.cc
src/simulator/high-precision-cairo.h
src/simulator/high-precision.cc
--- a/src/simulator/high-precision-128.cc	Fri Aug 13 13:28:38 2010 +0200
+++ b/src/simulator/high-precision-128.cc	Fri Aug 13 13:30:14 2010 +0200
@@ -33,6 +33,29 @@
 
 #define MASK_LO ((((uint128_t)1)<<64)-1)
 #define MASK_HI (~MASK_LO)
+HighPrecision::HighPrecision (int64_t high, uint64_t low)
+{
+  bool is_negative = high<0;
+  m_value = is_negative?-high:high;
+  m_value <<= 64;
+  m_value += low;
+  m_value = is_negative?-m_value:m_value;
+}
+int64_t
+HighPrecision::GetHigh (void) const
+{
+  return GetInteger ();
+}
+uint64_t 
+HighPrecision::GetLow (void) const
+{
+  bool negative = m_value < 0;
+  int128_t v = negative?-m_value:m_value;
+  int128_t low = v & MASK_LO;
+  uint64_t retval = low;
+  return retval;
+}
+
 void
 HighPrecision::Mul (HighPrecision const &o)
 {
@@ -154,4 +177,238 @@
   return result;
 }
 
+static uint8_t MostSignificantDigit (uint64_t value)
+{
+  uint8_t n = 0;
+  do
+    {
+      n++;
+      value /= 10;
+    } while (value != 0);
+  return n;
+}
+
+static uint128_t PowerOfTen (uint8_t n)
+{
+  uint128_t retval = 1;
+  while (n > 0)
+    {
+      retval *= 10;
+      n--;
+    }
+  return retval;
+}
+
+std::ostream &operator << (std::ostream &os, const HighPrecision &hp)
+{
+  int64_t hi = hp.GetHigh ();
+  os << ((hi<0)?"-":"+") << ((hi<0)?-hi:hi) << ".";
+  uint128_t low = hp.GetLow ();
+  uint8_t msd = MostSignificantDigit (~((uint64_t)0));
+  do
+    {
+      msd--;
+      uint128_t pow = PowerOfTen (msd);
+      uint8_t digit = low / pow;
+      NS_ASSERT (digit < 10);
+      os << (uint16_t) digit;
+      low -= digit * pow;
+    } while (msd > 0 && low > 0);
+  return os;
+}
+
+static uint64_t ReadDigits (std::string str)
+{
+  const char *buf = str.c_str ();
+  uint64_t retval = 0;
+  while (*buf != 0)
+    {
+      retval *= 10;
+      retval += *buf - 0x30;
+      buf++;
+    }
+  return retval;
+}
+
+std::istream &operator >> (std::istream &is, HighPrecision &hp)
+{
+  std::string str;
+
+  is >> str;
+  bool negative;
+  // skip heading spaces
+  std::string::size_type cur;
+  cur = str.find_first_not_of (" ");
+  std::string::size_type next;
+  // first, remove the sign.
+  next = str.find ("-", cur);
+  if (next != std::string::npos)
+    {
+      negative = true;
+      next++;
+    }
+  else
+    {
+      next = str.find ("+", cur);
+      if (next != std::string::npos)
+	{
+	  next++;
+	}
+      else
+	{
+	  next = cur;
+	}
+      negative = false;
+    }
+  cur = next;
+  int64_t hi;
+  uint64_t lo;
+  next = str.find(".", cur);
+  if (next != std::string::npos)
+    {
+      hi = ReadDigits (str.substr (cur, next-cur));
+      lo = ReadDigits (str.substr (next+1, str.size()-(next+1)));
+    }
+  else
+    {
+      hi = ReadDigits (str.substr (cur, str.size ()-cur));
+      lo = 0;
+    }
+  hi = negative?-hi:hi;
+  hp = HighPrecision (hi, lo);
+  return is;
+}
+
 } // namespace ns3
+
+#include "ns3/test.h"
+
+namespace ns3
+{
+
+class HpFracTestCase : public TestCase
+{
+public:
+  HpFracTestCase ();
+  virtual bool DoRun (void);
+  void CheckFrac (int64_t hi, uint64_t lo);
+};
+
+void 
+HpFracTestCase::CheckFrac (int64_t hi, uint64_t lo)
+{
+  HighPrecision tmp = HighPrecision (hi,lo);
+  NS_TEST_EXPECT_MSG_EQ (tmp.GetHigh (), hi,
+			 "High part does not match");
+  NS_TEST_EXPECT_MSG_EQ (tmp.GetLow (), lo,
+			 "Low part does not match");
+}
+
+HpFracTestCase::HpFracTestCase ()
+  : TestCase ("Check that we can manipulate the high and low part of every number")
+{
+}
+bool
+HpFracTestCase::DoRun (void)
+{
+  CheckFrac (1, 0);
+  CheckFrac (1, 1);
+  CheckFrac (-1, 0);
+  CheckFrac (-1, 1);
+  return GetErrorStatus ();
+}
+
+
+class HpInputTestCase : public TestCase
+{
+public:
+  HpInputTestCase ();
+  virtual bool DoRun (void);
+  void CheckString (std::string str, int64_t hi, uint64_t lo);
+};
+HpInputTestCase::HpInputTestCase ()
+  : TestCase ("Check that we parse HighPrecision numbers as strings")
+{
+}
+void 
+HpInputTestCase::CheckString (std::string str, int64_t hi, uint64_t lo)
+{
+  std::istringstream iss;
+  iss.str (str);
+  HighPrecision hp;
+  iss >> hp;
+  NS_TEST_EXPECT_MSG_EQ (hp.GetHigh (), hi, "High parts do not match for input string " << str);
+  NS_TEST_EXPECT_MSG_EQ (hp.GetLow (), lo, "Low parts do not match for input string " << str);
+}
+bool
+HpInputTestCase::DoRun (void)
+{
+  CheckString ("1", 1, 0);
+  CheckString ("+1", 1, 0);
+  CheckString ("-1", -1, 0);
+  CheckString ("1.0", 1, 0);
+  CheckString ("+1.0", 1, 0);
+  CheckString ("001.0", 1, 0);
+  CheckString ("+001.0", 1, 0);
+  CheckString ("020.0", 20, 0);
+  CheckString ("+020.0", 20, 0);
+  CheckString ("-1.0", -1, 0);
+  CheckString ("-1.0000", -1, 0);
+  CheckString ("1.0000000", 1, 0);
+  CheckString ("1.08446744073709551615", 1, 8446744073709551615LL);
+  CheckString ("-1.08446744073709551615", -1, 8446744073709551615LL);
+  
+  return GetErrorStatus ();
+}
+
+class HpInputOutputTestCase : public TestCase
+{
+public:
+  HpInputOutputTestCase ();
+  virtual bool DoRun (void);
+  void CheckString (std::string str);
+};
+HpInputOutputTestCase::HpInputOutputTestCase ()
+  : TestCase ("Check that we can roundtrip HighPrecision numbers as strings")
+{
+}
+void 
+HpInputOutputTestCase::CheckString (std::string str)
+{
+  std::istringstream iss;
+  iss.str (str);
+  HighPrecision hp;
+  iss >> hp;
+  std::ostringstream oss;
+  oss << hp;
+  NS_TEST_EXPECT_MSG_EQ (oss.str (), str, "Converted string does not match expected string");
+}
+bool
+HpInputOutputTestCase::DoRun (void)
+{
+  CheckString ("+1.0");
+  CheckString ("-1.0");
+  CheckString ("+20.0");
+  CheckString ("+1.08446744073709551615");
+  CheckString ("-1.08446744073709551615");
+  CheckString ("+1.18446744073709551615");
+  CheckString ("-1.18446744073709551615");
+  
+  return GetErrorStatus ();
+}
+
+
+static class HighPrecision128TestSuite : public TestSuite
+{
+public:
+  HighPrecision128TestSuite ()
+    : TestSuite ("high-precision-128", UNIT)
+  {
+    AddTestCase (new HpFracTestCase ());
+    AddTestCase (new HpInputTestCase ());
+    //AddTestCase (new HpOutputTestCase ());
+    AddTestCase (new HpInputOutputTestCase ());
+  }
+} g_highPrecision128TestSuite;
+
+} // namespace ns3
--- a/src/simulator/high-precision-128.h	Fri Aug 13 13:28:38 2010 +0200
+++ b/src/simulator/high-precision-128.h	Fri Aug 13 13:30:14 2010 +0200
@@ -23,6 +23,7 @@
 #include "ns3/simulator-config.h"
 #include <math.h>
 #include <stdint.h>
+#include <iostream>
 
 #define noCOUNT_OPS 1
 
@@ -53,6 +54,7 @@
 {
 public:
   inline HighPrecision ();
+  explicit HighPrecision (int64_t high, uint64_t low);
   explicit inline HighPrecision (int64_t value, bool dummy);
   explicit inline HighPrecision (double value);
 
@@ -67,6 +69,9 @@
 
   inline int Compare (HighPrecision const &o) const;
   inline static HighPrecision Zero (void);
+
+  int64_t GetHigh (void) const;
+  uint64_t GetLow (void) const;
 private:
   static uint128_t UmulByInvert (uint128_t a, uint128_t b);
   static uint128_t Umul (uint128_t a, uint128_t b);
@@ -86,6 +91,9 @@
 #endif
 };
 
+std::ostream &operator << (std::ostream &os, const HighPrecision &hp);
+std::istream &operator >> (std::istream &is, HighPrecision &hp);
+
 } // namespace ns3
 
 namespace ns3 {
@@ -103,8 +111,11 @@
 
 int64_t HighPrecision::GetInteger (void) const
 {
-  int128_t v = m_value >> 64;
-  return v;
+  bool negative = m_value < 0;
+  int128_t v = negative?-m_value:m_value;
+  v >>= 64;
+  int64_t retval = v;
+  return negative?-retval:retval;
 }
 
 void
--- a/src/simulator/high-precision-cairo.cc	Fri Aug 13 13:28:38 2010 +0200
+++ b/src/simulator/high-precision-cairo.cc	Fri Aug 13 13:30:14 2010 +0200
@@ -155,6 +155,15 @@
   return result;
 }
 
+std::ostream &operator << (std::ostream &os, const HighPrecision &hp)
+{
+  return os;
+}
+std::istream &operator >> (std::istream &is, HighPrecision &hp)
+{
+  return is;
+}
+
 
 } // namespace ns3
 
--- a/src/simulator/high-precision-cairo.h	Fri Aug 13 13:28:38 2010 +0200
+++ b/src/simulator/high-precision-cairo.h	Fri Aug 13 13:30:14 2010 +0200
@@ -68,6 +68,10 @@
   cairo_int128_t m_value;
 };
 
+std::ostream &operator << (std::ostream &os, const HighPrecision &hp);
+std::istream &operator >> (std::istream &is, HighPrecision &hp);
+
+
 } // namespace ns3
 
 namespace ns3 {
--- a/src/simulator/high-precision.cc	Fri Aug 13 13:28:38 2010 +0200
+++ b/src/simulator/high-precision.cc	Fri Aug 13 13:30:14 2010 +0200
@@ -172,7 +172,7 @@
   a.Mul (V (3));
   CHECK_EXPECTED (a, 1999999999);
 
-  return false;
+  return GetErrorStatus ();
 }
 
 class HpBug455TestCase : public TestCase
@@ -205,7 +205,7 @@
   a.Mul (HighPrecision (-5));
   NS_TEST_ASSERT_MSG_EQ (a.GetDouble (), -2.5, "only second operand negative");
 
-  return false;
+  return GetErrorStatus ();
 }
 
 
@@ -240,7 +240,7 @@
   a.Div (HighPrecision (-0.5));
   NS_TEST_ASSERT_MSG_EQ (a.GetDouble (), 1.0, "both arguments negative");
 
-  return false;
+  return GetErrorStatus ();
 }
 
 class HpCompareTestCase : public TestCase
@@ -279,7 +279,7 @@
   b = V (1);
   NS_TEST_ASSERT_MSG_EQ (a.Compare (b), 0, "a is equal to b");
 
-  return false;
+  return GetErrorStatus ();
 }
 
 class HpInvertTestCase : public TestCase
@@ -342,7 +342,7 @@
   TEST(100000000000000LL);
   TEST(1000000000000000LL);
 #undef TEST
-  return false;
+  return GetErrorStatus ();
 }