dotfiles/packages/firefox-webserial/extra_src/uuid4.c
2024-11-07 16:25:41 -07:00

358 lines
8.5 KiB
C

// (‑●‑●)> dual licensed under the WTFPL v2 and MIT licenses
// without any warranty.
// by Gregory Pakosz (@gpakosz)
// https://github.com/gpakosz/uuid4
#if defined(__linux__)
#if !defined(_GNU_SOURCE)
#define _GNU_SOURCE
#endif
#endif
// in case you want to #include "uuid4.c" in a larger compilation unit
#if !defined(UUID_4H)
#include <uuid4.h>
#endif
#if !defined(UUID4_ASSERT)
#include <assert.h>
#define UUID4_ASSERT(expression) assert(expression)
#endif
#ifdef __cplusplus
extern "C" {
#endif
// —————————————————————————————————————————————————————————————————————————————
// http://xoshiro.di.unimi.it/splitmix64.c
// Written in 2015 by Sebastiano Vigna (vigna@acm.org)
/*
This is a fixed-increment version of Java 8's SplittableRandom generator
See http://dx.doi.org/10.1145/2714064.2660195 and
http://docs.oracle.com/javase/8/docs/api/java/util/SplittableRandom.html
It is a very fast generator passing BigCrush.
*/
static inline uint64_t UUID4_PREFIX(splitmix64)(uint64_t* state)
{
uint64_t z = (*state += 0x9E3779B97F4A7C15u);
z = (z ^ (z >> 30)) * 0xBF58476D1CE4E5B9u;
z = (z ^ (z >> 27)) * 0x94D049BB133111EBu;
return z ^ (z >> 31);
}
// http://www.pcg-random.org/posts/developing-a-seed_seq-alternative.html
// Written in 2015 by Melissa O'Neil (oneill@pcg-random.org)
static inline uint32_t UUID4_PREFIX(hash)(uint32_t value)
{
static uint32_t multiplier = 0x43b0d7e5u;
value ^= multiplier;
multiplier *= 0x931e8875u;
value *= multiplier;
value ^= value >> 16;
return value;
}
static inline uint32_t UUID4_PREFIX(mix)(uint32_t x, uint32_t y)
{
uint32_t result = 0xca01f9ddu * x - 0x4973f715u * y;
result ^= result >> 16;
return result;
}
// —————————————————————————————————————————————————————————————————————————————
#if defined(_WIN32)
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
UUID4_FUNCSPEC
void UUID4_PREFIX(seed)(uint64_t* state)
{
static uint64_t state0 = 0;
LARGE_INTEGER time;
BOOL ok = QueryPerformanceCounter(&time);
UUID4_ASSERT(ok);
*state = state0++ + ((uintptr_t)&time ^ (uint64_t)time.QuadPart);
uint32_t pid = (uint32_t)GetCurrentProcessId();
uint32_t tid = (uint32_t)GetCurrentThreadId();
*state = *state * 6364136223846793005u + ((uint64_t)(UUID4_PREFIX(mix)(UUID4_PREFIX(hash)(pid), UUID4_PREFIX(hash)(tid))) << 32);
*state = *state * 6364136223846793005u + (uintptr_t)GetCurrentProcessId;
*state = *state * 6364136223846793005u + (uintptr_t)UUID4_PREFIX(gen);
}
#elif defined(__linux__)
#if !defined(UUID4_CLOCK_ID)
#define UUID4_CLOCK_ID CLOCK_MONOTONIC_RAW
#endif
#include <time.h>
#include <unistd.h>
#include <sys/syscall.h>
UUID4_FUNCSPEC
void UUID4_PREFIX(seed)(uint64_t* state)
{
static uint64_t state0 = 0;
struct timespec time;
bool ok = clock_gettime(UUID4_CLOCK_ID, &time) == 0;
UUID4_ASSERT(ok);
*state = state0++ + ((uintptr_t)&time ^ (uint64_t)(time.tv_sec * 1000000000 + time.tv_nsec));
uint32_t pid = (uint32_t)getpid();
uint32_t tid = (uint32_t)syscall(SYS_gettid);
*state = *state * 6364136223846793005u + ((uint64_t)(UUID4_PREFIX(mix)(UUID4_PREFIX(hash)(pid), UUID4_PREFIX(hash)(tid))) << 32);
*state = *state * 6364136223846793005u + (uintptr_t)getpid;
*state = *state * 6364136223846793005u + (uintptr_t)UUID4_PREFIX(gen);
}
#elif defined(__APPLE__)
#include <mach/mach_time.h>
#include <unistd.h>
#include <pthread.h>
UUID4_FUNCSPEC
void UUID4_PREFIX(seed)(uint64_t* state)
{
static uint64_t state0 = 0;
uint64_t time = mach_absolute_time();
*state = state0++ + time;
uint32_t pid = (uint32_t)getpid();
uint64_t tid;
pthread_threadid_np(NULL, &tid);
*state = *state * 6364136223846793005u + ((uint64_t)(UUID4_PREFIX(mix)(UUID4_PREFIX(hash)(pid), UUID4_PREFIX(hash)((uint32_t)tid))) << 32);
*state = *state * 6364136223846793005u + (uintptr_t)getpid;
*state = *state * 6364136223846793005u + (uintptr_t)UUID4_PREFIX(gen);
}
#else
#error unsupported platform
#endif
#include <stdio.h>
#include <inttypes.h>
static void UUID4_PREFIX(randomize)(UUID4_STATE_T* state, UUID4_T* out)
{
out->qwords[0] = UUID4_PREFIX(splitmix64)(state);
out->qwords[1] = UUID4_PREFIX(splitmix64)(state);
}
UUID4_FUNCSPEC
void UUID4_PREFIX(gen)(UUID4_STATE_T* state, UUID4_T* out)
{
UUID4_PREFIX(randomize)(state, out);
out->bytes[6] = (out->bytes[6] & 0xf) | 0x40;
out->bytes[8] = (out->bytes[8] & 0x3f) | 0x80;
}
UUID4_FUNCSPEC
bool UUID4_PREFIX(to_s)(const UUID4_T uuid, char* out, int capacity)
{
static const char hex[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
static const int groups[] = { 8, 4, 4, 4, 12 };
int b = 0;
if (capacity < UUID4_STR_BUFFER_SIZE)
return false;
for (int i = 0; i < (int)(sizeof(groups) / sizeof(groups[0])); ++i)
{
for (int j = 0; j < groups[i]; j += 2)
{
uint8_t byte = uuid.bytes[b++];
*out++ = hex[byte >> 4];
*out++ = hex[byte & 0xf];
}
*out++ = '-';
}
*--out = 0;
return true;
}
#if defined (UUID4_PRACTRAND_TEST)
// $ gcc -O2 -Wall -Werror -DUUID4_PRACTPRAND_TEST -o uuid4_practrand_test uuid.c
#include <stdlib.h>
#include <stdio.h>
#ifdef _WIN32
#include <io.h>
#include <fcntl.h>
#else
#include <unistd.h>
#endif
int main()
{
if (isatty(fileno(stdout)))
{
fprintf(stderr, "usage: uuid4_practrand_test | RNG_test stdin64\n");
exit(EXIT_FAILURE);
}
#ifdef _WIN32
_setmode(fileno(stdout), _O_BINARY);
#endif
UUID4_STATE_T state;
UUID4_PREFIX(seed)(&state);
while (true)
{
UUID4_T uuid[1024];
for (size_t i = 0; i < sizeof(uuid) / sizeof(uuid[0]); ++i)
UUID4_PREFIX(randomize)(&state, &uuid[i]);
fwrite(uuid, sizeof(uuid), 1, stdout);
}
return 0;
}
#elif defined(UUID4_TESTU01_TEST)
#include <stdlib.h>
#include <TestU01.h>
static inline uint32_t rev32(uint32_t v)
{
// https://graphics.stanford.edu/~seander/bithacks.html
// swap odd and even bits
v = ((v >> 1) & 0x55555555) | ((v & 0x55555555) << 1);
// swap consecutive pairs
v = ((v >> 2) & 0x33333333) | ((v & 0x33333333) << 2);
// swap nibbles ...
v = ((v >> 4) & 0x0F0F0F0F) | ((v & 0x0F0F0F0F) << 4);
// swap bytes
v = ((v >> 8) & 0x00FF00FF) | ((v & 0x00FF00FF) << 8);
// swap 2-byte-long pairs
v = ( v >> 16 ) | ( v << 16);
return v;
}
static UUID4_STATE_T state;
static unsigned int gen_uuid_0()
{
UUID4_T uuid;
UUID4_PREFIX(randomize)(&state, &uuid);
return uuid.dwords[0];
}
static unsigned int gen_uuid_0_rev()
{
return rev32(gen_uuid_0());
}
static unsigned int gen_uuid_1()
{
UUID4_T uuid;
UUID4_PREFIX(randomize)(&state, &uuid);
return uuid.dwords[1];
}
static unsigned int gen_uuid_1_rev()
{
return rev32(gen_uuid_1());
}
static unsigned int gen_uuid_2()
{
UUID4_T uuid;
UUID4_PREFIX(randomize)(&state, &uuid);
return uuid.dwords[2];
}
static unsigned int gen_uuid_2_rev()
{
return rev32(gen_uuid_2());
}
static unsigned int gen_uuid_3()
{
UUID4_T uuid;
UUID4_PREFIX(randomize)(&state, &uuid);
return uuid.dwords[3];
}
static unsigned int gen_uuid_3_rev()
{
return rev32(gen_uuid_3());
}
int main(int argc, char* argv[])
{
swrite_Basic = FALSE;
UUID4_PREFIX(seed)(&state);
struct
{
const char* name;
unsigned int (*gen)();
} gens[] =
{
{"uuid4.dwords[0]", gen_uuid_0}, {"uuid4.dwords[0] (reversed)", gen_uuid_0_rev},
{"uuid4.dwords[1]", gen_uuid_1}, {"uuid4.dwords[1] (reversed)", gen_uuid_1_rev},
{"uuid4.dwords[2]", gen_uuid_2}, {"uuid4.dwords[2] (reversed)", gen_uuid_2_rev},
{"uuid4.dwords[3]", gen_uuid_3}, {"uuid4.dwords[3] (reversed)", gen_uuid_3_rev}
};
for (size_t i = 0; i < sizeof(gens) / sizeof(gens[0]); ++i)
{
unif01_Gen* gen = unif01_CreateExternGenBits((char*)gens[i].name, gens[i].gen);
bbattery_SmallCrush(gen);
unif01_DeleteExternGenBits(gen);
}
for (size_t i = 0; i < sizeof(gens) / sizeof(gens[0]); ++i)
{
unif01_Gen* gen = unif01_CreateExternGenBits((char*)gens[i].name, gens[i].gen);
bbattery_Crush(gen);
unif01_DeleteExternGenBits(gen);
}
for (size_t i = 0; i < sizeof(gens) / sizeof(gens[0]); ++i)
{
unif01_Gen* gen = unif01_CreateExternGenBits((char*)gens[i].name, gens[i].gen);
bbattery_BigCrush(gen);
unif01_DeleteExternGenBits(gen);
}
return 0;
}
#endif
#ifdef __cplusplus
}
#endif