The unified diff between revisions [d57ff5f2..] and [7c8eae2e..] is displayed below. It can also be downloaded as a raw diff.

#
#
# patch "automate.cc"
#  from [381aaa54664879781aeba167a628c1ed97ba627f]
#    to [b513cd2780072daf1c03093dfde2b6a72da91221]
#
# patch "cert.cc"
#  from [e5059ada4c46b52d3d44a9967e704189a107e58b]
#    to [baf8acba61115f8f561be684f14d2bcfa5b1c95f]
#
# patch "cert.hh"
#  from [20b394fcb2715e2c1665cf078730b884530a78ab]
#    to [90f326c5c7395da76887c895e636490aae3ad23e]
#
# patch "cmd_merging.cc"
#  from [ef43a52ba5c71523ce8f64368ba4ab53d91eb735]
#    to [685d9601b8f0b2c245f7becc559c72a6496d90a2]
#
# patch "cmd_ws_commit.cc"
#  from [201c71b8a02f01f3f08ee18b55523e8e59f2b9a1]
#    to [f45192e24f0bcba0176136388df7b9ca1d273537]
#
# patch "commands.cc"
#  from [2156e9f28dd15029e426843e7d2cdbb4a7dfe0b2]
#    to [9db4e7816d584602c8ed1efb524b2d3d05a9ad97]
#
# patch "database.cc"
#  from [8765d79143535887778cb91322718a434f3fbdba]
#    to [ef355812309f57af3e2dbd9c199a57e7c3fda06f]
#
# patch "database.hh"
#  from [3dc62906e661f144ada2f80a80c07aa229d6e18e]
#    to [18d6041a5d6d8afaf2ddf77d89705e055a7ee703]
#
# patch "revision.cc"
#  from [3be6565e4dff6cc477866d5422b37d03ade13657]
#    to [758b12a05a00d2d054fa0121b016cb0f0558091a]
#
# patch "revision.hh"
#  from [9dc4a2e883ba9541b24d098a7ef2d08ae6228292]
#    to [35f2a6a122c321d7245268cce0e240c1bea51c8f]
#
# patch "update.cc"
#  from [92b1a8f703b14a10968969c070d4cb274cffc0d7]
#    to [df7f47db494f2814c1361a3f6531ec9820a3d321]
#
# patch "update.hh"
#  from [aa070b20691c389d9ff8458443f37a9add12383e]
#    to [1e41452e61b608f50c9822ae8c340c6ffaad48a8]
#
# patch "vocab.hh"
#  from [9c9abcf5283f4d0a4fdc7d1d1751b0617ec7ecc5]
#    to [aece3297d8a1e46392f6278eb0a478edc1071625]
#
============================================================
--- automate.cc	381aaa54664879781aeba167a628c1ed97ba627f
+++ automate.cc	b513cd2780072daf1c03093dfde2b6a72da91221
@@ -33,6 +33,7 @@
 #include "vocab.hh"
 #include "globish.hh"
 #include "charset.hh"
+#include "hash_map.hh"

 using std::allocator;
 using std::basic_ios;
@@ -52,7 +53,9 @@ using std::vector;
 using std::string;
 using std::vector;

+using hashmap::hash_set;

+
 // Name: heads
 // Arguments:
 //   1: branch name (optional, default branch is used if non-existant)
@@ -71,9 +74,9 @@ AUTOMATE(heads, N_("[BRANCH]"))
     // branchname was explicitly given, use that
     app.set_branch(idx(args, 0));
   }
-  set<revision_id> heads;
+  hash_set<revision_id> heads;
   get_branch_heads(app.branch_name(), app, heads);
-  for (set<revision_id>::const_iterator i = heads.begin(); i != heads.end(); ++i)
+  for (hash_set<revision_id>::const_iterator i = heads.begin(); i != heads.end(); ++i)
     output << (*i).inner()() << endl;
 }

