summaryrefslogtreecommitdiff
path: root/src/core/DataSet.vala
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/DataSet.vala')
-rw-r--r--src/core/DataSet.vala183
1 files changed, 183 insertions, 0 deletions
diff --git a/src/core/DataSet.vala b/src/core/DataSet.vala
new file mode 100644
index 0000000..ebb5500
--- /dev/null
+++ b/src/core/DataSet.vala
@@ -0,0 +1,183 @@
+/* Copyright 2011-2014 Yorba Foundation
+ *
+ * This software is licensed under the GNU Lesser General Public License
+ * (version 2.1 or later). See the COPYING file in this distribution.
+ */
+
+//
+// DataSet
+//
+// A DataSet is a collection class used for internal implementations of DataCollection
+// and its children. It may be of use to other classes, however.
+//
+// The general purpose of DataSet is to provide low-cost implementations of various collection
+// operations at a cost of internally maintaining its objects in more than one simple collection.
+// contains(), for example, can return a result with hash-table performance while notions of
+// ordering are maintained by a SortedList. The cost is in adding and removing objects (in general,
+// there are others).
+//
+// Because this class has no signalling mechanisms and does not manipulate DataObjects in ways
+// they expect to be manipulated (these features are performed by DataCollection), it's probably
+// best not to use this class. Even in cases of building a list of DataObjects for some quick
+// operation is probably best done by a Gee.ArrayList.
+//
+
+// ComparatorPredicate is used to determine if a re-sort operation is necessary; it has no
+// effect on adding a DataObject to a DataSet in sorted order.
+public delegate bool ComparatorPredicate(DataObject object, Alteration alteration);
+
+public class DataSet {
+ private SortedList<DataObject> list = new SortedList<DataObject>();
+ private Gee.HashSet<DataObject> hash_set = new Gee.HashSet<DataObject>();
+ private unowned Comparator user_comparator = null;
+ private unowned ComparatorPredicate? comparator_predicate = null;
+
+ public DataSet() {
+ reset_comparator();
+ }
+
+ private int64 order_added_comparator(void *a, void *b) {
+ return ((DataObject *) a)->internal_get_ordinal() - ((DataObject *) b)->internal_get_ordinal();
+ }
+
+ private bool order_added_predicate(DataObject object, Alteration alteration) {
+ // ordinals don't change (shouldn't change!) while a part of the DataSet
+ return false;
+ }
+
+ private int64 comparator_wrapper(void *a, void *b) {
+ if (a == b)
+ return 0;
+
+ // use the order-added comparator if the user's compare returns equal, to stabilize the
+ // sort
+ int64 result = 0;
+
+ if (user_comparator != null)
+ result = user_comparator(a, b);
+
+ if (result == 0)
+ result = order_added_comparator(a, b);
+
+ assert(result != 0);
+
+ return result;
+ }
+
+ public bool contains(DataObject object) {
+ return hash_set.contains(object);
+ }
+
+ public inline int get_count() {
+ return list.get_count();
+ }
+
+ public void reset_comparator() {
+ user_comparator = null;
+ comparator_predicate = order_added_predicate;
+ list.resort(order_added_comparator);
+ }
+
+ public unowned Comparator get_comparator() {
+ return user_comparator;
+ }
+
+ public unowned ComparatorPredicate get_comparator_predicate() {
+ return comparator_predicate;
+ }
+
+ public void set_comparator(Comparator user_comparator, ComparatorPredicate? comparator_predicate) {
+ this.user_comparator = user_comparator;
+ this.comparator_predicate = comparator_predicate;
+ list.resort(comparator_wrapper);
+ }
+
+ public Gee.List<DataObject> get_all() {
+ return list.read_only_view_as_list;
+ }
+
+ public DataSet copy() {
+ DataSet clone = new DataSet();
+ clone.list = list.copy();
+ clone.hash_set.add_all(hash_set);
+
+ return clone;
+ }
+
+ public DataObject? get_at(int index) {
+ return list.get_at(index);
+ }
+
+ public int index_of(DataObject object) {
+ return list.locate(object, false);
+ }
+
+ // DataObject's ordinal should be set before adding.
+ public bool add(DataObject object) {
+ if (!list.add(object))
+ return false;
+
+ if (!hash_set.add(object)) {
+ // attempt to back out of previous operation
+ list.remove(object);
+
+ return false;
+ }
+
+ return true;
+ }
+
+ // DataObjects' ordinals should be set before adding.
+ public bool add_many(Gee.Collection<DataObject> objects) {
+ int count = objects.size;
+ if (count == 0)
+ return true;
+
+ if (!list.add_all(objects))
+ return false;
+
+ if (!hash_set.add_all(objects)) {
+ // back out previous operation
+ list.remove_all(objects);
+
+ return false;
+ }
+
+ return true;
+ }
+
+ public bool remove(DataObject object) {
+ bool success = true;
+
+ if (!list.remove(object))
+ success = false;
+
+ if (!hash_set.remove(object))
+ success = false;
+
+ return success;
+ }
+
+ public bool remove_many(Gee.Collection<DataObject> objects) {
+ bool success = true;
+
+ if (!list.remove_all(objects))
+ success = false;
+
+ if (!hash_set.remove_all(objects))
+ success = false;
+
+ return success;
+ }
+
+ // Returns true if the item has moved.
+ public bool resort_object(DataObject object, Alteration? alteration) {
+ if (comparator_predicate != null && alteration != null
+ && !comparator_predicate(object, alteration)) {
+ return false;
+ }
+
+ return list.resort_item(object);
+ }
+}
+