# # 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