diff options
| author | Jonathan Bradley <jcb@pikum.xyz> | 2025-03-19 18:15:52 -0400 |
|---|---|---|
| committer | Jonathan Bradley <jcb@pikum.xyz> | 2025-03-20 12:01:56 -0400 |
| commit | 9cd55867de91013bdbfe0d73112df504eb7963ba (patch) | |
| tree | 35c7d25805c10a61dd65bd80febedb81e82c50bf | |
| parent | bc7e78b1766e8d9c9af1d47c207d084e161db98d (diff) | |
pkuuid.h: first-pass + bump version to 0.4.1
| -rw-r--r-- | Makefile | 17 | ||||
| -rw-r--r-- | config.mk | 2 | ||||
| -rw-r--r-- | pk.h.in | 21 | ||||
| -rw-r--r-- | pkuuid.h | 203 | ||||
| -rw-r--r-- | test/pkuuid.c | 165 | ||||
| -rw-r--r-- | test/pkuuid.cpp | 169 |
6 files changed, 576 insertions, 1 deletions
@@ -13,6 +13,7 @@ SRC = \ pkev.h \ pkarr.h \ pkstn.h \ + pkuuid.h \ test/pkmacros.c \ test/pkmacros.cpp \ test/pkmem-types.c \ @@ -29,6 +30,8 @@ SRC = \ test/pkstn.cpp \ test/pktmr.c\ test/pktmr.cpp \ + test/pkuuid.c\ + test/pkuuid.cpp \ OBJ = $(SRC:%.c=.o) PPOBJ = $(SRC:%.cpp=.so) @@ -44,6 +47,7 @@ all: options .WAIT clean .WAIT \ pkarr \ pkstn \ pktmr \ + pkuuid \ test/test-pkmem-types test/test-pkmem-types-cpp \ test/test-pkmem test/test-pkmem-cpp \ test/test-pkmacros test/test-pkmacros-cpp \ @@ -52,6 +56,7 @@ all: options .WAIT clean .WAIT \ test/test-pkarr test/test-pkarr-cpp \ test/test-pkstn test/test-pkstn-cpp \ test/test-pktmr test/test-pktmr-cpp \ + test/test-pkuuid test/test-pkuuid-cpp \ options: @echo at-suite build options: @@ -91,6 +96,8 @@ pkstn: pkstn.gch pkstn.gchpp pktmr: pktmr.gch pktmr.gchpp +pkuuid: pkuuid.gch pkuuid.gchpp + build: pkmacros build: pkmem-types build: pkmem @@ -109,6 +116,7 @@ build: pktmr pkarr.h \ pkstn.h \ pktmr.h \ + pkuuid.h \ >> pk.h echo "#endif /* PK_SINGLE_HEADER_FILE_H */" >> pk.h sed -i -r \ @@ -167,6 +175,12 @@ test/test-pktmr: test/pktmr.o test/test-pktmr-cpp: test/pktmr.so $(CXX) -g -O3 -std=c++23 $(CXXFLAGS) -o $@ $^ $(LDFLAGS) +test/test-pkuuid: test/pkuuid.o + $(CC) -g -O3 -std=c2x $(CFLAGS) -o $@ $^ $(LDFLAGS) + +test/test-pkuuid-cpp: test/pkuuid.so + $(CXX) -g -O3 -std=c++23 $(CXXFLAGS) -o $@ $^ $(LDFLAGS) + test: pkmacros pkmem-types pkmem pkstr pkev pkarr test: test/test-pkmacros test/test-pkmacros-cpp test: test/test-pkmem-types test/test-pkmem-types-cpp @@ -176,6 +190,7 @@ test: test/test-pkev test/test-pkev-cpp test: test/test-pkarr test/test-pkarr-cpp test: test/test-pkstn test/test-pkstn-cpp test: test/test-pktmr test/test-pktmr-cpp +test: test/test-pkuuid test/test-pkuuid-cpp test: @echo "" ./test/test-pkmacros ; echo Result: $$? "\n" @@ -194,6 +209,8 @@ test: ./test/test-pkstn-cpp ; echo Result: $$? "\n" ./test/test-pktmr ; echo Result: $$? "\n" ./test/test-pktmr-cpp ; echo Result: $$? "\n" + ./test/test-pkuuid ; echo Result: $$? "\n" + ./test/test-pkuuid-cpp ; echo Result: $$? "\n" clean: rm -f *.plist *.gch *.gchpp *.o *.so test/*.o test/*.so test/test-* @@ -1,5 +1,5 @@ # pk.h version -VERSION = 0.4.0 +VERSION = 0.4.1 # paths PREFIX = /usr/local @@ -184,6 +184,24 @@ * `pk_tmr.e` end the end time. * You could then call the `pk_tmr_duration...` convenience macros as needed. * +******************************************************************************** +* pkuuid.h: define PK_IMPL_UUID before including pk.h to enable ad-hoc. +* +* Provides a 16-byte unsigned char array struct for uuids. +* +* The following definitions (shown with defaults) can be overridden: +* PK_UUID_CLOCK CLOCK_TAI (preferred, if available) +* PK_UUID_CLOCK CLOCK_REALTIME (fallback) +* +* The `PK_UUID_CLOCK` macro has minimal built-in fallback logic. +* The uuidv7 specification states that the timestamp portion of the uuid must be +* a unix epoch, leap seconds EXCLUDED. Only `CLOCK_TAI` meets this requirement +* on Linux. +* +* Note that this currectly calls `srand()` once at startup, and calls `rand()` +* 2 times for each uuidv7 to fill 74 bits with random data (with an XOR for the +* remaining 10 bits). +* *******************************************************************************/ #define PK_VERSION "@@PK_VERSION@@" @@ -207,4 +225,7 @@ # ifndef PK_IMPL_STN # define PK_IMPL_STN # endif +# ifndef PK_IMPL_UUID +# define PK_IMPL_UUID +# endif #endif diff --git a/pkuuid.h b/pkuuid.h new file mode 100644 index 0000000..7426f79 --- /dev/null +++ b/pkuuid.h @@ -0,0 +1,203 @@ +#ifndef PK_UUID_H +#define PK_UUID_H + +#include "stddef.h" +#include <time.h> + +struct pk_uuid { + alignas(max_align_t) unsigned char uuid[16]; +}; + +const struct pk_uuid pk_uuid_zed = { .uuid = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }; +const struct pk_uuid pk_uuid_max = { .uuid = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } }; + +#define pk_uuid_printf_format PK_Q(%.2x%.2x%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x%.2x%.2x%.2x%.2x) +#define pk_uuid_printf_var(id) id.uuid[0], id.uuid[1], id.uuid[2], id.uuid[3], id.uuid[4], id.uuid[5], id.uuid[6], id.uuid[7], id.uuid[8], id.uuid[9], id.uuid[10], id.uuid[11], id.uuid[12], id.uuid[13], id.uuid[14], id.uuid[15] + +void pk_uuid_init(time_t srand_seed); +void pk_uuid_teardown(); + +struct pk_uuid pk_uuid_new_v7(); + +#if defined(__cplusplus) +#include <ostream> +#include <iomanip> +std::ostream& operator<<(std::ostream &o, const struct pk_uuid& uuid); +std::istream& operator>>(std::istream &i, struct pk_uuid& uuid); +#endif + +#endif /* PK_UUID_H */ + +#ifdef PK_IMPL_UUID + +#include <stdatomic.h> +#include <stdlib.h> +#include <stdint.h> + +// TODO JCB - 2025-03-19 +// This should have platform-specific defines +#ifndef PK_UUID_CLOCK + #ifdef CLOCK_TAI + #define PK_UUID_CLOCK CLOCK_TAI + #else + #define PK_UUID_CLOCK CLOCK_REALTIME + #endif +#endif + +void +pk_uuid_init(time_t srand_seed) +{ + // TODO 2025-03-19 - JCB + // pk.h should NOT be setting srand. + // Replace dependency on rand/srand with a sufficient rand() implementation. + // I would prefer if generating a UUID did not advance a global random. + // Consider creating a pkrand.h to resolve this. + srand(srand_seed); +} + +void +pk_uuid_teardown() +{ +} + +struct pk_uuid +pk_uuid_new_v7() +{ + const int n = 1; + uint32_t r; + // https://www.rfc-editor.org/rfc/rfc9562.html#name-uuid-version-7 + struct pk_uuid ret; + struct timespec t; + clock_gettime(PK_UUID_CLOCK, &t); + uint32_t sec = (uint32_t)t.tv_sec; + uint32_t nsec = (uint32_t)t.tv_nsec; + // [000-047] (6 bytes) big-endian unix epoch + // TODO test this on a big-endian machine, I don't think this is correct. + // This `if` determines if we are big or little endian. + // A return value of 1 says we are little endian, so swap the bits. + if (*(char *)&n == 1) { + ret.uuid[0] = (uint8_t)((sec & 0xFF000000) >> 24); + ret.uuid[1] = (uint8_t)((sec & 0x00FF0000) >> 16); + ret.uuid[2] = (uint8_t)((sec & 0x0000FF00) >> 8); + ret.uuid[3] = (uint8_t)((sec & 0x000000FF) >> 0); + ret.uuid[4] = (uint8_t)((nsec & 0x0000FF00) >> 8); + ret.uuid[5] = (uint8_t)((nsec & 0x000000FF) >> 0); + } else { + ret.uuid[0] = (uint8_t)((sec & 0xFF000000) >> 0); + ret.uuid[1] = (uint8_t)((sec & 0x00FF0000) >> 8); + ret.uuid[2] = (uint8_t)((sec & 0x0000FF00) >> 16); + ret.uuid[3] = (uint8_t)((sec & 0x000000FF) >> 24); + ret.uuid[4] = (uint8_t)((nsec & 0xFF000000) >> 0); + ret.uuid[5] = (uint8_t)((nsec & 0x00FF0000) >> 8); + } + // [052-127] random + r = (uint32_t)rand(); + if (*(char *)&n == 1) { + ret.uuid[8] = (uint8_t)((r & 0xFF000000) >> 24); + ret.uuid[9] = (uint8_t)((r & 0x00FF0000) >> 16); + ret.uuid[10] = (uint8_t)((r & 0x0000FF00) >> 8); + ret.uuid[11] = (uint8_t)((r & 0x000000FF) >> 0); + } else { + ret.uuid[8] = (uint8_t)((r & 0xFF000000) >> 0); + ret.uuid[9] = (uint8_t)((r & 0x00FF0000) >> 8); + ret.uuid[10] = (uint8_t)((r & 0x0000FF00) >> 16); + ret.uuid[11] = (uint8_t)((r & 0x000000FF) >> 24); + } + r = rand(); + if (*(char *)&n == 1) { + ret.uuid[12] = (uint8_t)((r & 0xFF000000) >> 24); + ret.uuid[13] = (uint8_t)((r & 0x00FF0000) >> 16); + ret.uuid[14] = (uint8_t)((r & 0x0000FF00) >> 8); + ret.uuid[15] = (uint8_t)((r & 0x000000FF) >> 0); + } else { + ret.uuid[12] = (uint8_t)((r & 0xFF000000) >> 0); + ret.uuid[13] = (uint8_t)((r & 0x00FF0000) >> 8); + ret.uuid[14] = (uint8_t)((r & 0x0000FF00) >> 16); + ret.uuid[15] = (uint8_t)((r & 0x000000FF) >> 24); + } + ret.uuid[6] = ret.uuid[9] ^ ret.uuid[12]; + ret.uuid[7] = ret.uuid[10] ^ ret.uuid[15]; + + // [048-051] v7 nibble + // version must be 0x7_ + // 0x70 is 0b01110000 + // 0x7F is 0b01111111 + ret.uuid[6] |= 0x70; + ret.uuid[6] &= 0x7F; + + // [064-065] 2-bit variant field + // variant must be 0b10 + // 0x80 is 0b10000000 + // 0xBF is 0b10111111 + ret.uuid[8] |= 0x80; + ret.uuid[8] &= 0xBF; + + return ret; +} + +#if defined(__cplusplus) +#include "./pkstn.h" /* deleteme */ +std::ostream& +operator<<(std::ostream &o, const struct pk_uuid& uuid) +{ + int i; + o << std::hex; + for (i = 0; i < 4; ++i) { + o << std::setw(2) << std::setfill('0'); + o << (uint16_t)uuid.uuid[i]; + } + o << "-"; + for (i = 4; i < 6; ++i) { + o << std::setw(2) << std::setfill('0'); + o << (uint16_t)uuid.uuid[i]; + } + o << "-"; + for (i = 6; i < 8; ++i) { + o << std::setw(2) << std::setfill('0'); + o << (uint16_t)uuid.uuid[i]; + } + o << "-"; + for (i = 8; i < 10; ++i) { + o << std::setw(2) << std::setfill('0'); + o << (uint16_t)uuid.uuid[i]; + } + o << "-"; + for (i = 10; i < 16; ++i) { + o << std::setw(2) << std::setfill('0'); + o << (uint16_t)uuid.uuid[i]; + } + return o; +} + +std::istream& +operator>>(std::istream &i, struct pk_uuid& uuid) +{ + char c[3]; + char k = 0; + char offset = 0; + c[2] = '\0'; + for (k = 0; k < 20; ++k) { + if (k == 4 || k == 7 || k == 10 || k == 13) { + offset += 1; + c[0] = i.peek(); + if (c[0] != '-') { + goto err_out; + } + i.get(); // burn + continue; + } + i.get(c[0]); + i.get(c[1]); + if (pk_stn_uint8_t(&uuid.uuid[k - offset], c, 16) != PK_STN_RES_SUCCESS) { + goto err_out; + } + } + return i; +err_out: + i.seekg(-(((k + 1) * 2) + offset), std::ios_base::cur); + uuid = pk_uuid_zed; + return i; +} +#endif + +#endif diff --git a/test/pkuuid.c b/test/pkuuid.c new file mode 100644 index 0000000..ee550cf --- /dev/null +++ b/test/pkuuid.c @@ -0,0 +1,165 @@ + +#define PK_IMPL_UUID +#define PK_IMPL_TMR +// #define PK_UUID_CLOCK CLOCK_REALTIME_ALARM + +#include "../pkmacros.h" +#include "../pkuuid.h" + +#include "../pktmr.h" + +#include <stdio.h> + +void +print_uuid_v7_breakdown(FILE *f, struct pk_uuid id) +{ + fprintf(f, "-------------------------------------------\n"); + fprintf(f, "field bits value\n"); + fprintf(f, "-------------------------------------------\n"); + fprintf(f, "unix_ts_ms 48 0x"); + fprintf(f, "%.2x", id.uuid[0]); + fprintf(f, "%.2x", id.uuid[1]); + fprintf(f, "%.2x", id.uuid[2]); + fprintf(f, "%.2x", id.uuid[3]); + fprintf(f, "%.2x", id.uuid[4]); + fprintf(f, "%.2x", id.uuid[5]); + fprintf(f, "\n"); + + fprintf(f, "ver 4 0x"); + fprintf(f, "%.x", (id.uuid[6] & 0xF0) >> 4); + fprintf(f, "\n"); + + fprintf(f, "rand_a 12 0x"); + fprintf(f, "%.1x", (id.uuid[6] & 0x0F)); + fprintf(f, "%.2x", id.uuid[7]); + fprintf(f, "\n"); + + fprintf(f, "var 2 0b"); + fprintf(f, "%.c", (id.uuid[8] & 0x80) ? '1' : '0'); + fprintf(f, "%.c", (id.uuid[8] & 0x40) ? '1' : '0'); + fprintf(f, "\n"); + + fprintf(f, "rand_b 62 0b"); + fprintf(f, "%.c", (id.uuid[8] & 0x20) ? '1' : '0'); + fprintf(f, "%.c", (id.uuid[8] & 0x10) ? '1' : '0'); + fprintf(f, ", 0x"); + fprintf(f, "%.x", (id.uuid[8] & 0x0F)); + fprintf(f, "%.2x", id.uuid[9]); + fprintf(f, "%.2x", id.uuid[10]); + fprintf(f, "%.2x", id.uuid[11]); + fprintf(f, "%.2x", id.uuid[12]); + fprintf(f, "%.2x", id.uuid[13]); + fprintf(f, "%.2x", id.uuid[14]); + fprintf(f, "%.2x", id.uuid[15]); + fprintf(f, "\n"); + + fprintf(f, "-------------------------------------------\n"); +} + +int +main(int argc, char *argv[]) +{ + (void)argc; + (void)argv; + pk_uuid_init(time(NULL)); + + fprintf(stdout, "\n"); + { + struct pk_uuid id; + id = pk_uuid_zed; + fprintf(stdout, "[%s] zed: " pk_uuid_printf_format "\n", __FILE__, pk_uuid_printf_var(id)); + } + + { + struct pk_uuid id; + id = pk_uuid_max; + fprintf(stdout, "[%s] one: " pk_uuid_printf_format "\n", __FILE__, pk_uuid_printf_var(id)); + } + + { + const int count = 4; + struct pk_uuid ids[count]; + + for (int i = 0; i < count; ++i) { + ids[i] = pk_uuid_new_v7(); + } + for (int i = 0; i < count; ++i) { + fprintf(stdout, "[%s] new: " pk_uuid_printf_format "\n", __FILE__, pk_uuid_printf_var(ids[i])); + } + + for (int i = 0; i < count; ++i) { + fprintf(stdout, "\n"); + print_uuid_v7_breakdown(stdout, ids[i]); + fprintf(stdout, "[%s] new: " pk_uuid_printf_format "\n", __FILE__, pk_uuid_printf_var(ids[i])); + } + fprintf(stdout, "\n"); + } + + { + double ms; + const int count = 1000; + struct pk_uuid ids[count]; + struct pk_tmr tmr; + pk_tmr_start(tmr); + for (int i = 0; i < count; ++i) { + ids[i] = pk_uuid_new_v7(); + } + pk_tmr_stop(tmr); + fprintf(stdout, "generated %i ids...\n", count); + ms = pk_tmr_duration_dbl_mili(tmr); + fprintf(stdout, "elapsed time : %f ms\n", ms); + fprintf(stdout, "elapsed time (avg): %f ms\n", ms / (double)count); + fprintf(stdout, pk_uuid_printf_format "\n", pk_uuid_printf_var(ids[0])); + fprintf(stdout, pk_uuid_printf_format "\n", pk_uuid_printf_var(ids[99])); + } + + // not really a test, just checking time + /* 2025-03-19 JCB - Disabled because we added a macro to define the clock + * instead of passing it as a parameter. + { + double ms; + const int count = 1000; + struct pk_uuid ids[count]; + struct pk_tmr tmr; + pk_tmr_start(tmr); + for (int i = 0; i < count; ++i) { + ids[i] = pk_uuid_new_v7(CLOCK_REALTIME); + } + pk_tmr_stop(tmr); + fprintf(stdout, "generated %i ids using CLOCK_REALTIME...\n", count); + ms = pk_tmr_duration_dbl_mili(tmr); + fprintf(stdout, "elapsed time : %f ms\n", ms); + fprintf(stdout, "elapsed time (avg): %f ms\n", ms / (double)count); + fprintf(stdout, pk_uuid_printf_format "\n", pk_uuid_printf_var(ids[0])); + fprintf(stdout, pk_uuid_printf_format "\n", pk_uuid_printf_var(ids[99])); + + pk_tmr_start(tmr); + for (int i = 0; i < count; ++i) { + ids[i] = pk_uuid_new_v7(CLOCK_REALTIME_COARSE); + } + pk_tmr_stop(tmr); + fprintf(stdout, "generated %i ids using CLOCK_REALTIME_COARSE...\n", count); + ms = pk_tmr_duration_dbl_mili(tmr); + fprintf(stdout, "elapsed time : %f ms\n", ms); + fprintf(stdout, "elapsed time (avg): %f ms\n", ms / (double)count); + fprintf(stdout, pk_uuid_printf_format "\n", pk_uuid_printf_var(ids[0])); + fprintf(stdout, pk_uuid_printf_format "\n", pk_uuid_printf_var(ids[99])); + + pk_tmr_start(tmr); + for (int i = 0; i < count; ++i) { + ids[i] = pk_uuid_new_v7(CLOCK_TAI); + } + pk_tmr_stop(tmr); + fprintf(stdout, "generated %i ids using CLOCK_TAI...\n", count); + ms = pk_tmr_duration_dbl_mili(tmr); + fprintf(stdout, "elapsed time : %f ms\n", ms); + fprintf(stdout, "elapsed time (avg): %f ms\n", ms / (double)count); + fprintf(stdout, pk_uuid_printf_format "\n", pk_uuid_printf_var(ids[0])); + fprintf(stdout, pk_uuid_printf_format "\n", pk_uuid_printf_var(ids[99])); + } + */ + + pk_uuid_teardown(); + + return 0; +} diff --git a/test/pkuuid.cpp b/test/pkuuid.cpp new file mode 100644 index 0000000..278cd02 --- /dev/null +++ b/test/pkuuid.cpp @@ -0,0 +1,169 @@ + +#define PK_IMPL_UUID +#define PK_IMPL_TMR +// #define PK_UUID_CLOCK CLOCK_REALTIME_ALARM + +#include "../pkmacros.h" +#include "../pkuuid.h" + +#include "../pktmr.h" + +#include <iostream> +#include <sstream> +#include <stdio.h> + +void +print_uuid_v7_breakdown(FILE *f, struct pk_uuid id) +{ + fprintf(f, "-------------------------------------------\n"); + fprintf(f, "field bits value\n"); + fprintf(f, "-------------------------------------------\n"); + fprintf(f, "unix_ts_ms 48 0x"); + fprintf(f, "%.2x", id.uuid[0]); + fprintf(f, "%.2x", id.uuid[1]); + fprintf(f, "%.2x", id.uuid[2]); + fprintf(f, "%.2x", id.uuid[3]); + fprintf(f, "%.2x", id.uuid[4]); + fprintf(f, "%.2x", id.uuid[5]); + fprintf(f, "\n"); + + fprintf(f, "ver 4 0x"); + fprintf(f, "%.x", (id.uuid[6] & 0xF0) >> 4); + fprintf(f, "\n"); + + fprintf(f, "rand_a 12 0x"); + fprintf(f, "%.1x", (id.uuid[6] & 0x0F)); + fprintf(f, "%.2x", id.uuid[7]); + fprintf(f, "\n"); + + fprintf(f, "var 2 0b"); + fprintf(f, "%.c", (id.uuid[8] & 0x80) ? '1' : '0'); + fprintf(f, "%.c", (id.uuid[8] & 0x40) ? '1' : '0'); + fprintf(f, "\n"); + + fprintf(f, "rand_b 62 0b"); + fprintf(f, "%.c", (id.uuid[8] & 0x20) ? '1' : '0'); + fprintf(f, "%.c", (id.uuid[8] & 0x10) ? '1' : '0'); + fprintf(f, ", 0x"); + fprintf(f, "%.x", (id.uuid[8] & 0x0F)); + fprintf(f, "%.2x", id.uuid[9]); + fprintf(f, "%.2x", id.uuid[10]); + fprintf(f, "%.2x", id.uuid[11]); + fprintf(f, "%.2x", id.uuid[12]); + fprintf(f, "%.2x", id.uuid[13]); + fprintf(f, "%.2x", id.uuid[14]); + fprintf(f, "%.2x", id.uuid[15]); + fprintf(f, "\n"); + + fprintf(f, "-------------------------------------------\n"); +} + +int +main(int argc, char *argv[]) +{ + (void)argc; + (void)argv; + pk_uuid_init(time(NULL)); + const struct pk_uuid example_id = { .uuid = { 0x01, 0x7F, 0x22, 0xE2, 0x79, 0xB0, 0x7C, 0xC3, 0x98, 0xC4, 0xDC, 0x0C, 0x0C, 0x07, 0x39, 0x8F } }; + + fprintf(stdout, "\n"); + { + struct pk_uuid id; + id = pk_uuid_zed; + fprintf(stdout, "[%s] zed: " pk_uuid_printf_format "\n", __FILE__, pk_uuid_printf_var(id)); + } + + { + struct pk_uuid id; + id = pk_uuid_max; + fprintf(stdout, "[%s] one: " pk_uuid_printf_format "\n", __FILE__, pk_uuid_printf_var(id)); + } + + { + const int count = 4; + struct pk_uuid ids[count]; + + for (int i = 0; i < count; ++i) { + ids[i] = pk_uuid_new_v7(); + } + for (int i = 0; i < count; ++i) { + fprintf(stdout, "[%s] new: " pk_uuid_printf_format "\n", __FILE__, pk_uuid_printf_var(ids[i])); + } + + for (int i = 0; i < count; ++i) { + fprintf(stdout, "\n"); + print_uuid_v7_breakdown(stdout, ids[i]); + fprintf(stdout, "[%s] new: " pk_uuid_printf_format "\n", __FILE__, pk_uuid_printf_var(ids[i])); + } + fprintf(stdout, "\n"); + } + + { + double ms; + const int count = 1000; + struct pk_uuid ids[count]; + struct pk_tmr tmr; + pk_tmr_start(tmr); + for (int i = 0; i < count; ++i) { + ids[i] = pk_uuid_new_v7(); + } + pk_tmr_stop(tmr); + fprintf(stdout, "generated %i ids...\n", count); + ms = pk_tmr_duration_dbl_mili(tmr); + fprintf(stdout, "elapsed time : %f ms\n", ms); + fprintf(stdout, "elapsed time (avg): %f ms\n", ms / (double)count); + fprintf(stdout, pk_uuid_printf_format "\n", pk_uuid_printf_var(ids[0])); + fprintf(stdout, pk_uuid_printf_format "\n", pk_uuid_printf_var(ids[99])); + } + + // << + { + std::stringstream ss; + ss << example_id; + + fprintf(stdout, "\n"); + fprintf(stdout, "[%s] expected: 017f22e2-79b0-7cc3-98c4-dc0c0c07398f\n", __FILE__); + fprintf(stdout, "[%s] result : %s\n", __FILE__, ss.str().c_str()); + if (ss.str() != "017f22e2-79b0-7cc3-98c4-dc0c0c07398f") return 1; + } + + // >> + { + struct pk_uuid id; + std::istringstream ssi("017f22e2-79b0-7cc3-98c4-dc0c0c07398f"); + + ssi >> id; + ssi >> std::cout.rdbuf(); + + fprintf(stdout, "\n"); + fprintf(stdout, "[%s] excpected: 017f22e2-79b0-7cc3-98c4-dc0c0c07398f\n", __FILE__); + fprintf(stdout, "[%s] result : " pk_uuid_printf_format "\n", __FILE__, pk_uuid_printf_var(id)); + + for (int i = 0; i < 16; ++i) { + if (example_id.uuid[i] != id.uuid[i]) return 1; + } + } + + // >> err + { + struct pk_uuid id; + std::istringstream ssi("gnud"); + + ssi >> id; + + fprintf(stdout, "\n"); + fprintf(stdout, "[%s] leftovers: ", __FILE__); + ssi >> std::cout.rdbuf(); + std::cout << std::endl; + fprintf(stdout, "[%s] excpected: 00000000-0000-0000-0000-000000000000\n", __FILE__); + fprintf(stdout, "[%s] result : " pk_uuid_printf_format "\n", __FILE__, pk_uuid_printf_var(id)); + + for (int i = 0; i < 16; ++i) { + if (pk_uuid_zed.uuid[i] != id.uuid[i]) return 1; + } + } + + pk_uuid_teardown(); + + return 0; +} |
