Debugging NameInfo, FullState, and DiffState

Now NameInfo is thread-safe and has automatic garbage collector.
Internal container is managed by weak_ptr instead of shared_ptr as it
was before.
diff --git a/doc/doxygen_boost_dummy.h b/doc/doxygen_boost_dummy.h
index 6a409cc..ffcc1b0 100644
--- a/doc/doxygen_boost_dummy.h
+++ b/doc/doxygen_boost_dummy.h
@@ -1 +1,3 @@
 namespace boost { template<class T> class shared_ptr { T *dummy; }; }
+
+namespace Sync { class DiffStateContainer { boost::shared_ptr<DiffState> dummy; }; }
diff --git a/model/sync-full-state.cc b/model/sync-full-state.cc
index 801bfbf..b30d2d4 100644
--- a/model/sync-full-state.cc
+++ b/model/sync-full-state.cc
@@ -64,14 +64,18 @@
 {
   if (m_digest == 0)
     {
+      // std::cout << "getDigest: ";
       m_digest = make_shared<Digest> ();
       BOOST_FOREACH (LeafConstPtr leaf, m_leaves.get<ordered> ())
         {
           FullLeafConstPtr fullLeaf = dynamic_pointer_cast<const FullLeaf> (leaf);
           BOOST_ASSERT (fullLeaf != 0);
           *m_digest << fullLeaf->getDigest ();
+          // std::cout << *leaf << "[" << fullLeaf->getDigest () << "] ";
         }
+      // std::cout << "\n";
     }
+  m_digest->finalize ();
 
   return m_digest;
 }
diff --git a/model/sync-leaf.h b/model/sync-leaf.h
index 037e4a5..00ae151 100644
--- a/model/sync-leaf.h
+++ b/model/sync-leaf.h
@@ -72,6 +72,13 @@
 typedef boost::shared_ptr<Leaf> LeafPtr;
 typedef boost::shared_ptr<const Leaf> LeafConstPtr;
 
+inline std::ostream &
+operator << (std::ostream &os, const Leaf &leaf)
+{
+  os << leaf.getInfo () << "(" << leaf.getSeq () << ")";
+  return os;
+}
+
 } // Sync
 
 #endif // SYNC_LEAF_H
diff --git a/model/sync-name-info.cc b/model/sync-name-info.cc
index 8f730e3..270e6fc 100644
--- a/model/sync-name-info.cc
+++ b/model/sync-name-info.cc
@@ -22,18 +22,12 @@
 
 #include "sync-name-info.h"
 
-#include <boost/lexical_cast.hpp>
+// #include <boost/lexical_cast.hpp>
 
 namespace Sync {
 
 NameInfo::NameMap NameInfo::m_names;
 size_t  NameInfo::m_ids = 0;
-
-/**
- * @brief Calculates digest of the name
- */
-// tempalte<>
-// Digest
-// NameInfo::getDigest<PrefixInfo> () const;
+boost::mutex NameInfo::m_namesMutex;
 
 } // Sync
diff --git a/model/sync-name-info.h b/model/sync-name-info.h
index ebe946b..a4d7e7d 100644
--- a/model/sync-name-info.h
+++ b/model/sync-name-info.h
@@ -24,6 +24,8 @@
 #define SYNC_NAME_INFO_H
 
 #include <boost/shared_ptr.hpp>
+#include <boost/weak_ptr.hpp>
+#include <boost/thread/mutex.hpp>
 #include <map>
 #include <string>
 #include "sync-digest.h"
@@ -37,7 +39,7 @@
 class NameInfo
 {
 private:
-  typedef boost::shared_ptr<const NameInfo> const_ptr;
+  typedef boost::weak_ptr<const NameInfo> const_weak_ptr;
   
 public:
   virtual ~NameInfo () { };
@@ -74,21 +76,28 @@
    */
   virtual std::string
   toString () const = 0;
-
+  
 protected:
   // actual stuff
   size_t m_id; ///< @brief Identifies NameInfo throughout the library (for hash container, doesn't need to be strictly unique)
   Digest m_digest;
 
   // static stuff
-  typedef std::map<std::string, const_ptr> NameMap;
+  typedef std::map<std::string, const_weak_ptr> NameMap;
   static size_t  m_ids;
   static NameMap m_names;
+  static boost::mutex m_namesMutex;
 };
 
 typedef boost::shared_ptr<NameInfo> NameInfoPtr;
 typedef boost::shared_ptr<const NameInfo> NameInfoConstPtr;
 
