/*
* handle-set.c - a set which refs a handle when inserted
*
* Copyright (C) 2005,2006 Collabora Ltd.
*
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* 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., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
*/
#include <glib.h>
#include "gintset.h"
#include "handles.h"
#include "handle-set.h"
struct _GabbleHandleSet
{
GabbleHandleRepo *repo;
GIntSet *intset;
TpHandleType type;
};
/**
* handle_set_new:
* @repo: #GabbleHandleRepo that holds the handles to be reffed by this set
*
* Creates a new #GabbleHandleSet
*
* Returns: A new #GabbleHandleSet
*/
GabbleHandleSet *
handle_set_new (GabbleHandleRepo *repo, TpHandleType type)
{
GabbleHandleSet *set = g_new(GabbleHandleSet, 1);
set->intset = g_intset_new();
set->repo = repo;
set->type = type;
return set;
}
static void
freer (GabbleHandleSet *set, GabbleHandle handle, gpointer userdata)
{
handle_set_remove (set, handle);
}
/**
* handle_set_destroy:
* @set:#GabbleHandleSet to destroy
*
* Delete a #GabbleHandleSet and unreference any handles that it holds
*/
void
handle_set_destroy (GabbleHandleSet *set)
{
handle_set_foreach (set, freer, NULL);
g_intset_destroy (set->intset);
g_free (set);
}
/**
* handle_set_peek:
* @set:#GabbleHandleSet to peek at
*
* Get the underlying GIntSet used by this GabbleHandleSet
*/
GIntSet *
handle_set_peek (GabbleHandleSet *set)
{
return set->intset;
}
/**
* handle_set_add:
* @set: #GabbleHandleSet to add this handle to
* @handle: handle to add
*
* Add a handle to a #GabbleHandleSet,and reference it in the attched
* #GabbleHandleRepo
*
*/
void
handle_set_add (GabbleHandleSet *set, GabbleHandle handle)
{
g_return_if_fail (set != NULL);
g_return_if_fail (handle != 0);
if (!g_intset_is_member(set->intset, handle))
{
g_return_if_fail (gabble_handle_ref (set->repo, set->type, handle));
g_intset_add (set->intset, handle);
}
}
/**
* handle_set_remove:
* @set: #GabbleHandleSet to remove this handle from
* @handle: handle to remove
* @type: type of handle
*
* Remove a handle to a #GabbleHandleSet,and unreference it in the attched
* #GabbleHandleRepo
*
* Returns: FALSE if the (handle,type) pair was invalid, or was not in this set
*/
gboolean
handle_set_remove (GabbleHandleSet *set, GabbleHandle handle)
{
g_return_val_if_fail (set != NULL, FALSE);
g_return_val_if_fail (handle != 0, FALSE);
if (g_intset_is_member(set->intset, handle))
{
g_return_val_if_fail (gabble_handle_unref (set->repo, set->type, handle), FALSE);
g_intset_remove (set->intset, handle);
return TRUE;
}
return FALSE;
}
/**
* handle_set_is_member:
* @set: A #GabbleHandleSet
* @handle: handle to check
* @type: type of handle
*
* Check if the (handle,type) pair is in this set
*
* Returns: TRUE if the (handle,type) pair is in this repo
*
*/
gboolean
handle_set_is_member (GabbleHandleSet *set, GabbleHandle handle)
{
return g_intset_is_member(set->intset, handle);
}
typedef struct __foreach_data
{
GabbleHandleSet *set;
GabbleHandleFunc func;
gpointer userdata;
} _foreach_data;
static void
foreach_helper(guint i, gpointer userdata)
{
_foreach_data *data = (_foreach_data*) userdata;
data->func(data->set, i, data->userdata);
}
void
handle_set_foreach (GabbleHandleSet *set, GabbleHandleFunc func, gpointer userdata)
{
_foreach_data data; /*= {set, func, userdata};*/
data.set = set;
data.func = func;
data.userdata = userdata;
g_intset_foreach (set->intset, foreach_helper, &data);
}
int
handle_set_size (GabbleHandleSet *set)
{
return g_intset_size (set->intset);
}
GArray *handle_set_to_array (GabbleHandleSet *set)
{
g_return_val_if_fail (set != NULL, NULL);
return g_intset_to_array (set->intset);
}
static void
ref_one (guint handle, gpointer data)
{
GabbleHandleSet *set = (GabbleHandleSet *) data;
gabble_handle_ref (set->repo, set->type, handle);
}
/**
* handle_set_update:
* @set: a #GabbleHandleSet to update
* @add: a #GIntSet of handles to add
*
* Add a set of handles to a handle set, referencing those which are not
* already members. The GIntSet returned must be freed with g_intset_destroy.
*
* Returns: the handles which were added
*/
GIntSet *
handle_set_update (GabbleHandleSet *set, const GIntSet *add)
{
GIntSet *ret, *tmp;
g_return_val_if_fail (set != NULL, NULL);
g_return_val_if_fail (add != NULL, NULL);
/* reference each of ADD - CURRENT */
ret = g_intset_difference (add, set->intset);
g_intset_foreach (ret, ref_one, set);
/* update CURRENT to be the union of CURRENT and ADD */
tmp = g_intset_union (add, set->intset);
g_intset_destroy (set->intset);
set->intset = tmp;
return ret;
}
static void
unref_one (guint handle, gpointer data)
{
GabbleHandleSet *set = (GabbleHandleSet *) data;
gabble_handle_unref (set->repo, set->type, handle);
}
/**
* handle_set_difference_update:
* @set: a #GabbleHandleSet to update
* @remove: a #GIntSet of handles to remove
*
* Remove a set of handles from a handle set, dereferencing those which are
* members. The GIntSet returned must be freed with g_intset_destroy.
*
* Returns: the handles which were removed
*/
GIntSet *
handle_set_difference_update (GabbleHandleSet *set, const GIntSet *remove)
{
GIntSet *ret, *tmp;
g_return_val_if_fail (set != NULL, NULL);
g_return_val_if_fail (remove != NULL, NULL);
/* dereference each of REMOVE n CURRENT */
ret = g_intset_intersection (remove, set->intset);
g_intset_foreach (ret, unref_one, set);
/* update CURRENT to be CURRENT - REMOVE */
tmp = g_intset_difference (set->intset, remove);
g_intset_destroy (set->intset);
set->intset = tmp;
return ret;
}