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