string_generator.hpp 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. // Boost string_generator.hpp header file ----------------------------------------------//
  2. // Copyright 2010 Andy Tompkins.
  3. // Distributed under the Boost Software License, Version 1.0. (See
  4. // accompanying file LICENSE_1_0.txt or copy at
  5. // https://www.boost.org/LICENSE_1_0.txt)
  6. #ifndef BOOST_UUID_STRING_GENERATOR_HPP
  7. #define BOOST_UUID_STRING_GENERATOR_HPP
  8. #include <boost/uuid/uuid.hpp>
  9. #include <string>
  10. #include <cstring> // for strlen, wcslen
  11. #include <iterator>
  12. #include <algorithm> // for find
  13. #include <stdexcept>
  14. #include <boost/throw_exception.hpp>
  15. #include <boost/config.hpp>
  16. #ifdef BOOST_NO_STDC_NAMESPACE
  17. namespace std {
  18. using ::strlen;
  19. using ::wcslen;
  20. } //namespace std
  21. #endif //BOOST_NO_STDC_NAMESPACE
  22. namespace boost {
  23. namespace uuids {
  24. // generate a uuid from a string
  25. // lexical_cast works fine using uuid_io.hpp
  26. // but this generator should accept more forms
  27. // and be more efficient
  28. // would like to accept the following forms:
  29. // 0123456789abcdef0123456789abcdef
  30. // 01234567-89ab-cdef-0123-456789abcdef
  31. // {01234567-89ab-cdef-0123-456789abcdef}
  32. // {0123456789abcdef0123456789abcdef}
  33. // others?
  34. struct string_generator {
  35. typedef uuid result_type;
  36. template <typename ch, typename char_traits, typename alloc>
  37. uuid operator()(std::basic_string<ch, char_traits, alloc> const& s) const {
  38. return operator()(s.begin(), s.end());
  39. }
  40. uuid operator()(char const*const s) const {
  41. return operator()(s, s+std::strlen(s));
  42. }
  43. uuid operator()(wchar_t const*const s) const {
  44. return operator()(s, s+std::wcslen(s));
  45. }
  46. template <typename CharIterator>
  47. uuid operator()(CharIterator begin, CharIterator end) const
  48. {
  49. typedef typename std::iterator_traits<CharIterator>::value_type char_type;
  50. // check open brace
  51. char_type c = get_next_char(begin, end);
  52. bool has_open_brace = is_open_brace(c);
  53. char_type open_brace_char = c;
  54. if (has_open_brace) {
  55. c = get_next_char(begin, end);
  56. }
  57. bool has_dashes = false;
  58. uuid u;
  59. int i=0;
  60. for (uuid::iterator it_byte=u.begin(); it_byte!=u.end(); ++it_byte, ++i) {
  61. if (it_byte != u.begin()) {
  62. c = get_next_char(begin, end);
  63. }
  64. if (i == 4) {
  65. has_dashes = is_dash(c);
  66. if (has_dashes) {
  67. c = get_next_char(begin, end);
  68. }
  69. }
  70. // if there are dashes, they must be in every slot
  71. else if (i == 6 || i == 8 || i == 10) {
  72. if (has_dashes == true) {
  73. if (is_dash(c)) {
  74. c = get_next_char(begin, end);
  75. } else {
  76. throw_invalid();
  77. }
  78. }
  79. }
  80. *it_byte = get_value(c);
  81. c = get_next_char(begin, end);
  82. *it_byte <<= 4;
  83. *it_byte |= get_value(c);
  84. }
  85. // check close brace
  86. if (has_open_brace) {
  87. c = get_next_char(begin, end);
  88. check_close_brace(c, open_brace_char);
  89. }
  90. // check end of string - any additional data is an invalid uuid
  91. if (begin != end) {
  92. throw_invalid();
  93. }
  94. return u;
  95. }
  96. private:
  97. template <typename CharIterator>
  98. typename std::iterator_traits<CharIterator>::value_type
  99. get_next_char(CharIterator& begin, CharIterator end) const {
  100. if (begin == end) {
  101. throw_invalid();
  102. }
  103. return *begin++;
  104. }
  105. unsigned char get_value(char c) const {
  106. static char const digits_begin[] = "0123456789abcdefABCDEF";
  107. static size_t digits_len = (sizeof(digits_begin) / sizeof(char)) - 1;
  108. static char const*const digits_end = digits_begin + digits_len;
  109. static unsigned char const values[] =
  110. { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,10,11,12,13,14,15 };
  111. size_t pos = std::find(digits_begin, digits_end, c) - digits_begin;
  112. if (pos >= digits_len) {
  113. throw_invalid();
  114. }
  115. return values[pos];
  116. }
  117. unsigned char get_value(wchar_t c) const {
  118. static wchar_t const digits_begin[] = L"0123456789abcdefABCDEF";
  119. static size_t digits_len = (sizeof(digits_begin) / sizeof(wchar_t)) - 1;
  120. static wchar_t const*const digits_end = digits_begin + digits_len;
  121. static unsigned char const values[] =
  122. { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,10,11,12,13,14,15 };
  123. size_t pos = std::find(digits_begin, digits_end, c) - digits_begin;
  124. if (pos >= digits_len) {
  125. throw_invalid();
  126. }
  127. return values[pos];
  128. }
  129. bool is_dash(char c) const {
  130. return c == '-';
  131. }
  132. bool is_dash(wchar_t c) const {
  133. return c == L'-';
  134. }
  135. // return closing brace
  136. bool is_open_brace(char c) const {
  137. return (c == '{');
  138. }
  139. bool is_open_brace(wchar_t c) const {
  140. return (c == L'{');
  141. }
  142. void check_close_brace(char c, char open_brace) const {
  143. if (open_brace == '{' && c == '}') {
  144. //great
  145. } else {
  146. throw_invalid();
  147. }
  148. }
  149. void check_close_brace(wchar_t c, wchar_t open_brace) const {
  150. if (open_brace == L'{' && c == L'}') {
  151. // great
  152. } else {
  153. throw_invalid();
  154. }
  155. }
  156. BOOST_NORETURN void throw_invalid() const {
  157. BOOST_THROW_EXCEPTION(std::runtime_error("invalid uuid string"));
  158. }
  159. };
  160. }} // namespace boost::uuids
  161. #endif //BOOST_UUID_STRING_GENERATOR_HPP