Forums > Dev

[dictobj] expose to pattr

January 31, 2014 | 5:20 am

Hi !

t_dictionary *d = NULL ;
 t_symbol *name = symbol_unique();
 d = dictionary_new();
 dictobj_register( d, &name );

how can i expose registered dictionary to the pattr ? cant find any clue .
perhaps im not understanding dependency .
do my object as a server which owns this dictionary should have special attribute setup ?
edit : considering that it is not a single value , but dictionary content


January 31, 2014 | 9:07 am

if then i would use pattr/get-set
is it appropriate way of de/serializing dictionary within set/getvalueof ?

t_max_err foo_setvalueof(t_foo *x, long argc, t_atom *argv)
{
    if (argc && argv) {
    	dictobj_dictionaryfromatoms(&x->dict,argc,argv);
    }
    return MAX_ERR_NONE;
}

t_max_err foo_getvalueof(t_foo *x, long *argc, t_atom **argv)
{
    char alloc;

    if (argc && argv && !(atom_alloc(argc, argv, &alloc))) {
    	dictobj_dictionarytoatoms(x->dict,argc,argv);
        return MAX_ERR_NONE;
    }
    return MAX_ERR_GENERIC;
}

is there something i should be aware of ?


February 1, 2014 | 1:55 am

im "asking" as i cant deduct everything on my own , using plain SDK .

"dict" connected to "pattr" doesnt show its content (in pattrstorage view) . it stands for "dictionary" .
so im assuming that there may be another way of storing custom dictionary within external that could be suited for dictionaries directly .
As if i use method above ,content of a dictionary is shown in "pattrstorage" view . every key , every value .

has someone experiences ? is it something that i should or not worry about ?


February 1, 2014 | 8:01 am

Hi there,

your approach makes sense to me, however the two setvalueof and getvalueof methods that you have written above are leaking major memory. It might not be a visible problem right now, but it will bite you in the ass in the long run. So you need to fix that. Let me explain…

The function dictobj_dictionaryfromatoms() returns a newly created dictionary. So you can’t just pass your dictionary over and over without managing memory. You need to do something like:

t_max_err foo_setvalueof(t_foo *x, long argc, t_atom *argv)
{
    if (argc && argv) {
        t_dictionary *dict = NULL;
    	dictobj_dictionaryfromatoms(&dict,argc,argv);
        if (x->dict) {
            object_free(x->dict);
        }
        x->dict = dict;
    }
    return MAX_ERR_NONE;
}

Same reasoning goes for the getvalueof method, which allocates an array of atoms.
Makes sense?

BTW, I have experience with dictionaries and there’s a lot to figure out on your own.
If you have specific questions I can try to answer them for you.

Cheers

- Luigi


February 1, 2014 | 8:43 am

Hello Luigi !
thank you for your time and pointers .

so what is actually happening in memory while new dict is returned , its stacked and memory is shifted for the pointer ?
as i im passing old pointer then should not it overwrite/overload my pointer ? its not that simple as i see

also does freeing can significantly impact cpu cycles per operation ?

im wondering because i had suspicion about it when ive been "collecting/packing" atoms over their pointer . and when it comes to operations with dictionaries it may slow down my application . im relying on this type of data structure really much .

k


February 1, 2014 | 11:03 am

Hi,

well, the function dictobj_dictionaryfromatoms() is expecting a t_dictionary pointer set to NULL. At this point the function will allocate the memory for a t_dictionary struct, fill it with the appropriate data and assign its memory address to your t_dictionary pointer. So if your pointer was already pointing to some memory, you need to free that memory or it will be just left unclaimed. The pointer will point to the newly allocated memory and you have just lost the address of your previous memory. That’s how a memory leak is created. So there is no overwriting or overloading happening (whatever that may mean…)

I don’t believe that freeing is going to affect performance significantly in this case.
So no worries for your application… It will not be slowed down.

If you haven’t already done so, please check out the ext_dictionary.h and ext_dictobj.h files. A lot of useful information is in there.

Here is the final version of the code I would use for those functions:

