Find file
Fetching contributors…
Cannot retrieve contributors at this time
295 lines (270 sloc) 6.67 KB
/*
* mono-mlist.c: Managed object list implementation
*
* Author:
* Paolo Molaro (lupus@ximian.com)
*
* Copyright 2006-2009 Novell, Inc (http://www.novell.com)
* Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include "mono/metadata/mono-mlist.h"
#include "mono/metadata/appdomain.h"
#include "mono/metadata/class-internals.h"
#include "mono/metadata/object-internals.h"
static
MonoMList* mono_mlist_alloc_checked (MonoObject *data, MonoError *error);
/* matches the System.MonoListItem object*/
struct _MonoMList {
MonoObject object;
MonoMList *next;
MonoObject *data;
};
/*
* note: we only allocate in the root domain: this lists are
* not exposed to managed code
*/
static MonoVTable *monolist_item_vtable = NULL;
/**
* mono_mlist_alloc:
* @data: object to use as data
*
* Allocates a new managed list node with @data as the contents.
* A managed list node also represents a singly-linked list.
* Managed lists are garbage collected, so there is no free routine
* and the user is required to keep references to the managed list
* to prevent it from being garbage collected.
*/
MonoMList*
mono_mlist_alloc (MonoObject *data)
{
MonoError error;
MonoMList *result = mono_mlist_alloc_checked (data, &error);
mono_error_cleanup (&error);
return result;
}
/**
* mono_mlist_alloc_checked:
* @data: object to use as data
* @error: set on error
*
* Allocates a new managed list node with @data as the contents. A
* managed list node also represents a singly-linked list. Managed
* lists are garbage collected, so there is no free routine and the
* user is required to keep references to the managed list to prevent
* it from being garbage collected. On failure returns NULL and sets
* @error.
*/
MonoMList*
mono_mlist_alloc_checked (MonoObject *data, MonoError *error)
{
mono_error_init (error);
MonoMList* res;
if (!monolist_item_vtable) {
MonoClass *klass = mono_class_load_from_name (mono_defaults.corlib, "System", "MonoListItem");
monolist_item_vtable = mono_class_vtable (mono_get_root_domain (), klass);
g_assert (monolist_item_vtable);
}
res = (MonoMList*)mono_object_new_fast_checked (monolist_item_vtable, error);
return_val_if_nok (error, NULL);
MONO_OBJECT_SETREF (res, data, data);
return res;
}
/**
* mono_mlist_get_data:
* @list: the managed list node
*
* Get the object stored in the list node @list.
*/
MonoObject*
mono_mlist_get_data (MonoMList* list)
{
return list->data;
}
/**
* mono_mlist_set_data:
* @list: the managed list node
*
* Set the object content in the list node @list.
*/
void
mono_mlist_set_data (MonoMList* list, MonoObject *data)
{
MONO_OBJECT_SETREF (list, data, data);
}
/**
* mono_mlist_set_next:
* @list: a managed list node
* @next: list node that will be next for the @list node.
*
* Set next node for @list to @next.
*/
MonoMList *
mono_mlist_set_next (MonoMList* list, MonoMList *next)
{
if (!list)
return next;
MONO_OBJECT_SETREF (list, next, next);
return list;
}
/**
* mono_mlist_length:
* @list: the managed list
*
* Get the number of items in the list @list.
* Since managed lists are singly-linked, this operation takes O(n) time.
*/
int
mono_mlist_length (MonoMList* list)
{
int len = 0;
while (list) {
list = list->next;
++len;
}
return len;
}
/**
* mono_mlist_next:
* @list: the managed list node
*
* Returns the next managed list node starting from @list.
*/
MonoMList*
mono_mlist_next (MonoMList* list)
{
return list->next;
}
/**
* mono_mlist_last:
* @list: the managed list node
*
* Returns the last managed list node in list @list.
* Since managed lists are singly-linked, this operation takes O(n) time.
*/
MonoMList*
mono_mlist_last (MonoMList* list)
{
if (list) {
while (list->next)
list = list->next;
return list;
}
return NULL;
}
/**
* mono_mlist_prepend:
* @list: the managed list
* @data: the object to add to the list
*
* Allocate a new list node with @data as content and prepend it
* to the list @list. @list can be NULL.
*/
MonoMList*
mono_mlist_prepend (MonoMList* list, MonoObject *data)
{
MonoError error;
MonoMList *result = mono_mlist_prepend_checked (list, data, &error);
mono_error_cleanup (&error);
return result;
}
/**
* mono_mlist_prepend_checked:
* @list: the managed list
* @data: the object to add to the list
* @error: set on error
*
* Allocate a new list node with @data as content and prepend it to
* the list @list. @list can be NULL. On failure returns NULL and sets
* @error.
*/
MonoMList*
mono_mlist_prepend_checked (MonoMList* list, MonoObject *data, MonoError *error)
{
mono_error_init (error);
MonoMList* res = mono_mlist_alloc_checked (data, error);
return_val_if_nok (error, NULL);
if (list)
MONO_OBJECT_SETREF (res, next, list);
return res;
}
/**
* mono_mlist_append:
* @list: the managed list
* @data: the object to add to the list
*
* Allocate a new list node with @data as content and append it
* to the list @list. @list can be NULL.
* Since managed lists are singly-linked, this operation takes O(n) time.
*/
MonoMList*
mono_mlist_append (MonoMList* list, MonoObject *data)
{
MonoError error;
MonoMList *result = mono_mlist_append_checked (list, data, &error);
mono_error_cleanup (&error);
return result;
}
/**
* mono_mlist_append_checked:
* @list: the managed list
* @data: the object to add to the list
* @error: set on error
*
* Allocate a new list node with @data as content and append it
* to the list @list. @list can be NULL.
* Since managed lists are singly-linked, this operation takes O(n) time.
* On failure returns NULL and sets @error.
*/
MonoMList*
mono_mlist_append_checked (MonoMList* list, MonoObject *data, MonoError *error)
{
mono_error_init (error);
MonoMList* res = mono_mlist_alloc_checked (data, error);
return_val_if_nok (error, NULL);
if (list) {
MonoMList* last = mono_mlist_last (list);
MONO_OBJECT_SETREF (last, next, res);
return list;
} else {
return res;
}
}
static MonoMList*
find_prev (MonoMList* list, MonoMList *item)
{
MonoMList* prev = NULL;
while (list) {
if (list == item)
break;
prev = list;
list = list->next;
}
return prev;
}
/**
* mono_mlist_remove_item:
* @list: the managed list
* @data: the object to remove from the list
*
* Remove the list node @item from the managed list @list.
* Since managed lists are singly-linked, this operation can take O(n) time.
*/
MonoMList*
mono_mlist_remove_item (MonoMList* list, MonoMList *item)
{
MonoMList* prev;
if (list == item) {
list = item->next;
item->next = NULL;
return list;
}
prev = find_prev (list, item);
if (prev) {
MONO_OBJECT_SETREF (prev, next, item->next);
item->next = NULL;
return list;
} else {
/* not found */
return list;
}
}