Search code examples
c++c++11boost

c++ create a global unique id that is not a UUID type


In other languages, such as Go, there are a myriad of libraries that can be used to create a globally unique ID string (using elements such as nanosecond time, machine id, process id, random bytes...)

However, in C++, the only real choice seems to be UUID (such as that from Boost)

I am looking to use a globally unique identifier in my code, but do not want something with as many chars as a UUID.

As an example of the type of things available in GoLang. Please see the below. Anything similiar in c++?

https://blog.kowalczyk.info/article/JyRZ/generating-good-unique-ids-in-go.html


Solution

  • Please note that when I say "as many chars", I am referring to the string representation of a UUID

    So, perhaps use your own representation.

    You didn't specify a whole lot. Keep in mind that time-clustering might lead to security vulnerabilities¹. I'd assume UUIDv4 standard, meaning 16 bytes. Let's use the encoding from the linked page that looks shortish:

    Live On Coliru

    #include <boost/lexical_cast.hpp>
    #include <boost/uuid/uuid_io.hpp>
    #include <cstring>
    #include <iostream>
    #include <string_view>
    
    using boost::uuids::uuid;
    static_assert(uuid::static_size() == 16);
    
    static constexpr auto alphabet57 =
        "23456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
    
    std::string encode57(uuid uid) {
        boost::uint128_type num;
        std::reverse(uid.data, uid.data+16);
        std::memcpy(&num, uid.data, 16);
    
        std::string s;
        s.reserve(12);
    
        while (num) {
            s += alphabet57[num % 57];
            num /= 57;
        }
    
        return s;
    }
    
    uuid decode57(std::string_view s) {
        boost::uint128_type num = 0;
    
        for (auto it = s.rbegin(); it != s.rend(); ++it) {
            num *= 57;
            num += std::find(alphabet57, alphabet57 + 57, *it) - alphabet57;
        }
    
        uuid uid;
        std::memcpy(uid.data, &num, 16);
        std::reverse(uid.data, uid.data + 16);
    
        return uid;
    }
    
    int main() {
        for (std::string test : {
                 "f7dd5274-f457-4239-a881-801662d589ad", // sfitJnfge8vaXnga8kzi7n
                 "3b387615-24ed-4c17-a715-c4413ffac3b5", // Vq6uZe6usvSwWftVdBPbYC
                 "3dd64dba-1ff3-40e5-84e3-3fbb0f8b86b9", // r5D3drtfrx7322ajzYv82D
                 "b17a848e-5d6b-45d9-ae25-57cfb8a8fec3", // petYHah9W3p8GptQ9QJuaZ
                 "a9edc682-147c-4e41-85e2-e06c4ce64086", // DFLa6tquGSZvSEi2WE3MFY
                 "2cc90c4a-192f-4b57-bc11-2c322dab2ce0", // yyg6AekktrpjdBCjGjsCy9
                 "ac1d94bd-3fbc-46c1-aeec-cdcdc2dd0dd2", // dzHCNTADG6R4n3QTjm7XdY
                 "1e3df271-a3c2-4b45-8871-0fde4c2d97e8", // tL66L6gqRESaABWsxbrhP7
                 "0d15c1d5-3646-474f-8a5d-989878f12a95", // FtnvH2QRENpsFcLXq5zhL4
                 "ececc5dc-cdf1-49f4-b3f7-bfe8697133fd", // Dkfm7JmgVAuP28JLPDBnAk
             })                                          //
        {
            auto const uid = boost::lexical_cast<uuid>(test);
            auto const txt = encode57(uid);
            std::cout << uid << " ~ " << txt << "\n";
            assert(decode57(txt) == uid);
        }
    }
    

    Prints

    f7dd5274-f457-4239-a881-801662d589ad ~ sfitJnfge8vaXnga8kzi7n
    3b387615-24ed-4c17-a715-c4413ffac3b5 ~ Vq6uZe6usvSwWftVdBPbYC
    3dd64dba-1ff3-40e5-84e3-3fbb0f8b86b9 ~ r5D3drtfrx7322ajzYv82D
    b17a848e-5d6b-45d9-ae25-57cfb8a8fec3 ~ petYHah9W3p8GptQ9QJuaZ
    a9edc682-147c-4e41-85e2-e06c4ce64086 ~ DFLa6tquGSZvSEi2WE3MFY
    2cc90c4a-192f-4b57-bc11-2c322dab2ce0 ~ yyg6AekktrpjdBCjGjsCy9
    ac1d94bd-3fbc-46c1-aeec-cdcdc2dd0dd2 ~ dzHCNTADG6R4n3QTjm7XdY
    1e3df271-a3c2-4b45-8871-0fde4c2d97e8 ~ tL66L6gqRESaABWsxbrhP7
    0d15c1d5-3646-474f-8a5d-989878f12a95 ~ FtnvH2QRENpsFcLXq5zhL4
    ececc5dc-cdf1-49f4-b3f7-bfe8697133fd ~ Dkfm7JmgVAuP28JLPDBnAk
    

    ¹ these all are examples of RFC4122 random-number based UUIDs, the default when using goolge/uuid in Go

    These encodings have been verified with the ones generated by shortuuid