rework the Tags API to ensure proper uid generation for tags
authorMathieu Lacage <mathieu.lacage@sophia.inria.fr>
Fri, 03 Aug 2007 13:00:38 +0200
changeset 1128 e5ab7564ae45
parent 1127 df45b772d989
child 1129 30a69a9bb20c
rework the Tags API to ensure proper uid generation for tags
samples/main-packet.cc
src/common/tags.cc
src/common/tags.h
--- a/samples/main-packet.cc	Fri Aug 03 10:39:55 2007 +0200
+++ b/samples/main-packet.cc	Fri Aug 03 13:00:38 2007 +0200
@@ -80,13 +80,18 @@
 
 /* A sample Tag implementation
  */
-struct MyTag {
+class MyTag 
+{
+public:
+  static const char *GetUid (void) {return "MyTag.test.nsnam.org";}
+  void Print (std::ostream &os) const {}
+  uint32_t GetSerializedSize (void) const {return 0;}
+  void Serialize (Buffer::Iterator i) const {}
+  uint32_t Deserialize (Buffer::Iterator i) {return 0;}
+
   uint16_t m_streamId;
 };
 
-static TagRegistration<struct MyTag> g_MyTagRegistration ("ns3::MyTag", 0);
-
-
 static void
 Receive (Packet p)
 {
--- a/src/common/tags.cc	Fri Aug 03 10:39:55 2007 +0200
+++ b/src/common/tags.cc	Fri Aug 03 13:00:38 2007 +0200
@@ -23,80 +23,43 @@
 
 namespace ns3 {
 
-TagRegistry *
-TagRegistry::GetInstance (void)
+Tag::TagInfoVector *
+Tag::GetInfo (void)
 {
-  static TagRegistry registry;
-  return &registry;
+  static Tag::TagInfoVector vector;
+  return &vector;
 }
 
-TagRegistry::TagRegistry ()
-  : m_sorted (false)
-{}
-
-
 void 
-TagRegistry::Record (std::string uuid, PrettyPrinter prettyPrinter, Destructor destructor)
+Tag::Destruct (uint32_t uid, uint8_t data[Tags::SIZE])
+{
+  TagInfo info = (*GetInfo ())[uid - 1];
+  info.destruct (data);
+}
+void 
+Tag::Print (uint32_t uid, uint8_t data[Tags::SIZE], std::ostream &os)
 {
-  NS_ASSERT (!m_sorted);
-  struct TagInfoItem item;
-  item.uuid = uuid;
-  item.printer = prettyPrinter;
-  item.destructor = destructor;
-  m_registry.push_back (item);
+  TagInfo info = (*GetInfo ())[uid - 1];
+  info.print (data, os);
 }
-bool 
-TagRegistry::CompareItem (const struct TagInfoItem &a, const struct TagInfoItem &b)
+uint32_t
+Tag::GetSerializedSize (uint32_t uid, uint8_t data[Tags::SIZE])
 {
-  return a.uuid < b.uuid;
+  TagInfo info = (*GetInfo ())[uid - 1];
+  return info.getSerializedSize (data);
+}
+void 
+Tag::Serialize (uint32_t uid, uint8_t data[Tags::SIZE], Buffer::Iterator start)
+{
+  TagInfo info = (*GetInfo ())[uid - 1];
+  info.serialize (data, start);
 }
 uint32_t 
-TagRegistry::LookupUid (std::string uuid)
+Tag::Deserialize (uint32_t uid, uint8_t data[Tags::SIZE], Buffer::Iterator start)
 {
-  if (!m_sorted) 
-    {
-      std::sort (m_registry.begin (), m_registry.end (), &TagRegistry::CompareItem);
-      m_sorted = true;
-    }
-  NS_ASSERT (m_sorted);
-  uint32_t uid = 1;
-  for (TagsDataCI i = m_registry.begin (); i != m_registry.end (); i++) 
-    {
-      if (i->uuid == uuid) 
-        {
-          return uid;
-        }
-      uid++;
-    }
-  // someone asked for a uid for an unregistered uuid.
-  NS_ASSERT (!"You tried to use unregistered tag: make sure you create an instance of type TagRegistration<YouTagType>.");
-  // quiet compiler
-  return 0;
+  TagInfo info = (*GetInfo ())[uid - 1];
+  return info.deserialize (data, start);
 }
-void 
-TagRegistry::PrettyPrint (uint32_t uid, uint8_t buf[Tags::SIZE], std::ostream &os)
-{
-  NS_ASSERT (uid > 0);
-  uint32_t index = uid - 1;
-  NS_ASSERT (m_registry.size () > index);
-  PrettyPrinter prettyPrinter = m_registry[index].printer;
-  if (prettyPrinter != 0) 
-    {
-      prettyPrinter (buf, os);
-    }
-}
-void 
-TagRegistry::Destruct (uint32_t uid, uint8_t buf[Tags::SIZE])
-{
-  NS_ASSERT (uid > 0);
-  uint32_t index = uid - 1;
-  NS_ASSERT (m_registry.size () > index);
-  Destructor destructor = m_registry[index].destructor;
-  NS_ASSERT (destructor != 0);
-  destructor (buf);
-}
-
-
 
 #ifdef USE_FREE_LIST
 
@@ -197,7 +160,7 @@
 {
   for (struct TagData *cur = m_next; cur != 0; cur = cur->m_next) 
     {
-      TagRegistry::GetInstance ()->PrettyPrint (cur->m_id, cur->m_data, os);
+      Tag::Print (cur->m_id, cur->m_data, os);
     }
 }
 
@@ -224,25 +187,65 @@
   virtual bool RunTests (void);
 };
 
-struct myTagA {
+class myTagA 
+{
+public:
+  static const char *GetUid (void) {return "myTagA.test.nsnam.org";}
+  void Print (std::ostream &os) const {g_a = true;}
+  uint32_t GetSerializedSize (void) const {return 0;}
+  void Serialize (Buffer::Iterator i) const {}
+  uint32_t Deserialize (Buffer::Iterator i) {return 0;}
+
   uint8_t a;
 };
-struct myTagB {
+class myTagB 
+{
+public:
+  static const char *GetUid (void) {return "myTagB.test.nsnam.org";}
+  void Print (std::ostream &os) const {g_b = true;}
+  uint32_t GetSerializedSize (void) const {return 0;}
+  void Serialize (Buffer::Iterator i) const {}
+  uint32_t Deserialize (Buffer::Iterator i) {return 0;}
+
   uint32_t b;
 };
-struct myTagC {
+class myTagC 
+{
+public:
+  static const char *GetUid (void) {return "myTagC.test.nsnam.org";}
+  void Print (std::ostream &os) const {g_c = true;}
+  uint32_t GetSerializedSize (void) const {return 0;}
+  void Serialize (Buffer::Iterator i) const {}
+  uint32_t Deserialize (Buffer::Iterator i) {return 0;}
   uint8_t c [Tags::SIZE];
 };
-struct myInvalidTag {
+class myInvalidTag 
+{
+public:
+  static const char *GetUid (void) {return "myInvalidTag.test.nsnam.org";}
+  void Print (std::ostream &os) const {}
+  uint32_t GetSerializedSize (void) const {return 0;}
+  void Serialize (Buffer::Iterator i) const {}
+  uint32_t Deserialize (Buffer::Iterator i) {return 0;}
+
   uint8_t invalid [Tags::SIZE+1];
 };
-struct myTagZ {
+class myTagZ 
+{
+public:
+  static const char *GetUid (void) {return "myTagZ.test.nsnam.org";}
+  void Print (std::ostream &os) const {g_z = true;}
+  uint32_t GetSerializedSize (void) const {return 0;}
+  void Serialize (Buffer::Iterator i) const {}
+  uint32_t Deserialize (Buffer::Iterator i) {return 0;}
+
   uint8_t z;
 };
 
 class MySmartTag 
 {
 public:
+  static const char *GetUid (void) {return "mySmartTag.test.nsnam.org";}
   MySmartTag ()
   {
     //std::cout << "construct" << std::endl;
@@ -260,43 +263,12 @@
     //std::cout << "assign" << std::endl;
     return *this;
   }
-  static void PrettyPrinterCb (const MySmartTag *a, std::ostream &os)
-  {}
+  void Print (std::ostream &os) const {}
+  uint32_t GetSerializedSize (void) const {return 0;}
+  void Serialize (Buffer::Iterator i) const {}
+  uint32_t Deserialize (Buffer::Iterator i) {return 0;}
 };
 
-static void 
-myTagAPrettyPrinterCb (struct myTagA const*a, std::ostream &os)
-{
-  //os << "struct myTagA, a="<<(uint32_t)a->a<<std::endl;
-  g_a = true;
-}
-static void 
-myTagBPrettyPrinterCb (struct myTagB const*b, std::ostream &os)
-{
-  //os << "struct myTagB, b="<<b->b<<std::endl;
-  g_b = true;
-}
-static void 
-myTagCPrettyPrinterCb (struct myTagC const*c, std::ostream &os)
-{
-  //os << "struct myTagC, c="<<(uint32_t)c->c[0]<<std::endl;
-  g_c = true;
-}
-static void 
-myTagZPrettyPrinterCb (struct myTagZ const*z, std::ostream &os)
-{
-  //os << "struct myTagZ" << std::endl;
-  g_z = true;
-}
-
-
-static TagRegistration<struct myTagA> gMyTagARegistration ("A", &myTagAPrettyPrinterCb);
-static TagRegistration<struct myTagB> gMyTagBRegistration ("B", &myTagBPrettyPrinterCb);
-static TagRegistration<struct myTagC> gMyTagCRegistration ("C", &myTagCPrettyPrinterCb);
-static TagRegistration<struct myTagZ> g_myTagZRegistration ("ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ", 
-                                                            &myTagZPrettyPrinterCb);
-static TagRegistration<MySmartTag> g_myTagSmartRegistration ("SmartTag", &MySmartTag::PrettyPrinterCb);
-
 
 TagsTest::TagsTest ()
   : Test ("Tags")
@@ -311,7 +283,7 @@
 
   // build initial tag.
   Tags tags;
-  struct myTagA a;
+  myTagA a;
   a.a = 10;
   tags.Add (a);
   a.a = 0;
@@ -326,7 +298,7 @@
     {
       ok = false;
     }
-  struct myTagB b;
+  myTagB b;
   b.b = 0xff;
   tags.Add (b);
   b.b = 0;
@@ -358,14 +330,14 @@
     {
       ok = false;
     }
-  struct myTagA oA;
+  myTagA oA;
   oA.a = 0;
   other.Peek (oA);
   if (oA.a != 10) 
     {
       ok = false;
     }
-  struct myTagB oB;
+  myTagB oB;
   oB.b = 1;
   other.Peek (oB);
   if (oB.b != 0xff) 
@@ -401,7 +373,7 @@
 
   other = tags;
   Tags another = other;
-  struct myTagC c;
+  myTagC c;
   memset (c.c, 0x66, 16);
   another.Add (c);
   c.c[0] = 0;
@@ -421,7 +393,7 @@
   //struct myInvalidTag invalid;
   //tags.add (&invalid);
 
-  struct myTagZ tagZ;
+  myTagZ tagZ;
   Tags testLastTag;
   tagZ.z = 0;
   testLastTag.Add (tagZ);
--- a/src/common/tags.h	Fri Aug 03 10:39:55 2007 +0200
+++ b/src/common/tags.h	Fri Aug 03 13:00:38 2007 +0200
@@ -24,6 +24,7 @@
 #include <stdint.h>
 #include <ostream>
 #include <vector>
+#include "buffer.h"
 
 namespace ns3 {
 
@@ -79,31 +80,7 @@
   struct TagData *m_next;
 };
 
-/**
- * \brief pretty print packet tags
- * 
- * This class is used to register a pretty-printer
- * callback function to print in a nice user-friendly
- * way the content of the target type. To register
- * such a type, all you need to do is instantiate
- * an instance of this type as a static variable.
- */
-template <typename T>
-class TagRegistration {
-public:
-  /**
-   * \param uuid a uuid generated with uuidgen
-   * \param fn a function which can pretty-print an instance
-   *        of type T in the output stream.
-   */
-  TagRegistration<T> (std::string uuid, void(*fn) (T const*, std::ostream &));
-private:
-  static void PrettyPrinterCb (uint8_t *buf, std::ostream &os);
-  static void DestructorCb (uint8_t *buf);
-  static void(*m_prettyPrinter) (T const*, std::ostream &);
-};
-
-}; // namespace ns3
+} // namespace ns3
 
 
 
@@ -115,110 +92,118 @@
 
 namespace ns3 {
 
-class TagRegistry {
+class Tag
+{
 public:
-  typedef void (*PrettyPrinter) (uint8_t [Tags::SIZE], std::ostream &);
-  typedef void (*Destructor) (uint8_t [Tags::SIZE]);
-  void Record (std::string uuid, PrettyPrinter prettyPrinter, Destructor destructor);
-  /**
-   * returns a numeric integer which uniquely identifies the input string.
-   * that integer cannot be zero which is a reserved value.
-   */
-  uint32_t LookupUid (std::string uuid);
-  void PrettyPrint (uint32_t uid, uint8_t buf[Tags::SIZE], std::ostream &os);
-  void Destruct (uint32_t uid, uint8_t buf[Tags::SIZE]);
-
-  static TagRegistry *GetInstance (void);
+  template <typename T>
+  static uint32_t GetUid (void);
+  static void Destruct (uint32_t uid, uint8_t data[Tags::SIZE]);
+  static void Print (uint32_t uid, uint8_t data[Tags::SIZE], std::ostream &os);
+  static uint32_t GetSerializedSize (uint32_t uid, uint8_t data[Tags::SIZE]);
+  static void Serialize (uint32_t uid, uint8_t data[Tags::SIZE], Buffer::Iterator start);
+  static uint32_t Deserialize (uint32_t uid, uint8_t data[Tags::SIZE], Buffer::Iterator start);
 private:
-  TagRegistry ();
-  struct TagInfoItem
+  typedef void (*DestructCb) (uint8_t [Tags::SIZE]);
+  typedef void (*PrintCb) (uint8_t [Tags::SIZE], std::ostream &);
+  typedef uint32_t (*GetSerializedSizeCb) (uint8_t [Tags::SIZE]);
+  typedef void (*SerializeCb) (uint8_t [Tags::SIZE], Buffer::Iterator);
+  typedef uint32_t (*DeserializeCb) (uint8_t [Tags::SIZE], Buffer::Iterator);
+  struct TagInfo
   {
-    std::string uuid;
-    PrettyPrinter printer;
-    Destructor destructor;
+    std::string uidString;
+    DestructCb destruct;
+    PrintCb print;
+    GetSerializedSizeCb getSerializedSize;
+    SerializeCb serialize;
+    DeserializeCb deserialize;
   };
-  typedef std::vector<struct TagInfoItem> TagsData;
-  typedef std::vector<struct TagInfoItem>::const_iterator TagsDataCI;
-  static bool CompareItem (const struct TagInfoItem &a, const struct TagInfoItem &b);
-  bool m_sorted;
-  TagsData m_registry;
-};
-/**
- * The TypeUid class is used to create a mapping Type --> uid
- * Note that we use a static getUuid function which contains a
- * static std::string variable rather than a simpler static
- * member std::string variable to ensure the proper order
- * of initialization when these methods are invoked
- * from the constructor of another static variable.
- */
-template <typename T>
-class TypeUid {
-public:
-  static void Record (std::string uuid);
-  static const uint32_t GetUid (void);
-private:
-  static std::string *GetUuid (void);
-  T m_realType;
+  typedef std::vector<struct TagInfo> TagInfoVector;
+
+  template <typename T>
+  static void DoDestruct (uint8_t data[Tags::SIZE]);
+  template <typename T>
+  static void DoPrint (uint8_t data[Tags::SIZE], std::ostream &os);
+  template <typename T>
+  static uint32_t DoGetSerializedSize (uint8_t data[Tags::SIZE]);
+  template <typename T>
+  static void DoSerialize (uint8_t data[Tags::SIZE], Buffer::Iterator start);
+  template <typename T>
+  static uint32_t DoDeserialize (uint8_t data[Tags::SIZE], Buffer::Iterator start);
+  template <typename T>
+  static uint32_t AllocateUid (void);
+
+  static TagInfoVector *GetInfo (void);
 };
 
 template <typename T>
-void TypeUid<T>::Record (std::string uuid)
+void 
+Tag::DoDestruct (uint8_t data[Tags::SIZE])
+{
+  T *tag = reinterpret_cast<T *> (data);
+  tag->~T ();  
+}
+template <typename T>
+void 
+Tag::DoPrint (uint8_t data[Tags::SIZE], std::ostream &os)
+{
+  T *tag = reinterpret_cast<T *> (data);
+  tag->Print (os);
+}
+template <typename T>
+uint32_t 
+Tag::DoGetSerializedSize (uint8_t data[Tags::SIZE])
 {
-  *(GetUuid ()) = uuid;
+  T *tag = reinterpret_cast<T *> (data);
+  return tag->GetSerializedSize ();
+}
+template <typename T>
+void 
+Tag::DoSerialize (uint8_t data[Tags::SIZE], Buffer::Iterator start)
+{
+  T *tag = reinterpret_cast<T *> (data);
+  tag->Serialize (start);
+}
+template <typename T>
+uint32_t 
+Tag::DoDeserialize (uint8_t data[Tags::SIZE], Buffer::Iterator start)
+{
+  T *tag = reinterpret_cast<T *> (data);
+  return tag->Deserialize (start);
 }
 
 template <typename T>
-const uint32_t TypeUid<T>::GetUid (void)
+uint32_t 
+Tag::GetUid (void)
 {
-  static const uint32_t uid = TagRegistry::GetInstance ()->
-    LookupUid (*(GetUuid ()));
+  static uint32_t uid = AllocateUid<T> ();
   return uid;
 }
 
 template <typename T>
-std::string *TypeUid<T>::GetUuid (void)
-{
-  static std::string uuid;
-  return &uuid;
-}
-
-
-
-/**
- * Implementation of the TagRegistration registration class.
- * It records a callback with the TagRegistry
- * This callback performs type conversion before forwarding
- * the call to the user-provided function.
- */
-template <typename T>
-TagRegistration<T>::TagRegistration (std::string uuid, void (*prettyPrinter) (T const*, std::ostream &))
+uint32_t 
+Tag::AllocateUid (void)
 {
-  NS_ASSERT (sizeof (T) <= Tags::SIZE);
-  m_prettyPrinter  = prettyPrinter;
-  TagRegistry::GetInstance ()->
-    Record (uuid, &TagRegistration<T>::PrettyPrinterCb, &TagRegistration<T>::DestructorCb);
-  TypeUid<T>::Record (uuid);
+  TagInfoVector *vec = GetInfo ();
+  uint32_t j = 0;
+  for (TagInfoVector::iterator i = vec->begin (); i != vec->end (); i++)
+    {
+      if (i->uidString == T::GetUid ())
+        {
+          return j;
+        }
+      j++;
+    }
+  TagInfo info;
+  info.uidString = T::GetUid ();
+  info.destruct = &Tag::DoDestruct<T>;
+  info.print = &Tag::DoPrint<T>;
+  info.getSerializedSize = &Tag::DoGetSerializedSize<T>;
+  info.serialize = &Tag::DoSerialize<T>;
+  info.deserialize = &Tag::DoDeserialize<T>;
+  vec->push_back (info);
+  uint32_t uid = vec->size ();
+  return uid;
 }
-template <typename T>
-void 
-TagRegistration<T>::PrettyPrinterCb (uint8_t *buf, std::ostream &os)
-{
-  NS_ASSERT (sizeof (T) <= Tags::SIZE);
-  T *tag = reinterpret_cast<T *> (buf);
-  (*m_prettyPrinter) (tag, os);
-}
-template <typename T>
-void
-TagRegistration<T>::DestructorCb (uint8_t *buf)
-{
-  T *tag = reinterpret_cast<T *> (buf);
-  tag->~T ();
-}
-template <typename T>
-void (*TagRegistration<T>::m_prettyPrinter) (T const*, std::ostream &) = 0;
-
-
-
 
 template <typename T>
 void 
@@ -228,12 +213,12 @@
   // ensure this id was not yet added
   for (struct TagData *cur = m_next; cur != 0; cur = cur->m_next) 
     {
-      NS_ASSERT (cur->m_id != TypeUid<T>::GetUid ());
+      NS_ASSERT (cur->m_id != Tag::GetUid<T> ());
     }
   struct TagData *newStart = AllocData ();
   newStart->m_count = 1;
   newStart->m_next = 0;
-  newStart->m_id = TypeUid<T>::GetUid ();
+  newStart->m_id = Tag::GetUid<T> ();
   void *buf = &newStart->m_data;
   new (buf) T (tag);
   newStart->m_next = m_next;
@@ -245,7 +230,7 @@
 Tags::Remove (T &tag)
 {
   NS_ASSERT (sizeof (T) <= Tags::SIZE);
-  return Remove (TypeUid<T>::GetUid ());
+  return Remove (Tag::GetUid<T> ());
 }
 
 template <typename T>
@@ -255,7 +240,7 @@
   NS_ASSERT (sizeof (T) <= Tags::SIZE);
   for (struct TagData *cur = m_next; cur != 0; cur = cur->m_next) 
     {
-      if (cur->m_id == TypeUid<T>::GetUid ()) 
+      if (cur->m_id == Tag::GetUid<T> ()) 
         {
           /* found tag */
           T *data = reinterpret_cast<T *> (&cur->m_data);
@@ -315,16 +300,14 @@
         }
       if (prev != 0) 
         {
-          TagRegistry::GetInstance ()->
-            Destruct (prev->m_id, prev->m_data);
+          Tag::Destruct (prev->m_id, prev->m_data);
           FreeData (prev);
         }
       prev = cur;
     }
   if (prev != 0) 
     {
-      TagRegistry::GetInstance ()->
-        Destruct (prev->m_id, prev->m_data);
+      Tag::Destruct (prev->m_id, prev->m_data);
       FreeData (prev);
     }
   m_next = 0;