#
# add_file "roster.cc"
#
# add_file "roster.hh"
#
# patch "roster.cc"
# from []
# to [56c408cbe2142701df6c3e55b67d8e1795968351]
#
# patch "roster.hh"
# from []
# to [5d4079ef6f31eb50e37271f6a48c43e0648a1890]
#
# patch "vocab_terms.hh"
# from [9abc8225074b278d3b7a57c291ab5d8fd0a98ea6]
# to [3ccb25132c10e1a06c23b7ef1f321667c8f58c8b]
#
========================================================================
--- roster.cc
+++ roster.cc 56c408cbe2142701df6c3e55b67d8e1795968351
@@ -0,0 +1,118 @@
+// copyright (C) 2005 nathaniel smith
+// all rights reserved.
+// licensed to the public under the terms of the GNU GPL (>= 2)
+// see the file COPYING for details
+
+#include "roster.hh"
+
+template
+V &
+get_existing_value(std::map & m, K const & key)
+{
+ std::map::iterator i = m.find(key);
+ I(i != m.end());
+ return i->second;
+}
+
+// FIXME: what semantics, exactly, does this expect of file_path's split/join
+// logic, wrt handling of null paths?
+
+element_soul
+lookup(roster_t const & roster, file_path const & fp)
+{
+ std::vector pieces;
+ fp.split(pieces);
+ element_soul es = root_dir;
+ I(!null_soul(es));
+ for (std::vector::const_iterator i = pieces.begin();
+ i != pieces.end(); ++i)
+ es = get_existing_value(get_existing_value(roster.children, es), *i);
+ return es;
+}
+
+void
+get_name(roster_t const & roster, element_soul es, file_path & fp)
+{
+ std::vector pieces;
+ while (es != roster.root_dir)
+ {
+ element_t const & element = get_existing_value(roster.elements, es);
+ pieces.push_back(element.name);
+ es = element.parent;
+ }
+ std::reverse(pieces.begin(), pieces.end());
+ fp = file_path(pieces);
+}
+
+void
+check_sane_element(element_t const & element)
+{
+ I(!null_id(element.birth_revision));
+ if (element.is_dir)
+ {
+ I(null_name(element.name) == null_soul(element.parent));
+ I(null_id(element.content));
+ }
+ else
+ {
+ I(!null_name(element.name));
+ I(!null_soul(element.parent));
+ I(!null_id(element.content));
+ }
+}
+
+bool is_root_dir(element_t const & element)
+{
+ return null_soul(element.parent);
+}
+
+roster_t::roster_t(element_map const & elements)
+ : elements(elements)
+{
+ // first pass: find all directories and the unique root directory
+ bool found_root_dir = false;
+ for (element_map::const_iterator i = elements.begin(); i != elements.end(); ++i)
+ {
+ element_soul es = i->first;
+ element_t const & element = i->second;
+ check_sane_element(element);
+ if (element.is_dir)
+ {
+ if (is_root_dir(element))
+ {
+ I(!found_root_dir);
+ found_root_dir = true;
+ root_dir = es;
+ }
+ children.insert(std::make_pair(es,
+ std::map()));
+ }
+ }
+ I(found_root_dir);
+ // second pass: fill in each directory
+ for (element_map::const_iterator i = elements.begin(); i != elements.end(); ++i)
+ {
+ element_soul es = i->first;
+ element_t const & element = i->second;
+ if (es == root_dir)
+ continue;
+ dir_map & dir = get_existing_value(roster.children, element.parent);
+ // this means that dir_map should not be an smap -- unless we want to
+ // more-offial-ize smap's assert-on-duplicate behavior, leave this out,
+ // and at the end do a 3rd pass to call "assert_no_dups" on each
+ // dir_map?
+ I(dir.find(element.name) == dir.end());
+ dir.insert(std::make_pair(element.name, es));
+ }
+ // third pass: sanity check result
+ check_sane_roster(*this);
+}
+
+void
+check_sane_roster(roster_t const & roster)
+{
+ // no loops
+ // no MT entry in top-level dir
+ // (though this would be caught before we could write out a manifest or
+ // anything, of course...)
+}
========================================================================
--- roster.hh
+++ roster.hh 5d4079ef6f31eb50e37271f6a48c43e0648a1890
@@ -0,0 +1,90 @@
+#ifndef __ROSTER_HH__
+#define __ROSTER_HH__
+
+// copyright (C) 2005 nathaniel smith
+// all rights reserved.
+// licensed to the public under the terms of the GNU GPL (>= 2)
+// see the file COPYING for details
+
+#include "vocab.hh"
+#include "numeric_vocab.hh"
+#include "paths.hh"
+
+// a persistent element id
+// but "file_id" means something else...
+// "element" terminology is stolen from clearcase, it means (file|directory)
+// 32 bits should be sufficient; 4 billion distinct files would use 4
+// terabytes of disk space, assuming each file requires only a single sqlite
+// page. easy to change in a few years, in any case.
+// FIXME: we have too many integer types. make them type-distinct.
+typedef uint32_t element_soul;
+
+const element_soul the_null_soul = 0;
+const uint32_t first_element_soul = 1;
+
+inline bool null_soul(element_soul es)
+{
+ return es = the_null_soul;
+}
+
+struct element_t
+{
+ bool is_dir;
+ revision_id birth_revision;
+ // this is null iff this is a root dir
+ element_soul parent;
+ // this is null iff this is a root dir
+ path_component name;
+ file_id content;
+ std::map attrs;
+ virtual ~element() {};
+};
+
+struct mark_item
+{
+ std::set name_marks;
+ std::set content_marks;
+ std::map > attr_marks;
+};
+
+typedef std::map element_map;
+typedef std::map dir_map;
+
+// FIXME: should we just make the root_dir always have the null soul for now?
+struct roster_t
+{
+ roster_t() : root_dir(the_null_element) {}
+ // might be better to make this destructive -- eat the element_map given...
+ roster_t(element_map const & elements);
+ element_map elements;
+ std::map children;
+ element_soul root_dir;
+ void clear()
+ {
+ elements.clear(); children.clear(); root_dir = the_null_element;
+ }
+};
+
+typedef std::map marking_t;
+
+element_soul lookup(roster_t const & roster, file_path const & fp);
+void get_name(roster_t const & roster, element_soul es, file_path & fp);
+
+// FIXME: how should this work?
+void apply_change_set(change_set const & cs, element_map & em);
+
+void markup(revision_id const & rid, roster_t const & root,
+ marking_t & marking);
+void markup(revision_id const & rid, roster_t const & child,
+ revision_id const & parent_rid, roster_t const & parent,
+ marking_t & marking);
+void markup(revision_id const & rid, roster_t const & root,
+ revision_id const & parent1_rid, roster_t const & parent1,
+ revision_id const & parent2_rid, roster_t const & parent2,
+ marking_t & marking);
+
+void read_roster(data const & dat, roster_t & roster, marking_t & marking);
+void write_roster(roster_t const & roster, marking_t const & marking, data & dat);
+void write_manifest(roster_t const & roster, data & dat);
+
+#endif // header guard
========================================================================
--- vocab_terms.hh 9abc8225074b278d3b7a57c291ab5d8fd0a98ea6
+++ vocab_terms.hh 3ccb25132c10e1a06c23b7ef1f321667c8f58c8b
@@ -36,6 +36,9 @@
ATOMIC(netsync_session_key); // key for netsync session HMAC
ATOMIC(netsync_hmac_value); // 160-bit SHA-1 HMAC
+ATOMIC_NOVERIFY(attr_key);
+ATOMIC_NOVERIFY(attr_value);
+
DECORATE(revision); // thing associated with a revision
DECORATE(manifest); // thing associated with a manifest
DECORATE(file); // thing associated with a file