
Here is what I see the interface looking like based on feedback from the review so far. It would, of course, be split into different header files. namespace boost { namespace uuids { class uuid : boost::totally_ordered<uuid> { // no default constructor private: uuid(); public: typedef ... value_type; // will only represent one octet typedef ... iterator; typedef ... const_iterator; typedef ... difference_type; typedef ... size_type; enum variant_type { variant_unknown, variant_ncs, variant_rfc_4122, variant_microsoft }; enum version_type { version_unknown, version_1 = 1, version_2 = 2, version_3 = 3, version_4 = 4, version_5 = 5, version_time_based = version_1, version_dce_security = version_2, version_name_based_md5 = version_3, version_random_number_based = version_4 version_name_based_sha1 = version_4 }; public: // valid expression // generator() - result type must be convertible to a uuid template <typename Generator> explicit uuid(Generator & generator); // assert(std::distance(begin, end) >= 16); template <typename ByteInputIterator> uuid(ByteInputIterator begin, ByteInputIterator end); iterator begin(); iterator end(); const_iterator begin() const; const_iterator end() const; bool is_nil() const; operator unspecified_bool_type() const; // return !is_nil(); static size_type size(); // always return 16 bool operator==(uuid const& rhs) const; bool operator<(uuid const& rhs) const; variant_type variant() const; version_type version() const; }; void swap(uuid & lhs, uuid & rhs); std::size_t hash_value(uuid const& u); // removed get/set_showbraces (does anybody want/use them?) template <typename ch, typename char_traits> std::basic_ostream<ch, char_traits>& operator<<(std::basic_ostream<ch, char_traits>& os, uuid const& u); template <typename ch, typename char_traits> std::basic_istream<ch, char_traits>& operator>>(std::basic_istream<ch, char_traits>& os, uuid& u); class nil_generator // always generates a nil uuid { public: typedef uuid result_type; uuid operator()(); }; uuid nil(); // easy to use function - should it be included? template <typename RandomGenerator = boost::mt19937> class random_generator { public: typedef uuid result_type; random_generator(); explicit random_generator(RandomGenerator & gen); explicit random_generator(RandomGenerator * gen); uuid operator()(); }; // I guess technically a transformer since it does not have a zero argument // operator() class name_based_generator // uses sha1 hash { public: typedef uuid result_type; explicit name_based_generator(uuid const& namespace_uuid); template <typename ch, typename char_traits, typename allocator> uuid operator()(std::basic_string<ch, char_traits, allocator> const& name); uuid operator()(const char* name); // use std::strlen uuid operator()(const wchar_t* name); // use std::wcslen template <typename ByteInputIterator> uuid operator()(ByteInputIterator begin, ByteInputIterator end); }; class windows_generator // uses UuidCreate { public: typedef uuid result_type; uuid operator()(); }; class linux_generator // used uuid_generate { public: typedef uuid result_type; uuid operator()(); }; // on windows - will typedef to windows_generator // on linux - will typedef to linix_generator typedef ... native_generator; } //namespace uuids using uuids::uuid; // so nobody has to type boost::uuids::uuid } //namespace boost BOOST_CLASS_IMPLEMENTATION(boost::uuids::uuid, boost::serialization::primitive_type) /* uuid Generator concept Notation: X - a type that is a model of uuid generator x - an object of type X Associated Types: Result Type - X::result_type - this must be convertable to boost::uuids::uuid Valid Expressions: x() - return a boost::uuids::uuid */ Regards, Andy Tompkins

On Fri, Dec 12, 2008 at 11:44, Andy Tompkins <atompkins@fastmail.fm> wrote:
Here is what I see the interface looking like based on feedback from the review so far. It would, of course, be split into different header files.
I like it.
// no default constructor private: uuid();
Great in theory, but I think it'll break lexical_cast<uuid>("21f7f8de-8051-5b89-8680-0195ef798b6a"), since the lexical_cast wants to default-construct the target type into which it will read.
// valid expression // generator() - result type must be convertible to a uuid template <typename Generator> explicit uuid(Generator & generator);
Does this use the Concept defined at the end? Also, when is uuid(gen) significantly more convenient than uuid(gen())? I'd have thought that the copy constructor was plenty.
// assert(std::distance(begin, end) >= 16); template <typename ByteInputIterator> uuid(ByteInputIterator begin, ByteInputIterator end);
Glad to see the exception is gone.
bool is_nil() const;
operator unspecified_bool_type() const; // return !is_nil();
shared_ptr.hpp says // operator! is redundant, but some compilers need it so providing it might be good; I don't know.
// removed get/set_showbraces (does anybody want/use them?) template <typename ch, typename char_traits> std::basic_ostream<ch, char_traits>& operator<<(std::basic_ostream<ch, char_traits>& os, uuid const& u); template <typename ch, typename char_traits> std::basic_istream<ch, char_traits>& operator>>(std::basic_istream<ch, char_traits>& os, uuid& u);
So long as reading still can handle them, it's probably easy enough to stream the brackets explicitly if desired, so that seems a fine decision. (The statics in headers always makes be nervous.)
class nil_generator // always generates a nil uuid { public: typedef uuid result_type; uuid operator()(); }; uuid nil(); // easy to use function - should it be included?
Might as well include it, I guess. On that note, are you including the name-based UUID name spaces anywhere?
// I guess technically a transformer since it does not have a zero argument // operator() class name_based_generator // uses sha1 hash {
On the assumption that an MD5 version would be a reasonable extension, what about templating this on the hasher, defaulting to the sha1 one? That way both the defaults would have the <>, for consistency (random_generator<> and name_based_generator<>). Speaking of which, the version_type enum entry and the generator for random UUIDs don't really match, since the former has number_based (paralleling the name_based enum entry and generator) but the latter does not. random_number_based_generator is admittedly getting rather unwieldy, though.
uuid operator()(const wchar_t* name); // use std::wcslen
What happens here if there are wchar_ts in the stream outside of 0xFF?
class windows_generator // uses UuidCreate class linux_generator // used uuid_generate typedef ... native_generator;
Should these be parametrized at all? Or do people just want defaults, if they want platform ones?
using uuids::uuid; // so nobody has to type boost::uuids::uuid
Good.
/* uuid Generator concept
Notation: X - a type that is a model of uuid generator x - an object of type X
Associated Types: Result Type - X::result_type - this must be convertable to boost::uuids::uuid
Valid Expressions: x() - return a boost::uuids::uuid */
If result_type allows convertible, then the x() should probably return a result_type, not strictly a uuid. What's this used for? Would it worth be adding one for message UUID generators too? Thanks for your work on this, ~ Scott

On Fri, 12 Dec 2008 15:42:32 -0500, "Scott McMurray" <me22.ca+boost@gmail.com> said:
On Fri, Dec 12, 2008 at 11:44, Andy Tompkins <atompkins@fastmail.fm> wrote:
Here is what I see the interface looking like based on feedback from the review so far. It would, of course, be split into different header files.
I like it.
// no default constructor private: uuid();
Great in theory, but I think it'll break lexical_cast<uuid>("21f7f8de-8051-5b89-8680-0195ef798b6a"), since the lexical_cast wants to default-construct the target type into which it will read.
Your right! Hmm. I want to be able to use lexical_cast as above, but I also don't want a default constructor. I think I will optionally include/exclude the default constructor with a #define. And I think a more explicit way to convert a string representation of a uuid to a uuid should be included. Something like the following: template <typename ch, typename char_traits, typename allocator> uuid from_string(std::basic_string<ch, char_traits, allocator> const& s); uuid from_string(const char* name); uuid from_string(const wchar_t* name); OR class string_generator //not a good name { public: typedef uuid result_type; template <typename ch, typename char_traits, typename allocator> uuid operator()(std::basic_string<ch, char_traits, allocator> const& name); uuid operator()(const char* name); // use std::strlen uuid operator()(const wchar_t* name); // use std::wcslen };
// valid expression // generator() - result type must be convertible to a uuid template <typename Generator> explicit uuid(Generator & generator);
Does this use the Concept defined at the end?
Yes.
Also, when is uuid(gen) significantly more convenient than uuid(gen())? I'd have thought that the copy constructor was plenty.
It is more convenient than the copy constructor for generators like random_generator. Eg: random_generator<> gen; uuid u(gen); instead of uuid u = gen(); or uuid u(gen()); It is _significantly_ more convenient? I guess not. Hmm, good point.
// assert(std::distance(begin, end) >= 16); template <typename ByteInputIterator> uuid(ByteInputIterator begin, ByteInputIterator end);
Glad to see the exception is gone.
bool is_nil() const;
operator unspecified_bool_type() const; // return !is_nil();
shared_ptr.hpp says
// operator! is redundant, but some compilers need it
so providing it might be good; I don't know.
Sure, I don't mind putting it in. I'm happy to follow shared_ptr's lead on this.
// removed get/set_showbraces (does anybody want/use them?) template <typename ch, typename char_traits> std::basic_ostream<ch, char_traits>& operator<<(std::basic_ostream<ch, char_traits>& os, uuid const& u); template <typename ch, typename char_traits> std::basic_istream<ch, char_traits>& operator>>(std::basic_istream<ch, char_traits>& os, uuid& u);
So long as reading still can handle them, it's probably easy enough to stream the brackets explicitly if desired, so that seems a fine decision. (The statics in headers always makes be nervous.)
I removed them because of the statics. operator>> can continue to handle them. I agree that it's easy to stream them explicitly, or create a modifier to use similar to: uuid u; cout << with_braces(u);
class nil_generator // always generates a nil uuid { public: typedef uuid result_type; uuid operator()(); }; uuid nil(); // easy to use function - should it be included?
Might as well include it, I guess.
Yes, so that one can create a nil uuid explicitly.
On that note, are you including the name-based UUID name spaces anywhere?
No, I didn't. But I can.
// I guess technically a transformer since it does not have a zero argument // operator() class name_based_generator // uses sha1 hash {
On the assumption that an MD5 version would be a reasonable extension, what about templating this on the hasher, defaulting to the sha1 one?
That way both the defaults would have the <>, for consistency (random_generator<> and name_based_generator<>).
Good idea. But there is no md5 implementation in boost, and I'm not planning to write one (unless there is significant demand).
Speaking of which, the version_type enum entry and the generator for random UUIDs don't really match, since the former has number_based (paralleling the name_based enum entry and generator) but the latter does not. random_number_based_generator is admittedly getting rather unwieldy, though.
Good point. Maybe just random_based_generator and version_random_based.
uuid operator()(const wchar_t* name); // use std::wcslen
What happens here if there are wchar_ts in the stream outside of 0xFF?
This function will treat the stream a sequence of bytes and will have the same effect as using the ByteInputIterator version on the stream. So each wchar_t will be treated as sizeof(wchar_t) bytes.
class windows_generator // uses UuidCreate class linux_generator // used uuid_generate typedef ... native_generator;
Should these be parametrized at all? Or do people just want defaults, if they want platform ones?
It sounds like people just want defaults. It is also easy to create a generator using one of these as a pattern to use a different platform function/parameter.
using uuids::uuid; // so nobody has to type boost::uuids::uuid
Good.
/* uuid Generator concept
Notation: X - a type that is a model of uuid generator x - an object of type X
Associated Types: Result Type - X::result_type - this must be convertible to boost::uuids::uuid
Valid Expressions: x() - return a boost::uuids::uuid */
If result_type allows convertible, then the x() should probably return a result_type, not strictly a uuid.
Good point.
What's this used for?
I am just trying to add flexibility.
Would it worth be adding one for message UUID generators too?
What do you mean by message uuid generators?
Thanks for your work on this, ~ Scott
Regards, Andy Tompkins

On Thu, Dec 18, 2008 at 13:37, Andy Tompkins <atompkins@fastmail.fm> wrote:
Your right! Hmm. I want to be able to use lexical_cast as above, but I also don't want a default constructor. I think I will optionally include/exclude the default constructor with a #define. And I think a more explicit way to convert a string representation of a uuid to a uuid should be included. Something like the following:
template <typename ch, typename char_traits, typename allocator> uuid from_string(std::basic_string<ch, char_traits, allocator> const& s); uuid from_string(const char* name); uuid from_string(const wchar_t* name);
As far as I'm concerned, the "explicit way to convert a string representation of a uuid to a uuid" is spelled lexical_cast<uuid>. I really dislike the idea of some idiom that's not used anywhere else.
class string_generator //not a good name {
I have to say, this seems really silly.
// valid expression // generator() - result type must be convertible to a uuid template <typename Generator> explicit uuid(Generator & generator);
Does this use the Concept defined at the end?
Yes.
What's the result_type needed for? It seems strange to not allow a uuid(*)() to be a UUIDGenerator. Perhaps you can say "where result_type is some unspecified type with an implicit conversion to uuid", not not require it as a typedef? Though I'm still not convinced that the constructor is worth bothering with.
On the assumption that an MD5 version would be a reasonable extension, what about templating this on the hasher, defaulting to the sha1 one?
That way both the defaults would have the <>, for consistency (random_generator<> and name_based_generator<>).
Good idea. But there is no md5 implementation in boost, and I'm not planning to write one (unless there is significant demand).
I wouldn't expect you too, but I can foresee a boost.message_hash library in the future, at which point it ought to be simple to make a name_based_generator<md5>. Would be a reasonable thing for someone else to contribute, too, if they needed it.
Good point. Maybe just random_based_generator and version_random_based.
Still a touch long-winded, but I can't think of anything better.
This function will treat the stream a sequence of bytes and will have the same effect as using the ByteInputIterator version on the stream. So each wchar_t will be treated as sizeof(wchar_t) bytes.
I think that should be up to the user. Otherwise endianness and wchar_t size differences mean it's not going to generate consistent UUIDs (such as between window's UCS-2 wchar_t and linux's UTF-32, iirc). I think it'd be better to force the user to choose between casting to char*, converting to UTF-8, using a casting_iterator, or whatever other method they like, and just allowing the 1-byte versions.
Would it worth be adding one for message UUID generators too?
What do you mean by message uuid generators?
Name-Based (Oor maybe Consistent) UUID Generator constructor: Generator(uuid uuid_namespace) creation: result_type operator(ByteIteratorRange) creation: result_type operator(ByteIterator begin, ByteIterator end) ... or something like that.

Scott McMurray wrote:
On Fri, Dec 12, 2008 at 11:44, Andy Tompkins <atompkins@fastmail.fm> wrote:
Here is what I see the interface looking like based on feedback from the review so far. It would, of course, be split into different header files.
I like it.
// no default constructor private: uuid();
Great in theory, but I think it'll break lexical_cast<uuid>("21f7f8de-8051-5b89-8680-0195ef798b6a"), since the lexical_cast wants to default-construct the target type into which it will read.
Could the relevant lexical_cast overloads be made friends so they can use the default constructor? John Bytheway

John Bytheway wrote:
Scott McMurray wrote:
On Fri, Dec 12, 2008 at 11:44, Andy Tompkins <atompkins@fastmail.fm> wrote:
Here is what I see the interface looking like based on feedback from the review so far. It would, of course, be split into different header files.
I like it.
// no default constructor private: uuid(); Great in theory, but I think it'll break lexical_cast<uuid>("21f7f8de-8051-5b89-8680-0195ef798b6a"), since the lexical_cast wants to default-construct the target type into which it will read.
Could the relevant lexical_cast overloads be made friends so they can use the default constructor?
I think the point was the lexical_cast overloads wouldn't have to use the default constructors. -- Michael Marcin
participants (4)
-
Andy Tompkins
-
John Bytheway
-
Michael Marcin
-
Scott McMurray