Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush Python API
      • ZBrush GoZ API
      • Code Examples on Github
    • Forum
    • Downloads
    • Support
      • Support Procedures
      • Registered Developer Program
      • Plugin IDs
      • Contact Us
    • Categories
      • Overview
      • News & Information
      • Cinema 4D SDK Support
      • Cineware SDK Support
      • ZBrush 4D SDK Support
      • Bugs
      • General Talk
    • Unread
    • Recent
    • Tags
    • Users
    • Login

    Datastorage unique and ordered

    Cinema 4D SDK
    r19 r20 c++
    2
    8
    828
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • C4DSC
      C4DS
      last edited by C4DS

      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

      1 Reply Last reply Reply Quote 0
      • ManuelM
        Manuel
        last edited by

        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

        MAXON SDK Specialist

        MAXON Registered Developer

        C4DSC 1 Reply Last reply Reply Quote 0
        • C4DSC
          C4DS @Manuel
          last edited by

          @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>'
          ```.
          1 Reply Last reply Reply Quote 0
          • ManuelM
            Manuel
            last edited by Manuel

            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

            MAXON SDK Specialist

            MAXON Registered Developer

            C4DSC 1 Reply Last reply Reply Quote 1
            • C4DSC
              C4DS @Manuel
              last edited by C4DS

              @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.

              1 Reply Last reply Reply Quote 0
              • ManuelM
                Manuel
                last edited by Manuel

                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

                MAXON SDK Specialist

                MAXON Registered Developer

                C4DSC 1 Reply Last reply Reply Quote 2
                • C4DSC
                  C4DS @Manuel
                  last edited by C4DS

                  @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.

                  1 Reply Last reply Reply Quote 0
                  • ManuelM
                    Manuel
                    last edited by Manuel

                    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

                    MAXON SDK Specialist

                    MAXON Registered Developer

                    1 Reply Last reply Reply Quote 1
                    • First post
                      Last post