@@ -7,7 +7,6 @@ use std::{
7
7
ffi:: CString ,
8
8
fmt:: Debug ,
9
9
iter:: FromIterator ,
10
- ptr:: NonNull ,
11
10
u64,
12
11
} ;
13
12
@@ -16,10 +15,12 @@ use crate::{
16
15
convert:: { FromZval , IntoZval } ,
17
16
error:: { Error , Result } ,
18
17
ffi:: {
19
- _Bucket, _zend_new_array, zend_array_destroy, zend_array_dup, zend_hash_clean,
20
- zend_hash_index_del, zend_hash_index_find, zend_hash_index_update,
18
+ _zend_new_array, zend_array_count, zend_array_destroy, zend_array_dup, zend_hash_clean,
19
+ zend_hash_get_current_data_ex, zend_hash_get_current_key_type_ex,
20
+ zend_hash_get_current_key_zval_ex, zend_hash_index_del, zend_hash_index_find,
21
+ zend_hash_index_update, zend_hash_move_backwards_ex, zend_hash_move_forward_ex,
21
22
zend_hash_next_index_insert, zend_hash_str_del, zend_hash_str_find, zend_hash_str_update,
22
- HT_MIN_SIZE ,
23
+ HashPosition , HT_MIN_SIZE ,
23
24
} ,
24
25
flags:: DataType ,
25
26
types:: Zval ,
@@ -117,7 +118,7 @@ impl ZendHashTable {
117
118
/// assert_eq!(ht.len(), 2);
118
119
/// ```
119
120
pub fn len ( & self ) -> usize {
120
- self . nNumOfElements as usize
121
+ unsafe { zend_array_count ( self as * const ZendHashTable as * mut ZendHashTable ) as usize }
121
122
}
122
123
123
124
/// Returns whether the hash table is empty.
@@ -520,8 +521,8 @@ impl ToOwned for ZendHashTable {
520
521
/// Immutable iterator upon a reference to a hashtable.
521
522
pub struct Iter < ' a > {
522
523
ht : & ' a ZendHashTable ,
523
- pos : Option < NonNull < _Bucket > > ,
524
- end : Option < NonNull < _Bucket > > ,
524
+ current_num : u64 ,
525
+ pos : HashPosition ,
525
526
}
526
527
527
528
impl < ' a > Iter < ' a > {
@@ -531,37 +532,57 @@ impl<'a> Iter<'a> {
531
532
///
532
533
/// * `ht` - The hashtable to iterate.
533
534
pub fn new ( ht : & ' a ZendHashTable ) -> Self {
534
- #[ cfg( not( php82) ) ]
535
- return Self {
535
+ Self {
536
536
ht,
537
- pos : NonNull :: new ( ht. arData ) ,
538
- end : NonNull :: new ( unsafe { ht. arData . offset ( ht. nNumUsed as isize ) } ) ,
539
- } ;
540
- #[ cfg( php82) ]
541
- return Self {
542
- ht,
543
- pos : NonNull :: new ( unsafe { ht. __bindgen_anon_1 . arData } ) ,
544
- end : NonNull :: new ( unsafe { ht. __bindgen_anon_1 . arData . offset ( ht. nNumUsed as isize ) } ) ,
545
- } ;
537
+ current_num : 0 ,
538
+ pos : 0 ,
539
+ }
546
540
}
547
541
}
548
542
549
543
impl < ' a > Iterator for Iter < ' a > {
550
544
type Item = ( u64 , Option < String > , & ' a Zval ) ;
551
545
552
546
fn next ( & mut self ) -> Option < Self :: Item > {
553
- let pos = self . pos ?;
547
+ let key_type = unsafe {
548
+ zend_hash_get_current_key_type_ex (
549
+ self . ht as * const ZendHashTable as * mut ZendHashTable ,
550
+ & mut self . pos as * mut HashPosition ,
551
+ )
552
+ } ;
554
553
555
- if pos == self . end ? {
554
+ if key_type == - 1 {
556
555
return None ;
557
556
}
558
557
559
- let bucket = unsafe { pos. as_ref ( ) } ;
560
- let key = unsafe { bucket. key . as_ref ( ) } . and_then ( |s| s. try_into ( ) . ok ( ) ) ;
558
+ let key = Zval :: new ( ) ;
559
+ unsafe {
560
+ zend_hash_get_current_key_zval_ex (
561
+ self . ht as * const ZendHashTable as * mut ZendHashTable ,
562
+ & key as * const Zval as * mut Zval ,
563
+ & mut self . pos as * mut HashPosition ,
564
+ ) ;
565
+ }
566
+ let value = unsafe {
567
+ & * zend_hash_get_current_data_ex (
568
+ self . ht as * const ZendHashTable as * mut ZendHashTable ,
569
+ & mut self . pos as * mut HashPosition ,
570
+ )
571
+ } ;
572
+ let r: ( u64 , Option < String > , & Zval ) = match key. is_long ( ) {
573
+ true => ( key. long ( ) . unwrap_or ( 0 ) as u64 , None , value) ,
574
+ false => ( self . current_num , key. try_into ( ) . ok ( ) , value) ,
575
+ } ;
561
576
562
- self . pos = NonNull :: new ( unsafe { pos. as_ptr ( ) . offset ( 1 ) } ) ;
577
+ unsafe {
578
+ zend_hash_move_forward_ex (
579
+ self . ht as * const ZendHashTable as * mut ZendHashTable ,
580
+ & mut self . pos as * mut HashPosition ,
581
+ )
582
+ } ;
583
+ self . current_num += 1 ;
563
584
564
- Some ( ( bucket . h , key , & bucket . val ) )
585
+ Some ( r )
565
586
}
566
587
567
588
fn count ( self ) -> usize
@@ -580,18 +601,45 @@ impl<'a> ExactSizeIterator for Iter<'a> {
580
601
581
602
impl < ' a > DoubleEndedIterator for Iter < ' a > {
582
603
fn next_back ( & mut self ) -> Option < Self :: Item > {
583
- let end = self . end ?;
604
+ let key_type = unsafe {
605
+ zend_hash_get_current_key_type_ex (
606
+ self . ht as * const ZendHashTable as * mut ZendHashTable ,
607
+ & mut self . pos as * mut HashPosition ,
608
+ )
609
+ } ;
584
610
585
- if end == self . pos ? {
611
+ if key_type == - 1 {
586
612
return None ;
587
613
}
588
614
589
- let new_end = NonNull :: new ( unsafe { end. as_ptr ( ) . offset ( -1 ) } ) ?;
590
- let bucket = unsafe { new_end. as_ref ( ) } ;
591
- let key = unsafe { bucket. key . as_ref ( ) } . and_then ( |s| s. try_into ( ) . ok ( ) ) ;
592
- self . end = Some ( new_end) ;
615
+ let key = Zval :: new ( ) ;
616
+ unsafe {
617
+ zend_hash_get_current_key_zval_ex (
618
+ self . ht as * const ZendHashTable as * mut ZendHashTable ,
619
+ & key as * const Zval as * mut Zval ,
620
+ & mut self . pos as * mut HashPosition ,
621
+ ) ;
622
+ }
623
+ let value = unsafe {
624
+ & * zend_hash_get_current_data_ex (
625
+ self . ht as * const ZendHashTable as * mut ZendHashTable ,
626
+ & mut self . pos as * mut HashPosition ,
627
+ )
628
+ } ;
629
+ let r: ( u64 , Option < String > , & Zval ) = match key. is_long ( ) {
630
+ true => ( key. long ( ) . unwrap_or ( 0 ) as u64 , None , value) ,
631
+ false => ( self . current_num , key. try_into ( ) . ok ( ) , value) ,
632
+ } ;
633
+
634
+ unsafe {
635
+ zend_hash_move_backwards_ex (
636
+ self . ht as * const ZendHashTable as * mut ZendHashTable ,
637
+ & mut self . pos as * mut HashPosition ,
638
+ )
639
+ } ;
640
+ self . current_num -= 1 ;
593
641
594
- Some ( ( bucket . h , key , & bucket . val ) )
642
+ Some ( r )
595
643
}
596
644
}
597
645
0 commit comments