// Copyright 2025 International Digital Economy Academy
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
///|
pub struct SparseSecondaryMap[K, V] {
slots : Map[Int, (Int, V)]
_key : K?
}
///|
pub fn[K, V] SparseSecondaryMap::new(
capacity? : Int = 0,
) -> SparseSecondaryMap[K, V] {
{ slots: Map([], capacity~), _key: None }
}
///|
pub fn[K, V] SparseSecondaryMap::default() -> SparseSecondaryMap[K, V] {
SparseSecondaryMap::new()
}
///|
pub fn[K, V] SparseSecondaryMap::with_capacity(
capacity : Int,
) -> SparseSecondaryMap[K, V] {
SparseSecondaryMap::new(capacity~)
}
///|
pub fn[K, V] SparseSecondaryMap::length(self : SparseSecondaryMap[K, V]) -> Int {
self.slots.length()
}
///|
pub fn[K, V] SparseSecondaryMap::len(self : SparseSecondaryMap[K, V]) -> Int {
self.length()
}
///|
pub fn[K, V] SparseSecondaryMap::is_empty(
self : SparseSecondaryMap[K, V],
) -> Bool {
self.slots.is_empty()
}
///|
pub fn[K, V] SparseSecondaryMap::capacity(
self : SparseSecondaryMap[K, V],
) -> Int {
self.slots.capacity()
}
///|
pub fn[K : Key, V] SparseSecondaryMap::contains_key(
self : SparseSecondaryMap[K, V],
key : K,
) -> Bool {
if key.is_null() {
return false
}
let index = key.index()
if index < 0 {
return false
}
match self.slots.get(index) {
Some((version, _)) => version == key.version()
None => false
}
}
///|
pub fn[K : Key, V] SparseSecondaryMap::contains(
self : SparseSecondaryMap[K, V],
key : K,
) -> Bool {
self.contains_key(key)
}
///|
pub fn[K : Key, V] SparseSecondaryMap::insert(
self : SparseSecondaryMap[K, V],
key : K,
value : V,
) -> V? {
if key.is_null() {
return None
}
let index = key.index()
if index < 0 {
return None
}
match self.slots.get(index) {
Some((version, current)) if version == key.version() => {
self.slots[index] = (version, value)
Some(current)
}
Some((version, _)) if version_is_older(key.version(), version) => None
_ => {
self.slots[index] = (key.version(), value)
None
}
}
}
///|
#alias("_[_]=_")
pub fn[K : Key, V] SparseSecondaryMap::set(
self : SparseSecondaryMap[K, V],
key : K,
value : V,
) -> Unit {
ignore(self.insert(key, value))
}
///|
pub fn[K : Key, V] SparseSecondaryMap::remove(
self : SparseSecondaryMap[K, V],
key : K,
) -> V? {
if key.is_null() {
return None
}
let index = key.index()
if index < 0 {
return None
}
match self.slots.get(index) {
Some((version, value)) if version == key.version() => {
self.slots.remove(index)
Some(value)
}
_ => None
}
}
///|
pub fn[K : Key, V] SparseSecondaryMap::get(
self : SparseSecondaryMap[K, V],
key : K,
) -> V? {
if key.is_null() {
return None
}
let index = key.index()
if index < 0 {
return None
}
match self.slots.get(index) {
Some((version, value)) if version == key.version() => Some(value)
_ => None
}
}
///|
#alias("_[_]")
pub fn[K : Key, V] SparseSecondaryMap::at(
self : SparseSecondaryMap[K, V],
key : K,
) -> V {
match self.get(key) {
Some(value) => value
None => abort("invalid sparse secondary key")
}
}
///|
pub fn[K : Key, V] SparseSecondaryMap::update(
self : SparseSecondaryMap[K, V],
key : K,
updater : (V?) -> V?,
) -> Unit {
if key.is_null() {
ignore(updater(None))
return
}
let index = key.index()
if index < 0 {
ignore(updater(None))
return
}
match self.slots.get(index) {
Some((version, current)) if version == key.version() =>
match updater(Some(current)) {
Some(value) => self.slots[index] = (version, value)
None => ignore(self.slots.remove(index))
}
Some((version, _)) if version_is_older(key.version(), version) =>
ignore(updater(None))
_ =>
match updater(None) {
Some(value) => self.slots[index] = (key.version(), value)
None => ()
}
}
}
///|
pub fn[K : Key, V] SparseSecondaryMap::get_or_default(
self : SparseSecondaryMap[K, V],
key : K,
default : V,
) -> V? {
if key.is_null() {
return None
}
let index = key.index()
if index < 0 {
return None
}
match self.slots.get(index) {
Some((version, value)) if version == key.version() => Some(value)
Some((version, _)) if version_is_older(key.version(), version) => None
_ => {
self.slots[index] = (key.version(), default)
Some(default)
}
}
}
///|
pub fn[K : Key, V] SparseSecondaryMap::get_or_init(
self : SparseSecondaryMap[K, V],
key : K,
init : () -> V,
) -> V? {
if key.is_null() {
ignore(init())
return None
}
let index = key.index()
if index < 0 {
ignore(init())
return None
}
match self.slots.get(index) {
Some((version, value)) if version == key.version() => Some(value)
Some((version, _)) if version_is_older(key.version(), version) => {
ignore(init())
None
}
_ => {
let value = init()
self.slots[index] = (key.version(), value)
Some(value)
}
}
}
///|
pub fn[K : Key, V] SparseSecondaryMap::retain(
self : SparseSecondaryMap[K, V],
predicate : (K, V) -> Bool,
) -> Unit {
self.slots.retain(fn(index, pair) {
predicate(K::from_raw_parts(index, pair.0), pair.1)
})
}
///|
pub fn[K, V] SparseSecondaryMap::clear(self : SparseSecondaryMap[K, V]) -> Unit {
self.slots.clear()
}
///|
pub fn[K : Key, V] SparseSecondaryMap::drain(
self : SparseSecondaryMap[K, V],
) -> Array[(K, V)] {
let items : Array[(K, V)] = Array::new(capacity=self.length())
self.slots.each(fn(index, pair) {
items.push((K::from_raw_parts(index, pair.0), pair.1))
})
self.clear()
items
}
///|
pub fn[K : Key, V] SparseSecondaryMap::to_array(
self : SparseSecondaryMap[K, V],
) -> Array[(K, V)] {
let items : Array[(K, V)] = Array::new(capacity=self.length())
self.slots.each(fn(index, pair) {
items.push((K::from_raw_parts(index, pair.0), pair.1))
})
items
}
///|
pub fn[K : Key, V] SparseSecondaryMap::iter(
self : SparseSecondaryMap[K, V],
) -> Array[(K, V)] {
self.to_array()
}
///|
#alias(iterator2, deprecated)
pub fn[K : Key, V] SparseSecondaryMap::iter2(
self : SparseSecondaryMap[K, V],
) -> Iter2[K, V] {
let inner = self.slots.iter2()
Iter2::new(fn() {
match inner.next() {
Some((index, pair)) => Some((K::from_raw_parts(index, pair.0), pair.1))
None => None
}
})
}
///|
pub fn[K : Key, V] SparseSecondaryMap::each(
self : SparseSecondaryMap[K, V],
visit : (K, V) -> Unit,
) -> Unit {
self.slots.each(fn(index, pair) {
visit(K::from_raw_parts(index, pair.0), pair.1)
})
}
///|
pub fn[K : Key, V] SparseSecondaryMap::keys(
self : SparseSecondaryMap[K, V],
) -> Array[K] {
let keys : Array[K] = Array::new(capacity=self.length())
self.slots.each(fn(index, pair) {
keys.push(K::from_raw_parts(index, pair.0))
})
keys
}
///|
pub fn[K, V] SparseSecondaryMap::values(
self : SparseSecondaryMap[K, V],
) -> Array[V] {
let values : Array[V] = Array::new(capacity=self.length())
self.slots.each(fn(_, pair) { values.push(pair.1) })
values
}