[Reminder][Review] The review of the Boost.Guid library starts today (April 30th)

Hi all, This is just a gentle reminder that the review for the proposed Boost.Guid library is still ongoing. This is not a lare library, but nevertheless a important one, IMHO. Please try to find some time to go over the documentation or the code to give your opinion and don't forget your vote. Regards Hartmut --------------------------------------------------- Below the original announcement: --------------------------------------------------- Hi all, The review of the proposed Boost Guid library written by Andy Tompkins starts today (April 30th, 2007) and ends May 10th, 2007. You can download the library here: http://www.boost-consulting.com/vault/ (file guid_v7.zip). --------------------------------------------------- About the library: Guid is a library providing an implementation of Globally Unique Identifiers. Guid's are used in many facets of programming, including databases, networks, remote procedures, serializations, transactions, identifying documents, and identifying classes. This library is efficient and is able to create name-based and random-based guids. --------------------------------------------------- Please always state in your review, whether you think the library should be accepted as a Boost library! Additionally please consider giving feedback on the following general topics: - What is your evaluation of the design? - What is your evaluation of the implementation? - What is your evaluation of the documentation? - What is your evaluation of the potential usefulness of the library? - Did you try to use the library? With what compiler? Did you have any problems? - How much effort did you put into your evaluation? A glance? A quick reading? In-depth study? - Are you knowledgeable about the problem domain? Regards Hartmut Review Manager

-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of Hartmut Kaiser Sent: 04 May 2007 15:31 To: boost@lists.boost.org Subject: [boost] [Reminder][Review] The review of the Boost.Guid librarystarts today (April 30th)
- What is your evaluation of the design? Can't see any problems. - What is your evaluation of the implementation? Seems to work and has been a sensible evolution/development process. Looks likely to be maintained and developed. - What is your evaluation of the documentation? Didn't spot anything wrong. - What is your evaluation of the potential usefulness of the library? Invaluable in certain places. - Did you try to use the library? With what compiler? Did you have any problems? Used an earlier version with MSVC 8.0 without problems. - How much effort did you put into your evaluation? A glance? Only a glance. - Are you knowledgeable about the problem domain? No.
I see no reason why this useful library should not be accepted, so vote to accept. Paul --- Paul A Bristow Prizet Farmhouse, Kendal, Cumbria UK LA8 8AB +44 1539561830 & SMS, Mobile +44 7714 330204 & SMS pbristow@hetp.u-net.com

Hi there, here my review.
Please always state in your review, whether you think the library should be accepted as a Boost library!
yes, please.
- What is your evaluation of the design? The design is simple and easy to understand. The learning curve is expectically very low.
- What is your evaluation of the implementation?
Somebody else on this list was mentioning of a conflicting license issue with sha1.hpp. This should be resolved before adding this lib to boost. Same as Dan Nuffer I would like to see a way to change the default random number generator.
- What is your evaluation of the documentation? Good enough.
- What is your evaluation of the potential usefulness of the library? I use it for over half a year now and haven't created the a equal guid yet. ;-)
- Did you try to use the library? With what compiler? Did you have any problems?
Yes. I'm using it at work already.
- How much effort did you put into your evaluation? A glance? A quick reading? In-depth study?
I'm using the lib for a while already and I have nothing to complain. The learning curve really isn't that huge either.
- Are you knowledgeable about the problem domain?
No. All I need is way to generate ids that are unique. Thanks for another useful lib. Christian

"Christian Henning" <chhenning@gmail.com> wrote in news:949801310705041848i4d355ec4oc17cc9b991651fe0@mail.gmail.com:
Hi there, here my review.
- What is your evaluation of the implementation?
Somebody else on this list was mentioning of a conflicting license issue with sha1.hpp. This should be resolved before adding this lib to boost.
The sha1 code comes with a license.txt file (included in boost\guid\, I could copy this text to sha1.hpp) that contains the following: Copyright (C) 1998 Paul E. Jones <paulej@arid.us> All Rights Reserved. This software is licensed as "freeware." Permission to distribute this software in source and binary forms is hereby granted without a fee. THIS SOFTWARE IS PROVIDED 'AS IS' AND WITHOUT ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHOR SHALL NOT BE HELD LIABLE FOR ANY DAMAGES RESULTING FROM THE USE OF THIS SOFTWARE, EITHER DIRECTLY OR INDIRECTLY, INCLUDING, BUT NOT LIMITED TO, LOSS OF DATA OR DATA BEING RENDERED INACCURATE. I believe that this allows it to be used in boost. I do not know for sure. I would value an opinion from someone who is qualified to know for sure.
Same as Dan Nuffer I would like to see a way to change the default random number generator.
See another post. < snip >
Thanks for another useful lib.
Christian _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

Hartmut Kaiser wrote:
Hi all,
This is just a gentle reminder that the review for the proposed Boost.Guid library is still ongoing. This is not a lare library, but nevertheless a important one, IMHO.
Please try to find some time to go over the documentation or the code to give your opinion and don't forget your vote.
This is not my formal review. I vote to accept the library, but have a consideration about the SHA-1 algorithm it uses. Because SHA-1 is very useful, would it be better to put it outside of guid library, maybe to a new library or boost/utility, so users can use it alone?

