Skip to main content

hara_native/lang/data/
map.rs

1use std::cell::Cell;
2use std::hash::{Hash, Hasher};
3use std::rc::Rc;
4
5thread_local! {
6    static CHAMP_PLACEMENT_HASHING: Cell<bool> = const { Cell::new(false) };
7}
8
9pub(crate) fn with_champ_placement_hash<T>(f: impl FnOnce() -> T) -> T {
10    CHAMP_PLACEMENT_HASHING.with(|active| {
11        let previous = active.replace(true);
12        let result = f();
13        active.set(previous);
14        result
15    })
16}
17
18pub(crate) fn champ_placement_hashing() -> bool {
19    CHAMP_PLACEMENT_HASHING.with(Cell::get)
20}
21
22use crate::lang::hash::JavaHash;
23use crate::lang::protocol::{
24    HashType, IAssoc, IColl, IConj, ICount, IDisplay, IDissoc, IEmpty, IEquality, IFind, IHash,
25    ILookup, IMetadata, IMutable, IObjType, IPersistent, IToMutable, IToPersistent, MetaType,
26    ObjType,
27};
28
29const SHIFT: usize = 5;
30const MASK: u64 = 0x1f;
31
32// CHAMP port of `java/src/main/java/hara/lang/data/Map.java`.
33//
34// Layout parity with the Java `DataNode`: a node's `slots` vec is split into
35// a data region `[0, data_arity)` holding one `Slot::Entry` per key/value pair
36// (Java flattens pairs into two array slots; one slot per pair here keeps the
37// same ordering) and a node region `[data_arity, len)` holding sub-nodes.
38// Entries ascend by bitpos from the front; sub-nodes ascend by bitpos from
39// the END, so `slots[data_arity]` is the highest-bitpos sub-node and
40// `slots[len - 1]` the lowest. Iteration emits the data region first, then
41// descends sub-nodes from `slots[data_arity]` forward — Java `NodeIter`
42// visits its node slots counting down from nodeArity, which is the same
43// descending-bitpos order.
44#[derive(Debug, Clone)]
45enum Slot<K, V> {
46    Entry { hash: u64, key: K, value: V },
47    Node(Rc<Node<K, V>>),
48}
49
50#[derive(Debug, Clone)]
51struct DataNode<K, V> {
52    edit: Cell<u64>,
53    datamap: u32,
54    nodemap: u32,
55    slots: Vec<Slot<K, V>>,
56}
57
58#[derive(Debug, Clone)]
59struct CollisionNode<K, V> {
60    edit: Cell<u64>,
61    hash: u64,
62    entries: Vec<(K, V)>,
63}
64
65#[derive(Debug, Clone)]
66enum Node<K, V> {
67    Data(DataNode<K, V>),
68    Collision(CollisionNode<K, V>),
69}
70
71impl<K, V> Node<K, V> {
72    fn empty() -> Rc<Self> {
73        Rc::new(Self::Data(DataNode {
74            edit: Cell::new(0),
75            datamap: 0,
76            nodemap: 0,
77            slots: Vec::new(),
78        }))
79    }
80    fn set_edit(&self, token: u64) {
81        match self {
82            Node::Data(d) => d.edit.set(token),
83            Node::Collision(c) => c.edit.set(token),
84        }
85    }
86    fn is_single(&self) -> bool {
87        match self {
88            Node::Data(d) => d.nodemap == 0 && d.datamap.count_ones() == 1,
89            Node::Collision(c) => c.entries.len() == 1,
90        }
91    }
92}
93
94/// Hash used for CHAMP placement, matching Java's `(int) G.hashRapid(key)` —
95/// the low 32 bits of the Java-parity value hash.
96///
97/// `core::Value`'s `std::hash::Hash` impl writes exactly its `stable_hash()`
98/// (the Java-parity RAPID hash) as a single `write_u64`, so we capture that
99/// write with a probe hasher and take its low 32 bits. Keys of any other
100/// type fall back to the previous `DefaultHasher`-over-`Hash` behaviour
101/// (identical writes, identical result — no Java parity exists for them).
102fn key_hash<K: Hash>(key: &K) -> u64 {
103    #[derive(Default)]
104    struct Probe {
105        captured: Option<u64>,
106        fallback: std::collections::hash_map::DefaultHasher,
107    }
108    impl Hasher for Probe {
109        fn finish(&self) -> u64 {
110            self.captured.unwrap_or_else(|| self.fallback.finish())
111        }
112        fn write(&mut self, bytes: &[u8]) {
113            self.fallback.write(bytes);
114        }
115        fn write_u64(&mut self, value: u64) {
116            if self.captured.is_none() {
117                self.captured = Some(value);
118            }
119        }
120    }
121    let mut probe = Probe::default();
122    with_champ_placement_hash(|| key.hash(&mut probe));
123    let hash = probe.finish();
124    if probe.captured.is_some() {
125        (hash as u32) as u64
126    } else {
127        hash
128    }
129}
130fn mask(hash: u64, shift: usize) -> usize {
131    ((hash >> shift) & MASK) as usize
132}
133fn bit(hash: u64, shift: usize) -> u32 {
134    1u32 << mask(hash, shift)
135}
136fn index(bitmap: u32, bit: u32) -> usize {
137    (bitmap & (bit - 1)).count_ones() as usize
138}
139/// Node-region slot index for `bit`: sub-nodes ascend by bitpos from the end,
140/// so the slot for `bit` sits at `data_arity + (node_arity - 1 - p)` where
141/// `p` counts node bits below `bit`.
142fn node_slot<K, V>(d: &DataNode<K, V>, bit: u32) -> usize {
143    d.datamap.count_ones() as usize + (d.nodemap.count_ones() as usize - 1 - index(d.nodemap, bit))
144}
145
146/// Clone-on-write unifier. Every node-level operation prepares its level
147/// through `ensure` before doing surgery. With `Some(token)` (transient) the
148/// node is edited in place when uniquely owned and cloned when shared; with
149/// `None` (persistent) the node is always cloned, leaving the source tree
150/// untouched.
151fn ensure<'a, K: Clone, V: Clone>(
152    node: &'a mut Rc<Node<K, V>>,
153    edit: Option<u64>,
154) -> &'a mut Node<K, V> {
155    match edit {
156        Some(token) => {
157            let n = Rc::make_mut(node);
158            n.set_edit(token);
159            n
160        }
161        None => {
162            let fresh = (**node).clone();
163            fresh.set_edit(0);
164            *node = Rc::new(fresh);
165            Rc::get_mut(node).expect("freshly cloned node is uniquely owned")
166        }
167    }
168}
169
170/// Java `mergeTwoKeyValuePairs`: build the sub-tree holding two entries that
171/// currently collide at `shift`. Past shift 32 equal hashes become a
172/// collision node (Java `BranchNode`); equal masks recurse wrapped in a
173/// single-node DataNode; differing masks produce a two-entry DataNode ordered
174/// by mask.
175fn merge_two<K: Clone, V: Clone>(
176    edit: Option<u64>,
177    shift: usize,
178    a_hash: u64,
179    a_key: K,
180    a_val: V,
181    b_hash: u64,
182    b_key: K,
183    b_val: V,
184) -> Rc<Node<K, V>> {
185    let e = edit.unwrap_or(0);
186    if shift > 32 && a_hash == b_hash {
187        return Rc::new(Node::Collision(CollisionNode {
188            edit: Cell::new(e),
189            hash: a_hash,
190            entries: vec![(a_key, a_val), (b_key, b_val)],
191        }));
192    }
193    let abit = bit(a_hash, shift);
194    let bbit = bit(b_hash, shift);
195    if abit == bbit {
196        return Rc::new(Node::Data(DataNode {
197            edit: Cell::new(e),
198            datamap: 0,
199            nodemap: abit,
200            slots: vec![Slot::Node(merge_two(
201                edit,
202                shift + SHIFT,
203                a_hash,
204                a_key,
205                a_val,
206                b_hash,
207                b_key,
208                b_val,
209            ))],
210        }));
211    }
212    let (first, second) = if mask(a_hash, shift) < mask(b_hash, shift) {
213        (
214            Slot::Entry {
215                hash: a_hash,
216                key: a_key,
217                value: a_val,
218            },
219            Slot::Entry {
220                hash: b_hash,
221                key: b_key,
222                value: b_val,
223            },
224        )
225    } else {
226        (
227            Slot::Entry {
228                hash: b_hash,
229                key: b_key,
230                value: b_val,
231            },
232            Slot::Entry {
233                hash: a_hash,
234                key: a_key,
235                value: a_val,
236            },
237        )
238    };
239    Rc::new(Node::Data(DataNode {
240        edit: Cell::new(e),
241        datamap: abit | bbit,
242        nodemap: 0,
243        slots: vec![first, second],
244    }))
245}
246
247/// Defensive merge of an existing (collision) node with a new entry whose
248/// hash differs — unreachable for 32-bit placement past shift 32, kept for
249/// fallback-hash keys. Data region first, node region last.
250fn merge_node<K: Clone, V: Clone>(
251    edit: Option<u64>,
252    shift: usize,
253    node_hash: u64,
254    node: Rc<Node<K, V>>,
255    hash: u64,
256    key: K,
257    value: V,
258) -> Rc<Node<K, V>> {
259    let e = edit.unwrap_or(0);
260    let abit = bit(node_hash, shift);
261    let bbit = bit(hash, shift);
262    if abit == bbit {
263        return Rc::new(Node::Data(DataNode {
264            edit: Cell::new(e),
265            datamap: 0,
266            nodemap: abit,
267            slots: vec![Slot::Node(merge_node(
268                edit,
269                shift + SHIFT,
270                node_hash,
271                node,
272                hash,
273                key,
274                value,
275            ))],
276        }));
277    }
278    Rc::new(Node::Data(DataNode {
279        edit: Cell::new(e),
280        datamap: bbit,
281        nodemap: abit,
282        slots: vec![Slot::Entry { hash, key, value }, Slot::Node(node)],
283    }))
284}
285
286/// Java `DataNode.assoc` / `BranchNode.assoc`. Returns whether a pair was
287/// added (false on value replacement). `node` is updated in place through
288/// the `Rc`; `ensure` at each level provides persistent vs transient
289/// behaviour.
290fn assoc_node<K: Clone + Eq, V: Clone>(
291    node: &mut Rc<Node<K, V>>,
292    edit: Option<u64>,
293    shift: usize,
294    hash: u64,
295    key: K,
296    value: V,
297) -> bool {
298    enum Act<K, V> {
299        CollisionReplace(usize),
300        CollisionPush,
301        CollisionMerge,
302        DataReplace(usize),
303        DataMerge { i: usize, b: u32, old: (u64, K, V) },
304        DataRecurse(usize),
305        DataInsert { i: usize, b: u32 },
306    }
307    let act = match node.as_ref() {
308        Node::Collision(c) => {
309            if c.hash == hash {
310                match c.entries.iter().position(|(k, _)| k == &key) {
311                    Some(i) => Act::CollisionReplace(i),
312                    None => Act::CollisionPush,
313                }
314            } else {
315                Act::CollisionMerge
316            }
317        }
318        Node::Data(d) => {
319            let b = bit(hash, shift);
320            if d.datamap & b != 0 {
321                let i = index(d.datamap, b);
322                match &d.slots[i] {
323                    Slot::Entry {
324                        hash: old_hash,
325                        key: old_key,
326                        value: old_value,
327                    } => {
328                        if old_key == &key {
329                            Act::DataReplace(i)
330                        } else {
331                            Act::DataMerge {
332                                i,
333                                b,
334                                old: (*old_hash, old_key.clone(), old_value.clone()),
335                            }
336                        }
337                    }
338                    Slot::Node(_) => unreachable!("data region holds entries only"),
339                }
340            } else if d.nodemap & b != 0 {
341                Act::DataRecurse(node_slot(d, b))
342            } else {
343                Act::DataInsert {
344                    i: index(d.datamap, b),
345                    b,
346                }
347            }
348        }
349    };
350    match act {
351        Act::CollisionReplace(i) => {
352            if let Node::Collision(c) = ensure(node, edit) {
353                c.entries[i].1 = value;
354            }
355            false
356        }
357        Act::CollisionPush => {
358            if let Node::Collision(c) = ensure(node, edit) {
359                c.entries.push((key, value));
360            }
361            true
362        }
363        Act::CollisionMerge => {
364            let node_hash = match node.as_ref() {
365                Node::Collision(c) => c.hash,
366                _ => unreachable!(),
367            };
368            let old = std::mem::replace(node, Node::empty());
369            *node = merge_node(edit, shift, node_hash, old, hash, key, value);
370            true
371        }
372        Act::DataReplace(i) => {
373            if let Node::Data(d) = ensure(node, edit) {
374                d.slots[i] = Slot::Entry { hash, key, value };
375            }
376            false
377        }
378        Act::DataMerge { i, b, old } => {
379            let (old_hash, old_key, old_value) = old;
380            let merged = merge_two(
381                edit,
382                shift + SHIFT,
383                old_hash,
384                old_key,
385                old_value,
386                hash,
387                key,
388                value,
389            );
390            if let Node::Data(d) = ensure(node, edit) {
391                // copyAndMigrateToNode: drop the data slot, move the bit to
392                // nodemap, insert the sub-node into the node region.
393                d.slots.remove(i);
394                d.datamap ^= b;
395                d.nodemap |= b;
396                let p = index(d.nodemap, b);
397                let pos =
398                    d.datamap.count_ones() as usize + (d.nodemap.count_ones() as usize - 1 - p);
399                d.slots.insert(pos, Slot::Node(merged));
400            }
401            true
402        }
403        Act::DataRecurse(i) => {
404            let n = ensure(node, edit);
405            match n {
406                Node::Data(d) => match &mut d.slots[i] {
407                    Slot::Node(child) => assoc_node(child, edit, shift + SHIFT, hash, key, value),
408                    Slot::Entry { .. } => unreachable!("node region holds nodes only"),
409                },
410                _ => unreachable!(),
411            }
412        }
413        Act::DataInsert { i, b } => {
414            if let Node::Data(d) = ensure(node, edit) {
415                d.slots.insert(i, Slot::Entry { hash, key, value });
416                d.datamap |= b;
417            }
418            true
419        }
420    }
421}
422
423fn find_node<'a, K: Eq, V>(
424    node: &'a Node<K, V>,
425    shift: usize,
426    hash: u64,
427    key: &K,
428) -> Option<(&'a K, &'a V)> {
429    match node {
430        Node::Collision(c) if c.hash == hash => c
431            .entries
432            .iter()
433            .find(|(k, _)| k == key)
434            .map(|(k, v)| (k, v)),
435        Node::Collision(_) => None,
436        Node::Data(d) => {
437            let b = bit(hash, shift);
438            if d.datamap & b != 0 {
439                match &d.slots[index(d.datamap, b)] {
440                    Slot::Entry {
441                        key: k, value: v, ..
442                    } if k == key => Some((k, v)),
443                    _ => None,
444                }
445            } else if d.nodemap & b != 0 {
446                match &d.slots[node_slot(d, b)] {
447                    Slot::Node(child) => find_node(child, shift + SHIFT, hash, key),
448                    Slot::Entry { .. } => None,
449                }
450            } else {
451                None
452            }
453        }
454    }
455}
456
457/// Java `DataNode.without` / `BranchNode.without` for a key known to be
458/// present — callers pre-check with `find_node`, so every level along the
459/// path changes and `ensure` is always safe. Exact-size semantics differ
460/// deliberately from two Java bugs this does not replicate: Java's
461/// `BranchNode.persistentAssoc` inflates the node pair count on value
462/// replacement, and its `BranchNode.without` two-element case threads the
463/// `removed_leaf` counter through `EMPTY.assoc`, double-counting the removal.
464fn without_present<K: Clone + Eq, V: Clone>(
465    node: &mut Rc<Node<K, V>>,
466    edit: Option<u64>,
467    shift: usize,
468    hash: u64,
469    key: &K,
470) {
471    enum Act {
472        DataRemove { i: usize, b: u32 },
473        DataCollapse { keep: usize, new_datamap: u32 },
474        Recurse { i: usize, b: u32 },
475        CollisionRemove(usize),
476        CollisionToData,
477        CollisionToEmpty,
478    }
479    let act = match node.as_ref() {
480        Node::Collision(c) => {
481            debug_assert_eq!(c.hash, hash);
482            match c.entries.len() {
483                1 => Act::CollisionToEmpty,
484                2 => Act::CollisionToData,
485                _ => Act::CollisionRemove(
486                    c.entries
487                        .iter()
488                        .position(|(k, _)| k == key)
489                        .expect("key is present"),
490                ),
491            }
492        }
493        Node::Data(d) => {
494            let b = bit(hash, shift);
495            if d.datamap & b != 0 {
496                let i = index(d.datamap, b);
497                if d.datamap.count_ones() == 2 && d.nodemap == 0 {
498                    let keep = if i == 0 { 1 } else { 0 };
499                    // Java re-bases the removed key's hash at level 0. That is
500                    // correct, not a bug: every key routed into a sub-node at
501                    // shift s shares the removed key's masks at shifts
502                    // 0..s-5, so both keys have the same root bitpos.
503                    let new_datamap = if shift == 0 {
504                        d.datamap ^ b
505                    } else {
506                        bit(hash, 0)
507                    };
508                    Act::DataCollapse { keep, new_datamap }
509                } else {
510                    Act::DataRemove { i, b }
511                }
512            } else {
513                debug_assert!(d.nodemap & b != 0, "key is present below");
514                Act::Recurse {
515                    i: node_slot(d, b),
516                    b,
517                }
518            }
519        }
520    };
521    match act {
522        Act::DataRemove { i, b } => {
523            if let Node::Data(d) = ensure(node, edit) {
524                d.slots.remove(i);
525                d.datamap ^= b;
526            }
527        }
528        Act::DataCollapse { keep, new_datamap } => {
529            let kept = match node.as_ref() {
530                Node::Data(d) => d.slots[keep].clone(),
531                _ => unreachable!(),
532            };
533            *node = Rc::new(Node::Data(DataNode {
534                edit: Cell::new(edit.unwrap_or(0)),
535                datamap: new_datamap,
536                nodemap: 0,
537                slots: vec![kept],
538            }));
539        }
540        Act::Recurse { i, b } => {
541            let n = ensure(node, edit);
542            let d = match n {
543                Node::Data(d) => d,
544                _ => unreachable!(),
545            };
546            let child_single = match &mut d.slots[i] {
547                Slot::Node(child) => {
548                    without_present(child, edit, shift + SHIFT, hash, key);
549                    child.is_single()
550                }
551                Slot::Entry { .. } => unreachable!("node region holds nodes only"),
552            };
553            if !child_single {
554                return;
555            }
556            if d.datamap == 0 && d.nodemap.count_ones() == 1 {
557                // Only child left: collapse this node away entirely.
558                let child = match &d.slots[i] {
559                    Slot::Node(c) => c.clone(),
560                    _ => unreachable!(),
561                };
562                *node = child;
563                return;
564            }
565            // copyAndMigrateToInline: lift the collapsed child's pair into
566            // this node's data region.
567            let child = match &d.slots[i] {
568                Slot::Node(c) => c.clone(),
569                _ => unreachable!(),
570            };
571            let (ehash, ekey, evalue) = match child.as_ref() {
572                Node::Data(cd) => match &cd.slots[0] {
573                    Slot::Entry { hash, key, value } => (*hash, key.clone(), value.clone()),
574                    Slot::Node(_) => unreachable!("single-pair node holds an entry"),
575                },
576                Node::Collision(cc) => {
577                    let (k, v) = cc.entries[0].clone();
578                    (cc.hash, k, v)
579                }
580            };
581            let p = index(d.nodemap, b);
582            let node_pos =
583                d.datamap.count_ones() as usize + (d.nodemap.count_ones() as usize - 1 - p);
584            d.slots.remove(node_pos);
585            d.nodemap ^= b;
586            d.datamap |= b;
587            let data_pos = index(d.datamap, b);
588            d.slots.insert(
589                data_pos,
590                Slot::Entry {
591                    hash: ehash,
592                    key: ekey,
593                    value: evalue,
594                },
595            );
596        }
597        Act::CollisionRemove(i) => {
598            if let Node::Collision(c) = ensure(node, edit) {
599                c.entries.remove(i);
600            }
601        }
602        Act::CollisionToData => {
603            // Java: `EMPTY.assoc(edit, 0, hash, remaining)` — a root-level
604            // single-pair DataNode keyed by the shared collision hash.
605            let (k, v) = match node.as_ref() {
606                Node::Collision(c) => c
607                    .entries
608                    .iter()
609                    .find(|(k, _)| k != key)
610                    .cloned()
611                    .expect("other entry is present"),
612                _ => unreachable!(),
613            };
614            *node = Rc::new(Node::Data(DataNode {
615                edit: Cell::new(edit.unwrap_or(0)),
616                datamap: bit(hash, 0),
617                nodemap: 0,
618                slots: vec![Slot::Entry {
619                    hash,
620                    key: k,
621                    value: v,
622                }],
623            }));
624        }
625        Act::CollisionToEmpty => {
626            *node = Rc::new(Node::Data(DataNode {
627                edit: Cell::new(edit.unwrap_or(0)),
628                datamap: 0,
629                nodemap: 0,
630                slots: Vec::new(),
631            }));
632        }
633    }
634}
635
636fn collect<'a, K, V>(node: &'a Node<K, V>, out: &mut Vec<(&'a K, &'a V)>) {
637    match node {
638        Node::Collision(c) => out.extend(c.entries.iter().map(|(k, v)| (k, v))),
639        Node::Data(d) => {
640            let data_arity = d.datamap.count_ones() as usize;
641            for slot in &d.slots[..data_arity] {
642                match slot {
643                    Slot::Entry { key, value, .. } => out.push((key, value)),
644                    Slot::Node(_) => unreachable!("data region holds entries only"),
645                }
646            }
647            // Java NodeIter descends sub-nodes from the highest bitpos down;
648            // that is the node region from `slots[data_arity]` forward.
649            for slot in &d.slots[data_arity..] {
650                match slot {
651                    Slot::Node(child) => collect(child, out),
652                    Slot::Entry { .. } => unreachable!("node region holds nodes only"),
653                }
654            }
655        }
656    }
657}
658
659#[derive(Debug, Clone)]
660pub struct Standard<K, V> {
661    metadata: Option<Rc<crate::lang::data::Metadata>>,
662    root: Rc<Node<K, V>>,
663    size: usize,
664}
665impl<K, V> Default for Standard<K, V> {
666    fn default() -> Self {
667        Self {
668            metadata: None,
669            root: Node::empty(),
670            size: 0,
671        }
672    }
673}
674impl<K: Clone + Eq + Hash, V: Clone> Standard<K, V> {
675    pub fn new() -> Self {
676        Self::default()
677    }
678    pub fn len(&self) -> usize {
679        self.size
680    }
681    pub fn is_empty(&self) -> bool {
682        self.size == 0
683    }
684    pub fn get(&self, key: &K) -> Option<&V> {
685        find_node(&self.root, 0, key_hash(key), key).map(|(_, v)| v)
686    }
687    pub fn find_entry(&self, key: &K) -> Option<(&K, &V)> {
688        find_node(&self.root, 0, key_hash(key), key)
689    }
690    pub fn assoc_value(&self, key: K, value: V) -> Self {
691        let mut root = self.root.clone();
692        let added = assoc_node(&mut root, None, 0, key_hash(&key), key, value);
693        Self {
694            metadata: self.metadata.clone(),
695            root,
696            size: self.size + usize::from(added),
697        }
698    }
699    /// Associates into a consumed map using clone-on-write nodes. This keeps
700    /// persistent aliases immutable while allowing uniquely owned paths to be
701    /// updated without first cloning every node on the path.
702    pub fn assoc_value_owned(mut self, key: K, value: V) -> Self {
703        let added = assoc_node(&mut self.root, Some(0), 0, key_hash(&key), key, value);
704        self.size += usize::from(added);
705        self
706    }
707    pub fn dissoc_value(&self, key: &K) -> Self {
708        let hash = key_hash(key);
709        if find_node(&self.root, 0, hash, key).is_none() {
710            return self.clone();
711        }
712        let mut root = self.root.clone();
713        without_present(&mut root, None, 0, hash, key);
714        Self {
715            metadata: self.metadata.clone(),
716            root,
717            size: self.size - 1,
718        }
719    }
720    pub fn iter(&self) -> std::vec::IntoIter<(&K, &V)> {
721        self.entries().into_iter()
722    }
723    pub fn entries(&self) -> Vec<(&K, &V)> {
724        let mut out = Vec::with_capacity(self.size);
725        collect(&self.root, &mut out);
726        out
727    }
728    pub fn shares_root_with(&self, other: &Self) -> bool {
729        Rc::ptr_eq(&self.root, &other.root)
730    }
731}
732impl<K: Clone + Eq + Hash, V: Clone> FromIterator<(K, V)> for Standard<K, V> {
733    fn from_iter<T: IntoIterator<Item = (K, V)>>(iter: T) -> Self {
734        iter.into_iter()
735            .fold(Self::new(), |map, (k, v)| map.assoc_value(k, v))
736    }
737}
738impl<K: Clone + Eq + Hash, V: Clone> IntoIterator for Standard<K, V> {
739    type Item = (K, V);
740    type IntoIter = std::vec::IntoIter<(K, V)>;
741    fn into_iter(self) -> Self::IntoIter {
742        self.entries()
743            .into_iter()
744            .map(|(k, v)| (k.clone(), v.clone()))
745            .collect::<Vec<_>>()
746            .into_iter()
747    }
748}
749impl<K: Clone + Eq + Hash, V: Clone + PartialEq> PartialEq for Standard<K, V> {
750    fn eq(&self, other: &Self) -> bool {
751        self.size == other.size && self.entries().iter().all(|(k, v)| other.get(k) == Some(*v))
752    }
753}
754impl<K: Clone + Eq + Hash, V: Clone> ICount for Standard<K, V> {
755    fn count(&self) -> usize {
756        self.size
757    }
758}
759impl<K: Clone + Eq + Hash, V: Clone> IAssoc<K, V> for Standard<K, V> {
760    type Output = Self;
761    fn assoc(&self, key: K, value: V) -> Self {
762        self.assoc_value(key, value)
763    }
764}
765impl<K: Clone + Eq + Hash, V: Clone> IDissoc<K> for Standard<K, V> {
766    type Output = Self;
767    fn dissoc(&self, key: &K) -> Self {
768        self.dissoc_value(key)
769    }
770}
771impl<K: Clone + Eq + Hash, V: Clone> IFind<K> for Standard<K, V> {
772    type Output = (K, V);
773    fn find(&self, key: &K) -> Option<Self::Output> {
774        self.find_entry(key).map(|(k, v)| (k.clone(), v.clone()))
775    }
776}
777impl<K: Clone + Eq + Hash, V: Clone> ILookup<K, V> for Standard<K, V> {
778    type Keys = std::vec::IntoIter<K>;
779    type Values = std::vec::IntoIter<V>;
780    fn keys(&self) -> Self::Keys {
781        self.entries()
782            .into_iter()
783            .map(|(k, _)| k.clone())
784            .collect::<Vec<_>>()
785            .into_iter()
786    }
787    fn vals(&self) -> Self::Values {
788        self.entries()
789            .into_iter()
790            .map(|(_, v)| v.clone())
791            .collect::<Vec<_>>()
792            .into_iter()
793    }
794}
795impl<K: Clone + Eq + Hash, V: Clone> IEmpty for Standard<K, V> {
796    type Output = Self;
797    fn empty(&self) -> Self {
798        Self::new().with_meta(self.metadata.clone())
799    }
800}
801impl<K: Clone + Eq + Hash, V: Clone> IMetadata for Standard<K, V> {
802    type Metadata = Rc<crate::lang::data::Metadata>;
803    fn meta(&self) -> Option<&Self::Metadata> {
804        self.metadata.as_ref()
805    }
806    fn with_meta(&self, metadata: Option<Self::Metadata>) -> Self {
807        Self {
808            metadata,
809            ..self.clone()
810        }
811    }
812
813    fn metatype(&self) -> MetaType {
814        MetaType::Map
815    }
816}
817impl<K: Clone + Eq + Hash, V: Clone> IPersistent for Standard<K, V> {}
818impl<K: Clone + Eq + Hash, V: Clone> IConj<(K, V)> for Standard<K, V> {
819    type Output = Self;
820    fn conj(&self, (key, value): (K, V)) -> Self {
821        self.assoc_value(key, value)
822    }
823}
824impl<K: Clone + Eq + Hash, V: Clone + PartialEq> IEquality for Standard<K, V> {
825    fn equality(&self, other: &Self) -> bool {
826        self == other
827    }
828}
829impl<K: Clone + Eq + Hash + std::fmt::Debug, V: Clone + std::fmt::Debug> IDisplay
830    for Standard<K, V>
831{
832    fn display(&self) -> String {
833        format!(
834            "{{{}}}",
835            self.entries()
836                .iter()
837                .map(|(k, v)| format!("{k:?} {v:?}"))
838                .collect::<Vec<_>>()
839                .join(" ")
840        )
841    }
842}
843impl<K: Clone + Eq + Hash + JavaHash, V: Clone + Hash + JavaHash> IHash for Standard<K, V> {
844    fn hash_calc(&self, hash_type: HashType) -> u64 {
845        // Java IMapType → IUnOrderedType over entries: order-insensitive sum,
846        // "::MAP" seed. Entries iterate as MapEntry values in Java, so each
847        // entry hashes as an ordered 2-tuple ("::SEQUENTIAL"
848        // seed): (seed * 31 + hk) * 31 + hv. See lang::hash.
849        crate::lang::hash::compose_unordered(
850            "MAP",
851            self.entries().iter().map(|(k, v)| {
852                crate::lang::hash::compose_entry(k.java_hash(hash_type), v.java_hash(hash_type))
853            }),
854        ) as u64
855    }
856}
857impl<K: Clone + Eq + Hash + std::fmt::Debug, V: Clone + std::fmt::Debug> IObjType
858    for Standard<K, V>
859{
860    fn obj_type(&self) -> ObjType {
861        ObjType::Map
862    }
863}
864impl<K, V> IColl<(K, V)> for Standard<K, V>
865where
866    K: Clone + Eq + Hash + JavaHash + std::fmt::Debug,
867    V: Clone + PartialEq + Hash + JavaHash + std::fmt::Debug,
868{
869    fn start_string(&self) -> &'static str {
870        "{"
871    }
872    fn end_string(&self) -> &'static str {
873        "}"
874    }
875}
876impl<K: Clone + Eq + Hash, V: Clone> IToMutable for Standard<K, V> {
877    type Mutable = Mutable<K, V>;
878    fn to_mutable(&self) -> Self::Mutable {
879        Mutable {
880            editable: Cell::new(true),
881            token: fresh_edit(),
882            standard: self.clone(),
883        }
884    }
885}
886
887thread_local! {
888    static NEXT_EDIT: Cell<u64> = const { Cell::new(1) };
889}
890fn fresh_edit() -> u64 {
891    NEXT_EDIT.with(|c| {
892        let token = c.get();
893        c.set(token + 1);
894        token
895    })
896}
897
898#[derive(Debug, Clone)]
899pub struct Mutable<K, V> {
900    editable: Cell<bool>,
901    token: u64,
902    standard: Standard<K, V>,
903}
904impl<K: Clone + Eq + Hash, V: Clone> Mutable<K, V> {
905    fn check(&self) {
906        assert!(self.editable.get(), "mutable map used after to_persistent")
907    }
908    pub fn assoc(&mut self, key: K, value: V) -> &mut Self {
909        self.check();
910        let hash = key_hash(&key);
911        // Take the root out first: otherwise this struct's own handle keeps
912        // the Rc shared and in-place editing never triggers.
913        let mut root = std::mem::replace(&mut self.standard.root, Node::empty());
914        let added = assoc_node(&mut root, Some(self.token), 0, hash, key, value);
915        self.standard.root = root;
916        self.standard.size += usize::from(added);
917        self
918    }
919    pub fn dissoc(&mut self, key: &K) -> &mut Self {
920        self.check();
921        let hash = key_hash(key);
922        if find_node(&self.standard.root, 0, hash, key).is_some() {
923            let mut root = std::mem::replace(&mut self.standard.root, Node::empty());
924            without_present(&mut root, Some(self.token), 0, hash, key);
925            self.standard.root = root;
926            self.standard.size -= 1;
927        }
928        self
929    }
930}
931impl<K: Clone + Eq + Hash, V: Clone> std::ops::Deref for Mutable<K, V> {
932    type Target = Standard<K, V>;
933    fn deref(&self) -> &Self::Target {
934        self.check();
935        &self.standard
936    }
937}
938impl<K, V> IMutable for Mutable<K, V> {}
939impl<K: Clone + Eq + Hash, V: Clone> IToPersistent for Mutable<K, V> {
940    type Persistent = Standard<K, V>;
941    fn to_persistent(&mut self) -> Self::Persistent {
942        self.check();
943        self.editable.set(false);
944        self.standard.clone()
945    }
946}
947
948#[cfg(test)]
949mod tests {
950    use super::Standard;
951    use crate::core::Value;
952    use crate::lang::protocol::{IEmpty, IMetadata, IToMutable, IToPersistent};
953    use std::collections::HashMap;
954    use std::hash::{Hash, Hasher};
955
956    #[derive(Clone, Debug, Eq, PartialEq)]
957    struct Collision(i32);
958    impl Hash for Collision {
959        fn hash<H: Hasher>(&self, state: &mut H) {
960            0.hash(state)
961        }
962    }
963
964    /// Key whose `Hash` writes its inner value as a single `write_u64`, so
965    /// `key_hash`'s probe captures it and placement uses its low 32 bits
966    /// exactly — controlled CHAMP placement without touching the fallback.
967    #[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
968    struct Key(u64);
969    impl Hash for Key {
970        fn hash<H: Hasher>(&self, state: &mut H) {
971            state.write_u64(self.0);
972        }
973    }
974
975    struct Rng(u64);
976    impl Rng {
977        fn next(&mut self) -> u64 {
978            let mut x = self.0;
979            x ^= x << 13;
980            x ^= x >> 7;
981            x ^= x << 17;
982            self.0 = x;
983            x
984        }
985    }
986
987    #[test]
988    fn persistent_operations_and_mutable_round_trip_preserve_metadata() {
989        let map = Standard::new()
990            .assoc_value("a", 1)
991            .with_meta(Some(crate::lang::data::Metadata::document("doc")));
992        assert_eq!(
993            map.assoc_value("b", 2).meta().map(|m| m.doc().unwrap()),
994            Some("doc")
995        );
996        assert_eq!(
997            map.dissoc_value(&"a").meta().map(|m| m.doc().unwrap()),
998            Some("doc")
999        );
1000        assert_eq!(map.empty().meta().map(|m| m.doc().unwrap()), Some("doc"));
1001        let mut mutable = map.to_mutable();
1002        mutable.assoc("b", 2);
1003        assert_eq!(
1004            mutable.to_persistent().meta().map(|m| m.doc().unwrap()),
1005            Some("doc")
1006        );
1007    }
1008
1009    #[test]
1010    fn assoc_collision_removal_and_persistence() {
1011        let empty = Standard::new();
1012        let a = empty.assoc_value(Collision(1), 10);
1013        let b = a.assoc_value(Collision(2), 20);
1014        let c = b.dissoc_value(&Collision(1));
1015        assert_eq!(a.get(&Collision(1)), Some(&10));
1016        assert_eq!(b.get(&Collision(2)), Some(&20));
1017        assert_eq!(c.get(&Collision(1)), None);
1018        assert_eq!(c.get(&Collision(2)), Some(&20));
1019        assert!(empty.shares_root_with(&empty.dissoc_value(&Collision(9))));
1020    }
1021
1022    #[test]
1023    fn assoc_get_overwrite_and_dissoc_basics() {
1024        let mut map = Standard::new();
1025        for i in 0..100u64 {
1026            map = map.assoc_value(i, i * 10);
1027        }
1028        assert_eq!(map.len(), 100);
1029        for i in 0..100u64 {
1030            assert_eq!(map.get(&i), Some(&(i * 10)));
1031        }
1032        // Overwrite keeps size.
1033        let overwritten = map.assoc_value(42, 999);
1034        assert_eq!(overwritten.len(), 100);
1035        assert_eq!(overwritten.get(&42), Some(&999));
1036        assert_eq!(map.get(&42), Some(&420));
1037        // Dissoc down to empty.
1038        for i in 0..100u64 {
1039            map = map.dissoc_value(&i);
1040        }
1041        assert!(map.is_empty());
1042        assert_eq!(map.get(&0), None);
1043    }
1044
1045    #[test]
1046    fn captured_hash_collision_converts_back_to_single_pair() {
1047        // Both keys capture low-32 == 1: identical placement hash, so they
1048        // land in a collision node past shift 32.
1049        let a = Key(1);
1050        let b = Key(0x1_0000_0001);
1051        let map = Standard::new().assoc_value(a, 10).assoc_value(b, 20);
1052        assert_eq!(map.len(), 2);
1053        assert_eq!(map.get(&a), Some(&10));
1054        assert_eq!(map.get(&b), Some(&20));
1055        // Overwrite inside a collision node keeps the size exact.
1056        let overwritten = map.assoc_value(a, 99);
1057        assert_eq!(overwritten.len(), 2);
1058        assert_eq!(overwritten.get(&a), Some(&99));
1059        assert_eq!(map.get(&a), Some(&10));
1060        // Removing one of two converts the node to a single-pair DataNode.
1061        let one = map.dissoc_value(&a);
1062        assert_eq!(one.len(), 1);
1063        assert_eq!(one.get(&a), None);
1064        assert_eq!(one.get(&b), Some(&20));
1065        // The pair still iterates.
1066        let entries: Vec<_> = one.entries().into_iter().map(|(k, v)| (*k, *v)).collect();
1067        assert_eq!(entries, vec![(b, 20)]);
1068    }
1069
1070    /// Churn a map against a `HashMap` model, twice (DefaultHasher fallback
1071    /// keys and probe-captured keys over a small space to force collisions
1072    /// and shared-mask sub-nodes), then require deterministic iteration.
1073    fn churn_build<K: Clone + Eq + Hash + Ord + std::fmt::Debug>(
1074        seed: u64,
1075        mk: impl Fn(u64) -> K,
1076    ) -> (Standard<K, u64>, HashMap<K, u64>) {
1077        let mut rng = Rng(seed);
1078        let mut map = Standard::new();
1079        let mut model = HashMap::new();
1080        for _ in 0..300 {
1081            let key = mk(rng.next() % 24);
1082            if rng.next() % 3 == 0 {
1083                map = map.dissoc_value(&key);
1084                model.remove(&key);
1085            } else {
1086                let value = rng.next();
1087                map = map.assoc_value(key.clone(), value);
1088                model.insert(key, value);
1089            }
1090        }
1091        (map, model)
1092    }
1093
1094    fn churn_case<K: Clone + Eq + Hash + Ord + std::fmt::Debug>(mk: impl Fn(u64) -> K + Copy) {
1095        let (map, model) = churn_build(0x9e37_79b9_7f4a_7c15, mk);
1096        assert_eq!(map.len(), model.len());
1097        for (k, v) in &model {
1098            assert_eq!(map.get(k), Some(v));
1099        }
1100        let mut got: Vec<(K, u64)> = map
1101            .entries()
1102            .into_iter()
1103            .map(|(k, v)| (k.clone(), *v))
1104            .collect();
1105        let mut want: Vec<(K, u64)> = model.iter().map(|(k, v)| (k.clone(), *v)).collect();
1106        got.sort();
1107        want.sort();
1108        assert_eq!(got, want);
1109        // Iteration determinism: an identical build yields identical order.
1110        let (again, _) = churn_build(0x9e37_79b9_7f4a_7c15, mk);
1111        let got_again: Vec<(K, u64)> = again
1112            .entries()
1113            .into_iter()
1114            .map(|(k, v)| (k.clone(), *v))
1115            .collect();
1116        let got_unsorted: Vec<(K, u64)> = map
1117            .entries()
1118            .into_iter()
1119            .map(|(k, v)| (k.clone(), *v))
1120            .collect();
1121        assert_eq!(got_unsorted, got_again);
1122    }
1123
1124    #[test]
1125    fn churn_matches_hashmap_model() {
1126        churn_case(|i| i as i64);
1127        churn_case(Key);
1128    }
1129
1130    #[test]
1131    fn transient_bulk_assoc_matches_persistent_build() {
1132        let mut rng = Rng(42);
1133        let mut mutable = Standard::new().to_mutable();
1134        let mut persistent = Standard::new();
1135        for _ in 0..1000 {
1136            let key = rng.next() % 500;
1137            let value = rng.next();
1138            mutable.assoc(key, value);
1139            persistent = persistent.assoc_value(key, value);
1140        }
1141        let frozen = mutable.to_persistent();
1142        assert_eq!(frozen.len(), persistent.len());
1143        // Content AND iteration order must match the persistent build.
1144        let transient_entries: Vec<_> = frozen
1145            .entries()
1146            .into_iter()
1147            .map(|(k, v)| (*k, *v))
1148            .collect();
1149        let persistent_entries: Vec<_> = persistent
1150            .entries()
1151            .into_iter()
1152            .map(|(k, v)| (*k, *v))
1153            .collect();
1154        assert_eq!(transient_entries, persistent_entries);
1155        // Persistent source remains intact after transient edits.
1156        let mut check = Standard::new();
1157        let mut rng = Rng(42);
1158        let mut expected_len = 0;
1159        let mut seen = HashMap::new();
1160        for _ in 0..1000 {
1161            let key = rng.next() % 500;
1162            let value = rng.next();
1163            if seen.insert(key, value).is_none() {
1164                expected_len += 1;
1165            }
1166            check = check.assoc_value(key, value);
1167        }
1168        assert_eq!(check.len(), expected_len);
1169    }
1170
1171    #[test]
1172    fn transient_assoc_dissoc_cycles_stay_correct() {
1173        let mut m = Standard::new().to_mutable();
1174        for round in 0..50u64 {
1175            for i in 0..20u64 {
1176                m.assoc(round * 20 + i, i);
1177            }
1178            for i in 0..20u64 {
1179                m.dissoc(&(round * 20 + i));
1180            }
1181            assert_eq!(m.len(), 0);
1182        }
1183        for i in 0..100u64 {
1184            m.assoc(i, i * 2);
1185        }
1186        for i in (0..100u64).step_by(2) {
1187            m.dissoc(&i);
1188        }
1189        assert_eq!(m.len(), 50);
1190        let frozen = m.to_persistent();
1191        assert_eq!(frozen.len(), 50);
1192        for i in (1..100u64).step_by(2) {
1193            assert_eq!(frozen.get(&i), Some(&(i * 2)));
1194        }
1195        // The frozen map is persistent: further dissoc does not alias it.
1196        let smaller = frozen.dissoc_value(&1);
1197        assert_eq!(smaller.len(), 49);
1198        assert_eq!(frozen.len(), 50);
1199        assert_eq!(frozen.get(&1), Some(&2));
1200    }
1201
1202    #[test]
1203    fn integer_churn_matches_java_champ_order() {
1204        let mut map = Standard::new();
1205        for i in 0..30i64 {
1206            map = map.assoc_value(Value::Number(i), i);
1207        }
1208        for i in (0..30i64).step_by(3) {
1209            map = map.dissoc_value(&Value::Number(i));
1210        }
1211        let entries: Vec<_> = map
1212            .entries()
1213            .into_iter()
1214            .map(|(k, _)| match k {
1215                Value::Number(value) => *value,
1216                other => panic!("unexpected key: {other:?}"),
1217            })
1218            .collect();
1219        assert_eq!(
1220            entries,
1221            vec![29, 28, 26, 25, 23, 22, 20, 19, 17, 16, 14, 13, 11, 10, 8, 7, 5, 4, 2, 1]
1222        );
1223    }
1224
1225    #[test]
1226    #[should_panic(expected = "mutable map used after to_persistent")]
1227    fn use_after_to_persistent_panics() {
1228        let mut m = Standard::new().to_mutable();
1229        m.assoc(1u64, 1u64);
1230        let _ = m.to_persistent();
1231        m.assoc(2u64, 2u64);
1232    }
1233}