• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

bkwoka / UUIDv7 / 23072519346

13 Mar 2026 10:10PM UTC coverage: 98.592% (-0.1%) from 98.693%
23072519346

push

github

bkwoka
fix: resolve post-refactor code review findings

- Fixed critical preprocessor bug: moved UUID7_OPTIMIZE_SIZE definition before TimestampState.h inclusion to ensure AVR RAM optimization is correctly applied.
- Fixed Makefile: added UUID7Rng.cpp and UUID7Clock.cpp to SRC to resolve linker errors in native builds.
- Refactored UUID7Rng.cpp: removed unnecessary public getter setEntropyAnalogPinFallback() and accessed private member directly.
- Added missing <string.h> include in UUID7Rng.cpp for memcpy.
- Updated CONTRIBUTING.md to use wildcards for clang-format command.

1 of 1 new or added line in 1 file covered. (100.0%)

4 existing lines in 1 file now uncovered.

280 of 284 relevant lines covered (98.59%)

72.92 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

97.14
/src/UUID7.cpp
1
// SPDX-License-Identifier: MIT
2
// Copyright (c) 2026 bkwoka
3
// Repository: https://github.com/bkwoka/UUIDv7
4

5
#include "UUID7.h"
6
#include "UUID7Codec.h"
7
#include "UUID7Guard.h"
8
#include <string.h>
9

10
#if defined(PLATFORMIO_ESP32) || defined(ARDUINO_ARCH_ESP32)
11
portMUX_TYPE _uuid_spinlock = portMUX_INITIALIZER_UNLOCKED;
12
#elif defined(ARDUINO_ARCH_RP2040) && defined(PICO_SDK_VERSION_MAJOR)
13
spin_lock_t *_uuid_rp2040_spinlock = nullptr;
14
__attribute__((constructor)) static void _uuid_init_spinlock() {
15
  int lock_num = spin_lock_claim_unused(false);
16
  if (lock_num >= 0) {
17
    _uuid_rp2040_spinlock = spin_lock_init(lock_num);
18
  }
19
}
20
#elif defined(PLATFORMIO_NATIVE)
21
#include <thread>
22
std::mutex _uuid_mutex;
23
static inline void yield() { std::this_thread::yield(); }
18✔
24
#else
25
#if !defined(ARDUINO)
26
static inline void yield() {}
27
#endif
28
#endif
29

30

31

32
UUID7::UUID7(fill_random_fn rng, void *rng_ctx, now_ms_fn now,
76✔
33
             void *now_ctx) noexcept
76✔
34
    : _version(UUID_VERSION_7), _overflowPolicy(UUID_OVERFLOW_FAIL_FAST),
76✔
35
      _rng(rng),
76✔
36
      // Provide instance context to static RNG function for accessing fallback entropy parameters
37
      _rng_ctx(rng ? rng_ctx : this), _now(now), _now_ctx(now_ctx),
76✔
38
      _entropy_mixer(0),
76✔
39
      _regressionThresholdMs(10000), _lock_cb(nullptr), _unlock_cb(nullptr) {
76✔
40
  memset(_b, 0, sizeof(_b));
76✔
41

42
#if defined(ARDUINO_ARCH_AVR) || defined(__AVR__)
43
#if defined(A0)
44
  _entropyAnalogPin = A0;
45
#else
46
  // Default to pin 14 (A0) for ATmega328P based boards (Uno/Nano)
47
  _entropyAnalogPin = 14;
48
#endif
49
#else
50
  _entropyAnalogPin = -1;
76✔
51
#endif
52
}
76✔
53

54
void UUID7::setVersion(UUIDVersion v) { _version = v; }
10✔
55

56
void UUID7::setStorage(uuid_load_fn load_fn, uuid_save_fn save_fn, void *ctx,
8✔
57
                       uint32_t auto_save_interval_ms) {
58
  _persistence.load = load_fn;
8✔
59
  _persistence.save = save_fn;
8✔
60
  _persistence.ctx = ctx;
8✔
61
  _persistence.interval_ms = auto_save_interval_ms;
8✔
62
}
8✔
63

