|
1 | 1 | // SPDX-License-Identifier: (Apache-2.0 OR MIT) |
2 | 2 |
|
3 | | -use pyo3_ffi::{PyObject, Py_hash_t, Py_ssize_t}; |
4 | | -use std::os::raw::{c_char, c_void}; |
| 3 | +use pyo3_ffi::{PyDictObject, PyObject, Py_ssize_t}; |
5 | 4 |
|
6 | 5 | #[allow(non_snake_case)] |
7 | 6 | #[inline(always)] |
8 | 7 | pub unsafe fn PyDict_GET_SIZE(op: *mut PyObject) -> Py_ssize_t { |
9 | 8 | (*op.cast::<PyDictObject>()).ma_used |
10 | 9 | } |
11 | | - |
12 | | -// dictobject.h |
13 | | -#[repr(C)] |
14 | | -#[derive(Debug, Copy, Clone)] |
15 | | -pub struct PyDictObject { |
16 | | - pub ob_refcnt: pyo3_ffi::Py_ssize_t, |
17 | | - pub ob_type: *mut pyo3_ffi::PyTypeObject, |
18 | | - pub ma_used: pyo3_ffi::Py_ssize_t, |
19 | | - pub ma_version_tag: u64, |
20 | | - pub ma_keys: *mut PyDictKeysObject, |
21 | | - pub ma_values: *mut *mut PyObject, |
22 | | -} |
23 | | - |
24 | | -// dict-common.h |
25 | | -#[repr(C)] |
26 | | -#[derive(Debug, Copy, Clone)] |
27 | | -pub struct PyDictKeyEntry { |
28 | | - pub me_hash: Py_hash_t, |
29 | | - pub me_key: *mut PyObject, |
30 | | - pub me_value: *mut PyObject, |
31 | | -} |
32 | | - |
33 | | -// dict-common.h |
34 | | -#[repr(C)] |
35 | | -#[derive(Debug, Copy, Clone)] |
36 | | -pub struct PyDictKeysObject { |
37 | | - pub dk_refcnt: Py_ssize_t, |
38 | | - pub dk_size: Py_ssize_t, |
39 | | - pub dk_lookup: *mut c_void, // dict_lookup_func |
40 | | - pub dk_usable: Py_ssize_t, |
41 | | - pub dk_nentries: Py_ssize_t, |
42 | | - pub dk_indices: [c_char; 1], |
43 | | -} |
44 | | - |
45 | | -// dictobject.c |
46 | | -#[allow(non_snake_case)] |
47 | | -#[cfg(target_pointer_width = "64")] |
48 | | -fn DK_IXSIZE(dk: *mut PyDictKeysObject) -> isize { |
49 | | - unsafe { |
50 | | - if (*dk).dk_size <= 0xff { |
51 | | - 1 |
52 | | - } else if (*dk).dk_size <= 0xffff { |
53 | | - 2 |
54 | | - } else if (*dk).dk_size <= 0xffffffff { |
55 | | - 4 |
56 | | - } else { |
57 | | - 8 |
58 | | - } |
59 | | - } |
60 | | -} |
61 | | - |
62 | | -// dictobject.c |
63 | | -#[allow(non_snake_case)] |
64 | | -#[cfg(target_pointer_width = "32")] |
65 | | -fn DK_IXSIZE(dk: *mut PyDictKeysObject) -> isize { |
66 | | - unsafe { |
67 | | - if (*dk).dk_size <= 0xff { |
68 | | - 1 |
69 | | - } else if (*dk).dk_size <= 0xffff { |
70 | | - 2 |
71 | | - } else { |
72 | | - 4 |
73 | | - } |
74 | | - } |
75 | | -} |
76 | | - |
77 | | -pub struct PyDictIter { |
78 | | - dict_ptr: *mut PyDictObject, |
79 | | - indices_ptr: *mut PyDictKeyEntry, |
80 | | - idx: usize, |
81 | | - len: usize, |
82 | | -} |
83 | | - |
84 | | -impl PyDictIter { |
85 | | - pub fn new(dict_ptr: *mut PyDictObject) -> Self { |
86 | | - unsafe { |
87 | | - let dk = (*dict_ptr).ma_keys; |
88 | | - let offset = (*dk).dk_size * DK_IXSIZE(dk); |
89 | | - let indices_ptr = std::mem::transmute::<*mut [c_char; 1], *mut u8>( |
90 | | - std::ptr::addr_of_mut!((*dk).dk_indices), |
91 | | - ) |
92 | | - .offset(offset) as *mut PyDictKeyEntry; |
93 | | - let len = PyDict_GET_SIZE(dict_ptr as *mut pyo3_ffi::PyObject) as usize; |
94 | | - PyDictIter { |
95 | | - dict_ptr: dict_ptr, |
96 | | - indices_ptr: indices_ptr, |
97 | | - idx: 0, |
98 | | - len: len, |
99 | | - } |
100 | | - } |
101 | | - } |
102 | | -} |
103 | | - |
104 | | -impl Iterator for PyDictIter { |
105 | | - type Item = (*mut pyo3_ffi::PyObject, *mut pyo3_ffi::PyObject); |
106 | | - |
107 | | - fn next(&mut self) -> Option<Self::Item> { |
108 | | - unsafe { |
109 | | - if unlikely!(self.idx == self.len) { |
110 | | - None |
111 | | - } else if !(*self.dict_ptr).ma_values.is_null() { |
112 | | - let entry_ptr: *mut PyDictKeyEntry = self.indices_ptr.add(self.idx); |
113 | | - let value = (*(*self.dict_ptr).ma_values).add(self.idx); |
114 | | - self.idx += 1; |
115 | | - Some(((*entry_ptr).me_key, value)) |
116 | | - } else { |
117 | | - let mut entry_ptr: *mut PyDictKeyEntry = self.indices_ptr.add(self.idx); |
118 | | - while self.idx < self.len && (*entry_ptr).me_value.is_null() { |
119 | | - entry_ptr = entry_ptr.add(1); |
120 | | - } |
121 | | - let value = (*entry_ptr).me_value; |
122 | | - self.idx += 1; |
123 | | - Some(((*entry_ptr).me_key, value)) |
124 | | - } |
125 | | - } |
126 | | - } |
127 | | -} |
128 | | - |
129 | | -impl ExactSizeIterator for PyDictIter { |
130 | | - fn len(&self) -> usize { |
131 | | - self.idx - self.len |
132 | | - } |
133 | | -} |
0 commit comments