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: Vec<LuaValue>,
285 pub node: Vec<TableNode>,
286 pub lastfree: u32,
291}
292
293pub const NO_LASTFREE: u32 = u32::MAX;
295
296impl TableInner {
297 fn new() -> Self {
298 TableInner {
299 flags: TableFlags(0x7F),
300 lsizenode: 0,
301 alimit: 0,
302 array: Vec::new(),
303 node: Vec::new(),
304 lastfree: NO_LASTFREE,
305 }
306 }
307
308 #[inline]
310 fn is_dummy(&self) -> bool {
311 self.lastfree == NO_LASTFREE
312 }
313
314 #[inline]
316 fn sizenode(&self) -> u32 {
317 1u32 << self.lsizenode
318 }
319
320 #[inline]
322 fn alloc_sizenode(&self) -> u32 {
323 if self.is_dummy() {
324 0
325 } else {
326 self.sizenode()
327 }
328 }
329
330 #[inline]
332 fn is_real_asize(&self) -> bool {
333 self.flags.is_real_asize()
334 }
335
336 #[inline]
338 fn is_pow2(x: u32) -> bool {
339 x == 0 || x.is_power_of_two()
340 }
341
342 fn real_asize(&self) -> u32 {
344 if self.limit_equals_asize() {
345 return self.alimit;
346 }
347 let mut size = self.alimit;
348 size |= size >> 1;
349 size |= size >> 2;
350 size |= size >> 4;
351 size |= size >> 8;
352 size |= size >> 16;
353 size = size.wrapping_add(1);
354 debug_assert!(Self::is_pow2(size) && size / 2 < self.alimit && self.alimit < size);
355 size
356 }
357
358 #[inline]
359 fn limit_equals_asize(&self) -> bool {
360 self.is_real_asize() || Self::is_pow2(self.alimit)
361 }
362
363 fn is_pow2_real_asize(&self) -> bool {
364 !self.is_real_asize() || Self::is_pow2(self.alimit)
365 }
366
367 fn set_limit_to_size(&mut self) -> u32 {
368 self.alimit = self.real_asize();
369 self.flags.set_real_asize();
370 self.alimit
371 }
372
373 fn hash_idx_for_int(&self, i: i64) -> usize {
376 let ui = i as u64;
377 let sn = self.sizenode() as usize;
378 let modulo = (sn - 1) | 1;
379 if ui <= i32::MAX as u64 {
380 (ui as usize) % modulo
381 } else {
382 (ui as usize) % modulo
383 }
384 }
385
386 #[inline]
387 fn hashpow2_idx(&self, h: u32) -> usize {
388 (h & (self.sizenode() - 1)) as usize
389 }
390
391 #[inline]
392 fn hashmod_idx(&self, h: usize) -> usize {
393 let sn = self.sizenode() as usize;
394 let modulo = (sn - 1) | 1;
395 h % modulo
396 }
397
398 fn main_position(&self, key: &LuaValue) -> usize {
399 match key {
400 LuaValue::Int(i) => self.hash_idx_for_int(*i),
401 LuaValue::Float(f) => {
402 let h = hash_float(*f);
403 self.hashmod_idx(h as usize)
404 }
405 LuaValue::Str(s) if s.is_short() => self.hashpow2_idx(s.hash()),
406 LuaValue::Str(s) => self.hashpow2_idx(s.hash()),
407 LuaValue::Bool(false) => self.hashpow2_idx(0),
408 LuaValue::Bool(true) => self.hashpow2_idx(1),
409 LuaValue::LightUserData(p) => {
410 let h = (*p as usize as u32) as usize;
411 self.hashmod_idx(h)
412 }
413 LuaValue::Function(LuaClosure::LightC(f)) => {
414 let h = (*f as u32) as usize;
415 self.hashmod_idx(h)
416 }
417 LuaValue::Table(t) => {
418 let h = (GcRef::identity(t) as u32) as usize;
419 self.hashmod_idx(h)
420 }
421 LuaValue::Function(LuaClosure::Lua(cl)) => {
422 let h = (GcRef::identity(cl) as u32) as usize;
423 self.hashmod_idx(h)
424 }
425 LuaValue::Function(LuaClosure::C(cl)) => {
426 let h = (GcRef::identity(cl) as u32) as usize;
427 self.hashmod_idx(h)
428 }
429 LuaValue::UserData(u) => {
430 let h = (GcRef::identity(u) as u32) as usize;
431 self.hashmod_idx(h)
432 }
433 LuaValue::Thread(th) => {
434 let h = (GcRef::identity(th) as u32) as usize;
435 self.hashmod_idx(h)
436 }
437 LuaValue::Nil => 0,
438 }
439 }
440
441 fn main_position_from_node(&self, nd: usize) -> usize {
442 let key = self.node[nd].key_value();
443 self.main_position(&key)
444 }
445
446 fn equal_key(k1: &LuaValue, n2: &TableNode) -> bool {
449 if n2.dead {
450 return false;
451 }
452 let types_match = std::mem::discriminant(k1) == std::mem::discriminant(&n2.key);
453 if !types_match {
454 return false;
455 }
456 match &n2.key {
457 LuaValue::Nil => true,
458 LuaValue::Bool(b) => matches!(k1, LuaValue::Bool(b2) if b == b2),
459 LuaValue::Int(ni) => matches!(k1, LuaValue::Int(ki) if ki == ni),
460 LuaValue::Float(nf) => matches!(k1, LuaValue::Float(kf) if kf == nf),
461 LuaValue::LightUserData(np) => matches!(k1, LuaValue::LightUserData(kp) if kp == np),
462 LuaValue::Function(LuaClosure::LightC(nf)) => {
463 matches!(k1, LuaValue::Function(LuaClosure::LightC(kf)) if kf == nf)
464 }
465 LuaValue::Str(ns) if ns.is_long() => {
466 if let LuaValue::Str(ks) = k1 {
467 lua_string_content_eq(ks, ns)
468 } else {
469 false
470 }
471 }
472 _ => Self::gc_ptr_eq(k1, &n2.key),
473 }
474 }
475
476 fn gc_ptr_eq(a: &LuaValue, b: &LuaValue) -> bool {
477 match (a, b) {
478 (LuaValue::Str(sa), LuaValue::Str(sb)) => GcRef::ptr_eq(sa, sb),
479 (LuaValue::Table(ta), LuaValue::Table(tb)) => GcRef::ptr_eq(ta, tb),
480 (LuaValue::Function(LuaClosure::Lua(fa)), LuaValue::Function(LuaClosure::Lua(fb))) => {
481 GcRef::ptr_eq(fa, fb)
482 }
483 (LuaValue::Function(LuaClosure::C(fa)), LuaValue::Function(LuaClosure::C(fb))) => {
484 GcRef::ptr_eq(fa, fb)
485 }
486 (LuaValue::UserData(ua), LuaValue::UserData(ub)) => GcRef::ptr_eq(ua, ub),
487 (LuaValue::Thread(ta), LuaValue::Thread(tb)) => GcRef::ptr_eq(ta, tb),
488 _ => false,
489 }
490 }
491
492 fn get_generic_slot(&self, key: &LuaValue) -> TableSlotRef {
495 if self.is_dummy() {
496 return TableSlotRef::Absent;
497 }
498 let mut n = self.main_position(key);
499 loop {
500 if Self::equal_key(key, &self.node[n]) {
501 return TableSlotRef::Hash(n);
502 }
503 let nx = self.node[n].next;
504 if nx == 0 {
505 return TableSlotRef::Absent;
506 }
507 n = (n as isize + nx as isize) as usize;
508 }
509 }
510
511 fn get_generic_slot_deadok(&self, key: &LuaValue) -> TableSlotRef {
518 if self.is_dummy() {
519 return TableSlotRef::Absent;
520 }
521 let mut n = self.main_position(key);
522 loop {
523 let node = &self.node[n];
524 let matched = if node.dead {
525 match (gc_identity_bits(key), gc_identity_bits(&node.key)) {
526 (Some(a), Some(b)) => a == b,
527 _ => false,
528 }
529 } else {
530 Self::equal_key(key, node)
531 };
532 if matched {
533 return TableSlotRef::Hash(n);
534 }
535 let nx = node.next;
536 if nx == 0 {
537 return TableSlotRef::Absent;
538 }
539 n = (n as isize + nx as isize) as usize;
540 }
541 }
542
543 fn array_index(k: i64) -> u32 {
546 let uk = k as u64;
547 if uk.wrapping_sub(1) < MAXASIZE as u64 {
548 k as u32
549 } else {
550 0
551 }
552 }
553
554 fn find_index(&self, key: &LuaValue, asize: u32) -> Result<u32, LuaError> {
558 if matches!(key, LuaValue::Nil) {
559 return Ok(0);
560 }
561 let i = if let LuaValue::Int(k) = key {
562 Self::array_index(*k)
563 } else {
564 0
565 };
566 if i.wrapping_sub(1) < asize {
567 return Ok(i);
568 }
569 let slot = self.get_generic_slot_deadok(key);
570 match slot {
571 TableSlotRef::Absent => Err(LuaError::runtime(format_args!("invalid key to 'next'"))),
572 TableSlotRef::Hash(node_idx) => Ok((node_idx as u32 + 1) + asize),
573 TableSlotRef::Array(_) => unreachable!("getgeneric returned Array slot"),
574 }
575 }
576
577 fn next_pair(&self, key: &LuaValue) -> Result<Option<(LuaValue, LuaValue)>, LuaError> {
580 let asize = self.real_asize();
581 let i = self.find_index(key, asize)?;
582 let mut i = i as usize;
583 while i < asize as usize {
584 if !matches!(self.array[i], LuaValue::Nil) {
585 return Ok(Some((LuaValue::Int((i + 1) as i64), self.array[i].clone())));
586 }
587 i += 1;
588 }
589 let mut hi = i.saturating_sub(asize as usize);
590 while hi < self.node.len() {
591 if !matches!(self.node[hi].value, LuaValue::Nil) {
592 return Ok(Some((
593 self.node[hi].key_value(),
594 self.node[hi].value.clone(),
595 )));
596 }
597 hi += 1;
598 }
599 Ok(None)
600 }
601
602 fn compute_sizes(nums: &[u32], pna: &mut u32) -> u32 {
605 let mut twotoi: u32 = 1;
606 let mut a: u32 = 0;
607 let mut na: u32 = 0;
608 let mut optimal: u32 = 0;
609 for i in 0..nums.len() {
610 if twotoi == 0 || *pna <= twotoi / 2 {
611 break;
612 }
613 a += nums[i];
614 if a > twotoi / 2 {
615 optimal = twotoi;
616 na = a;
617 }
618 twotoi = twotoi.wrapping_mul(2);
619 }
620 debug_assert!(optimal == 0 || optimal / 2 < na && na <= optimal);
621 *pna = na;
622 optimal
623 }
624
625 fn count_int(key: i64, nums: &mut [u32]) -> bool {
626 let k = Self::array_index(key);
627 if k != 0 {
628 nums[ceil_log2(k) as usize] += 1;
629 true
630 } else {
631 false
632 }
633 }
634
635 fn num_use_array(&self, nums: &mut [u32]) -> u32 {
636 debug_assert!(
637 self.is_real_asize(),
638 "numusearray: alimit must be real size"
639 );
640 let asize = self.alimit as usize;
641 let mut ause: u32 = 0;
642 let mut i: usize = 1;
643 let mut ttlg: usize = 1;
644 for lg in 0..=(MAXABITS as usize) {
645 let mut lc: u32 = 0;
646 let lim = if ttlg > asize { asize } else { ttlg };
647 if i > lim {
648 break;
649 }
650 while i <= lim {
651 if !matches!(self.array[i - 1], LuaValue::Nil) {
652 lc += 1;
653 }
654 i += 1;
655 }
656 nums[lg] += lc;
657 ause += lc;
658 ttlg = ttlg.saturating_mul(2);
659 }
660 ause
661 }
662
663 fn num_use_hash(&self, nums: &mut [u32], pna: &mut u32) -> i32 {
664 let mut totaluse: i32 = 0;
665 let mut ause: u32 = 0;
666 let mut i = self.node.len();
667 while i > 0 {
668 i -= 1;
669 let n = &self.node[i];
670 if !matches!(n.value, LuaValue::Nil) {
671 if n.key_is_int() {
672 if Self::count_int(n.key_int(), nums) {
673 ause += 1;
674 }
675 }
676 totaluse += 1;
677 }
678 }
679 *pna += ause;
680 totaluse
681 }
682
683 fn set_node_vector(&mut self, size: u32) -> Result<(), LuaError> {
684 if size == 0 {
685 self.node = Vec::new();
686 self.lsizenode = 0;
687 self.lastfree = NO_LASTFREE;
688 } else {
689 let lsize = ceil_log2(size);
690 if lsize as u32 > MAXHBITS || (1u32 << lsize) > MAXHSIZE {
691 return Err(LuaError::runtime(format_args!("table overflow")));
692 }
693 let actual_size = 1u32 << lsize;
694 let mut nodes = Vec::with_capacity(actual_size as usize);
695 for _ in 0..actual_size {
696 nodes.push(TableNode::empty());
697 }
698 self.node = nodes;
699 self.lsizenode = lsize as u8;
700 self.lastfree = actual_size;
701 }
702 Ok(())
703 }
704
705 fn reinsert(&mut self, old_nodes: Vec<(LuaValue, LuaValue)>) -> Result<(), LuaError> {
706 for (k, v) in old_nodes {
707 self.set(&k, v)?;
708 }
709 Ok(())
710 }
711
712 fn resize(&mut self, new_asize: u32, nhsize: u32) -> Result<(), LuaError> {
714 let old_asize = self.set_limit_to_size();
715
716 let (mut new_hash_node, mut new_hash_lsize, mut new_hash_lastfree) = {
717 let mut tmp = TableInner::new();
718 tmp.set_node_vector(nhsize)?;
719 (tmp.node, tmp.lsizenode, tmp.lastfree)
720 };
721
722 if new_asize < old_asize {
723 let migrate_end = (old_asize as usize).min(self.array.len());
724 let detached: Vec<(i64, LuaValue)> = ((new_asize as usize)..migrate_end)
725 .filter(|&i| !matches!(self.array[i], LuaValue::Nil))
726 .map(|i| ((i + 1) as i64, self.array[i].clone()))
727 .collect();
728 self.array.truncate(new_asize as usize);
729 self.alimit = new_asize;
730
731 std::mem::swap(&mut self.node, &mut new_hash_node);
732 std::mem::swap(&mut self.lsizenode, &mut new_hash_lsize);
733 std::mem::swap(&mut self.lastfree, &mut new_hash_lastfree);
734
735 for (key, v) in detached {
736 self.set_int(key, v)?;
737 }
738
739 self.alimit = old_asize;
740 std::mem::swap(&mut self.node, &mut new_hash_node);
741 std::mem::swap(&mut self.lsizenode, &mut new_hash_lsize);
742 std::mem::swap(&mut self.lastfree, &mut new_hash_lastfree);
743 }
744
745 self.array.resize_with(new_asize as usize, || LuaValue::Nil);
746
747 std::mem::swap(&mut self.node, &mut new_hash_node);
748 std::mem::swap(&mut self.lsizenode, &mut new_hash_lsize);
749 std::mem::swap(&mut self.lastfree, &mut new_hash_lastfree);
750 self.alimit = new_asize;
751
752 let old_hash_entries: Vec<(LuaValue, LuaValue)> = new_hash_node
753 .iter()
754 .filter(|n| !matches!(n.value, LuaValue::Nil))
755 .map(|n| (n.key_value(), n.value.clone()))
756 .collect();
757 drop(new_hash_node);
758 self.reinsert(old_hash_entries)?;
759
760 Ok(())
761 }
762
763 fn rehash(&mut self, extra_key: &LuaValue) -> Result<(), LuaError> {
764 let mut nums = [0u32; MAXABITS as usize + 1];
765 self.set_limit_to_size();
766
767 let na = self.num_use_array(&mut nums);
768 let mut na = na;
769 let mut totaluse = na as i32;
770
771 totaluse += self.num_use_hash(&mut nums, &mut na);
772
773 if let LuaValue::Int(ek) = extra_key {
774 if Self::count_int(*ek, &mut nums) {
775 na += 1;
776 }
777 }
778 totaluse += 1;
779
780 let asize = Self::compute_sizes(&nums, &mut na);
781
782 let nh = (totaluse - na as i32).max(0) as u32;
783 self.resize(asize, nh)
784 }
785
786 fn get_free_pos(&mut self) -> Option<usize> {
787 if self.is_dummy() {
788 return None;
789 }
790 loop {
791 if self.lastfree == NO_LASTFREE {
792 return None;
793 }
794 if self.lastfree == 0 {
795 self.lastfree = NO_LASTFREE;
796 return None;
797 }
798 let idx = (self.lastfree - 1) as usize;
799 self.lastfree = idx as u32;
800 if self.node[idx].key_is_nil() {
801 return Some(idx);
802 }
803 }
804 }
805
806 fn find_chain_predecessor(&self, idx: usize) -> Option<usize> {
807 self.node
808 .iter()
809 .enumerate()
810 .find(|(prev, node)| {
811 node.next != 0 && (*prev as isize + node.next as isize) == idx as isize
812 })
813 .map(|(prev, _)| prev)
814 }
815
816 fn clear_node(&mut self, idx: usize) {
817 self.node[idx].key = LuaValue::Nil;
818 self.node[idx].value = LuaValue::Nil;
819 self.node[idx].next = 0;
820 }
821
822 fn remove_hash_node(&mut self, idx: usize) {
823 if let Some(prev) = self.find_chain_predecessor(idx) {
824 let next = self.node[idx].next;
825 self.node[prev].next = if next == 0 {
826 0
827 } else {
828 let target = idx as isize + next as isize;
829 (target - prev as isize) as i32
830 };
831 self.clear_node(idx);
832 return;
833 }
834
835 let next = self.node[idx].next;
836 if next == 0 {
837 self.clear_node(idx);
838 return;
839 }
840
841 let next_idx = (idx as isize + next as isize) as usize;
842 let moved_next = self.node[next_idx].next;
843 let moved_key = self.node[next_idx].key_value();
844 let moved_value = self.node[next_idx].value.clone();
845 self.node[idx].key = moved_key;
846 self.node[idx].value = moved_value;
847 self.node[idx].next = if moved_next == 0 {
848 0
849 } else {
850 let target = next_idx as isize + moved_next as isize;
851 (target - idx as isize) as i32
852 };
853 self.clear_node(next_idx);
854 }
855
856 fn clear_dead_hash_node(&mut self, idx: usize) {
857 self.remove_hash_node(idx);
858 }
859
860 fn new_key(&mut self, key: &LuaValue, value: LuaValue) -> Result<(), LuaError> {
861 if matches!(key, LuaValue::Nil) {
862 return Err(LuaError::runtime(format_args!("table index is nil")));
863 }
864 let normalised_key;
865 let key = if let LuaValue::Float(f) = key {
866 let f = *f;
867 if f.is_nan() {
868 return Err(LuaError::runtime(format_args!("table index is NaN")));
869 }
870 let k = f as i64;
871 if k as f64 == f {
872 normalised_key = LuaValue::Int(k);
873 &normalised_key
874 } else {
875 key
876 }
877 } else {
878 key
879 };
880
881 if matches!(value, LuaValue::Nil) {
882 return Ok(());
883 }
884
885 if self.is_dummy() && !matches!(key, LuaValue::Int(_)) {
886 self.set_node_vector(DUMMY_TABLE_INIT_HASH_NODES)?;
887 let mp = self.main_position(key);
888 self.node[mp].set_key(key);
889 self.node[mp].value = value;
890 return Ok(());
891 }
892
893 let mp = self.main_position(key);
894 let mp_occupied = self.is_dummy() || !matches!(self.node[mp].value, LuaValue::Nil);
895 if mp_occupied {
896 let f = self.get_free_pos();
897 let f = match f {
898 None => {
899 self.rehash(key)?;
900 return self.set(key, value);
901 }
902 Some(idx) => idx,
903 };
904
905 debug_assert!(!self.is_dummy());
906 let othern = self.main_position_from_node(mp);
907
908 if othern != mp {
909 let mut prev = othern;
910 let mut steps = 0usize;
911 while (prev as isize + self.node[prev].next as isize) as usize != mp {
912 steps += 1;
913 if steps > self.node.len() {
914 panic!(
915 "table hash chain invariant broken: node {} unreachable from main position {} \
916 ({} nodes; usually a missing GC key barrier — see ltable.c:717 parity note)",
917 mp,
918 othern,
919 self.node.len()
920 );
921 }
922 prev = (prev as isize + self.node[prev].next as isize) as usize;
923 }
924 self.node[prev].next = (f as isize - prev as isize) as i32;
925 let mp_key = self.node[mp].key_value();
926 let mp_val = self.node[mp].value.clone();
927 let mp_next = self.node[mp].next;
928 self.node[f].key = mp_key;
929 self.node[f].value = mp_val;
930 if mp_next != 0 {
931 self.node[f].next = mp_next + (mp as isize - f as isize) as i32;
932 self.node[mp].next = 0;
933 } else {
934 self.node[f].next = 0;
935 }
936 self.node[mp].value = LuaValue::Nil;
937 } else {
938 if self.node[mp].next != 0 {
939 let target = (mp as isize + self.node[mp].next as isize) as usize;
940 self.node[f].next = (target as isize - f as isize) as i32;
941 } else {
942 debug_assert!(self.node[f].next == 0);
943 }
944 self.node[mp].next = (f as isize - mp as isize) as i32;
945 self.node[f].set_key(key);
946 debug_assert!(matches!(self.node[f].value, LuaValue::Nil));
947 self.node[f].value = value;
948 return Ok(());
949 }
950 }
951 self.node[mp].set_key(key);
952 debug_assert!(matches!(self.node[mp].value, LuaValue::Nil));
953 self.node[mp].value = value;
954 Ok(())
955 }
956
957 fn get_int_slot(&self, key: i64) -> TableSlotRef {
958 let alimit = self.alimit as u64;
959 let uk = key as u64;
960 if uk.wrapping_sub(1) < alimit {
961 return TableSlotRef::Array((key - 1) as usize);
962 }
963 if !self.is_real_asize() && alimit > 0 {
964 let masked = (uk.wrapping_sub(1)) & !(alimit.wrapping_sub(1));
965 if masked < alimit {
966 return TableSlotRef::Array((key - 1) as usize);
967 }
968 }
969 if self.is_dummy() {
970 return TableSlotRef::Absent;
971 }
972 let mut n = self.hash_idx_for_int(key);
973 loop {
974 if self.node[n].key_is_int() && self.node[n].key_int() == key {
975 return TableSlotRef::Hash(n);
976 }
977 let nx = self.node[n].next;
978 if nx == 0 {
979 break;
980 }
981 n = (n as isize + nx as isize) as usize;
982 }
983 TableSlotRef::Absent
984 }
985
986 #[inline]
993 fn get_int_value(&self, key: i64) -> LuaValue {
994 let alimit = self.alimit as u64;
995 let uk = key as u64;
996 if uk.wrapping_sub(1) < alimit {
997 return self.array[(key - 1) as usize].clone();
998 }
999 self.get_int_value_cold(key)
1000 }
1001
1002 #[cold]
1003 #[inline(never)]
1004 fn get_int_value_cold(&self, key: i64) -> LuaValue {
1005 let alimit = self.alimit as u64;
1006 let uk = key as u64;
1007 if !self.is_real_asize() && alimit > 0 {
1008 let masked = (uk.wrapping_sub(1)) & !(alimit.wrapping_sub(1));
1009 if masked < alimit {
1010 return self.array[(key - 1) as usize].clone();
1011 }
1012 }
1013 if self.is_dummy() {
1014 return LuaValue::Nil;
1015 }
1016 let mut n = self.hash_idx_for_int(key);
1017 loop {
1018 if self.node[n].key_is_int() && self.node[n].key_int() == key {
1019 return self.node[n].value.clone();
1020 }
1021 let nx = self.node[n].next;
1022 if nx == 0 {
1023 break;
1024 }
1025 n = (n as isize + nx as isize) as usize;
1026 }
1027 LuaValue::Nil
1028 }
1029
1030 #[inline(always)]
1031 fn get_short_str_slot(&self, key: &GcRef<LuaString>) -> TableSlotRef {
1032 debug_assert!(key.is_short());
1033 if self.is_dummy() {
1034 return TableSlotRef::Absent;
1035 }
1036 let mut n = self.hashpow2_idx(key.hash());
1037 loop {
1038 if self.node[n].key_is_short_str() {
1039 let ks = self.node[n].key_string();
1040 if lua_string_content_eq(ks, key) {
1041 return TableSlotRef::Hash(n);
1042 }
1043 }
1044 let nx = self.node[n].next;
1045 if nx == 0 {
1046 return TableSlotRef::Absent;
1047 }
1048 n = (n as isize + nx as isize) as usize;
1049 }
1050 }
1051
1052 #[inline(always)]
1053 fn try_update_short_str(
1054 &mut self,
1055 key: &GcRef<LuaString>,
1056 value: LuaValue,
1057 ) -> Result<(), LuaValue> {
1058 debug_assert!(key.is_short());
1059 if self.is_dummy() {
1060 return Err(value);
1061 }
1062 let mut n = self.hashpow2_idx(key.hash());
1063 loop {
1064 if self.node[n].key_is_short_str() {
1065 let ks = self.node[n].key_string();
1066 if lua_string_content_eq(ks, key) {
1067 self.node[n].value = value;
1068 return Ok(());
1069 }
1070 }
1071 let nx = self.node[n].next;
1072 if nx == 0 {
1073 return Err(value);
1074 }
1075 n = (n as isize + nx as isize) as usize;
1076 }
1077 }
1078
1079 #[inline(always)]
1080 fn try_update_int(&mut self, key: i64, value: LuaValue) -> Result<(), LuaValue> {
1081 let alimit = self.alimit as u64;
1082 let uk = key as u64;
1083 if uk.wrapping_sub(1) < alimit {
1084 self.array[(key - 1) as usize] = value;
1085 return Ok(());
1086 }
1087 if !self.is_real_asize() && alimit > 0 {
1088 let masked = (uk.wrapping_sub(1)) & !(alimit.wrapping_sub(1));
1089 if masked < alimit {
1090 self.array[(key - 1) as usize] = value;
1091 return Ok(());
1092 }
1093 }
1094 if !self.is_dummy() {
1095 let mut n = self.hash_idx_for_int(key);
1096 loop {
1097 if self.node[n].key_is_int() && self.node[n].key_int() == key {
1098 self.node[n].value = value;
1099 return Ok(());
1100 }
1101 let nx = self.node[n].next;
1102 if nx == 0 {
1103 break;
1104 }
1105 n = (n as isize + nx as isize) as usize;
1106 }
1107 }
1108 Err(value)
1109 }
1110
1111 #[inline]
1119 fn get_str_value(&self, key: &GcRef<LuaString>) -> LuaValue {
1120 debug_assert!(key.is_short());
1121 if self.is_dummy() {
1122 return LuaValue::Nil;
1123 }
1124 let mut n = self.hashpow2_idx(key.hash());
1125 loop {
1126 if self.node[n].key_is_short_str() {
1127 let ks = self.node[n].key_string();
1128 if lua_string_content_eq(ks, key) {
1129 return self.node[n].value.clone();
1130 }
1131 }
1132 let nx = self.node[n].next;
1133 if nx == 0 {
1134 return LuaValue::Nil;
1135 }
1136 n = (n as isize + nx as isize) as usize;
1137 }
1138 }
1139
1140 #[cold]
1145 #[inline(never)]
1146 fn get_generic_value(&self, key: &LuaValue) -> LuaValue {
1147 let slot = self.get_slot(key);
1148 self.slot_value(slot)
1149 }
1150
1151 fn get_str_slot(&self, key: &GcRef<LuaString>) -> TableSlotRef {
1152 if key.is_short() {
1153 self.get_short_str_slot(key)
1154 } else {
1155 let ko = LuaValue::Str(key.clone());
1156 self.get_generic_slot(&ko)
1157 }
1158 }
1159
1160 fn get_slot(&self, key: &LuaValue) -> TableSlotRef {
1161 match key {
1162 LuaValue::Str(s) if s.is_short() => self.get_short_str_slot(s),
1163 LuaValue::Int(i) => self.get_int_slot(*i),
1164 LuaValue::Nil => TableSlotRef::Absent,
1165 LuaValue::Float(f) => {
1166 let f = *f;
1167 let k = f as i64;
1168 if k as f64 == f {
1169 self.get_int_slot(k)
1170 } else {
1171 self.get_generic_slot(key)
1172 }
1173 }
1174 _ => self.get_generic_slot(key),
1175 }
1176 }
1177
1178 fn slot_value(&self, slot: TableSlotRef) -> LuaValue {
1179 match slot {
1180 TableSlotRef::Array(i) => self.array[i].clone(),
1181 TableSlotRef::Hash(i) => self.node[i].value.clone(),
1182 TableSlotRef::Absent => LuaValue::Nil,
1183 }
1184 }
1185
1186 fn finish_set(
1187 &mut self,
1188 key: &LuaValue,
1189 slot: TableSlotRef,
1190 value: LuaValue,
1191 ) -> Result<(), LuaError> {
1192 match slot {
1193 TableSlotRef::Absent => self.new_key(key, value),
1194 TableSlotRef::Array(i) => {
1195 self.array[i] = value;
1196 Ok(())
1197 }
1198 TableSlotRef::Hash(i) => {
1199 self.node[i].value = value;
1200 Ok(())
1201 }
1202 }
1203 }
1204
1205 fn set(&mut self, key: &LuaValue, value: LuaValue) -> Result<(), LuaError> {
1206 let slot = self.get_slot(key);
1207 self.finish_set(key, slot, value)
1208 }
1209
1210 fn set_int(&mut self, key: i64, value: LuaValue) -> Result<(), LuaError> {
1214 let slot = self.get_int_slot(key);
1215 if matches!(slot, TableSlotRef::Absent) {
1216 if key > 0 && (key as u64) <= ARRAY_GROW_CAP as u64 {
1217 let cur = self.alimit as i64;
1218 if key == cur + 1 && !matches!(value, LuaValue::Nil) {
1219 let new_size = (key as u32).next_power_of_two().max(4);
1220 let capped = new_size.min(ARRAY_GROW_CAP);
1221 if capped > self.alimit {
1222 let nsize = self.alloc_sizenode();
1223 self.resize(capped, nsize)?;
1224 let new_slot = self.get_int_slot(key);
1225 return self.finish_set(&LuaValue::Int(key), new_slot, value);
1226 }
1227 }
1228 }
1229 }
1230 match slot {
1231 TableSlotRef::Absent => {
1232 let k = LuaValue::Int(key);
1233 self.new_key(&k, value)
1234 }
1235 TableSlotRef::Array(i) => {
1236 self.array[i] = value;
1237 Ok(())
1238 }
1239 TableSlotRef::Hash(i) => {
1240 self.node[i].value = value;
1241 Ok(())
1242 }
1243 }
1244 }
1245
1246 #[inline]
1253 fn try_raw_set_int_fast(&mut self, key: i64, value: LuaValue) -> Result<(), LuaError> {
1254 let alimit = self.alimit as u64;
1255 let uk = key as u64;
1256 if uk.wrapping_sub(1) < alimit {
1257 self.array[(key - 1) as usize] = value;
1258 return Ok(());
1259 }
1260 self.try_raw_set_int_cold(key, value)
1261 }
1262
1263 #[cold]
1264 #[inline(never)]
1265 fn try_raw_set_int_cold(&mut self, key: i64, value: LuaValue) -> Result<(), LuaError> {
1266 if self.array.len() + self.node.len() >= TOTAL_GROW_CAP
1267 && matches!(self.get_int_slot(key), TableSlotRef::Absent)
1268 {
1269 return Err(LuaError::Memory);
1270 }
1271 self.set_int_value_cold(key, value)
1272 }
1273
1274 #[cold]
1281 #[inline(never)]
1282 fn set_int_value_cold(&mut self, key: i64, value: LuaValue) -> Result<(), LuaError> {
1283 let alimit = self.alimit as u64;
1284 let uk = key as u64;
1285 if !self.is_real_asize() && alimit > 0 {
1286 let masked = (uk.wrapping_sub(1)) & !(alimit.wrapping_sub(1));
1287 if masked < alimit {
1288 self.array[(key - 1) as usize] = value;
1289 return Ok(());
1290 }
1291 }
1292 if !self.is_dummy() {
1293 let mut n = self.hash_idx_for_int(key);
1294 loop {
1295 if self.node[n].key_is_int() && self.node[n].key_int() == key {
1296 self.node[n].value = value;
1297 return Ok(());
1298 }
1299 let nx = self.node[n].next;
1300 if nx == 0 {
1301 break;
1302 }
1303 n = (n as isize + nx as isize) as usize;
1304 }
1305 }
1306 if key > 0 && (key as u64) <= ARRAY_GROW_CAP as u64 {
1307 let cur = self.alimit as i64;
1308 if key == cur + 1 && !matches!(value, LuaValue::Nil) {
1309 let new_size = (key as u32).next_power_of_two().max(4);
1310 let capped = new_size.min(ARRAY_GROW_CAP);
1311 if capped > self.alimit {
1312 let nsize = self.alloc_sizenode();
1313 self.resize(capped, nsize)?;
1314 let new_slot = self.get_int_slot(key);
1315 return self.finish_set(&LuaValue::Int(key), new_slot, value);
1316 }
1317 }
1318 }
1319 let k = LuaValue::Int(key);
1320 self.new_key(&k, value)
1321 }
1322
1323 fn hash_search(&self, mut j: u64) -> u64 {
1326 let mut i: u64;
1327 if j == 0 {
1328 j = 1;
1329 }
1330 loop {
1331 i = j;
1332 if j <= (i64::MAX as u64) / 2 {
1333 j *= 2;
1334 } else {
1335 j = i64::MAX as u64;
1336 let s = self.get_int_slot(j as i64);
1337 if matches!(s, TableSlotRef::Absent) || matches!(self.slot_value(s), LuaValue::Nil)
1338 {
1339 break;
1340 } else {
1341 return j;
1342 }
1343 }
1344 let s = self.get_int_slot(j as i64);
1345 if matches!(s, TableSlotRef::Absent) {
1346 break;
1347 }
1348 if matches!(self.slot_value(s), LuaValue::Nil) {
1349 break;
1350 }
1351 }
1352 while j - i > 1 {
1353 let m = i / 2 + j / 2;
1354 let s = self.get_int_slot(m as i64);
1355 let empty =
1356 matches!(s, TableSlotRef::Absent) || matches!(self.slot_value(s), LuaValue::Nil);
1357 if empty {
1358 j = m;
1359 } else {
1360 i = m;
1361 }
1362 }
1363 i
1364 }
1365
1366 fn bin_search(array: &[LuaValue], mut i: u32, mut j: u32) -> u32 {
1367 while j - i > 1 {
1368 let m = (i + j) / 2;
1369 if matches!(array[(m - 1) as usize], LuaValue::Nil) {
1370 j = m;
1371 } else {
1372 i = m;
1373 }
1374 }
1375 i
1376 }
1377
1378 fn getn(&mut self) -> u64 {
1381 let limit = self.alimit;
1382 if limit > 0 && matches!(self.array[(limit - 1) as usize], LuaValue::Nil) {
1383 if limit >= 2 && !matches!(self.array[(limit - 2) as usize], LuaValue::Nil) {
1384 if self.is_pow2_real_asize() && !Self::is_pow2(limit - 1) {
1385 self.alimit = limit - 1;
1386 self.flags.set_no_real_asize();
1387 }
1388 return (limit - 1) as u64;
1389 } else {
1390 let boundary = Self::bin_search(&self.array, 0, limit);
1391 if self.is_pow2_real_asize() && boundary > self.real_asize() / 2 {
1392 self.alimit = boundary;
1393 self.flags.set_no_real_asize();
1394 }
1395 return boundary as u64;
1396 }
1397 }
1398 if !self.limit_equals_asize() {
1399 if matches!(self.array[limit as usize], LuaValue::Nil) {
1400 return limit as u64;
1401 }
1402 let real = self.real_asize();
1403 if matches!(self.array[(real - 1) as usize], LuaValue::Nil) {
1404 let old_alimit = self.alimit;
1405 let boundary = Self::bin_search(&self.array, old_alimit, real);
1406 self.alimit = boundary;
1407 return boundary as u64;
1408 }
1409 }
1410 let limit = self.real_asize();
1411 debug_assert!(
1412 limit == self.real_asize()
1413 && (limit == 0 || !matches!(self.array[(limit - 1) as usize], LuaValue::Nil))
1414 );
1415 let next_key = (limit as i64).saturating_add(1);
1416 let next_slot = self.get_int_slot(next_key);
1417 let next_empty = matches!(next_slot, TableSlotRef::Absent)
1418 || matches!(self.slot_value(next_slot), LuaValue::Nil);
1419 if self.is_dummy() || next_empty {
1420 return limit as u64;
1421 }
1422 self.hash_search(limit as u64)
1423 }
1424}
1425
1426#[derive(Debug)]
1434pub struct LuaTable {
1435 inner: RefCell<TableInner>,
1436 metatable: Cell<Option<GcRef<LuaTable>>>,
1440 weak_mode: Cell<u8>,
1441}
1442
1443impl std::fmt::Debug for TableInner {
1444 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1445 f.debug_struct("TableInner")
1446 .field("alimit", &self.alimit)
1447 .field("array_len", &self.array.len())
1448 .field("node_len", &self.node.len())
1449 .finish()
1450 }
1451}
1452
1453impl Default for LuaTable {
1454 fn default() -> Self {
1455 LuaTable {
1456 inner: RefCell::new(TableInner::new()),
1457 metatable: Cell::new(None),
1458 weak_mode: Cell::new(0),
1459 }
1460 }
1461}
1462
1463impl LuaTable {
1464 pub fn placeholder() -> Self {
1467 Self::default()
1468 }
1469
1470 pub fn with_inner<R>(&self, f: impl FnOnce(&TableInner) -> R) -> R {
1473 f(&self.inner.borrow())
1474 }
1475
1476 pub fn buffer_bytes(&self) -> usize {
1481 let inner = self.inner.borrow();
1482 inner.array.capacity() * std::mem::size_of::<LuaValue>()
1483 + inner.node.capacity() * std::mem::size_of::<TableNode>()
1484 }
1485
1486 #[inline(always)]
1496 pub fn get(&self, k: &LuaValue) -> LuaValue {
1497 let inner = self.inner.borrow();
1498 match k {
1499 LuaValue::Nil => LuaValue::Nil,
1500 LuaValue::Int(i) => inner.get_int_value(*i),
1501 LuaValue::Str(s) if s.is_short() => inner.get_str_value(s),
1502 _ => inner.get_generic_value(k),
1503 }
1504 }
1505
1506 #[inline(always)]
1512 pub fn get_int(&self, key: i64) -> LuaValue {
1513 let inner = self.inner.borrow();
1514 inner.get_int_value(key)
1515 }
1516
1517 #[inline(always)]
1525 pub fn get_short_str(&self, k: &GcRef<LuaString>) -> LuaValue {
1526 let inner = self.inner.borrow();
1527 if k.is_short() {
1528 inner.get_str_value(k)
1529 } else {
1530 let slot = inner.get_str_slot(k);
1531 inner.slot_value(slot)
1532 }
1533 }
1534
1535 pub fn get_str_bytes(&self, key_bytes: &[u8]) -> LuaValue {
1539 let mut found = LuaValue::Nil;
1540 self.for_each_entry(|k, v| {
1541 if !matches!(found, LuaValue::Nil) {
1542 return;
1543 }
1544 if let LuaValue::Str(s) = k {
1545 if s.as_bytes() == key_bytes {
1546 found = v.clone();
1547 }
1548 }
1549 });
1550 found
1551 }
1552
1553 pub fn raw_set(&self, k: LuaValue, v: LuaValue) {
1556 if matches!(k, LuaValue::Nil) {
1557 return;
1558 }
1559 if let LuaValue::Float(f) = &k {
1560 if f.is_nan() {
1561 return;
1562 }
1563 }
1564 let mut inner = self.inner.borrow_mut();
1565 let _ = inner.set(&k, v);
1566 }
1567
1568 #[inline]
1574 pub fn try_raw_set(&self, k: LuaValue, v: LuaValue) -> Result<(), LuaError> {
1575 match &k {
1576 LuaValue::Nil => Err(LuaError::runtime(format_args!("table index is nil"))),
1577 LuaValue::Float(f) if f.is_nan() => {
1578 Err(LuaError::runtime(format_args!("table index is NaN")))
1579 }
1580 LuaValue::Int(i) => {
1581 let key = *i;
1582 let mut inner = self.inner.borrow_mut();
1583 inner.try_raw_set_int_fast(key, v)
1584 }
1585 LuaValue::Float(f) => {
1586 let f = *f;
1587 let k_int = f as i64;
1588 if k_int as f64 == f {
1589 let mut inner = self.inner.borrow_mut();
1590 inner.try_raw_set_int_fast(k_int, v)
1591 } else {
1592 self.try_raw_set_generic(k, v)
1593 }
1594 }
1595 _ => self.try_raw_set_generic(k, v),
1596 }
1597 }
1598
1599 #[inline(always)]
1603 pub fn try_update_short_str(&self, k: &GcRef<LuaString>, v: LuaValue) -> Result<(), LuaValue> {
1604 if !k.is_short() {
1605 return Err(v);
1606 }
1607 let mut inner = self.inner.borrow_mut();
1608 inner.try_update_short_str(k, v)
1609 }
1610
1611 #[inline(always)]
1615 pub fn try_update_int(&self, k: i64, v: LuaValue) -> Result<(), LuaValue> {
1616 let mut inner = self.inner.borrow_mut();
1617 inner.try_update_int(k, v)
1618 }
1619
1620 #[cold]
1623 #[inline(never)]
1624 fn try_raw_set_generic(&self, k: LuaValue, v: LuaValue) -> Result<(), LuaError> {
1625 let mut inner = self.inner.borrow_mut();
1626 if inner.array.len() + inner.node.len() >= TOTAL_GROW_CAP
1627 && matches!(inner.get_slot(&k), TableSlotRef::Absent)
1628 {
1629 return Err(LuaError::Memory);
1630 }
1631 inner.set(&k, v)
1632 }
1633
1634 #[inline]
1641 pub fn try_raw_set_int(&self, k: i64, v: LuaValue) -> Result<(), LuaError> {
1642 let mut inner = self.inner.borrow_mut();
1643 inner.try_raw_set_int_fast(k, v)
1644 }
1645
1646 pub fn resize(&self, new_asize: u32, new_hsize: u32) -> Result<(), LuaError> {
1649 let mut inner = self.inner.borrow_mut();
1650 inner.resize(new_asize, new_hsize)
1651 }
1652
1653 pub fn array_len(&self) -> usize {
1656 self.inner.borrow().array.len()
1657 }
1658
1659 pub fn len(&self) -> usize {
1662 let inner = self.inner.borrow();
1663 let mut n = 0usize;
1664 for v in inner.array.iter() {
1665 if !matches!(v, LuaValue::Nil) {
1666 n += 1;
1667 }
1668 }
1669 for node in inner.node.iter() {
1670 if !matches!(node.value, LuaValue::Nil) {
1671 n += 1;
1672 }
1673 }
1674 n
1675 }
1676 pub fn is_empty(&self) -> bool {
1677 self.len() == 0
1678 }
1679
1680 pub fn getn(&self) -> u64 {
1682 let mut inner = self.inner.borrow_mut();
1683 inner.getn()
1684 }
1685
1686 pub fn contains_key(&self, k: &LuaValue) -> bool {
1689 if matches!(k, LuaValue::Nil) {
1690 return false;
1691 }
1692 let inner = self.inner.borrow();
1693 let slot = inner.get_slot(k);
1694 !matches!(slot, TableSlotRef::Absent)
1695 }
1696
1697 pub fn metatable(&self) -> Option<GcRef<LuaTable>> {
1698 self.metatable.get()
1699 }
1700
1701 #[inline(always)]
1702 pub fn has_metatable(&self) -> bool {
1703 self.metatable.get().is_some()
1704 }
1705
1706 pub fn set_metatable(&self, mt: Option<GcRef<LuaTable>>) {
1710 let mode = mt.as_ref().map(|t| extract_weak_mode(t)).unwrap_or(0);
1711 self.weak_mode.set(mode);
1712 self.metatable.set(mt);
1713 }
1714
1715 pub fn weak_mode(&self) -> u8 {
1716 self.weak_mode.get()
1717 }
1718
1719 pub fn next_pair(&self, k: &LuaValue) -> Option<(LuaValue, LuaValue)> {
1721 let inner = self.inner.borrow();
1722 inner.next_pair(k).ok().flatten()
1723 }
1724
1725 pub fn try_next_pair(&self, k: &LuaValue) -> Result<Option<(LuaValue, LuaValue)>, LuaError> {
1728 let inner = self.inner.borrow();
1729 inner.next_pair(k)
1730 }
1731
1732 pub fn trace_entries_with_clearkey(&self, mut f: impl FnMut(&LuaValue)) {
1744 let mut inner = self.inner.borrow_mut();
1745 for v in inner.array.iter() {
1746 if !matches!(v, LuaValue::Nil) {
1747 f(v);
1748 }
1749 }
1750 for node in inner.node.iter_mut() {
1751 if matches!(node.value, LuaValue::Nil) {
1752 if !node.dead && gc_identity_bits(&node.key).is_some() {
1753 node.dead = true;
1754 }
1755 } else {
1756 f(&node.key);
1757 f(&node.value);
1758 }
1759 }
1760 }
1761
1762 pub fn for_each_entry(&self, mut f: impl FnMut(&LuaValue, &LuaValue)) {
1763 let inner = self.inner.borrow();
1764 for (i, v) in inner.array.iter().enumerate() {
1765 if !matches!(v, LuaValue::Nil) {
1766 let k = LuaValue::Int((i + 1) as i64);
1767 f(&k, v);
1768 }
1769 }
1770 for node in inner.node.iter() {
1771 if !matches!(node.value, LuaValue::Nil) {
1772 f(&node.key, &node.value);
1773 }
1774 }
1775 }
1776
1777 pub fn prune_weak_dead(&self, is_reachable: &dyn Fn(usize) -> bool) -> Vec<LuaValue> {
1781 self.prune_weak_dead_with(is_reachable, is_reachable)
1782 }
1783
1784 pub fn prune_weak_dead_with(
1789 &self,
1790 is_key_reachable: &dyn Fn(usize) -> bool,
1791 is_value_reachable: &dyn Fn(usize) -> bool,
1792 ) -> Vec<LuaValue> {
1793 self.prune_weak_dead_with_value(
1794 &|v| collectable_identity(v).map_or(true, is_key_reachable),
1795 &|v| collectable_identity(v).map_or(true, is_value_reachable),
1796 )
1797 }
1798
1799 pub fn prune_weak_dead_with_value(
1810 &self,
1811 is_key_reachable: &dyn Fn(&LuaValue) -> bool,
1812 is_value_reachable: &dyn Fn(&LuaValue) -> bool,
1813 ) -> Vec<LuaValue> {
1814 let mode = self.weak_mode.get();
1815 if mode == 0 {
1816 return Vec::new();
1817 }
1818 let weak_k = (mode & WEAK_KEYS) != 0;
1819 let weak_v = (mode & WEAK_VALUES) != 0;
1820 let mut to_mark: Vec<LuaValue> = Vec::new();
1821 let mut inner = self.inner.borrow_mut();
1822 for i in 0..inner.array.len() {
1823 let v = inner.array[i].clone();
1824 if matches!(v, LuaValue::Nil) {
1825 continue;
1826 }
1827 if weak_v && value_is_dead_collectable(&v, is_value_reachable) {
1828 inner.array[i] = LuaValue::Nil;
1829 continue;
1830 }
1831 if weak_v {
1832 if matches!(v, LuaValue::Str(_)) {
1833 to_mark.push(v);
1834 }
1835 }
1836 }
1837 let mut i = 0;
1838 while i < inner.node.len() {
1839 let v = inner.node[i].value.clone();
1840 if matches!(v, LuaValue::Nil) {
1841 if !inner.node[i].dead && gc_identity_bits(&inner.node[i].key).is_some() {
1842 inner.node[i].dead = true;
1843 }
1844 i += 1;
1845 continue;
1846 }
1847 let k = inner.node[i].key.clone();
1848 if weak_v && value_is_dead_collectable(&v, is_value_reachable) {
1849 inner.clear_dead_hash_node(i);
1850 continue;
1851 }
1852 if weak_k && value_is_dead_collectable(&k, is_key_reachable) {
1853 inner.clear_dead_hash_node(i);
1854 continue;
1855 }
1856 if weak_k {
1857 if matches!(k, LuaValue::Str(_)) {
1858 to_mark.push(k);
1859 }
1860 }
1861 if weak_v {
1862 if matches!(v, LuaValue::Str(_)) {
1863 to_mark.push(v);
1864 }
1865 }
1866 i += 1;
1867 }
1868 to_mark
1869 }
1870
1871 pub fn ephemeron_values_to_mark(&self, is_reachable: &dyn Fn(usize) -> bool) -> Vec<LuaValue> {
1873 self.ephemeron_values_to_mark_with_value(&|v| {
1874 collectable_identity(v).map_or(true, is_reachable)
1875 })
1876 }
1877
1878 pub fn ephemeron_values_to_mark_with_value(
1881 &self,
1882 is_reachable: &dyn Fn(&LuaValue) -> bool,
1883 ) -> Vec<LuaValue> {
1884 let mode = self.weak_mode.get();
1885 if (mode & WEAK_KEYS) == 0 || (mode & WEAK_VALUES) != 0 {
1886 return Vec::new();
1887 }
1888 let inner = self.inner.borrow();
1889 let mut out = Vec::new();
1890 for node in inner.node.iter() {
1891 if matches!(node.value, LuaValue::Nil) {
1892 continue;
1893 }
1894 if !value_is_dead_collectable(&node.key, is_reachable) {
1895 out.push(node.value.clone());
1896 }
1897 }
1898 for (i, v) in inner.array.iter().enumerate() {
1899 if matches!(v, LuaValue::Nil) {
1900 continue;
1901 }
1902 let k = LuaValue::Int((i + 1) as i64);
1903 if !value_is_dead_collectable(&k, is_reachable) {
1904 out.push(v.clone());
1905 }
1906 }
1907 out
1908 }
1909}
1910
1911fn value_is_dead_collectable(v: &LuaValue, is_reachable: &dyn Fn(&LuaValue) -> bool) -> bool {
1916 collectable_identity(v).is_some() && !is_reachable(v)
1917}
1918
1919fn gc_identity_bits(v: &LuaValue) -> Option<usize> {
1922 match v {
1923 LuaValue::Str(x) => Some(x.identity()),
1924 LuaValue::Table(x) => Some(x.identity()),
1925 LuaValue::UserData(x) => Some(x.identity()),
1926 LuaValue::Thread(x) => Some(x.identity()),
1927 LuaValue::Function(LuaClosure::Lua(x)) => Some(x.identity()),
1928 LuaValue::Function(LuaClosure::C(x)) => Some(x.identity()),
1929 LuaValue::Function(LuaClosure::LightC(_))
1930 | LuaValue::Nil
1931 | LuaValue::Bool(_)
1932 | LuaValue::Int(_)
1933 | LuaValue::Float(_)
1934 | LuaValue::LightUserData(_) => None,
1935 }
1936}
1937
1938fn collectable_identity(v: &LuaValue) -> Option<usize> {
1939 match v {
1940 LuaValue::Table(t) => Some(t.identity()),
1941 LuaValue::UserData(u) => Some(u.identity()),
1942 LuaValue::Thread(th) => Some(th.identity()),
1943 LuaValue::Function(c) => match c {
1944 LuaClosure::Lua(x) => Some(x.identity()),
1945 LuaClosure::C(x) => Some(x.identity()),
1946 LuaClosure::LightC(_) => None,
1947 },
1948 LuaValue::Str(_)
1949 | LuaValue::Nil
1950 | LuaValue::Bool(_)
1951 | LuaValue::Int(_)
1952 | LuaValue::Float(_)
1953 | LuaValue::LightUserData(_) => None,
1954 }
1955}
1956
1957fn extract_weak_mode(mt: &LuaTable) -> u8 {
1961 let inner = mt.inner.borrow();
1962 for node in inner.node.iter() {
1963 if node.dead {
1964 continue;
1965 }
1966 if let LuaValue::Str(ks) = &node.key {
1967 if ks.as_bytes() == b"__mode" {
1968 if let LuaValue::Str(vs) = &node.value {
1969 let bytes = vs.as_bytes();
1970 let mut mode = 0u8;
1971 if bytes.iter().any(|b| *b == b'k') {
1972 mode |= WEAK_KEYS;
1973 }
1974 if bytes.iter().any(|b| *b == b'v') {
1975 mode |= WEAK_VALUES;
1976 }
1977 return mode;
1978 }
1979 return 0;
1980 }
1981 }
1982 }
1983 0
1984}
1985
1986