[libgweather/benzea/wip-variant-backend] weather-location: Add child iteration API



commit b9c922899613f3e98538f87f897ccd60a01a400e
Author: Benjamin Berg <bberg redhat com>
Date:   Sun Apr 26 21:24:47 2020 +0200

    weather-location: Add child iteration API
    
    This is just a single function, which will return the next child given
    an already passed in child.

 libgweather/gweather-location.c | 150 +++++++++++++++++++++++++++++++---------
 libgweather/gweather-location.h |   2 +
 2 files changed, 118 insertions(+), 34 deletions(-)
---
diff --git a/libgweather/gweather-location.c b/libgweather/gweather-location.c
index 1c3d4c3..1de68b6 100644
--- a/libgweather/gweather-location.c
+++ b/libgweather/gweather-location.c
@@ -729,6 +729,102 @@ gweather_location_get_parent (GWeatherLocation *loc)
     return location_sink_keep_alive (gweather_location_dup_parent (loc));;
 }
 
+/**
+ * gweather_location_get_children:
+ * @loc: a #GWeatherLocation
+ * @child: (transfer full): The child
+ *
+ * Allows iterating all children. Pass %NULL to get the first child,
+ * and any child to get the next one. Note that the reference to @child
+ * is taken, meaning iterating all children is as simple as:
+ *
+ * |[<!-- language="C" -->
+ *   g_autoptr(GWeatherLocation) child = NULL;
+ *   while ((child = gweather_location_next_child (location, child)))
+ *     {
+ *        // Do something with child
+ *     }
+ * ]|
+ *
+ * Returns: (transfer full): The next child, or %NULL
+ *
+ * Since: XXX.
+ **/
+GWeatherLocation*
+gweather_location_next_child  (GWeatherLocation  *loc, GWeatherLocation  *_child)
+{
+       g_autoptr(GWeatherLocation) child = _child;
+       DbArrayofuint16Ref children_ref;
+       gsize length;
+       gsize next_idx;
+       gsize i;
+
+       g_return_val_if_fail (loc != NULL, NULL);
+
+       /* Easy case, just look up the child and grab the next one. */
+       if (loc->_children) {
+               if (child == NULL)
+                       return gweather_location_ref (loc->_children[0]);
+
+               for (i = 0; loc->_children[i]; i++) {
+                       if (loc->_children[i] == child)
+                               return loc->_children[i + 1];
+               }
+
+               goto invalid_child;
+       }
+
+       /* If we have a magic nearest child, iterate over that. */
+       if (!g_getenv ("LIBGWEATHER_LOCATIONS_NO_NEAREST") &&
+           IDX_VALID (db_location_get_nearest (loc->ref))) {
+               g_autoptr(GWeatherLocation) res = location_ref_for_idx (loc->db, db_location_get_nearest 
(loc->ref), loc);
+               if (child) {
+                       if (res != child)
+                               goto invalid_child;
+
+                       return NULL;
+               } else {
+                       return res;
+               }
+       }
+
+       if (!loc->db || !IDX_VALID (loc->db_idx)) {
+               if (child)
+                       goto invalid_child;
+
+               return NULL;
+       }
+
+       children_ref = db_location_get_children (loc->ref);
+       length = db_arrayofuint16_get_length (children_ref);
+
+       if (!child) {
+               next_idx = 0;
+       } else {
+               /* Find child index in DB. */
+               for (i = 0; i < length; i++) {
+                       if (child->db_idx == db_arrayofuint16_get_at (children_ref, i))
+                               break;
+               }
+
+               if (i == length)
+                       goto invalid_child;
+               next_idx = i + 1;
+       }
+
+       if (next_idx == length)
+               return NULL;
+       else
+               return location_ref_for_idx (loc->db,
+                                            db_arrayofuint16_get_at (children_ref, next_idx),
+                                            NULL);
+
+
+invalid_child:
+       g_critical ("%s: Passed child %p is not a child of the given location %p", G_STRFUNC, loc, child);
+       return NULL;
+}
+
 /**
  * gweather_location_get_children:
  * @loc: a #GWeatherLocation
@@ -739,7 +835,7 @@ gweather_location_get_parent (GWeatherLocation *loc)
  * Return value: (transfer none) (array zero-terminated=1): @loc's
  * children. (May be empty, but will not be %NULL.)
  *
- * Deprecated: XXX. Use XXX() instead?
+ * Deprecated: XXX. Use gweather_location_next_child() instead
  **/
 GWeatherLocation **
 gweather_location_get_children (GWeatherLocation *loc)
