|
Boost : |
Subject: [boost] [UUID] Code for UUIDs as PODs and other changes
From: Scott McMurray (me22.ca+boost_at_[hidden])
Date: 2008-12-06 04:10:01
I remarked the other day that a UUID has a well-defined, portable
binary format, so I took a bit of time to rearrange things to make the
UUID class a POD and make more use of the generators idea. Along the
way I made a few other changes.
I've uploaded the result (with updated docs) to the vault as
uuid_alt_v13_pod.zip :
http://www.boostpro.com/vault/index.php?action=downloadfile&filename=uuid_alt_v13_pod.zip
Some elaboration follows below. Comments appreciated.
~ Scott
PODness:
As a POD, all the constructors are of course gone. This doesn't
bother me, but I have no idea what others will think. In fact, I like
it better, since I don't think that serialization to and from strings
belongs in the type, and it seems like using a lexical_cast is
perfectly reasonable:
uuid u = lexical_cast<uuid>("21f7f8de-8051-5b89-8680-0195ef798b6a");
This cuts out a large chunk of code, too.
I don't know if it's useful, but aggregate syntax also opens possibilities:
uuid u = { /* 6ba7b814-9dad-11d1-80b4-00c04fd430c8 */
0x6b, 0xa7, 0xb8, 0x14,
0x9d, 0xad,
0x11, 0xd1,
0x80, 0xb4,
0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8
};
In a possibly controversial move, I changed everything that could
throw exceptions. That's not that much, though. The std::string
parsing code I had already removed, which was the only source of one
exception. The other came from the byte input iterator range
constructor, which I kept as an assign member function (though I made
mutable iterators available, so it's unnecessary). In there I
switched the throw to an assert, assuming that it's reasonable for
people to arrange for there to always be 16 elements as a
precondition, since it's raw construction (which is used into the
generators, for example) rather than something likely to come from
user input.
Include cost:
I took the opportunity to move the stream I/O code out to its own
header, like the serialization code is. This means that the
uuids/uuid.hpp header is fairly light, as the <locale> and <string>
includes are gone. In fact, all that's left are these:
#include <boost/array.hpp>
#include <boost/assert.hpp>
#include <boost/config.hpp>
#include <boost/cstdint.hpp>
#include <boost/numeric/conversion/cast.hpp>
#include <boost/static_assert.hpp>
Generators:
I liked the idea of using a generator object for the random UUIDs, so
I wanted to extend that idea. I renamed it to random_generator, on
the theory that random_generator<> isn't strenuous if a user wants the
default PRNG.
boost::uuids::random_generator<> gen1;
boost::uuids::uuid u1 = gen1();
boost::lagged_fibonacci44497 rng;
boost::uuids::random_generator<boost::lagged_fibonacci44497&> gen2(rng);
boost::uuids::uuid u2 = gen2();
For name-based, I introduced a sha1_generator class. This is seeded
with a namespace UUID (those from the RFC are provided in
boost::uuids::namespaces), and then has an operator() that takes a
byte input iterator range. It may be interesting to add a boost.range
overload, allowing the generator to be used as a transform functor for
strings.
boost::uuids::sha1_generator gen(boost::uuids::namespaces::dns());
std::string name = "www.widgets.com";
boost::uuid u = gen(name.begin(), name.end());
Native UUIDs:
I recall that someone in the review wanted an interface to the OS
functionality, and I had been looking at Linux's earlier, so I wrote
up 2 additional generators. e2fsprogs_generator uses the
<uuid/uuid.h> header and libuuid on Linux, and passes all the tests
that random_generator does. windows_generator uses UuidCreate, and is
completely untested.
Variants and Versions:
I thought being able to find out these might be a good idea, so
they're there too.
enum variant_type {variant_ncs = 0,
variant_dce = 1,
variant_rfc_4122 = variant_dce,
variant_microsoft = 2,
variant_other = 3};
variant_type variant() const;
enum version_type {version_wrong_variant = -1,
version_unknown = 0,
version_1 = 1,
version_time_based = version_1,
version_2 = 2,
version_dce_security = version_2,
version_3 = 3,
version_name_based_md5 = version_3,
version_4 = 4,
version_random = version_4,
version_5 = 5,
version_name_based_sha1 = version_5};
version_type version() const;
Implementation Details:
I switched sha1.hpp over to using int32_t to remove the 4-byte-int
requirement. I also let it handle 512 MiB+ messages (if size_t can),
though that's not a serious concern. I replaced the
*reinterpret_cast<unsigned long*> in random_generator with the kind of
code used in sha1 that doesn't have the endianness dependence or what
I think is an aliasing violation.
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk