Beefy Boxes and Bandwidth Generously Provided by pair Networks
The stupid question is the question not asked
 
PerlMonks  

comment on

( [id://3333]=superdoc: print w/replies, xml ) Need Help??

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); }

In reply to Re: Arbitrarily Nested Loops by ikegami
in thread Arbitrarily Nested Loops by Limbic~Region

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post; it's "PerlMonks-approved HTML":



  • Are you posting in the right place? Check out Where do I post X? to know for sure.
  • Posts may use any of the Perl Monks Approved HTML tags. Currently these include the following:
    <code> <a> <b> <big> <blockquote> <br /> <dd> <dl> <dt> <em> <font> <h1> <h2> <h3> <h4> <h5> <h6> <hr /> <i> <li> <nbsp> <ol> <p> <small> <strike> <strong> <sub> <sup> <table> <td> <th> <tr> <tt> <u> <ul>
  • Snippets of code should be wrapped in <code> tags not <pre> tags. In fact, <pre> tags should generally be avoided. If they must be used, extreme care should be taken to ensure that their contents do not have long lines (<70 chars), in order to prevent horizontal scrolling (and possible janitor intervention).
  • Want more info? How to link or How to display code and escape characters are good places to start.
Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others surveying the Monastery: (5)
As of 2024-04-25 10:44 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found