@@ -195,23 +195,18 @@ static HashTable* spl_fixedarray_object_get_gc(zend_object *obj, zval **table, i
195
195
return ht ;
196
196
}
197
197
198
- static HashTable * spl_fixedarray_object_get_properties (zend_object * obj )
198
+ static HashTable * spl_fixedarray_get_properties_for (zend_object * obj , zend_prop_purpose purpose )
199
199
{
200
200
spl_fixedarray_object * intern = spl_fixed_array_from_obj (obj );
201
- HashTable * ht = zend_std_get_properties (obj );
202
201
203
- if (! spl_fixedarray_empty ( & intern -> array )) {
204
- zend_long j = zend_hash_num_elements ( ht );
202
+ /* Keep the values and properties separate*/
203
+ HashTable * ht = zend_array_dup ( zend_std_get_properties ( obj ) );
205
204
205
+ if (!spl_fixedarray_empty (& intern -> array )) {
206
206
for (zend_long i = 0 ; i < intern -> array .size ; i ++ ) {
207
- zend_hash_index_update (ht , i , & intern -> array .elements [i ]);
207
+ zend_hash_index_add_new (ht , i , & intern -> array .elements [i ]);
208
208
Z_TRY_ADDREF (intern -> array .elements [i ]);
209
209
}
210
- if (j > intern -> array .size ) {
211
- for (zend_long i = intern -> array .size ; i < j ; ++ i ) {
212
- zend_hash_index_del (ht , i );
213
- }
214
- }
215
210
}
216
211
217
212
return ht ;
@@ -628,7 +623,6 @@ PHP_METHOD(SplFixedArray, fromArray)
628
623
} else if (num > 0 && !save_indexes ) {
629
624
zval * element ;
630
625
zend_long i = 0 ;
631
-
632
626
spl_fixedarray_init (& array , num );
633
627
634
628
ZEND_HASH_FOREACH_VAL (Z_ARRVAL_P (data ), element ) {
@@ -754,6 +748,120 @@ PHP_METHOD(SplFixedArray, getIterator)
754
748
zend_create_internal_iterator_zval (return_value , ZEND_THIS );
755
749
}
756
750
751
+ /* Assumes the object has been created and the spl_fixedarray_object's
752
+ * array member is uninitialized or zero-initialized.
753
+ * The state can have string keys, but they must come prior to integers:
754
+ *
755
+ * SplFixedArray::__set_state(array(
756
+ * 'property' => 'value',
757
+ * 0 => 1,
758
+ * 1 => 2,
759
+ * 2 => 3,
760
+ * ))
761
+ */
762
+ static zend_result spl_fixedarray_import (zend_object * object , HashTable * ht )
763
+ {
764
+ spl_fixedarray_object * intern = spl_fixed_array_from_obj (object );
765
+ spl_fixedarray * fixed = & intern -> array ;
766
+
767
+ spl_fixedarray_init (fixed , 0 );
768
+
769
+ /* For performance we do a single pass over the input array and the
770
+ * spl_fixedarray elems. This complicates the implementation, but part
771
+ * of the reason for choosing SplFixedArray is for peformance, and
772
+ * although that is primarily for memory we should still care about CPU.
773
+ *
774
+ * We need to track the number of string keys, which must come before
775
+ * all the integer keys. This way the total size of the input minus the
776
+ * number of string keys equals the number of integer keys, so we can
777
+ * allocate the spl_fixedarray.elements and do this in a single pass.
778
+ */
779
+
780
+ // The total size of the input array
781
+ const zend_long nht = zend_hash_num_elements (ht );
782
+ zend_long nstrings = 0 ; // The number of string keys
783
+ zend_long nints ; // will be nht - nstrings
784
+
785
+ zend_string * str_idx = NULL ; // current string key of input array
786
+ zend_ulong num_idx = 0 ; // current int key (valid iff str_idx == NULL)
787
+ zval * val = NULL ; // current value of input array
788
+ zend_long max_idx = -1 ; // the largest index found so far
789
+ zval * begin = NULL ; // pointer to beginning of fixedarray's storage
790
+ zval * end = NULL ; // points one element passed the last element
791
+ const char * ex_msg = NULL ; // message for the value exception
792
+
793
+ ZEND_HASH_FOREACH_KEY_VAL (ht , num_idx , str_idx , val ) {
794
+ if (str_idx != NULL ) {
795
+ if (UNEXPECTED (max_idx >= 0 )) {
796
+ ex_msg = "must have all its string keys come before all integer keys" ;
797
+ goto value_error ;
798
+ }
799
+
800
+ ++ nstrings ;
801
+ object -> handlers -> write_property (object , str_idx , val , NULL );
802
+
803
+ } else if (UNEXPECTED ((zend_long )num_idx != ++ max_idx )) {
804
+ ex_msg = "did not have integer keys that start at 0 and increment sequentially" ;
805
+ goto value_error ;
806
+
807
+ } else {
808
+ if (UNEXPECTED (max_idx == 0 )) {
809
+ nints = nht - nstrings ;
810
+ fixed -> size = nints ;
811
+ fixed -> elements =
812
+ safe_emalloc (nints , sizeof (zval ), 0 );
813
+ begin = fixed -> elements ;
814
+ end = fixed -> elements + nints ;
815
+ }
816
+
817
+ ZEND_ASSERT (num_idx == max_idx );
818
+ ZEND_ASSERT (begin != end );
819
+
820
+ ZVAL_COPY (begin ++ , val );
821
+ }
822
+ } ZEND_HASH_FOREACH_END ();
823
+
824
+ ZEND_ASSERT (begin == end );
825
+ return SUCCESS ;
826
+
827
+ value_error :
828
+ spl_fixedarray_dtor_range (fixed , 0 , max_idx );
829
+ if (fixed -> elements ) {
830
+ efree (fixed -> elements );
831
+ }
832
+
833
+ /* Zero-initialize so the object release is valid. */
834
+ spl_fixedarray_init (fixed , 0 );
835
+ zend_object_release (object );
836
+
837
+ zend_argument_value_error (1 , ex_msg );
838
+ return FAILURE ;
839
+ }
840
+
841
+ PHP_METHOD (SplFixedArray , __set_state )
842
+ {
843
+ zval * state = NULL ;
844
+
845
+ ZEND_PARSE_PARAMETERS_START (1 , 1 )
846
+ Z_PARAM_ARRAY (state );
847
+ ZEND_PARSE_PARAMETERS_END ();
848
+
849
+ HashTable * ht = Z_ARRVAL_P (state );
850
+ zend_class_entry * called_scope = zend_get_called_scope (execute_data );
851
+
852
+ zend_result result = object_init_ex (return_value , called_scope );
853
+ if (UNEXPECTED (result != SUCCESS )) {
854
+ ZVAL_NULL (return_value );
855
+ RETURN_THROWS ();
856
+ }
857
+
858
+ zend_object * object = Z_OBJ_P (return_value );
859
+ if (UNEXPECTED (spl_fixedarray_import (object , ht ) != SUCCESS )) {
860
+ ZVAL_NULL (return_value );
861
+ RETURN_THROWS ();
862
+ }
863
+ }
864
+
757
865
static void spl_fixedarray_it_dtor (zend_object_iterator * iter )
758
866
{
759
867
zval_ptr_dtor (& iter -> data );
@@ -844,7 +952,8 @@ PHP_MINIT_FUNCTION(spl_fixedarray)
844
952
spl_handler_SplFixedArray .unset_dimension = spl_fixedarray_object_unset_dimension ;
845
953
spl_handler_SplFixedArray .has_dimension = spl_fixedarray_object_has_dimension ;
846
954
spl_handler_SplFixedArray .count_elements = spl_fixedarray_object_count_elements ;
847
- spl_handler_SplFixedArray .get_properties = spl_fixedarray_object_get_properties ;
955
+ spl_handler_SplFixedArray .get_properties_for
956
+ = spl_fixedarray_get_properties_for ;
848
957
spl_handler_SplFixedArray .get_gc = spl_fixedarray_object_get_gc ;
849
958
spl_handler_SplFixedArray .dtor_obj = zend_objects_destroy_object ;
850
959
spl_handler_SplFixedArray .free_obj = spl_fixedarray_object_free_storage ;
0 commit comments