I think that the library is useful, needed and should be accepted subject to the comments below. * The proper (standard) name for the component is UUID. GUID is a Microsoft-specific term for the same thing, which has later been adopted to mean any kind of globally unique identifier. We should stick to the standard name unless there are clear reasons to avoid it. * I agree that the time(0) seed is unacceptable. A good source of entropy probably deserves its own library. It's also not easy to make it header-only. One compromise could be for the create function to take an Engine argument, but this takes away the simplicity. * The dependency on Boost.Threads in its present form can be dropped since it doesn't make the library thread safe. There are a number of function static variables, many of them unnecessary. * The string constructors should probably be optimized to not use iostream extraction, but this is an implementation detail. * The guid class is almost a container, but not quite. It is not clear why output_bytes has been preferred over begin/end returning const iterators. These could come for free from the underlying array<>. * The dependency on uint8_t is unnecessary; the underlying type should be unsigned char. There is no need to insist on exactly 8 bits. * The c == '{' comparison in operator>> seems to be missing a 'widen' call. There is no guarantee that '{' and L'{' compare equal. * It isn't clear why a guid is marked as a primitive type for serialization purposes. Not doing so would allow the macro BOOST_GUID_ENABLE_SERIALIZATION to be dropped since friend class boost::serialization::access; template<class Archive> void serialize(Archive &ar, const unsigned int /* file_version */){ ar & data_; } does not seem to need any serialization headers and is therefore zero-cost.

On 5 May 2007, at 06:16, Peter Dimov wrote:
* It isn't clear why a guid is marked as a primitive type for serialization purposes. Not doing so would allow the macro BOOST_GUID_ENABLE_SERIALIZATION to be dropped since
friend class boost::serialization::access;
template<class Archive> void serialize(Archive &ar, const unsigned int /* file_version */){ ar & data_; }
One will still need to include the serialization header to serialize boost::array . Matthias

Matthias Troyer wrote:
On 5 May 2007, at 06:16, Peter Dimov wrote:
* It isn't clear why a guid is marked as a primitive type for serialization purposes. Not doing so would allow the macro BOOST_GUID_ENABLE_SERIALIZATION to be dropped since
friend class boost::serialization::access;
template<class Archive> void serialize(Archive &ar, const unsigned int /* file_version */){ ar & data_; }
One will still need to include the serialization header to serialize boost::array .
Which serialization header?

On 6 May 2007, at 14:38, Peter Dimov wrote:
Matthias Troyer wrote:
On 5 May 2007, at 06:16, Peter Dimov wrote:
* It isn't clear why a guid is marked as a primitive type for serialization purposes. Not doing so would allow the macro BOOST_GUID_ENABLE_SERIALIZATION to be dropped since
friend class boost::serialization::access;
template<class Archive> void serialize(Archive &ar, const unsigned int /* file_version */){ ar & data_; }
One will still need to include the serialization header to serialize boost::array .
Which serialization header?
Actually there is no serialization support for boost::array yet, and the test thus should not even compile. Looking more closely I realized that the test contains the following lines: test_archive<text_oarchive, text_iarchive, ostringstream, istringstream>(); test_archive<xml_oarchive, xml_iarchive, ostringstream, istringstream>(); //test_archive<binary_oarchive, binary_iarchive, ostringstream, istringstream>(); test_archive<text_woarchive, text_wiarchive, wostringstream, wistringstream>(); The binary test has been commented out exactly because it does not work since there is no serialization support for boost::array. Why does it work at all for the text based archives? Digging into the code I realized that the reason is just that the type is marked as a primitive type. This means that instead of using the serialize function of the class, the serialization library requires the archive to be able to deal with the type directly. This works for tetx based archives since there is an operator<< to write the guid class into a std::ostream. Thus, to summarize, the serialization of guid does not work since there is no serialization support for boost::array yet. This bug was masked by decalring the type primitive which works - by chance not not intent - for the text based archives. In order to fix serialization one has to - remove the declaration as primitive type - write serialization support for boost::array - include that header Matthias

Matthias Troyer wrote:
Thus, to summarize, the serialization of guid does not work since there is no serialization support for boost::array yet. This bug was masked by decalring the type primitive which works - by chance not not intent - for the text based archives. In order to fix serialization one has to
- remove the declaration as primitive type - write serialization support for boost::array - include that header
Follow-up question. What needs to be included if guid::data_ is defined as unsigned char[16] instead of boost::array?

On 6 May 2007, at 17:24, Peter Dimov wrote:
Matthias Troyer wrote:
Thus, to summarize, the serialization of guid does not work since there is no serialization support for boost::array yet. This bug was masked by decalring the type primitive which works - by chance not not intent - for the text based archives. In order to fix serialization one has to
- remove the declaration as primitive type - write serialization support for boost::array - include that header
Follow-up question. What needs to be included if guid::data_ is defined as unsigned char[16] instead of boost::array?
In that case the standard headers included by the archive class will have all necessary functions and no header will need to be included by the guid library

Matthias Troyer <troyer@phys.ethz.ch> wrote in news:E182D037-0155-4C8B-9202-5F7248CE35AB@phys.ethz.ch:
On 6 May 2007, at 17:24, Peter Dimov wrote:
Matthias Troyer wrote:
Thus, to summarize, the serialization of guid does not work since there is no serialization support for boost::array yet. This bug was masked by decalring the type primitive which works - by chance not not intent - for the text based archives. In order to fix serialization one has to
- remove the declaration as primitive type - write serialization support for boost::array - include that header
I declared the guid type as a primitive because I believed that it made sense for it to be a primitive. I only wanted 16 bytes to be written when using a binary archive. Thank you for looking in to this! I didn't know why it didn't work for binary archives or why it did work for text archives. I meant to get back to this but forgot. I had no idea that marking it primitive masked these problems and by chance it worked. I don't know a lot about the Boost Serialization library, but I want to make guids serializable. If it shouldn't be a primitive type, then I won't make it one.
Follow-up question. What needs to be included if guid::data_ is defined as unsigned char[16] instead of boost::array?
If this is best, I'll do this. No problem. I guess sometimes I go a little overboard and use boost libraries when I don't need to.
In that case the standard headers included by the archive class will have all necessary functions and no header will need to be included by the guid library
Andy.