@@ -183,7 +186,7 @@ AUTOMATE(erase_ancestors, N_("[REV1 [REV
 //   stdout, prints an error message to stderr, and exits with status 1.
 AUTOMATE(erase_ancestors, N_("[REV1 [REV2 [REV3 [...]]]]"))
 {
-  set<revision_id> revs;
+  hash_set<revision_id> revs;
   for (vector<utf8>::const_iterator i = args.begin(); i != args.end(); ++i)
     {
       revision_id rid((*i)());
@@ -191,7 +194,7 @@ AUTOMATE(erase_ancestors, N_("[REV1 [REV
       revs.insert(rid);
     }
   erase_ancestors(revs, app);
-  for (set<revision_id>::const_iterator i = revs.begin(); i != revs.end(); ++i)
+  for (hash_set<revision_id>::const_iterator i = revs.begin(); i != revs.end(); ++i)
     output << (*i).inner()() << endl;
 }

============================================================
--- cert.cc	e5059ada4c46b52d3d44a9967e704189a107e58b
+++ cert.cc	baf8acba61115f8f561be684f14d2bcfa5b1c95f
@@ -32,6 +32,7 @@
 #include "simplestring_xform.hh"
 #include "transforms.hh"
 #include "ui.hh"
+#include "hash_map.hh"

 using std::make_pair;
 using std::map;
@@ -46,6 +47,8 @@ using boost::lexical_cast;
 using boost::tuple;
 using boost::lexical_cast;

+using hashmap::hash_set;
+
 // The alternaive is to #include "cert.hh" in vocab.*, which is even
 // uglier.

@@ -560,7 +563,7 @@ get_branch_heads(cert_value const & bran
 void
 get_branch_heads(cert_value const & branchname,
                  app_state & app,
-                 set<revision_id> & heads)
+                 hash_set<revision_id> & heads)
 {
   L(FL("getting heads of branch %s") % branchname);
   base64<cert_value> branch_encoded;
============================================================
--- cert.hh	20b394fcb2715e2c1665cf078730b884530a78ab
+++ cert.hh	90f326c5c7395da76887c895e636490aae3ad23e
@@ -18,6 +18,7 @@
 #include <time.h>

 #include "vocab.hh"
+#include "hash_map.hh"

 // Certs associate an opaque name/value pair with a revision ID, and
 // are accompanied by an RSA public-key signature attesting to the
@@ -92,7 +93,7 @@ get_branch_heads(cert_value const & bran
 void
 get_branch_heads(cert_value const & branchname,
                  app_state & app,
-                 std::set<revision_id> & heads);
+                 hashmap::hash_set<revision_id> & heads);

 // We also define some common cert types, to help establish useful
 // conventions. you should use these unless you have a compelling
============================================================
--- cmd_merging.cc	ef43a52ba5c71523ce8f64368ba4ab53d91eb735
+++ cmd_merging.cc	685d9601b8f0b2c245f7becc559c72a6496d90a2
@@ -21,6 +21,7 @@
 #include "update.hh"
 #include "work.hh"
 #include "safe_map.hh"
+#include "hash_map.hh"

 using std::cout;
 using std::map;
@@ -31,6 +32,8 @@ using boost::shared_ptr;

 using boost::shared_ptr;

+using hashmap::hash_set;
+
 static void
 three_way_merge(roster_t const & ancestor_roster,
                 roster_t const & left_roster, roster_t const & right_roster,
@@ -100,7 +103,7 @@ CMD(update, N_("workspace"), "",
   if (app.revision_selectors.size() == 0)
     {
       P(F("updating along branch '%s'") % app.branch_name);
-      set<revision_id> candidates;
+      hash_set<revision_id> candidates;
       pick_update_candidates(old_rid, app, candidates);
       N(!candidates.empty(),
         F("your request matches no descendents of the current revision\n"
@@ -110,7 +113,7 @@ CMD(update, N_("workspace"), "",
       if (candidates.size() != 1)
         {
           P(F("multiple update candidates:"));
-          for (set<revision_id>::const_iterator i = candidates.begin();
+          for (hash_set<revision_id>::const_iterator i = candidates.begin();
                i != candidates.end(); ++i)
             P(i18n_format("  %s") % describe_revision(app, *i));
           P(F("choose one with '%s update -r<id>'") % ui.prog_name);
@@ -320,7 +323,7 @@ CMD(merge, N_("tree"), "", N_("merge unm
     option::branch_name % option::date % option::author)
 {
   typedef std::pair<revision_id, revision_id> revpair;
-  typedef set<revision_id>::const_iterator rid_set_iter;
+  typedef hash_set<revision_id>::const_iterator rid_set_iter;

   if (args.size() != 0)
     throw usage(name);
@@ -328,7 +331,7 @@ CMD(merge, N_("tree"), "", N_("merge unm
   N(app.branch_name() != "",
     F("please specify a branch, with --branch=BRANCH"));

-  set<revision_id> heads;
+  hash_set<revision_id> heads;
   get_branch_heads(app.branch_name(), app, heads);

   N(heads.size() != 0, F("branch '%s' is empty") % app.branch_name);
@@ -342,7 +345,7 @@ CMD(merge, N_("tree"), "", N_("merge unm
     % heads.size() % app.branch_name);

   map<revision_id, revpair> heads_for_ancestor;
-  set<revision_id> ancestors;
+  hash_set<revision_id> ancestors;
   size_t pass = 1, todo = heads.size() - 1;

   // If there are more than two heads to be merged, on each iteration we
@@ -457,7 +460,7 @@ CMD(merge_into_dir, N_("tree"), N_("SOUR
   //   'dir' in the merged tree. (ie, it has name "basename(dir)", and its
   //   parent node is "N2.get_node(dirname(dir))")

-  set<revision_id> src_heads, dst_heads;
+  hash_set<revision_id> src_heads, dst_heads;

   if (args.size() != 3)
     throw usage(name);
@@ -471,8 +474,8 @@ CMD(merge_into_dir, N_("tree"), N_("SOUR
   N(dst_heads.size() != 0, F("branch '%s' is empty") % idx(args, 1)());
   N(dst_heads.size() == 1, F("branch '%s' is not merged") % idx(args, 1)());

-  set<revision_id>::const_iterator src_i = src_heads.begin();
-  set<revision_id>::const_iterator dst_i = dst_heads.begin();
+  hash_set<revision_id>::const_iterator src_i = src_heads.begin();
+  hash_set<revision_id>::const_iterator dst_i = dst_heads.begin();

   P(F("propagating %s -> %s") % idx(args,0) % idx(args,1));
   P(F("[source] %s") % *src_i);
@@ -818,7 +821,7 @@ CMD(heads, N_("tree"), "", N_("show unme
 CMD(heads, N_("tree"), "", N_("show unmerged head revisions of branch"),
     option::branch_name)
 {
-  set<revision_id> heads;
+  hash_set<revision_id> heads;
   if (args.size() != 0)
     throw usage(name);

@@ -834,7 +837,7 @@ CMD(heads, N_("tree"), "", N_("show unme
   else
     P(F("branch '%s' is currently unmerged:") % app.branch_name);

-  for (set<revision_id>::const_iterator i = heads.begin();
+  for (hash_set<revision_id>::const_iterator i = heads.begin();
        i != heads.end(); ++i)
     cout << describe_revision(app, *i) << "\n";
 }
============================================================
--- cmd_ws_commit.cc	201c71b8a02f01f3f08ee18b55523e8e59f2b9a1
+++ cmd_ws_commit.cc	f45192e24f0bcba0176136388df7b9ca1d273537
@@ -18,6 +18,7 @@
 #include "revision.hh"
 #include "transforms.hh"
 #include "work.hh"
+#include "hash_map.hh"

 using std::cout;
 using std::make_pair;
@@ -29,6 +30,8 @@ using boost::shared_ptr;

 using boost::shared_ptr;

+using hashmap::hash_set;
+
 static void
 get_log_message_interactively(revision_t const & cs,
                               app_state & app,
@@ -424,14 +427,14 @@ CMD(checkout, N_("tree"), N_("[DIRECTORY
       N(!app.branch_name().empty(),
         F("use --revision or --branch to specify what to checkout"));

-      set<revision_id> heads;
+      hash_set<revision_id> heads;
       get_branch_heads(app.branch_name(), app, heads);
       N(heads.size() > 0,
         F("branch '%s' is empty") % app.branch_name);
       if (heads.size() > 1)
         {
           P(F("branch %s has multiple heads:") % app.branch_name);
-          for (set<revision_id>::const_iterator i = heads.begin(); i != heads.end(); ++i)
+          for (hash_set<revision_id>::const_iterator i = heads.begin(); i != heads.end(); ++i)
             P(i18n_format("  %s") % describe_revision(app, *i));
           P(F("choose one with '%s checkout -r<id>'") % ui.prog_name);
           E(false, F("branch %s has multiple heads") % app.branch_name);
@@ -680,7 +683,7 @@ CMD(commit, N_("workspace"), N_("[PATH].
   cert_value branchname;
   I(restricted_rev.edges.size() == 1);

-  set<revision_id> heads;
+  hash_set<revision_id> heads;
   get_branch_heads(app.branch_name(), app, heads);
   unsigned int old_head_size = heads.size();

============================================================
--- commands.cc	2156e9f28dd15029e426843e7d2cdbb4a7dfe0b2
+++ commands.cc	9db4e7816d584602c8ed1efb524b2d3d05a9ad97
@@ -17,6 +17,7 @@
 #include "cert.hh"
 #include "ui.hh"
 #include "cmd.hh"
+#include "hash_map.hh"

 #ifndef _WIN32
 #include <boost/lexical_cast.hpp>
@@ -30,6 +31,8 @@ using std::vector;
 using std::strlen;
 using std::vector;

+using hashmap::hash_set;
+
 // this file defines the task-oriented "top level" commands which can be
 // issued as part of a monotone command line. the command line can only
 // have one such command on it, followed by a vector of strings which are its
@@ -434,7 +437,7 @@ notify_if_multiple_heads(app_state & app
 void
 notify_if_multiple_heads(app_state & app)
 {
-  set<revision_id> heads;
+  hash_set<revision_id> heads;
   get_branch_heads(app.branch_name(), app, heads);
   if (heads.size() > 1) {
     string prefixedline;
============================================================
--- database.cc	8765d79143535887778cb91322718a434f3fbdba
+++ database.cc	ef355812309f57af3e2dbd9c199a57e7c3fda06f
@@ -39,6 +39,7 @@
 #include "vocab.hh"
 #include "xdelta.hh"
 #include "epoch.hh"
+#include "hash_map.hh"

 #undef _REENTRANT
 #include "lru_cache.h"
@@ -68,6 +69,8 @@ using boost::lexical_cast;
 using boost::shared_ptr;
 using boost::lexical_cast;

+using hashmap::hash_set;
+
 int const one_row = 1;
 int const one_col = 1;
 int const any_rows = -1;
@@ -2223,7 +2226,7 @@ database::get_revisions_with_cert(cert_n
 void
 database::get_revisions_with_cert(cert_name const & name,
                                   base64<cert_value> const & val,
-                                  set<revision_id> & revisions)
+                                  hashmap::hash_set<revision_id> & revisions)
 {
   revisions.clear();
   results res;
@@ -2517,7 +2520,7 @@ void database::complete(selector_type ty
               set<revision_id> heads;
               for (vector<cert_value>::const_iterator bn = branch_names.begin(); bn != branch_names.end(); bn++)
                 {
-                  set<revision_id> branch_heads;
+                  hash_set<revision_id> branch_heads;
                   get_branch_heads(*bn, *__app, branch_heads);
                   heads.insert(branch_heads.begin(), branch_heads.end());
                   L(FL("after get_branch_heads for %s, heads has %d entries") % (*bn) % heads.size());
@@ -2899,7 +2902,7 @@ database::put_roster(revision_id const &
 }


-typedef hashmap::hash_multimap<string, string> ancestry_map;
+typedef multimap<string, string> ancestry_map;

 static void
 transitive_closure(string const & x,
============================================================
--- database.hh	3dc62906e661f144ada2f80a80c07aa229d6e18e
+++ database.hh	18d6041a5d6d8afaf2ddf77d89705e055a7ee703
@@ -22,6 +22,8 @@ int sqlite3_finalize(sqlite3_stmt *);
 #include <map>
 #include <string>

+#include "hash_map.hh"
+
 #include "cset.hh"
 #include "numeric_vocab.hh"
 #include "paths.hh"
@@ -359,7 +361,7 @@ public:

   void get_revisions_with_cert(cert_name const & name,
                                base64<cert_value> const & value,
-                               std::set<revision_id> & revisions);
+                               hashmap::hash_set<revision_id> & revisions);

   void get_revision_certs(revision_id const & ident,
                           std::vector< revision<cert> > & certs);
============================================================
--- revision.cc	3be6565e4dff6cc477866d5422b37d03ade13657
+++ revision.cc	758b12a05a00d2d054fa0121b016cb0f0558091a
@@ -62,6 +62,8 @@ using boost::shared_ptr;
 using boost::dynamic_bitset;
 using boost::shared_ptr;

+using hashmap::hash_set;
+
 void revision_t::check_sane() const
 {
   // null id in current manifest only permitted if previous
@@ -432,8 +434,8 @@ accumulate_strict_ancestors(revision_id

 static void
 accumulate_strict_ancestors(revision_id const & start,
-                            set<revision_id> & new_ancestors,
-                            set<revision_id> & all_ancestors,
+                            hash_set<revision_id> & new_ancestors,
+                            hash_set<revision_id> & all_ancestors,
                             multimap<revision_id, revision_id> const & inverse_graph)
 {
   typedef multimap<revision_id, revision_id>::const_iterator gi;
@@ -472,7 +474,7 @@ void
 // set to get a new minimum height (perhaps, whenever we remove the minimum
 // height candidate).
 void
-erase_ancestors_and_failures(std::set<revision_id> & candidates,
+erase_ancestors_and_failures(hash_set<revision_id> & candidates,
                              is_failure & p,
                              app_state & app)
 {
@@ -489,7 +491,7 @@ erase_ancestors_and_failures(std::set<re

   // Keep a set of all ancestors that we've traversed -- to avoid
   // combinatorial explosion.
-  set<revision_id> all_ancestors;
+  hash_set<revision_id> all_ancestors;

   vector<revision_id> todo(candidates.begin(), candidates.end());
   std::random_shuffle(todo.begin(), todo.end());
@@ -512,10 +514,10 @@ erase_ancestors_and_failures(std::set<re
       // okay, it is good enough that all its ancestors should be
       // eliminated; do that now.
       {
-        set<revision_id> new_ancestors;
+        hash_set<revision_id> new_ancestors;
         accumulate_strict_ancestors(rid, new_ancestors, all_ancestors, inverse_graph);
         I(new_ancestors.find(rid) == new_ancestors.end());
-        for (set<revision_id>::const_iterator i = new_ancestors.begin();
+        for (hash_set<revision_id>::const_iterator i = new_ancestors.begin();
              i != new_ancestors.end(); ++i)
           candidates.erase(*i);
       }
@@ -537,7 +539,7 @@ void
   };
 }
 void
-erase_ancestors(set<revision_id> & revisions, app_state & app)
+erase_ancestors(hash_set<revision_id> & revisions, app_state & app)
 {
   no_failures p;
   erase_ancestors_and_failures(revisions, p, app);
============================================================
--- revision.hh	9dc4a2e883ba9541b24d098a7ef2d08ae6228292
+++ revision.hh	35f2a6a122c321d7245268cce0e240c1bea51c8f
@@ -18,6 +18,7 @@
 #include "app_state.hh"
 #include "cset.hh"
 #include "vocab.hh"
+#include "hash_map.hh"

 // a revision is a text object. It has a precise, normalizable serial form
 // as UTF-8 text. it also has some sub-components. not all of these
@@ -131,7 +132,7 @@ void
          app_state & app);

 void
-erase_ancestors(std::set<revision_id> & revisions, app_state & app);
+erase_ancestors(hashmap::hash_set<revision_id> & revisions, app_state & app);

 struct is_failure
 {
@@ -139,7 +140,7 @@ void
   virtual ~is_failure() {};
 };
 void
-erase_ancestors_and_failures(std::set<revision_id> & revisions,
+erase_ancestors_and_failures(hashmap::hash_set<revision_id> & revisions,
                              is_failure & p,
                              app_state & app);

============================================================
--- update.cc	92b1a8f703b14a10968969c070d4cb274cffc0d7
+++ update.cc	df7f47db494f2814c1361a3f6531ec9820a3d321
@@ -21,6 +21,7 @@
 #include "update.hh"
 #include "vocab.hh"
 #include "revision.hh"
+#include "hash_map.hh"

 // these functions just encapsulate the (somewhat complex) logic behind
 // picking an update target. the actual updating takes place in
@@ -49,6 +50,8 @@ using boost::lexical_cast;

 using boost::lexical_cast;

+using hashmap::hash_set;
+
 static void
 get_test_results_for_revision(revision_id const & id,
                               map<rsa_keypair_id, bool> & results,
@@ -115,7 +118,7 @@ calculate_update_set(revision_id const &
 calculate_update_set(revision_id const & base,
                      cert_value const & branch,
                      app_state & app,
-                     set<revision_id> & candidates)
+                     hash_set<revision_id> & candidates)
 {
   map<rsa_keypair_id, bool> base_results;
   get_test_results_for_revision(base, base_results, app);
@@ -160,7 +163,7 @@ void pick_update_candidates(revision_id

 void pick_update_candidates(revision_id const & base_ident,
                             app_state & app,
-                            set<revision_id> & candidates)
+                            hash_set<revision_id> & candidates)
 {
   N(app.branch_name() != "",
     F("cannot determine branch for update"));
============================================================
--- update.hh	aa070b20691c389d9ff8458443f37a9add12383e
+++ update.hh	1e41452e61b608f50c9822ae8c340c6ffaad48a8
@@ -14,6 +14,7 @@

 #include "app_state.hh"
 #include "vocab.hh"
+#include "hash_map.hh"

 // this function just encapsulates the (somewhat complex) logic
 // behind picking an update target. the actual updating takes
@@ -26,7 +27,7 @@ void pick_update_candidates(revision_id

 void pick_update_candidates(revision_id const & base_ident,
                             app_state & app,
-                            std::set<revision_id> &candidates);
+                            hashmap::hash_set<revision_id> &candidates);

 // Local Variables:
 // mode: C++
============================================================
--- vocab.hh	9c9abcf5283f4d0a4fdc7d1d1751b0617ec7ecc5
+++ vocab.hh	aece3297d8a1e46392f6278eb0a478edc1071625
@@ -16,6 +16,8 @@
 #include <string>
 #include <iosfwd>

+#include "hash_map.hh"
+
 // the purpose of this file is to wrap things which are otherwise strings
 // in a bit of typesafety, set up enumerations and tuple-types, and
 // generally describe the "vocabulary" (nouns anyways) that modules in this
@@ -159,7 +161,18 @@ null_id(revision_id const & i)
   return i.inner()().empty();
 }

+namespace hashmap {
+  template<>
+  struct hash<revision_id>
+  {
+    size_t operator()(revision_id const & i) const
+    {
+      return hash<std::string>()(i.inner()());
+    }
+  };
+}

+
 hexenc<id>
 fake_id();