#ifndef BOOST_UUID_DETAIL_BASIC_NAME_GENERATOR_HPP_INCLUDED #define BOOST_UUID_DETAIL_BASIC_NAME_GENERATOR_HPP_INCLUDED // Boost basic_name_generator.hpp header file -----------------------// // Copyright 2010 Andy Tompkins. // Copyright 2017 James E. King III // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // https://www.boost.org/LICENSE_1_0.txt) #include #include #include #include #include #include #include // for strlen, wcslen namespace boost { namespace uuids { namespace detail { template class basic_name_generator { private: uuid namespace_uuid_; private: using digest_type = typename HashAlgo::digest_type; public: using result_type = uuid; explicit basic_name_generator( uuid const& namespace_uuid ) noexcept : namespace_uuid_( namespace_uuid ) {} template uuid operator()( Ch const* name ) const noexcept { HashAlgo hash; hash.process_bytes( namespace_uuid_.begin(), namespace_uuid_.size() ); process_characters( hash, name, std::char_traits().length( name ) ); return hash_to_uuid( hash ); } template uuid operator()( std::basic_string const& name ) const noexcept { HashAlgo hash; hash.process_bytes( namespace_uuid_.begin(), namespace_uuid_.size() ); process_characters( hash, name.c_str(), name.length() ); return hash_to_uuid( hash ); } uuid operator()( void const* buffer, std::size_t byte_count ) const noexcept { HashAlgo hash; hash.process_bytes( namespace_uuid_.begin(), namespace_uuid_.size() ); hash.process_bytes( buffer, byte_count ); return hash_to_uuid( hash ); } private: void process_characters( HashAlgo& hash, char const* p, std::size_t n ) const noexcept { hash.process_bytes( p, n ); } // For portability, we convert all wide characters to uint32_t so that each // character is 4 bytes regardless of sizeof(wchar_t). void process_characters( HashAlgo& hash, wchar_t const* p, std::size_t n ) const noexcept { BOOST_UUID_STATIC_ASSERT( sizeof( std::uint32_t ) >= sizeof( wchar_t ) ); for( std::size_t i = 0; i < n; ++i) { std::uint32_t ch = p[ i ]; unsigned char bytes[ 4 ] = { static_cast( ( ch >> 0 ) & 0xFF ), static_cast( ( ch >> 8 ) & 0xFF ), static_cast( ( ch >> 16 ) & 0xFF ), static_cast( ( ch >> 24 ) & 0xFF ) }; hash.process_bytes( bytes, 4 ); } } void process_characters( HashAlgo& hash, char32_t const* p, std::size_t n ) const noexcept { for( std::size_t i = 0; i < n; ++i) { process_utf32_codepoint( hash, p[ i ] ); } } void process_characters( HashAlgo& hash, char16_t const* p, std::size_t n ) const noexcept { for( std::size_t i = 0; i < n; ++i) { char16_t ch = p[ i ]; if( ch >= 0xD800 && ch <= 0xDBFF && i + 1 < n && p[ i+1 ] >= 0xDC00 && p[ i+1 ] <= 0xDFFF ) { char16_t ch2 = p[ ++i ]; std::uint32_t high = ch - 0xD800; std::uint32_t low = ch2 - 0xDC00; process_utf32_codepoint( hash, ( high << 10 ) + low + 0x10000 ); } else { process_utf32_codepoint( hash, ch ); } } } void process_utf32_codepoint( HashAlgo& hash, std::uint32_t cp ) const noexcept { if( ( cp >= 0xD800 && cp <= 0xDFFF ) || cp > 0x10FFFF ) { cp = 0xFFFD; // Unicode replacement character } if( cp < 0x80 ) { hash.process_byte( static_cast( cp ) ); } else if( cp < 0x800 ) { unsigned char bytes[ 2 ] = { static_cast( 0xC0 | (cp >> 6) ), static_cast( 0x80 | (cp & 0x3F) ) }; hash.process_bytes( bytes, 2 ); } else if( cp < 0x10000 ) { unsigned char bytes[ 3 ] = { static_cast( 0xE0 | (cp >> 12) ), static_cast( 0x80 | ((cp >> 6) & 0x3F) ), static_cast( 0x80 | (cp & 0x3F) ) }; hash.process_bytes( bytes, 3 ); } else { unsigned char bytes[ 4 ] = { static_cast( 0xF0 | ( cp >> 18 ) ), static_cast( 0x80 | ((cp >> 12 ) & 0x3F ) ), static_cast( 0x80 | ((cp >> 6 ) & 0x3F ) ), static_cast( 0x80 | (cp & 0x3F) ) }; hash.process_bytes( bytes, 4 ); } } #if defined(__cpp_char8_t) && __cpp_char8_t >= 201811L void process_characters( HashAlgo& hash, char8_t const* p, std::size_t n ) const noexcept { hash.process_bytes( p, n ); } #endif uuid hash_to_uuid( HashAlgo& hash ) const noexcept { digest_type digest; hash.get_digest(digest); BOOST_UUID_STATIC_ASSERT( sizeof(digest_type) >= 16 ); uuid u; std::memcpy( u.data, digest, 16 ); // set variant: must be 0b10xxxxxx *(u.begin()+8) &= 0x3F; *(u.begin()+8) |= 0x80; // set version unsigned char hashver = hash.get_version(); *(u.begin()+6) &= 0x0F; // clear out the relevant bits *(u.begin()+6) |= (hashver << 4); // and apply them return u; } }; } // namespace detail } // uuids } // boost #endif // BOOST_UUID_DETAIL_BASIC_NAME_GENERATOR_HPP_INCLUDED