1use std::cell::{Cell, RefCell};
24
25use crate::closure::LuaClosure;
26use crate::error::LuaError;
27use crate::gc::GcRef;
28use crate::string::LuaString;
29use crate::value::LuaValue;
30
31const MAXABITS: u32 = (std::mem::size_of::<i32>() as u32) * 8 - 1;
35
36pub const MAXASIZE: u32 = 1u32 << MAXABITS;
38
39pub const MAXHBITS: u32 = MAXABITS - 1;
41
42const MAXHSIZE: u32 = 1u32 << MAXHBITS;
44
45const DUMMY_TABLE_INIT_HASH_NODES: u32 = 4;
51
52const BIT_RAS: u8 = 1 << 7;
54
55pub const ARRAY_GROW_CAP: u32 = 1u32 << 20;
63
64pub const TOTAL_GROW_CAP: usize = 1usize << 24;
77
78const WEAK_KEYS: u8 = 1 << 0;
79const WEAK_VALUES: u8 = 1 << 1;
80
81#[derive(Clone, Copy, Debug, Default)]
86pub struct TableFlags(pub u8);
87
88impl TableFlags {
89 #[inline]
91 pub fn is_real_asize(self) -> bool {
92 (self.0 & BIT_RAS) == 0
93 }
94
95 #[inline]
97 pub fn set_real_asize(&mut self) {
98 self.0 &= !BIT_RAS;
99 }
100
101 #[inline]
103 pub fn set_no_real_asize(&mut self) {
104 self.0 |= BIT_RAS;
105 }
106
107 #[inline]
109 pub fn invalidate_tm_cache(&mut self) {
110 const MASK_FLAGS: u8 = 0x7F;
111 self.0 &= !MASK_FLAGS;
112 }
113}
114
115pub struct TableNode {
121 pub value: LuaValue,
123 pub key: LuaValue,
125 pub next: i32,
127 pub dead: bool,
136}
137
138impl TableNode {
139 fn empty() -> Self {
140 TableNode {
141 value: LuaValue::Nil,
142 key: LuaValue::Nil,
143 next: 0,
144 dead: false,
145 }
146 }
147
148 fn key_is_nil(&self) -> bool {
149 matches!(self.key, LuaValue::Nil)
150 }
151 fn key_is_int(&self) -> bool {
152 matches!(self.key, LuaValue::Int(_))
153 }
154 fn key_int(&self) -> i64 {
155 if let LuaValue::Int(i) = self.key {
156 i
157 } else {
158 panic!("TableNode::key_int: key is not int")
159 }
160 }
161 fn key_is_short_str(&self) -> bool {
162 if self.dead {
163 return false;
164 }
165 if let LuaValue::Str(s) = &self.key {
166 s.is_short()
167 } else {
168 false
169 }
170 }
171 fn key_string(&self) -> &GcRef<LuaString> {
172 if let LuaValue::Str(s) = &self.key {
173 s
174 } else {
175 panic!("TableNode::key_string: key is not a string")
176 }
177 }
178 fn key_value(&self) -> LuaValue {
179 self.key.clone()
180 }
181 fn set_key(&mut self, k: &LuaValue) {
182 self.key = k.clone();
183 self.dead = false;
184 }
185}
186
187#[inline]
188fn lua_string_content_eq(a: &GcRef<LuaString>, b: &GcRef<LuaString>) -> bool {
189 GcRef::ptr_eq(a, b) || (a.hash() == b.hash() && a.as_bytes() == b.as_bytes())
190}
191
192#[derive(Debug, Clone, Copy)]
199pub enum TableSlotRef {
200 Array(usize),
202 Hash(usize),
204 Absent,
206}
207
208fn ceil_log2(x: u32) -> i32 {
212 static LOG_2: [u8; 256] = [
213 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
214 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
215 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
216 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
217 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
218 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
219 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
220 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
221 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
222 ];
223 let mut l: i32 = 0;
224 let mut x = x.wrapping_sub(1);
225 while x >= 256 {
226 l += 8;
227 x >>= 8;
228 }
229 l + LOG_2[x as usize] as i32
230}
231
232fn hash_float(n: f64) -> i32 {
240 if n.is_nan() || n.is_infinite() {
241 return 0;
242 }
243 let (mantissa, exp) = frexp(n);
244 let scaled = mantissa * -(i32::MIN as f64);
245 let ni = scaled as i64;
246 if ni as f64 != scaled {
247 return 0;
248 }
249 let u = (exp as u32).wrapping_add(ni as u32);
250 if u <= i32::MAX as u32 {
251 u as i32
252 } else {
253 !(u as i32)
254 }
255}
256
257fn frexp(x: f64) -> (f64, i32) {
259 if x == 0.0 || x.is_nan() || x.is_infinite() {
260 return (x, 0);
261 }
262 let bits = x.to_bits();
263 let exp_bits = ((bits >> 52) & 0x7FFu64) as i32;
264 if exp_bits == 0 {
265 let scaled = x * (2.0f64.powi(64));
266 let (m, e) = frexp(scaled);
267 return (m, e - 64);
268 }
269 let exp = exp_bits - 1022;
270 let mantissa_bits = (bits & !(0x7FFu64 << 52)) | (0x3FEu64 << 52);
271 (f64::from_bits(mantissa_bits), exp)
272}
273
274pub struct TableInner {
281 pub flags: TableFlags,
282 pub lsizenode: u8,
283 pub alimit: u32,
284 pub array: Box<[LuaValue]>,
290 pub node: Box<[TableNode]>,
294 pub lastfree: u32,
299}
300
301pub const NO_LASTFREE: u32 = u32::MAX;
303
304#[cfg(target_pointer_width = "64")]
314const _: () = assert!(std::mem::size_of::<TableInner>() == 48);
315
316impl TableInner {
317 fn new() -> Self {
318 TableInner {
319 flags: TableFlags(0x7F),
320 lsizenode: 0,
321 alimit: 0,
322 array: Box::default(),
323 node: Box::default(),
324 lastfree: NO_LASTFREE,
325 }
326 }
327
328 #[inline]
330 fn is_dummy(&self) -> bool {
331 self.lastfree == NO_LASTFREE
332 }
333
334 #[inline]
336 fn sizenode(&self) -> u32 {
337 1u32 << self.lsizenode
338 }
339
340 #[inline]
342 fn alloc_sizenode(&self) -> u32 {
343 if self.is_dummy() {
344 0
345 } else {
346 self.sizenode()
347 }
348 }
349
350 #[inline]
352 fn is_real_asize(&self) -> bool {
353 self.flags.is_real_asize()
354 }
355
356 #[inline]
358 fn is_pow2(x: u32) -> bool {
359 x == 0 || x.is_power_of_two()
360 }
361
362 fn real_asize(&self) -> u32 {
364 if self.limit_equals_asize() {
365 return self.alimit;
366 }
367 let mut size = self.alimit;
368 size |= size >> 1;
369 size |= size >> 2;
370 size |= size >> 4;
371 size |= size >> 8;
372 size |= size >> 16;
373 size = size.wrapping_add(1);
374 debug_assert!(Self::is_pow2(size) && size / 2 < self.alimit && self.alimit < size);
375 size
376 }
377
378 #[inline]
379 fn limit_equals_asize(&self) -> bool {
380 self.is_real_asize() || Self::is_pow2(self.alimit)
381 }
382
383 fn is_pow2_real_asize(&self) -> bool {
384 !self.is_real_asize() || Self::is_pow2(self.alimit)
385 }
386
387 fn set_limit_to_size(&mut self) -> u32 {
388 self.alimit = self.real_asize();
389 self.flags.set_real_asize();
390 self.alimit
391 }
392
393 fn hash_idx_for_int(&self, i: i64) -> usize {
396 let ui = i as u64;
397 let sn = self.sizenode() as usize;
398 let modulo = (sn - 1) | 1;
399 if ui <= i32::MAX as u64 {
400 (ui as usize) % modulo
401 } else {
402 (ui as usize) % modulo
403 }
404 }
405
406 #[inline]
407 fn hashpow2_idx(&self, h: u32) -> usize {
408 (h & (self.sizenode() - 1)) as usize
409 }
410
411 #[inline]
412 fn hashmod_idx(&self, h: usize) -> usize {
413 let sn = self.sizenode() as usize;
414 let modulo = (sn - 1) | 1;
415 h % modulo
416 }
417
418 fn main_position(&self, key: &LuaValue) -> usize {
419 match key {
420 LuaValue::Int(i) => self.hash_idx_for_int(*i),
421 LuaValue::Float(f) => {
422 let h = hash_float(*f);
423 self.hashmod_idx(h as usize)
424 }
425 LuaValue::Str(s) if s.is_short() => self.hashpow2_idx(s.hash()),
426 LuaValue::Str(s) => self.hashpow2_idx(s.hash()),
427 LuaValue::Bool(false) => self.hashpow2_idx(0),
428 LuaValue::Bool(true) => self.hashpow2_idx(1),
429 LuaValue::LightUserData(p) => {
430 let h = (*p as usize as u32) as usize;
431 self.hashmod_idx(h)
432 }
433 LuaValue::Function(LuaClosure::LightC(f)) => {
434 let h = (*f as u32) as usize;
435 self.hashmod_idx(h)
436 }
437 LuaValue::Table(t) => {
438 let h = (GcRef::identity(t) as u32) as usize;
439 self.hashmod_idx(h)
440 }
441 LuaValue::Function(LuaClosure::Lua(cl)) => {
442 let h = (GcRef::identity(cl) as u32) as usize;
443 self.hashmod_idx(h)
444 }
445 LuaValue::Function(LuaClosure::C(cl)) => {
446 let h = (GcRef::identity(cl) as u32) as usize;
447 self.hashmod_idx(h)
448 }
449 LuaValue::UserData(u) => {
450 let h = (GcRef::identity(u) as u32) as usize;
451 self.hashmod_idx(h)
452 }
453 LuaValue::Thread(th) => {
454 let h = (GcRef::identity(th) as u32) as usize;
455 self.hashmod_idx(h)
456 }
457 LuaValue::Nil => 0,
458 }
459 }
460
461 fn main_position_from_node(&self, nd: usize) -> usize {
462 let key = self.node[nd].key_value();
463 self.main_position(&key)
464 }
465
466 fn equal_key(k1: &LuaValue, n2: &TableNode) -> bool {
469 if n2.dead {
470 return false;
471 }
472 let types_match = std::mem::discriminant(k1) == std::mem::discriminant(&n2.key);
473 if !types_match {
474 return false;
475 }
476 match &n2.key {
477 LuaValue::Nil => true,
478 LuaValue::Bool(b) => matches!(k1, LuaValue::Bool(b2) if b == b2),
479 LuaValue::Int(ni) => matches!(k1, LuaValue::Int(ki) if ki == ni),
480 LuaValue::Float(nf) => matches!(k1, LuaValue::Float(kf) if kf == nf),
481 LuaValue::LightUserData(np) => matches!(k1, LuaValue::LightUserData(kp) if kp == np),
482 LuaValue::Function(LuaClosure::LightC(nf)) => {
483 matches!(k1, LuaValue::Function(LuaClosure::LightC(kf)) if kf == nf)
484 }
485 LuaValue::Str(ns) if ns.is_long() => {
486 if let LuaValue::Str(ks) = k1 {
487 lua_string_content_eq(ks, ns)
488 } else {
489 false
490 }
491 }
492 _ => Self::gc_ptr_eq(k1, &n2.key),
493 }
494 }
495
496 fn gc_ptr_eq(a: &LuaValue, b: &LuaValue) -> bool {
497 match (a, b) {
498 (LuaValue::Str(sa), LuaValue::Str(sb)) => GcRef::ptr_eq(sa, sb),
499 (LuaValue::Table(ta), LuaValue::Table(tb)) => GcRef::ptr_eq(ta, tb),
500 (LuaValue::Function(LuaClosure::Lua(fa)), LuaValue::Function(LuaClosure::Lua(fb))) => {
501 GcRef::ptr_eq(fa, fb)
502 }
503 (LuaValue::Function(LuaClosure::C(fa)), LuaValue::Function(LuaClosure::C(fb))) => {
504 GcRef::ptr_eq(fa, fb)
505 }
506 (LuaValue::UserData(ua), LuaValue::UserData(ub)) => GcRef::ptr_eq(ua, ub),
507 (LuaValue::Thread(ta), LuaValue::Thread(tb)) => GcRef::ptr_eq(ta, tb),
508 _ => false,
509 }
510 }
511
512 fn get_generic_slot(&self, key: &LuaValue) -> TableSlotRef {
515 if self.is_dummy() {
516 return TableSlotRef::Absent;
517 }
518 let mut n = self.main_position(key);
519 loop {
520 if Self::equal_key(key, &self.node[n]) {
521 return TableSlotRef::Hash(n);
522 }
523 let nx = self.node[n].next;
524 if nx == 0 {
525 return TableSlotRef::Absent;
526 }
527 n = (n as isize + nx as isize) as usize;
528 }
529 }
530
531 fn get_generic_slot_deadok(&self, key: &LuaValue) -> TableSlotRef {
538 if self.is_dummy() {
539 return TableSlotRef::Absent;
540 }
541 let mut n = self.main_position(key);
542 loop {
543 let node = &self.node[n];
544 let matched = if node.dead {
545 match (gc_identity_bits(key), gc_identity_bits(&node.key)) {
546 (Some(a), Some(b)) => a == b,
547 _ => false,
548 }
549 } else {
550 Self::equal_key(key, node)
551 };
552 if matched {
553 return TableSlotRef::Hash(n);
554 }
555 let nx = node.next;
556 if nx == 0 {
557 return TableSlotRef::Absent;
558 }
559 n = (n as isize + nx as isize) as usize;
560 }
561 }
562
563 fn array_index(k: i64) -> u32 {
566 let uk = k as u64;
567 if uk.wrapping_sub(1) < MAXASIZE as u64 {
568 k as u32
569 } else {
570 0
571 }
572 }
573
574 fn find_index(&self, key: &LuaValue, asize: u32) -> Result<u32, LuaError> {
578 if matches!(key, LuaValue::Nil) {
579 return Ok(0);
580 }
581 let i = if let LuaValue::Int(k) = key {
582 Self::array_index(*k)
583 } else {
584 0
585 };
586 if i.wrapping_sub(1) < asize {
587 return Ok(i);
588 }
589 let slot = self.get_generic_slot_deadok(key);
590 match slot {
591 TableSlotRef::Absent => Err(LuaError::runtime(format_args!("invalid key to 'next'"))),
592 TableSlotRef::Hash(node_idx) => Ok((node_idx as u32 + 1) + asize),
593 TableSlotRef::Array(_) => unreachable!("getgeneric returned Array slot"),
594 }
595 }
596
597 fn next_pair(&self, key: &LuaValue) -> Result<Option<(LuaValue, LuaValue)>, LuaError> {
600 let asize = self.real_asize();
601 let i = self.find_index(key, asize)?;
602 let mut i = i as usize;
603 while i < asize as usize {
604 if !matches!(self.array[i], LuaValue::Nil) {
605 return Ok(Some((LuaValue::Int((i + 1) as i64), self.array[i].clone())));
606 }
607 i += 1;
608 }
609 let mut hi = i.saturating_sub(asize as usize);
610 while hi < self.node.len() {
611 if !matches!(self.node[hi].value, LuaValue::Nil) {
612 return Ok(Some((
613 self.node[hi].key_value(),
614 self.node[hi].value.clone(),
615 )));
616 }
617 hi += 1;
618 }
619 Ok(None)
620 }
621
622 fn compute_sizes(nums: &[u32], pna: &mut u32) -> u32 {
625 let mut twotoi: u32 = 1;
626 let mut a: u32 = 0;
627 let mut na: u32 = 0;
628 let mut optimal: u32 = 0;
629 for i in 0..nums.len() {
630 if twotoi == 0 || *pna <= twotoi / 2 {
631 break;
632 }
633 a += nums[i];
634 if a > twotoi / 2 {
635 optimal = twotoi;
636 na = a;
637 }
638 twotoi = twotoi.wrapping_mul(2);
639 }
640 debug_assert!(optimal == 0 || optimal / 2 < na && na <= optimal);
641 *pna = na;
642 optimal
643 }
644
645 fn count_int(key: i64, nums: &mut [u32]) -> bool {
646 let k = Self::array_index(key);
647 if k != 0 {
648 nums[ceil_log2(k) as usize] += 1;
649 true
650 } else {
651 false
652 }
653 }
654
655 fn num_use_array(&self, nums: &mut [u32]) -> u32 {
656 debug_assert!(
657 self.is_real_asize(),
658 "numusearray: alimit must be real size"
659 );
660 let asize = self.alimit as usize;
661 let mut ause: u32 = 0;
662 let mut i: usize = 1;
663 let mut ttlg: usize = 1;
664 for lg in 0..=(MAXABITS as usize) {
665 let mut lc: u32 = 0;
666 let lim = if ttlg > asize { asize } else { ttlg };
667 if i > lim {
668 break;
669 }
670 while i <= lim {
671 if !matches!(self.array[i - 1], LuaValue::Nil) {
672 lc += 1;
673 }
674 i += 1;
675 }
676 nums[lg] += lc;
677 ause += lc;
678 ttlg = ttlg.saturating_mul(2);
679 }
680 ause
681 }
682
683 fn num_use_hash(&self, nums: &mut [u32], pna: &mut u32) -> i32 {
684 let mut totaluse: i32 = 0;
685 let mut ause: u32 = 0;
686 let mut i = self.node.len();
687 while i > 0 {
688 i -= 1;
689 let n = &self.node[i];
690 if !matches!(n.value, LuaValue::Nil) {
691 if n.key_is_int() {
692 if Self::count_int(n.key_int(), nums) {
693 ause += 1;
694 }
695 }
696 totaluse += 1;
697 }
698 }
699 *pna += ause;
700 totaluse
701 }
702
703 fn set_array_size(&mut self, new_size: usize) {
715 let old = std::mem::take(&mut self.array);
716 let keep = old.len().min(new_size);
717 let mut survivors = old.into_vec();
718 survivors.truncate(keep);
719 survivors.reserve_exact(new_size - keep);
720 survivors.resize_with(new_size, || LuaValue::Nil);
721 self.array = survivors.into_boxed_slice();
722 }
723
724 fn set_node_vector(&mut self, size: u32) -> Result<(), LuaError> {
725 if size == 0 {
726 self.node = Box::default();
727 self.lsizenode = 0;
728 self.lastfree = NO_LASTFREE;
729 } else {
730 let lsize = ceil_log2(size);
731 if lsize as u32 > MAXHBITS || (1u32 << lsize) > MAXHSIZE {
732 return Err(LuaError::runtime(format_args!("table overflow")));
733 }
734 let actual_size = 1u32 << lsize;
735 let nodes: Vec<TableNode> = (0..actual_size).map(|_| TableNode::empty()).collect();
736 self.node = nodes.into_boxed_slice();
737 self.lsizenode = lsize as u8;
738 self.lastfree = actual_size;
739 }
740 Ok(())
741 }
742
743 fn reinsert(&mut self, old_nodes: Vec<(LuaValue, LuaValue)>) -> Result<(), LuaError> {
744 for (k, v) in old_nodes {
745 self.set(&k, v)?;
746 }
747 Ok(())
748 }
749
750 fn resize(&mut self, new_asize: u32, nhsize: u32) -> Result<(), LuaError> {
752 let old_asize = self.set_limit_to_size();
753
754 let (mut new_hash_node, mut new_hash_lsize, mut new_hash_lastfree) = {
755 let mut tmp = TableInner::new();
756 tmp.set_node_vector(nhsize)?;
757 (tmp.node, tmp.lsizenode, tmp.lastfree)
758 };
759
760 if new_asize < old_asize {
761 let migrate_end = (old_asize as usize).min(self.array.len());
762 let detached: Vec<(i64, LuaValue)> = ((new_asize as usize)..migrate_end)
763 .filter(|&i| !matches!(self.array[i], LuaValue::Nil))
764 .map(|i| ((i + 1) as i64, self.array[i].clone()))
765 .collect();
766 self.set_array_size(new_asize as usize);
767 self.alimit = new_asize;
768
769 std::mem::swap(&mut self.node, &mut new_hash_node);
770 std::mem::swap(&mut self.lsizenode, &mut new_hash_lsize);
771 std::mem::swap(&mut self.lastfree, &mut new_hash_lastfree);
772
773 for (key, v) in detached {
774 self.set_int(key, v)?;
775 }
776
777 self.alimit = old_asize;
778 std::mem::swap(&mut self.node, &mut new_hash_node);
779 std::mem::swap(&mut self.lsizenode, &mut new_hash_lsize);
780 std::mem::swap(&mut self.lastfree, &mut new_hash_lastfree);
781 }
782
783 self.set_array_size(new_asize as usize);
784
785 std::mem::swap(&mut self.node, &mut new_hash_node);
786 std::mem::swap(&mut self.lsizenode, &mut new_hash_lsize);
787 std::mem::swap(&mut self.lastfree, &mut new_hash_lastfree);
788 self.alimit = new_asize;
789
790 let old_hash_entries: Vec<(LuaValue, LuaValue)> = new_hash_node
791 .iter()
792 .filter(|n| !matches!(n.value, LuaValue::Nil))
793 .map(|n| (n.key_value(), n.value.clone()))
794 .collect();
795 drop(new_hash_node);
796 self.reinsert(old_hash_entries)?;
797
798 Ok(())
799 }
800
801 fn rehash(&mut self, extra_key: &LuaValue) -> Result<(), LuaError> {
802 let mut nums = [0u32; MAXABITS as usize + 1];
803 self.set_limit_to_size();
804
805 let na = self.num_use_array(&mut nums);
806 let mut na = na;
807 let mut totaluse = na as i32;
808
809 totaluse += self.num_use_hash(&mut nums, &mut na);
810
811 if let LuaValue::Int(ek) = extra_key {
812 if Self::count_int(*ek, &mut nums) {
813 na += 1;
814 }
815 }
816 totaluse += 1;
817
818 let asize = Self::compute_sizes(&nums, &mut na);
819
820 let nh = (totaluse - na as i32).max(0) as u32;
821 self.resize(asize, nh)
822 }
823
824 fn get_free_pos(&mut self) -> Option<usize> {
825 if self.is_dummy() {
826 return None;
827 }
828 loop {
829 if self.lastfree == NO_LASTFREE {
830 return None;
831 }
832 if self.lastfree == 0 {
833 self.lastfree = NO_LASTFREE;
834 return None;
835 }
836 let idx = (self.lastfree - 1) as usize;
837 self.lastfree = idx as u32;
838 if self.node[idx].key_is_nil() {
839 return Some(idx);
840 }
841 }
842 }
843
844 fn find_chain_predecessor(&self, idx: usize) -> Option<usize> {
845 self.node
846 .iter()
847 .enumerate()
848 .find(|(prev, node)| {
849 node.next != 0 && (*prev as isize + node.next as isize) == idx as isize
850 })
851 .map(|(prev, _)| prev)
852 }
853
854 fn clear_node(&mut self, idx: usize) {
855 self.node[idx].key = LuaValue::Nil;
856 self.node[idx].value = LuaValue::Nil;
857 self.node[idx].next = 0;
858 }
859
860 fn remove_hash_node(&mut self, idx: usize) {
861 if let Some(prev) = self.find_chain_predecessor(idx) {
862 let next = self.node[idx].next;
863 self.node[prev].next = if next == 0 {
864 0
865 } else {
866 let target = idx as isize + next as isize;
867 (target - prev as isize) as i32
868 };
869 self.clear_node(idx);
870 return;
871 }
872
873 let next = self.node[idx].next;
874 if next == 0 {
875 self.clear_node(idx);
876 return;
877 }
878
879 let next_idx = (idx as isize + next as isize) as usize;
880 let moved_next = self.node[next_idx].next;
881 let moved_key = self.node[next_idx].key_value();
882 let moved_value = self.node[next_idx].value.clone();
883 self.node[idx].key = moved_key;
884 self.node[idx].value = moved_value;
885 self.node[idx].next = if moved_next == 0 {
886 0
887 } else {
888 let target = next_idx as isize + moved_next as isize;
889 (target - idx as isize) as i32
890 };
891 self.clear_node(next_idx);
892 }
893
894 fn clear_dead_hash_node(&mut self, idx: usize) {
895 self.remove_hash_node(idx);
896 }
897
898 fn new_key(&mut self, key: &LuaValue, value: LuaValue) -> Result<(), LuaError> {
899 if matches!(key, LuaValue::Nil) {
900 return Err(LuaError::runtime(format_args!("table index is nil")));
901 }
902 let normalised_key;
903 let key = if let LuaValue::Float(f) = key {
904 let f = *f;
905 if f.is_nan() {
906 return Err(LuaError::runtime(format_args!("table index is NaN")));
907 }
908 let k = f as i64;
909 if k as f64 == f {
910 normalised_key = LuaValue::Int(k);
911 &normalised_key
912 } else {
913 key
914 }
915 } else {
916 key
917 };
918
919 if matches!(value, LuaValue::Nil) {
920 return Ok(());
921 }
922
923 if self.is_dummy() && !matches!(key, LuaValue::Int(_)) {
924 self.set_node_vector(DUMMY_TABLE_INIT_HASH_NODES)?;
925 let mp = self.main_position(key);
926 self.node[mp].set_key(key);
927 self.node[mp].value = value;
928 return Ok(());
929 }
930
931 let mp = self.main_position(key);
932 let mp_occupied = self.is_dummy() || !matches!(self.node[mp].value, LuaValue::Nil);
933 if mp_occupied {
934 let f = self.get_free_pos();
935 let f = match f {
936 None => {
937 self.rehash(key)?;
938 return self.set(key, value);
939 }
940 Some(idx) => idx,
941 };
942
943 debug_assert!(!self.is_dummy());
944 let othern = self.main_position_from_node(mp);
945
946 if othern != mp {
947 let mut prev = othern;
948 let mut steps = 0usize;
949 while (prev as isize + self.node[prev].next as isize) as usize != mp {
950 steps += 1;
951 if steps > self.node.len() {
952 panic!(
953 "table hash chain invariant broken: node {} unreachable from main position {} \
954 ({} nodes; usually a missing GC key barrier — see ltable.c:717 parity note)",
955 mp,
956 othern,
957 self.node.len()
958 );
959 }
960 prev = (prev as isize + self.node[prev].next as isize) as usize;
961 }
962 self.node[prev].next = (f as isize - prev as isize) as i32;
963 let mp_key = self.node[mp].key_value();
964 let mp_val = self.node[mp].value.clone();
965 let mp_next = self.node[mp].next;
966 self.node[f].key = mp_key;
967 self.node[f].value = mp_val;
968 if mp_next != 0 {
969 self.node[f].next = mp_next + (mp as isize - f as isize) as i32;
970 self.node[mp].next = 0;
971 } else {
972 self.node[f].next = 0;
973 }
974 self.node[mp].value = LuaValue::Nil;
975 } else {
976 if self.node[mp].next != 0 {
977 let target = (mp as isize + self.node[mp].next as isize) as usize;
978 self.node[f].next = (target as isize - f as isize) as i32;
979 } else {
980 debug_assert!(self.node[f].next == 0);
981 }
982 self.node[mp].next = (f as isize - mp as isize) as i32;
983 self.node[f].set_key(key);
984 debug_assert!(matches!(self.node[f].value, LuaValue::Nil));
985 self.node[f].value = value;
986 return Ok(());
987 }
988 }
989 self.node[mp].set_key(key);
990 debug_assert!(matches!(self.node[mp].value, LuaValue::Nil));
991 self.node[mp].value = value;
992 Ok(())
993 }
994
995 fn get_int_slot(&self, key: i64) -> TableSlotRef {
996 let alimit = self.alimit as u64;
997 let uk = key as u64;
998 if uk.wrapping_sub(1) < alimit {
999 return TableSlotRef::Array((key - 1) as usize);
1000 }
1001 if !self.is_real_asize() && alimit > 0 {
1002 let masked = (uk.wrapping_sub(1)) & !(alimit.wrapping_sub(1));
1003 if masked < alimit {
1004 return TableSlotRef::Array((key - 1) as usize);
1005 }
1006 }
1007 if self.is_dummy() {
1008 return TableSlotRef::Absent;
1009 }
1010 let mut n = self.hash_idx_for_int(key);
1011 loop {
1012 if self.node[n].key_is_int() && self.node[n].key_int() == key {
1013 return TableSlotRef::Hash(n);
1014 }
1015 let nx = self.node[n].next;
1016 if nx == 0 {
1017 break;
1018 }
1019 n = (n as isize + nx as isize) as usize;
1020 }
1021 TableSlotRef::Absent
1022 }
1023
1024 #[inline]
1031 fn get_int_value(&self, key: i64) -> LuaValue {
1032 let alimit = self.alimit as u64;
1033 let uk = key as u64;
1034 if uk.wrapping_sub(1) < alimit {
1035 return self.array[(key - 1) as usize].clone();
1036 }
1037 self.get_int_value_cold(key)
1038 }
1039
1040 #[cold]
1041 #[inline(never)]
1042 fn get_int_value_cold(&self, key: i64) -> LuaValue {
1043 let alimit = self.alimit as u64;
1044 let uk = key as u64;
1045 if !self.is_real_asize() && alimit > 0 {
1046 let masked = (uk.wrapping_sub(1)) & !(alimit.wrapping_sub(1));
1047 if masked < alimit {
1048 return self.array[(key - 1) as usize].clone();
1049 }
1050 }
1051 if self.is_dummy() {
1052 return LuaValue::Nil;
1053 }
1054 let mut n = self.hash_idx_for_int(key);
1055 loop {
1056 if self.node[n].key_is_int() && self.node[n].key_int() == key {
1057 return self.node[n].value.clone();
1058 }
1059 let nx = self.node[n].next;
1060 if nx == 0 {
1061 break;
1062 }
1063 n = (n as isize + nx as isize) as usize;
1064 }
1065 LuaValue::Nil
1066 }
1067
1068 #[inline(always)]
1069 fn get_short_str_slot(&self, key: &GcRef<LuaString>) -> TableSlotRef {
1070 debug_assert!(key.is_short());
1071 if self.is_dummy() {
1072 return TableSlotRef::Absent;
1073 }
1074 let mut n = self.hashpow2_idx(key.hash());
1075 loop {
1076 if self.node[n].key_is_short_str() {
1077 let ks = self.node[n].key_string();
1078 if lua_string_content_eq(ks, key) {
1079 return TableSlotRef::Hash(n);
1080 }
1081 }
1082 let nx = self.node[n].next;
1083 if nx == 0 {
1084 return TableSlotRef::Absent;
1085 }
1086 n = (n as isize + nx as isize) as usize;
1087 }
1088 }
1089
1090 #[inline(always)]
1091 fn try_update_short_str(
1092 &mut self,
1093 key: &GcRef<LuaString>,
1094 value: LuaValue,
1095 ) -> Result<(), LuaValue> {
1096 debug_assert!(key.is_short());
1097 if self.is_dummy() {
1098 return Err(value);
1099 }
1100 let mut n = self.hashpow2_idx(key.hash());
1101 loop {
1102 if self.node[n].key_is_short_str() {
1103 let ks = self.node[n].key_string();
1104 if lua_string_content_eq(ks, key) {
1105 self.node[n].value = value;
1106 return Ok(());
1107 }
1108 }
1109 let nx = self.node[n].next;
1110 if nx == 0 {
1111 return Err(value);
1112 }
1113 n = (n as isize + nx as isize) as usize;
1114 }
1115 }
1116
1117 #[inline(always)]
1118 fn try_update_int(&mut self, key: i64, value: LuaValue) -> Result<(), LuaValue> {
1119 let alimit = self.alimit as u64;
1120 let uk = key as u64;
1121 if uk.wrapping_sub(1) < alimit {
1122 self.array[(key - 1) as usize] = value;
1123 return Ok(());
1124 }
1125 if !self.is_real_asize() && alimit > 0 {
1126 let masked = (uk.wrapping_sub(1)) & !(alimit.wrapping_sub(1));
1127 if masked < alimit {
1128 self.array[(key - 1) as usize] = value;
1129 return Ok(());
1130 }
1131 }
1132 if !self.is_dummy() {
1133 let mut n = self.hash_idx_for_int(key);
1134 loop {
1135 if self.node[n].key_is_int() && self.node[n].key_int() == key {
1136 self.node[n].value = value;
1137 return Ok(());
1138 }
1139 let nx = self.node[n].next;
1140 if nx == 0 {
1141 break;
1142 }
1143 n = (n as isize + nx as isize) as usize;
1144 }
1145 }
1146 Err(value)
1147 }
1148
1149 #[inline]
1157 fn get_str_value(&self, key: &GcRef<LuaString>) -> LuaValue {
1158 debug_assert!(key.is_short());
1159 if self.is_dummy() {
1160 return LuaValue::Nil;
1161 }
1162 let mut n = self.hashpow2_idx(key.hash());
1163 loop {
1164 if self.node[n].key_is_short_str() {
1165 let ks = self.node[n].key_string();
1166 if lua_string_content_eq(ks, key) {
1167 return self.node[n].value.clone();
1168 }
1169 }
1170 let nx = self.node[n].next;
1171 if nx == 0 {
1172 return LuaValue::Nil;
1173 }
1174 n = (n as isize + nx as isize) as usize;
1175 }
1176 }
1177
1178 #[cold]
1183 #[inline(never)]
1184 fn get_generic_value(&self, key: &LuaValue) -> LuaValue {
1185 let slot = self.get_slot(key);
1186 self.slot_value(slot)
1187 }
1188
1189 fn get_str_slot(&self, key: &GcRef<LuaString>) -> TableSlotRef {
1190 if key.is_short() {
1191 self.get_short_str_slot(key)
1192 } else {
1193 let ko = LuaValue::Str(key.clone());
1194 self.get_generic_slot(&ko)
1195 }
1196 }
1197
1198 fn get_slot(&self, key: &LuaValue) -> TableSlotRef {
1199 match key {
1200 LuaValue::Str(s) if s.is_short() => self.get_short_str_slot(s),
1201 LuaValue::Int(i) => self.get_int_slot(*i),
1202 LuaValue::Nil => TableSlotRef::Absent,
1203 LuaValue::Float(f) => {
1204 let f = *f;
1205 let k = f as i64;
1206 if k as f64 == f {
1207 self.get_int_slot(k)
1208 } else {
1209 self.get_generic_slot(key)
1210 }
1211 }
1212 _ => self.get_generic_slot(key),
1213 }
1214 }
1215
1216 fn slot_value(&self, slot: TableSlotRef) -> LuaValue {
1217 match slot {
1218 TableSlotRef::Array(i) => self.array[i].clone(),
1219 TableSlotRef::Hash(i) => self.node[i].value.clone(),
1220 TableSlotRef::Absent => LuaValue::Nil,
1221 }
1222 }
1223
1224 fn finish_set(
1225 &mut self,
1226 key: &LuaValue,
1227 slot: TableSlotRef,
1228 value: LuaValue,
1229 ) -> Result<(), LuaError> {
1230 match slot {
1231 TableSlotRef::Absent => self.new_key(key, value),
1232 TableSlotRef::Array(i) => {
1233 self.array[i] = value;
1234 Ok(())
1235 }
1236 TableSlotRef::Hash(i) => {
1237 self.node[i].value = value;
1238 Ok(())
1239 }
1240 }
1241 }
1242
1243 fn set(&mut self, key: &LuaValue, value: LuaValue) -> Result<(), LuaError> {
1244 let slot = self.get_slot(key);
1245 self.finish_set(key, slot, value)
1246 }
1247
1248 fn set_int(&mut self, key: i64, value: LuaValue) -> Result<(), LuaError> {
1252 let slot = self.get_int_slot(key);
1253 if matches!(slot, TableSlotRef::Absent) {
1254 if key > 0 && (key as u64) <= ARRAY_GROW_CAP as u64 {
1255 let cur = self.alimit as i64;
1256 if key == cur + 1 && !matches!(value, LuaValue::Nil) {
1257 let new_size = (key as u32).next_power_of_two().max(4);
1258 let capped = new_size.min(ARRAY_GROW_CAP);
1259 if capped > self.alimit {
1260 let nsize = self.alloc_sizenode();
1261 self.resize(capped, nsize)?;
1262 let new_slot = self.get_int_slot(key);
1263 return self.finish_set(&LuaValue::Int(key), new_slot, value);
1264 }
1265 }
1266 }
1267 }
1268 match slot {
1269 TableSlotRef::Absent => {
1270 let k = LuaValue::Int(key);
1271 self.new_key(&k, value)
1272 }
1273 TableSlotRef::Array(i) => {
1274 self.array[i] = value;
1275 Ok(())
1276 }
1277 TableSlotRef::Hash(i) => {
1278 self.node[i].value = value;
1279 Ok(())
1280 }
1281 }
1282 }
1283
1284 #[inline]
1291 fn try_raw_set_int_fast(&mut self, key: i64, value: LuaValue) -> Result<(), LuaError> {
1292 let alimit = self.alimit as u64;
1293 let uk = key as u64;
1294 if uk.wrapping_sub(1) < alimit {
1295 self.array[(key - 1) as usize] = value;
1296 return Ok(());
1297 }
1298 self.try_raw_set_int_cold(key, value)
1299 }
1300
1301 #[cold]
1302 #[inline(never)]
1303 fn try_raw_set_int_cold(&mut self, key: i64, value: LuaValue) -> Result<(), LuaError> {
1304 if self.array.len() + self.node.len() >= TOTAL_GROW_CAP
1305 && matches!(self.get_int_slot(key), TableSlotRef::Absent)
1306 {
1307 return Err(LuaError::Memory);
1308 }
1309 self.set_int_value_cold(key, value)
1310 }
1311
1312 #[cold]
1319 #[inline(never)]
1320 fn set_int_value_cold(&mut self, key: i64, value: LuaValue) -> Result<(), LuaError> {
1321 let alimit = self.alimit as u64;
1322 let uk = key as u64;
1323 if !self.is_real_asize() && alimit > 0 {
1324 let masked = (uk.wrapping_sub(1)) & !(alimit.wrapping_sub(1));
1325 if masked < alimit {
1326 self.array[(key - 1) as usize] = value;
1327 return Ok(());
1328 }
1329 }
1330 if !self.is_dummy() {
1331 let mut n = self.hash_idx_for_int(key);
1332 loop {
1333 if self.node[n].key_is_int() && self.node[n].key_int() == key {
1334 self.node[n].value = value;
1335 return Ok(());
1336 }
1337 let nx = self.node[n].next;
1338 if nx == 0 {
1339 break;
1340 }
1341 n = (n as isize + nx as isize) as usize;
1342 }
1343 }
1344 if key > 0 && (key as u64) <= ARRAY_GROW_CAP as u64 {
1345 let cur = self.alimit as i64;
1346 if key == cur + 1 && !matches!(value, LuaValue::Nil) {
1347 let new_size = (key as u32).next_power_of_two().max(4);
1348 let capped = new_size.min(ARRAY_GROW_CAP);
1349 if capped > self.alimit {
1350 let nsize = self.alloc_sizenode();
1351 self.resize(capped, nsize)?;
1352 let new_slot = self.get_int_slot(key);
1353 return self.finish_set(&LuaValue::Int(key), new_slot, value);
1354 }
1355 }
1356 }
1357 let k = LuaValue::Int(key);
1358 self.new_key(&k, value)
1359 }
1360
1361 fn hash_search(&self, mut j: u64) -> u64 {
1364 let mut i: u64;
1365 if j == 0 {
1366 j = 1;
1367 }
1368 loop {
1369 i = j;
1370 if j <= (i64::MAX as u64) / 2 {
1371 j *= 2;
1372 } else {
1373 j = i64::MAX as u64;
1374 let s = self.get_int_slot(j as i64);
1375 if matches!(s, TableSlotRef::Absent) || matches!(self.slot_value(s), LuaValue::Nil)
1376 {
1377 break;
1378 } else {
1379 return j;
1380 }
1381 }
1382 let s = self.get_int_slot(j as i64);
1383 if matches!(s, TableSlotRef::Absent) {
1384 break;
1385 }
1386 if matches!(self.slot_value(s), LuaValue::Nil) {
1387 break;
1388 }
1389 }
1390 while j - i > 1 {
1391 let m = i / 2 + j / 2;
1392 let s = self.get_int_slot(m as i64);
1393 let empty =
1394 matches!(s, TableSlotRef::Absent) || matches!(self.slot_value(s), LuaValue::Nil);
1395 if empty {
1396 j = m;
1397 } else {
1398 i = m;
1399 }
1400 }
1401 i
1402 }
1403
1404 fn bin_search(array: &[LuaValue], mut i: u32, mut j: u32) -> u32 {
1405 while j - i > 1 {
1406 let m = (i + j) / 2;
1407 if matches!(array[(m - 1) as usize], LuaValue::Nil) {
1408 j = m;
1409 } else {
1410 i = m;
1411 }
1412 }
1413 i
1414 }
1415
1416 fn getn(&mut self) -> u64 {
1419 let limit = self.alimit;
1420 if limit > 0 && matches!(self.array[(limit - 1) as usize], LuaValue::Nil) {
1421 if limit >= 2 && !matches!(self.array[(limit - 2) as usize], LuaValue::Nil) {
1422 if self.is_pow2_real_asize() && !Self::is_pow2(limit - 1) {
1423 self.alimit = limit - 1;
1424 self.flags.set_no_real_asize();
1425 }
1426 return (limit - 1) as u64;
1427 } else {
1428 let boundary = Self::bin_search(&self.array, 0, limit);
1429 if self.is_pow2_real_asize() && boundary > self.real_asize() / 2 {
1430 self.alimit = boundary;
1431 self.flags.set_no_real_asize();
1432 }
1433 return boundary as u64;
1434 }
1435 }
1436 if !self.limit_equals_asize() {
1437 if matches!(self.array[limit as usize], LuaValue::Nil) {
1438 return limit as u64;
1439 }
1440 let real = self.real_asize();
1441 if matches!(self.array[(real - 1) as usize], LuaValue::Nil) {
1442 let old_alimit = self.alimit;
1443 let boundary = Self::bin_search(&self.array, old_alimit, real);
1444 self.alimit = boundary;
1445 return boundary as u64;
1446 }
1447 }
1448 let limit = self.real_asize();
1449 debug_assert!(
1450 limit == self.real_asize()
1451 && (limit == 0 || !matches!(self.array[(limit - 1) as usize], LuaValue::Nil))
1452 );
1453 let next_key = (limit as i64).saturating_add(1);
1454 let next_slot = self.get_int_slot(next_key);
1455 let next_empty = matches!(next_slot, TableSlotRef::Absent)
1456 || matches!(self.slot_value(next_slot), LuaValue::Nil);
1457 if self.is_dummy() || next_empty {
1458 return limit as u64;
1459 }
1460 self.hash_search(limit as u64)
1461 }
1462}
1463
1464#[derive(Debug)]
1472pub struct LuaTable {
1473 inner: RefCell<TableInner>,
1474 metatable: Cell<Option<GcRef<LuaTable>>>,
1478 weak_mode: Cell<u8>,
1479}
1480
1481impl std::fmt::Debug for TableInner {
1482 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1483 f.debug_struct("TableInner")
1484 .field("alimit", &self.alimit)
1485 .field("array_len", &self.array.len())
1486 .field("node_len", &self.node.len())
1487 .finish()
1488 }
1489}
1490
1491impl Default for LuaTable {
1492 fn default() -> Self {
1493 LuaTable {
1494 inner: RefCell::new(TableInner::new()),
1495 metatable: Cell::new(None),
1496 weak_mode: Cell::new(0),
1497 }
1498 }
1499}
1500
1501impl LuaTable {
1502 pub fn placeholder() -> Self {
1505 Self::default()
1506 }
1507
1508 pub fn with_inner<R>(&self, f: impl FnOnce(&TableInner) -> R) -> R {
1511 f(&self.inner.borrow())
1512 }
1513
1514 pub fn buffer_bytes(&self) -> usize {
1521 let inner = self.inner.borrow();
1522 inner.array.len() * std::mem::size_of::<LuaValue>()
1523 + inner.node.len() * std::mem::size_of::<TableNode>()
1524 }
1525
1526 #[inline(always)]
1536 pub fn get(&self, k: &LuaValue) -> LuaValue {
1537 let inner = self.inner.borrow();
1538 match k {
1539 LuaValue::Nil => LuaValue::Nil,
1540 LuaValue::Int(i) => inner.get_int_value(*i),
1541 LuaValue::Str(s) if s.is_short() => inner.get_str_value(s),
1542 _ => inner.get_generic_value(k),
1543 }
1544 }
1545
1546 #[inline(always)]
1552 pub fn get_int(&self, key: i64) -> LuaValue {
1553 let inner = self.inner.borrow();
1554 inner.get_int_value(key)
1555 }
1556
1557 #[inline(always)]
1565 pub fn get_short_str(&self, k: &GcRef<LuaString>) -> LuaValue {
1566 let inner = self.inner.borrow();
1567 if k.is_short() {
1568 inner.get_str_value(k)
1569 } else {
1570 let slot = inner.get_str_slot(k);
1571 inner.slot_value(slot)
1572 }
1573 }
1574
1575 pub fn get_str_bytes(&self, key_bytes: &[u8]) -> LuaValue {
1579 let mut found = LuaValue::Nil;
1580 self.for_each_entry(|k, v| {
1581 if !matches!(found, LuaValue::Nil) {
1582 return;
1583 }
1584 if let LuaValue::Str(s) = k {
1585 if s.as_bytes() == key_bytes {
1586 found = v.clone();
1587 }
1588 }
1589 });
1590 found
1591 }
1592
1593 pub fn raw_set(&self, k: LuaValue, v: LuaValue) {
1596 if matches!(k, LuaValue::Nil) {
1597 return;
1598 }
1599 if let LuaValue::Float(f) = &k {
1600 if f.is_nan() {
1601 return;
1602 }
1603 }
1604 let mut inner = self.inner.borrow_mut();
1605 let _ = inner.set(&k, v);
1606 }
1607
1608 #[inline]
1614 pub fn try_raw_set(&self, k: LuaValue, v: LuaValue) -> Result<(), LuaError> {
1615 match &k {
1616 LuaValue::Nil => Err(LuaError::runtime(format_args!("table index is nil"))),
1617 LuaValue::Float(f) if f.is_nan() => {
1618 Err(LuaError::runtime(format_args!("table index is NaN")))
1619 }
1620 LuaValue::Int(i) => {
1621 let key = *i;
1622 let mut inner = self.inner.borrow_mut();
1623 inner.try_raw_set_int_fast(key, v)
1624 }
1625 LuaValue::Float(f) => {
1626 let f = *f;
1627 let k_int = f as i64;
1628 if k_int as f64 == f {
1629 let mut inner = self.inner.borrow_mut();
1630 inner.try_raw_set_int_fast(k_int, v)
1631 } else {
1632 self.try_raw_set_generic(k, v)
1633 }
1634 }
1635 _ => self.try_raw_set_generic(k, v),
1636 }
1637 }
1638
1639 #[inline(always)]
1643 pub fn try_update_short_str(&self, k: &GcRef<LuaString>, v: LuaValue) -> Result<(), LuaValue> {
1644 if !k.is_short() {
1645 return Err(v);
1646 }
1647 let mut inner = self.inner.borrow_mut();
1648 inner.try_update_short_str(k, v)
1649 }
1650
1651 #[inline(always)]
1655 pub fn try_update_int(&self, k: i64, v: LuaValue) -> Result<(), LuaValue> {
1656 let mut inner = self.inner.borrow_mut();
1657 inner.try_update_int(k, v)
1658 }
1659
1660 #[cold]
1663 #[inline(never)]
1664 fn try_raw_set_generic(&self, k: LuaValue, v: LuaValue) -> Result<(), LuaError> {
1665 let mut inner = self.inner.borrow_mut();
1666 if inner.array.len() + inner.node.len() >= TOTAL_GROW_CAP
1667 && matches!(inner.get_slot(&k), TableSlotRef::Absent)
1668 {
1669 return Err(LuaError::Memory);
1670 }
1671 inner.set(&k, v)
1672 }
1673
1674 #[inline]
1681 pub fn try_raw_set_int(&self, k: i64, v: LuaValue) -> Result<(), LuaError> {
1682 let mut inner = self.inner.borrow_mut();
1683 inner.try_raw_set_int_fast(k, v)
1684 }
1685
1686 pub fn resize(&self, new_asize: u32, new_hsize: u32) -> Result<(), LuaError> {
1689 let mut inner = self.inner.borrow_mut();
1690 inner.resize(new_asize, new_hsize)
1691 }
1692
1693 pub fn array_len(&self) -> usize {
1696 self.inner.borrow().array.len()
1697 }
1698
1699 pub fn len(&self) -> usize {
1702 let inner = self.inner.borrow();
1703 let mut n = 0usize;
1704 for v in inner.array.iter() {
1705 if !matches!(v, LuaValue::Nil) {
1706 n += 1;
1707 }
1708 }
1709 for node in inner.node.iter() {
1710 if !matches!(node.value, LuaValue::Nil) {
1711 n += 1;
1712 }
1713 }
1714 n
1715 }
1716 pub fn is_empty(&self) -> bool {
1717 self.len() == 0
1718 }
1719
1720 pub fn getn(&self) -> u64 {
1722 let mut inner = self.inner.borrow_mut();
1723 inner.getn()
1724 }
1725
1726 pub fn contains_key(&self, k: &LuaValue) -> bool {
1729 if matches!(k, LuaValue::Nil) {
1730 return false;
1731 }
1732 let inner = self.inner.borrow();
1733 let slot = inner.get_slot(k);
1734 !matches!(slot, TableSlotRef::Absent)
1735 }
1736
1737 pub fn metatable(&self) -> Option<GcRef<LuaTable>> {
1738 self.metatable.get()
1739 }
1740
1741 #[inline(always)]
1742 pub fn has_metatable(&self) -> bool {
1743 self.metatable.get().is_some()
1744 }
1745
1746 pub fn set_metatable(&self, mt: Option<GcRef<LuaTable>>) {
1750 let mode = mt.as_ref().map(|t| extract_weak_mode(t)).unwrap_or(0);
1751 self.weak_mode.set(mode);
1752 self.metatable.set(mt);
1753 }
1754
1755 pub fn weak_mode(&self) -> u8 {
1756 self.weak_mode.get()
1757 }
1758
1759 pub fn next_pair(&self, k: &LuaValue) -> Option<(LuaValue, LuaValue)> {
1761 let inner = self.inner.borrow();
1762 inner.next_pair(k).ok().flatten()
1763 }
1764
1765 pub fn try_next_pair(&self, k: &LuaValue) -> Result<Option<(LuaValue, LuaValue)>, LuaError> {
1768 let inner = self.inner.borrow();
1769 inner.next_pair(k)
1770 }
1771
1772 pub fn trace_entries_with_clearkey(&self, mut f: impl FnMut(&LuaValue)) {
1784 let mut inner = self.inner.borrow_mut();
1785 for v in inner.array.iter() {
1786 if !matches!(v, LuaValue::Nil) {
1787 f(v);
1788 }
1789 }
1790 for node in inner.node.iter_mut() {
1791 if matches!(node.value, LuaValue::Nil) {
1792 if !node.dead && gc_identity_bits(&node.key).is_some() {
1793 node.dead = true;
1794 }
1795 } else {
1796 f(&node.key);
1797 f(&node.value);
1798 }
1799 }
1800 }
1801
1802 pub fn for_each_entry(&self, mut f: impl FnMut(&LuaValue, &LuaValue)) {
1803 let inner = self.inner.borrow();
1804 for (i, v) in inner.array.iter().enumerate() {
1805 if !matches!(v, LuaValue::Nil) {
1806 let k = LuaValue::Int((i + 1) as i64);
1807 f(&k, v);
1808 }
1809 }
1810 for node in inner.node.iter() {
1811 if !matches!(node.value, LuaValue::Nil) {
1812 f(&node.key, &node.value);
1813 }
1814 }
1815 }
1816
1817 pub fn prune_weak_dead(&self, is_reachable: &dyn Fn(usize) -> bool) -> Vec<LuaValue> {
1821 self.prune_weak_dead_with(is_reachable, is_reachable)
1822 }
1823
1824 pub fn prune_weak_dead_with(
1829 &self,
1830 is_key_reachable: &dyn Fn(usize) -> bool,
1831 is_value_reachable: &dyn Fn(usize) -> bool,
1832 ) -> Vec<LuaValue> {
1833 self.prune_weak_dead_with_value(
1834 &|v| collectable_identity(v).map_or(true, is_key_reachable),
1835 &|v| collectable_identity(v).map_or(true, is_value_reachable),
1836 )
1837 }
1838
1839 pub fn prune_weak_dead_with_value(
1850 &self,
1851 is_key_reachable: &dyn Fn(&LuaValue) -> bool,
1852 is_value_reachable: &dyn Fn(&LuaValue) -> bool,
1853 ) -> Vec<LuaValue> {
1854 let mode = self.weak_mode.get();
1855 if mode == 0 {
1856 return Vec::new();
1857 }
1858 let weak_k = (mode & WEAK_KEYS) != 0;
1859 let weak_v = (mode & WEAK_VALUES) != 0;
1860 let mut to_mark: Vec<LuaValue> = Vec::new();
1861 let mut inner = self.inner.borrow_mut();
1862 for i in 0..inner.array.len() {
1863 let v = inner.array[i].clone();
1864 if matches!(v, LuaValue::Nil) {
1865 continue;
1866 }
1867 if weak_v && value_is_dead_collectable(&v, is_value_reachable) {
1868 inner.array[i] = LuaValue::Nil;
1869 continue;
1870 }
1871 if weak_v {
1872 if matches!(v, LuaValue::Str(_)) {
1873 to_mark.push(v);
1874 }
1875 }
1876 }
1877 let mut i = 0;
1878 while i < inner.node.len() {
1879 let v = inner.node[i].value.clone();
1880 if matches!(v, LuaValue::Nil) {
1881 if !inner.node[i].dead && gc_identity_bits(&inner.node[i].key).is_some() {
1882 inner.node[i].dead = true;
1883 }
1884 i += 1;
1885 continue;
1886 }
1887 let k = inner.node[i].key.clone();
1888 if weak_v && value_is_dead_collectable(&v, is_value_reachable) {
1889 inner.clear_dead_hash_node(i);
1890 continue;
1891 }
1892 if weak_k && value_is_dead_collectable(&k, is_key_reachable) {
1893 inner.clear_dead_hash_node(i);
1894 continue;
1895 }
1896 if weak_k {
1897 if matches!(k, LuaValue::Str(_)) {
1898 to_mark.push(k);
1899 }
1900 }
1901 if weak_v {
1902 if matches!(v, LuaValue::Str(_)) {
1903 to_mark.push(v);
1904 }
1905 }
1906 i += 1;
1907 }
1908 to_mark
1909 }
1910
1911 pub fn ephemeron_values_to_mark(&self, is_reachable: &dyn Fn(usize) -> bool) -> Vec<LuaValue> {
1913 self.ephemeron_values_to_mark_with_value(&|v| {
1914 collectable_identity(v).map_or(true, is_reachable)
1915 })
1916 }
1917
1918 pub fn ephemeron_values_to_mark_with_value(
1921 &self,
1922 is_reachable: &dyn Fn(&LuaValue) -> bool,
1923 ) -> Vec<LuaValue> {
1924 let mode = self.weak_mode.get();
1925 if (mode & WEAK_KEYS) == 0 || (mode & WEAK_VALUES) != 0 {
1926 return Vec::new();
1927 }
1928 let inner = self.inner.borrow();
1929 let mut out = Vec::new();
1930 for node in inner.node.iter() {
1931 if matches!(node.value, LuaValue::Nil) {
1932 continue;
1933 }
1934 if !value_is_dead_collectable(&node.key, is_reachable) {
1935 out.push(node.value.clone());
1936 }
1937 }
1938 for (i, v) in inner.array.iter().enumerate() {
1939 if matches!(v, LuaValue::Nil) {
1940 continue;
1941 }
1942 let k = LuaValue::Int((i + 1) as i64);
1943 if !value_is_dead_collectable(&k, is_reachable) {
1944 out.push(v.clone());
1945 }
1946 }
1947 out
1948 }
1949}
1950
1951fn value_is_dead_collectable(v: &LuaValue, is_reachable: &dyn Fn(&LuaValue) -> bool) -> bool {
1956 collectable_identity(v).is_some() && !is_reachable(v)
1957}
1958
1959fn gc_identity_bits(v: &LuaValue) -> Option<usize> {
1962 match v {
1963 LuaValue::Str(x) => Some(x.identity()),
1964 LuaValue::Table(x) => Some(x.identity()),
1965 LuaValue::UserData(x) => Some(x.identity()),
1966 LuaValue::Thread(x) => Some(x.identity()),
1967 LuaValue::Function(LuaClosure::Lua(x)) => Some(x.identity()),
1968 LuaValue::Function(LuaClosure::C(x)) => Some(x.identity()),
1969 LuaValue::Function(LuaClosure::LightC(_))
1970 | LuaValue::Nil
1971 | LuaValue::Bool(_)
1972 | LuaValue::Int(_)
1973 | LuaValue::Float(_)
1974 | LuaValue::LightUserData(_) => None,
1975 }
1976}
1977
1978fn collectable_identity(v: &LuaValue) -> Option<usize> {
1979 match v {
1980 LuaValue::Table(t) => Some(t.identity()),
1981 LuaValue::UserData(u) => Some(u.identity()),
1982 LuaValue::Thread(th) => Some(th.identity()),
1983 LuaValue::Function(c) => match c {
1984 LuaClosure::Lua(x) => Some(x.identity()),
1985 LuaClosure::C(x) => Some(x.identity()),
1986 LuaClosure::LightC(_) => None,
1987 },
1988 LuaValue::Str(_)
1989 | LuaValue::Nil
1990 | LuaValue::Bool(_)
1991 | LuaValue::Int(_)
1992 | LuaValue::Float(_)
1993 | LuaValue::LightUserData(_) => None,
1994 }
1995}
1996
1997fn extract_weak_mode(mt: &LuaTable) -> u8 {
2001 let inner = mt.inner.borrow();
2002 for node in inner.node.iter() {
2003 if node.dead {
2004 continue;
2005 }
2006 if let LuaValue::Str(ks) = &node.key {
2007 if ks.as_bytes() == b"__mode" {
2008 if let LuaValue::Str(vs) = &node.value {
2009 let bytes = vs.as_bytes();
2010 let mut mode = 0u8;
2011 if bytes.iter().any(|b| *b == b'k') {
2012 mode |= WEAK_KEYS;
2013 }
2014 if bytes.iter().any(|b| *b == b'v') {
2015 mode |= WEAK_VALUES;
2016 }
2017 return mode;
2018 }
2019 return 0;
2020 }
2021 }
2022 }
2023 0
2024}
2025
2026