On 7 May 2007, at 17:38, Andy wrote:
Matthias Troyer <troyer@phys.ethz.ch> wrote in news:E182D037-0155-4C8B-9202-5F7248CE35AB@phys.ethz.ch:
On 6 May 2007, at 17:24, Peter Dimov wrote:
Matthias Troyer wrote:
Thus, to summarize, the serialization of guid does not work since there is no serialization support for boost::array yet. This bug was masked by decalring the type primitive which works - by chance not not intent - for the text based archives. In order to fix serialization one has to
- remove the declaration as primitive type - write serialization support for boost::array - include that header
I declared the guid type as a primitive because I believed that it made sense for it to be a primitive. I only wanted 16 bytes to be written when using a binary archive. Thank you for looking in to this! I didn't know why it didn't work for binary archives or why it did work for text archives. I meant to get back to this but forgot. I had no idea that marking it primitive masked these problems and by chance it worked. I don't know a lot about the Boost Serialization library, but I want to make guids serializable. If it shouldn't be a primitive type, then I won't make it one.
Follow-up question. What needs to be included if guid::data_ is defined as unsigned char[16] instead of boost::array?
If this is best, I'll do this. No problem. I guess sometimes I go a little overboard and use boost libraries when I don't need to.
It might be easier to just add a one-line serialize function- that does not need to pull in any header - to boost/array.hpp Matthias

On 5 May 2007, at 06:16, Peter Dimov wrote:
* I agree that the time(0) seed is unacceptable. A good source of entropy probably deserves its own library. It's also not easy to make it header-only. One compromise could be for the create function to take an Engine argument, but this takes away the simplicity.
How about just adding an additional create function that takes an engine?

Matthias Troyer wrote:
On 5 May 2007, at 06:16, Peter Dimov wrote:
* I agree that the time(0) seed is unacceptable. A good source of entropy probably deserves its own library. It's also not easy to make it header-only. One compromise could be for the create function to take an Engine argument, but this takes away the simplicity.
How about just adding an additional create function that takes an engine?
The existing create function is dangerous as it doesn't generate reasonably unique identifiers. We can't fix that by adding more overloads.

On 6 May 2007, at 14:37, Peter Dimov wrote:
Matthias Troyer wrote:
On 5 May 2007, at 06:16, Peter Dimov wrote:
* I agree that the time(0) seed is unacceptable. A good source of entropy probably deserves its own library. It's also not easy to make it header-only. One compromise could be for the create function to take an Engine argument, but this takes away the simplicity.
How about just adding an additional create function that takes an engine?
The existing create function is dangerous as it doesn't generate reasonably unique identifiers. We can't fix that by adding more overloads.
I fully agree that it is very dangerous, especially on parallel machines. However, in addition to fixing this, it would be good to have the engine be customizable. Matthias

Matthias Troyer <troyer@phys.ethz.ch> wrote in news:F45D2822-2671-4B1B-B930-3A56E9CEF1C5@phys.ethz.ch:
On 6 May 2007, at 14:37, Peter Dimov wrote:
Matthias Troyer wrote:
On 5 May 2007, at 06:16, Peter Dimov wrote:
* I agree that the time(0) seed is unacceptable. A good source of entropy probably deserves its own library. It's also not easy to make it header-only. One compromise could be for the create function to take an Engine argument, but this takes away the simplicity.
How about just adding an additional create function that takes an engine?
The existing create function is dangerous as it doesn't generate reasonably unique identifiers. We can't fix that by adding more overloads.
I fully agree that it is very dangerous, especially on parallel machines. However, in addition to fixing this, it would be good to have the engine be customizable.
Matthias
I agree that the create function needs improvement. It suffers from threading problems (because of static variables) and from a hard coded random number generator (also a hard coded seed). My solution is to create a generator class, as follows: // maybe a better name // maybe a different default random number generator template <typename UniformRandomNumberGenerator = boost::mt19937> class random_guid_generator : boost::noncopyable { typedef boost::uniform_int<uint8_t> DistributionType; public: explicit random_guid_generator(UniformRandomNumberGenerator& engine = boost::mt19937(time(0))) : engine_(engine) , generator_(engine_, DistributionType(0, 255)) {} guid create() { guid g; // create guid using generator_() return g; } private: UniformRandomNumberGenerator& engine_; boost::variate_generator<UniformRandomNumberGenerator&, DistributionType> generator_; }; to be used like: random_guid_generator<> guid_gen; guid g = guid_gen.create(); or: uint32_t seed = 0; // get good seed boost::lagged_fibonacci44497 engine(seed); random_guid_generator<boost::lagged_fibonacci44497> guid_gen(engine); guid g = guid_gen.create(); or: boost::random_device engine; random_guid_generator<boost::random_device> guid_gen(engine); guid g = guid_gen.create(); One could have a random_guid_generator per thread/processor/... solving the threading problems. Also one can provide any random number generator that satisfies the Uniform Random Number Generator concept from the Boost.Random library. Andy.

Andy wrote:
I agree that the create function needs improvement. It suffers from threading problems (because of static variables) and from a hard coded random number generator (also a hard coded seed).
My solution is to create a generator class, as follows:
// maybe a better name // maybe a different default random number generator template <typename UniformRandomNumberGenerator = boost::mt19937> class random_guid_generator : boost::noncopyable
[...]
random_guid_generator<> guid_gen; guid g = guid_gen.create();
Why not just add an Engine & e parameter to guid::create? For the default seed, you might want to look into combining several sources of entropy (unpredictable values) such as - time(0) - clock() - the values of an unsigned char[] array that is allocated on the stack and not initialized - the addresses of some variables or functions - the address of a newly allocated object - anything else that you can come up with

