/**
|
* \file
|
* 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 <config.h>
|
#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:
|
* \param data object to use as data
|
* Allocates a new managed list node with \p 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:
|
* \param data object to use as data
|
* \param error set on error
|
* Allocates a new managed list node with \p 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
|
* \p error.
|
*/
|
MonoMList*
|
mono_mlist_alloc_checked (MonoObject *data, MonoError *error)
|
{
|
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_specific_checked (monolist_item_vtable, error);
|
return_val_if_nok (error, NULL);
|
MONO_OBJECT_SETREF (res, data, data);
|
return res;
|
}
|
|
/**
|
* mono_mlist_get_data:
|
* \param list the managed list node
|
* Get the object stored in the list node \p list.
|
*/
|
MonoObject*
|
mono_mlist_get_data (MonoMList* list)
|
{
|
return list->data;
|
}
|
|
/**
|
* mono_mlist_set_data:
|
* \param list the managed list node
|
* Set the object content in the list node \p list.
|
*/
|
void
|
mono_mlist_set_data (MonoMList* list, MonoObject *data)
|
{
|
MONO_OBJECT_SETREF (list, data, data);
|
}
|
|
/**
|
* mono_mlist_set_next:
|
* \param list a managed list node
|
* \param next list node that will be next for the \p list node.
|
* Set next node for \p list to \p 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:
|
* \param list the managed list
|
* Get the number of items in the list \p 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:
|
* \param list the managed list node
|
* Returns the next managed list node starting from \p list.
|
*/
|
MonoMList*
|
mono_mlist_next (MonoMList* list)
|
{
|
return list->next;
|
}
|
|
/**
|
* mono_mlist_last:
|
* \param list the managed list node
|
* Returns the last managed list node in list \p 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:
|
* \param list the managed list
|
* \param data the object to add to the list
|
* Allocate a new list node with \p data as content and prepend it
|
* to the list \p list. \p 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:
|
* \param list the managed list
|
* \param data the object to add to the list
|
* \param error set on error
|
* Allocate a new list node with \p data as content and prepend it to
|
* the list \p list. \p list can be NULL. On failure returns NULL and sets
|
* \p error.
|
*/
|
MonoMList*
|
mono_mlist_prepend_checked (MonoMList* list, MonoObject *data, MonoError *error)
|
{
|
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:
|
* \param list the managed list
|
* \param data the object to add to the list
|
* Allocate a new list node with \p data as content and append it
|
* to the list \p list. \p 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:
|
* \param list the managed list
|
* \param data the object to add to the list
|
* \param error set on error
|
* Allocate a new list node with \p data as content and append it
|
* to the list \p list. \p list can be NULL.
|
* Since managed lists are singly-linked, this operation takes O(n) time.
|
* On failure returns NULL and sets \p error.
|
*/
|
MonoMList*
|
mono_mlist_append_checked (MonoMList* list, MonoObject *data, MonoError *error)
|
{
|
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:
|
* \param list the managed list
|
* \param data the object to remove from the list
|
* Remove the list node \p item from the managed list \p 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;
|
}
|
}
|