+inline std::ostream &
+operator << (std::ostream &os, const NameInfo &info)
+{
+  os << info.toString ();
+  return os;
+}
 
 } // Sync
 
diff --git a/model/sync-ns3-name-info.cc b/model/sync-ns3-name-info.cc
index d1c8e31..9e0ef78 100644
--- a/model/sync-ns3-name-info.cc
+++ b/model/sync-ns3-name-info.cc
@@ -27,6 +27,7 @@
 
 #include <boost/foreach.hpp>
 #include <boost/lexical_cast.hpp>
+#include <boost/make_shared.hpp>
 #include <utility>
 
 using namespace std;
@@ -40,11 +41,17 @@
 {
   string key = lexical_cast<string> (*name);
 
-  NameInfoPtr value = NameInfoPtr (new Ns3NameInfo (name));
-  pair<NameMap::iterator,bool> item =
-    m_names.insert (make_pair (key, value));
+  NameMap::iterator item = m_names.find (key);
+  if (item == m_names.end ())
+    {
+      NameInfoPtr value = NameInfoPtr (new Ns3NameInfo (name));
+      pair<NameMap::iterator,bool> inserted =
+        m_names.insert (make_pair (key, value));
+      BOOST_ASSERT (inserted.second); // previous call has to insert value
+      item = inserted.first;
+    }
 
-  return item.first->second;
+  return item->second;
 }
 
 Ns3NameInfo::Ns3NameInfo (ns3::Ptr<const ns3::CcnxNameComponents> name)
diff --git a/model/sync-seq-no.h b/model/sync-seq-no.h
index 354a1b6..ae7f355 100644
--- a/model/sync-seq-no.h
+++ b/model/sync-seq-no.h
@@ -139,6 +139,13 @@
   uint32_t m_seq;
 };
 
+inline std::ostream &
+operator << (std::ostream &os, const SeqNo &seqno)
+{
+  os << seqno.getSession () << ":" << seqno.getSeq ();
+  return os;
+}
+
 } // Sync
 
 #endif // SYNC_SEQ_NO_H
diff --git a/model/sync-state.cc b/model/sync-state.cc
index 2680859..268a45f 100644
--- a/model/sync-state.cc
+++ b/model/sync-state.cc
@@ -19,3 +19,10 @@
  *         卞超轶 Chaoyi Bian <bcy@pku.edu.cn>
  *	   Alexander Afanasyev <alexander.afanasyev@ucla.edu>
  */
+
+#include "sync-state.h"
+#include <boost/assert.hpp>
+
+namespace Sync {
+
+}
diff --git a/model/sync-state.h b/model/sync-state.h
index 0576af2..03d4ec4 100644
--- a/model/sync-state.h
+++ b/model/sync-state.h
@@ -52,7 +52,6 @@
 
   /**
    * @brief Remove leaf from the state tree
-   *
    * @param info name of the leaf
    */
   virtual void
diff --git a/model/sync-std-name-info.cc b/model/sync-std-name-info.cc
index 53fcdac..762ecfd 100644
--- a/model/sync-std-name-info.cc
+++ b/model/sync-std-name-info.cc
@@ -21,8 +21,10 @@
  */
 
 #include "sync-std-name-info.h"
+#include "boost/thread/locks.hpp"
 
 using namespace std;
+using namespace boost;
 
 namespace Sync {
 
@@ -30,11 +32,30 @@
 NameInfoConstPtr
 StdNameInfo::FindOrCreate (const std::string &key)
 {
-  NameInfoPtr value = NameInfoPtr (new StdNameInfo (key));
-  pair<NameMap::iterator,bool> item =
-    m_names.insert (make_pair (key, value));
+  mutex::scoped_lock namesLock (m_namesMutex);
+  
+  // std::cout << "FindOrCreate: " << m_names.size () << "\n";
+  
+  NameInfoConstPtr ret;
+  
+  NameMap::iterator item = m_names.find (key);
+  if (item != m_names.end ())
+    {
+      ret = item->second.lock ();
+      BOOST_ASSERT (ret != 0);
+    }
+  else
+    {
+      ret = NameInfoPtr (new StdNameInfo (key));
+      weak_ptr<const NameInfo> value (ret);
+      pair<NameMap::iterator,bool> inserted =
+        m_names.insert (make_pair (key, value));
+      
+      BOOST_ASSERT (inserted.second); // previous call has to insert value
+      item = inserted.first;
+    }
 
-  return item.first->second;
+  return ret;
 }
 
 StdNameInfo::StdNameInfo (const std::string &name)
@@ -43,6 +64,16 @@
   m_id = m_ids ++; // set ID for a newly inserted element
   m_digest << name;
   m_digest.getHash (); // finalize digest
+
+  // std::cout << "StdNameInfo: " << name << " = " << m_id << "\n";
+}
+
+StdNameInfo::~StdNameInfo ()
+{
+  mutex::scoped_lock namesLock (m_namesMutex);
+
+  // cout << "Destructor for " << m_name << "\n";
+  m_names.erase (toString ());
 }
 
 string
