Atomic integers that panic on overflow

I wanted to check my implementation of an atomic integer that panics on overflow, so that I don't get dangerous logic errors where things that should have unique IDs do not. The following is my implementation:

static ID_FACTORY: AtomicU64 = std::sync::atomic::AtomicU64::new(0);
fn next_id() -> ConnId {
    // We fetch the value, check it isn't overflow, then swap it with another value, repeating the
    // process if it has changed in the mean time.
    loop {
        let current_val = ID_FACTORY.load(Ordering::Relaxed);
        if current_val == u64::max_value() {
            panic!("Connection id overflow");
        }
        if ID_FACTORY.compare_and_swap(current_val, current_val + 1, Ordering::Relaxed)
            == current_val
        {
            // Nobody changed the value since our fetch.
            break current_val + 1;
        }
    }
}

Is this the best way to implement such a type? Also, should something like this be in std?

ID_FACTORY should be a static global, not const.

2 Likes

Of note: if you're sequentially allocating 2^64 values at a rate of 1GHz, it'll take 584 years to get through all the values.

Not to tell you to not handle the edge case, but just to put it into perspective.

4 Likes

You could follow what the standard library does with Arc's MAX_REFCOUNT. That's a usize that cuts off at isize::MAX, so there's room for slop if multiple threads see the "overflow".

3 Likes

To be clear: isize::MAX (±1) times to observe the overflow! If you really need to be guaranteed overflow still never happen, just set it back to isize::MAX + 1 when observing overflow.