summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authorbrettw@google.com <brettw@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2008-12-09 23:29:51 +0000
committerbrettw@google.com <brettw@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2008-12-09 23:29:51 +0000
commit78f346a6f58cd39450c86e65fe85eca4bb458e05 (patch)
tree2b6a7881447a3bff0ad5f55328f5623cf4289058 /chrome
parent5534be7842eeeb47365e189e94e6d352e7de329e (diff)
downloadchromium_src-78f346a6f58cd39450c86e65fe85eca4bb458e05.zip
chromium_src-78f346a6f58cd39450c86e65fe85eca4bb458e05.tar.gz
chromium_src-78f346a6f58cd39450c86e65fe85eca4bb458e05.tar.bz2
Add a property bag which is a typesafe list of arbitrary data that can be
associated with any object. Review URL: http://codereview.chromium.org/13676 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@6654 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r--chrome/common/property_bag.cc48
-rw-r--r--chrome/common/property_bag.h165
-rw-r--r--chrome/common/property_bag_unittest.cc62
3 files changed, 275 insertions, 0 deletions
diff --git a/chrome/common/property_bag.cc b/chrome/common/property_bag.cc
new file mode 100644
index 0000000..f7c92a3
--- /dev/null
+++ b/chrome/common/property_bag.cc
@@ -0,0 +1,48 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/property_bag.h"
+
+PropertyBag::PropertyBag() {
+}
+
+PropertyBag::PropertyBag(const PropertyBag& other) {
+ operator=(other);
+}
+
+PropertyBag::~PropertyBag() {
+}
+
+PropertyBag& PropertyBag::operator=(const PropertyBag& other) {
+ props_.clear();
+
+ // We need to make copies of each property using the virtual copy() method.
+ for (PropertyMap::const_iterator i = other.props_.begin();
+ i != other.props_.end(); ++i)
+ props_[i->first] = linked_ptr<Prop>(i->second->copy());
+ return *this;
+}
+
+void PropertyBag::SetProperty(PropID id, Prop* prop) {
+ props_[id] = linked_ptr<Prop>(prop);
+}
+
+PropertyBag::Prop* PropertyBag::GetProperty(PropID id) {
+ PropertyMap::const_iterator found = props_.find(id);
+ if (found == props_.end())
+ return NULL;
+ return found->second.get();
+}
+
+void PropertyBag::DeleteProperty(PropID id) {
+ PropertyMap::iterator found = props_.find(id);
+ if (found == props_.end())
+ return; // Not found, nothing to do.
+ props_.erase(found);
+}
+
+PropertyAccessorBase::PropertyAccessorBase() {
+ static PropertyBag::PropID next_id = 1;
+ prop_id_ = next_id++;
+}
diff --git a/chrome/common/property_bag.h b/chrome/common/property_bag.h
new file mode 100644
index 0000000..cf9ad41
--- /dev/null
+++ b/chrome/common/property_bag.h
@@ -0,0 +1,165 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_PROPERTY_BAG_H_
+#define CHROME_COMMON_PROPERTY_BAG_H_
+
+#include <map>
+
+#include "base/basictypes.h"
+#include "base/linked_ptr.h"
+
+class PropertyAccessorBase;
+
+// A property bag holds a generalized list of arbitrary metadata called
+// properties. Each property is a class type derived from PropertyBag::Prop
+// that can bet set and retrieved.
+//
+// The property bag is not read or written directly. Instead, callers go
+// through a PropertyAccessor. The Accessor generates the unique IDs that
+// identify different properties, so uniquely identify a property. The Accessor
+// is templatized to also provide typesafety to the callers.
+//
+// Example:
+// // Note: you don't want to use Singleton for your Accessor if you're using
+// // a simple type like int or string as the data, since it will enforce that
+// // there is only one singleton for that type, which will conflict. If
+// // you're putting in some struct that's unique to you, go ahead.
+// PropertyAccessor<int>* my_accessor() const {
+// static PropertyAccessor<int>* accessor = NULL;
+// if (!accessor) accessor = new PropertyAccessor<int>;
+// return accessor;
+// }
+//
+// void doit(SomeObjectThatImplementsPropertyBag* object) {
+// PropertyAccessor<int>* accessor = my_accessor();
+// int* property = accessor.GetProperty(object);
+// if (property)
+// ... use property ...
+//
+// accessor.SetProperty(object, 22);
+// }
+class PropertyBag {
+ public:
+ // The type that uniquely identifies a property type.
+ typedef int PropID;
+ enum { NULL_PROP_ID = -1 }; // Invalid property ID.
+
+ // Properties are all derived from this class. They must be deletable and
+ // copyable
+ class Prop {
+ public:
+ virtual ~Prop() {}
+
+ // Copies the property and returns a pointer to the new one. The caller is
+ // responsible for managing the lifetime.
+ virtual Prop* copy() = 0;
+ };
+
+ PropertyBag();
+ PropertyBag(const PropertyBag& other);
+ virtual ~PropertyBag();
+
+ PropertyBag& operator=(const PropertyBag& other);
+
+ private:
+ friend class PropertyAccessorBase;
+
+ typedef std::map<PropID, linked_ptr<Prop> > PropertyMap;
+
+ // Used by the PropertyAccessor to set the property with the given ID.
+ // Ownership of the given pointer will be transferred to us. Any existing
+ // property matching the given ID will be deleted.
+ void SetProperty(PropID id, Prop* prop);
+
+ // Used by the PropertyAccessor to retrieve the property with the given ID.
+ // The returned pointer will be NULL if there is no match. Ownership of the
+ // pointer will stay with the property bag.
+ Prop* GetProperty(PropID id);
+
+ // Deletes the property with the given ID from the bag if it exists.
+ void DeleteProperty(PropID id);
+
+ PropertyMap props_;
+
+ // Copy and assign is explicitly allowed for this class.
+};
+
+// PropertyAccessorBase -------------------------------------------------------
+
+// Manages getting the unique IDs to identify a property. Callers should use
+// PropertyAccessor below instead.
+class PropertyAccessorBase {
+ public:
+ PropertyAccessorBase();
+ virtual ~PropertyAccessorBase() {}
+
+ // Removes our property, if any, from the given property bag.
+ void DeleteProperty(PropertyBag* bag) {
+ bag->DeleteProperty(prop_id_);
+ }
+
+ protected:
+ void SetPropertyInternal(PropertyBag* bag, PropertyBag::Prop* prop) {
+ bag->SetProperty(prop_id_, prop);
+ }
+ PropertyBag::Prop* GetPropertyInternal(PropertyBag* bag) {
+ return bag->GetProperty(prop_id_);
+ }
+
+ private:
+ // Identifier for this property.
+ PropertyBag::PropID prop_id_;
+
+ DISALLOW_COPY_AND_ASSIGN(PropertyAccessorBase);
+};
+
+// PropertyAccessor -----------------------------------------------------------
+
+// Provides typesafe accessor functions for a property bag, and manages the
+// unique identifiers for properties via the PropertyAccessorBase.
+//
+// Note that class T must be derived from PropertyBag::Prop.
+template<class T>
+class PropertyAccessor : public PropertyAccessorBase {
+ public:
+ PropertyAccessor() : PropertyAccessorBase() {}
+ virtual ~PropertyAccessor() {}
+
+ // Takes ownership of the |prop| pointer.
+ void SetProperty(PropertyBag* bag, const T& prop) {
+ SetPropertyInternal(bag, new Container<T>(prop));
+ }
+
+ // Returns our property in the given bag or NULL if there is no match. The
+ // returned pointer's ownership will stay with the property bag.
+ T* GetProperty(PropertyBag* bag) {
+ PropertyBag::Prop* prop = GetPropertyInternal(bag);
+ if (!prop)
+ return NULL;
+ return static_cast< Container<T>* >(prop)->get();
+ }
+
+ // See also DeleteProperty on thn PropertyAccessorBase.
+
+ private:
+ template<class T>
+ class Container : public PropertyBag::Prop {
+ public:
+ Container(const T& data) : data_(data) {}
+
+ T* get() { return &data_; }
+
+ private:
+ virtual Prop* copy() {
+ return new Container<T>(data_);
+ }
+
+ T data_;
+ };
+
+ DISALLOW_COPY_AND_ASSIGN(PropertyAccessor);
+};
+
+#endif // CHROME_COMMON_PROPERTY_BAG_H_
diff --git a/chrome/common/property_bag_unittest.cc b/chrome/common/property_bag_unittest.cc
new file mode 100644
index 0000000..51db07c
--- /dev/null
+++ b/chrome/common/property_bag_unittest.cc
@@ -0,0 +1,62 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/property_bag.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+TEST(PropertyBagTest, AddQueryRemove) {
+ PropertyBag bag;
+ PropertyAccessor<int> adaptor;
+
+ // Should be no match initially.
+ EXPECT_EQ(NULL, adaptor.GetProperty(&bag));
+
+ // Add the value and make sure we get it back.
+ const int kFirstValue = 1;
+ adaptor.SetProperty(&bag, kFirstValue);
+ ASSERT_TRUE(adaptor.GetProperty(&bag));
+ EXPECT_EQ(kFirstValue, *adaptor.GetProperty(&bag));
+
+ // Set it to a new value.
+ const int kSecondValue = 2;
+ adaptor.SetProperty(&bag, kSecondValue);
+ ASSERT_TRUE(adaptor.GetProperty(&bag));
+ EXPECT_EQ(kSecondValue, *adaptor.GetProperty(&bag));
+
+ // Remove the value and make sure it's gone.
+ adaptor.DeleteProperty(&bag);
+ EXPECT_EQ(NULL, adaptor.GetProperty(&bag));
+}
+
+TEST(PropertyBagTest, Copy) {
+ PropertyAccessor<int> adaptor1;
+ PropertyAccessor<double> adaptor2;
+
+ // Create a bag with property type 1 in it.
+ PropertyBag copy;
+ adaptor1.SetProperty(&copy, 22);
+
+ const int kType1Value = 10;
+ const double kType2Value = 2.7;
+ {
+ // Create a bag with property types 1 and 2 in it.
+ PropertyBag initial;
+ adaptor1.SetProperty(&initial, kType1Value);
+ adaptor2.SetProperty(&initial, kType2Value);
+
+ // Assign to the original.
+ copy = initial;
+ }
+
+ // Verify the copy got the two properties.
+ ASSERT_TRUE(adaptor1.GetProperty(&copy));
+ ASSERT_TRUE(adaptor2.GetProperty(&copy));
+ EXPECT_EQ(kType1Value, *adaptor1.GetProperty(&copy));
+ EXPECT_EQ(kType2Value, *adaptor2.GetProperty(&copy));
+
+ // Clear it out, neither property should be left.
+ copy = PropertyBag();
+ EXPECT_EQ(NULL, adaptor1.GetProperty(&copy));
+ EXPECT_EQ(NULL, adaptor2.GetProperty(&copy));
+}