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