diff --git a/model/sync-std-name-info.h b/model/sync-std-name-info.h
index 1821fb4..a70af38 100644
--- a/model/sync-std-name-info.h
+++ b/model/sync-std-name-info.h
@@ -38,7 +38,10 @@
   static NameInfoConstPtr
   FindOrCreate (const std::string &name);
 
-  virtual ~StdNameInfo () { };
+  /**
+   * @brief Destructor which will clean up m_names structure
+   */
+  virtual ~StdNameInfo ();
   
   // from NameInfo
   virtual bool
diff --git a/test/test.cc b/test/test.cc
deleted file mode 100644
index 55745d9..0000000
--- a/test/test.cc
+++ /dev/null
@@ -1,25 +0,0 @@
-/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */
-/*
- * Copyright (c) 2012 University of California, Los Angeles
- *
- * 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: Zhenkai Zhu <zhenkai@cs.ucla.edu>
- *         卞超轶 Chaoyi Bian <bcy@pku.edu.cn>
- *	   Alexander Afanasyev <alexander.afanasyev@ucla.edu>
- */
-
-#define BOOST_TEST_MODULE Digest
-#include <boost/test/unit_test.hpp>
-
diff --git a/test/test_digest.cc b/test/test_digest.cc
index a1ae6a3..cbbc385 100644
--- a/test/test_digest.cc
+++ b/test/test_digest.cc
@@ -20,6 +20,7 @@
  *	   Alexander Afanasyev <alexander.afanasyev@ucla.edu>
  */
 
+#define BOOST_TEST_MAIN 1
 #include <boost/test/unit_test.hpp>
 #include <boost/test/output_test_stream.hpp> 
 using boost::test_tools::output_test_stream;
@@ -32,7 +33,7 @@
 using namespace std;
 using namespace boost;
 
-BOOST_AUTO_TEST_SUITE(DigestTestSuite)
+BOOST_AUTO_TEST_SUITE(DigestTests)
 
 BOOST_AUTO_TEST_CASE (BasicTest)
 {
@@ -96,4 +97,3 @@
 }
 
 BOOST_AUTO_TEST_SUITE_END()
-
diff --git a/test/test_leaf.cc b/test/test_leaf.cc
index 991e14b..76b517c 100644
--- a/test/test_leaf.cc
+++ b/test/test_leaf.cc
@@ -34,7 +34,7 @@
 using namespace std;
 using namespace boost;
 
