Beefy Boxes and Bandwidth Generously Provided by pair Networks
Just another Perl shrine
 
PerlMonks  

Re: Arbitrarily Nested Loops

by ikegami (Patriarch)
on Feb 03, 2006 at 16:44 UTC ( [id://527721]=note: print w/replies, xml ) Need Help??


in reply to Arbitrarily Nested Loops

Update: Forget this node. Go see Re: Arbitrarily Nested Loops.

(Moving here what I had on my pad for you.)


I wrote this to get the problem clearly in my head. It doesn't really solve anything, since your problem is "...work with element_ptr...". There's also the issue of whether individual elements should be freed. Perl solved both of these problems by using SVs. Your requirement that your lists can contains more than one kind of data complicates things greatly. It would be much simpler if you could deal with a single type at a time (even if the type was different in different calls to NestedLoops). See "Take 2", below, where I came up with something along the lines of a simple SV.

struct NestedLoopList { int elem_size; int length; void* ptr; int free_ptr; /* 0 = no, 1 = yes */ }; struct NestedLoopArrayArg { int elem_size; int length; void* ptr; }; struct NestedLoopFuncArg void (*ptr)(struct NestedLoopList* list_ptr, void* pad); void* pad; }; struct NestedLoopArg { int ptr_type; /* 0 = array, 1 = func */ union { struct NestedLoopArrayArg array; struct NestedLoopFuncArg func; } ptr; };

Calling the function

struct NestedLoopArg* args = (NestedLoopArg*)calloc(2, sizeof(NestedLo +opArg)); args[0].ptr_type = 0; /* array */ args[0].ptr.array.elem_size = sizeof(int); args[0].ptr.array.length = 5; args[0].ptr.array.ptr = calloc(arg[0].array.length, arg[0].array +.elem_size); args[1].ptr_type = 1; /* func */ args[1].ptr.func.ptr = my_func; struct MyFuncPad arg1_pad; arg1_pad.count = 5; args[1].ptr.func.pad = &arg1_pad; NestedLoops(args); ... free memory allocated for args ...

Getting the list

struct NestedLoopList list; if ((*arg_ptr).ptr_type == 0) { /* array */ struct NestedLoopArrayArg* array_ptr = (*arg_ptr).ptr; list.elem_size = (*array_ptr).elem_size; list.length = (*array_ptr).length; list.ptr = (*array_ptr).ptr; list.free_ptr = 0; } else { /* function */ struct NestedLoopFuncArg* func_ptr = (*arg_ptr).ptr; (*(*func_ptr).ptr)(&list, (*func_ptr).pad); }

Example function pointer argument

struct MyFuncPad { int count; }; /* Creates a list of ints, numbered 1 to the int located at *pad. */ void my_func(struct NestedLoopList* list_ptr, void* pad) { int count = (*(MyFuncPad*)pad).count; int* array = (int*)calloc(count, sizeof(int)); int i; for (i=0; i<count; i++) { array[i] = i+1; } (*list_ptr).elem_size = sizeof(int); (*list_ptr).length = count; (*list_ptr).ptr = array; (*list_ptr).free_ptr = 1; }

Going over the list

/* Convert the pointer to an int since ++ and other */ /* arithmentic operators are overloaded for pointers */ int p = (int)list.ptr; for (i=0; i<list.length; i++) { void* elem_ptr = (void*)p; p += list.elem_size; ...work with elem_ptr... }

Take 2.

Much better. ElementType probably should not contain handler, and handler needs more arguments, but you get the idea.

struct ElementType { int size; void (*handler )(void* ptr); void (*destructor)(void* ptr); }; struct Element { struct ElementType* type_ptr void* ptr; }; struct NestedLoopList { int length; Element* ptr; int free_ptr; /* 1 when ptr needs to be freed. */ int free_elems; /* 1 when each element of ptr[] needs to be f +reed and destroyed. */ }; struct NestedLoopArrayArg { struct ElementType* type_ptr; int length; void* ptr; }; struct NestedLoopMixedArg { int length; struct Element* ptr; }; struct NestedLoopFuncArg { void (*ptr)(struct NestedLoopList* list_ptr, void* pad); void* pad; }; struct NestedLoopArg { int ptr_type; /* 0 = array, 1 = mixed array, 2 = func */ union { struct NestedLoopArrayArg array; struct NestedLoopMixedArg mixed; struct NestedLoopFuncArg func; } ptr; };

Calling the function

struct NestedLoopArg* arg = (NestedLoopArg*)calloc(2, sizeof(NestedLoo +pArg)); args[0].ptr_type = 0; /* array */ args[0].ptr.array.type_ptr = &IntType; args[0].ptr.array.length = 5; args[0].ptr.array.ptr = calloc(arg[0].array.length, arg[0].array. +elem_size); args[1].ptr_type = 1; /* mixed array */ args[1].ptr.mixed.length = 4; args[1].ptr.mixed.ptr = (Element*)calloc(arg[0].array.length, siz +eof(struct Element)); { ... populate args[1].mixed.ptr[] ... } args[2].ptr_type = 2; /* func */ args[2].ptr.func.ptr = my_func; struct MyFuncPad arg2_pad; arg2_pad.count = 5; args[2].ptr.func.pad = &arg2_pad; NestedLoops(args); ... free memory allocated for args ...

Getting a list

struct NestedLoopList list; switch ((*arg_ptr).ptr_type) { case 0: /* array */ { struct NestedLoopArrayArg* array_ptr = (*arg_ptr).ptr; int length; struct ElementType* type_ptr int elem_size; void* data_arr; struct Element* elem_arr; int src; Element* dst; int i; length = (*array_ptr).length; type_ptr = (*array_ptr).type_ptr; elem_size = type_ptr.size; data_arr = (*array_ptr).ptr; elem_arr = (struct Element*)calloc(length, sizeof(struct Element +)); /* Convert the pointer to an int since ++ and other */ /* arithmentic operators are overloaded for pointers */ src = (int)data_arr; dst = elem_arr; for (i=length; i--; ) { (*dst).type_ptr = type_ptr; (*dst).ptr = (void*)src; src += elem_size; dst++; } list.length = length; list.ptr = elem_arr; list.free_ptr = 1; list.free_elems = 0; break; } case 1: /* mixed array */ { struct NestedLoopMixedArg* mixed_ptr = (*arg_ptr).ptr; list.length = (*mixed_ptr).length list.ptr = (*mixed_ptr).ptr; list.free_ptr = 0; list.free_elems = 0; break; } case 2: /* func */ { struct NestedLoopFuncArg* func = (*arg_ptr).ptr; (*(*func_ptr).ptr)(&list, (*func_ptr).pad); break; } }

Example function pointer argument

struct MyFuncPad { int count; }; /* Creates a list of ints, numbered 1 to the int located at *pad. */ void my_func(struct NestedLoopList* list_ptr, void* pad) { int count; struct Element* elem_arr; Element* dst; int i; count = (*(MyFuncPad*)pad).count; elem_arr = (struct Element*)calloc(count, sizeof(struct Element)); dst = elem_arr; for (i=0; i<count; i++) { int* elem_ptr = (int*)malloc(sizeof(int)) (*elem_arr).type_ptr = &IntType; (*elem_arr).ptr = elem_ptr; elem_arr++; } (*list_ptr).length = count; (*list_ptr).ptr = elem_arr; (*list_ptr).free_ptr = 1; (*list_ptr).free_elems = 1; }

Going over the list (and freeing it as we go along)

Element* elem_ptr = list.ptr; for (i=0; i<list.length; i++) { (*(*(*elem_ptr).type_ptr).handler)(elem_ptr.ptr); if (list.free_elems) { free(elem_ptr.ptr); elem_ptr.ptr = NULL; } elem_ptr++; } if (list.free_ptr) { free(list.ptr); list.ptr = NULL; }

Freeing memory

if (list.free_elems) { int i; Element* elem_ptr = list.ptr; for (i=list.length; i--; ) { (*(*(*elem_ptr).type_ptr).destructor)(elem_ptr.ptr); free(elem_ptr.ptr); elem_ptr++; } } if (list.free_ptr) { free(list.ptr); }

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://527721]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others rifling through the Monastery: (4)
As of 2024-04-26 00:17 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found