Compare only parts of two BaseContainers()



  • Hello,

    there is a lot of stuff in my plugin object's BaseContainer, e.g. the object's name, and other irrelevant stuff. Since the object is quite complex and takes a while to calculate, I want it to rebuild only when relevant attributes have changed.

    Is there a smart way already, to detect changes to certain values in a BaseContainer?

    If not, I'd probably end up writing a Compare() function for two BaseContainers that accepts a BaseArray of value IDs, and compare the values of each of those IDs from the two containers.
    Is there a way to get a list of all IDs defined in my object's resource header?

    I found COPYFLAGS::PRIVATE_CONTAINER_COPY_DIRTY and COPYFLAGS::PRIVATE_CONTAINER_COPY_IDENTICAL which sound promising, but they're marked as private and not explained in the SDK docs.

    Thanks for advice!

    Cheers,
    Frank



  • Hi,

    I am not quite sure if I do understand you correctly. With "rebuilding the object" you are referring to rebuilding the cache of some BaseObject, right? And you want to know when "the important parameters" of the node have changed so that you can then rebuild the node on the next cache request?

    Have you considered using NodeData::SetDParameter? You could probably also listen to the messages sent to the node and react to them.

    Cheers,
    zipit



  • Not sure if this might help or add to the confusion, but in the past I was surprised about this.

    I had always assumed a BaseContainer to be similar to what a Python dict represents.
    However, the behaviour encountered in above link indicates that next to the key-value, also the sequence of storing the key-values does pay importance in a BaseContainer ... something -if present in the documentation- I always seemed to have overlooked, or missed.

    So, doing a compare between two BaseContainers, while containing identical key-value seem to not being equal if those key-value are stored in a different sequence.
    Hence "comparing only parts of two BaseContainers" might result in some unexpected behaviours.



  • Yeah, I read that thread, too :D And in deed, the BaseContainer is a sequential storage. That's why it has the FindIndex(), GetIndexId()and GetIndexData() members.

    And yes, with "rebuilding the object" I meant to rebuild my object's generator cache.

    I have tried the following solution now, and found that it's fast enough to not impact performance.

    Bool EqualContainerValues(const BaseContainer &a, const BaseContainer &b, const maxon::BaseArray<Int32> &ids)
    {
    	if (ids.GetCount() == 0)
    		return true;
    
    	for (maxon::BaseArray<Int32>::ConstIterator it = ids.Begin(); it != ids.End(); ++it)
    	{
    		const Int32 valueId = *it;
    		if (a.GetData(valueId) != b.GetData(valueId))
    			return false;
    	}
    
    	return true;
    }
    

    I simply memorise a copy of my object's BaseContainer, and when GetVirtualObjects() is called next time, I pass the current BaseContainer and the memorised copy of the previous BaseContainer to the above shown function, along with a BaseArray of IDs. It does the trick, and I'll use this until I stumble upon a better solution.

    Cheers,
    Frank



  • hi,

    I would probably go with SetDParameter and if i see any parameter i'm tracking, i set the object dirty.
    But as long as it's working and performance are good enough..

    PRIVATE_CONTAINER_COPY_DIRTY copy also the dirty sum stored on the object.
    PRIVATE_CONTAINER_COPY_IDENTICAL is harder to decrypt. Seems that copy is going to be faster than the other.
    Both are used together in our code in the Mograph module (why i'm not surprised ?)

    About your code, you can use IsEmpty and a range-based loop. (a bit easier to read)

    Bool EqualContainerValues(const BaseContainer& a, const BaseContainer& b, const maxon::BaseArray<Int32>& ids)
    {
    	if (ids.IsEmpty())
    		return true;
    
    	for (const Int32 & valueId : ids)
    	{
    		if (a.GetData(valueId) != b.GetData(valueId))
    			return false;
    	}
    
    	return true;
    }
    


  • Nice, Manuel, thank you!

    I guess, I'll try the SetDParameter() approach, too, in good time.

    Cheers,
    Frank