std1.0.0-beta-7 SafeC docs

Source dsp/timer_wheel.sc

View in the repository

#pragma once
#include <std/dsp/timer_wheel.h>

// ── TimerWheel::init ──────────────────────────────────────────────────────────
// Zero-initialise the wheel.  Must be called before any other operation.
namespace std {

inline void TimerWheel::init() {
    self.current_tick = 0;
    int i = 0;
    while (i < WHEEL_TIMERS) {
        unsafe {
            self.timers[i].used     = 0;
            self.timers[i].periodic = 0;
            self.timers[i].period   = 0;
            self.timers[i].expires  = 0;
            self.timers[i].callback = null;
            self.timers[i].ctx      = null;
        }
        i = i + 1;
    }
}

// ── Internal helper: allocate a free timer slot ───────────────────────────────
// Returns 0-based index or -1 if full.
static int alloc_slot(&TimerWheel tw) {
    int i = 0;
    while (i < WHEEL_TIMERS) {
        unsafe {
            if (tw.timers[i].used == 0) {
                return i;
            }
        }
        i = i + 1;
    }
    return -1;
}

// ── TimerWheel::add ───────────────────────────────────────────────────────────
inline int TimerWheel::add_raw_(unsigned long tick, fn void(?&Erased) callback, ?&Erased ctx) {
    int idx = alloc_slot(self);
    if (idx < 0) {
        return 0;  // wheel full
    }
    unsafe {
        self.timers[idx].expires  = tick;
        self.timers[idx].callback = callback;
        self.timers[idx].ctx      = ctx;
        self.timers[idx].used     = 1;
        self.timers[idx].periodic = 0;
        self.timers[idx].period   = 0;
    }
    // Return 1-based ID.
    return idx + 1;
}

// ── TimerWheel::add_periodic ──────────────────────────────────────────────────
inline int TimerWheel::add_periodic_raw_(unsigned long period, fn void(?&Erased) callback, ?&Erased ctx) {
    if (period == 0) {
        return 0;
    }
    int idx = alloc_slot(self);
    if (idx < 0) {
        return 0;
    }
    unsafe {
        self.timers[idx].expires  = self.current_tick + period;
        self.timers[idx].callback = callback;
        self.timers[idx].ctx      = ctx;
        self.timers[idx].used     = 1;
        self.timers[idx].periodic = 1;
        self.timers[idx].period   = period;
    }
    return idx + 1;
}

// ── TimerWheel::cancel ────────────────────────────────────────────────────────
inline void TimerWheel::cancel(int id) {
    if (id <= 0 || id > WHEEL_TIMERS) {
        return;
    }
    int idx = id - 1;
    unsafe {
        self.timers[idx].used = 0;
    }
}

// ── TimerWheel::tick ──────────────────────────────────────────────────────────
// Advance by one tick.  Fire all timers whose expires == new current_tick.
// Periodic timers are rescheduled by incrementing expires by their period.
int TimerWheel::tick() {
    self.current_tick = self.current_tick + (unsigned long)1;
    unsigned long now = self.current_tick;

    int fired = 0;
    int i = 0;
    while (i < WHEEL_TIMERS) {
        int do_fire = 0;
        unsafe {
            if (self.timers[i].used == 1 && self.timers[i].expires == now) {
                do_fire = 1;
            }
        }
        if (do_fire == 1) {
            // Invoke the callback.
            ?fn void(?&Erased) cb = self.timers[i].callback;
            ?&Erased context = self.timers[i].ctx;
            match (cb) {
                case some(func): func(context);
                case null: { }
            }
            fired = fired + 1;

            // Reschedule periodic timers; free one-shot timers.
            int is_periodic;
            unsigned long period;
            unsafe {
                is_periodic = self.timers[i].periodic;
                period      = self.timers[i].period;
            }
            if (is_periodic == 1) {
                unsafe {
                    self.timers[i].expires = now + period;
                }
            } else {
                unsafe {
                    self.timers[i].used = 0;
                }
            }
        }
        i = i + 1;
    }
    return fired;
}

// ── TimerWheel::now ───────────────────────────────────────────────────────────
inline unsigned long TimerWheel::now() const {
    return self.current_tick;
}

} // namespace std