DataSet.vala 5.56 KB
Newer Older
1
/* Copyright 2016 Software Freedom Conservancy Inc.
2 3
 *
 * This software is licensed under the GNU Lesser General Public License
4
 * (version 2.1 or later).  See the COPYING file in this distribution.
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
 */

//
// 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>();
32 33
    private unowned Comparator user_comparator = null;
    private unowned ComparatorPredicate? comparator_predicate = null;
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
    
    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
54 55 56 57 58
        int64 result = 0;
        
        if (user_comparator != null)
            result = user_comparator(a, b);
            
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
        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);
    }
    
81
    public unowned Comparator get_comparator() {
82 83 84
        return user_comparator;
    }
    
85
    public unowned ComparatorPredicate get_comparator_predicate() {
86 87 88
        return comparator_predicate;
    }
    
89 90 91 92 93 94
    public void set_comparator(Comparator user_comparator, ComparatorPredicate? comparator_predicate) {
        this.user_comparator = user_comparator;
        this.comparator_predicate = comparator_predicate;
        list.resort(comparator_wrapper);
    }
    
95 96
    public Gee.List<DataObject> get_all() {
        return list.read_only_view_as_list;
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
    }
    
    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);
    }
}