64
void UUID7::load() {
6✔
65
  if (_persistence.load) {
6✔
66
    uint64_t saved_ts = _persistence.load(_persistence.ctx);
6✔
67
    if (saved_ts > 0) {
6✔
68
      _persistence.last_saved_ms = saved_ts;
4✔
69
      uint64_t target = saved_ts + _persistence.interval_ms;
4✔
70

71
      _tsState.set(target);
4✔
72
    }
73
  }
74
}
6✔
75

76

77

78
bool UUID7::_incrementRandom() noexcept {
18✔
79
  // Continuously increment the random section, respecting variant/version boundaries.
80
  for (int i = 15; i >= 9; i--) {
48✔
81
    if (++_b[i] != 0)
44✔
82
      return true;
14✔
83
  }
84

85
  // Increment byte 8 (variant byte), preserving RFC variant flags (10x)
86
  uint8_t b8 = _b[8] & 0x3F;
4✔
87
  b8++;
4✔
88
  _b[8] = (_b[8] & 0xC0) | (b8 & 0x3F);
4✔
89
  if ((b8 & 0x40) == 0)
4✔
UNCOV
90
    return true; // No overflow if carry didn't reach bit 6
×
91

92

93
  if (++_b[7] != 0)
4✔
UNCOV
94
    return true;
×
95

96
  // Increment byte 6 (version byte), preserving UUID version flags (0111)
97
  uint8_t b6 = _b[6] & 0x0F;
4✔
98
  b6++;
4✔
99
  _b[6] = (_b[6] & 0xF0) | (b6 & 0x0F);
4✔
100

101
  if ((b6 & 0x10) == 0)
4✔
UNCOV
102
    return true; // No overflow if carry didn't reach bit 4
×
103

104
  return false;
4✔
105
}
106
bool UUID7::generate() {
110✔
107
  fill_random_fn rng = _rng ? _rng : &UUID7::default_fill_random;
110✔
108

109
  if (_version == UUID_VERSION_4) {
110✔
110
    rng(_b, sizeof(_b), _rng_ctx);
10✔
111
    uint8_t sum = 0;
10✔
112
    for (size_t i = 0; i < sizeof(_b); i++)
170✔
113
      sum |= _b[i];
160✔
114
    if (sum == 0)
10✔
115
      return false;
2✔
116

117
    _b[6] = (_b[6] & 0x0F) | 0x40; // Set UUID version to 4 (Random)
8✔
118
    _b[8] = (_b[8] & 0x3F) | 0x80; // Set variant to RFC 4122 (10b)
8✔
119
    return true;
8✔
120
  }
121

122
  now_ms_fn now_func = _now ? _now : &UUID7::default_now_ms;
100✔
123
  bool overflow_state = false;
100✔
124

125
  while (true) {
126
    uint8_t temp_rand[16];
127
    rng(temp_rand, sizeof(temp_rand), _rng_ctx);
118✔
128

129
    uint8_t sum = 0;
118✔
130
    for (size_t i = 0; i < sizeof(temp_rand); i++)
2,006✔
131
      sum |= temp_rand[i];
1,888✔
132
    if (sum == 0)
118✔
133
      return false;
100✔
134

135
    // Retrieve current timestamp before acquiring the lock to avoid deadlocks 
136
    // strictly with multi-threaded/blocking time providers.
137
    uint64_t now_ms = now_func(_now_ctx);
116✔
138
    if (now_ms == 0)
116✔
139
      return false;
2✔
140

141
    bool save_needed = false;
114✔
142
    uint64_t ts_to_save = 0;
114✔
143
    bool success = false;
114✔
144
    bool overflow_occurred = false;
114✔
145

146
    {
147
      // Enforce exclusivity with RAII guard
148
      UUID7Guard lock(_lock_cb, _unlock_cb);
114✔
149

150
      if (_entropy_mixer != 0) {
114✔
151
        for (int i = 0; i < 8; i++) {
18✔
152
          temp_rand[8 + i] ^= (uint8_t)(_entropy_mixer >> (i * 8));
16✔
153
        }
154
      }
155

156
      int cmp = _tsState.compare(now_ms);
114✔
157
      bool major_regression = false;
114✔
158

159
      if (cmp < 0) {
114✔
160
        if (now_ms + _regressionThresholdMs < _tsState.get()) {
10✔
161
          major_regression = true;
4✔
162
        } else {
163
          // Minor regression or race condition: clamp strictly to the last monotonic state
164
          now_ms = _tsState.get();
6✔
165
          cmp = 0; // Evaluate as intra-millisecond progression
6✔
166
        }
167
      }
168

169
      if (major_regression) {
114✔
170
        // Major regression detected: initiate RFC9562 fallback (UUIDv4) to guarantee collision resistance
171
        temp_rand[6] = (temp_rand[6] & 0x0F) | 0x40; // v4 bits
4✔
172
        temp_rand[8] = (temp_rand[8] & 0x3F) | 0x80; // variant bits
4✔
173
        memcpy(_b, temp_rand, 16);
4✔
174
        return true;
4✔
175
      }
176

177
      if (cmp > 0) {
110✔
178
        _tsState.set(now_ms);
72✔
179
        memcpy(_b, temp_rand, 16);
72✔
180
        success = true;
72✔
181
        overflow_state = false;
72✔
182
      } else {
183
        if (overflow_state) {
38✔
184
          overflow_occurred = true;
16✔
185
        } else {
186
          bool initialized = (_b[6] & 0xF0) == 0x70;
22✔
187
          if (!initialized) {
22✔
188
            memcpy(_b, temp_rand, 16);
4✔
189
            success = true;
4✔
190
          } else {
191
            // Increment internal counter for same-millisecond monotonicity.
192
            if (!_incrementRandom()) {
18✔
193
              overflow_occurred = true;
4✔
194
              overflow_state = true;
4✔
195
            } else {
196
              success = true;
14✔
197
            }
198
          }
199
        }
200
      }
201

202
      if (success) {
110✔
203
        _tsState.stampBytes(_b);
90✔
204
      }
205
      if (success && _persistence.save &&
110✔
206
          (now_ms > _persistence.last_saved_ms + _persistence.interval_ms)) {
12✔
207
        save_needed = true;
6✔
208
        _persistence.last_saved_ms = now_ms;
6✔
209
        ts_to_save = now_ms;
6✔
210
      }
211

212
      if (success) {
110✔
213
        _b[6] = (_b[6] & 0x0F) | ((uint8_t)_version << 4);
90✔
214
        _b[8] = (_b[8] & 0x3F) | 0x80;
90✔
215
      }
216
    }
114✔
217

218
    if (success) {
110✔
219
      if (save_needed && _persistence.save) {
90✔
220
        _persistence.save(ts_to_save, _persistence.ctx);
6✔
221
      }
222
      return true;
90✔
223
    }
224

225
    if (overflow_occurred) {
20✔
226
      if (_overflowPolicy == UUID_OVERFLOW_FAIL_FAST) {
20✔
227
        return false;
2✔
228
      } else {
229
#if defined(ARDUINO)
230
        delay(1); // RTOS context yielding to prevent thread starvation during constraint resolution
231
#else
232
        yield();
18✔
233
#endif
234
        continue;
18✔
235
      }
236
    }
UNCOV
237
    return false;
×
238
  }
18✔
239
}
240

241
bool UUID7::toString(char *out, size_t buflen, bool uppercase,
30✔
242
                     bool dashes) const noexcept {
243
  uint8_t local_b[16];
244
  {
245
    UUID7Guard lock(_lock_cb, _unlock_cb);
30✔
246
    memcpy(local_b, _b, 16);
30✔
247
  }
30✔
248
  return UUID7Codec::encode(local_b, out, buflen, uppercase, dashes);
30✔
249
}
250

251
bool UUID7::parseFromString(const char *str, uint8_t out[16]) noexcept {
26✔
252
  return UUID7Codec::decode(str, out);
26✔
253
}
254

255
uint64_t UUID7::getTimestamp() const noexcept {
4✔
256
  if (!isV7())
4✔
257
    return 0;
2✔
258
  uint64_t ts = 0;
2✔
259
  uint8_t snap[6];
260
  {
261
    UUID7Guard lock(_lock_cb, _unlock_cb);
2✔
262
    memcpy(snap, _b, 6);
2✔
263
  }
2✔
264
  for (int i = 0; i < 6; i++) {
14✔
265
    ts = (ts << 8) | snap[i];
12✔
266
  }
267
  return ts;
2✔
268
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc