boost uuid
uuid:
uuid庫是一個小的使用工具,可以表示和生成UUID
UUID是University Unique Identifier的縮寫,它是一個128位的數字(16字節),不需要有一個中央認證機構就可以創建全國唯一的標示符。別名:GUID
uuid位于名字空間boost::uuisd,沒有集中的頭文件,把功能分散在了若干小文件中,因此為了使用uuid組件,需要包含數個頭文件,即:
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>
using namespace boost::uuids;
uuid還全面支持比較操作和流輸入輸出,兩個uuid值的比較是基于字典序的,分別使用了標準算法std
::equal()和std::lexicographical_compare().
用法:
uuid是一個很小的類,它特意被設計為沒有構造函數,可以像POD數據類型一樣使用.
uuid內部使用一個16字節的數組data作為UUID值的存儲,這個數組是public的,因此可以任意訪問,比如拷貝或者賦值。基于data數組,uuid提供了begin()和end()的迭代器支持,可以像一個容器一樣操作UUID值的每個字節。成員函數size()和靜態成員函數static_size()可以獲得UUID的長度,是一個固定值,大小總為16,元素類型為unsigned char的容器。
示例:
#include <iostream>
#include <vector>
#include <assert.h>
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>
using namespace boost::uuids;
using namespace std;
int main()
{
uuid u;
assert(uuid::static_size() == 16);
assert(u.size() == 16);
vector<unsigned char> v(16, 7);
//使用標準拷貝算法
std::copy(v.begin(), v.end(), u.begin());
assert(u.data[0] == u.data[1] && u.data[15] == 7); //數組方式訪問
cout<<u<<endl;
std::fill_n(u.data + 10, 6, 8); //標準算法fill_n直接操縱數組
cout<<u<<endl;
system("pause");
return 0;
}
uuid內部定義的枚舉類型variant_type標識了UUID的變體號,表示了UUID的布局類型,成員函數variant()可以獲得這個UUID的變體號.
UUID的生成有不同的算法,這些算法使用枚舉version_type來標識,version()函數可以獲得UUID的算法版本,uuid類可以識別現在的有五種生成算法:
【1】基于時間和MAC的算法(version_time_based);
【2】分布計算環境算法(dce_security);
【3】MD5摘要算法(version_name_based_md5);
【4】隨機數算法(version_random_number)based)
【5】SHA1摘要算法(version_name_based_shal)
在數量龐大的UUID中有一個特殊的全零值nil,它表示一個無效的UUID,成員函數is_nil()可以檢測uuid是否是nil。
示范:uuid用于表示UUID用法的代碼如下:
uuid u;
std::fill_n(u.begin(), u.size(), 0xab);
assert(!u.is_nil);
assert(u.variant() == u.variant_rfc_4122); //4122變體類型
assert(!u.version() == u.version_unknown); //生成算法未知
cout<<u<<endl;
std::memset(u.data, 0, 16);
assert(u.is_nil());
uuid u1,u2;
std::file_n(u1.begin(), u1.size(), 0xab);
std::file_n(u2.begin(), u2.size(), 0xa0);
assert(u1 != u2 && u1>u2);
u2.data[0] = 0xff; //u2的第一個字節改為0xff
assert(u1 < u2);
std::memset(u1.data, 0, 16);
std::memset(u2.data, 0, 16);
assert(u1 == u2);
生成器:
使用uuid提供的數組和迭代器接口,可以直接寫出任意的UUID值,但因為不使用規定的算法,手工創建的UUID值很容易重復,這種方式只適合于從其他地方獲得的原始UUID值導入到uuid對象中,如果要創建屬于自己的UUID,需要使用UUID生成器。
uuid庫提供了四種生成器,分別是Nil生成器,字符串生成器,名字生成器和隨機生成器,它們都是函數對象,重載了operator(),可以直接調用uuid對象.
Nil生成器:
Nil生成器是最簡單的UUID生成器,只能生成一個無效的UUID值,它的存在只是為了方便地表示無效UUID。
Nil生成器的類名是nil_generator,另外有一個內聯函數nil_uuid(),相當于直接調用了Nil生成器。
示范:
uuid u = nil_generator()();//第一對圓括號與nil_generator()結合,結果是調用nil_generator的構造函數,生成一個臨時對象,然后第二對圓括號是nil_generator對象的operator()操作符重載,就像是一個函數調用,產生了一個nil uuid對象.
assert(u.is_nil);
u = nil_uuid();
assert(u.is_nil());
字符串生成器:
字符串生成器string_generator可以從一個字符串創建出uuid對象,字符串可以是C數組(NULL結尾),string,wstring,或者是一對迭代器指定的字符序列的區間。
string_generator對字符串的格式有嚴格的要求,有兩種格式是可接受的,一種是沒有連字符的全16進制數字,另一種是使用連字符,但必須符合UUID的定義,在第5,7,9,11,字節前使用連字符,其他位置出現連字符都不允許。UUID字符串也可以使用花括號括起來,除了花括號不能出現16進制數以外的任何字符,否則會拋出runtime_error異常。
示范string_generator用法的代碼如下:
string_generator sgen; //聲明字符串生成器對象
uuid u1 = sgen("0123456789abcdef0123456789abcdef");
cout<<u1<<endl;
uuid u2 = sgen("01234567-89ab-cdef-0123-456789abcdef");
cout<<u2<<endl;
uuid u3 = sgen(L"{01234567-89ab-cdef-0123-456789abcdef}");
cout<<u3<<endl;
名字生成器:
名字生成器name_generator使用基于名字的SHA1摘要算法,它需要先指定一個基準UUID,然后使用字符串名字派生出基于這個UUID的一系列UUID,名字生成器的典型的應用場景是為一個組織內的所有成員創建UUID標識,只有基準UUID不變,那么相同的名字總會產生相同的UUID。
示范:name_generator用法:
//首先生成一個組織的UUID
uuid www_xxx_com = string_generator()("{0123456789abcdef0123456789abcdef}");
name_generator ngen(www_xxx_com);//構造名字生成器
uuid u1 = ngen("mario");//為名字mario生成UUID
assert(!u1.is_nil() && u1.version() == uuid::version_name_based_sha1);//version是sha1算法
uuid u2 = ngen("link");//為名字link生成uuid
cout<<u2<<endl;
隨機生成器:
隨機生成器采用隨機數生成UUID,uuid庫使用Boost庫的另一個組件random作為隨機數的發生源,它可以產生高質量的偽隨機數,保證生成的隨機UUID不會重復。
隨機生成器basic_random_generator是一個模板類,可以用模板參數指定要使用的隨機數發生器,具有的隨機數類可以參考random庫,為了方便使用,uuid定義了一個常用的生成器random_generator,它使用mt19937作為隨機數發生器。
示范隨機生成器用法的代碼:
random_generator rgen;//隨機生成器
uuid u = rgen();//生成一個隨機的UUID
assert(u.version() == uuid::version_random_number_based)
cout<<u<<endl;
增強的uuid類:
uuid類為了追求效率而沒有提供構造函數,要生成一個UUID值,必須要使用生成器,但有時候這個操作步驟顯得有些麻煩,因此可以從uuid類派生一個可以自動產生uuid值的增強類,以簡化uuid的使用。
uuid_t,它是uuid的子類,具有uuid的全部能力,它內部定義了兩個生成器的靜態成員變量,分別用來產生隨機uuid和字符串uuid,對應地也提供了兩種重載形式的構造函數,對于Nil生成器,uuid_t使用帶int參數的構造函數來調用實現,而名字生成器則使用了接受uuid和字符串參數的構造函數。
uuid_t還實現了兩個類型轉換操作符重載,可以隱式地轉換uuid對象,方便被應用在其他使用uuid類型的場景。
uuid_t的全部實現代碼:
class uuid_t:pubilc uuid
{
private:
static random_generator rgen; //隨機生成器
static string_generator sgen;//字符串生成器
public:
uuid_t(): uuid(rgen()){}//缺省構造函數,生成隨機UUID
uuid_t(int):uuid(nil_uuid()){}//0值的uuid構造函數
uuid_t(const char*str):uuid(sgen(str)){}//字符串構造函數
uuid_t(const uuid&u, const char* str)://名字生成器構造函數
uuid(name_generator(u)(str)){}
explicit uuid_t(const uuid& u):uuid(u){}拷貝構造函數
operator uuid()//轉換到uuid類型
{ return static_cast<uuid&>(*this);}
operator uuid() const //常函數,轉換到const uuid類型
{ return static_cast<const uuid&>(*this);}
};
random_generator uuid_t::rgen;//靜態成員變量的定義
string_generator uuid_t::sgen;
由于uuid_t類封裝了uuid的所有生成器,故它比uuid用起來更加方便容易,例如:
uuid_t u0 =0;
assert(u0.is_nil());;
uuid_t u1,u2;
cout<< u1<<endl;
cout<< u2<<endl;
uuid_t u3("{01234567-89ab-cdef-0123-456789abcdef}");//字符串構造
cout<<u3<<endl;
cout<< uuid_t(u3, "test name gen")<<endl; //通過名字構造
與字符串的轉換:
uuid不能直接獲得一個uuid的字符串表示,但因為uuid支持流輸入輸出,故可以使用std::stringstream轉換為字符串,例如;
uuid u = string_generator()("01234567-89ab-cdef-0123-456789abcdef");
stringstream ss;
ss << u; //uuid輸出到字符串流
string str;
ss>>str;//字符串流輸出到字符串對象
cout<<str<<endl;
另一個Boost庫組件lexical_cast,它可以方便地實現字符串與uuid的雙向轉換
示例:
#include <iostream>
#include <vector>
#include <assert.h>
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>
#include <boost/lexical_cast.hpp>
using namespace boost;
using namespace boost::uuids;
using namespace std;
int main()
{
uuid u = lexical_cast<uuid>("01234567-89ab-cdef-0123-456789abcdef");
cout<<u<<endl;
string str = lexical_cast<string>(u); //uuid轉換到字符串
cout<<str<<endl;
}
lexical_cast的字符串轉換uuid的用法很類似字符串生成器string_generator,但功能要弱很多,因為lexical_cast的轉換功能是基于uuid的流輸入能力,因此只能接受連字符格式的字符串,而且不能有花括號.
SHA1摘要算法:
SHA1算法廣泛地應用于防篡改,身份鑒定等安全認證領域.
#include <boost/uuid/sha1.hpp>
boost::uuids::detail
shal類的用法很簡單,使用成員函數process_byte(),process_block()和process_bytes()以不用的方式把數據"喂"給shal對象,當輸入所有數據后用get_digest()獲得計算出的摘要值。
示例:
#include <iostream>
#include <vector>
#include <assert.h>
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/uuid/sha1.hpp>
using namespace boost;
using namespace boost::uuids::detail;
using namespace std;
int main()
{
sha1 sha;
char *szMsg = "a short message"; //用于摘要的消息
sha.process_byte(0x10); //處理一個字節
sha.process_bytes(szMsg, strlen(szMsg)); //處理多個字節
sha.process_block(szMsg, szMsg + strlen(szMsg));
unsigned int digest[5]; //摘要的返回值
sha.get_digest(digest);
for (int i = 0; i< 5; ++i)
cout<< hex << digest[i]; //16進制輸出
}