1use crate::Table;
2use crate::handle::RawHandle;
3use crate::metamethod::TmEvent;
4use crate::string::TString;
5use crate::types::{
6 LUA_TBOOLEAN, LUA_TINTEGER, LUA_TLIGHTUSERDATA, LUA_TNIL, LUA_TNUMBER, LUA_TSTRING,
7 LUA_TVECTOR, LUA_VECTOR_SIZE,
8};
9use crate::value::{TValue, nil_object};
10
11use super::{LuaNode, LuaNodeCursor, RawLuaNode};
12
13#[allow(
14 clippy::missing_safety_doc,
15 reason = "Table's shared raw-handle contract is documented on Table"
16)]
17impl Table {
18 pub fn dummy_node_cursor() -> LuaNodeCursor {
19 struct SharedDummyNode(RawLuaNode);
20
21 unsafe impl Sync for SharedDummyNode {}
22
23 static DUMMY_NODE: SharedDummyNode = SharedDummyNode(crate::table::RAW_LUA_NODE_DUMMY);
24
25 LuaNodeCursor::from_ptr((&raw const DUMMY_NODE.0).cast_mut())
26 }
27
28 pub fn dummy_node() -> LuaNode {
29 unsafe { Self::dummy_node_cursor().node_unchecked() }
30 }
31
32 pub fn dummy_node_ptr() -> *mut RawLuaNode {
33 Self::dummy_node().as_ptr()
34 }
35
36 pub fn array_index(key: f64) -> Option<i32> {
38 let index = key as i32;
39 ((index as f64) == key).then_some(index)
40 }
41
42 unsafe fn hash_pow2(&self, hash: u32) -> LuaNodeCursor {
44 unsafe {
45 self.node_cursor()
46 .add((hash as usize) & (self.node_count() - 1))
47 }
48 }
49
50 unsafe fn hash_str(&self, string: TString) -> LuaNodeCursor {
52 unsafe { self.hash_pow2(string.as_ptr().as_ref().unwrap_unchecked().hash) }
53 }
54
55 unsafe fn hash_boolean(&self, value: i32) -> LuaNodeCursor {
57 unsafe { self.hash_pow2(value as u32) }
58 }
59
60 unsafe fn hash_pointer(&self, pointer: *const ()) -> LuaNodeCursor {
62 let mut hash = pointer as usize as u32;
63 hash ^= hash >> 16;
64 hash = hash.wrapping_mul(0x85ebca6b);
65 hash ^= hash >> 13;
66 hash = hash.wrapping_mul(0xc2b2ae35);
67 hash ^= hash >> 16;
68 unsafe { self.hash_pow2(hash) }
69 }
70
71 pub(super) unsafe fn hash_num(&self, number: f64) -> LuaNodeCursor {
73 let bits = number.to_bits() & 0x7fff_ffff_ffff_ffff;
74 let mut h1 = bits as u32;
75 let mut h2 = (bits >> 32) as u32;
76 let m = 0x5bd1e995u32;
77
78 h1 ^= h2 >> 18;
79 h1 = h1.wrapping_mul(m);
80 h2 ^= h1 >> 22;
81 h2 = h2.wrapping_mul(m);
82 h1 ^= h2 >> 17;
83 h1 = h1.wrapping_mul(m);
84 h2 ^= h1 >> 19;
85 h2 = h2.wrapping_mul(m);
86
87 unsafe { self.hash_pow2(h2) }
88 }
89
90 unsafe fn hash_int(&self, integer: i64) -> LuaNodeCursor {
92 let bits = integer as u64;
93 let mut h1 = bits as u32;
94 let mut h2 = (bits >> 32) as u32;
95 let m = 0x5bd1e995u32;
96
97 h1 ^= h2 >> 18;
98 h1 = h1.wrapping_mul(m);
99 h2 ^= h1 >> 22;
100 h2 = h2.wrapping_mul(m);
101 h1 ^= h2 >> 17;
102 h1 = h1.wrapping_mul(m);
103 h2 ^= h1 >> 19;
104 h2 = h2.wrapping_mul(m);
105
106 unsafe { self.hash_pow2(h2) }
107 }
108
109 unsafe fn hash_vec(&self, vector: [f32; LUA_VECTOR_SIZE]) -> LuaNodeCursor {
111 let mut values = [
112 vector[0].to_bits(),
113 vector[1].to_bits(),
114 vector[2].to_bits(),
115 ];
116 #[cfg(feature = "vector4")]
117 let value3 = vector[3].to_bits();
118 for value in &mut values {
119 if *value == 0x8000_0000 {
120 *value = 0;
121 }
122 *value ^= *value >> 17;
123 }
124
125 let hash = values[0].wrapping_mul(73_856_093)
126 ^ values[1].wrapping_mul(19_349_663)
127 ^ values[2].wrapping_mul(83_492_791);
128 #[cfg(feature = "vector4")]
129 {
130 let mut hash = hash;
131 let mut value3 = if value3 == 0x8000_0000 { 0 } else { value3 };
132 value3 ^= value3 >> 17;
133 hash ^= value3.wrapping_mul(39_916_801);
134 unsafe { self.hash_pow2(hash) }
135 }
136 #[cfg(not(feature = "vector4"))]
137 {
138 unsafe { self.hash_pow2(hash) }
139 }
140 }
141
142 pub(super) unsafe fn get_pointer_node(&self, key: *mut (), tag: i32) -> Option<LuaNodeCursor> {
143 let mut node = unsafe { self.hash_pointer(key.cast_const()) };
144
145 loop {
146 let node_key = unsafe { node.node_unchecked() }.key();
147 if node_key.tt() == LUA_TLIGHTUSERDATA
148 && node_key.pointer_value() == key
149 && node_key.light_userdata_tag() == tag
150 {
151 return Some(node);
152 }
153
154 let next = node_key.next();
155 if next == 0 {
156 break;
157 }
158
159 node = unsafe { node.offset(next as isize) };
160 }
161
162 None
163 }
164
165 pub unsafe fn main_position(&self, key: TValue) -> LuaNodeCursor {
167 unsafe {
168 match key.tt() {
169 x if x == LUA_TNUMBER => self.hash_num(key.number_value()),
170 x if x == LUA_TINTEGER => self.hash_int(key.integer_value()),
171 x if x == LUA_TVECTOR => self.hash_vec(key.vector_value()),
172 x if x == LUA_TSTRING => self.hash_str(key.string_value()),
173 x if x == LUA_TBOOLEAN => self.hash_boolean(key.boolean_value()),
174 x if x == LUA_TLIGHTUSERDATA => self.hash_pointer(key.pointer_value().cast_const()),
175 _ => self.hash_pointer(key.gc_value().as_ptr().cast()),
176 }
177 }
178 }
179
180 pub unsafe fn get_hash_node(&self, key: TValue) -> Option<LuaNodeCursor> {
181 let mut node = unsafe { self.main_position(key) };
182
183 loop {
184 if unsafe { node.node_unchecked() }.key().raw_equal_value(key) {
185 return Some(node);
186 }
187
188 let next = unsafe { node.node_unchecked() }.next();
189 if next == 0 {
190 break;
191 }
192
193 node = unsafe { node.offset(next as isize) };
194 }
195
196 None
197 }
198
199 #[inline(always)]
200 pub unsafe fn get_str_node(self, key: TString) -> Option<LuaNodeCursor> {
201 let mut node = unsafe { self.hash_str(key) };
202
203 loop {
204 let current = unsafe { node.node_unchecked() };
205 if current.has_string_key(key) {
206 return Some(node);
207 }
208
209 let next = current.next();
210 if next == 0 {
211 break;
212 }
213
214 node = unsafe { node.offset(next as isize) };
215 }
216
217 None
218 }
219}
220
221#[allow(
222 clippy::missing_safety_doc,
223 reason = "Table's shared raw-handle contract is documented on Table"
224)]
225impl Table {
226 pub unsafe fn get_num(&self, key: i32) -> TValue {
228 unsafe {
229 if let Some(slot) = self.array_slot_for_key(key) {
230 slot
231 } else if !self.has_dummy_node() {
232 let nk = key as f64;
233 let mut node_cursor = self.hash_num(nk);
234
235 loop {
236 let node_key = node_cursor.node_unchecked().key();
237 if node_key.tt() == LUA_TNUMBER && node_key.number_value() == nk {
238 return node_cursor.node_unchecked().value_unchecked();
239 }
240
241 let next = node_key.next();
242 if next == 0 {
243 break;
244 }
245
246 node_cursor = node_cursor.offset(next as isize);
247 }
248
249 nil_object()
250 } else {
251 nil_object()
252 }
253 }
254 }
255
256 pub unsafe fn get_str(&self, key: TString) -> TValue {
258 unsafe {
259 self.get_str_node(key)
260 .map(|node_cursor| node_cursor.node_unchecked().value_unchecked())
261 .unwrap_or_else(nil_object)
262 }
263 }
264
265 unsafe fn get_hash(&self, key: TValue) -> TValue {
266 unsafe {
267 self.get_hash_node(key)
268 .map(|node_cursor| node_cursor.node_unchecked().value_unchecked())
269 .unwrap_or_else(nil_object)
270 }
271 }
272
273 pub unsafe fn get(&self, key: TValue) -> TValue {
275 unsafe {
276 match key.tt() {
277 x if x == LUA_TNIL => nil_object(),
278 x if x == LUA_TSTRING => self.get_str(key.string_value()),
279 x if x == LUA_TNUMBER => {
280 if let Some(index) = Self::array_index(key.number_value()) {
281 self.get_num(index)
282 } else {
283 self.get_hash(key)
284 }
285 }
286 _ => self.get_hash(key),
287 }
288 }
289 }
290
291 pub unsafe fn getp(&self, key: *mut (), tag: i32) -> TValue {
293 unsafe {
294 self.get_pointer_node(key, tag)
295 .map(|node_cursor| node_cursor.node_unchecked().value_unchecked())
296 .unwrap_or_else(nil_object)
297 }
298 }
299
300 #[inline(always)]
302 pub unsafe fn getn(self) -> i32 {
303 unsafe {
304 let mut boundary = self.get_aboundary();
305 let size_array = self.as_ptr().as_ref().unwrap_unchecked().size_array;
306 let array = self.array_cursor();
307
308 if boundary > 0 {
309 let node_is_dummy = self.has_dummy_node();
310
311 if size_array > 0
312 && !array.add((size_array - 1) as usize).is_nil_unchecked()
313 && node_is_dummy
314 {
315 return size_array;
316 }
317
318 if boundary < size_array
319 && !array.add((boundary - 1) as usize).is_nil_unchecked()
320 && array.add(boundary as usize).is_nil_unchecked()
321 {
322 return boundary;
323 }
324
325 let found = self.update_aboundary(boundary);
326 if found > 0 {
327 return found;
328 }
329 }
330
331 let last_array_is_nil = if size_array > 0 {
332 array.add((size_array - 1) as usize).is_nil_unchecked()
333 } else {
334 false
335 };
336
337 if last_array_is_nil {
338 let mut base = array;
339 let mut rest = size_array;
340
341 while rest >> 1 != 0 {
342 let half = rest >> 1;
343 let half_slot = base.add(half as usize);
344 let half_is_nil = half_slot.is_nil_unchecked();
345 base = if half_is_nil { base } else { half_slot };
346 rest -= half;
347 }
348
349 let base_is_nil = base.is_nil_unchecked();
350 boundary = i32::from(!base_is_nil) + base.offset_from(array) as i32;
351 self.maybe_set_aboundary(boundary);
352 boundary
353 } else {
354 debug_assert!(self.has_dummy_node() || self.get_num(size_array + 1).is_nil());
355 size_array
356 }
357 }
358 }
359
360 pub unsafe fn get_tm(&self, event: TmEvent, event_name: TString) -> Option<TValue> {
362 let tm = unsafe { self.get_str(event_name) };
363 if tm.is_nil() {
364 unsafe {
365 self.as_ptr().as_mut().unwrap_unchecked().tm_cache =
366 self.as_ptr().as_ref().unwrap_unchecked().tm_cache | (1u8 << event as usize)
367 };
368 None
369 } else {
370 Some(tm)
371 }
372 }
373}