diff -r e30bc51d0eee src/contrib/seq-num.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/contrib/seq-num.cc Sun Jun 20 16:36:48 2010 +0100 @@ -0,0 +1,195 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +// +// Copyright (c) 2008-2010 INESC Porto +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation; +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Author: Gustavo J. A. M. Carneiro +// + +#include "seq-num.h" +#include "ns3/test.h" +#include "ns3/object.h" +#include "ns3/traced-value.h" +#include "ns3/trace-source-accessor.h" + +namespace ns3 { + +class SeqNumTestObj : public Object +{ + TracedValue m_testTracedSeqNum; + + +public: + + SeqNumTestObj () + { + m_testTracedSeqNum = SeqNum32 (0); + } + + static TypeId GetTypeId (void) + { + static TypeId tid = TypeId("ns3::SeqNumTestObj") + .SetParent () + .AddTraceSource ("TestTracedSeqNum", + "A traceable sequence number", + MakeTraceSourceAccessor (&SeqNumTestObj::m_testTracedSeqNum)) + .AddConstructor () + ; + return tid; + } + + TypeId GetInstanceTypeId (void) const + { + return GetTypeId (); + } + + void IncSeqNum () + { + ++m_testTracedSeqNum; + } + + +}; + +class SeqNumTestCase : public TestCase +{ + SeqNum32 m_oldval; + SeqNum32 m_newval; + + void SeqNumTracer (SeqNum32 oldval, SeqNum32 newval); + +public: + + SeqNumTestCase (); + virtual ~SeqNumTestCase (); + virtual bool DoRun (void); +}; + +SeqNumTestCase::SeqNumTestCase () + : TestCase ("SeqNum") +{ + m_oldval = 0; + m_newval = 0; +} + +SeqNumTestCase::~SeqNumTestCase () +{} + +void +SeqNumTestCase::SeqNumTracer (SeqNum32 oldval, SeqNum32 newval) +{ + m_oldval = oldval; + m_newval = newval; +} + +bool SeqNumTestCase::DoRun (void) +{ +#define NS_TEST_ASSERT_EQUAL(a,b) NS_TEST_ASSERT_MSG_EQ(a,b, "foo") +#define NS_TEST_ASSERT(a) NS_TEST_ASSERT_MSG_EQ(bool(a), true, "foo") + + { + SeqNum32 num1 (3), num2 (5); + uint32_t value; + + value = (num1 + num2).GetValue (); + NS_TEST_ASSERT_EQUAL (value, 8); + + num1 += num2.GetValue (); + NS_TEST_ASSERT_EQUAL (num1, SeqNum32 (8)); + + ++num1; + NS_TEST_ASSERT_EQUAL (num1, SeqNum32 (9)); + + --num1; + NS_TEST_ASSERT_EQUAL (num1, SeqNum32 (8)); + + num1++; + NS_TEST_ASSERT_EQUAL (num1, SeqNum32 (9)); + + num1--; + NS_TEST_ASSERT_EQUAL (num1, SeqNum32 (8)); + + } + + { + SeqNum16 num1 (60900), num2 (5), num3 (10000); + + NS_TEST_ASSERT (num1 == num1); + + NS_TEST_ASSERT (num2 != num1); + + NS_TEST_ASSERT (num3 > num2); + NS_TEST_ASSERT (num3 >= num2); + NS_TEST_ASSERT (num1 < num3); + NS_TEST_ASSERT (num1 <= num3); + + NS_TEST_ASSERT (num1 < num2); + NS_TEST_ASSERT (num1 <= num2); + NS_TEST_ASSERT (num2 > num1); + NS_TEST_ASSERT (num2 >= num1); + + NS_TEST_ASSERT (num1+num2 > num1); + NS_TEST_ASSERT (num1+num2 >= num1); + NS_TEST_ASSERT (num1 < num1+num2); + NS_TEST_ASSERT (num1 <= num1+num2); + + NS_TEST_ASSERT (num1 < num1+num3); + NS_TEST_ASSERT (num1 <= num1+num3); + NS_TEST_ASSERT (num1+num3 > num1); + NS_TEST_ASSERT (num1+num3 >= num1); + } + + { + NS_TEST_ASSERT_EQUAL ((SeqNum16 (1000) + SeqNum16 (6000)) - SeqNum16 (1000), 6000); + NS_TEST_ASSERT_EQUAL ((SeqNum16 (60000) + SeqNum16 (6000)) - SeqNum16 (60000), 6000); + NS_TEST_ASSERT_EQUAL (SeqNum16 (1000) - SeqNum16 (6000), -5000); + NS_TEST_ASSERT_EQUAL ((SeqNum16 (60000) + SeqNum16 (1000)) - SeqNum16 (65000), -4000); + } + + { + SeqNum32 num1 (3); + + NS_TEST_ASSERT_EQUAL (num1 + 10, SeqNum32 (13)); + num1 += -1; + NS_TEST_ASSERT_EQUAL (num1, SeqNum32 (2)); + + NS_TEST_ASSERT_EQUAL (num1 - (num1 - 100), 100); + } + + { + Ptr obj = CreateObject (); + obj->TraceConnectWithoutContext ("TestTracedSeqNum", MakeCallback (&SeqNumTestCase::SeqNumTracer, this)); + obj->IncSeqNum (); + NS_TEST_ASSERT_EQUAL (m_oldval, SeqNum32 (0)); + NS_TEST_ASSERT_EQUAL (m_newval, SeqNum32 (1)); + obj->Dispose (); + } + + + return false; +} + +static class SeqNumTestSuite : public TestSuite +{ +public: + SeqNumTestSuite () + : TestSuite ("SeqNum", UNIT) + { + AddTestCase (new SeqNumTestCase ()); + } +} g_seqNumTests; + +} + diff -r e30bc51d0eee src/contrib/seq-num.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/contrib/seq-num.h Sun Jun 20 16:36:48 2010 +0100 @@ -0,0 +1,270 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +// +// Copyright (c) 2008-2010 INESC Porto +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation; +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Author: Gustavo J. A. M. Carneiro +// + +#ifndef __NS3_SEQ_NUM_H__ +#define __NS3_SEQ_NUM_H__ + +#include +#include +#include + +namespace ns3 { + +template +class SeqNum +{ +public: + SeqNum () + : m_value (0) + {} + + // contruct from a plain number; but the contructor is _explicit_, so not called automatically, ever. + explicit SeqNum (NUMERIC_TYPE value) + : m_value (value) + {} + + // copy contructor + SeqNum (SeqNum const &value) + : m_value (value.m_value) + {} + + // assignment from a plain number + SeqNum& operator= (NUMERIC_TYPE value) + { + m_value = value; + return *this; + } + + // assignment from a sequence number + SeqNum& operator= (SeqNum const &value) + { + m_value = value.m_value; + return *this; + } + +#if 0 + // a SeqNum implicitly converts to a plain number, but not the other way around + operator NUMERIC_TYPE () const + { + return m_value; + } +#endif + + NUMERIC_TYPE GetValue () const + { + return m_value; + } + + // prefix ++ + SeqNum operator++ () + { + m_value++; + return *this; + } + + // postfix ++ + SeqNum operator++ (int) + { + SeqNum retval (m_value); + m_value++; + return retval; + } + + // prefix -- + SeqNum operator-- () + { + m_value--; + return *this; + } + + // postfix -- + SeqNum operator-- (int) + { + SeqNum retval (m_value); + m_value--; + return retval; + } + + SeqNum& operator+= (SIGNED_TYPE value) + { + m_value += value; + return *this; + } + + SeqNum& operator-= (SIGNED_TYPE value) + { + m_value -= value; + return *this; + } + + SeqNum operator + (const SeqNum &other) + { + return SeqNum (m_value + other.m_value); + } + + SeqNum operator + (SIGNED_TYPE delta) + { + return SeqNum (m_value + delta); + } + + SeqNum operator - (SIGNED_TYPE delta) + { + return SeqNum (m_value - delta); + } + + SIGNED_TYPE operator - (const SeqNum &other) + { + static const NUMERIC_TYPE maxValue = std::numeric_limits::max (); + static const NUMERIC_TYPE halfMaxValue = std::numeric_limits::max () / 2; + if (m_value > other.m_value) + { + NUMERIC_TYPE diff = m_value - other.m_value; + if (diff < halfMaxValue) + { + return static_cast (diff); + } + else + { + // |------------|------------| + // ==== === + // ^ ^ + // other.m_value m_value + return -(static_cast (maxValue - m_value + 1 + other.m_value)); + } + } + else + { + NUMERIC_TYPE diff = other.m_value - m_value; + if (diff < halfMaxValue) + { + // |------------|------------| + // ======== + // ^ ^ + // m_value other.m_value + return -(static_cast (diff)); + } + else + { + // |------------|------------| + // ==== === + // ^ ^ + // m_value other.m_value + return static_cast (maxValue - other.m_value + 1 + m_value); + } + } + } + + + // Here is the critical part, how the comparison is made taking into + // account wrap-around. From RFC 3626: + // + // The sequence number S1 is said to be "greater than" the sequence + // number S2 if: + // + // S1 > S2 AND S1 - S2 <= MAXVALUE/2 OR + // + // S2 > S1 AND S2 - S1 > MAXVALUE/2 + bool operator > (const SeqNum &other) + { + static const NUMERIC_TYPE halfMaxValue = std::numeric_limits::max () / 2; + + return (((m_value > other.m_value) && (m_value - other.m_value) <= halfMaxValue) + || ((other.m_value > m_value) && (other.m_value - m_value) > halfMaxValue)); + } + + bool operator == (const SeqNum &other) + { + return (m_value == other.m_value); + } + + bool operator != (const SeqNum &other) + { + return (m_value != other.m_value); + } + + bool operator <= (const SeqNum &other) + { + return (!this->operator> (other)); + } + + bool operator >= (const SeqNum &other) + { + return (this->operator> (other) || this->operator== (other)); + } + + bool operator < (const SeqNum &other) + { + return !this->operator> (other) && m_value != other.m_value; + } + + + template + friend std::ostream & operator<< (std::ostream& os, const SeqNum &val); + + template + friend std::istream & operator >> (std::istream &is, const SeqNum &val); + +private: // unimplemented operators + SeqNum& operator+= (SeqNum const &value); + SeqNum& operator-= (SeqNum const &value); + SeqNum operator* (const SeqNum& b) const; + SeqNum operator/ (const SeqNum& b) const; + SeqNum operator% (const SeqNum& b) const; + bool operator ! () const; + bool operator && (const SeqNum& b) const; + bool operator || (const SeqNum& b) const; + SeqNum operator~ () const; + SeqNum operator& (const SeqNum& b) const; + SeqNum operator| (const SeqNum& b) const; + SeqNum operator^ (const SeqNum& b) const; + SeqNum operator<< (const SeqNum& b) const; + SeqNum operator>> (const SeqNum& b) const; + int operator* (); + SeqNum* operator& (); + +private: + NUMERIC_TYPE m_value; +}; + + +template +std::ostream & +operator<< (std::ostream& os, const SeqNum &val) +{ + os << val.m_value; + return os; +} + +template +std::istream & operator >> (std::istream &is, const SeqNum &val) +{ + is >> val.m_value; + return is; +} + + +typedef SeqNum SeqNum32; +typedef SeqNum SeqNum16; + +} // namespace ns3 + +#endif + + diff -r e30bc51d0eee src/contrib/wscript --- a/src/contrib/wscript Sun Jun 20 15:57:49 2010 +0100 +++ b/src/contrib/wscript Sun Jun 20 16:36:48 2010 +0100 @@ -31,6 +31,7 @@ 'attribute-default-iterator.cc', 'file-config.cc', 'raw-text-config.cc', + 'seq-num.cc', ] headers = bld.new_task_gen('ns3header') @@ -43,6 +44,7 @@ 'config-store.h', 'flow-id-tag.h', 'average.h', + 'seq-num.h', ] if bld.env['ENABLE_GTK_CONFIG_STORE']: