Changeset 304
- Timestamp:
- 03/31/05 12:00:54 (4 years ago)
- Files:
-
- todo2/trunk/src/Category.cc (modified) (1 diff)
- todo2/trunk/src/Category.h (modified) (1 diff)
- todo2/trunk/src/filter/Expression.cc (modified) (3 diffs)
- todo2/trunk/src/Item.cc (modified) (2 diffs)
- todo2/trunk/src/Item.h (modified) (5 diffs)
- todo2/trunk/src/Manager.cc (modified) (9 diffs)
- todo2/trunk/src/Manager.h (modified) (2 diffs)
- todo2/trunk/src/PropertyMap.cc (modified) (3 diffs)
- todo2/trunk/src/PropertyMap.h (modified) (1 diff)
- todo2/trunk/src/User.cc (modified) (1 diff)
- todo2/trunk/src/User.h (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
todo2/trunk/src/Category.cc
r295 r304 1 1 #include "Category.h" 2 2 3 Category::Category(const PropertyMap &props) : mid(props.get("id")), mdescription(props.get("description")) {3 Category::Category(const AbstractPropertyMap &props) : mid(props.get("id")), mdescription(props.get("description")) { 4 4 } todo2/trunk/src/Category.h
r295 r304 21 21 22 22 Category() {} 23 Category(const PropertyMap &props);23 Category(const AbstractPropertyMap &props); 24 24 25 25 std::string id() const { return mid; } todo2/trunk/src/filter/Expression.cc
r302 r304 16 16 17 17 // Load aliases 18 Manager::PropertyMap aliases = MANAGER.prefixToPropertyMap("expression.alias.");19 Manager::Keys keys = aliases.keys();18 OverlayPropertyMap aliases(&MANAGER, "expression.alias."); 19 PropertyMap::Keys keys = aliases.keys(); 20 20 crash::Expression expr; 21 21 … … 82 82 " children the number of children of the current node (integer)\n" 83 83 " index the numeric index of the current node (integer)\n" 84 " a indexthe absolute index for the current node (string in the form\n"84 " absindex the absolute index for the current node (string in the form\n" 85 85 " <n>.<m>.<o> ...)\n" 86 86 " depth the numeric depth of the current node (integer)\n" … … 258 258 if (ev == "children") return (double)item->children(); 259 259 if (ev == "index") return (double)item->index(); 260 if (ev == "a index") return (string)item->aindex();260 if (ev == "absindex") return (string)item->absIndex(); 261 261 if (ev == "depth") return (double)item->depth(); 262 262 if (ev == "true") return 1.0; todo2/trunk/src/Item.cc
r302 r304 132 132 } 133 133 134 Item::Index Item::a index() const {134 Item::Index Item::absIndex() const { 135 135 Index index; 136 136 … … 141 141 } 142 142 143 /*void Item::vacuum(bool clean) {144 for (KeyValues::iterator i = mkv.begin(); i != mkv.end(); ++i)145 i->second.dirty(clean);146 }147 148 void Item::vacuum(std::string key, bool clean) {149 if (mkv.find(key) == mkv.end()) throw Exception(_("can't clean non-existent key '") + key + "'");150 mkv[key].dirty(clean);151 }152 153 bool Item::dirty(std::string key) const {154 KeyValues::const_iterator i = mkv.find(key);155 if (i == mkv.end())156 throw Exception(_("non-existent key '") + key + "'");157 return i->second.dirty();158 }*/159 160 143 bool Item::dirty() const { 161 for (KeyValues::const_iterator i = mkv.begin(); i != mkv.end(); ++i)162 if (i->second.dirty())return true;144 if (COWPropertyMap::dirty()) 145 return true; 163 146 if (child()) return child()->dirty(); 164 147 if (next()) return next()->dirty(); todo2/trunk/src/Item.h
r302 r304 2 2 #define ITEM_H__ 3 3 4 #include <time.h>5 4 #include <stdexcept> 6 5 #include <string> 7 6 #include <vector> 8 7 #include <map> 8 #include <ctime> 9 9 #include <crash/Tree.h> 10 10 #include <crash/Exception.h> … … 16 16 /** An Item represents a single entry in the devtodo database. */ 17 17 18 class Item : public crash::Tree<Item>, public PropertyMap {18 class Item : public crash::Tree<Item>, public COWPropertyMap { 19 19 public : 20 20 SUBCLASS_DEFAULT_EXCEPTION … … 52 52 53 53 /** Find root of tree */ 54 Item *root() { return parent() ?parent() : this; }54 Item *root() { return crash::Tree<Item>::parent() ? crash::Tree<Item>::parent() : this; } 55 55 /** Find root of tree */ 56 const Item *root() const { return parent() ?parent() : this; }56 const Item *root() const { return crash::Tree<Item>::parent() ? crash::Tree<Item>::parent() : this; } 57 57 58 /* Hierarchy traversal */59 /* Item *parent() { return crash::Tree<Item>::parent(); }60 const Item *parent() const { return crash::Tree<Item>::parent(); }61 Item *child() { return crash::Tree<Item>::child(); }62 const Item *child() const { return crash::Tree<Item>::child(); }63 Item *next() { return crash::Tree<Item>::next(); }64 Item *prev() { return crash::Tree<Item>::prev(); }65 const Item *next() const { return crash::Tree<Item>::next(); }66 const Item *prev() const { return crash::Tree<Item>::prev(); }67 unsigned children() const { return crash::Tree<Item>::children(); }68 unsigned depth() const { return crash::Tree<Item>::depth(); }*/69 70 /* Hierarchy modification */71 /* Item *peer(Item *peer) { return crash::Tree<Item>::peer(peer); }72 Item *next(Item *next) { return crash::Tree<Item>::next(next); }73 Item *prev(Item *prev) { return crash::Tree<Item>::prev(prev); }*/74 58 Item *adopt(Item *child) { 75 if (child) propertyParent(this);59 if (child) child->backing(this); 76 60 return crash::Tree<Item>::adopt(child); 77 61 } 78 Item *detach() { propertyParent(0); return crash::Tree<Item>::detach(); }62 Item *detach() { backing(0); return crash::Tree<Item>::detach(); } 79 63 80 64 // Attribute queries 81 65 /// Get body of Item 82 const std::string &body() const { return get("body"); }66 std::string body() const { return get("body"); } 83 67 /// Get title of Item 84 const std::string &title() const { return get("title"); }68 std::string title() const { return get("title"); } 85 69 // Scheduling times 86 70 /// Get beginning of scheduled time … … 125 109 Priority priority() const { return static_cast<Priority>(get<int>("priority")); } 126 110 /// Return the absolute index to this item. 127 Index a index() const;111 Index absIndex() const; 128 112 /** Note that active() is not equivalent to !completed(), because an 129 113 item can be inactive until a dependency is satisfied, or it's … … 147 131 bool dirty() const; 148 132 private : 133 // Demoted methods we don't want to be used in Item context. 134 void flatten(const std::string &) {} 135 void flatten() {} 136 149 137 std::vector<Item*> mdeps; 150 138 bool mfiltered; todo2/trunk/src/Manager.cc
r302 r304 91 91 } 92 92 93 Manager::Manager() : mself(0), mfrontend(0), mbackend(0), mprogramname("todo2") { 93 ////////////////////////////// Manager 94 95 96 Manager::Manager() : COWPropertyMap(new PropertyMap()), mself(0), mfrontend(0), mbackend(0), mprogramname("todo2") { 94 97 // Find this time zones offset from UTC 95 98 time_t now = ::time(0); … … 118 121 /* Add ourselves to the AddressBook. Hopefully, though, the user will 119 122 override this with a valid E-Mail address. */ 120 if (pw && ! defined("addressbook." + string(pw->pw_name) + ".name")) {123 if (pw && !exists("addressbook." + string(pw->pw_name) + ".name")) { 121 124 set("addressbook." + string(pw->pw_name) + ".name", pw->pw_gecos); 122 125 set("addressbook." + string(pw->pw_name) + ".contact", "mail:" + string(pw->pw_name) + "@" + hostname()); … … 281 284 /* All configuration changes from here on will be written to the 282 285 currently open database. */ 283 vacuum();286 commit(); 284 287 285 288 // Final pass before handing off to modules. … … 345 348 break; 346 349 case DUMPCONFIG : { 347 Manager::Keys keys = PropertyMap::keys();350 Manager::Keys keys = this->keys(); 348 351 349 352 for (Manager::Keys::iterator i = keys.begin(); i != keys.end(); ++i) … … 486 489 props.set("id", (*i).substr(9)); 487 490 props.set("description", get(*i)); 491 492 mcategories[props.get("id")] = new Category(props); 488 493 } 489 494 } … … 494 499 for (Keys::iterator i = ab.begin(); i != ab.end(); ++i) { 495 500 vector<string> c = split(".", *i); 496 PropertyMap props = prefixToPropertyMap("addressbook." + c[1] + ".");501 OverlayPropertyMap props(this, "addressbook." + c[1] + "."); 497 502 498 503 props.set("id", c[1]); … … 502 507 503 508 void Manager::populatePriorities() { 504 PropertyMap props = prefixToPropertyMap("priority.");505 PropertyMap::Keys keys = props.keys();506 507 for ( PropertyMap::Keys::const_iterator i = keys.begin(); i != keys.end(); ++i) {509 OverlayPropertyMap props(this, "priority."); 510 Keys keys = props.keys(); 511 512 for (Keys::const_iterator i = keys.begin(); i != keys.end(); ++i) { 508 513 try { 509 514 int p = from_string<int>(*i); … … 553 558 } 554 559 555 void Manager::addUser(const PropertyMap &prop) {560 void Manager::addUser(const AbstractPropertyMap &prop) { 556 561 DEBUG(9, "adding user " << prop.get("id") << " to global address book"); 557 562 musers[prop.get("id")] = new User(prop); … … 572 577 } 573 578 574 void Manager::addCategory(const PropertyMap &prop) {579 void Manager::addCategory(const AbstractPropertyMap &prop) { 575 580 mcategories[prop.get("id")] = new Category(prop); 576 581 } todo2/trunk/src/Manager.h
r302 r304 17 17 18 18 /** 19 Manager is ... (TODO: complete description) 19 Manager is the core singleton class for DT2. 20 21 NOTE: Manager uses COWPropertyMap rather than the more basic PropertyMap in 22 order to write "dirty" properties to the current database, allowing 23 per-database overrides. 20 24 */ 21 22 class Manager : public PropertyMap, public crash::Singleton<Manager> { 25 class Manager : public COWPropertyMap, public crash::Singleton<Manager> { 23 26 public : 24 27 SUBCLASS_DEFAULT_EXCEPTION … … 43 46 /** Return the User entry for the current user. */ 44 47 const User *self() { return mself; } 45 void addUser(const PropertyMap &prop);48 void addUser(const AbstractPropertyMap &prop); 46 49 const User *getUser(std::string id); 47 50 User::List allUsers() const; 48 51 49 52 /// Add a new category 50 void addCategory(const PropertyMap &prop);53 void addCategory(const AbstractPropertyMap &prop); 51 54 const Category *getCategory(std::string name) const; 52 55 const Category *defaultCategory() const; todo2/trunk/src/PropertyMap.cc
r302 r304 1 1 #include <fstream> 2 2 #include <iostream> 3 #include <algorithm> 4 #include <set> 3 5 #include "PropertyMap.h" 4 6 #include "main.h" … … 7 9 using namespace crash; 8 10 9 PropertyMap::Keys PropertyMap::keys() const { 10 Keys out; 11 12 for (KeyValues::const_iterator i = mkv.begin(); i != mkv.end(); ++i) 13 out.push_back(i->first); 14 return out; 15 } 16 17 /// Return all keys that match glob 18 PropertyMap::Keys PropertyMap::keys(const std::string &glob) const { 19 Keys out; 20 21 for (KeyValues::const_iterator i = mkv.begin(); i != mkv.end(); ++i) 22 if (crash::glob(glob, i->first)) 23 out.push_back(i->first); 24 return out; 25 } 26 27 PropertyMap PropertyMap::prefixToPropertyMap(const std::string &prefix) { 28 PropertyMap props(this); 29 30 for (KeyValues::const_iterator i = mkv.begin(); i != mkv.end(); ++i) 31 if (i->first.compare(0, prefix.size(), prefix) == 0) 32 props.set(i->first.substr(prefix.size()), i->second.get()); 33 return props; 34 } 35 36 void PropertyMap::load(const std::string &file) { 11 void AbstractPropertyMap::load(const std::string &file) { 37 12 ifstream in(file.c_str()); 38 13 string line, section; … … 62 37 } 63 38 64 void PropertyMap::vacuum(const std::string &key, bool state) { 65 mkv[key].dirty(!state); 39 AbstractPropertyMap::Keys COWPropertyMap::keys() const { 40 std::set<std::string> transient; 41 Keys skeys = mstore->keys(); 42 Keys pkeys; 43 if (mbacking) pkeys = mbacking->keys(); 44 transient.insert(skeys.begin(), skeys.end()); 45 transient.insert(pkeys.begin(), pkeys.end()); 46 Keys out(transient.size()); 47 std::copy(transient.begin(), transient.end(), out.begin()); 48 return out; 66 49 } 67 50 68 void PropertyMap::vacuum(bool state) { 69 for (KeyValues::iterator i = mkv.begin(); i != mkv.end(); ++i) 70 i->second.dirty(!state); 71 } 72 73 bool PropertyMap::dirty(const std::string &key) { 74 return mkv[key].dirty(); 75 } 76 77 PropertyMap::Keys PropertyMap::dirty() { 78 Keys out; 79 80 for (KeyValues::iterator i = mkv.begin(); i != mkv.end(); ++i) 81 if (i->second.dirty()) 82 out.push_back(i->first); 51 AbstractPropertyMap::Keys COWPropertyMap::keys(const std::string &glob) const { 52 std::set<std::string> transient; 53 Keys skeys = mstore->keys(glob); 54 Keys pkeys; 55 if (mbacking) pkeys = mbacking->keys(glob); 56 transient.insert(skeys.begin(), skeys.end()); 57 transient.insert(pkeys.begin(), pkeys.end()); 58 Keys out(transient.size()); 59 std::copy(transient.begin(), transient.end(), out.begin()); 83 60 return out; 84 61 } todo2/trunk/src/PropertyMap.h
r302 r304 1 #ifndef BASICCONFIG_H__2 #define BASICCONFIG_H__1 #ifndef PROPERTYMAP_H__ 2 #define PROPERTYMAP_H__ 3 3 4 4 #include <crash/Exception.h> 5 5 #include <crash/StringManip.h> 6 6 #include <crash/TypeResolver.h> 7 #include <crash/smart_ptr.h>8 7 #include <map> 9 10 /** 11 PropertyMap is a generic key/value pair storage mechanism. Various queries 12 can be used against the store to retrieve sets of keys. 13 14 When a configuration key is created it is marked as dirty. 15 16 There are two situations where PropertyMap is used: 17 18 1. Each Item in the Database is a PropertyMap with its parent Item 19 also the parent PropertyMap. This lets properties be inherited 20 through the Database hierarchy. 21 22 2. The global configuration, rooted in Manager. Each Module has its 23 own "namespace" uniquely prefixed by its name "<module>.". 24 25 The second of these two implies that dirty keys, which should be stored in 26 the Database when it is committed, must be obtainable through the root map 27 even if they are in sub-maps. 28 */ 29 30 class PropertyMap { 8 #include <iostream> 9 #include <vector> 10 #include <string> 11 12 class AbstractProperty { 13 public : 14 virtual ~AbstractProperty() {} 15 16 virtual std::string get() const = 0; 17 virtual void set(const std::string &value) = 0; 18 private : 19 }; 20 21 class ValueProperty : public AbstractProperty { 22 public : 23 ValueProperty() {} 24 ValueProperty(const std::string &value) : mvalue(value) {} 25 26 virtual std::string get() const { return mvalue; } 27 virtual void set(const std::string &value) { mvalue = value; } 28 private : 29 std::string mvalue; 30 }; 31 32 template <typename T> 33 class ReferenceProperty : public AbstractProperty { 34 public : 35 ReferenceProperty(T &value) : mvalue(value) {} 36 37 virtual std::string get() const { return crash::to_string(mvalue); } 38 virtual void set(const std::string &value) { mvalue = crash::from_string<T>(value); } 39 private : 40 T &mvalue; 41 }; 42 43 class AbstractPropertyMap { 31 44 public : 32 45 SUBCLASS_DEFAULT_EXCEPTION 33 46 SUBCLASS_NAMED_EXCEPTION(InvalidValue, Exception) 34 47 35 class Property {36 public :37 Property() : mdirty(true) {}38 explicit Property(const std::string &value) : mvalue(value), mdirty(true) {}39 40 void dirty(bool state) { mdirty = state; }41 bool dirty() const { return mdirty; }42 43 const std::string &get() const { return mvalue; }44 void set(const std::string &value) { mvalue = value; mdirty = true; }45 private :46 std::string mvalue;47 bool mdirty;48 };49 50 typedef std::map<std::string, Property> KeyValues;51 typedef KeyValues::const_iterator const_iterator;52 typedef KeyValues::iterator iterator;53 54 48 typedef std::vector<std::string> Keys; 55 49 56 explicit PropertyMap(PropertyMap *parent = 0) : mparentpm(parent) {} 57 virtual ~PropertyMap() {} 58 59 /* XXX This is called "propertyParent" due to ambiguities with multiple 60 inheritance when joined with crash::Tree<T>. XXX */ 61 PropertyMap *propertyParent() { return mparentpm; } 62 const PropertyMap *propertyParent() const { return mparentpm; } 63 PropertyMap *propertyParent(PropertyMap *parent) { mparentpm = parent; return parent; } 64 65 /// Return all keys 66 virtual Keys keys() const; 67 /// Return all keys that match glob 68 virtual Keys keys(const std::string &glob) const; 69 70 /// Query the existence of a key/value. 71 virtual bool exists(const std::string &key) const { 72 return mkv.find(key) != mkv.end(); 73 } 74 75 /// Return the value of a key. 76 virtual const std::string & get(const std::string &key) const { 77 KeyValues::const_iterator i = mkv.find(key); 78 79 if (i == mkv.end()) throw Exception("no such key '" + key + "'"); 80 return i->second.get(); 81 } 82 83 /// Set the value of a key. 84 virtual void set(const std::string &key, const std::string &value) { 85 KeyValues::iterator i = mkv.find(key); 86 if (i == mkv.end()) 87 mkv[key] = Property(value); 88 else 89 i->second.set(value); 90 } 91 92 /// Destroy a key/value pair. 93 virtual void unset(const std::string &key) { 94 KeyValues::iterator i = mkv.find(key); 95 96 if (i != mkv.end()) 97 mkv.erase(i); 98 } 99 100 /********************************************************************** 101 Most methods from here on are for convenience only 102 **********************************************************************/ 103 104 /// Query the existence of a key/value. 105 bool isset(const std::string &key) const { return exists(key); } 106 107 /// Query the existence of a key/value. 108 bool defined(const std::string &key) const { return exists(key); } 109 110 /** Return the value of a key. If the key does not exist, return a 111 default value. */ 112 const std::string &get(const std::string &key, const std::string &def) const { 113 if (!exists(key)) return def; 114 return get(key); 115 } 116 117 /** Return the value of a key as a specific type. If the key does not 118 exist throw an Exception. */ 50 virtual ~AbstractPropertyMap() {} 51 52 /// Abstract "get" method 53 virtual std::string vget(const std::string &key) const = 0; 54 virtual bool exists(const std::string &key) const = 0; 55 /** Set a value to the given property. This will overwrite the existing 56 property. */ 57 virtual void pset(const std::string &key, AbstractProperty *property) = 0; 58 /** Set a value to a basic string. If the key exists its set() method 59 will be used. */ 60 virtual void vset(const std::string &key, const std::string &value) = 0; 61 virtual void unset(const std::string &key) = 0; 62 virtual void clear() = 0; 63 /// Retrieve list of keys 64 virtual Keys keys() const = 0; 65 /** Retrieve list of keys matching glob. This should probably be 66 overloaded for efficiency. */ 67 virtual Keys keys(const std::string &glob) const { 68 Keys k = keys(); 69 Keys out; 70 71 for (Keys::const_iterator i = k.begin(); i != k.end(); ++i) 72 if (crash::glob(glob, *i)) 73 out.push_back(*i); 74 return out; 75 } 76 virtual unsigned size() const { 77 return keys().size(); 78 } 79 80 /********************************************************************* 81 Convenience functions. 82 *********************************************************************/ 83 void load(const std::string &filename); 84 85 std::string get(const std::string &key, const std::string &defaultvalue) const { 86 if (exists(key)) 87 return vget(key); 88 return defaultvalue; 89 } 90 inline void set(const std::string &key, const std::string &value) { 91 vset(key, value); 92 } 93 119 94 template <typename T> 120 const T get(const std::string &key) const { 121 122 if (!exists(key)) throw Exception("no such key '" + key + "'"); 95 inline void bind(const std::string &key, T &value) { 96 pset(key, new ReferenceProperty<T>(value)); 97 } 98 99 template <typename T> 100 inline void set(const std::string &key, const T &value) { 101 vset(key, crash::to_string(value)); 102 } 103 104 inline std::string get(const std::string &key) const { 105 return vget(key); 106 } 107 108 template <typename T> 109 inline T get(const std::string &key) const { 123 110 try { 124 return crash::from_string<T>( get(key));111 return crash::from_string<T>(vget(key)); 125 112 } catch (crash::BadCast) { 126 throw Exception("could not convert property " + key + " with value '" + get(key) + "' to " + crash::type2string<T>());113 throw Exception("could not convert property " + key + " with value '" + vget(key) + "' to " + crash::type2string<T>()); 127 114 } 128 115 } 129 116 130 /** Return the value of a key as a specific type. If the key does not131 exist return a default value. */132 117 template <typename T> 133 const T get(const std::string &key, const T &def) const { 134 if (!exists(key)) return def; 118 inline T get(const std::string &key, const T &defaultvalue) const { 135 119 try { 136 return crash::from_string<T>(get(key)); 120 if (exists(key)) 121 return crash::from_string<T>(vget(key)); 122 return defaultvalue; 137 123 } catch (crash::BadCast) { 138 throw Exception("could not convert property " + key + " with value '" + get(key) + "' to " + crash::type2string<T>());124 throw Exception("could not convert property " + key + " with value '" + vget(key) + "' to " + crash::type2string<T>()); 139 125 } 140 126 } 141 127 142 /// Set the value of a key to a specific type.143 template <typename T>144 void set(const std::string &key, const T &value) {145 set(key, crash::to_string(value));146 }147 148 /// Set the value of a key.149 128 void setUnlessDefined(const std::string &key, const std::string &value) { 150 129 if (!exists(key)) set(key, value); 151 130 } 152 131 153 /// Set the value of a key to a specific type.154 132 template <typename T> 155 133 void setUnlessDefined(const std::string &key, const T &value) { 156 if (!exists(key)) set(key, crash::to_string(value)); 157 } 158 159 /** Return a prefixed set as a new PropertyMap<>. 160 eg. Given the following properties.. 161 162 user.athomas.name = Alec Thomas 163 user.athomas.contact = mail:alec@swapoff.org 164 165 This code.. 166 167 PropertMap props = conf.prefixToPropertyMap("user.athomas."); 168 169 Would yield the following PropertyMap.. 170 171 name = Alec Thomas 172 contact = mail:alec@swapoff.org 173 */ 174 PropertyMap prefixToPropertyMap(const std::string &prefix); 175 176 /// Load a property map from a configuration file 177 void load(const std::string &file); 178 179 /// Mark all keys as dirty/not dirty 180 void vacuum(bool state = true); 181 /// Mark a key as dirty/not dirty 182 void vacuum(const std::string &key, bool state = true); 183 /// Return the dirty flag for a key 184 bool dirty(const std::string &key); 185 /// Return list of dirty keys 186 Keys dirty(); 187 134 if (!exists(key)) set(key, value); 135 } 188 136 protected : 189 PropertyMap *mparentpm; 190 KeyValues mkv; 137 AbstractPropertyMap() {} 138 }; 139 140 /** 141 PropertyMap maintains a set of properties mapped by key strings. 142 */ 143 class PropertyMap : public AbstractPropertyMap { 144 public : 145 PropertyMap() {} 146 ~PropertyMap() { 147 for (Properties::iterator i = mproperties.begin(); i != mproperties.end(); ++i) 148 delete i->second; 149 } 150 151 /// A PropertyMap can be a copy of an AbstractPropertyMap 152 PropertyMap(const AbstractPropertyMap ©) { 153 Keys keys = copy.keys(); 154 155 for (Keys::iterator i = keys.begin(); i != keys.end(); ++i) 156 set(*i, copy.vget(*i)); 157 } 158 /// A PropertyMap can be a copy of an AbstractPropertyMap 159 PropertyMap &operator = (const AbstractPropertyMap ©) { 160 Keys keys = copy.keys(); 161 162 for (Properties::iterator i = mproperties.begin(); i != mproperties.end(); ++i) 163 delete i->second; 164 mproperties.clear(); 165 for (Keys::iterator i = keys.begin(); i != keys.end(); ++i) 166 set(*i, copy.vget(*i)); 167 return *this; 168 } 169 170 virtual unsigned size() const { 171 return mproperties.size(); 172 } 173 174 std::string vget(const std::string &key) const { 175 Properties::const_iterator i = mproperties.find(key); 176 177 if (i == mproperties.end()) 178 throw Exception("no property named '" + key + "'"); 179 return i->second->get(); 180 } 181 bool exists(const std::string &key) const { 182 return mproperties.find(key) != mproperties.end(); 183 } 184 void pset(const std::string &key, AbstractProperty *property) { 185 Properties::iterator i = mproperties.find(key); 186 187 if (i != mproperties.end()) { 188 delete i->second; 189 i->second = property; 190 } else 191 mproperties[key] = property; 192 } 193 void vset(const std::string &key, const std::string &value) { 194 Properties::iterator i = mproperties.find(key); 195 196 if (i == mproperties.end()) 197 mproperties[key] = new ValueProperty(value); 198 else 199 i->second->set(value); 200 201 } 202 virtual void unset(const std::string &key) { 203 mproperties.erase(key); 204 } 205 virtual Keys keys() const { 206 Keys out; 207 208 for (Properties::const_iterator i = mproperties.begin(); i != mproperties.end(); ++i) 209 out.push_back(i->first); 210 return out; 211 } 212 /// Retrieve list of keys matching glob 213 virtual Keys keys(const std::string &glob) const { 214 Keys out; 215 216 for (Properties::const_iterator i = mproperties.begin(); i != mproperties.end(); ++i) 217 if (crash::glob(glob, i->first)) 218 out.push_back(i->first); 219 return out; 220 } 221 222 void clear() { 223 for (Properties::iterator i = mproperties.begin(); i != mproperties.end(); ++i) 224 delete i->second; 225 mproperties.clear(); 226 } 227 228 private : 229 typedef std::map<std::string, AbstractProperty*> Properties; 230 231 Properties mproperties; 232 }; 233 234 /** 235 The behaviours of COWPropertyMap are thus: 236 237 * Property reads transparently traverse up the hierarchy, returning the 238 first key value that matches. 239 * Setting a property will create a new property in the current map, 240 "overlaying" properties higher up the hierarchy. 241 * Actual values are stored in a "store" map. 242 * Backing store can be null. In this situation, "flatten" 243 244 Essentially, this behaviour implements a copy-on-write PropertyMap. 245 */ 246 class COWPropertyMap : public AbstractPropertyMap { 247 public : 248 /// Construct a new COW property map. store is owned by the object. 249 COWPropertyMap(AbstractPropertyMap *backing = 0, AbstractPropertyMap *store = new PropertyMap()) : mbacking(backing), mstore(store) {} 250 ~COWPropertyMap() { 251 delete mstore; 252 } 253 254 std::string vget(const std::string &key) const { 255 if (mstore->exists(key)) 256 return mstore->vget(key); 257 if (mbacking) 258 return mbacking->vget(key); 259 throw Exception("no property named '" + key + "'"); 260 } 261 bool exists(const std::string &key) const { 262 if (mstore->exists(key)) 263 return true; 264 if (mbacking) 265 return mbacking->exists(key); 266 return false; 267 } 268 void pset(const std::string &key, AbstractProperty *property) { 269 mstore->pset(key, property); 270 } 271 void vset(const std::string &key, const std::string &value) { 272 mstore->vset(key, value); 273 } 274 void unset(const std::string &key) { 275 mstore->unset(key); 276 if (mbacking) 277 mbacking->unset(key); 278 } 279 /* This is probably not the most efficient. It basically extracts 280 both sets of keys, inserts them into a set then converts the set 281 into a vector before returning it. */ 282 Keys keys() const; 283 Keys keys(const std::string &glob) const; 284 285 /* TODO: Make an efficient size() method for COWPropertyMap 286 unsigned size() const; */ 287 288 void clear() { 289 mstore->clear(); 290 if (mbacking) 291 mbacking->clear(); 292 } 293 294 /// Return list of COWed keys 295 Keys dirtyKeys() const { 296 return mstore->keys(); 297 } 298 /// Return list of COWed keys 299 Keys dirtyKeys(const std::string &glob) const { 300 return mstore->keys(glob); 301 } 302 303 unsigned dirty() const { 304 return mstore->size(); 305 } 306 307 bool dirty(const std::string &key) const { 308 return mstore->exists(key); 309 } 310 311 /// Merge COWed keys into backing. 312 void commit() { 313 Keys keys = mstore->keys(); 314 315 if (!mbacking)
