1use core::mem;
2use core::ptr::{self, NonNull};
3
4mod layout;
5mod lookup;
6
7pub use layout::{
8 LuaNode, LuaNodeCursor, RAW_LUA_NODE_DUMMY, RAW_TKEY_DEAD_KEY, RAW_TKEY_NIL, RawLuaNode,
9 RawTKey, TKey,
10};
11
12use crate::VmErrorResult;
13use crate::debug::DebugRuntime;
14use crate::gc::GcBarrier;
15use crate::gc::{GcObject, RawGcObject};
16use crate::handle::RawHandle;
17use crate::handle::sealed::Sealed;
18use crate::memory::{LuaPage, MemoryRuntime};
19use crate::string::TString;
20use crate::thread::Thread;
21use crate::types::{LUA_TNUMBER, LUA_TTABLE};
22use crate::value::{RAW_TVALUE_NIL, RawTValue, TValue, TValueCursor, nil_object};
23
24#[repr(C)]
25pub struct RawLuaTable {
26 pub tt: u8,
27 pub marked: u8,
28 pub memcat: u8,
29 pub tm_cache: u8,
30 pub readonly: u8,
31 pub safe_env: u8,
32 pub lsize_node: u8,
33 pub node_mask_8: u8,
34 pub size_array: i32,
35 pub free: RawLuaTableFree,
36 pub metatable: *mut RawLuaTable,
37 pub array: *mut RawTValue,
38 pub node: *mut RawLuaNode,
39 pub gc_list: *mut RawGcObject,
40}
41
42#[repr(C)]
43pub union RawLuaTableFree {
44 pub last_free: i32,
45 pub aboundary: i32,
46}
47
48const LOG_2: [u8; 256] = [
49 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, 5, 5,
50 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, 6, 6, 6, 6,
51 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, 7, 7,
52 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, 7, 7,
53 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, 8, 8,
54 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, 8, 8,
55 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, 8, 8,
56 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, 8, 8,
57];
58
59fn log_2(mut value: u32) -> i32 {
61 let mut log = -1;
62 while value >= 256 {
63 log += 8;
64 value >>= 8;
65 }
66 log + i32::from(LOG_2[value as usize])
67}
68
69pub(super) fn ceil_log_2(value: u32) -> i32 {
71 log_2(value - 1) + 1
72}
73
74#[derive(Clone, Copy, PartialEq, Eq)]
75#[repr(transparent)]
76pub struct Table {
85 pub(crate) raw: NonNull<RawLuaTable>,
86}
87
88#[allow(
96 clippy::missing_safety_doc,
97 reason = "all methods share the capability-level safety contract"
98)]
99pub trait TableRuntime: Sealed {
100 unsafe fn set_num(&self, table: Table, key: i32) -> VmErrorResult<TValue>;
101 unsafe fn set_str(&self, table: Table, key: TString) -> VmErrorResult<LuaNodeCursor>;
102 unsafe fn setp(&self, table: Table, key: *mut (), tag: i32) -> VmErrorResult<TValue>;
103 unsafe fn set(&self, table: Table, key: TValue) -> VmErrorResult<TValue>;
104 unsafe fn set_slot(&self, table: Table, slot: TValue, key: TValue) -> VmErrorResult<TValue>;
105 unsafe fn new_key(&self, table: Table, key: TValue) -> VmErrorResult<TValue>;
106 unsafe fn next_internal(&self, table: Table, key: TValueCursor) -> VmErrorResult<i32>;
107 unsafe fn new_table_internal(&self, n_array: i32, n_hash: i32) -> VmErrorResult<Table>;
108 unsafe fn resize_array(&self, table: Table, n_array: i32) -> VmErrorResult;
109 unsafe fn resize_hash(&self, table: Table, n_hash: i32) -> VmErrorResult;
110 unsafe fn free_table(&self, table: Table, page: LuaPage);
111 unsafe fn clone_table_internal(&self, table: Table) -> VmErrorResult<Table>;
112}
113
114impl crate::handle::sealed::Sealed for Table {}
115
116impl RawHandle for Table {
117 type Raw = RawLuaTable;
118
119 fn as_ptr(&self) -> *mut Self::Raw {
120 self.raw.as_ptr()
121 }
122}
123
124impl AsRef<Table> for Table {
125 fn as_ref(&self) -> &Table {
126 self
127 }
128}
129
130const MAX_BITS: i32 = 26;
131const MAX_SIZE: i32 = 1 << MAX_BITS;
132
133fn twoto(value: i32) -> i32 {
135 1 << value
136}
137
138fn count_int(key: f64, nums: &mut [i32; (MAX_BITS + 1) as usize]) -> i32 {
140 match Table::array_index(key) {
141 Some(index) if index > 0 && index <= MAX_SIZE => {
142 nums[ceil_log_2(index as u32) as usize] += 1;
143 1
144 }
145 _ => 0,
146 }
147}
148
149fn compute_sizes(nums: &[i32; (MAX_BITS + 1) as usize], n_array: &mut i32) -> i32 {
151 let mut a = 0;
152 let mut na = 0;
153 let mut n = 0;
154 let mut twotoi = 1;
155 let mut index = 0;
156
157 while twotoi / 2 < *n_array {
158 if nums[index] > 0 {
159 a += nums[index];
160 if a > twotoi / 2 {
161 n = twotoi;
162 na = a;
163 }
164 }
165
166 if a == *n_array {
167 break;
168 }
169
170 index += 1;
171 twotoi *= 2;
172 }
173
174 *n_array = n;
175 debug_assert!(*n_array / 2 <= na && na <= *n_array);
176 na
177}
178
179#[allow(
180 clippy::missing_safety_doc,
181 reason = "Table's shared raw-handle contract is documented on Table"
182)]
183impl Table {
184 fn num_use_array(&self, nums: &mut [i32; (MAX_BITS + 1) as usize]) -> i32 {
186 let mut ause = 0;
187 let mut index = 1;
188 let mut ttlg = 1;
189 let size_array = unsafe { self.as_ptr().as_ref().unwrap_unchecked().size_array };
190 let array = unsafe { self.array_cursor() };
191
192 for lg in 0..=MAX_BITS {
193 let mut lc = 0;
194 let mut limit = ttlg;
195 if limit > size_array {
196 limit = size_array;
197 if index > limit {
198 break;
199 }
200 }
201
202 while index <= limit {
203 if unsafe { !array.add((index - 1) as usize).is_nil_unchecked() } {
204 lc += 1;
205 }
206 index += 1;
207 }
208
209 nums[lg as usize] += lc;
210 ause += lc;
211 ttlg *= 2;
212 }
213
214 ause
215 }
216
217 fn num_use_hash(&self, nums: &mut [i32; (MAX_BITS + 1) as usize], n_array: &mut i32) -> i32 {
219 let mut total_use = 0;
220 let mut ause = 0;
221 let mut index = unsafe { self.node_count() };
222
223 while index > 0 {
224 index -= 1;
225 let node = unsafe { self.node(index as i32) };
226 if !node.value_unchecked().is_nil() {
227 let key = node.key();
228 if key.tt() == LUA_TNUMBER {
229 ause += count_int(key.number_value(), nums);
230 }
231 total_use += 1;
232 }
233 }
234
235 *n_array += ause;
236 total_use
237 }
238
239 unsafe fn set_array_vector(&self, thread: &Thread, size: i32) -> VmErrorResult {
241 if size > MAX_SIZE {
242 return unsafe { crate::run_error!(thread, "table overflow") };
243 }
244
245 unsafe {
246 let old_size = self.as_ptr().as_ref().unwrap_unchecked().size_array as usize;
247 let new_size = size as usize;
248 let memcat = self.as_ptr().as_ref().unwrap_unchecked().memcat;
249 let array = TValueCursor::from_ptr(thread.realloc_array(
250 self.as_ptr().as_ref().unwrap_unchecked().array,
251 old_size,
252 new_size,
253 memcat,
254 )?);
255
256 for index in old_size..new_size {
257 array.add(index).value_unchecked().set_nil();
258 }
259 self.set_array(array);
260 self.as_ptr().as_mut().unwrap_unchecked().size_array = size;
261 }
262 Ok(())
263 }
264
265 unsafe fn set_node_vector(&self, thread: &Thread, size: i32) -> VmErrorResult {
267 unsafe {
268 let (node, lsize, count) = if size == 0 {
269 (Table::dummy_node_cursor(), 0, 0usize)
270 } else {
271 let lsize = ceil_log_2(size as u32);
272 if lsize > MAX_BITS {
273 return crate::run_error!(thread, "table overflow");
274 }
275
276 let count = twoto(lsize) as usize;
277 let node = LuaNodeCursor::from_ptr(thread.new_array::<RawLuaNode>(
278 count,
279 self.as_ptr().as_ref().unwrap_unchecked().memcat,
280 )?);
281
282 for index in 0..count {
283 let current_cursor = node.add(index);
284 let current_node = current_cursor.node_unchecked();
285 current_node.key().set_nil();
286 current_node.value_unchecked().set_nil();
287 }
288
289 (node, lsize, count)
290 };
291
292 self.set_node(node);
293 self.as_ptr().as_mut().unwrap_unchecked().lsize_node = lsize as u8;
294 self.as_ptr().as_mut().unwrap_unchecked().node_mask_8 = ((1 << lsize) - 1) as u8;
295 self.as_ptr().as_mut().unwrap_unchecked().free = RawLuaTableFree {
296 last_free: count as i32,
297 };
298 }
299 Ok(())
300 }
301
302 unsafe fn array_or_new_key(&self, thread: &Thread, key: TValue) -> VmErrorResult<TValue> {
304 unsafe {
305 if key.is_number() {
306 let Some(index) = Table::array_index(key.number_value()) else {
307 return self.new_key(thread, key);
308 };
309 if let Some(slot) = self.array_slot_for_key(index) {
310 return Ok(slot);
311 }
312 }
313
314 self.new_key(thread, key)
315 }
316 }
317
318 unsafe fn resize(&self, thread: &Thread, n_array: i32, n_hash: i32) -> VmErrorResult {
320 unsafe {
321 if n_array > MAX_SIZE || n_hash > MAX_SIZE {
322 return crate::run_error!(thread, "table overflow");
323 }
324
325 let old_array_size = self.as_ptr().as_ref().unwrap_unchecked().size_array;
326 let old_hash_lsize = self.as_ptr().as_ref().unwrap_unchecked().lsize_node as i32;
327 let old_nodes = self.node_cursor();
328
329 if n_array > old_array_size {
330 self.set_array_vector(thread, n_array)?;
331 }
332
333 self.set_node_vector(thread, n_hash)?;
334 let new_nodes = self.node_cursor();
335
336 if n_array < old_array_size {
337 self.as_ptr().as_mut().unwrap_unchecked().size_array = n_array;
338
339 for index in n_array..old_array_size {
340 let value = self.array_slot(index as usize);
341 if !value.is_nil() {
342 let mut key_storage = RawTValue::number((index + 1) as f64);
343 let key = TValue::from_mut(&mut key_storage);
344 self.array_or_new_key(thread, key)?.set_obj(value);
345 }
346 }
347
348 let array = TValueCursor::from_ptr(thread.realloc_array(
349 self.as_ptr().as_ref().unwrap_unchecked().array,
350 old_array_size as usize,
351 n_array as usize,
352 self.as_ptr().as_ref().unwrap_unchecked().memcat,
353 )?);
354 self.set_array(array);
355 }
356
357 let new_array = self.array_cursor();
358 for index in (0..twoto(old_hash_lsize)).rev() {
359 let old_cursor = old_nodes.add(index as usize);
360 let old_node = old_cursor.node_unchecked();
361 if !old_node.value_unchecked().is_nil() {
362 let mut key_storage = RawTValue::nil();
363 let key = TValue::from_mut(&mut key_storage);
364 old_node.write_key_to_value(key);
365 self.array_or_new_key(thread, key)?
366 .set_obj(old_node.value_unchecked());
367 }
368 }
369
370 debug_assert!(new_nodes == self.node_cursor());
371 debug_assert!(new_array == self.array_cursor());
372
373 if old_nodes != Table::dummy_node_cursor() {
374 thread.free_array(
375 old_nodes.as_ptr(),
376 twoto(old_hash_lsize) as usize,
377 self.as_ptr().as_ref().unwrap_unchecked().memcat,
378 );
379 }
380 }
381 Ok(())
382 }
383
384 unsafe fn adjust_array_size(&self, mut size: i32, extra_key: Option<TValue>) -> i32 {
386 let table_bound = unsafe {
387 !self.has_dummy_node() || size < self.as_ptr().as_ref().unwrap_unchecked().size_array
388 };
389 let extra_key_index = extra_key
390 .and_then(|key| {
391 if key.is_number() {
392 Table::array_index(key.number_value())
393 } else {
394 None
395 }
396 })
397 .unwrap_or(-1);
398
399 while size + 1 == extra_key_index
400 || (table_bound && !unsafe { self.get_num(size + 1) }.is_nil())
401 {
402 size += 1;
403 }
404
405 size
406 }
407
408 unsafe fn rehash(&self, thread: &Thread, extra_key: TValue) -> VmErrorResult {
410 let mut nums = [0; (MAX_BITS + 1) as usize];
411 let mut n_array = self.num_use_array(&mut nums);
412 let mut total_use = n_array;
413 total_use += self.num_use_hash(&mut nums, &mut n_array);
414
415 if extra_key.is_number() {
416 n_array += count_int(extra_key.number_value(), &mut nums);
417 }
418 total_use += 1;
419
420 let na = compute_sizes(&nums, &mut n_array);
421 let mut n_hash = total_use - na;
422
423 unsafe {
424 let mut adjusted = self.adjust_array_size(n_array, Some(extra_key));
425 let extra_array = adjusted - n_array;
426 if extra_array != 0 {
427 n_hash -= extra_array;
428 n_array = adjusted + extra_array;
429 adjusted = self.adjust_array_size(n_array, Some(extra_key));
430 }
431
432 self.resize(thread, adjusted, n_hash)?;
433 }
434 Ok(())
435 }
436
437 unsafe fn free_position(&self) -> Option<LuaNodeCursor> {
439 let mut last_free = unsafe { self.as_ptr().as_ref().unwrap_unchecked().free.last_free };
440 while last_free > 0 {
441 last_free -= 1;
442 unsafe {
443 self.as_ptr().as_mut().unwrap_unchecked().free = RawLuaTableFree { last_free };
444 let node_cursor = self.node_cursor().add(last_free as usize);
445 if node_cursor.node_unchecked().key().is_nil() {
446 return Some(node_cursor);
447 }
448 }
449 }
450
451 None
452 }
453
454 unsafe fn new_hash_key(&self, thread: &Thread, key: TValue) -> VmErrorResult<TValue> {
455 unsafe {
456 let mut main_cursor = self.main_position(key);
457 if !main_cursor.node_unchecked().value_unchecked().is_nil()
458 || main_cursor == Table::dummy_node_cursor()
459 {
460 let Some(free_cursor) = self.free_position() else {
461 self.rehash(thread, key)?;
462 return self.array_or_new_key(thread, key);
463 };
464
465 debug_assert!(free_cursor != Table::dummy_node_cursor());
466
467 let mut main_key_storage = RAW_TVALUE_NIL;
468 let main_key = TValue::from_mut(&mut main_key_storage);
469 main_cursor.node_unchecked().write_key_to_value(main_key);
470
471 let mut other_cursor = self.main_position(main_key);
472 if other_cursor != main_cursor {
473 let mut next_cursor =
474 other_cursor.offset(other_cursor.node_unchecked().next() as isize);
475 while next_cursor != main_cursor {
476 other_cursor =
477 other_cursor.offset(other_cursor.node_unchecked().next() as isize);
478 next_cursor =
479 other_cursor.offset(other_cursor.node_unchecked().next() as isize);
480 }
481
482 other_cursor
483 .node_unchecked()
484 .key()
485 .set_next(free_cursor.offset_from(other_cursor) as i32);
486 ptr::copy_nonoverlapping(main_cursor.as_ptr(), free_cursor.as_ptr(), 1);
487 let main_next = main_cursor.node_unchecked().next();
488 if main_next != 0 {
489 free_cursor.node_unchecked().key().set_next(
490 free_cursor.node_unchecked().next()
491 + main_cursor.offset_from(free_cursor) as i32,
492 );
493 main_cursor.node_unchecked().key().set_next(0);
494 }
495 main_cursor.node_unchecked().value_unchecked().set_nil();
496 } else {
497 let main_next = main_cursor.node_unchecked().next();
498 if main_next != 0 {
499 free_cursor.node_unchecked().key().set_next(
500 main_cursor
501 .offset(main_next as isize)
502 .offset_from(free_cursor) as i32,
503 );
504 } else {
505 debug_assert!(free_cursor.node_unchecked().next() == 0);
506 }
507
508 main_cursor
509 .node_unchecked()
510 .key()
511 .set_next(free_cursor.offset_from(main_cursor) as i32);
512 main_cursor = free_cursor;
513 }
514 }
515
516 let main_node = main_cursor.node_unchecked();
517 main_node.set_key_from_value(key);
518 if key.is_collectable() {
519 let object = key.gc_value();
520 let table_object: GcObject = (*self).into();
521 if table_object.is_black() && object.is_white() {
522 thread.barrier_table(*self, object);
523 }
524 }
525
526 debug_assert!(main_node.value_unchecked().is_nil());
527 Ok(main_node.value())
528 }
529 }
530
531 unsafe fn new_key(&self, thread: &Thread, key: TValue) -> VmErrorResult<TValue> {
533 unsafe {
534 let size_array = self.as_ptr().as_ref().unwrap_unchecked().size_array;
535 if key.is_number() && key.number_value() == (size_array + 1) as f64 {
536 self.rehash(thread, key)?;
537 return self.array_or_new_key(thread, key);
538 }
539
540 self.new_hash_key(thread, key)
541 }
542 }
543
544 unsafe fn find_index(&self, thread: &Thread, key: TValue) -> VmErrorResult<i32> {
546 if key.is_nil() {
547 return Ok(-1);
548 }
549
550 unsafe {
551 if key.is_number()
552 && matches!(
553 Table::array_index(key.number_value()),
554 Some(index) if index > 0 && index <= self.as_ptr().as_ref().unwrap_unchecked().size_array
555 )
556 {
557 return Ok(Table::array_index(key.number_value()).unwrap_unchecked() - 1);
558 }
559
560 let mut node_cursor = self.main_position(key);
561 loop {
562 let node_key = node_cursor.node_unchecked().key();
563 if node_key.raw_equal_value(key)
564 || (node_key.is_dead_key()
565 && key.is_collectable()
566 && node_key.gc_value() == key.gc_value())
567 {
568 let index = self.node_index(node_cursor);
569 return Ok(index + self.as_ptr().as_ref().unwrap_unchecked().size_array);
570 }
571
572 let next = node_key.next();
573 if next == 0 {
574 break;
575 }
576 node_cursor = node_cursor.offset(next as isize);
577 }
578
579 crate::run_error!(thread, "invalid key to 'next'")
580 }
581 }
582}
583
584impl TableRuntime for Thread {
585 #[inline(always)]
587 unsafe fn set_num(&self, table: Table, key: i32) -> VmErrorResult<TValue> {
588 unsafe {
589 if let Some(slot) = table.array_slot_for_key(key) {
590 Ok(slot)
591 } else {
592 let slot = table.get_num(key);
593 if slot != nil_object() {
594 Ok(slot)
595 } else {
596 let mut value_storage = RawTValue::number(key as f64);
597 let value = TValue::from_mut(&mut value_storage);
598 table.new_key(self, value)
599 }
600 }
601 }
602 }
603
604 #[inline(always)]
606 unsafe fn set_str(&self, table: Table, key: TString) -> VmErrorResult<LuaNodeCursor> {
607 unsafe {
608 table.invalidate_tm_cache();
609
610 if let Some(node_cursor) = table.get_str_node(key) {
611 Ok(node_cursor)
612 } else {
613 let mut value_storage = RawTValue::string(key);
614 let value = TValue::from_mut(&mut value_storage);
615 table.new_hash_key(self, value)?;
616 Ok(table.get_str_node(key).unwrap_unchecked())
617 }
618 }
619 }
620
621 unsafe fn setp(&self, table: Table, key: *mut (), tag: i32) -> VmErrorResult<TValue> {
623 unsafe {
624 let slot = table.getp(key, tag);
625 if slot != nil_object() {
626 Ok(slot)
627 } else {
628 let mut value_storage = RawTValue::light_userdata(key, tag);
629 let value = TValue::from_mut(&mut value_storage);
630 table.new_key(self, value)
631 }
632 }
633 }
634
635 unsafe fn set(&self, table: Table, key: TValue) -> VmErrorResult<TValue> {
637 unsafe {
638 let slot = table.get(key);
639 self.set_slot(table, slot, key)
640 }
641 }
642
643 unsafe fn set_slot(&self, table: Table, slot: TValue, key: TValue) -> VmErrorResult<TValue> {
645 unsafe {
646 table.invalidate_tm_cache();
647 if slot != nil_object() {
648 Ok(slot)
649 } else {
650 self.new_key(table, key)
651 }
652 }
653 }
654
655 unsafe fn new_key(&self, table: Table, key: TValue) -> VmErrorResult<TValue> {
657 unsafe {
658 if key.is_nil() {
659 return crate::run_error!(self, "table index is nil");
660 } else if key.is_number() && key.number_value().is_nan() {
661 return crate::run_error!(self, "table index is NaN");
662 } else if key.is_vector() && crate::number::vec_is_nan(&key.vector_value()) {
663 return crate::run_error!(self, "table index contains NaN");
664 }
665
666 table.new_key(self, key)
667 }
668 }
669
670 unsafe fn next_internal(&self, table: Table, key: TValueCursor) -> VmErrorResult<i32> {
672 unsafe {
673 let mut index = table.find_index(self, key.value_unchecked())?;
674
675 index += 1;
676 while index < table.as_ptr().as_ref().unwrap_unchecked().size_array {
677 let value = table.array_slot(index as usize);
678 if !value.is_nil() {
679 key.value_unchecked().set_number((index + 1) as f64);
680 key.add(1).value_unchecked().set_obj(value);
681 return Ok(1);
682 }
683 index += 1;
684 }
685
686 index -= table.as_ptr().as_ref().unwrap_unchecked().size_array;
687 while index < table.node_count() as i32 {
688 let node = table.node(index);
689 if !node.value_unchecked().is_nil() {
690 node.write_key_to_value(key.value_unchecked());
691 key.add(1).value_unchecked().set_obj(node.value_unchecked());
692 return Ok(1);
693 }
694 index += 1;
695 }
696
697 Ok(0)
698 }
699 }
700
701 unsafe fn new_table_internal(&self, n_array: i32, n_hash: i32) -> VmErrorResult<Table> {
703 let table = unsafe {
704 let table = self.new_gco::<Table>(
705 mem::size_of::<RawLuaTable>(),
706 self.as_ptr().as_ref().unwrap_unchecked().active_memcat,
707 )?;
708 GcObject::from(table).init_header(self, LUA_TTABLE as u8);
709 let table_ref = table.as_ptr().as_mut().unwrap_unchecked();
710 table_ref.metatable = ptr::null_mut();
711 table_ref.tm_cache = !0;
712 table.init_empty_storage();
713 if n_array > 0 {
714 table.set_array_vector(self, n_array)?;
715 }
716 if n_hash > 0 {
717 table.set_node_vector(self, n_hash)?;
718 }
719 table
720 };
721
722 Ok(table)
723 }
724
725 unsafe fn resize_array(&self, table: Table, n_array: i32) -> VmErrorResult {
727 unsafe {
728 let n_hash = if table.has_dummy_node() {
729 0
730 } else {
731 table.node_count() as i32
732 };
733 let adjusted = table.adjust_array_size(n_array, None);
734 table.resize(self, adjusted, n_hash)
735 }
736 }
737
738 unsafe fn resize_hash(&self, table: Table, n_hash: i32) -> VmErrorResult {
740 unsafe {
741 table.resize(
742 self,
743 table.as_ptr().as_ref().unwrap_unchecked().size_array,
744 n_hash,
745 )
746 }
747 }
748
749 unsafe fn free_table(&self, table: Table, page: LuaPage) {
751 unsafe {
752 let table_ref = table.as_ptr().as_ref().unwrap_unchecked();
753 let memcat = table_ref.memcat;
754 table.free_storage(self);
755 self.free_gco(
756 table.into(),
757 core::mem::size_of::<RawLuaTable>(),
758 memcat,
759 page,
760 );
761 }
762 }
763
764 unsafe fn clone_table_internal(&self, table: Table) -> VmErrorResult<Table> {
766 unsafe {
767 let active_memcat = self.as_ptr().as_ref().unwrap_unchecked().active_memcat;
768 let cloned = self.new_gco::<Table>(mem::size_of::<RawLuaTable>(), active_memcat)?;
769 GcObject::from(cloned).init_header(self, LUA_TTABLE as u8);
770
771 let cloned_ref = cloned.as_ptr().as_mut().unwrap_unchecked();
772 cloned_ref.metatable = table
773 .metatable()
774 .map_or(ptr::null_mut(), |table| table.as_ptr());
775 cloned_ref.tm_cache = table.as_ptr().as_ref().unwrap_unchecked().tm_cache;
776 cloned.init_empty_storage();
777
778 let table_ref = table.as_ptr().as_ref().unwrap_unchecked();
779 let cloned_memcat = cloned.as_ptr().as_ref().unwrap_unchecked().memcat;
780
781 if table_ref.size_array > 0 {
782 let size_array = table_ref.size_array as usize;
783 let array =
784 TValueCursor::from_ptr(self.new_array::<RawTValue>(size_array, cloned_memcat)?);
785
786 cloned.set_array(array);
787 cloned.as_ptr().as_mut().unwrap_unchecked().size_array = table_ref.size_array;
788 cloned.maybe_set_aboundary(table.get_aboundary());
789 ptr::copy_nonoverlapping(table.array_cursor().as_ptr(), array.as_ptr(), size_array);
790 }
791
792 if !table.has_dummy_node() {
793 let size = table.node_count();
794 let node = self.new_array::<RawLuaNode>(size, cloned_memcat)?;
795
796 cloned.set_node(LuaNodeCursor::from_ptr(node));
797 cloned.as_ptr().as_mut().unwrap_unchecked().lsize_node = table_ref.lsize_node;
798 cloned.as_ptr().as_mut().unwrap_unchecked().node_mask_8 = table_ref.node_mask_8;
799 cloned.as_ptr().as_mut().unwrap_unchecked().free = RawLuaTableFree {
800 last_free: table_ref.free.last_free,
801 };
802 ptr::copy_nonoverlapping(table_ref.node, node, size);
803 }
804
805 Ok(cloned)
806 }
807 }
808}
809
810impl Table {
811 pub unsafe fn clear(&self) {
819 unsafe {
820 for index in 0..self.as_ptr().as_ref().unwrap_unchecked().size_array as usize {
821 self.array_slot(index).set_nil();
822 }
823
824 self.maybe_set_aboundary(0);
825
826 if !self.has_dummy_node() {
827 let size = self.node_count();
828 self.as_ptr().as_mut().unwrap_unchecked().free = RawLuaTableFree {
829 last_free: size as i32,
830 };
831
832 for index in 0..size {
833 let node = self.node(index as i32);
834 node.set_key_from_value(nil_object());
835 node.value_unchecked().set_nil();
836 node.key().set_next(0);
837 }
838 }
839
840 self.as_ptr().as_mut().unwrap_unchecked().tm_cache = !0;
841 }
842 }
843}