/* Copyright 2016 Software Freedom Conservancy Inc. * * This software is licensed under the GNU Lesser General Public License * (version 2.1 or later). See the COPYING file in this distribution. */ namespace Geary.Collection { public delegate uint8 ByteTransformer(uint8 b); public inline bool is_empty(Gee.Collection? c) { return c == null || c.size == 0; } /** Returns a modifiable collection containing a single element. */ public Gee.Collection single(T element) { Gee.Collection single = new Gee.LinkedList(); single.add(element); return single; } /** Returns a modifiable map containing a single entry. */ public Gee.Map single_map(K key, V value) { Gee.Map single = new Gee.HashMap(); single.set(key, value); return single; } // A substitute for ArrayList.wrap() for compatibility with older versions of Gee. public Gee.ArrayList array_list_wrap(G[] a, owned Gee.EqualDataFunc? equal_func = null) { Gee.ArrayList list = new Gee.ArrayList((owned) equal_func); add_all_array(list, a); return list; } public Gee.ArrayList to_array_list(Gee.Collection c) { Gee.ArrayList list = new Gee.ArrayList(); list.add_all(c); return list; } public Gee.HashMap to_hash_map( Gee.Collection c, Gee.MapFunc key_selector) { Gee.HashMap map = new Gee.HashMap(); foreach (Value v in c) map.set(key_selector(v), v); return map; } public void add_all_array(Gee.Collection c, G[] ar) { foreach (G g in ar) c.add(g); } public G? get_first(Gee.Collection c) { Gee.Iterator iter = c.iterator(); return iter.next() ? iter.get() : null; } /** * Returns the first element in the Collection that passes the Predicte function. * * The Collection is walked in Iterator order. */ public G? find_first(Gee.Collection c, owned Gee.Predicate pred) { Gee.Iterator iter = c.iterator(); while (iter.next()) { if (pred(iter.get())) return iter.get(); } return null; } public bool are_sets_equal(Gee.Set a, Gee.Set b) { if (a.size != b.size) return false; foreach (G element in a) { if (!b.contains(element)) return false; } return true; } /** * Removes all elements from the Collection that do pass the Predicate function. * * Note that this modifies the supplied Collection. */ public Gee.Collection remove_if(Gee.Collection c, owned Gee.Predicate pred) { Gee.Iterator iter = c.iterator(); while (iter.next()) { if (pred(iter.get())) iter.remove(); } return c; } /** * Sets the dest Map with all keys and values in src. */ public void map_set_all(Gee.Map dest, Gee.Map src) { foreach (K key in src.keys) dest.set(key, src.get(key)); } /** * Sets multiple elements with the same key in a MultiMap. */ public void multi_map_set_all(Gee.MultiMap dest, K key, Gee.Collection values) { foreach (V value in values) dest.set(key, value); } /** * Removes all keys from the Map. */ public void map_unset_all_keys(Gee.Map map, Gee.Collection keys) { foreach (K key in keys) map.unset(key); } /** * Return a MultiMap of value => key of the input map's key => values. */ public Gee.MultiMap reverse_multi_map(Gee.MultiMap map) { Gee.HashMultiMap reverse = new Gee.HashMultiMap(); foreach (K key in map.get_keys()) { foreach (V value in map.get(key)) reverse.set(value, key); } return reverse; } /** * To be used by a Hashable's to_hash() method. */ public inline uint int64_hash(int64 value) { return hash_memory(&value, sizeof(int64)); } /** * To be used as hash_func for Gee collections. */ public inline uint int64_hash_func(int64? n) { return hash_memory((uint8 *) n, sizeof(int64)); } /** * To be used as equal_func for Gee collections. */ public bool int64_equal_func(int64? a, int64? b) { int64 *bia = (int64 *) a; int64 *bib = (int64 *) b; return (*bia) == (*bib); } /** * A rotating-XOR hash that can be used to hash memory buffers of any size. */ public uint hash_memory(void *ptr, size_t bytes) { if (ptr == null || bytes == 0) return 0; uint8 *u8 = (uint8 *) ptr; // initialize hash to first byte value and then rotate-XOR from there uint hash = *u8; for (int ctr = 1; ctr < bytes; ctr++) hash = (hash << 4) ^ (hash >> 28) ^ (*u8++); return hash; } /** * A rotating-XOR hash that can be used to hash memory buffers of any size until a terminator byte * is found. * * A {@link ByteTransformer} may be supplied to convert bytes before they are hashed. * * Returns zero if the initial byte is the terminator. */ public uint hash_memory_stream(void *ptr, uint8 terminator, ByteTransformer? cb) { uint8 *u8 = (uint8 *) ptr; uint hash = 0; for (;;) { uint8 b = *u8++; if (b == terminator) break; if (cb != null) b = cb(b); hash = (hash << 4) ^ (hash >> 28) ^ b; } return hash; } }