"Peter Dimov" <pdimov@mmltd.net> wrote in news:002e01c790c0$0f2d3510$6407a80a@pdimov2:
Andy wrote:
I agree that the create function needs improvement. It suffers from threading problems (because of static variables) and from a hard coded random number generator (also a hard coded seed).
My solution is to create a generator class, as follows:
// maybe a better name // maybe a different default random number generator template <typename UniformRandomNumberGenerator = boost::mt19937> class random_guid_generator : boost::noncopyable
[...]
random_guid_generator<> guid_gen; guid g = guid_gen.create();
Why not just add an Engine & e parameter to guid::create?
Good idea. Something like: template<typename Engine> boost::guid guid::create(Engine& e = boost::mt19937(get_seed())); where get_seed() does something like what you said below. I want to be able to call the create function with a default Engine because I don't want to force users to create one themselves. The only downside is for people who do want a different engine/seed, they will have to pass that engine to the function everytime they call it.
For the default seed, you might want to look into combining several sources of entropy (unpredictable values) such as
- time(0) - clock() - the values of an unsigned char[] array that is allocated on the stack and not initialized - the addresses of some variables or functions - the address of a newly allocated object - anything else that you can come up with
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Andy.

Andy wrote:
"Peter Dimov" <pdimov@mmltd.net> wrote in news:002e01c790c0$0f2d3510$6407a80a@pdimov2:
Andy wrote:
I agree that the create function needs improvement. It suffers from threading problems (because of static variables) and from a hard coded random number generator (also a hard coded seed).
My solution is to create a generator class, as follows:
// maybe a better name // maybe a different default random number generator template <typename UniformRandomNumberGenerator = boost::mt19937> class random_guid_generator : boost::noncopyable
[...]
random_guid_generator<> guid_gen; guid g = guid_gen.create();
Why not just add an Engine & e parameter to guid::create?
Good idea. Something like:
template<typename Engine> boost::guid guid::create(Engine& e = boost::mt19937(get_seed()));
[sorry for jumping in] That would need to be "Engine const&", right?
where get_seed() does something like what you said below.
I want to be able to call the create function with a default Engine because I don't want to force users to create one themselves.
I'd suggest to rather use an overload of create with zero arguments. Helps if the methods are ever used with function binding.
The only downside is for people who do want a different engine/seed, they will have to pass that engine to the function everytime they call it.
Yes, people are likely to go for one specific engine within a specific context (e.g. application). Perhaps a _complementing_ guid_factory would be usable for people preferring the generator/factory interface you mentioned above. template<typename Engine> class guid_factory{ ... explicit guid_factory(Engine const& e = Engine()) : e_(e) {} guid create_guid() [const?] { return guid::create(e_); } ... [mutable?] Engine e_; }; / Johan

"Johan Nilsson" <r.johan.nilsson@gmail.com> wrote in news:f1p510$eig$1@sea.gmane.org:
Andy wrote:
"Peter Dimov" <pdimov@mmltd.net> wrote in news:002e01c790c0$0f2d3510$6407a80a@pdimov2:
Andy wrote:
I agree that the create function needs improvement. It suffers from threading problems (because of static variables) and from a hard coded random number generator (also a hard coded seed).
My solution is to create a generator class, as follows:
// maybe a better name // maybe a different default random number generator template <typename UniformRandomNumberGenerator = boost::mt19937> class random_guid_generator : boost::noncopyable
[...]
random_guid_generator<> guid_gen; guid g = guid_gen.create();
Why not just add an Engine & e parameter to guid::create?
Good idea. Something like:
template<typename Engine> boost::guid guid::create(Engine& e = boost::mt19937(get_seed()));
[sorry for jumping in]
That would need to be "Engine const&", right?
Right.
where get_seed() does something like what you said below.
I want to be able to call the create function with a default Engine because I don't want to force users to create one themselves.
I'd suggest to rather use an overload of create with zero arguments. Helps if the methods are ever used with function binding.
Sure. template <typename Engine> boost::guid guid::create(Engine& engine) { ... } boost::guid guid::create() { boost::mt19937 engine(get_seed()); return create(engine); }
The only downside is for people who do want a different engine/seed, they will have to pass that engine to the function everytime they call it.
Yes, people are likely to go for one specific engine within a specific context (e.g. application). Perhaps a _complementing_ guid_factory would be usable for people preferring the generator/factory interface you mentioned above.
template<typename Engine> class guid_factory{ ... explicit guid_factory(Engine const& e = Engine()) : e_(e) {}
guid create_guid() [const?] { return guid::create(e_); } ... [mutable?] Engine e_; };
/ Johan
Good idea. Provide both. Andy.

Matthias Troyer <troyer@phys.ethz.ch> wrote in news:F45D2822-2671-4B1B-B930-3A56E9CEF1C5@phys.ethz.ch:
On 6 May 2007, at 14:37, Peter Dimov wrote:
Matthias Troyer wrote:
On 5 May 2007, at 06:16, Peter Dimov wrote:
* I agree that the time(0) seed is unacceptable. A good source of entropy probably deserves its own library. It's also not easy to make it header-only. One compromise could be for the create function to take an Engine argument, but this takes away the simplicity.
How about just adding an additional create function that takes an engine?
The existing create function is dangerous as it doesn't generate reasonably unique identifiers. We can't fix that by adding more overloads.
I fully agree that it is very dangerous, especially on parallel machines. However, in addition to fixing this, it would be good to have the engine be customizable.
Does the solution I presented here: http://article.gmane.org/gmane.comp.lib.boost.devel/158740 solve the problem? For parallel machines?
Matthias
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Andy.

On 7 May 2007, at 17:40, Andy wrote:
Does the solution I presented here: http://article.gmane.org/gmane.comp.lib.boost.devel/158740 solve the problem? For parallel machines?
Why don't you just put that code into a create function that takes an engine as argument? Matthias

