flix

0.78.0

UniqueInts.flix

/*
 * Copyright 2025 Casper Dalgaard Nielsen
 *                Adam Yasser Tallouzi
 *
 * Use of this source code is governed by the Apache 2.0 license
 * that can be found in the LICENSE.md file.
 */

/// Type for assigning unique integer identifiers to elements, and its functions.
pub mod Fixpoint3.UniqueInts {
    use Fixpoint3.Counter

    ///
    /// The purpose of `UniqueInts` is to assign unique numbers/identifiers to elements.
    ///
    /// Example of use: When generating joins automatically we have data of type
    /// `(RelSym, Search)`. These needs to be placed somewhere in memory. For
    /// a pair `(rel, search)` calling `createIndex((rel, search))` will return its
    /// index if it has been seen before and otherwise return the new index
    /// which henceforth will be returned for subsequent queries of `(rel, search)`.
    ///
    /// `ReverseUniqueInts` allows using an index, `i`, assigned by `UniqueInts`, and get
    /// the value, which `UniqueInts` assigned index `i`.
    ///
    pub struct UniqueInts[k: Type, r: Region] {
        map:     MutMap[k, Int32, r],
        counter: Counter[r]
    }

    ///
    /// Returns an empty mapping from `k` to identifiers.
    ///
    pub def empty(rc: Region[r]): UniqueInts[k, r] \ r =
        new UniqueInts @ rc {
            map = MutMap.empty(rc),
            counter = Counter.fresh(rc)
        }

    ///
    /// Returns the index of `val` generated by `state`.
    ///
    /// If an index does not exist for `val` it is created.
    /// Otherwise the existing index for `val` is returned.
    ///
    pub def createIndex(val: k, state: UniqueInts[k, r]): Int32 \ r with Order[k] =
        let map = state->map;
        let counter = state->counter;
        match MutMap.get(val, map) {
            case None =>
                let id = Counter.getAndIncrement(counter);
                MutMap.put(val, id, map);
                id
            case Some(v) => v
        }

    ///
    /// Returns the current mapping of `state` as a map.
    ///
    pub def toMap(state: UniqueInts[k, r]): Map[k, Int32] \ r = {
        MutMap.toMap(state->map)
    }

    ///
    /// Returns the maximal assigned identifier of `state`.
    ///
    pub def get(state: UniqueInts[k, r]): Int32 \ r = {
        Counter.get(state->counter)
    }

    ///
    /// Returns an `ReverseUniqueInts` of `state` allowing mapping identifiers
    /// back to the values they represent.
    ///
    pub def reverse(state: UniqueInts[k, r]): Map[Int32, k] \ r with Order[k] =
        let map = state->map;
        let reverseMap = MutMap.foldLeftWithKey(acc -> key -> val -> Map.insert(val, key, acc), Map#{}, map);
        reverseMap
}