Parcel Label Numbers

MediumdesignAlso known as Snowflake ID Generator

A courier prints a barcode number on every parcel at up to 16 depots. The numbers must never repeat, the depots cannot call a central server for each label (the warehouse network drops out), and sorting labels by number should roughly sort them by time. So each depot builds the number itself from three parts: the time in milliseconds, its own machine number, and a counter for labels printed in the same millisecond.

This is the Snowflake-style generator from Unique IDs. Real layouts use 64 bits; this one is squeezed into 53 bits so every ID is an exact JavaScript number and survives a trip through JSON in a browser.

Your task

An ID is t × 4096 + machine × 256 + seq, which is the bit layout:

  • 41 bits: t, milliseconds since the courier's chosen epoch (0 to 241 − 1, about 69 years).
  • 4 bits: machine, the depot number, 0 to 15.
  • 8 bits: seq, 0 to 255, counting IDs made in the same millisecond.

Write a class LabelIds:

  • constructor(machine).
  • next(t): return a new ID for time t. If t is later than the time of the last ID issued (or nothing was issued yet), use seq = 0. If t equals it, use the last seq plus 1. Return -1 and change nothing in two cases: the seq would reach 256 (this millisecond is used up), or t is earlier than the last ID's time (the clock moved backwards).
  • parts(id): split any valid ID into [t, machine, seq].

JavaScript's bit operators (<<, >>, &) work on 32 bits only, so they cannot handle a 53-bit ID. Use multiplication, division and remainder.

class LabelIds

Examples

Example 1
Input
new LabelIds(5)
.next(1000)
.next(1000)
.next(1001)
.parts(4097281)
Output
[null, 4097280, 4097281, 4101376, [1000, 5, 1]]
Why

1000 × 4096 = 4,096,000 and 5 × 256 = 1,280, so the first ID at t = 1000 is 4,097,280 (seq 0). A second label in the same millisecond gets seq 1: 4,097,281. At t = 1001 the seq starts again at 0: 4,100,096 + 1,280 = 4,101,376. Splitting 4,097,281 back: 4,097,281 ÷ 4096 rounds down to 1000, the remainder is 1,281, and 1,281 ÷ 256 = 5 remainder 1.

Example 2
Input
new LabelIds(0)
.next(2000)
.next(1999)
.next(2000)
.next(2001)
Output
[null, 8192000, -1, 8192001, 8196096]
Why

After an ID at t = 2000, the clock reports 1999. Issuing an ID at 1999 could repeat one already given out in that millisecond, so the generator refuses with -1 and keeps its state. Back at 2000 it continues the sequence with seq 1, and at 2001 it starts again from 0.

Constraints

  • 0 ≤ machine ≤ 15
  • 0 ≤ t ≤ 2,199,023,255,551 (2⁴¹ − 1)
  • parts is only called with IDs that this layout can produce, so 0 ≤ id ≤ 9,007,199,254,740,991
  • At most 1,000 calls per test
Start with brute force

The simplest unique number is a shared counter in one database: every depot asks it for the next value. That needs a network call per label and stops every depot when the counter is unreachable, which is what the courier cannot accept.

Random 53-bit numbers need no coordination, but they do not sort by time, and with many labels two will eventually collide. Building the ID from time, machine and sequence gives uniqueness and rough time order with no network call at all.

Hints

0 of 4 shown

Walkthrough and solution

Unlocks when you pass every test. Stuck for a while? Looking is fine too, as long as you then close it and write the code yourself.

Ctrl+Enter runs

Run your code to see results here. Run checks the examples. Submit checks every test, including hidden edge cases.

Write code