cleanup
[platform/upstream/glib.git] / gio / gsrvtarget.c
index 537d816..232da5a 100644 (file)
@@ -15,9 +15,7 @@
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General
- * Public License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #include "config.h"
@@ -29,7 +27,6 @@
 #include <stdlib.h>
 #include <string.h>
 
-#include "gioalias.h"
 
 /**
  * SECTION:gsrvtarget
  * would look up the "xmpp-client" SRV record for "example.com", and
  * then connect to whatever host was pointed to by that record.
  *
- * Use g_resolver_lookup_service() or
- * g_resolver_lookup_service_async() to find the #GSrvTarget<!-- -->s
- * for a given service.
- **/
+ * You can use g_resolver_lookup_service() or
+ * g_resolver_lookup_service_async() to find the #GSrvTargets
+ * for a given service. However, if you are simply planning to connect
+ * to the remote service, you can use #GNetworkService's
+ * #GSocketConnectable interface and not need to worry about
+ * #GSrvTarget at all.
+ */
 
 struct _GSrvTarget {
   gchar   *hostname;
@@ -63,21 +63,8 @@ struct _GSrvTarget {
  * A single target host/port that a network service is running on.
  */
 
-GType
-g_srv_target_get_type (void)
-{
-  static volatile gsize type_volatile = 0;
-
-  if (g_once_init_enter (&type_volatile))
-    {
-      GType type = g_boxed_type_register_static (
-                        g_intern_static_string ("GSrvTarget"),
-                       (GBoxedCopyFunc) g_srv_target_copy,
-                       (GBoxedFreeFunc) g_srv_target_free);
-      g_once_init_leave (&type_volatile, type);
-    }
-  return type_volatile;
-}
+G_DEFINE_BOXED_TYPE (GSrvTarget, g_srv_target,
+                     g_srv_target_copy, g_srv_target_free)
 
 /**
  * g_srv_target_new:
@@ -88,13 +75,13 @@ g_srv_target_get_type (void)
  *
  * Creates a new #GSrvTarget with the given parameters.
  *
- * You should not need to use this; normally #GSrvTarget<!-- -->s are
+ * You should not need to use this; normally #GSrvTargets are
  * created by #GResolver.
  *
- * Return value: a new #GSrvTarget.
+ * Returns: a new #GSrvTarget.
  *
  * Since: 2.22
- **/
+ */
 GSrvTarget *
 g_srv_target_new (const gchar *hostname,
                   guint16      port,
@@ -117,10 +104,10 @@ g_srv_target_new (const gchar *hostname,
  *
  * Copies @target
  *
- * Return value: a copy of @target
+ * Returns: a copy of @target
  *
  * Since: 2.22
- **/
+ */
 GSrvTarget *
 g_srv_target_copy (GSrvTarget *target)
 {
@@ -135,7 +122,7 @@ g_srv_target_copy (GSrvTarget *target)
  * Frees @target
  *
  * Since: 2.22
- **/
+ */
 void
 g_srv_target_free (GSrvTarget *target)
 {
@@ -152,10 +139,10 @@ g_srv_target_free (GSrvTarget *target)
  * check if it contains encoded Unicode segments, and use
  * g_hostname_to_unicode() to convert it if it does.)
  *
- * Return value: @target's hostname
+ * Returns: @target's hostname
  *
  * Since: 2.22
- **/
+ */
 const gchar *
 g_srv_target_get_hostname (GSrvTarget *target)
 {
@@ -168,10 +155,10 @@ g_srv_target_get_hostname (GSrvTarget *target)
  *
  * Gets @target's port
  *
- * Return value: @target's port
+ * Returns: @target's port
  *
  * Since: 2.22
- **/
+ */
 guint16
 g_srv_target_get_port (GSrvTarget *target)
 {
@@ -186,10 +173,10 @@ g_srv_target_get_port (GSrvTarget *target)
  * #GResolver already sorts the targets according to the algorithm in
  * RFC 2782.
  *
- * Return value: @target's priority
+ * Returns: @target's priority
  *
  * Since: 2.22
- **/
+ */
 guint16
 g_srv_target_get_priority (GSrvTarget *target)
 {
@@ -204,17 +191,17 @@ g_srv_target_get_priority (GSrvTarget *target)
  * #GResolver already sorts the targets according to the algorithm in
  * RFC 2782.
  *
- * Return value: @target's weight
+ * Returns: @target's weight
  *
  * Since: 2.22
- **/
+ */
 guint16
 g_srv_target_get_weight (GSrvTarget *target)
 {
   return target->weight;
 }
 
-gint
+static gint
 compare_target (gconstpointer a, gconstpointer b)
 {
   GSrvTarget *ta = (GSrvTarget *)a;
@@ -226,34 +213,28 @@ compare_target (gconstpointer a, gconstpointer b)
        * that all those with weight 0 are placed at the beginning of
        * the list"
        */
-      if (ta->weight == 0)
-        return -1;
-      else if (tb->weight == 0)
-        return 1;
-      else
-        return g_random_int_range (-1, 1);
+      return ta->weight - tb->weight;
     }
   else
     return ta->priority - tb->priority;
 }
 
 /**
- * g_srv_target_list_sort:
+ * g_srv_target_list_sort: (skip)
  * @targets: a #GList of #GSrvTarget
  *
  * Sorts @targets in place according to the algorithm in RFC 2782.
  *
- * Return value: the head of the sorted list.
+ * Returns: (transfer full): the head of the sorted list.
  *
  * Since: 2.22
- **/ 
+ */
 GList *
 g_srv_target_list_sort (GList *targets)
 {
-  gint sum, val, priority, weight;
-  GList *first, *last, *n;
+  gint sum, num, val, priority, weight;
+  GList *t, *out, *tail;
   GSrvTarget *target;
-  gpointer tmp;
 
   if (!targets)
     return NULL;
@@ -272,63 +253,60 @@ g_srv_target_list_sort (GList *targets)
         }
     }
 
-  /* Sort by priority, and partly by weight */
+  /* Sort input list by priority, and put the 0-weight targets first
+   * in each priority group. Initialize output list to %NULL.
+   */
   targets = g_list_sort (targets, compare_target);
+  out = tail = NULL;
 
-  /* For each group of targets with the same priority, rebalance them
-   * according to weight.
+  /* For each group of targets with the same priority, remove them
+   * from @targets and append them to @out in a valid order.
    */
-  for (first = targets; first; first = last->next)
+  while (targets)
     {
-      /* Skip @first to a non-0-weight target. */
-      while (first && ((GSrvTarget *)first->data)->weight == 0)
-        first = first->next;
-      if (!first)
-        break;
-
-      /* Skip @last to the last target of the same priority. */
-      priority = ((GSrvTarget *)first->data)->priority;
-      last = first;
-      while (last->next &&
-             ((GSrvTarget *)last->next->data)->priority == priority)
-        last = last->next;
-
-      /* If there's only one non-0 weight target at this priority,
-       * we can move on to the next priority level.
-       */
-      if (last == first)
-        continue;
-
-      /* Randomly reorder the non-0 weight targets, giving precedence
-       * to the ones with higher weight. RFC 2782 describes this in
-       * terms of assigning a running sum to each target and building
-       * a new list. We do things slightly differently, but should get
-       * the same result.
+      priority = ((GSrvTarget *)targets->data)->priority;
+
+      /* Count the number of targets at this priority level, and
+       * compute the sum of their weights.
        */
-      for (n = first, sum = 0; n != last->next; n = n->next)
-        sum += ((GSrvTarget *)n->data)->weight;
-      while (first != last)
+      sum = num = 0;
+      for (t = targets; t; t = t->next)
         {
-          val = g_random_int_range (0, sum);
-          for (n = first; n != last; n = n->next)
+          target = (GSrvTarget *)t->data;
+          if (target->priority != priority)
+            break;
+          sum += target->weight;
+          num++;
+        }
+
+      /* While there are still targets at this priority level... */
+      while (num)
+        {
+          /* Randomly select from the targets at this priority level,
+           * giving precedence to the ones with higher weight,
+           * according to the rules from RFC 2782.
+           */
+          val = g_random_int_range (0, sum + 1);
+          for (t = targets; ; t = t->next)
             {
-              weight = ((GSrvTarget *)n->data)->weight;
-              if (val < weight)
+              weight = ((GSrvTarget *)t->data)->weight;
+              if (weight >= val)
                 break;
               val -= weight;
             }
 
-          tmp = first->data;
-          first->data = n->data;
-          n->data = tmp;
+          targets = g_list_remove_link (targets, t);
+
+          if (!out)
+            out = t;
+          else
+            tail->next = t;
+          tail = t;
 
           sum -= weight;
-          first = first->next;
+          num--;
         }
     }
 
-  return targets;
+  return out;
 }
-
-#define __G_SRV_TARGET_C__
-#include "gioaliasdef.c"