Boost.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进制输出 }