MaplePointerType - query the type of a MaplePointer in external code
MaplePointerSetType - set the type of a MaplePointer in external code
MaplePointerSetMarkFunction - associate a mark function with a MaplePointer in external code
MaplePointerSetDisposeFunction - associate a dispose function with a MaplePointer in external code
MaplePointerSetPrintFunction - associate a display function with a MaplePointer in external code
|
Calling Sequence
|
|
MaplePointerType(kv, p)
MaplePointerSetType(kv, p, type)
MaplePointerSetMarkFunction(kv, p, f)
MaplePointerSetDisposeFunction(kv, p, f)
MaplePointerSetPrintFunction(kv, p, f)
|
|
Parameters
|
|
kv
|
-
|
kernel handle of type MKernelVector
|
p
|
-
|
MaplePointer object
|
type
|
-
|
machine word sized integer type designator
|
f
|
-
|
hardware callback function
|
|
|
|
|
Description
|
|
•
|
A MaplePointer is a Maple object with embedded data and methods associated with it. It allows arbitrary external data to be represented as a new Maple object. Other Maple objects can contain MaplePointers. Some operators can be overloaded using a module, so use of standard operator notation with these external objects is possible.
|
•
|
The type given when creating a MaplePointer with ToMaplePointer can be updated with MaplePointerSetType and queried with MaplePointerType. This identifier can be used to distinguish between MaplePointers representing different data structures. To generate a unique type identifier, use the address of an external function.
|
•
|
If a MaplePointer's data contains references to other Maple objects, it is important to set up a mark callback using MaplePointerSetMarkFunction. Maple reuses memory containing objects that are not referred to by any active data structure. Since Maple cannot traverse external data structures, it relies on user supplied mark functions to mark Maple objects as active. The supplied mark function is called during every sweep of the Maple garbage collector. The callback must then call MapleGcMark(obj) for every object, obj, contained in the external data structure.
|
•
|
A finalizer callback can be setup using MaplePointerSetDisposeFunction. The supplied callback is called when the MaplePointer object is about to be disposed of by the Maple garbage collector, on exit, or when restarting. This callback can be used for various tasks, such as freeing externally allocated memory and closing open file handles.
|
•
|
The MaplePointerSetPrintFunction is called whenever the MaplePointer object is about to be displayed. The provided callback can return any valid printable Maple object that Maple can render. The print callback is not responsible for displaying the MaplePointer, just converting it to a non-external Maple object.
|
•
|
It is critical that MaplePointer callbacks never raise errors, or otherwise change the execution path of code. In addition, the mark and dispose callbacks must never create any new Maple objects. Failure to obey these rules may result in unpredictable behavior of the active Maple session.
|
|
|
Examples
|
|
#include <stdlib.h>
|
#include "maplec.h"
|
typedef struct _listelem {
|
ALGEB val;
|
struct _listelem *next;
|
} ListElem;
|
static MKernelVector KV;
|
static void M_DECL MarkLinkedList( ALGEB p )
|
{
|
ListElem **list, *elem;
|
list = (ListElem**)MapleToPointer(KV,p);
|
elem = *list;
|
while( elem ) {
|
MapleGcMark(KV,elem->val);
|
elem = elem->next;
|
}
|
}
|
static void M_DECL DisposeLinkedList( ALGEB p )
|
{
|
ListElem **list, *elem, *cur;
|
list = (ListElem**)MapleToPointer(KV,p);
|
elem = *list;
|
while( elem ) {
|
cur = elem;
|
elem = elem->next;
|
free(cur);
|
}
|
}
|
static ALGEB M_DECL ConvertLinkedList( ALGEB p )
|
{
|
ListElem **list, *elem, *last;
|
list = (ListElem**)MapleToPointer(KV,p);
|
elem = *list;
|
if( !elem )
|
return( ToMapleNULL(KV) );
|
if( !elem->next )
|
return( elem->val );
|
if( !elem->next->next )
|
return( ToMapleFunction(KV,ToMapleName(KV,".",TRUE),2,elem->val,
|
elem->next->val) );
|
if( !elem->next->next->next )
|
return( ToMapleFunction(KV,ToMapleName(KV,".",TRUE),3,elem->val,
|
elem->next->val,elem->next->next->val) );
|
for( last=elem; last->next != NULL; last=last->next )
|
;
|
return( ToMapleFunction(KV,ToMapleName(KV,".",TRUE),4,elem->val,
|
elem->next->val,ToMapleName(KV,"...",TRUE),last->val) );
|
}
|
ALGEB M_DECL MyLinkedList( MKernelVector kv, ALGEB *args )
|
{
|
ListElem *elem, **list;
|
ALGEB val;
|
M_INT argc;
|
char *code;
|
argc = MapleNumArgs(kv,(ALGEB)args);
|
if( argc < 1 ) {
|
MapleRaiseError(kv,"at least one argument expected");
|
return( NULL );
|
}
|
if( !IsMapleString(kv,args[1]) ) {
|
MapleRaiseError(kv,"string expected");
|
return( NULL );
|
}
|
code = MapleToString(kv,args[1]);
|
if( strcmp(code,"create") == 0 ) {
|
KV = kv;
|
list = (ListElem**)malloc(sizeof(ListElem*));
|
*list = NULL;
|
val = ToMaplePointer(kv,(void*)list,(M_INT)&MarkLinkedList);
|
MaplePointerSetMarkFunction(kv,val,MarkLinkedList);
|
MaplePointerSetDisposeFunction(kv,val,DisposeLinkedList);
|
MaplePointerSetPrintFunction(kv,val,ConvertLinkedList);
|
return( val );
|
}
|
if( argc < 2 ) {
|
MapleRaiseError(kv,
|
"at least 3 arguments expected for this operation");
|
return( NULL );
|
}
|
if( !IsMaplePointer(kv,args[2])
|
|| MaplePointerType(kv,args[2]) != (M_INT)&MarkLinkedList ) {
|
MapleRaiseError(kv,"linked list expected");
|
return( NULL );
|
}
|
list = (ListElem**)MapleToPointer(kv,args[2]);
|
if( strcmp(code,"insert_head") == 0 ) {
|
if( argc != 3 ) {
|
MapleRaiseError(kv,"3 arguments expected for insert");
|
return( NULL );
|
}
|
elem = (ListElem*)malloc(sizeof(ListElem));
|
elem->next = *list;
|
elem->val = args[3];
|
*list = elem;
|
return( ToMapleBoolean(kv,TRUE) );
|
}
|
else if( strcmp(code,"remove_head") == 0 ) {
|
elem = *list;
|
if( !elem ) {
|
MapleRaiseError(kv,"linked list is empty");
|
return( NULL );
|
}
|
*list = elem->next;
|
val = elem->val;
|
free(elem);
|
return( val );
|
}
|
else if( strcmp(code,"map") == 0 ) {
|
if( argc != 3 ) {
|
MapleRaiseError(kv,"3 arguments expected for map");
|
return( NULL );
|
}
|
elem = *list;
|
while( elem ) {
|
elem->val = EvalMapleProc(kv,args[3],1,elem->val);
|
elem = elem->next;
|
}
|
return( args[2] );
|
}
|
else {
|
MapleRaiseError1(kv,"unrecognized option %1",args[1]);
|
return( NULL );
|
}
|
}
|
|
|
Execute the external function from Maple.
>
|
|
>
|
|
>
|
|
>
|
|
| (1) |
>
|
|
>
|
|
>
|
|
>
|
|
>
|
|
>
|
|
| (2) |
>
|
|
| (3) |
>
|
|
| (4) |
>
|
|
| (5) |
>
|
|
| (6) |
|
|