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