Browse Source

Merge remote-tracking branch 'origin/master'

disinfection_machine
zhaohe 2 years ago
parent
commit
f5a2ccc1a0
  1. 17
      core/utils/uuid/sole/LICENSE
  2. 77
      core/utils/uuid/sole/README.md
  3. 23
      core/utils/uuid/sole/RELEASE
  4. 903
      core/utils/uuid/sole/sole.hpp
  5. 29
      core/utils/uuid/uuid.hpp

17
core/utils/uuid/sole/LICENSE

@ -0,0 +1,17 @@
Copyright (c) 2015 r-lyeh (https://github.com/r-lyeh)
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.

77
core/utils/uuid/sole/README.md

@ -0,0 +1,77 @@
sole <a href="https://travis-ci.org/r-lyeh/sole"><img src="https://api.travis-ci.org/r-lyeh/sole.svg?branch=master" align="right" /></a>
====
- Sole is a lightweight C++11 library to generate universally unique identificators (UUID).
- Sole provides interface for UUID versions 0, 1 and 4.
- Sole rebuilds UUIDs from hexadecimal and base62 cooked strings as well.
- Sole is tiny, header-only, cross-platform.
- Sole is zlib/libpng licensed.
### Some theory
- UUID version 1 (48-bit MAC address + 60-bit clock with a resolution of 100 ns)
- UUID version 4 (122-bits of randomness)
- Use v1 if you are worried about leaving it up to probabilities.
- Use v4 if you are worried about security issues and determinism.
### About custom version 0
- UUID version 0 (16-bit PID + 48-bit MAC address + 60-bit clock with a resolution of 100ns since Unix epoch)
- Format is EPOCH_LOW-EPOCH_MID-VERSION(0)|EPOCH_HI-PID-MAC
### Public API
- `sole::uuid` 128-bit UUID base type that allows comparison and sorting. `std::ostream <<` friendly. `.str()` to get a cooked hex string. `.base62()` to get a cooked base62 string. `.pretty()` to get a pretty decomposed report.
- `sole::uuid0()` creates an UUID v0.
- `sole::uuid1()` creates an UUID v1.
- `sole::uuid4()` creates an UUID v4.
- `sole::rebuild()` rebuilds an UUID from given string or 64-bit tuple.
### Showcase
```c++
~sole> cat sample.cc
#include <iostream>
#include "sole.hpp"
int main() {
sole::uuid u0 = sole::uuid0(), u1 = sole::uuid1(), u4 = sole::uuid4();
std::cout << "uuid v0 string : " << u0 << std::endl;
std::cout << "uuid v0 base62 : " << u0.base62() << std::endl;
std::cout << "uuid v0 pretty : " << u0.pretty() << std::endl << std::endl;
std::cout << "uuid v1 string : " << u1 << std::endl;
std::cout << "uuid v1 base62 : " << u1.base62() << std::endl;
std::cout << "uuid v1 pretty : " << u1.pretty() << std::endl << std::endl;
std::cout << "uuid v4 string : " << u4 << std::endl;
std::cout << "uuid v4 base62 : " << u4.base62() << std::endl;
std::cout << "uuid v4 pretty : " << u4.pretty() << std::endl << std::endl;
u1 = sole::rebuild("F81D4FAE-7DEC-11D0-A765-00A0C91E6BF6");
std::cout << "uuid v1 rebuilt: " << u1 << " -> " << u1.pretty() << std::endl;
u4 = sole::rebuild("GITheR4tLlg-BagIW20DGja");
std::cout << "uuid v4 rebuilt: " << u4 << " -> " << u4.pretty() << std::endl;
}
~sole> g++ sample.cc -std=c++11 -lrt && ./a.out
uuid v0 string : 00aed2f9-c5f8-0030-0fd8-00ffb77bd832
uuid v0 base62 : 3dNJHWv0aW-1MKpXy7mEmf
uuid v0 pretty : version=0,timestamp="03/07/2013 12:19:43",mac=00ffb77bd832,pid=4056,
uuid v1 string : 14314b83-e3ca-11e2-8b83-00ffb77bd832
uuid v1 base62 : 1jU2TXBD9t4-BycINxiP5Jh
uuid v1 pretty : version=1,timestamp="03/07/2013 12:19:43",mac=00ffb77bd832,clock_seq=2947,
uuid v4 string : fa237b32-d580-42db-aeb9-b09a1d90067e
uuid v4 base62 : LTTsO5t3jMR-F03eZqkMchC
uuid v4 pretty : version=4,randbits=fa237b32d58002db2eb9b09a1d90067e,
uuid v1 rebuilt : f81d4fae-7dec-11d0-a765-00a0c91e6bf6 -> version=1,timestamp="03/02/1997 18:43:12",mac=00a0c91e6bf6,clock_seq=10085,
uuid v4 rebuilt : bdd55e2f-6f6b-4088-8703-ddedba9456a2 -> version=4,randbits=bdd55e2f6f6b0088703ddedba9456a2,
```
### Special notes
- clang/g++ users: both `-std=c++11` and `-lrt` may be required when compiling `sole.cpp`
### Changelog
- v1.0.1 (2017/05/16): Improve UUID4 and base62 performance; Fix warnings
- v1.0.0 (2016/02/03): Initial semver adherence; Switch to header-only; Remove warnings

23
core/utils/uuid/sole/RELEASE

@ -0,0 +1,23 @@
commit 89f9c68bba69a53bcb7c3f6e4980312a86cf21b0
Merge: ad2d25c 7e5c0ed
Author: r-lyeh <35402248+r-lyeh@users.noreply.github.com>
Date: Sat May 18 10:28:20 2019 +0200
Merge pull request #25 from MisterTea/patch-2
localtime_r() doesn't exist on mingw so use localtime()
commit 7e5c0eddc3877d93be401bb50f7c51022055f232
Author: Jason Gauci <jgmath2000@gmail.com>
Date: Fri May 17 22:26:50 2019 -0700
localtime_r() doesn't exist on mingw so use localtime()
commit ad2d25cc0a622f006b65fb449606edf457dd2566
Merge: 653a25a ff14f0b
Author: r-lyeh <35402248+r-lyeh@users.noreply.github.com>
Date: Sun May 5 10:46:33 2019 +0200
Merge pull request #24 from MisterTea/patch-1
Change "class hash" to "struct hash" to avoid compiler warnings on Xcode

903
core/utils/uuid/sole/sole.hpp

@ -0,0 +1,903 @@
/* Sole is a lightweight C++11 library to generate universally unique identificators.
* Sole provides interface for UUID versions 0, 1 and 4.
* https://github.com/r-lyeh/sole
* Copyright (c) 2013,2014,2015 r-lyeh. zlib/libpng licensed.
* Based on code by Dmitri Bouianov, Philip O'Toole, Poco C++ libraries and anonymous
* code found on the net. Thanks guys!
* Theory: (see Hoylen's answer at [1])
* - UUID version 1 (48-bit MAC address + 60-bit clock with a resolution of 100ns)
* Clock wraps in 3603 A.D.
* Up to 10000000 UUIDs per second.
* MAC address revealed.
*
* - UUID Version 4 (122-bits of randomness)
* See [2] or other analysis that describe how very unlikely a duplicate is.
*
* - Use v1 if you need to sort or classify UUIDs per machine.
* Use v1 if you are worried about leaving it up to probabilities (e.g. your are the
* type of person worried about the earth getting destroyed by a large asteroid in your
* lifetime). Just use a v1 and it is guaranteed to be unique till 3603 AD.
*
* - Use v4 if you are worried about security issues and determinism. That is because
* v1 UUIDs reveal the MAC address of the machine it was generated on and they can be
* predictable. Use v4 if you need more than 10 million uuids per second, or if your
* application wants to live past 3603 A.D.
* Additionally a custom UUID v0 is provided:
* - 16-bit PID + 48-bit MAC address + 60-bit clock with a resolution of 100ns since Unix epoch
* - Format is EPOCH_LOW-EPOCH_MID-VERSION(0)|EPOCH_HI-PID-MAC
* - Clock wraps in 3991 A.D.
* - Up to 10000000 UUIDs per second.
* - MAC address and PID revealed.
* References:
* - [1] http://stackoverflow.com/questions/1155008/how-unique-is-uuid
* - [2] http://en.wikipedia.org/wiki/UUID#Random%5FUUID%5Fprobability%5Fof%5Fduplicates
* - http://en.wikipedia.org/wiki/Universally_unique_identifier
* - http://en.cppreference.com/w/cpp/numeric/random/random_device
* - http://www.itu.int/ITU-T/asn1/uuid.html f81d4fae-7dec-11d0-a765-00a0c91e6bf6
* - rlyeh ~~ listening to Hedon Cries / Until The Sun Goes up
*/
//////////////////////////////////////////////////////////////////////////////////////
#pragma once
#include <stdint.h>
#include <stdio.h> // for size_t; should be stddef.h instead; however, clang+archlinux fails when compiling it (@Travis-Ci)
#include <sys/types.h> // for uint32_t; should be stdint.h instead; however, GCC 5 on OSX fails when compiling it (See issue #11)
#include <functional>
#include <string>
// public API
#define SOLE_VERSION "1.0.1" /* (2017/05/16): Improve UUID4 and base62 performance; fix warnings
#define SOLE_VERSION "1.0.0" // (2016/02/03): Initial semver adherence; Switch to header-only; Remove warnings */
namespace sole
{
// 128-bit basic UUID type that allows comparison and sorting.
// Use .str() for printing and .pretty() for pretty printing.
// Also, ostream friendly.
struct uuid
{
uint64_t ab;
uint64_t cd;
bool operator==( const uuid &other ) const;
bool operator!=( const uuid &other ) const;
bool operator <( const uuid &other ) const;
std::string pretty() const;
std::string base62() const;
std::string str() const;
template<typename ostream>
inline friend ostream &operator<<( ostream &os, const uuid &self ) {
return os << self.str(), os;
}
};
// Generators
uuid uuid0(); // UUID v0, pro: unique; cons: MAC revealed, pid revealed, predictable.
uuid uuid1(); // UUID v1, pro: unique; cons: MAC revealed, predictable.
uuid uuid4(); // UUID v4, pros: anonymous, fast; con: uuids "can clash"
// Rebuilders
uuid rebuild( uint64_t ab, uint64_t cd );
uuid rebuild( const std::string &uustr );
}
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable:4127)
#endif
namespace std {
template<>
struct hash< sole::uuid > {
public:
// hash functor: hash uuid to size_t value by pseudorandomizing transform
size_t operator()( const sole::uuid &uuid ) const {
if( sizeof(size_t) > 4 ) {
return size_t( uuid.ab ^ uuid.cd );
} else {
uint64_t hash64 = uuid.ab ^ uuid.cd;
return size_t( uint32_t( hash64 >> 32 ) ^ uint32_t( hash64 ) );
}
}
};
}
#ifdef _MSC_VER
#pragma warning(pop)
#endif
// implementation
#include <memory.h>
#include <stdint.h>
#include <stdio.h>
#include <time.h>
#include <cstring>
#include <ctime>
#include <iomanip>
#include <random>
#include <sstream>
#include <string>
#include <vector>
#if defined(_WIN32)
# include <winsock2.h>
# include <process.h>
# include <iphlpapi.h>
# ifdef _MSC_VER
# pragma comment(lib,"iphlpapi.lib")
# endif
# define $windows $yes
#elif defined(__FreeBSD__) || defined(__NetBSD__) || \
defined(__OpenBSD__) || defined(__MINT__) || defined(__bsdi__)
# include <ifaddrs.h>
# include <net/if_dl.h>
# include <sys/socket.h>
# include <sys/time.h>
# include <sys/types.h>
# include <unistd.h>
# define $bsd $yes
#elif (defined(__APPLE__) && defined(__MACH__))
# include <ifaddrs.h>
# include <net/if_dl.h>
# include <sys/socket.h>
# include <sys/time.h>
# include <sys/types.h>
# include <unistd.h>
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wdollar-in-identifier-extension"
# define $osx $yes
#elif defined(__linux__)
# include <arpa/inet.h>
# include <net/if.h>
# include <netinet/in.h>
# include <sys/ioctl.h>
# include <sys/socket.h>
# include <sys/time.h>
# include <unistd.h>
# define $linux $yes
#else //elif defined(__unix__)
# if defined(__VMS)
# include <ioctl.h>
# include <inet.h>
# else
# include <sys/ioctl.h>
# include <arpa/inet.h>
# endif
# if defined(sun) || defined(__sun)
# include <sys/sockio.h>
# endif
# include <net/if.h>
# include <net/if_arp.h>
# include <netdb.h>
# include <netinet/in.h>
# include <sys/socket.h>
# include <sys/time.h>
# include <sys/types.h>
# include <unistd.h>
# if defined(__VMS)
namespace { enum { MAXHOSTNAMELEN = 64 }; }
# endif
# define $unix $yes
#endif
#ifdef _MSC_VER
# define $msvc $yes
#endif
#if defined(__GNUC__) && (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 < 50100)
namespace std
{
static inline std::string put_time( const std::tm* tmb, const char* fmt ) {
std::string s( 128, '\0' );
while( !strftime( &s[0], s.size(), fmt, tmb ) )
s.resize( s.size() + 128 );
return s;
}
}
#endif
////////////////////////////////////////////////////////////////////////////////////
#ifdef $windows
#define $welse $no
#else
#define $windows $no
#define $welse $yes
#endif
#ifdef $bsd
#define $belse $no
#else
#define $bsd $no
#define $belse $yes
#endif
#ifdef $linux
#define $lelse $no
#else
#define $linux $no
#define $lelse $yes
#endif
#ifdef $unix
#define $uelse $no
#else
#define $unix $no
#define $uelse $yes
#endif
#ifdef $osx
#define $oelse $no
#else
#define $osx $no
#define $oelse $yes
#endif
#ifdef $msvc
#define $melse $no
#else
#define $msvc $no
#define $melse $yes
#endif
#define $yes(...) __VA_ARGS__
#define $no(...)
inline bool sole::uuid::operator==( const sole::uuid &other ) const {
return ab == other.ab && cd == other.cd;
}
inline bool sole::uuid::operator!=( const sole::uuid &other ) const {
return !operator==(other);
}
inline bool sole::uuid::operator<( const sole::uuid &other ) const {
if( ab < other.ab ) return true;
if( ab > other.ab ) return false;
if( cd < other.cd ) return true;
return false;
}
namespace sole {
inline std::string printftime( uint64_t timestamp_secs = 0, const std::string &locale = std::string() ) {
std::string timef;
try {
// Taken from parameter
//std::string locale; // = "es-ES", "Chinese_China.936", "en_US.UTF8", etc...
std::time_t t = timestamp_secs;
std::tm tm;
$msvc(
localtime_s( &tm, &t );
)
$melse(
$windows(tm = *localtime( &t ); )
$welse( localtime_r(&t, &tm); )
)
std::stringstream ss;
$melse(
std::locale lc( locale.c_str() );
ss.imbue( lc );
)
ss << std::put_time( &tm, "\"%c\"" );
timef = ss.str();
}
catch(...) {
timef = "\"\"";
}
return timef;
}
inline std::string uuid::pretty() const {
std::stringstream ss;
uint64_t a = (ab >> 32);
uint64_t b = (ab & 0xFFFFFFFF);
uint64_t c = (cd >> 32);
uint64_t d = (cd & 0xFFFFFFFF);
int version = (b & 0xF000) >> 12;
uint64_t timestamp = ((b & 0x0FFF) << 48 ) | (( b >> 16 ) << 32) | a; // in 100ns units
ss << "version=" << (version) << ',';
if( version == 1 )
timestamp = timestamp - 0x01b21dd213814000ULL; // decrement Gregorian calendar
ss << std::hex << std::nouppercase << std::setfill('0');
version <= 1 && ss << "timestamp=" << printftime(timestamp/10000000) << ',';
version <= 1 && ss << "mac=" << std::setw(4) << (c & 0xFFFF) << std::setw(8) << d << ',';
version == 4 && ss << "randbits=" << std::setw(8) << (ab & 0xFFFFFFFFFFFF0FFFULL) << std::setw(8) << (cd & 0x3FFFFFFFFFFFFFFFULL) << ',';
ss << std::dec;
version == 0 && ss << "pid=" << std::setw(4) << (c >> 16 ) << ',';
version == 1 && ss << "clock_seq=" << std::setw(4) << ((c >> 16) & 0x3FFF) << ',';
return ss.str();
}
inline std::string uuid::str() const {
std::stringstream ss;
ss << std::hex << std::nouppercase << std::setfill('0');
uint32_t a = (ab >> 32);
uint32_t b = (ab & 0xFFFFFFFF);
uint32_t c = (cd >> 32);
uint32_t d = (cd & 0xFFFFFFFF);
ss << std::setw(8) << (a) << '-';
ss << std::setw(4) << (b >> 16) << '-';
ss << std::setw(4) << (b & 0xFFFF) << '-';
ss << std::setw(4) << (c >> 16 ) << '-';
ss << std::setw(4) << (c & 0xFFFF);
ss << std::setw(8) << d;
return ss.str();
}
inline std::string uuid::base62() const {
int base62len = 10 + 26 + 26;
const char base62[] =
"0123456789"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz";
char res[24], *end = &res[24]; *(--end) = '\0';
uint64_t rem, AB = ab, CD = cd;
do {
rem = CD % base62len;
*--end = base62[int(rem)];
CD /= base62len;
} while (CD > 0);
*--end = '-';
do {
rem = AB % base62len;
*--end = base62[int(rem)];
AB /= base62len;
} while (AB > 0);
return end;
}
//////////////////////////////////////////////////////////////////////////////////////
// multiplatform clock_gettime()
$windows(
struct timespec {
uint64_t tv_sec;
uint64_t tv_nsec;
};
struct timezone {
int tz_minuteswest; /* minutes W of Greenwich */
int tz_dsttime; /* type of dst correction */
};
inline int gettimeofday( struct timeval *tv, struct timezone *tz ) {
FILETIME ft;
uint64_t tmpres = 0;
if( NULL != tv ) {
GetSystemTimeAsFileTime(&ft);
// The GetSystemTimeAsFileTime returns the number of 100 nanosecond
// intervals since Jan 1, 1601 in a structure. Copy the high bits to
// the 64 bit tmpres, shift it left by 32 then or in the low 32 bits.
tmpres |= ft.dwHighDateTime;
tmpres <<= 32;
tmpres |= ft.dwLowDateTime;
// Convert to microseconds by dividing by 10
tmpres /= 10;
// The Unix epoch starts on Jan 1 1970. Need to subtract the difference
// in seconds from Jan 1 1601.
tmpres -= 11644473600000000ULL;
// Finally change microseconds to seconds and place in the seconds value.
// The modulus picks up the microseconds.
tv->tv_sec = static_cast<long>(tmpres / 1000000UL);
tv->tv_usec = (tmpres % 1000000UL);
}
if( NULL != tz ) {
static bool once = true;
if( once ) {
once = false;
_tzset();
}
long timezoneSecs = 0;
int daylight = 0;
$msvc(
_get_timezone(&timezoneSecs);
_get_daylight(&daylight);
)
$melse(
timezoneSecs = _timezone;
daylight = _daylight;
)
tz->tz_minuteswest = timezoneSecs / 60;
tz->tz_dsttime = daylight;
}
return 0;
}
)
$lelse( $belse( // if not linux, if not bsd... valid for apple/win32
inline int clock_gettime( int /*clk_id*/, struct timespec* t ) {
struct timeval now;
int rv = gettimeofday(&now, NULL);
if( rv ) return rv;
t->tv_sec = now.tv_sec;
t->tv_nsec = now.tv_usec * 1000;
return 0;
}
))
//////////////////////////////////////////////////////////////////////////////////////
// Timestamp and MAC interfaces
// Returns number of 100ns intervals
inline uint64_t get_time( uint64_t offset ) {
struct timespec tp;
clock_gettime(0 /*CLOCK_REALTIME*/, &tp);
// Convert to 100-nanosecond intervals
uint64_t uuid_time;
uuid_time = tp.tv_sec * 10000000;
uuid_time = uuid_time + (tp.tv_nsec / 100);
uuid_time = uuid_time + offset;
// If the clock looks like it went backwards, or is the same, increment it.
static uint64_t last_uuid_time = 0;
if( last_uuid_time > uuid_time )
last_uuid_time = uuid_time;
else
last_uuid_time = ++uuid_time;
return uuid_time;
}
// Looks for first MAC address of any network device, any size.
inline bool get_any_mac( std::vector<unsigned char> &_node ) {
$windows({
PIP_ADAPTER_INFO pAdapterInfo;
PIP_ADAPTER_INFO pAdapter = 0;
ULONG len = sizeof(IP_ADAPTER_INFO);
pAdapterInfo = reinterpret_cast<IP_ADAPTER_INFO*>(new char[len]);
// Make an initial call to GetAdaptersInfo to get
// the necessary size into len
DWORD rc = GetAdaptersInfo(pAdapterInfo, &len);
if (rc == ERROR_BUFFER_OVERFLOW)
{
delete [] reinterpret_cast<char*>(pAdapterInfo);
pAdapterInfo = reinterpret_cast<IP_ADAPTER_INFO*>(new char[len]);
}
else if (rc != ERROR_SUCCESS)
{
return $no("cannot get network adapter list") false;
}
bool found = false, gotten = false;
if (GetAdaptersInfo(pAdapterInfo, &len) == NO_ERROR)
{
gotten = true;
pAdapter = pAdapterInfo;
while (pAdapter && !found)
{
if (pAdapter->Type == MIB_IF_TYPE_ETHERNET && pAdapter->AddressLength > 0 )
{
_node.resize( pAdapter->AddressLength );
std::memcpy(_node.data(), pAdapter->Address, _node.size() );
found = true;
}
pAdapter = pAdapter->Next;
}
}
delete [] reinterpret_cast<char*>(pAdapterInfo);
if( !gotten )
return $no("cannot get network adapter list") false;
if (!found)
return $no("no Ethernet adapter found") false;
return true;
})
$bsd({
struct ifaddrs* ifaphead;
int rc = getifaddrs(&ifaphead);
if (rc) return $no("cannot get network adapter list") false;
bool foundAdapter = false;
for (struct ifaddrs* ifap = ifaphead; ifap; ifap = ifap->ifa_next)
{
if (ifap->ifa_addr && ifap->ifa_addr->sa_family == AF_LINK)
{
struct sockaddr_dl* sdl = reinterpret_cast<struct sockaddr_dl*>(ifap->ifa_addr);
caddr_t ap = (caddr_t) (sdl->sdl_data + sdl->sdl_nlen);
int alen = sdl->sdl_alen;
if (ap && alen > 0)
{
_node.resize( alen );
std::memcpy(_node.data(), ap, _node.size() );
foundAdapter = true;
break;
}
}
}
freeifaddrs(ifaphead);
if (!foundAdapter) return $no("cannot determine MAC address (no suitable network adapter found)") false;
return true;
})
$osx({
struct ifaddrs* ifaphead;
int rc = getifaddrs(&ifaphead);
if (rc) return $no("cannot get network adapter list") false;
bool foundAdapter = false;
for (struct ifaddrs* ifap = ifaphead; ifap; ifap = ifap->ifa_next)
{
if (ifap->ifa_addr && ifap->ifa_addr->sa_family == AF_LINK)
{
struct sockaddr_dl* sdl = reinterpret_cast<struct sockaddr_dl*>(ifap->ifa_addr);
caddr_t ap = (caddr_t) (sdl->sdl_data + sdl->sdl_nlen);
int alen = sdl->sdl_alen;
if (ap && alen > 0)
{
_node.resize( alen );
std::memcpy(_node.data(), ap, _node.size() );
foundAdapter = true;
break;
}
}
}
freeifaddrs(ifaphead);
if (!foundAdapter) return $no("cannot determine MAC address (no suitable network adapter found)") false;
return true;
})
$linux({
struct ifreq ifr;
int s = socket(PF_INET, SOCK_DGRAM, 0);
if (s == -1) return $no("cannot open socket") false;
std::strcpy(ifr.ifr_name, "eth0");
int rc = ioctl(s, SIOCGIFHWADDR, &ifr);
close(s);
if (rc < 0) return $no("cannot get MAC address") false;
struct sockaddr* sa = reinterpret_cast<struct sockaddr*>(&ifr.ifr_addr);
_node.resize( sizeof(sa->sa_data) );
std::memcpy(_node.data(), sa->sa_data, _node.size() );
return true;
})
$unix({
char name[MAXHOSTNAMELEN];
if (gethostname(name, sizeof(name)))
return $no("cannot get host name") false;
struct hostent* pHost = gethostbyname(name);
if (!pHost) return $no("cannot get host IP address") false;
int s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (s == -1) return $no("cannot open socket") false;
struct arpreq ar;
std::memset(&ar, 0, sizeof(ar));
struct sockaddr_in* pAddr = reinterpret_cast<struct sockaddr_in*>(&ar.arp_pa);
pAddr->sin_family = AF_INET;
std::memcpy(&pAddr->sin_addr, *pHost->h_addr_list, sizeof(struct in_addr));
int rc = ioctl(s, SIOCGARP, &ar);
close(s);
if (rc < 0) return $no("cannot get MAC address") false;
_node.resize( sizeof(ar.arp_ha.sa_data) );
std::memcpy(_node.data(), ar.arp_ha.sa_data, _node.size());
return true;
})
}
// Looks for first MAC address of any network device, size truncated to 48bits.
inline uint64_t get_any_mac48() {
std::vector<unsigned char> node;
if( get_any_mac(node) ) {
std::stringstream ss;
ss << std::hex << std::setfill('0');
node.resize(6);
for( unsigned i = 0; i < 6; ++i )
ss << std::setw(2) << int(node[i]);
uint64_t t;
if( ss >> t )
return t;
}
return 0;
}
//////////////////////////////////////////////////////////////////////////////////////
// UUID implementations
inline uuid uuid4() {
static std::random_device rd;
static std::uniform_int_distribution<uint64_t> dist(0, (uint64_t)(~0));
uuid my;
my.ab = dist(rd);
my.cd = dist(rd);
my.ab = (my.ab & 0xFFFFFFFFFFFF0FFFULL) | 0x0000000000004000ULL;
my.cd = (my.cd & 0x3FFFFFFFFFFFFFFFULL) | 0x8000000000000000ULL;
return my;
}
inline uuid uuid1() {
// Number of 100-ns intervals since 00:00:00.00 15 October 1582; [ref] uuid.py
uint64_t ns100_intervals = get_time( 0x01b21dd213814000ULL );
uint16_t clock_seq = (uint16_t)( ns100_intervals & 0x3fff ); // 14-bits max
uint64_t mac = get_any_mac48(); // 48-bits max
uint32_t time_low = ns100_intervals & 0xffffffff;
uint16_t time_mid = (ns100_intervals >> 32) & 0xffff;
uint16_t time_hi_version = (ns100_intervals >> 48) & 0xfff;
uint8_t clock_seq_low = clock_seq & 0xff;
uint8_t clock_seq_hi_variant = (clock_seq >> 8) & 0x3f;
uuid u;
uint64_t &upper_ = u.ab;
uint64_t &lower_ = u.cd;
// Build the high 32 bytes
upper_ = (uint64_t) time_low << 32;
upper_ |= (uint64_t) time_mid << 16;
upper_ |= (uint64_t) time_hi_version;
// Build the low 32 bytes, using the clock sequence number
lower_ = (uint64_t) ((clock_seq_hi_variant << 8) | clock_seq_low) << 48;
lower_ |= mac;
// Set the variant to RFC 4122.
lower_ &= ~((uint64_t)0xc000 << 48);
lower_ |= (uint64_t)0x8000 << 48;
// Set the version number.
enum { version = 1 };
upper_ &= ~0xf000;
upper_ |= version << 12;
return u;
}
inline uuid uuid0() {
// Number of 100-ns intervals since Unix epoch time
uint64_t ns100_intervals = get_time( 0 );
uint64_t pid = $windows( _getpid() ) $welse( getpid() );
uint16_t pid16 = (uint16_t)( pid & 0xffff ); // 16-bits max
uint64_t mac = get_any_mac48(); // 48-bits max
uint32_t time_low = ns100_intervals & 0xffffffff;
uint16_t time_mid = (ns100_intervals >> 32) & 0xffff;
uint16_t time_hi_version = (ns100_intervals >> 48) & 0xfff;
uint8_t pid_low = pid16 & 0xff;
uint8_t pid_hi = (pid16 >> 8) & 0xff;
uuid u;
uint64_t &upper_ = u.ab;
uint64_t &lower_ = u.cd;
// Build the high 32 bytes.
upper_ = (uint64_t) time_low << 32;
upper_ |= (uint64_t) time_mid << 16;
upper_ |= (uint64_t) time_hi_version;
// Build the low 32 bytes, using the mac and pid number.
lower_ = (uint64_t) ((pid_hi << 8) | pid_low) << 48;
lower_ |= mac;
// Set the version number.
enum { version = 0 };
upper_ &= ~0xf000;
upper_ |= version << 12;
return u;
}
inline uuid rebuild( uint64_t ab, uint64_t cd ) {
uuid u;
u.ab = ab; u.cd = cd;
return u;
}
inline uuid rebuild( const std::string &uustr ) {
char sep;
uint64_t a,b,c,d,e;
uuid u = { 0, 0 };
auto idx = uustr.find_first_of("-");
if( idx != std::string::npos ) {
// single separator, base62 notation
if( uustr.find_first_of("-",idx+1) == std::string::npos ) {
auto rebase62 = [&]( const char *input, size_t limit ) -> uint64_t {
int base62len = 10 + 26 + 26;
auto strpos = []( char ch ) -> size_t {
if( ch >= 'a' ) return ch - 'a' + 10 + 26;
if( ch >= 'A' ) return ch - 'A' + 10;
return ch - '0';
};
uint64_t res = strpos( input[0] );
for( size_t i = 1; i < limit; ++i )
res = base62len * res + strpos( input[i] );
return res;
};
u.ab = rebase62( &uustr[0], idx );
u.cd = rebase62( &uustr[idx+1], uustr.size() - (idx+1) );
}
// else classic hex notation
else {
std::stringstream ss( uustr );
if( ss >> std::hex >> a >> sep >> b >> sep >> c >> sep >> d >> sep >> e ) {
if( ss.eof() ) {
u.ab = (a << 32) | (b << 16) | c;
u.cd = (d << 48) | e;
}
}
}
}
return u;
}
} // ::sole
#undef $bsd
#undef $belse
#undef $linux
#undef $lelse
#undef $osx
#undef $oelse
#undef $unix
#undef $uelse
#undef $windows
#undef $welse
#undef $yes
#undef $no
// Pop disabled warnings
#if (defined(__APPLE__) && defined(__MACH__))
#pragma clang diagnostic pop
#endif
#ifdef SOLE_BUILD_DEMO
// g++ users: `g++ demo.cc -std=c++11 -lrt -o sample`
// visual studio: `cl.exe demo.cc sole.cpp`
#include <iostream>
int main() {
sole::uuid u0 = sole::uuid0(), u1 = sole::uuid1(), u4 = sole::uuid4();
std::cout << "uuid v0 string : " << u0 << std::endl;
std::cout << "uuid v0 base62 : " << u0.base62() << std::endl;
std::cout << "uuid v0 pretty : " << u0.pretty() << std::endl << std::endl;
std::cout << "uuid v1 string : " << u1 << std::endl;
std::cout << "uuid v1 base62 : " << u1.base62() << std::endl;
std::cout << "uuid v1 pretty : " << u1.pretty() << std::endl << std::endl;
std::cout << "uuid v4 string : " << u4 << std::endl;
std::cout << "uuid v4 base62 : " << u4.base62() << std::endl;
std::cout << "uuid v4 pretty : " << u4.pretty() << std::endl << std::endl;
u1 = sole::rebuild("F81D4FAE-7DEC-11D0-A765-00A0C91E6BF6");
u4 = sole::rebuild("GITheR4tLlg-BagIW20DGja");
std::cout << "uuid v1 rebuilt : " << u1 << " -> " << u1.pretty() << std::endl;
std::cout << "uuid v4 rebuilt : " << u4 << " -> " << u4.pretty() << std::endl;
}
#endif
#ifdef SOLE_BUILD_TESTS
// g++ users: `g++ sole.cxx -std=c++11 -lrt -o tests`
// visual studio: `cl.exe sole.cxx`
#include <cassert>
#include <set>
#include <ratio>
#include <chrono>
#include <iostream>
using namespace sole;
namespace run
{
auto epoch = [](){
return std::chrono::system_clock::to_time_t( std::chrono::system_clock::now() );
};
template<typename FN>
void benchmark( const FN &fn, const std::string &name ) {
std::cout << "Benchmarking " << name << "... " << std::flush;
auto then = epoch();
while( epoch() == then );
then = epoch();
unsigned c = 0;
while( epoch() == then ) c = ( fn(), ++c );
std::cout << (c) << " uuids/sec" << std::endl;
}
template<typename FN>
void tests( const FN &fn ) {
unsigned numtests = ~0;
std::cout << "Testing for " << numtests << " collisions... " << std::endl;
auto then = epoch();
std::set<uuid> all;
for( unsigned i = 0; i < numtests; ++i ) {
auto now = epoch();
if( now != then ) {
then = now;
double pct6digs = ( int( ( double(i) / (unsigned)(~0) ) * 1e4 ) / double(1e4) );
std::cout << '\r' << i << " uuids generated, no collision (" << pct6digs << "%)" << std::flush;
}
sole::uuid my_uuid = fn();
assert( all.find(my_uuid) == all.end() && "error: UUIDs just collided! is std::random_device a real random generator?" );
all.insert( my_uuid );
}
}
template<typename FN>
void verify( const FN &fn ) {
std::cout << "Verifying serialization of 1 million UUIDs... " << std::flush;
for( unsigned i = 0; i < 1000000; ++i ) {
sole::uuid uuid = fn();
sole::uuid rebuilt1 = sole::rebuild( uuid.str() );
sole::uuid rebuilt2 = sole::rebuild( uuid.base62() );
assert( rebuilt1 == uuid && "error: rebuild() or .str() failed" );
assert( rebuilt2 == uuid && "error: rebuild() or .base62() failed" );
}
std::cout << "ok" << std::endl;
}
}
int main() {
assert( sizeof(sole::uuid ) * 8 == 128 );
assert( sizeof(sole::uuid0().ab) * 8 == 64 );
assert( sizeof(sole::uuid0().cd) * 8 == 64 );
run::benchmark(uuid0, "v0");
run::benchmark(uuid1, "v1");
run::benchmark(uuid4, "v4");
run::verify(uuid4); // use fastest implementation
// run::tests(uuid0); // not applicable
// run::tests(uuid1); // not applicable
run::tests(uuid4);
}
#endif

29
core/utils/uuid/uuid.hpp

@ -0,0 +1,29 @@
#pragma once
#include <fstream>
#include <functional>
#include <iostream>
#include <list>
#include <map>
#include <memory>
#include <set>
#include <sstream>
#include <string>
#include <vector>
#include "iflytopcpp/core/utils/uuid/sole/sole.hpp"
namespace iflytop {
namespace core {
using namespace std;
class UUID {
public:
UUID() {
sole::uuid u4 = sole::uuid4();
value = u4.str();
};
~UUID(){};
const std::string &toString() { return value; };
private:
std::string value;
};
} // namespace core
} // namespace iflytop
Loading…
Cancel
Save