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

Generated on Fri Apr 30 14:48:53 2010 for pion-net by  doxygen 1.4.7