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> {
595 if matches!(key, LuaValue::Nil) {
596 return Ok(0);
597 }
598 let i = if let LuaValue::Int(k) = key {
599 Self::array_index(*k)
600 } else {
601 0
602 };
603 if i.wrapping_sub(1) < asize {
604 return Ok(i);
605 }
606 let slot = self.get_generic_slot_deadok(key);
607 match slot {
608 TableSlotRef::Absent => Err(LuaError::runtime(format_args!("invalid key to 'next'"))),
609 TableSlotRef::Hash(node_idx) => Ok((node_idx as u32 + 1) + asize),
610 TableSlotRef::Array(_) => unreachable!("getgeneric returned Array slot"),
611 }
612 }
613
614 fn next_pair(&self, key: &LuaValue) -> Result<Option<(LuaValue, LuaValue)>, LuaError> {
617 let asize = self.real_asize();
618 let i = self.find_index(key, asize)?;
619 let mut i = i as usize;
620 while i < asize as usize {
621 if !matches!(self.array[i], LuaValue::Nil) {
622 return Ok(Some((LuaValue::Int((i + 1) as i64), self.array[i].clone())));
623 }
624 i += 1;
625 }
626 let mut hi = i.saturating_sub(asize as usize);
627 while hi < self.node.len() {
628 if !matches!(self.node[hi].value, LuaValue::Nil) {
629 return Ok(Some((
630 self.node[hi].key_value(),
631 self.node[hi].value.clone(),
632 )));
633 }
634 hi += 1;
635 }
636 Ok(None)
637 }
638
639 fn compute_sizes(nums: &[u32], pna: &mut u32) -> u32 {
642 let mut twotoi: u32 = 1;
643 let mut a: u32 = 0;
644 let mut na: u32 = 0;
645 let mut optimal: u32 = 0;
646 for i in 0..nums.len() {
647 if twotoi == 0 || *pna <= twotoi / 2 {
648 break;
649 }
650 a += nums[i];
651 if a > twotoi / 2 {
652 optimal = twotoi;
653 na = a;
654 }
655 twotoi = twotoi.wrapping_mul(2);
656 }
657 debug_assert!(optimal == 0 || optimal / 2 < na && na <= optimal);
658 *pna = na;
659 optimal
660 }
661
662 fn count_int(key: i64, nums: &mut [u32]) -> bool {
663 let k = Self::array_index(key);
664 if k != 0 {
665 nums[ceil_log2(k) as usize] += 1;
666 true
667 } else {
668 false
669 }
670 }
671
672 fn num_use_array(&self, nums: &mut [u32]) -> u32 {
673 debug_assert!(
674 self.is_real_asize(),
675 "numusearray: alimit must be real size"
676 );
677 let asize = self.alimit as usize;
678 let mut ause: u32 = 0;
679 let mut i: usize = 1;
680 let mut ttlg: usize = 1;
681 for lg in 0..=(MAXABITS as usize) {
682 let mut lc: u32 = 0;
683 let lim = if ttlg > asize { asize } else { ttlg };
684 if i > lim {
685 break;
686 }
687 while i <= lim {
688 if !matches!(self.array[i - 1], LuaValue::Nil) {
689 lc += 1;
690 }
691 i += 1;
692 }
693 nums[lg] += lc;
694 ause += lc;
695 ttlg = ttlg.saturating_mul(2);
696 }
697 ause
698 }
699
700 fn num_use_hash(&self, nums: &mut [u32], pna: &mut u32) -> i32 {
701 let mut totaluse: i32 = 0;
702 let mut ause: u32 = 0;
703 let mut i = self.node.len();
704 while i > 0 {
705 i -= 1;
706 let n = &self.node[i];
707 if !matches!(n.value, LuaValue::Nil) {
708 if n.key_is_int() {
709 if Self::count_int(n.key_int(), nums) {
710 ause += 1;
711 }
712 }
713 totaluse += 1;
714 }
715 }
716 *pna += ause;
717 totaluse
718 }
719
720 fn set_array_size(&mut self, new_size: usize) {
732 let old = std::mem::take(&mut self.array);
733 let keep = old.len().min(new_size);
734 let mut survivors = old.into_vec();
735 survivors.truncate(keep);
736 survivors.reserve_exact(new_size - keep);
737 survivors.resize_with(new_size, || LuaValue::Nil);
738 self.array = survivors.into_boxed_slice();
739 }
740
741 fn set_node_vector(&mut self, size: u32) -> Result<(), LuaError> {
742 if size == 0 {
743 self.node = Box::default();
744 self.lsizenode = 0;
745 self.lastfree = NO_LASTFREE;
746 } else {
747 let lsize = ceil_log2(size);
748 if lsize as u32 > MAXHBITS || (1u32 << lsize) > MAXHSIZE {
749 return Err(LuaError::runtime(format_args!("table overflow")));
750 }
751 let actual_size = 1u32 << lsize;
752 let nodes: Vec<TableNode> = (0..actual_size).map(|_| TableNode::empty()).collect();
753 self.node = nodes.into_boxed_slice();
754 self.lsizenode = lsize as u8;
755 self.lastfree = actual_size;
756 }
757 Ok(())
758 }
759
760 fn reinsert(&mut self, old_nodes: Vec<(LuaValue, LuaValue)>) -> Result<(), LuaError> {
761 for (k, v) in old_nodes {
762 self.set(&k, v)?;
763 }
764 Ok(())
765 }
766
767 fn resize(&mut self, new_asize: u32, nhsize: u32) -> Result<(), LuaError> {
769 let old_asize = self.set_limit_to_size();
770
771 let (mut new_hash_node, mut new_hash_lsize, mut new_hash_lastfree) = {
772 let mut tmp = TableInner::new();
773 tmp.set_node_vector(nhsize)?;
774 (tmp.node, tmp.lsizenode, tmp.lastfree)
775 };
776
777 if new_asize < old_asize {
778 let migrate_end = (old_asize as usize).min(self.array.len());
779 let detached: Vec<(i64, LuaValue)> = ((new_asize as usize)..migrate_end)
780 .filter(|&i| !matches!(self.array[i], LuaValue::Nil))
781 .map(|i| ((i + 1) as i64, self.array[i].clone()))
782 .collect();
783 self.set_array_size(new_asize as usize);
784 self.alimit = new_asize;
785
786 std::mem::swap(&mut self.node, &mut new_hash_node);
787 std::mem::swap(&mut self.lsizenode, &mut new_hash_lsize);
788 std::mem::swap(&mut self.lastfree, &mut new_hash_lastfree);
789
790 for (key, v) in detached {
791 self.set_int(key, v)?;
792 }
793
794 self.alimit = old_asize;
795 std::mem::swap(&mut self.node, &mut new_hash_node);
796 std::mem::swap(&mut self.lsizenode, &mut new_hash_lsize);
797 std::mem::swap(&mut self.lastfree, &mut new_hash_lastfree);
798 }
799
800 self.set_array_size(new_asize as usize);
801
802 std::mem::swap(&mut self.node, &mut new_hash_node);
803 std::mem::swap(&mut self.lsizenode, &mut new_hash_lsize);
804 std::mem::swap(&mut self.lastfree, &mut new_hash_lastfree);
805 self.alimit = new_asize;
806
807 let old_hash_entries: Vec<(LuaValue, LuaValue)> = new_hash_node
808 .iter()
809 .filter(|n| !matches!(n.value, LuaValue::Nil))
810 .map(|n| (n.key_value(), n.value.clone()))
811 .collect();
812 drop(new_hash_node);
813 self.reinsert(old_hash_entries)?;
814
815 Ok(())
816 }
817
818 fn rehash(&mut self, extra_key: &LuaValue) -> Result<(), LuaError> {
819 let mut nums = [0u32; MAXABITS as usize + 1];
820 self.set_limit_to_size();
821
822 let na = self.num_use_array(&mut nums);
823 let mut na = na;
824 let mut totaluse = na as i32;
825
826 totaluse += self.num_use_hash(&mut nums, &mut na);
827
828 if let LuaValue::Int(ek) = extra_key {
829 if Self::count_int(*ek, &mut nums) {
830 na += 1;
831 }
832 }
833 totaluse += 1;
834
835 let asize = Self::compute_sizes(&nums, &mut na);
836
837 let nh = (totaluse - na as i32).max(0) as u32;
838 self.resize(asize, nh)
839 }
840
841 fn get_free_pos(&mut self) -> Option<usize> {
842 if self.is_dummy() {
843 return None;
844 }
845 loop {
846 if self.lastfree == NO_LASTFREE {
847 return None;
848 }
849 if self.lastfree == 0 {
850 self.lastfree = NO_LASTFREE;
851 return None;
852 }
853 let idx = (self.lastfree - 1) as usize;
854 self.lastfree = idx as u32;
855 if self.node[idx].key_is_nil() {
856 return Some(idx);
857 }
858 }
859 }
860
861 fn find_chain_predecessor(&self, idx: usize) -> Option<usize> {
862 self.node
863 .iter()
864 .enumerate()
865 .find(|(prev, node)| {
866 node.next != 0 && (*prev as isize + node.next as isize) == idx as isize
867 })
868 .map(|(prev, _)| prev)
869 }
870
871 fn clear_node(&mut self, idx: usize) {
872 self.node[idx].key = LuaValue::Nil;
873 self.node[idx].value = LuaValue::Nil;
874 self.node[idx].next = 0;
875 }
876
877 fn remove_hash_node(&mut self, idx: usize) {
878 if let Some(prev) = self.find_chain_predecessor(idx) {
879 let next = self.node[idx].next;
880 self.node[prev].next = if next == 0 {
881 0
882 } else {
883 let target = idx as isize + next as isize;
884 (target - prev as isize) as i32
885 };
886 self.clear_node(idx);
887 return;
888 }
889
890 let next = self.node[idx].next;
891 if next == 0 {
892 self.clear_node(idx);
893 return;
894 }
895
896 let next_idx = (idx as isize + next as isize) as usize;
897 let moved_next = self.node[next_idx].next;
898 let moved_key = self.node[next_idx].key_value();
899 let moved_value = self.node[next_idx].value.clone();
900 self.node[idx].key = moved_key;
901 self.node[idx].value = moved_value;
902 self.node[idx].next = if moved_next == 0 {
903 0
904 } else {
905 let target = next_idx as isize + moved_next as isize;
906 (target - idx as isize) as i32
907 };
908 self.clear_node(next_idx);
909 }
910
911 fn clear_dead_hash_node(&mut self, idx: usize) {
912 self.remove_hash_node(idx);
913 }
914
915 fn new_key(&mut self, key: &LuaValue, value: LuaValue) -> Result<(), LuaError> {
916 if matches!(key, LuaValue::Nil) {
917 return Err(LuaError::runtime(format_args!("table index is nil")));
918 }
919 let normalised_key;
920 let key = if let LuaValue::Float(f) = key {
921 let f = *f;
922 if f.is_nan() {
923 return Err(LuaError::runtime(format_args!("table index is NaN")));
924 }
925 let k = f as i64;
926 if k as f64 == f {
927 normalised_key = LuaValue::Int(k);
928 &normalised_key
929 } else {
930 key
931 }
932 } else {
933 key
934 };
935
936 if matches!(value, LuaValue::Nil) {
937 return Ok(());
938 }
939
940 if self.is_dummy() && !matches!(key, LuaValue::Int(_)) {
941 self.set_node_vector(DUMMY_TABLE_INIT_HASH_NODES)?;
942 let mp = self.main_position(key);
943 self.node[mp].set_key(key);
944 self.node[mp].value = value;
945 return Ok(());
946 }
947
948 let mp = self.main_position(key);
949 let mp_occupied = self.is_dummy() || !matches!(self.node[mp].value, LuaValue::Nil);
950 if mp_occupied {
951 let f = self.get_free_pos();
952 let f = match f {
953 None => {
954 self.rehash(key)?;
955 return self.set(key, value);
956 }
957 Some(idx) => idx,
958 };
959
960 debug_assert!(!self.is_dummy());
961 let othern = self.main_position_from_node(mp);
962
963 if othern != mp {
964 let mut prev = othern;
965 let mut steps = 0usize;
966 while (prev as isize + self.node[prev].next as isize) as usize != mp {
967 steps += 1;
968 if steps > self.node.len() {
969 panic!(
970 "table hash chain invariant broken: node {} unreachable from main position {} \
971 ({} nodes; usually a missing GC key barrier — see ltable.c:717 parity note)",
972 mp,
973 othern,
974 self.node.len()
975 );
976 }
977 prev = (prev as isize + self.node[prev].next as isize) as usize;
978 }
979 self.node[prev].next = (f as isize - prev as isize) as i32;
980 let mp_key = self.node[mp].key_value();
981 let mp_val = self.node[mp].value.clone();
982 let mp_next = self.node[mp].next;
983 self.node[f].key = mp_key;
984 self.node[f].value = mp_val;
985 if mp_next != 0 {
986 self.node[f].next = mp_next + (mp as isize - f as isize) as i32;
987 self.node[mp].next = 0;
988 } else {
989 self.node[f].next = 0;
990 }
991 self.node[mp].value = LuaValue::Nil;
992 } else {
993 if self.node[mp].next != 0 {
994 let target = (mp as isize + self.node[mp].next as isize) as usize;
995 self.node[f].next = (target as isize - f as isize) as i32;
996 } else {
997 debug_assert!(self.node[f].next == 0);
998 }
999 self.node[mp].next = (f as isize - mp as isize) as i32;
1000 self.node[f].set_key(key);
1001 debug_assert!(matches!(self.node[f].value, LuaValue::Nil));
1002 self.node[f].value = value;
1003 return Ok(());
1004 }
1005 }
1006 self.node[mp].set_key(key);
1007 debug_assert!(matches!(self.node[mp].value, LuaValue::Nil));
1008 self.node[mp].value = value;
1009 Ok(())
1010 }
1011
1012 fn get_int_slot(&self, key: i64) -> TableSlotRef {
1013 let alimit = self.alimit as u64;
1014 let uk = key as u64;
1015 if uk.wrapping_sub(1) < alimit {
1016 return TableSlotRef::Array((key - 1) as usize);
1017 }
1018 if !self.is_real_asize() && alimit > 0 {
1019 let masked = (uk.wrapping_sub(1)) & !(alimit.wrapping_sub(1));
1020 if masked < alimit {
1021 return TableSlotRef::Array((key - 1) as usize);
1022 }
1023 }
1024 if self.is_dummy() {
1025 return TableSlotRef::Absent;
1026 }
1027 let mut n = self.hash_idx_for_int(key);
1028 loop {
1029 if self.node[n].key_is_int() && self.node[n].key_int() == key {
1030 return TableSlotRef::Hash(n);
1031 }
1032 let nx = self.node[n].next;
1033 if nx == 0 {
1034 break;
1035 }
1036 n = (n as isize + nx as isize) as usize;
1037 }
1038 TableSlotRef::Absent
1039 }
1040
1041 #[inline]
1048 fn get_int_value(&self, key: i64) -> LuaValue {
1049 let alimit = self.alimit as u64;
1050 let uk = key as u64;
1051 if uk.wrapping_sub(1) < alimit {
1052 return self.array[(key - 1) as usize].clone();
1053 }
1054 self.get_int_value_cold(key)
1055 }
1056
1057 #[cold]
1058 #[inline(never)]
1059 fn get_int_value_cold(&self, key: i64) -> LuaValue {
1060 let alimit = self.alimit as u64;
1061 let uk = key as u64;
1062 if !self.is_real_asize() && alimit > 0 {
1063 let masked = (uk.wrapping_sub(1)) & !(alimit.wrapping_sub(1));
1064 if masked < alimit {
1065 return self.array[(key - 1) as usize].clone();
1066 }
1067 }
1068 if self.is_dummy() {
1069 return LuaValue::Nil;
1070 }
1071 let mut n = self.hash_idx_for_int(key);
1072 loop {
1073 if self.node[n].key_is_int() && self.node[n].key_int() == key {
1074 return self.node[n].value.clone();
1075 }
1076 let nx = self.node[n].next;
1077 if nx == 0 {
1078 break;
1079 }
1080 n = (n as isize + nx as isize) as usize;
1081 }
1082 LuaValue::Nil
1083 }
1084
1085 #[inline(always)]
1086 fn get_short_str_slot(&self, key: &GcRef<LuaString>) -> TableSlotRef {
1087 debug_assert!(key.is_short());
1088 if self.is_dummy() {
1089 return TableSlotRef::Absent;
1090 }
1091 let mut n = self.hashpow2_idx(key.hash());
1092 loop {
1093 if self.node[n].key_is_short_str() {
1094 let ks = self.node[n].key_string();
1095 if lua_string_content_eq(ks, key) {
1096 return TableSlotRef::Hash(n);
1097 }
1098 }
1099 let nx = self.node[n].next;
1100 if nx == 0 {
1101 return TableSlotRef::Absent;
1102 }
1103 n = (n as isize + nx as isize) as usize;
1104 }
1105 }
1106
1107 #[inline(always)]
1108 fn try_update_short_str(
1109 &mut self,
1110 key: &GcRef<LuaString>,
1111 value: LuaValue,
1112 ) -> Result<(), LuaValue> {
1113 debug_assert!(key.is_short());
1114 if self.is_dummy() {
1115 return Err(value);
1116 }
1117 let mut n = self.hashpow2_idx(key.hash());
1118 loop {
1119 if self.node[n].key_is_short_str() {
1120 let ks = self.node[n].key_string();
1121 if lua_string_content_eq(ks, key) {
1122 self.node[n].value = value;
1123 return Ok(());
1124 }
1125 }
1126 let nx = self.node[n].next;
1127 if nx == 0 {
1128 return Err(value);
1129 }
1130 n = (n as isize + nx as isize) as usize;
1131 }
1132 }
1133
1134 #[inline(always)]
1135 fn try_update_int(&mut self, key: i64, value: LuaValue) -> Result<(), LuaValue> {
1136 let alimit = self.alimit as u64;
1137 let uk = key as u64;
1138 if uk.wrapping_sub(1) < alimit {
1139 self.array[(key - 1) as usize] = value;
1140 return Ok(());
1141 }
1142 if !self.is_real_asize() && alimit > 0 {
1143 let masked = (uk.wrapping_sub(1)) & !(alimit.wrapping_sub(1));
1144 if masked < alimit {
1145 self.array[(key - 1) as usize] = value;
1146 return Ok(());
1147 }
1148 }
1149 if !self.is_dummy() {
1150 let mut n = self.hash_idx_for_int(key);
1151 loop {
1152 if self.node[n].key_is_int() && self.node[n].key_int() == key {
1153 self.node[n].value = value;
1154 return Ok(());
1155 }
1156 let nx = self.node[n].next;
1157 if nx == 0 {
1158 break;
1159 }
1160 n = (n as isize + nx as isize) as usize;
1161 }
1162 }
1163 Err(value)
1164 }
1165
1166 #[inline]
1174 fn get_str_value(&self, key: &GcRef<LuaString>) -> LuaValue {
1175 debug_assert!(key.is_short());
1176 if self.is_dummy() {
1177 return LuaValue::Nil;
1178 }
1179 let mut n = self.hashpow2_idx(key.hash());
1180 loop {
1181 if self.node[n].key_is_short_str() {
1182 let ks = self.node[n].key_string();
1183 if lua_string_content_eq(ks, key) {
1184 return self.node[n].value.clone();
1185 }
1186 }
1187 let nx = self.node[n].next;
1188 if nx == 0 {
1189 return LuaValue::Nil;
1190 }
1191 n = (n as isize + nx as isize) as usize;
1192 }
1193 }
1194
1195 #[cold]
1200 #[inline(never)]
1201 fn get_generic_value(&self, key: &LuaValue) -> LuaValue {
1202 let slot = self.get_slot(key);
1203 self.slot_value(slot)
1204 }
1205
1206 fn get_str_slot(&self, key: &GcRef<LuaString>) -> TableSlotRef {
1207 if key.is_short() {
1208 self.get_short_str_slot(key)
1209 } else {
1210 let ko = LuaValue::Str(key.clone());
1211 self.get_generic_slot(&ko)
1212 }
1213 }
1214
1215 fn get_slot(&self, key: &LuaValue) -> TableSlotRef {
1216 match key {
1217 LuaValue::Str(s) if s.is_short() => self.get_short_str_slot(s),
1218 LuaValue::Int(i) => self.get_int_slot(*i),
1219 LuaValue::Nil => TableSlotRef::Absent,
1220 LuaValue::Float(f) => {
1221 let f = *f;
1222 let k = f as i64;
1223 if k as f64 == f {
1224 self.get_int_slot(k)
1225 } else {
1226 self.get_generic_slot(key)
1227 }
1228 }
1229 _ => self.get_generic_slot(key),
1230 }
1231 }
1232
1233 fn slot_value(&self, slot: TableSlotRef) -> LuaValue {
1234 match slot {
1235 TableSlotRef::Array(i) => self.array[i].clone(),
1236 TableSlotRef::Hash(i) => self.node[i].value.clone(),
1237 TableSlotRef::Absent => LuaValue::Nil,
1238 }
1239 }
1240
1241 fn finish_set(
1242 &mut self,
1243 key: &LuaValue,
1244 slot: TableSlotRef,
1245 value: LuaValue,
1246 ) -> Result<(), LuaError> {
1247 match slot {
1248 TableSlotRef::Absent => self.new_key(key, value),
1249 TableSlotRef::Array(i) => {
1250 self.array[i] = value;
1251 Ok(())
1252 }
1253 TableSlotRef::Hash(i) => {
1254 self.node[i].value = value;
1255 Ok(())
1256 }
1257 }
1258 }
1259
1260 fn set(&mut self, key: &LuaValue, value: LuaValue) -> Result<(), LuaError> {
1261 let slot = self.get_slot(key);
1262 self.finish_set(key, slot, value)
1263 }
1264
1265 fn set_int(&mut self, key: i64, value: LuaValue) -> Result<(), LuaError> {
1269 let slot = self.get_int_slot(key);
1270 if matches!(slot, TableSlotRef::Absent) {
1271 if key > 0 && (key as u64) <= ARRAY_GROW_CAP as u64 {
1272 let cur = self.alimit as i64;
1273 if key == cur + 1 && !matches!(value, LuaValue::Nil) {
1274 let new_size = (key as u32).next_power_of_two().max(4);
1275 let capped = new_size.min(ARRAY_GROW_CAP);
1276 if capped > self.alimit {
1277 let nsize = self.alloc_sizenode();
1278 self.resize(capped, nsize)?;
1279 let new_slot = self.get_int_slot(key);
1280 return self.finish_set(&LuaValue::Int(key), new_slot, value);
1281 }
1282 }
1283 }
1284 }
1285 match slot {
1286 TableSlotRef::Absent => {
1287 let k = LuaValue::Int(key);
1288 self.new_key(&k, value)
1289 }
1290 TableSlotRef::Array(i) => {
1291 self.array[i] = value;
1292 Ok(())
1293 }
1294 TableSlotRef::Hash(i) => {
1295 self.node[i].value = value;
1296 Ok(())
1297 }
1298 }
1299 }
1300
1301 #[inline]
1308 fn try_raw_set_int_fast(&mut self, key: i64, value: LuaValue) -> Result<(), LuaError> {
1309 let alimit = self.alimit as u64;
1310 let uk = key as u64;
1311 if uk.wrapping_sub(1) < alimit {
1312 self.array[(key - 1) as usize] = value;
1313 return Ok(());
1314 }
1315 self.try_raw_set_int_cold(key, value)
1316 }
1317
1318 #[cold]
1319 #[inline(never)]
1320 fn try_raw_set_int_cold(&mut self, key: i64, value: LuaValue) -> Result<(), LuaError> {
1321 if self.array.len() + self.node.len() >= TOTAL_GROW_CAP
1322 && matches!(self.get_int_slot(key), TableSlotRef::Absent)
1323 {
1324 return Err(LuaError::Memory);
1325 }
1326 self.set_int_value_cold(key, value)
1327 }
1328
1329 #[cold]
1336 #[inline(never)]
1337 fn set_int_value_cold(&mut self, key: i64, value: LuaValue) -> Result<(), LuaError> {
1338 let alimit = self.alimit as u64;
1339 let uk = key as u64;
1340 if !self.is_real_asize() && alimit > 0 {
1341 let masked = (uk.wrapping_sub(1)) & !(alimit.wrapping_sub(1));
1342 if masked < alimit {
1343 self.array[(key - 1) as usize] = value;
1344 return Ok(());
1345 }
1346 }
1347 if !self.is_dummy() {
1348 let mut n = self.hash_idx_for_int(key);
1349 loop {
1350 if self.node[n].key_is_int() && self.node[n].key_int() == key {
1351 self.node[n].value = value;
1352 return Ok(());
1353 }
1354 let nx = self.node[n].next;
1355 if nx == 0 {
1356 break;
1357 }
1358 n = (n as isize + nx as isize) as usize;
1359 }
1360 }
1361 if key > 0 && (key as u64) <= ARRAY_GROW_CAP as u64 {
1362 let cur = self.alimit as i64;
1363 if key == cur + 1 && !matches!(value, LuaValue::Nil) {
1364 let new_size = (key as u32).next_power_of_two().max(4);
1365 let capped = new_size.min(ARRAY_GROW_CAP);
1366 if capped > self.alimit {
1367 let nsize = self.alloc_sizenode();
1368 self.resize(capped, nsize)?;
1369 let new_slot = self.get_int_slot(key);
1370 return self.finish_set(&LuaValue::Int(key), new_slot, value);
1371 }
1372 }
1373 }
1374 let k = LuaValue::Int(key);
1375 self.new_key(&k, value)
1376 }
1377
1378 fn hash_search(&self, mut j: u64) -> u64 {
1381 let mut i: u64;
1382 if j == 0 {
1383 j = 1;
1384 }
1385 loop {
1386 i = j;
1387 if j <= (i64::MAX as u64) / 2 {
1388 j *= 2;
1389 } else {
1390 j = i64::MAX as u64;
1391 let s = self.get_int_slot(j as i64);
1392 if matches!(s, TableSlotRef::Absent) || matches!(self.slot_value(s), LuaValue::Nil)
1393 {
1394 break;
1395 } else {
1396 return j;
1397 }
1398 }
1399 let s = self.get_int_slot(j as i64);
1400 if matches!(s, TableSlotRef::Absent) {
1401 break;
1402 }
1403 if matches!(self.slot_value(s), LuaValue::Nil) {
1404 break;
1405 }
1406 }
1407 while j - i > 1 {
1408 let m = i / 2 + j / 2;
1409 let s = self.get_int_slot(m as i64);
1410 let empty =
1411 matches!(s, TableSlotRef::Absent) || matches!(self.slot_value(s), LuaValue::Nil);
1412 if empty {
1413 j = m;
1414 } else {
1415 i = m;
1416 }
1417 }
1418 i
1419 }
1420
1421 fn bin_search(array: &[LuaValue], mut i: u32, mut j: u32) -> u32 {
1422 while j - i > 1 {
1423 let m = (i + j) / 2;
1424 if matches!(array[(m - 1) as usize], LuaValue::Nil) {
1425 j = m;
1426 } else {
1427 i = m;
1428 }
1429 }
1430 i
1431 }
1432
1433 fn getn(&mut self) -> u64 {
1436 let limit = self.alimit;
1437 if limit > 0 && matches!(self.array[(limit - 1) as usize], LuaValue::Nil) {
1438 if limit >= 2 && !matches!(self.array[(limit - 2) as usize], LuaValue::Nil) {
1439 if self.is_pow2_real_asize() && !Self::is_pow2(limit - 1) {
1440 self.alimit = limit - 1;
1441 self.flags.set_no_real_asize();
1442 }
1443 return (limit - 1) as u64;
1444 } else {
1445 let boundary = Self::bin_search(&self.array, 0, limit);
1446 if self.is_pow2_real_asize() && boundary > self.real_asize() / 2 {
1447 self.alimit = boundary;
1448 self.flags.set_no_real_asize();
1449 }
1450 return boundary as u64;
1451 }
1452 }
1453 if !self.limit_equals_asize() {
1454 if matches!(self.array[limit as usize], LuaValue::Nil) {
1455 return limit as u64;
1456 }
1457 let real = self.real_asize();
1458 if matches!(self.array[(real - 1) as usize], LuaValue::Nil) {
1459 let old_alimit = self.alimit;
1460 let boundary = Self::bin_search(&self.array, old_alimit, real);
1461 self.alimit = boundary;
1462 return boundary as u64;
1463 }
1464 }
1465 let limit = self.real_asize();
1466 debug_assert!(
1467 limit == self.real_asize()
1468 && (limit == 0 || !matches!(self.array[(limit - 1) as usize], LuaValue::Nil))
1469 );
1470 let next_key = (limit as i64).saturating_add(1);
1471 let next_slot = self.get_int_slot(next_key);
1472 let next_empty = matches!(next_slot, TableSlotRef::Absent)
1473 || matches!(self.slot_value(next_slot), LuaValue::Nil);
1474 if self.is_dummy() || next_empty {
1475 return limit as u64;
1476 }
1477 self.hash_search(limit as u64)
1478 }
1479}
1480
1481#[derive(Debug)]
1489pub struct LuaTable {
1490 inner: RefCell<TableInner>,
1491 metatable: Cell<Option<GcRef<LuaTable>>>,
1495 weak_mode: Cell<u8>,
1496}
1497
1498impl std::fmt::Debug for TableInner {
1499 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1500 f.debug_struct("TableInner")
1501 .field("alimit", &self.alimit)
1502 .field("array_len", &self.array.len())
1503 .field("node_len", &self.node.len())
1504 .finish()
1505 }
1506}
1507
1508impl Default for LuaTable {
1509 fn default() -> Self {
1510 LuaTable {
1511 inner: RefCell::new(TableInner::new()),
1512 metatable: Cell::new(None),
1513 weak_mode: Cell::new(0),
1514 }
1515 }
1516}
1517
1518impl LuaTable {
1519 pub fn placeholder() -> Self {
1522 Self::default()
1523 }
1524
1525 pub fn with_inner<R>(&self, f: impl FnOnce(&TableInner) -> R) -> R {
1528 f(&self.inner.borrow())
1529 }
1530
1531 pub fn buffer_bytes(&self) -> usize {
1538 let inner = self.inner.borrow();
1539 inner.array.len() * std::mem::size_of::<LuaValue>()
1540 + inner.node.len() * std::mem::size_of::<TableNode>()
1541 }
1542
1543 #[inline(always)]
1553 pub fn get(&self, k: &LuaValue) -> LuaValue {
1554 let inner = self.inner.borrow();
1555 match k {
1556 LuaValue::Nil => LuaValue::Nil,
1557 LuaValue::Int(i) => inner.get_int_value(*i),
1558 LuaValue::Str(s) if s.is_short() => inner.get_str_value(s),
1559 _ => inner.get_generic_value(k),
1560 }
1561 }
1562
1563 #[inline(always)]
1569 pub fn get_int(&self, key: i64) -> LuaValue {
1570 let inner = self.inner.borrow();
1571 inner.get_int_value(key)
1572 }
1573
1574 #[inline(always)]
1582 pub fn get_short_str(&self, k: &GcRef<LuaString>) -> LuaValue {
1583 let inner = self.inner.borrow();
1584 if k.is_short() {
1585 inner.get_str_value(k)
1586 } else {
1587 let slot = inner.get_str_slot(k);
1588 inner.slot_value(slot)
1589 }
1590 }
1591
1592 pub fn get_str_bytes(&self, key_bytes: &[u8]) -> LuaValue {
1596 let mut found = LuaValue::Nil;
1597 self.for_each_entry(|k, v| {
1598 if !matches!(found, LuaValue::Nil) {
1599 return;
1600 }
1601 if let LuaValue::Str(s) = k {
1602 if s.as_bytes() == key_bytes {
1603 found = v.clone();
1604 }
1605 }
1606 });
1607 found
1608 }
1609
1610 pub fn raw_set(&self, k: LuaValue, v: LuaValue) {
1613 if matches!(k, LuaValue::Nil) {
1614 return;
1615 }
1616 if let LuaValue::Float(f) = &k {
1617 if f.is_nan() {
1618 return;
1619 }
1620 }
1621 let mut inner = self.inner.borrow_mut();
1622 let _ = inner.set(&k, v);
1623 }
1624
1625 #[inline]
1631 pub fn try_raw_set(&self, k: LuaValue, v: LuaValue) -> Result<(), LuaError> {
1632 match &k {
1633 LuaValue::Nil => Err(LuaError::runtime(format_args!("table index is nil"))),
1634 LuaValue::Float(f) if f.is_nan() => {
1635 Err(LuaError::runtime(format_args!("table index is NaN")))
1636 }
1637 LuaValue::Int(i) => {
1638 let key = *i;
1639 let mut inner = self.inner.borrow_mut();
1640 inner.try_raw_set_int_fast(key, v)
1641 }
1642 LuaValue::Float(f) => {
1643 let f = *f;
1644 let k_int = f as i64;
1645 if k_int as f64 == f {
1646 let mut inner = self.inner.borrow_mut();
1647 inner.try_raw_set_int_fast(k_int, v)
1648 } else {
1649 self.try_raw_set_generic(k, v)
1650 }
1651 }
1652 _ => self.try_raw_set_generic(k, v),
1653 }
1654 }
1655
1656 #[inline(always)]
1660 pub fn try_update_short_str(&self, k: &GcRef<LuaString>, v: LuaValue) -> Result<(), LuaValue> {
1661 if !k.is_short() {
1662 return Err(v);
1663 }
1664 let mut inner = self.inner.borrow_mut();
1665 inner.try_update_short_str(k, v)
1666 }
1667
1668 #[inline(always)]
1672 pub fn try_update_int(&self, k: i64, v: LuaValue) -> Result<(), LuaValue> {
1673 let mut inner = self.inner.borrow_mut();
1674 inner.try_update_int(k, v)
1675 }
1676
1677 #[cold]
1680 #[inline(never)]
1681 fn try_raw_set_generic(&self, k: LuaValue, v: LuaValue) -> Result<(), LuaError> {
1682 let mut inner = self.inner.borrow_mut();
1683 if inner.array.len() + inner.node.len() >= TOTAL_GROW_CAP
1684 && matches!(inner.get_slot(&k), TableSlotRef::Absent)
1685 {
1686 return Err(LuaError::Memory);
1687 }
1688 inner.set(&k, v)
1689 }
1690
1691 #[inline]
1698 pub fn try_raw_set_int(&self, k: i64, v: LuaValue) -> Result<(), LuaError> {
1699 let mut inner = self.inner.borrow_mut();
1700 inner.try_raw_set_int_fast(k, v)
1701 }
1702
1703 pub fn resize(&self, new_asize: u32, new_hsize: u32) -> Result<(), LuaError> {
1706 let mut inner = self.inner.borrow_mut();
1707 inner.resize(new_asize, new_hsize)
1708 }
1709
1710 pub fn array_len(&self) -> usize {
1713 self.inner.borrow().array.len()
1714 }
1715
1716 pub fn len(&self) -> usize {
1719 let inner = self.inner.borrow();
1720 let mut n = 0usize;
1721 for v in inner.array.iter() {
1722 if !matches!(v, LuaValue::Nil) {
1723 n += 1;
1724 }
1725 }
1726 for node in inner.node.iter() {
1727 if !matches!(node.value, LuaValue::Nil) {
1728 n += 1;
1729 }
1730 }
1731 n
1732 }
1733 pub fn is_empty(&self) -> bool {
1734 self.len() == 0
1735 }
1736
1737 pub fn getn(&self) -> u64 {
1739 let mut inner = self.inner.borrow_mut();
1740 inner.getn()
1741 }
1742
1743 pub fn contains_key(&self, k: &LuaValue) -> bool {
1746 if matches!(k, LuaValue::Nil) {
1747 return false;
1748 }
1749 let inner = self.inner.borrow();
1750 let slot = inner.get_slot(k);
1751 !matches!(slot, TableSlotRef::Absent)
1752 }
1753
1754 pub fn metatable(&self) -> Option<GcRef<LuaTable>> {
1755 self.metatable.get()
1756 }
1757
1758 #[inline(always)]
1759 pub fn has_metatable(&self) -> bool {
1760 self.metatable.get().is_some()
1761 }
1762
1763 pub fn set_metatable(&self, mt: Option<GcRef<LuaTable>>) {
1767 let mode = mt.as_ref().map(|t| extract_weak_mode(t)).unwrap_or(0);
1768 self.weak_mode.set(mode);
1769 self.metatable.set(mt);
1770 }
1771
1772 pub fn weak_mode(&self) -> u8 {
1773 self.weak_mode.get()
1774 }
1775
1776 pub fn next_pair(&self, k: &LuaValue) -> Option<(LuaValue, LuaValue)> {
1778 let inner = self.inner.borrow();
1779 inner.next_pair(k).ok().flatten()
1780 }
1781
1782 pub fn try_next_pair(&self, k: &LuaValue) -> Result<Option<(LuaValue, LuaValue)>, LuaError> {
1785 let inner = self.inner.borrow();
1786 inner.next_pair(k)
1787 }
1788
1789 pub fn trace_entries_with_clearkey(&self, mut f: impl FnMut(&LuaValue)) {
1801 let mut inner = self.inner.borrow_mut();
1802 for v in inner.array.iter() {
1803 if !matches!(v, LuaValue::Nil) {
1804 f(v);
1805 }
1806 }
1807 for node in inner.node.iter_mut() {
1808 if matches!(node.value, LuaValue::Nil) {
1809 if !node.dead && gc_identity_bits(&node.key).is_some() {
1810 node.dead = true;
1811 }
1812 } else {
1813 f(&node.key);
1814 f(&node.value);
1815 }
1816 }
1817 }
1818
1819 pub fn for_each_entry(&self, mut f: impl FnMut(&LuaValue, &LuaValue)) {
1820 let inner = self.inner.borrow();
1821 for (i, v) in inner.array.iter().enumerate() {
1822 if !matches!(v, LuaValue::Nil) {
1823 let k = LuaValue::Int((i + 1) as i64);
1824 f(&k, v);
1825 }
1826 }
1827 for node in inner.node.iter() {
1828 if !matches!(node.value, LuaValue::Nil) {
1829 f(&node.key, &node.value);
1830 }
1831 }
1832 }
1833
1834 pub fn prune_weak_dead(&self, is_reachable: &dyn Fn(usize) -> bool) -> Vec<LuaValue> {
1838 self.prune_weak_dead_with(is_reachable, is_reachable)
1839 }
1840
1841 pub fn prune_weak_dead_with(
1846 &self,
1847 is_key_reachable: &dyn Fn(usize) -> bool,
1848 is_value_reachable: &dyn Fn(usize) -> bool,
1849 ) -> Vec<LuaValue> {
1850 self.prune_weak_dead_with_value(
1851 &|v| collectable_identity(v).map_or(true, is_key_reachable),
1852 &|v| collectable_identity(v).map_or(true, is_value_reachable),
1853 )
1854 }
1855
1856 pub fn prune_weak_dead_with_value(
1867 &self,
1868 is_key_reachable: &dyn Fn(&LuaValue) -> bool,
1869 is_value_reachable: &dyn Fn(&LuaValue) -> bool,
1870 ) -> Vec<LuaValue> {
1871 let mode = self.weak_mode.get();
1872 if mode == 0 {
1873 return Vec::new();
1874 }
1875 let weak_k = (mode & WEAK_KEYS) != 0;
1876 let weak_v = (mode & WEAK_VALUES) != 0;
1877 let mut to_mark: Vec<LuaValue> = Vec::new();
1878 let mut inner = self.inner.borrow_mut();
1879 for i in 0..inner.array.len() {
1880 let v = inner.array[i].clone();
1881 if matches!(v, LuaValue::Nil) {
1882 continue;
1883 }
1884 if weak_v && value_is_dead_collectable(&v, is_value_reachable) {
1885 inner.array[i] = LuaValue::Nil;
1886 continue;
1887 }
1888 if weak_v {
1889 if matches!(v, LuaValue::Str(_)) {
1890 to_mark.push(v);
1891 }
1892 }
1893 }
1894 let mut i = 0;
1895 while i < inner.node.len() {
1896 let v = inner.node[i].value.clone();
1897 if matches!(v, LuaValue::Nil) {
1898 if !inner.node[i].dead && gc_identity_bits(&inner.node[i].key).is_some() {
1899 inner.node[i].dead = true;
1900 }
1901 i += 1;
1902 continue;
1903 }
1904 let k = inner.node[i].key.clone();
1905 if weak_v && value_is_dead_collectable(&v, is_value_reachable) {
1906 inner.clear_dead_hash_node(i);
1907 continue;
1908 }
1909 if weak_k && value_is_dead_collectable(&k, is_key_reachable) {
1910 inner.clear_dead_hash_node(i);
1911 continue;
1912 }
1913 if weak_k {
1914 if matches!(k, LuaValue::Str(_)) {
1915 to_mark.push(k);
1916 }
1917 }
1918 if weak_v {
1919 if matches!(v, LuaValue::Str(_)) {
1920 to_mark.push(v);
1921 }
1922 }
1923 i += 1;
1924 }
1925 to_mark
1926 }
1927
1928 pub fn ephemeron_values_to_mark(&self, is_reachable: &dyn Fn(usize) -> bool) -> Vec<LuaValue> {
1930 self.ephemeron_values_to_mark_with_value(&|v| {
1931 collectable_identity(v).map_or(true, is_reachable)
1932 })
1933 }
1934
1935 pub fn ephemeron_values_to_mark_with_value(
1938 &self,
1939 is_reachable: &dyn Fn(&LuaValue) -> bool,
1940 ) -> Vec<LuaValue> {
1941 let mode = self.weak_mode.get();
1942 if (mode & WEAK_KEYS) == 0 || (mode & WEAK_VALUES) != 0 {
1943 return Vec::new();
1944 }
1945 let inner = self.inner.borrow();
1946 let mut out = Vec::new();
1947 for node in inner.node.iter() {
1948 if matches!(node.value, LuaValue::Nil) {
1949 continue;
1950 }
1951 if !value_is_dead_collectable(&node.key, is_reachable) {
1952 out.push(node.value.clone());
1953 }
1954 }
1955 for (i, v) in inner.array.iter().enumerate() {
1956 if matches!(v, LuaValue::Nil) {
1957 continue;
1958 }
1959 let k = LuaValue::Int((i + 1) as i64);
1960 if !value_is_dead_collectable(&k, is_reachable) {
1961 out.push(v.clone());
1962 }
1963 }
1964 out
1965 }
1966}
1967
1968fn value_is_dead_collectable(v: &LuaValue, is_reachable: &dyn Fn(&LuaValue) -> bool) -> bool {
1973 collectable_identity(v).is_some() && !is_reachable(v)
1974}
1975
1976fn gc_identity_bits(v: &LuaValue) -> Option<usize> {
1979 match v {
1980 LuaValue::Str(x) => Some(x.identity()),
1981 LuaValue::Table(x) => Some(x.identity()),
1982 LuaValue::UserData(x) => Some(x.identity()),
1983 LuaValue::Thread(x) => Some(x.identity()),
1984 LuaValue::Function(LuaClosure::Lua(x)) => Some(x.identity()),
1985 LuaValue::Function(LuaClosure::C(x)) => Some(x.identity()),
1986 LuaValue::Function(LuaClosure::LightC(_))
1987 | LuaValue::Nil
1988 | LuaValue::Bool(_)
1989 | LuaValue::Int(_)
1990 | LuaValue::Float(_)
1991 | LuaValue::LightUserData(_) => None,
1992 }
1993}
1994
1995fn collectable_identity(v: &LuaValue) -> Option<usize> {
1996 match v {
1997 LuaValue::Table(t) => Some(t.identity()),
1998 LuaValue::UserData(u) => Some(u.identity()),
1999 LuaValue::Thread(th) => Some(th.identity()),
2000 LuaValue::Function(c) => match c {
2001 LuaClosure::Lua(x) => Some(x.identity()),
2002 LuaClosure::C(x) => Some(x.identity()),
2003 LuaClosure::LightC(_) => None,
2004 },
2005 LuaValue::Str(_)
2006 | LuaValue::Nil
2007 | LuaValue::Bool(_)
2008 | LuaValue::Int(_)
2009 | LuaValue::Float(_)
2010 | LuaValue::LightUserData(_) => None,
2011 }
2012}
2013
2014fn extract_weak_mode(mt: &LuaTable) -> u8 {
2018 let inner = mt.inner.borrow();
2019 for node in inner.node.iter() {
2020 if node.dead {
2021 continue;
2022 }
2023 if let LuaValue::Str(ks) = &node.key {
2024 if ks.as_bytes() == b"__mode" {
2025 if let LuaValue::Str(vs) = &node.value {
2026 let bytes = vs.as_bytes();
2027 let mut mode = 0u8;
2028 if bytes.iter().any(|b| *b == b'k') {
2029 mode |= WEAK_KEYS;
2030 }
2031 if bytes.iter().any(|b| *b == b'v') {
2032 mode |= WEAK_VALUES;
2033 }
2034 return mode;
2035 }
2036 return 0;
2037 }
2038 }
2039 }
2040 0
2041}
2042
2043