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":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.