impotent/stc/smap.h
2025-08-31 16:22:38 +03:00

607 lines
19 KiB
C

/* MIT License
*
* Copyright (c) 2025 Tyge Løvset
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
// Sorted/Ordered set and map - implemented as an AA-tree.
/*
#include <stdio.h>
#include <stc/cstr.h>
#define T SMap, cstr, double, (c_keypro) // Sorted map<cstr, double>
#include <stc/sortedmap.h>
int main(void) {
SMap m = {0};
SMap_emplace(&m, "Testing one", 1.234);
SMap_emplace(&m, "Testing two", 12.34);
SMap_emplace(&m, "Testing three", 123.4);
SMap_value *v = SMap_get(&m, "Testing five"); // NULL
double num = *SMap_at(&m, "Testing one");
SMap_emplace_or_assign(&m, "Testing three", 1000.0); // update
SMap_erase(&m, "Testing two");
for (c_each(i, SMap, m))
printf("map %s: %g\n", cstr_str(&i.ref->first), i.ref->second);
SMap_drop(&m);
}
*/
#include "priv/linkage.h"
#include "types.h"
#ifndef STC_SMAP_H_INCLUDED
#define STC_SMAP_H_INCLUDED
#include "common.h"
#include <stdlib.h>
#endif // STC_SMAP_H_INCLUDED
#ifndef _i_prefix
#define _i_prefix smap_
#endif
#ifndef _i_is_set
#define _i_is_map
#define _i_MAP_ONLY c_true
#define _i_SET_ONLY c_false
#define _i_keyref(vp) (&(vp)->first)
#else
#define _i_MAP_ONLY c_false
#define _i_SET_ONLY c_true
#define _i_keyref(vp) (vp)
#endif
#define _i_sorted
#include "priv/template.h"
#ifndef i_declared
_c_DEFTYPES(_declare_aatree, Self, i_key, i_val, _i_MAP_ONLY, _i_SET_ONLY, _i_aux_def);
#endif
_i_MAP_ONLY( struct _m_value {
_m_key first;
_m_mapped second;
}; )
struct _m_node {
int32_t link[2];
int8_t level;
_m_value value;
};
typedef i_keyraw _m_keyraw;
typedef i_valraw _m_rmapped;
typedef _i_SET_ONLY( _m_keyraw )
_i_MAP_ONLY( struct { _m_keyraw first; _m_rmapped second; } )
_m_raw;
#if !defined i_no_emplace
STC_API _m_result _c_MEMB(_emplace)(Self* self, _m_keyraw rkey _i_MAP_ONLY(, _m_rmapped rmapped));
#endif // !i_no_emplace
#if !defined i_no_clone
STC_API Self _c_MEMB(_clone)(Self tree);
#endif // !i_no_clone
STC_API void _c_MEMB(_drop)(const Self* cself);
STC_API bool _c_MEMB(_reserve)(Self* self, isize cap);
STC_API _m_value* _c_MEMB(_find_it)(const Self* self, _m_keyraw rkey, _m_iter* out);
STC_API _m_iter _c_MEMB(_lower_bound)(const Self* self, _m_keyraw rkey);
STC_API _m_value* _c_MEMB(_front)(const Self* self);
STC_API _m_value* _c_MEMB(_back)(const Self* self);
STC_API int _c_MEMB(_erase)(Self* self, _m_keyraw rkey);
STC_API _m_iter _c_MEMB(_erase_at)(Self* self, _m_iter it);
STC_API _m_iter _c_MEMB(_erase_range)(Self* self, _m_iter it1, _m_iter it2);
STC_API _m_iter _c_MEMB(_begin)(const Self* self);
STC_API void _c_MEMB(_next)(_m_iter* it);
STC_INLINE bool _c_MEMB(_is_empty)(const Self* self) { return self->size == 0; }
STC_INLINE isize _c_MEMB(_size)(const Self* self) { return self->size; }
STC_INLINE isize _c_MEMB(_capacity)(const Self* self) { return self->capacity; }
STC_INLINE _m_iter _c_MEMB(_find)(const Self* self, _m_keyraw rkey)
{ _m_iter it; _c_MEMB(_find_it)(self, rkey, &it); return it; }
STC_INLINE bool _c_MEMB(_contains)(const Self* self, _m_keyraw rkey)
{ _m_iter it; return _c_MEMB(_find_it)(self, rkey, &it) != NULL; }
STC_INLINE const _m_value* _c_MEMB(_get)(const Self* self, _m_keyraw rkey)
{ _m_iter it; return _c_MEMB(_find_it)(self, rkey, &it); }
STC_INLINE _m_value* _c_MEMB(_get_mut)(Self* self, _m_keyraw rkey)
{ _m_iter it; return _c_MEMB(_find_it)(self, rkey, &it); }
STC_INLINE _m_raw _c_MEMB(_value_toraw)(const _m_value* val) {
return _i_SET_ONLY( i_keytoraw(val) )
_i_MAP_ONLY( c_literal(_m_raw){i_keytoraw((&val->first)),
i_valtoraw((&val->second))} );
}
STC_INLINE void _c_MEMB(_value_drop)(const Self* self, _m_value* val) {
(void)self;
i_keydrop(_i_keyref(val));
_i_MAP_ONLY( i_valdrop((&val->second)); )
}
STC_INLINE Self _c_MEMB(_move)(Self *self) {
Self m = *self;
self->capacity = self->size = self->root = self->disp = self->head = 0;
self->nodes = NULL;
return m;
}
STC_INLINE void _c_MEMB(_clear)(Self* self) {
_c_MEMB(_drop)(self);
(void)_c_MEMB(_move)(self);
}
STC_INLINE void _c_MEMB(_take)(Self *self, Self unowned) {
_c_MEMB(_drop)(self);
*self = unowned;
}
#if !defined i_no_clone
STC_INLINE _m_value _c_MEMB(_value_clone)(const Self* self, _m_value _val) {
(void)self;
*_i_keyref(&_val) = i_keyclone((*_i_keyref(&_val)));
_i_MAP_ONLY( _val.second = i_valclone(_val.second); )
return _val;
}
STC_INLINE void _c_MEMB(_copy)(Self *self, const Self* other) {
if (self == other)
return;
_c_MEMB(_drop)(self);
*self = _c_MEMB(_clone)(*other);
}
STC_INLINE void _c_MEMB(_shrink_to_fit)(Self *self) {
Self tmp = _c_MEMB(_clone)(*self);
_c_MEMB(_drop)(self); *self = tmp;
}
#endif // !i_no_clone
STC_API _m_result _c_MEMB(_insert_entry_)(Self* self, _m_keyraw rkey);
#ifdef _i_is_map
STC_API _m_result _c_MEMB(_insert_or_assign)(Self* self, _m_key key, _m_mapped mapped);
#ifndef i_no_emplace
STC_API _m_result _c_MEMB(_emplace_or_assign)(Self* self, _m_keyraw rkey, _m_rmapped rmapped);
#endif
STC_INLINE const _m_mapped* _c_MEMB(_at)(const Self* self, _m_keyraw rkey)
{ _m_iter it; return &_c_MEMB(_find_it)(self, rkey, &it)->second; }
STC_INLINE _m_mapped* _c_MEMB(_at_mut)(Self* self, _m_keyraw rkey)
{ _m_iter it; return &_c_MEMB(_find_it)(self, rkey, &it)->second; }
#endif // _i_is_map
STC_INLINE _m_iter _c_MEMB(_end)(const Self* self) {
_m_iter it; (void)self;
it.ref = NULL, it._top = 0, it._tn = 0;
return it;
}
STC_INLINE _m_iter _c_MEMB(_advance)(_m_iter it, size_t n) {
while (n-- && it.ref)
_c_MEMB(_next)(&it);
return it;
}
#if defined _i_has_eq
STC_INLINE bool
_c_MEMB(_eq)(const Self* self, const Self* other) {
if (_c_MEMB(_size)(self) != _c_MEMB(_size)(other)) return false;
_m_iter i = _c_MEMB(_begin)(self), j = _c_MEMB(_begin)(other);
for (; i.ref; _c_MEMB(_next)(&i), _c_MEMB(_next)(&j)) {
const _m_keyraw _rx = i_keytoraw(_i_keyref(i.ref)), _ry = i_keytoraw(_i_keyref(j.ref));
if (!(i_eq((&_rx), (&_ry)))) return false;
}
return true;
}
#endif
STC_INLINE _m_result
_c_MEMB(_insert)(Self* self, _m_key _key _i_MAP_ONLY(, _m_mapped _mapped)) {
_m_result _res = _c_MEMB(_insert_entry_)(self, i_keytoraw((&_key)));
if (_res.inserted)
{ *_i_keyref(_res.ref) = _key; _i_MAP_ONLY( _res.ref->second = _mapped; )}
else
{ i_keydrop((&_key)); _i_MAP_ONLY( i_valdrop((&_mapped)); )}
return _res;
}
STC_INLINE _m_value* _c_MEMB(_push)(Self* self, _m_value _val) {
_m_result _res = _c_MEMB(_insert_entry_)(self, i_keytoraw(_i_keyref(&_val)));
if (_res.inserted)
*_res.ref = _val;
else
_c_MEMB(_value_drop)(self, &_val);
return _res.ref;
}
#ifdef _i_is_map
STC_INLINE _m_result _c_MEMB(_put)(Self* self, _m_keyraw rkey, _m_rmapped rmapped) {
#ifdef i_no_emplace
return _c_MEMB(_insert_or_assign)(self, rkey, rmapped);
#else
return _c_MEMB(_emplace_or_assign)(self, rkey, rmapped);
#endif
}
#endif
STC_INLINE void _c_MEMB(_put_n)(Self* self, const _m_raw* raw, isize n) {
while (n--)
#if defined _i_is_set && defined i_no_emplace
_c_MEMB(_insert)(self, *raw++);
#elif defined _i_is_set
_c_MEMB(_emplace)(self, *raw++);
#else
_c_MEMB(_put)(self, raw->first, raw->second), ++raw;
#endif
}
#ifndef _i_aux_alloc
STC_INLINE Self _c_MEMB(_init)(void)
{ Self cx = {0}; return cx; }
STC_INLINE Self _c_MEMB(_from_n)(const _m_raw* raw, isize n)
{ Self cx = {0}; _c_MEMB(_put_n)(&cx, raw, n); return cx; }
STC_INLINE Self _c_MEMB(_with_capacity)(const isize cap)
{ Self cx = {0}; _c_MEMB(_reserve)(&cx, cap); return cx; }
#endif
/* -------------------------- IMPLEMENTATION ------------------------- */
#if defined i_implement
STC_DEF void
_c_MEMB(_next)(_m_iter *it) {
int32_t tn = it->_tn;
if (it->_top || tn) {
while (tn) {
it->_st[it->_top++] = tn;
tn = it->_d[tn].link[0];
}
tn = it->_st[--it->_top];
it->_tn = it->_d[tn].link[1];
it->ref = &it->_d[tn].value;
} else
it->ref = NULL;
}
STC_DEF _m_iter
_c_MEMB(_begin)(const Self* self) {
_m_iter it;
it.ref = NULL;
it._d = self->nodes, it._top = 0;
it._tn = self->root;
if (it._tn)
_c_MEMB(_next)(&it);
return it;
}
STC_DEF bool
_c_MEMB(_reserve)(Self* self, const isize cap) {
if (cap <= self->capacity)
return false;
_m_node* nodes = (_m_node*)_i_realloc_n(self->nodes, self->capacity + 1, cap + 1);
if (nodes == NULL)
return false;
nodes[0] = c_literal(_m_node){0};
self->nodes = nodes;
self->capacity = (int32_t)cap;
return true;
}
STC_DEF _m_value*
_c_MEMB(_front)(const Self* self) {
_m_node *d = self->nodes;
int32_t tn = self->root;
while (d[tn].link[0])
tn = d[tn].link[0];
return &d[tn].value;
}
STC_DEF _m_value*
_c_MEMB(_back)(const Self* self) {
_m_node *d = self->nodes;
int32_t tn = self->root;
while (d[tn].link[1])
tn = d[tn].link[1];
return &d[tn].value;
}
static int32_t
_c_MEMB(_new_node_)(Self* self, int level) {
int32_t tn;
if (self->disp != 0) {
tn = self->disp;
self->disp = self->nodes[tn].link[1];
} else {
if (self->head == self->capacity)
if (!_c_MEMB(_reserve)(self, self->head*3/2 + 4))
return 0;
tn = ++self->head; /* start with 1, 0 is nullnode. */
}
_m_node* dn = &self->nodes[tn];
dn->link[0] = dn->link[1] = 0; dn->level = (int8_t)level;
return tn;
}
#ifdef _i_is_map
STC_DEF _m_result
_c_MEMB(_insert_or_assign)(Self* self, _m_key _key, _m_mapped _mapped) {
_m_result _res = _c_MEMB(_insert_entry_)(self, i_keytoraw((&_key)));
_m_mapped* _mp = _res.ref ? &_res.ref->second : &_mapped;
if (_res.inserted)
_res.ref->first = _key;
else
{ i_keydrop((&_key)); i_valdrop(_mp); }
*_mp = _mapped;
return _res;
}
#if !defined i_no_emplace
STC_DEF _m_result
_c_MEMB(_emplace_or_assign)(Self* self, _m_keyraw rkey, _m_rmapped rmapped) {
_m_result _res = _c_MEMB(_insert_entry_)(self, rkey);
if (_res.inserted)
_res.ref->first = i_keyfrom(rkey);
else {
if (_res.ref == NULL) return _res;
i_valdrop((&_res.ref->second));
}
_res.ref->second = i_valfrom(rmapped);
return _res;
}
#endif // !i_no_emplace
#endif // !_i_is_map
STC_DEF _m_value*
_c_MEMB(_find_it)(const Self* self, _m_keyraw rkey, _m_iter* out) {
int32_t tn = self->root;
_m_node *d = out->_d = self->nodes;
out->_top = 0;
while (tn) {
int c; const _m_keyraw _raw = i_keytoraw(_i_keyref(&d[tn].value));
if ((c = i_cmp((&_raw), (&rkey))) < 0)
tn = d[tn].link[1];
else if (c > 0)
{ out->_st[out->_top++] = tn; tn = d[tn].link[0]; }
else
{ out->_tn = d[tn].link[1]; return (out->ref = &d[tn].value); }
}
return (out->ref = NULL);
}
STC_DEF _m_iter
_c_MEMB(_lower_bound)(const Self* self, _m_keyraw rkey) {
_m_iter it;
_c_MEMB(_find_it)(self, rkey, &it);
if (it.ref == NULL && it._top != 0) {
int32_t tn = it._st[--it._top];
it._tn = it._d[tn].link[1];
it.ref = &it._d[tn].value;
}
return it;
}
STC_DEF int32_t
_c_MEMB(_skew_)(_m_node *d, int32_t tn) {
if (tn != 0 && d[d[tn].link[0]].level == d[tn].level) {
int32_t tmp = d[tn].link[0];
d[tn].link[0] = d[tmp].link[1];
d[tmp].link[1] = tn;
tn = tmp;
}
return tn;
}
STC_DEF int32_t
_c_MEMB(_split_)(_m_node *d, int32_t tn) {
if (d[d[d[tn].link[1]].link[1]].level == d[tn].level) {
int32_t tmp = d[tn].link[1];
d[tn].link[1] = d[tmp].link[0];
d[tmp].link[0] = tn;
tn = tmp;
++d[tn].level;
}
return tn;
}
STC_DEF int32_t
_c_MEMB(_insert_entry_i_)(Self* self, int32_t tn, const _m_keyraw* rkey, _m_result* _res) {
int32_t up[64], tx = tn;
_m_node* d = self->nodes;
int c, top = 0, dir = 0;
while (tx) {
up[top++] = tx;
const _m_keyraw _raw = i_keytoraw(_i_keyref(&d[tx].value));
if ((c = i_cmp((&_raw), rkey)) == 0)
{ _res->ref = &d[tx].value; return tn; }
dir = (c < 0);
tx = d[tx].link[dir];
}
if ((tx = _c_MEMB(_new_node_)(self, 1)) == 0)
return 0;
d = self->nodes;
_res->ref = &d[tx].value;
_res->inserted = true;
if (top == 0)
return tx;
d[up[top - 1]].link[dir] = tx;
while (top--) {
if (top != 0)
dir = (d[up[top - 1]].link[1] == up[top]);
up[top] = _c_MEMB(_skew_)(d, up[top]);
up[top] = _c_MEMB(_split_)(d, up[top]);
if (top)
d[up[top - 1]].link[dir] = up[top];
}
return up[0];
}
STC_DEF _m_result
_c_MEMB(_insert_entry_)(Self* self, _m_keyraw rkey) {
_m_result res = {0};
int32_t tn = _c_MEMB(_insert_entry_i_)(self, self->root, &rkey, &res);
self->root = tn;
self->size += res.inserted;
return res;
}
STC_DEF int32_t
_c_MEMB(_erase_r_)(Self *self, int32_t tn, const _m_keyraw* rkey, int *erased) {
_m_node *d = self->nodes;
if (tn == 0)
return 0;
_m_keyraw raw = i_keytoraw(_i_keyref(&d[tn].value));
int32_t tx; int c = i_cmp((&raw), rkey);
if (c != 0)
d[tn].link[c < 0] = _c_MEMB(_erase_r_)(self, d[tn].link[c < 0], rkey, erased);
else {
if ((*erased)++ == 0)
_c_MEMB(_value_drop)(self, &d[tn].value); // drop first time, not second.
if (d[tn].link[0] && d[tn].link[1]) {
tx = d[tn].link[0];
while (d[tx].link[1])
tx = d[tx].link[1];
d[tn].value = d[tx].value; /* move */
raw = i_keytoraw(_i_keyref(&d[tn].value));
d[tn].link[0] = _c_MEMB(_erase_r_)(self, d[tn].link[0], &raw, erased);
} else { /* unlink node */
tx = tn;
tn = d[tn].link[ d[tn].link[0] == 0 ];
/* move it to disposed nodes list */
d[tx].link[1] = self->disp;
self->disp = tx;
}
}
tx = d[tn].link[1];
if (d[d[tn].link[0]].level < d[tn].level - 1 || d[tx].level < d[tn].level - 1) {
if (d[tx].level > --d[tn].level)
d[tx].level = d[tn].level;
tn = _c_MEMB(_skew_)(d, tn);
tx = d[tn].link[1] = _c_MEMB(_skew_)(d, d[tn].link[1]);
d[tx].link[1] = _c_MEMB(_skew_)(d, d[tx].link[1]);
tn = _c_MEMB(_split_)(d, tn);
d[tn].link[1] = _c_MEMB(_split_)(d, d[tn].link[1]);
}
return tn;
}
STC_DEF int
_c_MEMB(_erase)(Self* self, _m_keyraw rkey) {
int erased = 0;
int32_t root = _c_MEMB(_erase_r_)(self, self->root, &rkey, &erased);
if (erased == 0)
return 0;
self->root = root;
--self->size;
return 1;
}
STC_DEF _m_iter
_c_MEMB(_erase_at)(Self* self, _m_iter it) {
_m_keyraw raw = i_keytoraw(_i_keyref(it.ref));
_c_MEMB(_next)(&it);
if (it.ref != NULL) {
_m_keyraw nxt = i_keytoraw(_i_keyref(it.ref));
_c_MEMB(_erase)(self, raw);
_c_MEMB(_find_it)(self, nxt, &it);
} else
_c_MEMB(_erase)(self, raw);
return it;
}
STC_DEF _m_iter
_c_MEMB(_erase_range)(Self* self, _m_iter it1, _m_iter it2) {
if (it2.ref == NULL) {
while (it1.ref != NULL)
it1 = _c_MEMB(_erase_at)(self, it1);
return it1;
}
_m_key k1 = *_i_keyref(it1.ref), k2 = *_i_keyref(it2.ref);
_m_keyraw r1 = i_keytoraw((&k1));
for (;;) {
if (memcmp(&k1, &k2, sizeof k1) == 0)
return it1;
_c_MEMB(_next)(&it1);
k1 = *_i_keyref(it1.ref);
_c_MEMB(_erase)(self, r1);
r1 = i_keytoraw((&k1));
_c_MEMB(_find_it)(self, r1, &it1);
}
}
#if !defined i_no_clone
STC_DEF int32_t
_c_MEMB(_clone_r_)(Self* self, _m_node* src, int32_t sn) {
if (sn == 0)
return 0;
int32_t tx, tn = _c_MEMB(_new_node_)(self, src[sn].level);
self->nodes[tn].value = _c_MEMB(_value_clone)(self, src[sn].value);
tx = _c_MEMB(_clone_r_)(self, src, src[sn].link[0]); self->nodes[tn].link[0] = tx;
tx = _c_MEMB(_clone_r_)(self, src, src[sn].link[1]); self->nodes[tn].link[1] = tx;
return tn;
}
STC_DEF Self
_c_MEMB(_clone)(Self tree) {
Self out = tree;
out.root = out.disp = out.head = out.size = out.capacity = 0;
out.nodes = NULL; _c_MEMB(_reserve)(&out, tree.size);
out.root = _c_MEMB(_clone_r_)(&out, tree.nodes, tree.root);
return out;
}
#endif // !i_no_clone
#if !defined i_no_emplace
STC_DEF _m_result
_c_MEMB(_emplace)(Self* self, _m_keyraw rkey _i_MAP_ONLY(, _m_rmapped rmapped)) {
_m_result res = _c_MEMB(_insert_entry_)(self, rkey);
if (res.inserted) {
*_i_keyref(res.ref) = i_keyfrom(rkey);
_i_MAP_ONLY(res.ref->second = i_valfrom(rmapped);)
}
return res;
}
#endif // i_no_emplace
static void
_c_MEMB(_drop_r_)(Self* s, int32_t tn) {
if (tn != 0) {
_c_MEMB(_drop_r_)(s, s->nodes[tn].link[0]);
_c_MEMB(_drop_r_)(s, s->nodes[tn].link[1]);
_c_MEMB(_value_drop)(s, &s->nodes[tn].value);
}
}
STC_DEF void
_c_MEMB(_drop)(const Self* cself) {
Self* self = (Self*)cself;
if (self->capacity != 0) {
_c_MEMB(_drop_r_)(self, self->root);
_i_free_n(self->nodes, self->capacity + 1);
}
}
#endif // i_implement
#undef _i_is_set
#undef _i_is_map
#undef _i_sorted
#undef _i_keyref
#undef _i_MAP_ONLY
#undef _i_SET_ONLY
#include "sys/finalize.h"