Dear Andy, I remember that serialization library needs some sort of unique identifier. Currently it uses a class name. But Robert said several times that he will gladly allow using some other unique identifier. Is your library prepared for that? When the identifier is assigned? - when the program starts? - when the code is compiled? - when an attempt to read identifier for a given class is made? Is the identifier the same across several program runs? (serialization library needs that to properly distinguish classes ;) Is it possible to get an identifier of a class: - during compilation (so it could be used in template metaprogramming, typedeffed enums or in #defines) - during runtime when only a polymorphic(!) class instance is provided (eg. I got a class Shape and classes Square and Circle deriving from it. Then I want to get a unique identifier to distinguish whether a pointer Shape* is a Square* or a Circle*) - during runtime when only a type is provided? Not an instance of a class. Is it possible to tell your library to assign numbers not random, but incrementing sequentially, starting from some given number? Maybe that's unfeasible, why? Is the unique identifier an 'int' number, or is it custom? Maybe a string? If the deadline can be extended till 11 or 12 May I should be able to write a review. Currently I completely have no time even to look at the documentation. However I'm curious to see your answers to my questions above. I'm particularly interested in using your library in multimethods (see. Andrei Alexandrescu "Modern C++ Design" to check what's that ;) for constant time dispatch (classes will be indexed by their identifier). best regards -- Janek Kozicki |

Janek Kozicki <janek_listy@wp.pl> wrote in news:20070506182937.0da237c8@absurd:
Dear Andy,
I remember that serialization library needs some sort of unique identifier. Currently it uses a class name. But Robert said several times that he will gladly allow using some other unique identifier. Is your library prepared for that?
I believe that my library can be used for this. I would gladly look into any issues. I do not know a lot about the Boost Serialization library but I do see the BOOST_CLASS_EXPORT_GUID macro. One could write: class my_class { public: static const my_class_guid("1234...."); }; BOOST_CLASS_EXPORT_GUID(my_class, my_class_guid.to_string());
When the identifier is assigned? - when the program starts?
I believe this is the case.
- when the code is compiled?
My guid library can not generate guids at compile time.
- when an attempt to read identifier for a given class is made?
Is the identifier the same across several program runs? (serialization library needs that to properly distinguish classes ;)
Yes, if one types in the guid as a string.
Is it possible to get an identifier of a class:
- during compilation (so it could be used in template metaprogramming, typedeffed enums or in #defines)
No.
- during runtime when only a polymorphic(!) class instance is provided (eg. I got a class Shape and classes Square and Circle deriving from it. Then I want to get a unique identifier to distinguish whether a pointer Shape* is a Square* or a Circle*)
yes.
- during runtime when only a type is provided? Not an instance of a class.
yes.
Is it possible to tell your library to assign numbers not random, but incrementing sequentially, starting from some given number? Maybe that's unfeasible, why?
yes. Just use one of the constructors.
Is the unique identifier an 'int' number, or is it custom? Maybe a string?
It is a custom type, a 16 byte number that has a string representation.
If the deadline can be extended till 11 or 12 May I should be able to write a review. Currently I completely have no time even to look at the documentation. However I'm curious to see your answers to my questions above.
I'm particularly interested in using your library in multimethods (see. Andrei Alexandrescu "Modern C++ Design" to check what's that ;) for constant time dispatch (classes will be indexed by their identifier).
Multimethods do something based on the dynamic type of two or more parameters. I see no reason why this could not work for multimethods. One way would be to have a virtual base class method return the guid of the class and each derived class would return the correct guid. The multimethod could determine what to do based on this information.
best regards
Andy.

"Peter Dimov" <pdimov@mmltd.net> wrote in news:00dd01c78f17$ba7e5610$6407a80a@pdimov2:
I think that the library is useful, needed and should be accepted subject to the comments below.
* The proper (standard) name for the component is UUID. GUID is a Microsoft-specific term for the same thing, which has later been adopted to mean any kind of globally unique identifier. We should stick to the standard name unless there are clear reasons to avoid it.
This has been suggested before and I will gladly change it to uuid.
* I agree that the time(0) seed is unacceptable. A good source of entropy probably deserves its own library. It's also not easy to make it header-only. One compromise could be for the create function to take an Engine argument, but this takes away the simplicity.
See another post. http://article.gmane.org/gmane.comp.lib.boost.devel/158740 I hope that the defaults will keep the simplicity.
* The dependency on Boost.Threads in its present form can be dropped since it doesn't make the library thread safe. There are a number of function static variables, many of them unnecessary.
Agreed.
* The string constructors should probably be optimized to not use iostream extraction, but this is an implementation detail.
I can look into this.
* The guid class is almost a container, but not quite. It is not clear why output_bytes has been preferred over begin/end returning const iterators. These could come for free from the underlying array<>.
Great idea! I didn't want to make it easy to directly change values. I didn't think of providing just const iterators.
* The dependency on uint8_t is unnecessary; the underlying type should be unsigned char. There is no need to insist on exactly 8 bits.
Ok. If unsigned char is more than 8 bits then sizeof(guid) would be larger. Maybe this is not an issue.
* The c == '{' comparison in operator>> seems to be missing a 'widen' call. There is no guarantee that '{' and L'{' compare equal.
Thanks. I get a little lost with this sort of stuff sometimes. Just to help me, who provides the 'widen' function? The stream?
* It isn't clear why a guid is marked as a primitive type for serialization purposes. Not doing so would allow the macro BOOST_GUID_ENABLE_SERIALIZATION to be dropped since
friend class boost::serialization::access;
template<class Archive> void serialize(Archive &ar, const unsigned int /* file_version */){ ar & data_; }
does not seem to need any serialization headers and is therefore zero-cost.
I want to read the other post about this before I reply. Andy.

Andy wrote:
* The dependency on uint8_t is unnecessary; the underlying type should be unsigned char. There is no need to insist on exactly 8 bits.
Ok. If unsigned char is more than 8 bits then sizeof(guid) would be larger. Maybe this is not an issue.
If unsigned char is more than 8 bits uint8_t will not be defined. unsigned char is the smallest type; its sizeof() is always 1.

"Peter Dimov" <pdimov@mmltd.net> wrote in news:001d01c790bf$1d844730$6407a80a@pdimov2:
Andy wrote:
* The dependency on uint8_t is unnecessary; the underlying type should be unsigned char. There is no need to insist on exactly 8 bits.
Ok. If unsigned char is more than 8 bits then sizeof(guid) would be larger. Maybe this is not an issue.
If unsigned char is more than 8 bits uint8_t will not be defined. unsigned char is the smallest type; its sizeof() is always 1.
Thanks! I didn't know that. Could unsigned char be less than 8 bits? Does boost provide uint8_t just to be complete with uint?_t types? Andy.

Andy wrote:
* The c == '{' comparison in operator>> seems to be missing a 'widen' call. There is no guarantee that '{' and L'{' compare equal.
Thanks. I get a little lost with this sort of stuff sometimes. Just to help me, who provides the 'widen' function? The stream?
Yes, I think that the stream provides a widen() member function.

"Peter Dimov" <pdimov@mmltd.net> wrote in news:002f01c790c0$0f8a2220$6407a80a@pdimov2:
Andy wrote:
* The c == '{' comparison in operator>> seems to be missing a 'widen' call. There is no guarantee that '{' and L'{' compare equal.
Thanks. I get a little lost with this sort of stuff sometimes. Just to help me, who provides the 'widen' function? The stream?
Yes, I think that the stream provides a widen() member function.
Thanks. Andy.

- What is your evaluation of the design?
I like the general design. It is easy enough to use.
- What is your evaluation of the implementation?
I'd really like to see the MAC address + time generator. I realize that this might be a pain to do in a cross-platform manner, but it would make the library more complete in my eyes, and more likely for me to recommend it to my colleagues. Is there a way that the library could be engineered so that we could provide our own generation implementation?
- What is your evaluation of the documentation?
I don't like it's organization. I'd much rather see it start out with the Rationale section followed by a simple example of the most likely used scenario. I think this is what most users are expecting to see who haven't used the library before and want to get started quickly. You have to weed into the documentation a while before you run into the first generation examples, which is what I think most people will be intereste in. If you need to put the "Class guid synopsis" in the docs, I'd put it near the end since it is more-or-less a dump of the uncommented header file.
- What is your evaluation of the potential usefulness of the library?
A good, cross-platform, UUID library is extremely useful. Without the guaruntee of uniqueness provided by MAC address + time, it isn't as useful for my situation. We have data generated across a large number of disconnected computers (I highly doubt there would see a duplicate, but in my case, we can't take the risk).
- Did you try to use the library? With what compiler? Did you have any problems?
Played around with it with Apple's version of gcc 4. Worked fine.
- How much effort did you put into your evaluation? A glance? A quick reading? In-depth study?
I read through the docs pretty thuroughly, and the implementation.
- Are you knowledgeable about the problem domain?
I've used several libraries for different purposes. I have developed a crossplatform wrapper in the past for platform specific libraries, but have not had to implement that actual generator before. I have a hard time saying that I'd recommend it for the library or not. I think it would cover a lot of people's needs, but does fall a little short in cases where you have to be absolutely sure that the generated ID will be unique across systems. That is unless I'm miss-understanding how these are generated.

