Chris@16: // Boost string_generator.hpp header file ----------------------------------------------// Chris@16: Chris@16: // Copyright 2010 Andy Tompkins. Chris@16: // Distributed under the Boost Software License, Version 1.0. (See Chris@16: // accompanying file LICENSE_1_0.txt or copy at Chris@16: // http://www.boost.org/LICENSE_1_0.txt) Chris@16: Chris@16: #ifndef BOOST_UUID_STRING_GENERATOR_HPP Chris@16: #define BOOST_UUID_STRING_GENERATOR_HPP Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include // for strlen, wcslen Chris@16: #include Chris@16: #include // for find Chris@16: #include Chris@16: #include Chris@16: Chris@16: #ifdef BOOST_NO_STDC_NAMESPACE Chris@16: namespace std { Chris@16: using ::strlen; Chris@16: using ::wcslen; Chris@16: } //namespace std Chris@16: #endif //BOOST_NO_STDC_NAMESPACE Chris@16: Chris@16: namespace boost { Chris@16: namespace uuids { Chris@16: Chris@16: // generate a uuid from a string Chris@16: // lexical_cast works fine using uuid_io.hpp Chris@16: // but this generator should accept more forms Chris@16: // and be more efficient Chris@16: // would like to accept the following forms: Chris@16: // 0123456789abcdef0123456789abcdef Chris@16: // 01234567-89ab-cdef-0123456789abcdef Chris@16: // {01234567-89ab-cdef-0123456789abcdef} Chris@16: // {0123456789abcdef0123456789abcdef} Chris@16: // others? Chris@16: struct string_generator { Chris@16: typedef uuid result_type; Chris@16: Chris@16: template Chris@16: uuid operator()(std::basic_string const& s) const { Chris@16: return operator()(s.begin(), s.end()); Chris@16: } Chris@16: Chris@16: uuid operator()(char const*const s) const { Chris@16: return operator()(s, s+std::strlen(s)); Chris@16: } Chris@16: Chris@16: uuid operator()(wchar_t const*const s) const { Chris@16: return operator()(s, s+std::wcslen(s)); Chris@16: } Chris@16: Chris@16: template Chris@16: uuid operator()(CharIterator begin, CharIterator end) const Chris@16: { Chris@16: typedef typename std::iterator_traits::value_type char_type; Chris@16: Chris@16: // check open brace Chris@16: char_type c = get_next_char(begin, end); Chris@16: bool has_open_brace = is_open_brace(c); Chris@16: char_type open_brace_char = c; Chris@16: if (has_open_brace) { Chris@16: c = get_next_char(begin, end); Chris@16: } Chris@16: Chris@16: bool has_dashes = false; Chris@16: Chris@16: uuid u; Chris@16: int i=0; Chris@16: for (uuid::iterator it_byte=u.begin(); it_byte!=u.end(); ++it_byte, ++i) { Chris@16: if (it_byte != u.begin()) { Chris@16: c = get_next_char(begin, end); Chris@16: } Chris@16: Chris@16: if (i == 4) { Chris@16: has_dashes = is_dash(c); Chris@16: if (has_dashes) { Chris@16: c = get_next_char(begin, end); Chris@16: } Chris@16: } Chris@16: Chris@16: if (has_dashes) { Chris@16: if (i == 6 || i == 8 || i == 10) { Chris@16: if (is_dash(c)) { Chris@16: c = get_next_char(begin, end); Chris@16: } else { Chris@16: throw_invalid(); Chris@16: } Chris@16: } Chris@16: } Chris@16: Chris@16: *it_byte = get_value(c); Chris@16: Chris@16: c = get_next_char(begin, end); Chris@16: *it_byte <<= 4; Chris@16: *it_byte |= get_value(c); Chris@16: } Chris@16: Chris@16: // check close brace Chris@16: if (has_open_brace) { Chris@16: c = get_next_char(begin, end); Chris@16: check_close_brace(c, open_brace_char); Chris@16: } Chris@16: Chris@16: return u; Chris@16: } Chris@16: Chris@16: private: Chris@16: template Chris@16: typename std::iterator_traits::value_type Chris@16: get_next_char(CharIterator& begin, CharIterator end) const { Chris@16: if (begin == end) { Chris@16: throw_invalid(); Chris@16: } Chris@16: return *begin++; Chris@16: } Chris@16: Chris@16: unsigned char get_value(char c) const { Chris@16: static char const*const digits_begin = "0123456789abcdefABCDEF"; Chris@16: static char const*const digits_end = digits_begin + 22; Chris@16: Chris@16: static unsigned char const values[] = Chris@16: { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,10,11,12,13,14,15 Chris@16: , static_cast(-1) }; Chris@16: Chris@16: char const* d = std::find(digits_begin, digits_end, c); Chris@16: return values[d - digits_begin]; Chris@16: } Chris@16: Chris@16: unsigned char get_value(wchar_t c) const { Chris@16: static wchar_t const*const digits_begin = L"0123456789abcdefABCDEF"; Chris@16: static wchar_t const*const digits_end = digits_begin + 22; Chris@16: Chris@16: static unsigned char const values[] = Chris@16: { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,10,11,12,13,14,15 Chris@16: , static_cast(-1) }; Chris@16: Chris@16: wchar_t const* d = std::find(digits_begin, digits_end, c); Chris@16: return values[d - digits_begin]; Chris@16: } Chris@16: Chris@16: bool is_dash(char c) const { Chris@16: return c == '-'; Chris@16: } Chris@16: Chris@16: bool is_dash(wchar_t c) const { Chris@16: return c == L'-'; Chris@16: } Chris@16: Chris@16: // return closing brace Chris@16: bool is_open_brace(char c) const { Chris@16: return (c == '{'); Chris@16: } Chris@16: Chris@16: bool is_open_brace(wchar_t c) const { Chris@16: return (c == L'{'); Chris@16: } Chris@16: Chris@16: void check_close_brace(char c, char open_brace) const { Chris@16: if (open_brace == '{' && c == '}') { Chris@16: //great Chris@16: } else { Chris@16: throw_invalid(); Chris@16: } Chris@16: } Chris@16: Chris@16: void check_close_brace(wchar_t c, wchar_t open_brace) const { Chris@16: if (open_brace == L'{' && c == L'}') { Chris@16: // great Chris@16: } else { Chris@16: throw_invalid(); Chris@16: } Chris@16: } Chris@16: Chris@16: void throw_invalid() const { Chris@16: BOOST_THROW_EXCEPTION(std::runtime_error("invalid uuid string")); Chris@16: } Chris@16: }; Chris@16: Chris@16: }} // namespace boost::uuids Chris@16: Chris@16: #endif //BOOST_UUID_STRING_GENERATOR_HPP Chris@16: