Thread: std::unordered_map question

  1. #1
    Registered User
    Join Date
    Jan 2010
    Posts
    227

    Question std::unordered_map question

    Hi there,

    I'm struggling a bit with this as it's a little new to me. I've come across this in my project and was wondering exactly what it's doing?

    Here's a struct definition which contains the un-ordered map. The struct MeshGeometry has some COM pointers in it that will (presumably) point to filled vertex and index buffers later. I've left some of the details out for clarity:

    Code:
    struct MeshGeometry
    {
        // Give it a name so we can look it up by name.
        std::string Name;
    
        // System memory copies.  Use Blobs because the vertex/index format can be generic.
        // It is up to the client to cast appropriately.  
        Microsoft::WRL::ComPtr<ID3DBlob> VertexBufferCPU = nullptr;
        Microsoft::WRL::ComPtr<ID3DBlob> IndexBufferCPU  = nullptr;
    
        Microsoft::WRL::ComPtr<ID3D12Resource> VertexBufferGPU = nullptr;
        Microsoft::WRL::ComPtr<ID3D12Resource> IndexBufferGPU = nullptr;
    
        Microsoft::WRL::ComPtr<ID3D12Resource> VertexBufferUploader = nullptr;
        Microsoft::WRL::ComPtr<ID3D12Resource> IndexBufferUploader = nullptr;
    
        // Data about the buffers.
        UINT VertexByteStride = 0;
        UINT VertexBufferByteSize = 0;
        DXGI_FORMAT IndexFormat = DXGI_FORMAT_R16_UINT;
        UINT IndexBufferByteSize = 0;
    
        // A MeshGeometry may store multiple geometries in one vertex/index buffer.
        // Use this container to define the Submesh geometries so we can draw
        // the Submeshes individually.
        std::unordered_map<std::string, SubmeshGeometry> DrawArgs;
    
    .... rest omitted (just a few member functions)
    
    }
    So that's the struct where the unordered_map data member is first defined. The SubmeshGeometry struct has the following definition:

    Code:
    // Defines a subrange of geometry in a MeshGeometry.  This is for when multiple
    // geometries are stored in one vertex and index buffer.  It provides the offsets
    // and data needed to draw a subset of geometry stores in the vertex and index 
    // buffers so that we can implement the technique described by Figure 6.3.
    
    struct SubmeshGeometry
    {
        UINT IndexCount = 0;
        UINT StartIndexLocation = 0;
        INT BaseVertexLocation = 0;
    
        // Bounding box of the geometry defined by this submesh. 
        // This is used in later chapters of the book.
        DirectX::BoundingBox Bounds;
    };
    And here's the code used to run this stuff in the .cpp file:

    Code:
        SubmeshGeometry submesh;
        submesh.IndexCount = (UINT)indices.size();
        submesh.StartIndexLocation = 0;
        submesh.BaseVertexLocation = 0;
    
        mBoxGeo->DrawArgs["box"] = submesh;
    So a MeshGeometry can hold buffers that actually contain several individual objects such as a box, a sphere and a cylinder. When we only want to draw one of them we need only a portion of the MeshGeometry - which is the SubmeshGeometry.

    So it seems the map takes the Submesh declaration and somehow ties it to a portion of the MeshGeometry struct. It seems to do this however with an std::string, which I found a bit weird. I know there's a lot of API stuff in here but it's the C++ stuff I'm concerned about. Namely how the unordered_map ties data to struct and does so using a string.

    So when this is done can I sort of "access" the unordered_map in the MeshGeometry struct and retrieve Submesh data from it?

    That would make sense actually, because some of this data is needed later on (functions not shown here) to tell the GPU which part of the buffer to draw from, so you can pick out which specific shape you want to draw.

    Still a bit shaky on it though, so I'd appreciate some input on the C++ only parts of it. I understand this is not the place to be requesting info about the API parts.

    Thanks
    Last edited by shrink_tubing; 5 Days Ago at 10:41 AM.

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,674
    I'd suggest you practice with an example or two using types you're more familiar with.

    std::unordered_map - cppreference.com

    When you know what an unordered_map is all about, you'll be able to understand the code that much better.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    Registered User
    Join Date
    Jan 2010
    Posts
    227
    Thank you Salem I'll make some practice projects and have a go! Cheers

  4. #4
    Registered User
    Join Date
    Dec 2017
    Posts
    1,664
    All truths are half-truths. - A.N. Whitehead

  5. #5
    Registered User
    Join Date
    Jan 2010
    Posts
    227
    Thank you John, I haven't checked that link out yet, but I always appreciate your input - no matter what it is. Thanks very much

  6. #6
    Registered User
    Join Date
    Dec 2017
    Posts
    1,664
    I may have misinterpreted your question, but I thought you were asking how the unordered_map works. It uses a hash table, which is an "unordered" data structure, hence the name. The standard map class uses a balanced binary tree, which is ordered so that you can output the data by key in sorted order.
    Code:
    #include <iostream>
    #include <string>
    #include <map>
    #include <unordered_map>
    
    int main() {
        const char *s[] = {
            "one", "two", "three", "four", "five",
            "six", "seven", "eight", "nine", "ten"
        };
    
        std::map<std::string, int> om;
        std::unordered_map<std::string, int> um;
    
        for (int i = 0; i < int(sizeof s / sizeof *s); ++i) {
            om.insert({s[i], i + 1});
            um.insert({s[i], i + 1});
        }
        
        // this outputs in sorted key order
        for (const auto& [k, v]: om)
            std::cout << k << ": " << v << '\n';
    
        std::cout << "----\n";
    
        // this outputs in a seemingly arbitrary order
        for (const auto& [k, v]: um)
            std::cout << k << ": " << v << '\n';
    }
    Output:
    Code:
    eight: 8
    five: 5
    four: 4
    nine: 9
    one: 1
    seven: 7
    six: 6
    ten: 10
    three: 3
    two: 2
    ----
    one: 1
    two: 2
    six: 6
    three: 3
    nine: 9
    five: 5
    four: 4
    seven: 7
    eight: 8
    ten: 10
    All truths are half-truths. - A.N. Whitehead

  7. #7
    Registered User
    Join Date
    Jan 2010
    Posts
    227

    Smile Thanks!

    That's proper cool thanks very much John. I was indeed asking how an unordered map works and I understand it a lot better now. Your example has helped me understand the difference between the two types of map also.

    I wrote this little bit of code (I copied and pasted some of it) to try and investigate using the SubmeshGeometry struct too. I haven't produced anything you guys haven't already covered but it was fun to try.

    Code:
    // C++ program to demonstrate
    // functionality of unordered_map
    #include <iostream>
    #include <unordered_map>
    #include <typeinfo>
    using namespace std;
    
    struct SubmeshGeometry
    {
        unsigned int IndexCount = 0;
        unsigned int StartIndexLocation = 0;
        unsigned int BaseVertexLocation = 0;
    };
    
    int main()
    {
        SubmeshGeometry Box;
        Box.IndexCount = (unsigned int)36;
        Box.StartIndexLocation = 0;
        Box.BaseVertexLocation = 0;
    
        SubmeshGeometry Sphere;
        Sphere.IndexCount = (unsigned int)64;
        Sphere.StartIndexLocation = 36;
        Sphere.BaseVertexLocation = 8;
    
        unordered_map<string, SubmeshGeometry> umap;
    
        // inserting values by using [] operator
        umap["box"] = Box;
        umap["sphere"] = Sphere;
    
        // Traversing an unordered map
        for (auto x : umap)
            cout << x.first << " "
             << x.second.IndexCount << endl
             << x.second.StartIndexLocation << endl
             << x.second.BaseVertexLocation << endl
             << endl;
    
        auto handle = umap.find("box");
        cout << handle->first << " "
             << handle->second.IndexCount << endl
             << handle->second.StartIndexLocation << endl
             << handle->second.BaseVertexLocation << endl
             << endl;
    
        cout << typeid(handle).name() << endl;
    
        return 0;
    }
    I assume the hashing in an unordered_map uses the same kind of hash used for passwords or to create a unique key for a hard disk image and so on. So the hash is some kind of alias for the actual data.

    The code above outputs the following:

    std::unordered_map question-unordered_map-jpg

    It's a good thing I used the auto keyword for the 'handle' variable my dear God look at that for a variable type name lol. Also I noticed when using the find() function you have to refer to the data using pointer type access ->data rather than dot access .data. I don't know why to be honest.

    This has been great, but.... it seems like an awful lot of trouble to go to. Surely if I wanted to retrieve data about a "box" or "sphere" I could just put all their details in a vector (or plain old array) and keep track of which index their data began from?

    Seems like the code's original author went to the trouble of using an unordered_map purely just to be able to retrieve data by using a name.

    All interesting stuff for me. Thanks for helping

  8. #8
    Registered User
    Join Date
    May 2012
    Location
    Arizona, USA
    Posts
    956
    Quote Originally Posted by shrink_tubing View Post
    I assume the hashing in an unordered_map uses the same kind of hash used for passwords or to create a unique key for a hard disk image and so on. So the hash is some kind of alias for the actual data.
    Yes, more or less.

    A hash is just a number of some fixed size, and the kind used in maps can be small and simple, like 32 bits wide or smaller. A hash map is typically just an array where a key's hash value (or a part of it) is used as an index into that array. So you can store or retrieve an object from a map quickly by computing the key's hash and using it as the index. There's more to actual hash maps (for example, how to handle two keys that have the same hash value, which is called a collision), but that's the basics of it.

  9. #9
    Registered User
    Join Date
    Jan 2010
    Posts
    227
    Much thanks christop that's a great reply

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. unordered_map of vectors
    By baxy in forum C++ Programming
    Replies: 7
    Last Post: 09-20-2013, 10:31 AM
  2. unordered_map and const ??
    By baxy in forum C++ Programming
    Replies: 2
    Last Post: 09-15-2013, 02:00 PM
  3. map, unordered_map or vector ?
    By baxy in forum C++ Programming
    Replies: 5
    Last Post: 03-22-2013, 01:25 AM
  4. Replies: 1
    Last Post: 03-23-2011, 09:00 AM
  5. Replies: 2
    Last Post: 05-06-2008, 10:41 AM

Tags for this Thread