Jared McIntyre <jmcintyre@dfsoftware.com> wrote in news:loom.20070507T004550-745@post.gmane.org: < snip >
I'd really like to see the MAC address + time generator. I realize that this might be a pain to do in a cross-platform manner, but it would make the library more complete in my eyes, and more likely for me to recommend it to my colleagues. Is there a way that the library could be engineered so that we could provide our own generation implementation?
I agree that it would be very useful to have a time based guid generator. I will continue to look in to this. In the meantime, one could write a function to create guids based on anything they want, eg: boost::guid create() { //generate a guid or values for a guid in the way you want //a platform specific call, MAC address+time generator function //call a boost::guid constructor with either the values //or a string representation of the values boost::guid g(guid_string); return g; }
- What is your evaluation of the documentation?
I don't like it's organization. I'd much rather see it start out with the Rationale section followed by a simple example of the most likely used scenario. I think this is what most users are expecting to see who haven't used the library before and want to get started quickly. You have to weed into the documentation a while before you run into the first generation examples, which is what I think most people will be intereste in. If you need to put the "Class guid synopsis" in the docs, I'd put it near the end since it is more-or-less a dump of the uncommented header file.
I can reorder the docs if that helps people use the library better.
- What is your evaluation of the potential usefulness of the library?
A good, cross-platform, UUID library is extremely useful. Without the guaruntee of uniqueness provided by MAC address + time, it isn't as useful for my situation. We have data generated across a large number of disconnected computers (I highly doubt there would see a duplicate, but in my case, we can't take the risk).
This could also be done in a way using the name-based guid create function. See http://article.gmane.org/gmane.comp.lib.boost.devel/154791 < snip > Andy.

I'd really like to see the MAC address + time generator. I realize that this might be a pain to do in a cross-platform manner, but it would make the library more complete in my eyes, and more likely for me to recommend it to my colleagues. Is there a way that the library could be engineered so that we could provide our own generation implementation?
I agree that it would be very useful to have a time based guid generator. I will continue to look in to this. In the meantime, one could write a function to create guids based on anything they want, eg:
How useful can seed using MAC address + time be in system with multiple cores? Shouldn't it be CoreID + time? Just image you have 16 cores and just one MAC address. Is such an assumption valid to make? Christian

On 7 May 2007, at 19:41, Christian Henning wrote:
I'd really like to see the MAC address + time generator. I realize that this might be a pain to do in a cross-platform manner, but it would make the library more complete in my eyes, and more likely for me to recommend it to my colleagues. Is there a way that the library could be engineered so that we could provide our own generation implementation?
I agree that it would be very useful to have a time based guid generator. I will continue to look in to this. In the meantime, one could write a function to create guids based on anything they want, eg:
How useful can seed using MAC address + time be in system with multiple cores? Shouldn't it be CoreID + time? Just image you have 16 cores and just one MAC address. Is such an assumption valid to make?
You would need process/thread number + mac address + time Matthias

How useful can seed using MAC address + time be in system with multiple cores? Shouldn't it be CoreID + time? Just image you have 16 cores and just one MAC address. Is such an assumption valid to make?
You would need process/thread number + mac address + time
Hmm - the RFC 4122 doesn't tell anything about threads. Version 1 UUIDs are generated according to the following algorithm: o Determine the values for the UTC-based timestamp and clock sequence to be used in the UUID, as described in Section 4.2.1. o For the purposes of this algorithm, consider the timestamp to be a 60-bit unsigned integer and the clock sequence to be a 14-bit unsigned integer. Sequentially number the bits in a field, starting with zero for the least significant bit. o Set the time_low field equal to the least significant 32 bits (bits zero through 31) of the timestamp in the same order of significance. o Set the time_mid field equal to bits 32 through 47 from the timestamp in the same order of significance. o Set the 12 least significant bits (bits zero through 11) of the time_hi_and_version field equal to bits 48 through 59 from the timestamp in the same order of significance. o Set the four most significant bits (bits 12 through 15) of the time_hi_and_version field to the 4-bit version number corresponding to the UUID version being created, as shown in the table above. o Set the clock_seq_low field to the eight least significant bits (bits zero through 7) of the clock sequence in the same order of significance. o Set the 6 least significant bits (bits zero through 5) of the clock_seq_hi_and_reserved field to the 6 most significant bits (bits 8 through 13) of the clock sequence in the same order of significance. o Set the two most significant bits (bits 6 and 7) of the clock_seq_hi_and_reserved to zero and one, respectively. o Set the node field to the 48-bit IEEE address in the same order of significance as the address. Oliver

<Oliver.Kowalke@qimonda.com> wrote in news:B1EAFF2DAE7658488B631F25813CD91F0137D996@drsse602.eu.infineon.com:
How useful can seed using MAC address + time be in system with multiple cores? Shouldn't it be CoreID + time? Just image you have 16 cores and just one MAC address. Is such an assumption valid to make?
You would need process/thread number + mac address + time
Hmm - the RFC 4122 doesn't tell anything about threads.
This is not exactly true. The first step in their basic algorithm (4.2.1) is to obtain a system-wide global lock. This lock ensures that each guid has a different time stamp. Often an implementation strays from the standard by adding in a process/thread/core number to avoid a global lock. It also talks about an optimization (in 4.2.1.4) that allocates a block of time stamps at a time and a per-process generator can allocate from that block until it is exhausted.
Version 1 UUIDs are generated according to the following algorithm:
o Determine the values for the UTC-based timestamp and clock sequence to be used in the UUID, as described in Section 4.2.1.
< snip >
Oliver
Andy.

Andy <atompkins <at> fastmail.fm> writes: < snip >
A good, cross-platform, UUID library is extremely useful. Without the guaruntee of uniqueness provided by MAC address + time, it isn't as useful for my situation. We have data generated across a large number of disconnected computers (I highly doubt there would see a duplicate, but in my case, we can't take the risk).
This could also be done in a way using the name-based guid create function.
See http://article.gmane.org/gmane.comp.lib.boost.devel/154791
I thought about that, and for most people I think this would work well. The most obvious way would be to use the computer name, since that is usually unique. However, in my weird situation, we have computers all over the world, and they all have the same name. So, I'd have to come up with another way to get a unique name. We would most likely just keep using the same mechanism we have now. I do like what you have done so far, my situation is a bit on the extreme side with our uniqueness requirements. Jared

Jared McIntyre <jmcintyre@dfsoftware.com> wrote in news:loom.20070508T183548-374@post.gmane.org:
Andy <atompkins <at> fastmail.fm> writes:
< snip >
A good, cross-platform, UUID library is extremely useful. Without the guaruntee of uniqueness provided by MAC address + time, it isn't as useful for my situation. We have data generated across a large number of disconnected computers (I highly doubt there would see a duplicate, but in my case, we can't take the risk).
This could also be done in a way using the name-based guid create function.
See http://article.gmane.org/gmane.comp.lib.boost.devel/154791
I thought about that, and for most people I think this would work well. The most obvious way would be to use the computer name, since that is usually unique. However, in my weird situation, we have computers all over the world, and they all have the same name. So, I'd have to come up with another way to get a unique name. We would most likely just keep using the same mechanism we have now.
I do like what you have done so far, my situation is a bit on the extreme side with our uniqueness requirements.
Jared
Maybe this solution will never work in your situation, I'm not sure. But the 'unique computer name' could be the mac address instead of the computer name. If not, I would expect that there is some piece of information that is unique for each of your machines that you could use. But maybe not. I hope that one day this library will have a solution for you. Andy.

Hello, Instead of bool is_null() const and static guid const& null() I would prefer bool is_nil() const and static guid const& nil(). I'de like to see uuid v1 (node hardware address + time based). Access to MAC: - on HP/UX you could use DLPI interface (example: http://h10025.www1.hp.com/ewfrf/wc/genericDocument?docname=c00904700&cc= us&dlc=en&lc=en&jumpid=reg_R1002_USEN) - ::ioctl + SIOCGIFHWADDR on Linux Because my apps are bloated if I use some header-only libraries from boost I'de like to see guid library not as header-only library - but this was already discussed in this mailing list. Regards, Oliver

Oliver.Kowalke@qimonda.com wrote:
Hello,
Instead of bool is_null() const and static guid const& null() I would prefer bool is_nil() const and static guid const& nil().
null()/nil() are actually redundant and only contribute thread safety problems. The default constructor already creates a NULL UUID, as it should.

