basic_name_generator.hpp 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. #ifndef BOOST_UUID_DETAIL_BASIC_NAME_GENERATOR_HPP_INCLUDED
  2. #define BOOST_UUID_DETAIL_BASIC_NAME_GENERATOR_HPP_INCLUDED
  3. // Boost basic_name_generator.hpp header file -----------------------//
  4. // Copyright 2010 Andy Tompkins.
  5. // Copyright 2017 James E. King III
  6. // Distributed under the Boost Software License, Version 1.0. (See
  7. // accompanying file LICENSE_1_0.txt or copy at
  8. // https://www.boost.org/LICENSE_1_0.txt)
  9. #include <boost/uuid/namespaces.hpp>
  10. #include <boost/uuid/uuid.hpp>
  11. #include <boost/uuid/detail/static_assert.hpp>
  12. #include <boost/config.hpp>
  13. #include <string>
  14. #include <cstdint>
  15. #include <cstring> // for strlen, wcslen
  16. namespace boost {
  17. namespace uuids {
  18. namespace detail {
  19. template<class HashAlgo>
  20. class basic_name_generator
  21. {
  22. private:
  23. uuid namespace_uuid_;
  24. private:
  25. using digest_type = typename HashAlgo::digest_type;
  26. public:
  27. using result_type = uuid;
  28. explicit basic_name_generator( uuid const& namespace_uuid ) noexcept
  29. : namespace_uuid_( namespace_uuid )
  30. {}
  31. template<class Ch> uuid operator()( Ch const* name ) const noexcept
  32. {
  33. HashAlgo hash;
  34. hash.process_bytes( namespace_uuid_.begin(), namespace_uuid_.size() );
  35. process_characters( hash, name, std::char_traits<Ch>().length( name ) );
  36. return hash_to_uuid( hash );
  37. }
  38. template<class Ch, class Traits, class Alloc>
  39. uuid operator()( std::basic_string<Ch, Traits, Alloc> const& name ) const noexcept
  40. {
  41. HashAlgo hash;
  42. hash.process_bytes( namespace_uuid_.begin(), namespace_uuid_.size() );
  43. process_characters( hash, name.c_str(), name.length() );
  44. return hash_to_uuid( hash );
  45. }
  46. uuid operator()( void const* buffer, std::size_t byte_count ) const noexcept
  47. {
  48. HashAlgo hash;
  49. hash.process_bytes( namespace_uuid_.begin(), namespace_uuid_.size() );
  50. hash.process_bytes( buffer, byte_count );
  51. return hash_to_uuid( hash );
  52. }
  53. private:
  54. void process_characters( HashAlgo& hash, char const* p, std::size_t n ) const noexcept
  55. {
  56. hash.process_bytes( p, n );
  57. }
  58. // For portability, we convert all wide characters to uint32_t so that each
  59. // character is 4 bytes regardless of sizeof(wchar_t).
  60. void process_characters( HashAlgo& hash, wchar_t const* p, std::size_t n ) const noexcept
  61. {
  62. BOOST_UUID_STATIC_ASSERT( sizeof( std::uint32_t ) >= sizeof( wchar_t ) );
  63. for( std::size_t i = 0; i < n; ++i)
  64. {
  65. std::uint32_t ch = p[ i ];
  66. unsigned char bytes[ 4 ] =
  67. {
  68. static_cast<unsigned char>( ( ch >> 0 ) & 0xFF ),
  69. static_cast<unsigned char>( ( ch >> 8 ) & 0xFF ),
  70. static_cast<unsigned char>( ( ch >> 16 ) & 0xFF ),
  71. static_cast<unsigned char>( ( ch >> 24 ) & 0xFF )
  72. };
  73. hash.process_bytes( bytes, 4 );
  74. }
  75. }
  76. void process_characters( HashAlgo& hash, char32_t const* p, std::size_t n ) const noexcept
  77. {
  78. for( std::size_t i = 0; i < n; ++i)
  79. {
  80. process_utf32_codepoint( hash, p[ i ] );
  81. }
  82. }
  83. void process_characters( HashAlgo& hash, char16_t const* p, std::size_t n ) const noexcept
  84. {
  85. for( std::size_t i = 0; i < n; ++i)
  86. {
  87. char16_t ch = p[ i ];
  88. if( ch >= 0xD800 && ch <= 0xDBFF && i + 1 < n && p[ i+1 ] >= 0xDC00 && p[ i+1 ] <= 0xDFFF )
  89. {
  90. char16_t ch2 = p[ ++i ];
  91. std::uint32_t high = ch - 0xD800;
  92. std::uint32_t low = ch2 - 0xDC00;
  93. process_utf32_codepoint( hash, ( high << 10 ) + low + 0x10000 );
  94. }
  95. else
  96. {
  97. process_utf32_codepoint( hash, ch );
  98. }
  99. }
  100. }
  101. void process_utf32_codepoint( HashAlgo& hash, std::uint32_t cp ) const noexcept
  102. {
  103. if( ( cp >= 0xD800 && cp <= 0xDFFF ) || cp > 0x10FFFF )
  104. {
  105. cp = 0xFFFD; // Unicode replacement character
  106. }
  107. if( cp < 0x80 )
  108. {
  109. hash.process_byte( static_cast<unsigned char>( cp ) );
  110. }
  111. else if( cp < 0x800 )
  112. {
  113. unsigned char bytes[ 2 ] =
  114. {
  115. static_cast<unsigned char>( 0xC0 | (cp >> 6) ),
  116. static_cast<unsigned char>( 0x80 | (cp & 0x3F) )
  117. };
  118. hash.process_bytes( bytes, 2 );
  119. }
  120. else if( cp < 0x10000 )
  121. {
  122. unsigned char bytes[ 3 ] =
  123. {
  124. static_cast<unsigned char>( 0xE0 | (cp >> 12) ),
  125. static_cast<unsigned char>( 0x80 | ((cp >> 6) & 0x3F) ),
  126. static_cast<unsigned char>( 0x80 | (cp & 0x3F) )
  127. };
  128. hash.process_bytes( bytes, 3 );
  129. }
  130. else
  131. {
  132. unsigned char bytes[ 4 ] =
  133. {
  134. static_cast<unsigned char>( 0xF0 | ( cp >> 18 ) ),
  135. static_cast<unsigned char>( 0x80 | ((cp >> 12 ) & 0x3F ) ),
  136. static_cast<unsigned char>( 0x80 | ((cp >> 6 ) & 0x3F ) ),
  137. static_cast<unsigned char>( 0x80 | (cp & 0x3F) )
  138. };
  139. hash.process_bytes( bytes, 4 );
  140. }
  141. }
  142. #if defined(__cpp_char8_t) && __cpp_char8_t >= 201811L
  143. void process_characters( HashAlgo& hash, char8_t const* p, std::size_t n ) const noexcept
  144. {
  145. hash.process_bytes( p, n );
  146. }
  147. #endif
  148. uuid hash_to_uuid( HashAlgo& hash ) const noexcept
  149. {
  150. digest_type digest;
  151. hash.get_digest(digest);
  152. BOOST_UUID_STATIC_ASSERT( sizeof(digest_type) >= 16 );
  153. uuid u;
  154. std::memcpy( u.data, digest, 16 );
  155. // set variant: must be 0b10xxxxxx
  156. *(u.begin()+8) &= 0x3F;
  157. *(u.begin()+8) |= 0x80;
  158. // set version
  159. unsigned char hashver = hash.get_version();
  160. *(u.begin()+6) &= 0x0F; // clear out the relevant bits
  161. *(u.begin()+6) |= (hashver << 4); // and apply them
  162. return u;
  163. }
  164. };
  165. } // namespace detail
  166. } // uuids
  167. } // boost
  168. #endif // BOOST_UUID_DETAIL_BASIC_NAME_GENERATOR_HPP_INCLUDED