@peerbit/shared-log 10.3.9 → 10.3.10-49afc60

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/ranges.ts CHANGED
@@ -1354,21 +1354,45 @@ export const appromixateCoverage = async <R extends "u32" | "u64">(properties: {
1354
1354
  }
1355
1355
  return hits / properties.samples;
1356
1356
  };
1357
-
1358
1357
  export const calculateCoverage = async <R extends "u32" | "u64">(properties: {
1359
1358
  peers: Index<ReplicationRangeIndexable<R>>;
1360
1359
  numbers: Numbers<R>;
1360
+ /** Optional: start of the content range (inclusive) */
1361
+ start?: NumberFromType<R>;
1362
+ /** Optional: end of the content range (exclusive) */
1363
+ end?: NumberFromType<R>;
1361
1364
  }): Promise<number> => {
1362
- const contentStart = properties.numbers.zero;
1363
- const contentEnd = properties.numbers.maxValue;
1365
+ // Use the provided content range if given; otherwise use the default full range.
1366
+ const contentStart = properties.start ?? properties.numbers.zero;
1367
+ const contentEnd = properties.end ?? properties.numbers.maxValue;
1368
+
1369
+ // Optional: Validate that the range is nonempty.
1370
+ if (contentStart > contentEnd) {
1371
+ // calculate coveragare for two ranges and take the min (wrapped)
1372
+ const coverage1 = await calculateCoverage({
1373
+ peers: properties.peers,
1374
+ numbers: properties.numbers,
1375
+ start: contentStart,
1376
+ end: properties.numbers.maxValue,
1377
+ });
1378
+ const coverage2 = await calculateCoverage({
1379
+ peers: properties.peers,
1380
+ numbers: properties.numbers,
1381
+ start: properties.numbers.zero,
1382
+ end: contentEnd,
1383
+ });
1384
+
1385
+ return Math.min(coverage1, coverage2);
1386
+ }
1387
+
1364
1388
  const endpoints: { point: NumberFromType<R>; delta: -1 | 1 }[] = [];
1365
- let lastPoint = contentStart;
1366
1389
 
1367
1390
  // For each range, record its start and end as events.
1368
1391
  for (const r of await properties.peers.iterate().all()) {
1369
1392
  endpoints.push({ point: r.value.start1, delta: +1 });
1370
1393
  endpoints.push({ point: r.value.end1, delta: -1 });
1371
1394
 
1395
+ // Process the optional second range if it differs.
1372
1396
  if (r.value.start1 !== r.value.start2) {
1373
1397
  endpoints.push({ point: r.value.start2, delta: +1 });
1374
1398
  endpoints.push({ point: r.value.end2, delta: -1 });
@@ -1379,23 +1403,38 @@ export const calculateCoverage = async <R extends "u32" | "u64">(properties: {
1379
1403
  // When points are equal, process a start (delta +1) before an end (delta -1)
1380
1404
  endpoints.sort((a, b) => {
1381
1405
  if (a.point === b.point) return b.delta - a.delta;
1382
- return Number(a.point - b.point);
1406
+ return Number(a.point) - Number(b.point);
1383
1407
  });
1384
1408
 
1409
+ // If there are no endpoints at all, nothing covers the content range.
1410
+ if (endpoints.length === 0) {
1411
+ return 0;
1412
+ }
1413
+
1414
+ // Process events occurring before or at contentStart so we have the correct
1415
+ // initial coverage at contentStart.
1385
1416
  let currentCoverage = 0;
1386
- let minCoverage = Infinity;
1417
+ let idx = 0;
1418
+ while (idx < endpoints.length && endpoints[idx].point <= contentStart) {
1419
+ currentCoverage += endpoints[idx].delta;
1420
+ idx++;
1421
+ }
1387
1422
 
1388
- // If the very start of the content space isn’t covered, return 0.
1389
- if (endpoints.length === 0 || endpoints[0].point > contentStart) {
1423
+ // If no range covers the very beginning of the content space, return 0.
1424
+ if (currentCoverage <= 0) {
1390
1425
  return 0;
1391
1426
  }
1392
1427
 
1393
- // Process each endpoint, updating the current coverage.
1394
- for (const e of endpoints) {
1395
- // If there is an interval from lastPoint to this endpoint,
1396
- // then the coverage in that entire segment was currentCoverage.
1428
+ let minCoverage = currentCoverage;
1429
+ let lastPoint = contentStart;
1430
+
1431
+ // Process remaining endpoints.
1432
+ for (; idx < endpoints.length; idx++) {
1433
+ const e = endpoints[idx];
1434
+
1435
+ // Only process if the event point advances our sweep.
1397
1436
  if (e.point > lastPoint) {
1398
- // Restrict to our content space.
1437
+ // Restrict the segment to our content space.
1399
1438
  const segStart = properties.numbers.max(lastPoint, contentStart);
1400
1439
  const segEnd = properties.numbers.min(e.point, contentEnd);
1401
1440
  if (segStart < segEnd) {
@@ -1403,15 +1442,21 @@ export const calculateCoverage = async <R extends "u32" | "u64">(properties: {
1403
1442
  }
1404
1443
  lastPoint = e.point;
1405
1444
  }
1445
+
1446
+ // Once we've passed the content end, we can stop processing.
1447
+ if (lastPoint >= contentEnd) {
1448
+ break;
1449
+ }
1450
+
1406
1451
  currentCoverage += e.delta;
1407
1452
  }
1408
1453
 
1409
- // Check if the last endpoint left a tail inside the content space.
1454
+ // Process any tail at the end of the content range.
1410
1455
  if (lastPoint < contentEnd) {
1411
1456
  minCoverage = Math.min(minCoverage, currentCoverage);
1412
1457
  }
1413
1458
 
1414
- // If any segment has zero coverage or nothing was covered, return 0.
1459
+ // If any segment has zero (or negative) coverage, or nothing was covered, return 0.
1415
1460
  return minCoverage === Infinity || minCoverage <= 0 ? 0 : minCoverage;
1416
1461
  };
1417
1462