"Peter Dimov" <pdimov@mmltd.net> wrote in news:00b601c790ad$8e357b00$6407a80a@pdimov2:
Oliver.Kowalke@qimonda.com wrote:
Hello,
Instead of bool is_null() const and static guid const& null() I would prefer bool is_nil() const and static guid const& nil().
null()/nil() are actually redundant and only contribute thread safety problems. The default constructor already creates a NULL UUID, as it should.
I agree that they are redundant. I am not pushing them, but just wondering why they would contribute to thread safety problems since they return a constant object? Andy.

Andy wrote:
"Peter Dimov" <pdimov@mmltd.net> wrote in news:00b601c790ad$8e357b00$6407a80a@pdimov2:
null()/nil() are actually redundant and only contribute thread safety problems. The default constructor already creates a NULL UUID, as it should.
I agree that they are redundant. I am not pushing them, but just wondering why they would contribute to thread safety problems since they return a constant object?
Because of the local static variable.

"Peter Dimov" <pdimov@mmltd.net> wrote in news:01c201c7919b$0a73fb40$6407a80a@pdimov2:
Andy wrote:
"Peter Dimov" <pdimov@mmltd.net> wrote in news:00b601c790ad$8e357b00$6407a80a@pdimov2:
null()/nil() are actually redundant and only contribute thread safety problems. The default constructor already creates a NULL UUID, as it should.
I agree that they are redundant. I am not pushing them, but just wondering why they would contribute to thread safety problems since they return a constant object?
Because of the local static variable.
Ah! Multiple threads may try to initialize the variable at the same time. If it could be initialized correctly, there wouldn't be a problem. Thanks. Andy.

Andy wrote:
"Peter Dimov" <pdimov@mmltd.net> wrote in news:01c201c7919b$0a73fb40$6407a80a@pdimov2:
Andy wrote:
"Peter Dimov" <pdimov@mmltd.net> wrote in news:00b601c790ad$8e357b00$6407a80a@pdimov2:
null()/nil() are actually redundant and only contribute thread safety problems. The default constructor already creates a NULL UUID, as it should.
I agree that they are redundant. I am not pushing them, but just wondering why they would contribute to thread safety problems since they return a constant object?
Because of the local static variable.
Ah! Multiple threads may try to initialize the variable at the same time. If it could be initialized correctly, there wouldn't be a problem.
... which people have been writing essays about (i.e. thread-safe local static initialization). You could use boost::once, but that feels like rather heavy-weight for this specific case. FWIW, I like the concept of an explicit "null" object instead of relying on a default-constructed guid being equivalent to a null one (syntactic sugar). If you decide to go for a non-header only implementation, you could always define the "one" null guid as a static const member instead (or simply define it at namespace-level in one of the sources). You could also define the real implementation of guid as a template: ----------------------- namespace boost { namespace detail { template<int dummy = 0> class guid_impl_t { public: static guid_impl_t const& null() { return g_null_guid; } private: static guid_impl_t const g_null_guid; }; template<int dummy> guid_impl_t<dummy> const guid_impl_t<dummy>::g_null_guid = guid_impl_t<dummy>(); } // namespace detail typedef ::boost::detail::guid_impl_t<> guid; } // namespace boost -------- Don't know if that's standard-compliant though. / Johan

<Oliver.Kowalke@qimonda.com> wrote in news:B1EAFF2DAE7658488B631F25813CD91F01331CCC@drsse602.eu.infineon.com:
Hello,
Instead of bool is_null() const and static guid const& null() I would prefer bool is_nil() const and static guid const& nil().
I prefer null, but I can easily be swayed by this groups voice.
I'de like to see uuid v1 (node hardware address + time based). Access to MAC: - on HP/UX you could use DLPI interface (example: http://h10025.www1.hp.com/ewfrf/wc/genericDocument?docname=c00904700&cc = us&dlc=en&lc=en&jumpid=reg_R1002_USEN) - ::ioctl + SIOCGIFHWADDR on Linux
This is helpful and gets me one-step closer to creating this functionality.
Because my apps are bloated if I use some header-only libraries from boost I'de like to see guid library not as header-only library - but this was already discussed in this mailing list.
I have not read the thread about making libraries both header-only and not header-only. If this was/is a solution, I will do this.
Regards, Oliver _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Andy.

Hello Andy,
Hello,
Instead of bool is_null() const and static guid const& null() I would prefer bool is_nil() const and static guid const& nil().
I prefer null, but I can easily be swayed by this groups voice.
It was only a suggestion - in the rfc 4122 for UUIDs (http://www.ietf.org/rfc/rfc4122.txt) nil is used instead of null. As I read in one of your responses that you would change the name from guid to uuid in order to be standard conform. Regards, Oliver

<Oliver.Kowalke@qimonda.com> wrote in news:B1EAFF2DAE7658488B631F25813CD91F0137D995@drsse602.eu.infineon.com:
Hello Andy,
Hello,
Instead of bool is_null() const and static guid const& null() I would prefer bool is_nil() const and static guid const& nil().
I prefer null, but I can easily be swayed by this groups voice.
It was only a suggestion - in the rfc 4122 for UUIDs (http://www.ietf.org/rfc/rfc4122.txt) nil is used instead of null. As I read in one of your responses that you would change the name from guid to uuid in order to be standard conform.
Regards, Oliver _______________________________________________
I didn't notice that. Neither is mentioned in http://www.itu.int/ITU-T/studygroups/com17/oid/X.667-E.pdf. Unless there is opposition, 'bool guid::is_nil()' it is. Andy.
participants (11)
-
Andy
-
Christian Henning
-
gchen
-
Hartmut Kaiser
-
Janek Kozicki
-
Jared McIntyre
-
Johan Nilsson
-
Matthias Troyer
-
Oliver.Kowalke@qimonda.com
-
Paul A Bristow
-
Peter Dimov