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