C++のboostライブラリによるUUID

# はじめに
　本記事はboostライブラリを使用したC++でUUIDを使用する方法を説明します。
 # 環境
 ・2024/02/23
 ・GitHub Codespaces
 # UUIDとは
　UUID(Universally Unique IDentifiler)は36文字(128bit)の英数字で情報を識別するために使用される文字列のことです。生成規則から生成されたUUIDは、他に生成されたUUIDと同一となる可能性は非常に低いです。そのためUUIDは一意の情報としての価値が高く、データベースなどのユニークIDとして使用されます。

UUIDの例：c2253419-a003-4431-95cf-fe8db55938ac

# C++のUUID
　C++は標準データ型としてuuid_tを持ちますが、非常に機能が弱いです。そこで本記事はboostライブラリに含まれるUUIDの使用法を説明します。
　boostライブラリのインストール方法は以下の記事を参考にしてください。

https://qiita.com/king_dog_fun/items/0dc555e847acba89aae7

# 使い方

　以下はboostライブラリがインストールされていることを前提に説明します。
　幾つかのコード例を提示しますが、コードを実際の実行環境で確認したい場合は以下のコマンドでコンパイルしてください。boostのビルドが/usr/localで成されていることを前提としているため、boostのライブラリとヘッダーが/usr/local/libと/usr/local/includeに存在しない場合、都度コンパイルコマンドに変更を加えてください。

 ```
g++ -o example example.cpp -I /usr/local/include/boost -L /usr/local/lib
 ```


## UUID生成

　UUIDはrandom_generatorで生成する。

```c++:generate.cpp
#include <iostream>
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>

int main()
{
    // UUIDを生成する
    boost::uuids::uuid uuid = boost::uuids::random_generator()();
    // UUIDを文字列に変換して表示する
    std::cout << uuid << std::endl;
    return 0;
}
```

## UUID➡文字列変換

　uuid型はlexical_castで文字列型を変換する。

```c++:conversion1.cpp
#include <iostream>
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>
#include <boost/lexical_cast.hpp>

int main()
{
    // UUIDを生成する
    boost::uuids::uuid uuid = boost::uuids::random_generator()();
    // UUIDを文字列に変換
    std::string s = boost::lexical_cast<std::string>(uuid);
    // 文字列を表示する
    std::cout << s << std::endl;
    return 0;
}
```

## 文字列➡UUID
　文字列型はlexical_castでUUID型に変換する。

 ```c++:conversion2.cpp
#include <iostream>
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_io.hpp>
#include <boost/lexical_cast.hpp>

int main()
{
    std::string s = "c2253419-a003-4431-95cf-fe8db55938ac";
    // 文字列をUUIDに変換
    boost::uuids::uuid uuid = boost::lexical_cast<boost::uuids::uuid>(s);
    // UUIDを文字列に変換して表示する
    std::cout << uuid << std::endl;
    return 0;
}
 ```

## UUIDのコピー
　UUIDは代入することでコピーが行える。

 ```c++:copy.cpp
#include <iostream>
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>

int main()
{
    // UUIDを生成する
    boost::uuids::uuid uuid1 = boost::uuids::random_generator()();
    // UUIDをコピーする
    boost::uuids::uuid uuid2 = uuid1;
    // UUIDを文字列に変換して表示する
    std::cout << uuid2 << std::endl;
    return 0;
}
 ```

 ## UUIDの比較
 　UUIDは等価演算子により比較を行うことができる。

```c++:comparison.cpp
#include <iostream>
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>

int main()
{
    // UUIDを生成する
    boost::uuids::uuid uuid1 = boost::uuids::random_generator()();
    boost::uuids::uuid uuid2 = boost::uuids::random_generator()();
    // UUIDをコピーする
    boost::uuids::uuid uuid3 = uuid1;
    // UUIDを比較
    bool b1 =uuid1 == uuid2;
    bool b2 =uuid1 == uuid3;
    // UUIDを文字列に変換して表示する
    std::cout << "b1:" << b1 << std::endl;
    std::cout << "b2:" << b2 << std::endl;
    return 0;
}
```

 実行した場合以下のような結果を得る。

```
b1:0
b2:1
```

 ## nil値の生成
　nil値とは値が存在しないことを示す特別な情報のことです。
　nilはnil_generatorで生成する。

 ```c++:nil.cpp
#include <iostream>
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>

int main()
{
    // nil値を生成する
    boost::uuids::uuid nil = boost::uuids::nil_generator{}();
    // nil値を表示する
    std::cout << nil << std::endl;
    return 0;
}
 ```

 実行した場合以下のような結果を得る。

 ```
00000000-0000-0000-0000-000000000000
 ```

 ## nil値の判別

  UUIDがnil値であるかis_nilで判別することができる。

```c++:decision.cpp
#include <iostream>
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>

int main()
{
    // UUIDを生成する
    boost::uuids::uuid uuid = boost::uuids::random_generator()();
    // nil値を生成する
    boost::uuids::uuid nil = boost::uuids::nil_generator{}();
    // nilか判別する
    bool b1 = uuid.is_nil();
    bool b2 = nil.is_nil();
    // 結果を表示する
    std::cout << "b1:" << b1 << std::endl;
    std::cout << "b2:" << b2 << std::endl;
    return 0;
}
```

 実行した場合以下のような結果を得る。

 ```
b1:0
b2:1
 ```

## ハッシュマップ作製:int
　boostにあるUUIDの最大の特徴はハッシュマップ作製の機能が標準で搭載されている点です。UUIDからハッシュマップを作成することが可能となります。例としてint型のデータを探索するハッシュマップを作成しましょう。
 　ハッシュマップはunoredered_mapで生成できます。テンプレートパラメータにデータ型を指定し、そのデータを格納します。以下の例では、boost::uuids::uuidとintでハッシュマップのキーとデータの型を決定しています。
 　

 ```c++:hashmap1.cpp
#include <iostream>
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>
#include <boost/unordered_map.hpp>

int main()
{
    // UUIDを生成する
    boost::uuids::uuid uuid1 = boost::uuids::random_generator()();
    boost::uuids::uuid uuid2 = boost::uuids::random_generator()();
    // ハッシュマップ作製
    boost::unordered_map<boost::uuids::uuid, int> map;
    map[uuid1] = 100;
    map[uuid2] = 200;
    // ハッシュマップから数字を表示する
    std::cout << "map[uuid1] :" << map[uuid1] << std::endl;
    std::cout << "map[uuid2] :" << map[uuid2] << std::endl;
    return 0;
}
 ```

  実行した場合以下のような結果を得る。

  ```
map[uuid1] :100
map[uuid2] :200
  ```

## ハッシュマップ作製:string
　前例はint型のデータを格納しました。ならば、他の型を格納することも当然出来るだろうということで、検証しましょう。以下の例では、boost::uuids::uuidとstringでハッシュマップのキーとデータの型を決定しています。

```c++:hashmap2.cpp
#include <iostream>
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>
#include <boost/unordered_map.hpp>

int main()
{
    // UUIDを生成する
    boost::uuids::uuid uuid1 = boost::uuids::random_generator()();
    boost::uuids::uuid uuid2 = boost::uuids::random_generator()();
    // ハッシュマップ作製
    boost::unordered_map<boost::uuids::uuid, std::string> map;
    map[uuid1] = "one hundred";
    map[uuid2] = "two hundred";
    // ハッシュマップから数字を表示する
    std::cout << "map[uuid1] :" << map[uuid1] << std::endl;
    std::cout << "map[uuid2] :" << map[uuid2] << std::endl;
    return 0;
}
```

  実行した場合以下のような結果を得る。

```
map[1] :one hundred
map[2] :two hundred
```

## ハッシュマップの応用
　ハッシュマップはテンプレートパラメータを自由に設定できるため、自身で定義した構造体なども入れられます。int型などでは、UUID一つに対しデータが一つに限られますが、構造体を自身で定義すれば、複数のデータをハッシュマップと結びつけられます。以下がハッシュマップの応用例です。

 ```c++:hashmap3.cpp
#include <iostream>
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>
#include <boost/unordered_map.hpp>

struct Student {
    std::string name;
    int age;
};

int main()
{
    // UUIDを生成する
    boost::uuids::uuid uuid1 = boost::uuids::random_generator()();
    boost::uuids::uuid uuid2 = boost::uuids::random_generator()();
    // ハッシュマップ作製
    boost::unordered_map<boost::uuids::uuid, Student*> map;
    Student *s1 = new Student;
    s1->name = "Alice";
    s1->age = 20;
    Student *s2 = new Student;
    s2->name = "Clara";
    s2->age = 105;
    map[uuid1] = s1;
    map[uuid2] = s2;
    // ハッシュマップから数字を表示する
    std::cout << "map[uuid1]->name :" << map[uuid1]->name << std::endl;
    std::cout << "map[uuid2]->name :" << map[uuid2]->name << std::endl;
    return 0;
}
 ```

　実行した場合以下のような結果を得る。

 ```
map[uuid1]->name :Alice
map[uuid2]->name :Clara
 ```

# 蛇足
　本記事で紹介してハッシュマップ作製では、unordered_mapのテンプレートパラメータの第一パラメータをUUIDで固定しました。しかし、テンプレートパラメータの第一項が指定できるのであれば、UUID以外も使用できるのではないだろうかと気になり検証した。

 ```c++:extraordinary.cpp
#include <iostream>
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>
#include <boost/unordered_map.hpp>

int main()
{
    // ハッシュマップ作製
    boost::unordered_map<int, std::string> map;
    map[1] = "one hundred";
    map[2] = "two hundred";
    // ハッシュマップから数字を表示する
    std::cout << "map[1] :" << map[1] << std::endl;
    std::cout << "map[2] :" << map[2] << std::endl;
    return 0;
}
 ```

　実行した場合以下のような結果を得る。

```
map[1] :one hundred
map[2] :two hundred
```

ps. 私はまだC++に関して初心者なのですが、C++にはどうやらmapという、上記で示したハッシュマップと似たものが標準で搭載されているのですね。ChatGPT君に聞いてみれば以下の様な違いがあると教えてくれました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2647158/661f2dbe-9164-c10f-0e97-4caecc27ea2a.png)


# 参考記事

https://zenn.dev/kaorumori/articles/08ff8106300a7b

https://diary-039.com/entry/2021/05/17/cpp_uuid_01#toc9