# common/include/pion/PionId.hpp

    00001 // -----------------------------------------------------------------------
    00002 // pion-common: a collection of common libraries used by the Pion Platform
    00003 // -----------------------------------------------------------------------
    00004 // Copyright (C) 2007-2009 Atomic Labs, Inc.  (http://www.atomiclabs.com)
    00005 //
    00006 // Distributed under the Boost Software License, Version 1.0.
    00007 // See http://www.boost.org/LICENSE_1_0.txt
    00008 //
    00009
    00010 #ifndef __PION_PIONID_HEADER__
    00011 #define __PION_PIONID_HEADER__
    00012
    00013 #include <string>
    00014 #include <limits>
    00015 #include <ctime>
    00016 #include <cstring>
    00017 #include <cstdlib>
    00018 #include <boost/functional/hash.hpp>
    00019 #include <boost/date_time/posix_time/posix_time.hpp>
    00020 #include <boost/random/uniform_int.hpp>
    00021 #include <boost/random/variate_generator.hpp>
    00022 #include <boost/random/mersenne_twister.hpp>
    00023 #include <boost/numeric/conversion/cast.hpp>
    00024 #include <pion/PionConfig.hpp>
    00025
    00026 namespace pion {    // begin namespace pion
    00027
    00028
    00032 class PionId {
    00033 public:
    00034
    00036     typedef unsigned char *         iterator;
    00037
    00039     typedef const unsigned char *   const_iterator;
    00040
    00041     enum {
    00042         PION_ID_DATA_BYTES = 16,            //< total number of data bytes
    00043         PION_ID_HEX_BYTES = 16 * 2 + 4      //< number of bytes in hexadecimal representation
    00044     };
    00045
    00047     virtual ~PionId() {}
    00048
    00050     PionId(void) {
    00051         typedef boost::mt19937 gen_type;
    00052         typedef boost::uniform_int<unsigned long> dist_type;
    00053         typedef boost::variate_generator<gen_type,dist_type> die_type;
    00054         gen_type rng_gen(PionId::make_seed());
    00055         dist_type rng_dist((std::numeric_limits<unsigned long>::min)(), (std::numeric_limits<unsigned long>::max)());
    00056         die_type rng_die(rng_gen, rng_dist);
    00057         generate(m_data, rng_die);
    00058     }
    00059
    00061     explicit PionId(const std::string& str) {
    00062         from_string(str.c_str());
    00063     }
    00064
    00066     explicit PionId(const char *str) {
    00067         from_string(str);
    00068     }
    00069
    00071     template<typename base_generator_type, typename distribution_type>
    00072     explicit PionId(boost::variate_generator<base_generator_type, distribution_type>& rng) {
    00073         generate(m_data, rng);
    00074     }
    00075
    00077     PionId(const PionId& id) {
    00078         memcpy(m_data, id.m_data, PION_ID_DATA_BYTES);
    00079     }
    00080
    00082     PionId& operator=(const PionId& id) {
    00083         memcpy(m_data, id.m_data, PION_ID_DATA_BYTES);
    00084         return *this;
    00085     }
    00086
    00088     inline unsigned char operator[](const std::size_t n) const {
    00089         return m_data[n];
    00090     }
    00091
    00093     inline bool operator==(const PionId& id) const {
    00094         return (memcmp(m_data, id.m_data, PION_ID_DATA_BYTES) == 0);
    00095     }
    00096
    00098     inline bool operator!=(const PionId& id) const {
    00099         return (memcmp(m_data, id.m_data, PION_ID_DATA_BYTES) != 0);
    00100     }
    00101
    00103     inline bool operator<(const PionId& id) const {
    00104         return (memcmp(m_data, id.m_data, PION_ID_DATA_BYTES) < 0);
    00105     }
    00106
    00108     inline bool operator>(const PionId& id) const {
    00109         return (memcmp(m_data, id.m_data, PION_ID_DATA_BYTES) > 0);
    00110     }
    00111
    00113     inline iterator begin(void) { return m_data; }
    00114
    00116     inline iterator end(void) { return m_data + PION_ID_DATA_BYTES; }
    00117
    00119     inline const_iterator begin(void) const { return m_data; }
    00120
    00122     inline const_iterator end(void) const { return m_data + PION_ID_DATA_BYTES; }
    00123
    00125     inline std::string to_string(void) const {
    00126         std::string hex_str;
    00127         static const char hex[] = "0123456789abcdef";
    00128         for (std::size_t i = 0; i < PION_ID_DATA_BYTES; i++) {
    00129             hex_str += hex[m_data[i] >> 4];
    00130             hex_str += hex[m_data[i] & 0x0f];
    00131             if (i == 3 || i == 5 || i == 7 || i == 9)
    00132                 hex_str += '-';
    00133         }
    00134         return hex_str;
    00135     }
    00136
    00138     void from_string(const char *str) {
    00139         std::size_t data_pos = 0;
    00140         char buf[3];
    00141         buf[2] = '\0';
    00142         while (*str != '\0' && data_pos < PION_ID_DATA_BYTES) {
    00143             if (isxdigit(*str)) {
    00144                 buf[0] = *str;
    00145                 if (*(++str) == '\0' || !isxdigit(*str))    // sanity check
    00146                     break;
    00147                 buf[1] = *str;
    00148                 m_data[data_pos++] = boost::numeric_cast<unsigned char>(strtoul(buf, NULL, 16));
    00149             }
    00150             ++str;
    00151         }
    00152     }
    00153
    00155     static inline boost::uint32_t make_seed(void) {
    00156         // this could probably be much better, but trying to KISS...
    00157         typedef boost::mt19937 gen_type;
    00158         typedef boost::uniform_int<unsigned long> dist_type;
    00159         typedef boost::variate_generator<gen_type,dist_type> die_type;
    00160         // initialize a static generator with seed based upon system time
    00161         static boost::uint64_t seed_seed_64 = (time(NULL) * 1000000) + boost::posix_time::microsec_clock::local_time().time_of_day().total_microseconds();
    00162         // Convert to 32 bits, keeping most of the available entropy.
    00163         static gen_type::result_type seed_seed_32 = boost::numeric_cast<gen_type::result_type>((seed_seed_64 >> 32) ^ (seed_seed_64 & 0xFFFFFFFF));
    00164         static gen_type rng_gen(seed_seed_32);
    00165         static dist_type rng_dist((std::numeric_limits<unsigned long>::min)(), (std::numeric_limits<unsigned long>::max)());
    00166         static die_type rng_die(rng_gen, rng_dist);
    00167         // use the static rng to produce seed values that initialize other generators
    00168         return rng_die();
    00169     }
    00170
    00171
    00172 protected:
    00173
    00180     template<typename base_generator_type, typename distribution_type>
    00181     static inline void generate(unsigned char *data, boost::variate_generator<base_generator_type, distribution_type>& rng) {
    00182         // Note: this code is adapted from the Boost UUID library, (c) 2006 Andy Tompkins
    00183         for (std::size_t i = 0; i < PION_ID_DATA_BYTES; i += sizeof(unsigned long)) {
    00184             *reinterpret_cast<unsigned long*>(&data[i]) = rng();
    00185         }
    00186
    00187         // set variant
    00188         // should be 0b10xxxxxx
    00189         data[8] &= 0xBF;
    00190         data[8] |= 0x80;
    00191
    00192         // set version
    00193         // should be 0b0100xxxx
    00194         data[6] &= 0x4F; //0b01001111
    00195         data[6] |= 0x40; //0b01000000
    00196     }
    00197
    00199     unsigned char   m_data[PION_ID_DATA_BYTES];
    00200 };
    00201
    00202
    00204 static inline std::size_t hash_value(const PionId& id) {
    00205     std::size_t seed = 0;
    00206     const unsigned char * data = id.begin();
    00207     const unsigned char * const end = id.end();
    00208     while (data < end) {
    00209         boost::hash_combine(seed, *reinterpret_cast<const unsigned long*>(data));
    00210         data += sizeof(unsigned long);
    00211     }
    00212     return seed;
    00213 }
    00214
    00215
    00219 template <typename BaseGeneratorType>
    00220 class PionIdGeneratorBase {
    00221 public:
    00222
    00224     typedef BaseGeneratorType   base_generator_type;
    00225
    00227     typedef boost::uniform_int<unsigned long>   distribution_type;
    00228
    00230     typedef boost::variate_generator<base_generator_type, distribution_type>    gen_type;
    00231
    00232
    00234     virtual ~PionIdGeneratorBase() {}
    00235
    00237     PionIdGeneratorBase(void)
    00238         : m_random_gen(PionId::make_seed()),
    00239         m_random_dist((std::numeric_limits<unsigned long>::min)(), (std::numeric_limits<unsigned long>::max)()),
    00240         m_random_die(m_random_gen, m_random_dist)
    00241     {}
    00242
    00244     inline PionId operator()(void) { return PionId(m_random_die); }
    00245
    00247     inline gen_type& getRNG(void) { return m_random_die; }
    00248
    00250     inline unsigned long getNumber(void) { return m_random_die(); }
    00251
    00252
    00253 protected:
    00254
    00256     base_generator_type             m_random_gen;
    00257
    00259     distribution_type               m_random_dist;
    00260
    00262     gen_type                        m_random_die;
    00263 };
    00264
    00265
    00267 typedef PionIdGeneratorBase<boost::mt19937> PionIdGenerator;
    00268
    00269
    00270 }   // end namespace pion
    00271
    00272 #endif