t_max_err foo_setvalueof(t_foo *x, long argc, t_atom *argv)
{
    if (argc && argv) {
        t_dictionary *dict = NULL;
        dictobj_dictionaryfromatoms(&dict, argc, argv);
        if (dict) {
            if (x->dictionary) {
                object_free(x->dictionary);
            }
            x->dictionary = dict;
        }
    }
    return MAX_ERR_NONE;
}

and

t_max_err foo_getvalueof(t_foo *x, long *argc, t_atom **argv)
{
    if (argc && argv) {
        return dictobj_dictionarytoatoms(x->dictionary, argc, argv);
    }
    return MAX_ERR_NONE;
}

Hope it helps…

- Luigi

P.S.
sorry for the code formatting, but the code tag really does a poor job…
How do you format yours to show up so nicely?


February 1, 2014 | 11:57 am

yes , thank you ! . it clarifies a bit .

but the pointers itself dont need to be freed or zeroed out at that point ?
when pointer is cashed in main struct doesnt need to be zeroed out before assigning to new memory allocated for our new dictionary ? we are rereferencing here right ?
im just trying to understand nature of C by "doing" , so im sorry for my trivial questions . memory maintaining is still quite magic for me .

CODE FORMATTING you can achieve by "pre" tag instead of "code" its rarely useful these days and the forum also breaks sometimes when someone tries to paste copy-compressed patches

EDIT : a little confusion , you are not allocating memory for received atoms inside "getvalueof" function ? i will never get it im affraid :D


February 1, 2014 | 12:22 pm

Ok, keep in mind that these functions are meant to only allocate memory (mainly for the atoms). The same memory will be freed in other functions that will be called under the hood.
I don’t work for C74 so I don’t have access to the code of those specific function, however your concern of freeing memory is right. There is memory that needs to be freed. But you are not responsible for it this time.

Inside the getvalueof() function we don’t need to allocate memory for the atoms with atom_alloc(). Those atoms will be already allocated for us inside dictobj_dictionarytoatoms().

- Luigi


February 1, 2014 | 12:47 pm

wonderful !
one last thing , if my dict is registered inside its server external ,and the other externals that are clients are referencing my dictionary by "retain" function should not they share dict data ? :D because they are not (they even do not notify dictionary that something has changed),
it seems like they relate to another instance of "it" even if it has the same dict registration name. wow , the x-files .
has it something to do with freeing dict inside "getvalueof" at launch ?.

EDIT . should i release and register again ?


February 1, 2014 | 1:11 pm

No, it does not have anything to do with freeing dict inside "getvalueof" at launch.
Yes, they should share their data and be notified when the data has changed.
In order to trigger notifications, after you have changed the data in your dictionary you need to do something like:

void foo_setdictionary(t_foo *x, t_symbol *name)
{
    t_dictionary *dict;

    dict = dictobj_findregistered_retain(name);

    // ...
    // here you change the data contained in dict
    // ...

    // notify all clients that the data has changed
    object_notify(dict, gensym("modified"), NULL);

    // you no longer need a reference to the dictionary
    dictobj_release(dict);
}

This way all client objects will be notified that the data has changed.
You owe me a beer :)

- Luigi


February 1, 2014 | 1:39 pm

definitely :)

its not working yet , but i will investigate . some strange things are here .

by the way . as a client do i need to reference , and release dict on every operation ? cant cache it as client will anyway rely on its (dict) instance and maybe others ? :)
3 beers


February 2, 2014 | 3:09 am

Yes, you need to reference and release the dictionary on every operation. You can’t cache it. The short explanation is that other clients might be reading/writing to the same dictionary at the same time as you. So, there need to be a way to keep:
1) a count of how many clients have acquired a pointer to the same dictionary.
2) the operations on that dictionary serialized, so that only one client can read/write at a time.

I believe retain/release functions (among other things) provide this functionality for you.

I just want to keep in mind that these are educated guesses based on my knowledge and experience. Remember than I don’t have access to the code of those API functions.
A C74 engineer will be able to answer your questions much more accurately than I can.

- Luigi


February 2, 2014 | 3:28 am

thanks again for your time Luigi ! its valuable . i really appreciate it even if you are not sure . it leads to some deductions that may build up my intuition and awareness of API habbbits .

anyway
might be that ive been mislead with conception of threadsafe that dictionaries are providing .


Viewing 13 posts - 1 through 13 (of 13 total)