//////////////////////////////////////////////////////////////////////////////// /** \file \brief \ru Глобально уникальный идентификатор. \en Global unique identifier. \~ */ //////////////////////////////////////////////////////////////////////////////// #ifndef _TOOL_UUID_H_ #define _TOOL_UUID_H_ #include #include #include #include #include class reader; class writer; const_expr uint8 uuidSize = 16; //------------------------------------------------------------------------------ /** \brief \ru Глобально уникальный идентификатор. \en Global unique identifier. \~ \details \ru Глобально уникальный идентификатор - используется как идентификатор типа пользовательского атрибута. \en Global unique identifier - it is used as an identifier of a type of user attribute. \~ \ingroup Model_Attributes */ struct MbUuid { protected: uint8 data[uuidSize]; private: mutable ThreeStates isEmpty; public: typedef uint8 * iterator; typedef uint8 const * const_iterator; public: MbUuid() : isEmpty( ts_positive ) { ::memset( data, 0, uuidSize ); } MbUuid( const MbUuid & id ) : isEmpty( id.isEmpty ) { ::memcpy( data, id.data, uuidSize ); } public: iterator begin() { isEmpty = ts_neutral; return data; } iterator end() { isEmpty = ts_neutral; return data + uuidSize; } const_iterator cbegin() const { return data; } const_iterator cend() const { return data + uuidSize; } size_t size() const { return uuidSize; } bool is_nil() const { if ( isEmpty == ts_neutral ) { isEmpty = ts_positive; for ( uint8 i = 0; i < uuidSize; i++ ) { if ( data[i] != 0U ) { isEmpty = ts_negative; break; } } } return (isEmpty == ts_positive); } void swap( MbUuid & id ) { uint8 temp[16]; ::memcpy( temp, data, uuidSize ); ::memcpy( data, id.data, uuidSize ); ::memcpy( id.data, temp, uuidSize ); std::swap( isEmpty, id.isEmpty ); } public: MbUuid & operator = ( const MbUuid & id ) { ::memcpy( data, id.data, uuidSize ); isEmpty = id.isEmpty; return *this; } bool operator == ( const MbUuid & id ) const { //return std::equal( cbegin(), cend(), id.cbegin() ); MbUuid::const_iterator first1 = cbegin(), last1 = cend(), first2 = id.cbegin(); while ( first1 != last1 ) { if ( !(*first1 == *first2) ) return false; ++first1; ++first2; } return true; } bool operator != ( const MbUuid & id ) const { return !(*this == id); } bool operator < ( const MbUuid & id ) const { return std::lexicographical_compare( cbegin(), cend(), id.cbegin(), id.cend() ); } bool operator > ( const MbUuid & id ) const { return (id < *this); } bool operator <= ( const MbUuid & id ) const { return !(id < *this); } bool operator >= ( const MbUuid & id ) const { return !(*this < id); } public: friend struct string_generator; friend reader & CALL_DECLARATION operator >> ( reader & in, MbUuid & ref ); friend writer & CALL_DECLARATION operator << ( writer & out, const MbUuid & ref ); friend writer & CALL_DECLARATION operator << ( writer & out, MbUuid & ref ) { return operator << ( out, (const MbUuid &)ref ); } }; //------------------------------------------------------------------------------ /** \brief \ru Генератор MbUuid из string. \en Generator of MbUuid from string. \~ \details \ru Генератор MbUuid из string. Принимает следующие формы: \n 0123456789abcdef0123456789abcdef, \n 01234567-89ab-cdef-0123456789abcdef, \n {01234567-89ab-cdef-0123456789abcdef}, \n {0123456789abcdef0123456789abcdef}. \n \en Generator of MbUuid from string. It accepts the next format: \n 0123456789abcdef0123456789abcdef, \n 01234567-89ab-cdef-0123456789abcdef, \n {01234567-89ab-cdef-0123456789abcdef}, \n {0123456789abcdef0123456789abcdef}. \n \~ \ingroup Model_Attributes */ //--- struct string_generator { template MbUuid operator()( std::basic_string const & s ) const { return operator()( s.begin(), s.end() ); }; MbUuid operator()( char const * const s ) const { return operator()( s, s+std::strlen(s) ); } MbUuid operator()( wchar_t const * const s ) const { return operator()( s, s+std::wcslen(s) ); } template MbUuid operator()( CharIterator begin, CharIterator end ) const { typedef typename std::iterator_traits::value_type char_type; // \ru Проверяем открывающую скобку \en Check an opening parenthesis. char_type c = get_next_char( begin, end ); bool has_open_brace = is_open_brace(c); char_type open_brace_char = c; if ( has_open_brace ) { c = get_next_char( begin, end ); } bool has_dashes = false; MbUuid u; bool isEmpty = true; int i = 0; for ( MbUuid::iterator it_byte = u.begin(); it_byte != u.end(); ++it_byte, ++i ) { if ( it_byte != u.begin() ) { c = get_next_char( begin, end ); } if ( i == 4 ) { if ( is_dash(c) ) { c = get_next_char( begin, end ); has_dashes = true; } } if ( has_dashes ) { if ( is_dash(c) ) { c = get_next_char( begin, end ); } } *it_byte = get_value(c); c = get_next_char( begin, end ); *it_byte <<= 4; *it_byte |= get_value(c); if ( *it_byte != 0U ) isEmpty = false; } // \ru Проверяем закрывающую скобку \en Check a closing parenthesis if ( has_open_brace ) { c = get_next_char( begin, end ); check_close_brace( c, open_brace_char ); } u.isEmpty = isEmpty ? ts_positive : ts_negative; return u; } private: template typename std::iterator_traits::value_type get_next_char( CharIterator & begin, CharIterator end ) const { if ( begin == end ) { _ASSERT( false ); } return *begin++; } unsigned char get_value( char c ) const { static char const*const digits_begin = "0123456789abcdefABCDEF"; static char const*const digits_end = digits_begin + 22; static unsigned char const values[] = { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,10,11,12,13,14,15 , static_cast(-1) }; char const * d = std::find( digits_begin, digits_end, c ); return values[d - digits_begin]; } unsigned char get_value( wchar_t c ) const { static wchar_t const*const digits_begin = L"0123456789abcdefABCDEF"; static wchar_t const*const digits_end = digits_begin + 22; static unsigned char const values[] = { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,10,11,12,13,14,15 , static_cast(-1) }; wchar_t const * d = std::find( digits_begin, digits_end, c ); return values[d - digits_begin]; } bool is_dash( char c ) const { return c == '-'; } bool is_dash( wchar_t c ) const { return c == L'-'; } // \ru Возвращаем открывающую скобку \en Return an opening parenthesis. bool is_open_brace( char c ) const { return (c == '{'); } bool is_open_brace( wchar_t c ) const { return (c == L'{'); } bool check_close_brace( char c, char open_brace ) const { if ( open_brace == '{' && c == '}' ) return true; _ASSERT( false ); return false; } bool check_close_brace( wchar_t c, wchar_t open_brace ) const { if ( open_brace == L'{' && c == L'}' ) return true; _ASSERT( false ); return false; } }; struct hash8_generator { uint8 operator()( const MbUuid & trg ) const { static uint8 rand8[256] = { 1, 14, 110, 25, 97, 174, 132, 119, 138, 170, 125, 118, 27, 233, 140, 51, 87, 197, 177, 107, 234, 169, 56, 68, 30, 7, 173, 73, 188, 40, 36, 65, 49, 213, 104, 190, 57, 211, 148, 223, 48, 115, 15, 2, 67, 186, 210, 28, 12, 181, 103, 70, 22, 58, 75, 78, 183, 167, 238, 157, 124, 147, 172, 144, 176, 161, 141, 86, 60, 66, 128, 83, 156, 241, 79, 46, 168, 198, 41, 254, 178, 85, 253, 237, 250, 154, 133, 88, 35, 206, 95, 116, 252, 192, 54, 221, 102, 218, 255, 240, 82, 106, 158, 201, 61, 3, 89, 9, 42, 155, 159, 93, 166, 80, 50, 34, 175, 195, 100, 99, 26, 150, 16, 145, 4, 33, 8, 189, 121, 64, 77, 72, 208, 245, 130, 122, 143, 55, 105, 134, 29, 164, 185, 194, 193, 239, 101, 242, 5, 171, 126, 11, 74, 59, 137, 228, 108, 191, 232, 139, 6, 24, 81, 20, 127, 17, 91, 92, 251, 151, 225, 207, 21, 98, 113, 112, 84, 226, 18, 214, 199, 187, 13, 32, 94, 220, 224, 212, 247, 204, 196, 43, 249, 236, 45, 244, 111, 182, 153, 136, 129, 90, 217, 202, 19, 165, 231, 71, 230, 142, 96, 227, 62, 179, 246, 114, 162, 53, 160, 215, 205, 180, 47, 109, 44, 38, 31, 149, 135, 0, 216, 52, 63, 23, 37, 69, 39, 117, 146, 184, 163, 200, 222, 235, 248, 243, 219, 10, 152, 131, 123, 229, 203, 76, 120, 209 }; uint8 h = 0; MbUuid::const_iterator curr_iter = trg.cbegin(), end_iter = trg.cend(); while ( curr_iter != end_iter ) h = rand8[h ^ *curr_iter++]; return h; } }; #endif // _TOOL_UUID_H_