sl@0: /* GObject - GLib Type, Object, Parameter and Signal Library sl@0: * Copyright (C) 2001 Red Hat, Inc. sl@0: * Portions copyright (c) 2006-2009 Nokia Corporation. All rights reserved. sl@0: * sl@0: * This library is free software; you can redistribute it and/or sl@0: * modify it under the terms of the GNU Lesser General Public sl@0: * License as published by the Free Software Foundation; either sl@0: * version 2 of the License, or (at your option) any later version. sl@0: * sl@0: * This library is distributed in the hope that it will be useful, sl@0: * but WITHOUT ANY WARRANTY; without even the implied warranty of sl@0: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU sl@0: * Lesser General Public License for more details. sl@0: * sl@0: * You should have received a copy of the GNU Lesser General sl@0: * Public License along with this library; if not, write to the sl@0: * Free Software Foundation, Inc., 59 Temple Place, Suite 330, sl@0: * Boston, MA 02111-1307, USA. sl@0: */ sl@0: sl@0: /* sl@0: * MT safe sl@0: */ sl@0: sl@0: #include "config.h" sl@0: sl@0: #include sl@0: #include /* qsort() */ sl@0: sl@0: #include "gvaluearray.h" sl@0: #include "gobjectalias.h" sl@0: sl@0: sl@0: /** sl@0: * SECTION:value_arrays sl@0: * @short_description: A container structure to maintain an array of sl@0: * generic values sl@0: * @see_also: #GValue, #GParamSpecValueArray, g_param_spec_value_array() sl@0: * @title: Value arrays sl@0: * sl@0: * The prime purpose of a #GValueArray is for it to be used as an sl@0: * object property that holds an array of values. A #GValueArray wraps sl@0: * an array of #GValue elements in order for it to be used as a boxed sl@0: * type through %G_TYPE_VALUE_ARRAY. sl@0: */ sl@0: sl@0: sl@0: #ifdef DISABLE_MEM_POOLS sl@0: # define GROUP_N_VALUES (1) /* power of 2 !! */ sl@0: #else sl@0: # define GROUP_N_VALUES (8) /* power of 2 !! */ sl@0: #endif sl@0: sl@0: sl@0: /* --- functions --- */ sl@0: /** sl@0: * g_value_array_get_nth: sl@0: * @value_array: #GValueArray to get a value from sl@0: * @index_: index of the value of interest sl@0: * sl@0: * Return a pointer to the value at @index_ containd in @value_array. sl@0: * sl@0: * Returns: pointer to a value at @index_ in @value_array sl@0: */ sl@0: EXPORT_C GValue* sl@0: g_value_array_get_nth (GValueArray *value_array, sl@0: guint index) sl@0: { sl@0: g_return_val_if_fail (value_array != NULL, NULL); sl@0: g_return_val_if_fail (index < value_array->n_values, NULL); sl@0: sl@0: return value_array->values + index; sl@0: } sl@0: sl@0: static inline void sl@0: value_array_grow (GValueArray *value_array, sl@0: guint n_values, sl@0: gboolean zero_init) sl@0: { sl@0: g_return_if_fail (n_values >= value_array->n_values); sl@0: sl@0: value_array->n_values = n_values; sl@0: if (value_array->n_values > value_array->n_prealloced) sl@0: { sl@0: guint i = value_array->n_prealloced; sl@0: sl@0: value_array->n_prealloced = (value_array->n_values + GROUP_N_VALUES - 1) & ~(GROUP_N_VALUES - 1); sl@0: value_array->values = g_renew (GValue, value_array->values, value_array->n_prealloced); sl@0: if (!zero_init) sl@0: i = value_array->n_values; sl@0: memset (value_array->values + i, 0, sl@0: (value_array->n_prealloced - i) * sizeof (value_array->values[0])); sl@0: } sl@0: } sl@0: sl@0: static inline void sl@0: value_array_shrink (GValueArray *value_array) sl@0: { sl@0: #ifdef DISABLE_MEM_POOLS sl@0: if (value_array->n_prealloced >= value_array->n_values + GROUP_N_VALUES) sl@0: { sl@0: value_array->n_prealloced = (value_array->n_values + GROUP_N_VALUES - 1) & ~(GROUP_N_VALUES - 1); sl@0: value_array->values = g_renew (GValue, value_array->values, value_array->n_prealloced); sl@0: } sl@0: #endif sl@0: } sl@0: sl@0: /** sl@0: * g_value_array_new: sl@0: * @n_prealloced: number of values to preallocate space for sl@0: * sl@0: * Allocate and initialize a new #GValueArray, optionally preserve space sl@0: * for @n_prealloced elements. New arrays always contain 0 elements, sl@0: * regardless of the value of @n_prealloced. sl@0: * sl@0: * Returns: a newly allocated #GValueArray with 0 values sl@0: */ sl@0: EXPORT_C GValueArray* sl@0: g_value_array_new (guint n_prealloced) sl@0: { sl@0: GValueArray *value_array = g_slice_new (GValueArray); sl@0: sl@0: value_array->n_values = 0; sl@0: value_array->n_prealloced = 0; sl@0: value_array->values = NULL; sl@0: value_array_grow (value_array, n_prealloced, TRUE); sl@0: value_array->n_values = 0; sl@0: sl@0: return value_array; sl@0: } sl@0: sl@0: /** sl@0: * g_value_array_free: sl@0: * @value_array: #GValueArray to free sl@0: * sl@0: * Free a #GValueArray including its contents. sl@0: */ sl@0: EXPORT_C void sl@0: g_value_array_free (GValueArray *value_array) sl@0: { sl@0: guint i; sl@0: sl@0: g_return_if_fail (value_array != NULL); sl@0: sl@0: for (i = 0; i < value_array->n_values; i++) sl@0: { sl@0: GValue *value = value_array->values + i; sl@0: sl@0: if (G_VALUE_TYPE (value) != 0) /* we allow unset values in the array */ sl@0: g_value_unset (value); sl@0: } sl@0: g_free (value_array->values); sl@0: g_slice_free (GValueArray, value_array); sl@0: } sl@0: sl@0: /** sl@0: * g_value_array_copy: sl@0: * @value_array: #GValueArray to copy sl@0: * sl@0: * Construct an exact copy of a #GValueArray by duplicating all its sl@0: * contents. sl@0: * sl@0: * Returns: Newly allocated copy of #GValueArray sl@0: */ sl@0: EXPORT_C GValueArray* sl@0: g_value_array_copy (const GValueArray *value_array) sl@0: { sl@0: GValueArray *new_array; sl@0: guint i; sl@0: sl@0: g_return_val_if_fail (value_array != NULL, NULL); sl@0: sl@0: new_array = g_slice_new (GValueArray); sl@0: new_array->n_values = 0; sl@0: new_array->values = NULL; sl@0: new_array->n_prealloced = 0; sl@0: value_array_grow (new_array, value_array->n_values, TRUE); sl@0: for (i = 0; i < new_array->n_values; i++) sl@0: if (G_VALUE_TYPE (value_array->values + i) != 0) sl@0: { sl@0: GValue *value = new_array->values + i; sl@0: sl@0: g_value_init (value, G_VALUE_TYPE (value_array->values + i)); sl@0: g_value_copy (value_array->values + i, value); sl@0: } sl@0: return new_array; sl@0: } sl@0: sl@0: /** sl@0: * g_value_array_prepend: sl@0: * @value_array: #GValueArray to add an element to sl@0: * @value: #GValue to copy into #GValueArray sl@0: * sl@0: * Insert a copy of @value as first element of @value_array. sl@0: * sl@0: * Returns: the #GValueArray passed in as @value_array sl@0: */ sl@0: EXPORT_C GValueArray* sl@0: g_value_array_prepend (GValueArray *value_array, sl@0: const GValue *value) sl@0: { sl@0: g_return_val_if_fail (value_array != NULL, NULL); sl@0: sl@0: return g_value_array_insert (value_array, 0, value); sl@0: } sl@0: sl@0: /** sl@0: * g_value_array_append: sl@0: * @value_array: #GValueArray to add an element to sl@0: * @value: #GValue to copy into #GValueArray sl@0: * sl@0: * Insert a copy of @value as last element of @value_array. sl@0: * sl@0: * Returns: the #GValueArray passed in as @value_array sl@0: */ sl@0: EXPORT_C GValueArray* sl@0: g_value_array_append (GValueArray *value_array, sl@0: const GValue *value) sl@0: { sl@0: g_return_val_if_fail (value_array != NULL, NULL); sl@0: sl@0: return g_value_array_insert (value_array, value_array->n_values, value); sl@0: } sl@0: sl@0: /** sl@0: * g_value_array_insert: sl@0: * @value_array: #GValueArray to add an element to sl@0: * @index_: insertion position, must be <= value_array->n_values sl@0: * @value: #GValue to copy into #GValueArray sl@0: * sl@0: * Insert a copy of @value at specified position into @value_array. sl@0: * sl@0: * Returns: the #GValueArray passed in as @value_array sl@0: */ sl@0: EXPORT_C GValueArray* sl@0: g_value_array_insert (GValueArray *value_array, sl@0: guint index, sl@0: const GValue *value) sl@0: { sl@0: guint i; sl@0: sl@0: g_return_val_if_fail (value_array != NULL, NULL); sl@0: g_return_val_if_fail (index <= value_array->n_values, value_array); sl@0: sl@0: /* we support NULL for "value" as a shortcut for an unset value */ sl@0: sl@0: i = value_array->n_values; sl@0: value_array_grow (value_array, value_array->n_values + 1, FALSE); sl@0: if (index + 1 < value_array->n_values) sl@0: g_memmove (value_array->values + index + 1, value_array->values + index, sl@0: (i - index) * sizeof (value_array->values[0])); sl@0: memset (value_array->values + index, 0, sizeof (value_array->values[0])); sl@0: if (value) sl@0: { sl@0: g_value_init (value_array->values + index, G_VALUE_TYPE (value)); sl@0: g_value_copy (value, value_array->values + index); sl@0: } sl@0: return value_array; sl@0: } sl@0: sl@0: /** sl@0: * g_value_array_remove: sl@0: * @value_array: #GValueArray to remove an element from sl@0: * @index_: position of value to remove, must be < value_array->n_values sl@0: * sl@0: * Remove the value at position @index_ from @value_array. sl@0: * sl@0: * Returns: the #GValueArray passed in as @value_array sl@0: */ sl@0: EXPORT_C GValueArray* sl@0: g_value_array_remove (GValueArray *value_array, sl@0: guint index) sl@0: { sl@0: g_return_val_if_fail (value_array != NULL, NULL); sl@0: g_return_val_if_fail (index < value_array->n_values, value_array); sl@0: sl@0: if (G_VALUE_TYPE (value_array->values + index) != 0) sl@0: g_value_unset (value_array->values + index); sl@0: value_array->n_values--; sl@0: if (index < value_array->n_values) sl@0: g_memmove (value_array->values + index, value_array->values + index + 1, sl@0: (value_array->n_values - index) * sizeof (value_array->values[0])); sl@0: value_array_shrink (value_array); sl@0: if (value_array->n_prealloced > value_array->n_values) sl@0: memset (value_array->values + value_array->n_values, 0, sizeof (value_array->values[0])); sl@0: sl@0: return value_array; sl@0: } sl@0: sl@0: /** sl@0: * g_value_array_sort: sl@0: * @value_array: #GValueArray to sort sl@0: * @compare_func: function to compare elements sl@0: * sl@0: * Sort @value_array using @compare_func to compare the elements accoring to sl@0: * the semantics of #GCompareFunc. sl@0: * sl@0: * The current implementation uses Quick-Sort as sorting algorithm. sl@0: * sl@0: * Returns: the #GValueArray passed in as @value_array sl@0: */ sl@0: EXPORT_C GValueArray* sl@0: g_value_array_sort (GValueArray *value_array, sl@0: GCompareFunc compare_func) sl@0: { sl@0: g_return_val_if_fail (compare_func != NULL, NULL); sl@0: sl@0: if (value_array->n_values) sl@0: qsort (value_array->values, sl@0: value_array->n_values, sl@0: sizeof (value_array->values[0]), sl@0: compare_func); sl@0: return value_array; sl@0: } sl@0: sl@0: /** sl@0: * g_value_array_sort_with_data: sl@0: * @value_array: #GValueArray to sort sl@0: * @compare_func: function to compare elements sl@0: * @user_data: extra data argument provided for @compare_func sl@0: * sl@0: * Sort @value_array using @compare_func to compare the elements accoring sl@0: * to the semantics of #GCompareDataFunc. sl@0: * sl@0: * The current implementation uses Quick-Sort as sorting algorithm. sl@0: * sl@0: * Returns: the #GValueArray passed in as @value_array sl@0: */ sl@0: EXPORT_C GValueArray* sl@0: g_value_array_sort_with_data (GValueArray *value_array, sl@0: GCompareDataFunc compare_func, sl@0: gpointer user_data) sl@0: { sl@0: g_return_val_if_fail (value_array != NULL, NULL); sl@0: g_return_val_if_fail (compare_func != NULL, NULL); sl@0: sl@0: if (value_array->n_values) sl@0: g_qsort_with_data (value_array->values, sl@0: value_array->n_values, sl@0: sizeof (value_array->values[0]), sl@0: compare_func, user_data); sl@0: return value_array; sl@0: } sl@0: sl@0: #define __G_VALUE_ARRAY_C__ sl@0: #include "gobjectaliasdef.c"