Datastorage unique and ordered



  • I am looking for a storage type which would allow me to hold a sequence of values, but would avoid duplicate values.
    I was originally looking at BaseArray but when appending a new value I would like to avoid iterating over all entries to find out if this new value is already present.
    An HashMap doesn't preserve the order of items being inserted (as far as I know).
    As such I was more thinking about a custom class containing:

    • a BaseArray to hold the values in the order they are appended.
    • an HashMap to hold the values (as key) in order to perform an easy Find, knowing if the value should be appended or not.

    But having the values stored twice this would mean this custom class takes up twice the memory.
    Since I intend to share implementation between R20 and pre-R20 I cannot rely on the new maxon::Data or maxon::DataDictionnary.

    Anyone having a better idea than the BaseArray-HashMap combination?
    The storage type should be able to handle any type of data, from Int32, Float, Strings, custom class instances, ...

    Example with Int32:
    input = 0, 1, 2, 0, 3, 1, 5, 4
    The data storage should hold:
    0, 1, 2, 3, 5, 4



  • hello,

    looks like you need a HashSet

    I first thought you wanted a sorted array with unique value.

    I would than go with a sorted array and Unique witch give you a iterator that you can use in the Erase Function of the Sorted Array

    Cheers
    Manuel



  • @m_magalhaes
    Hi,
    HashSet seems indeed what I need. From the name I assumed its functionality was similar to std::set which is not what I wanted. But I have tested out HashSet in R20 and it does provide the result I was looking for.
    Unfortunately, I could not get to compile the test in R19.
    The Insert() function in R20 was to be replaced by an Add(), no problems there.
    But iterating (using iterator or range based loop) does not compile, as it seems the iterators are derived privately from the base class HashMap

    error C2247: 'maxon::HashMap<V,maxon::EmptyClass,HASH,maxon::HashMapKeyValuePair,ALLOCATOR>::begin' not accessible because 'maxon::HashSet<Int32,maxon::DefaultHash,maxon::DefaultAllocator>' uses 'private' to inherit from 'maxon::HashMap<V,maxon::EmptyClass,HASH,maxon::HashMapKeyValuePair,ALLOCATOR>'
    ```.


  • hello,
    on R19 you can use this code to iterate through your array. (or did i missed something here)
    The rangeLoop is not possible yea.

    	for (auto it = myarray.Begin(); it != myarray.End(); it++)
    	{
    		GePrint("value is " + String::IntToString(*it));
    	}
    
    

    Cheers
    Manuel



  • @m_magalhaes
    Thanks for reminding me of the "auto" ...

    Yesterday I had tried using the iterator, but got compiler error, then I tried the range-based loop, again hitting a compiler error.

    I don't quite get the difference between following two implementations

    	maxon::HashSet<Int32>::Iterator it;
    	for (it = hashset.Begin(); it != hashset.End(); ++it)
    		GePrint("HashSet value " + String::IntToString(*it));
    
    	for (auto it = hashset.Begin(); it != hashset.End(); ++it)
    		GePrint("HashSet value " + String::IntToString(*it));
    

    The first implementation (which I tried using ... not thinking about using "auto") gives me following errors:

    error C2512: 'maxon::HashSet<Int32,maxon::DefaultHash,maxon::DefaultAllocator>::Iterator': no appropriate default constructor available
    
    error C2248: 'maxon::HashSet<Int32,maxon::DefaultHash,maxon::DefaultAllocator>::Iterator::operator =': cannot access private member declared in class 'maxon::HashSet<Int32,maxon::DefaultHash,maxon::DefaultAllocator>::Iterator'
    

    I am confused that using "auto" does work.
    Especially that when hovering over "auto" in Visual Studio does show a popup, containing "class maxon::HashSet<Int32>::Iterator" ... exactly what the first implementation does.



  • hello,

    no appropriate default constructor available

    The difference is the iterator initialization.

    // same as 
    // maxon::HashSet<maxon::Int32>::Iterator it(myarray.Begin());
    maxon::HashSet<maxon::Int32>::Iterator it = myarray.Begin();
    
    	for (it; it != myarray.End(); it++)
    	{
    		GePrint("without auto value is " + String::IntToString(*it));
    	}
    

    or prefered (and that's what the auto is doing)

    	for (maxon::HashSet<maxon::Int32>::Iterator it = myarray.Begin(); it != myarray.End(); it++)
    	{
    		GePrint("without auto value is " + String::IntToString(*it));
    	}
    

    I will ask the other what they think about it but it's more a c++/ compiler question than a SDK question.

    Cheers
    Manuel



  • @m_magalhaes
    I agree that the last few replies to this thread are C++ and not SDK related.
    The main topic lead to the HashSet, and for completeness of future reference I thought to mention the compiling issues.
    I didn't know about the difference being the iterator initialization. To me it all looked the same.

    Just for completeness, I never really realized the following two implementations had a complete different internal behaviour:

    	// does compile
    	maxon::HashSet<Int32>::Iterator it = hashset.Begin();
    
    	// does not compile
    	maxon::HashSet<Int32>::Iterator it;
    	it = hashset.Begin();
    
    

    I will set the topic as solved, since HashSet is the way to go, and I learned something new about iterator initialization in the process.



  • hello,

    It's not related to Iterator.
    This simple example also complain about the default constructor.

    #include <iostream>
    
    class MYINT
    {
    public:
    	MYINT(int inInt) {	_myint = inInt; };
    private:
    	int _myint;
    };
    
    int main()
    {
    	MYINT myint;
    
    	system("pause");
    	return 0;
    }
    

    It should say 'hey i don't have any constructor with no parameters".

    But if you give him something to initialize with it understand.

    MYINT myint = MYINT(10);
    MYINT myOtherInt = 10;
    MYINT myThirdInt(10);
    

    all this will end with _myint = 10;

    Cheers
    Manuel