-BOOST_AUTO_TEST_SUITE(LeafTestSuite)
+BOOST_AUTO_TEST_SUITE(LeafTests)
 
 BOOST_AUTO_TEST_CASE (LeafBase)
 {
@@ -43,19 +43,19 @@
 
   // find the same name
   BOOST_CHECK (name.get () == StdNameInfo::FindOrCreate ("/test/name").get ());
-  BOOST_CHECK_EQUAL (name.use_count (), 2);
+  BOOST_CHECK_EQUAL (name.use_count (), 1);
 
   BOOST_CHECK_NO_THROW (DiffLeaf x (name, SeqNo (12)));
-  BOOST_CHECK_EQUAL (name.use_count (), 2);
+  BOOST_CHECK_EQUAL (name.use_count (), 1);
   
   BOOST_CHECK_NO_THROW (DiffLeaf x (name));
-  BOOST_CHECK_EQUAL (name.use_count (), 2);
+  BOOST_CHECK_EQUAL (name.use_count (), 1);
 
   DiffLeaf updateLeaf (name, SeqNo (12));
-  BOOST_CHECK_EQUAL (name.use_count (), 3);
+  BOOST_CHECK_EQUAL (name.use_count (), 2);
 
   DiffLeaf removeLeaf (name);
-  BOOST_CHECK_EQUAL (name.use_count (), 4);
+  BOOST_CHECK_EQUAL (name.use_count (), 3);
 
   BOOST_CHECK_EQUAL (updateLeaf.getOperation (), UPDATE);
   BOOST_CHECK_EQUAL (updateLeaf.getSeq ().getSession (), 0);
@@ -67,12 +67,12 @@
   
   BOOST_REQUIRE_NO_THROW (FullLeaf x (name, SeqNo (12)));
   FullLeaf fullLeaf (name, SeqNo (12));
-  BOOST_CHECK_EQUAL (name.use_count (), 5);
+  BOOST_CHECK_EQUAL (name.use_count (), 4);
 }
 
 BOOST_AUTO_TEST_CASE (LeafDigest)
 {
-  BOOST_CHECK_EQUAL (StdNameInfo::FindOrCreate ("/test/name").use_count (), 2);
+  BOOST_CHECK_EQUAL (StdNameInfo::FindOrCreate ("/test/name").use_count (), 1);
   NameInfoConstPtr name = StdNameInfo::FindOrCreate ("/test/name");
   FullLeaf fullLeaf (name, SeqNo (12));
 
diff --git a/test/test_state.cc b/test/test_state.cc
index 00be3c4..ff0a8a1 100644
--- a/test/test_state.cc
+++ b/test/test_state.cc
@@ -20,6 +20,9 @@
  *	   Alexander Afanasyev <alexander.afanasyev@ucla.edu>
  */
 
+#define BOOST_TEST_DYN_LINK 1
+#define BOOST_TEST_NO_MAIN 1
+// #define BOOST_TEST_MODULE StateTests
 #include <boost/test/unit_test.hpp>
 #include <boost/test/output_test_stream.hpp> 
 using boost::test_tools::output_test_stream;
@@ -35,7 +38,7 @@
 using namespace std;
 using namespace boost;
 
-BOOST_AUTO_TEST_SUITE(StateTestSuite)
+BOOST_AUTO_TEST_SUITE(StateTests)
 
 BOOST_AUTO_TEST_CASE (FullStateTest)
 {
@@ -84,4 +87,52 @@
   BOOST_CHECK_EQUAL ((*state.getLeaves ().begin ())->getSeq ().getSeq (), 0);
 }
 
+BOOST_AUTO_TEST_CASE (FullStateDigestTest)
+{
+  FullState state;
+  BOOST_CHECK_EQUAL (state.getLeaves ().size (), 0);
+
+  NameInfoConstPtr name3 = StdNameInfo::FindOrCreate ("3");
+  NameInfoConstPtr name2 = StdNameInfo::FindOrCreate ("2");
+  NameInfoConstPtr name1 = StdNameInfo::FindOrCreate ("1");
+
+  state.update (name1, SeqNo (10));
+  DigestConstPtr digest1 = state.getDigest ();
+
+  state.update (name2, SeqNo (12));
+  DigestConstPtr digest2 = state.getDigest ();
+
+  BOOST_CHECK (digest1.get () != digest2.get ());
+  BOOST_CHECK (!digest1->empty ());
+  BOOST_CHECK (!digest2->empty ());
+
+  state.update (name3, SeqNo (8));
+  DigestConstPtr digest3 = state.getDigest ();
+
+  BOOST_CHECK (digest1.get () != digest2.get ());
+  BOOST_CHECK (digest2.get () != digest3.get ());
+  BOOST_CHECK (digest1.get () != digest3.get ());
+
+  BOOST_CHECK (*digest1 != *digest2);
+  BOOST_CHECK (*digest2 != *digest3);
+  BOOST_CHECK (*digest1 != *digest3);
+
+  // removing elements. Digest should get reverted to digest1
+  state.remove (name2);
+  state.remove (name3);
+  DigestConstPtr digest4 = state.getDigest ();
+  BOOST_CHECK (*digest1 == *digest4);
+
+  name2.reset (); // force destructor
+  name3.reset (); // force destructor
+  name3 = StdNameInfo::FindOrCreate ("3"); // this will enforce different (larger) hashing ID of name
+  name2 = StdNameInfo::FindOrCreate ("2"); // this will enforce different (larger) hashing ID of name
+  
+  // adding in different order
+  state.update (name3, SeqNo (8));
+  state.update (name2, SeqNo (12));
+  DigestConstPtr digest5 = state.getDigest ();
+  BOOST_CHECK (*digest5 == *digest3);
+}
+
 BOOST_AUTO_TEST_SUITE_END()