From ed30714507e6099c5f56bd7469706e550a68bda8 Mon Sep 17 00:00:00 2001 From: Rodrigo Moya Date: Thu, 29 Dec 2016 01:05:00 +0100 Subject: Add some more query operations for Traversable * first_match (Predicate) returns the first item that matches * any_match (Predicate) checks if any element matches * all_match (Predicate) checks if all elements match * max/min returns max/min value * order_by to perform ordering on any Traversable https://bugzilla.gnome.org/show_bug.cgi?id=776558 --- gee/traversable.vala | 112 ++++++++++++++++++++++++++++++++++++++++++++++ tests/testcollection.vala | 62 +++++++++++++++++++++++++ 2 files changed, 174 insertions(+) diff --git a/gee/traversable.vala b/gee/traversable.vala index 77ce6ea..bc6ae1d 100644 --- a/gee/traversable.vala +++ b/gee/traversable.vala @@ -446,6 +446,118 @@ public interface Gee.Traversable : Object { } } + /** + * Returns the first element that matches a given condition + * + * @param pred Predicate to be called to check for matches + * @return The first element that matches or null + * @since 0.18.2 + */ + [CCode (ordering = 10)] + public virtual G? first_match (owned Predicate pred) { + G? result = null; + this.foreach ((item) => { + if (pred (item)) { + result = item; + return false; + } + return true; + }); + return (owned) result; + } + + /** + * Returns whether any element matches the given predicate. + * + * This is similar to @first_match, with the difference that it + * just returns whether there is a match or not, not the value + * of the match. + * + * @param pred Predicate to be called to check for matches + * @return Whether there was a match or not + * @since 0.18.2 + */ + [CCode (ordering = 11)] + public virtual bool any_match (owned Predicate pred) { + return this.first_match (pred) != null; + } + + /** + * Checks whether all elements match the given predicate. + * + * @param pred Predicate to be called to check for matches + * @return Whether all elements match or not + * @since 0.18.2 + */ + [CCode (ordering = 12)] + public virtual bool all_match (owned Predicate pred) { + bool result = true; + this.foreach ((item) => { + if (!pred (item)) { + result = false; + return false; + } + return true; + }); + return result; + } + + /** + * Returns the item in the sequence that contains the max value + * based on the given compare function. + * + * @param compare Function to be called for comparisons + * @return The item containing the max value. + * @since 0.18.2 + */ + [CCode (ordering = 13)] + public virtual G max (owned CompareDataFunc compare) { + G max_value = null; + this.foreach ((item) => { + if (max_value == null || compare (max_value, item) > 0) { + max_value = item; + } + return true; + }); + return max_value; + } + + /** + * Returns the item in the sequence that contains the min value + * based on the given compare function. + * + * @param compare Function to be called for comparisons + * @return The item containing the min value. + * @since 0.18.2 + */ + [CCode (ordering = 14)] + public virtual G min (owned CompareDataFunc compare) { + G min_value = null; + this.foreach ((item) => { + if (min_value == null || compare (min_value, item) < 0) { + min_value = item; + } + return true; + }); + return min_value; + } + + /** + * Returns a new iterator containing the elements in the source + * ordered as specified by the comparison function. + * + * @param compare Comparison function + * @return A new iterator with the source elements sorted. + * @since 0.18.2 + */ + [CCode (ordering = 15)] + public virtual Iterator order_by (owned CompareDataFunc? compare = null) { + ArrayList result = new ArrayList (); + this.foreach ((item) => result.add (item)); + result.sort (compare); + return result.iterator (); + } + public enum Stream { YIELD, CONTINUE, diff --git a/tests/testcollection.vala b/tests/testcollection.vala index 268724a..819e130 100644 --- a/tests/testcollection.vala +++ b/tests/testcollection.vala @@ -51,6 +51,11 @@ public abstract class CollectionTests : Gee.TestCase { add_test ("[Collection] scan", test_scan); add_test ("[Collection] filter", test_filter); add_test ("[Collection] chop", test_chop); + add_test ("[Collection] first_match", test_first_match); + add_test ("[Collection] any_match", test_any_match); + add_test ("[Collection] all_match", test_all_match); + add_test ("[Collection] max_min", test_max_min); + add_test ("[Collection] order_by", test_order_by); } protected Collection test_collection; @@ -1197,5 +1202,62 @@ public abstract class CollectionTests : Gee.TestCase { assert (!iter.next ()); assert (iter2.next ()); } + + public void test_first_match () { + assert (test_collection.add ("one")); + assert (test_collection.add ("two")); + assert (test_collection.add ("three")); + + assert (test_collection.first_match ((x) => x == "one") == "one"); + assert (test_collection.first_match ((x) => x == "two") == "two"); + assert (test_collection.first_match ((x) => x == "three") == "three"); + assert (test_collection.first_match ((x) => x == "four") == null); + } + + public void test_any_match () { + assert (test_collection.add ("one")); + assert (test_collection.add ("two")); + assert (test_collection.add ("three")); + + assert (test_collection.any_match ((x) => x == "one")); + assert (test_collection.any_match ((x) => x == "two")); + assert (test_collection.any_match ((x) => x == "three")); + assert (!test_collection.any_match ((x) => x == "four")); + } + + public void test_all_match () { + assert (test_collection.add ("one")); + assert (test_collection.all_match ((x) => x == "one")); + + assert (test_collection.add ("two")); + assert (!test_collection.all_match ((x) => x == "one")); + } + + public void test_max_min () { + assert (test_collection.add ("one")); + assert (test_collection.add ("two")); + assert (test_collection.add ("three")); + + assert (test_collection.max ((a, b) => strcmp (a, b)) == "one"); + assert (test_collection.min ((a, b) => strcmp (a, b)) == "two"); + } + + public void test_order_by () { + assert (test_collection.add ("one")); + assert (test_collection.add ("two")); + assert (test_collection.add ("three")); + + var sorted_collection = test_collection.order_by ((a, b) => strcmp (a, b)); + + string previous_item = null; + while (sorted_collection.next ()) { + var item = sorted_collection.get (); + if (previous_item != null) { + assert (strcmp (previous_item, item) <= 0); + } + + previous_item = item; + } + } } -- cgit v1.2.1