@@ -803,27 +899,11 @@ foreach_city (GWeatherLocation  *loc,
 
     if (loc->level == GWEATHER_LOCATION_CITY) {
         callback (loc, user_data);
-    } else if (loc->_children) { /* Iteration cached/static children */
-        int i;
-        for (i = 0; loc->_children[i]; i++)
-            foreach_city (loc->_children[i], callback, user_data, country_code, func, user_data_func);
-    } else if (loc->db) { /* Iteration children without caching them */
-       DbArrayofuint16Ref children_ref;
-       gsize length;
-       gsize i;
-
-       children_ref = db_location_get_children (loc->ref);
-       length = db_arrayofuint16_get_length (children_ref);
-
-       for (i = 0; i < length; i++) {
-           g_autoptr(GWeatherLocation) child = NULL;
-
-           child = location_ref_for_idx (loc->db,
-                                         db_arrayofuint16_get_at (children_ref, i),
-                                         NULL);
+    } else {
+       g_autoptr(GWeatherLocation) child = NULL;
 
+       while ((child = gweather_location_next_child (loc, child)))
            foreach_city (child, callback, user_data, country_code, func, user_data_func);
-       }
     }
 }
 
@@ -1249,18 +1329,17 @@ gweather_location_get_timezone_str (GWeatherLocation *loc)
 static void
 add_timezones (GWeatherLocation *loc, GPtrArray *zones)
 {
-    GWeatherLocation **children;
     int i;
 
-    /* FIXME: Do this without holding on to the children! */
-    children = gweather_location_get_children (loc);
     if (loc->zones) {
        for (i = 0; loc->zones[i]; i++)
            g_ptr_array_add (zones, gweather_timezone_ref (loc->zones[i]));
     }
-    if (loc->level < GWEATHER_LOCATION_COUNTRY && children) {
-       for (i = 0; children[i]; i++)
-           add_timezones (children[i], zones);
+    if (loc->level < GWEATHER_LOCATION_COUNTRY) {
+       g_autoptr(GWeatherLocation) child = NULL;
+
+       while ((child = gweather_location_next_child (loc, child)))
+           add_timezones (child, zones);
     }
 }
 
@@ -1397,18 +1476,21 @@ _gweather_location_update_weather_location (GWeatherLocation *gloc,
     gint tz_hint_idx = INVALID_IDX;
     gboolean latlon_valid = FALSE;
     gdouble lat = DBL_MAX, lon = DBL_MAX;
+    g_autoptr(GWeatherLocation) start = NULL;
     g_autoptr(GWeatherLocation) l = NULL;
-    GWeatherLocation **children;
     GWeatherDb *db = NULL;
 
-    /* FIXME: Do this without holding on to the children! */
-    children = gweather_location_get_children (gloc);
-    if (gloc->level == GWEATHER_LOCATION_CITY && children)
-       l = children[0];
-    else
-       l = gloc;
+    if (gloc->level == GWEATHER_LOCATION_CITY) {
+       GWeatherLocation *first_child;
+       first_child = gweather_location_next_child (gloc, NULL);
+
+       if (first_child)
+               start = first_child;
+    }
+    if (!start)
+       start = gweather_location_ref (gloc);
 
-    ITER_UP(gloc, l) {
+    ITER_UP(start, l) {
        if (!db && l->db)
            db = l->db;
        if (!code && l->station_code)
diff --git a/libgweather/gweather-location.h b/libgweather/gweather-location.h
index 95f1361..caf396c 100644
--- a/libgweather/gweather-location.h
+++ b/libgweather/gweather-location.h
@@ -75,6 +75,8 @@ GWeatherLocation      *gweather_location_get_parent     (GWeatherLocation  *loc)
 GWEATHER_EXTERN
 GWeatherLocation      *gweather_location_dup_parent     (GWeatherLocation  *loc);
 
+GWEATHER_EXTERN
+GWeatherLocation      *gweather_location_next_child     (GWeatherLocation  *loc, GWeatherLocation  *child);
 GWEATHER_EXTERN
 GWeatherLocation     **gweather_location_get_children   (GWeatherLocation  *loc);
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]