@@ -72,11 +72,11 @@ public function map_post( $byte_offset, $data ) {
72
72
--$ this ->orphan_post_counter ;
73
73
}
74
74
75
- // This is an array saved as: [ parent, byte_offset, moved ], to save space and not using an associative one.
75
+ // This is an array saved as: [ parent, byte_offset ], to save
76
+ // space and not using an associative one.
76
77
$ this ->posts [ $ data ['post_id ' ] ] = array (
77
78
$ data ['post_parent ' ],
78
79
$ byte_offset ,
79
- false ,
80
80
);
81
81
}
82
82
@@ -120,110 +120,58 @@ public function is_sorted() {
120
120
*
121
121
* Sorted posts will be stored as attachments and posts/pages separately.
122
122
*/
123
- public function sort_topologically ( $ empty_memory = true ) {
123
+ public function sort_topologically ( $ free_space = true ) {
124
124
foreach ( $ this ->categories as $ slug => $ category ) {
125
125
$ this ->topological_category_sort ( $ slug , $ category );
126
126
}
127
127
128
- $ this ->sort_parent_child ( $ this ->posts );
128
+ $ this ->sort_elements ( $ this ->posts );
129
129
130
- // Empty some memory.
131
- if ( $ empty_memory ) {
130
+ // Free some space.
131
+ if ( $ free_space ) {
132
+ /**
133
+ * @TODO: all the elements that have not been moved can be flushed away.
134
+ */
132
135
foreach ( $ this ->posts as $ id => $ element ) {
133
- if ( ! $ element [2 ] ) {
134
- // The element have not been moved, unset it.
135
- unset( $ this ->posts [ $ id ] );
136
- } else {
137
- // Save only the byte offset.
138
- $ this ->posts [ $ id ] = $ element [1 ];
139
- }
136
+ // Save only the byte offset.
137
+ $ this ->posts [ $ id ] = $ element [1 ];
140
138
}
141
139
}
142
140
143
141
$ this ->sorted = true ;
144
142
}
145
143
146
144
/**
147
- * Recursive topological sorting.
148
- * @todo Check for circular dependencies.
149
- *
150
- * @param array $elements The elements to sort.
145
+ * Recursive sort elements. Posts with parents will be moved to the correct position.
151
146
*
152
- * @return void
147
+ * @return true
153
148
*/
154
- private function sort_parent_child ( &$ elements ) {
155
- // Sort the array in-place.
156
- // reset( $elements );
157
- $ position = 0 ; // key( $elements );
158
- $ length = count ( $ elements );
159
-
160
- if ( $ length < 2 ) {
161
- // No need to sort.
162
- return ;
163
- }
164
-
165
- if ( 2 === $ length ) {
166
- $ keys = array_keys ( $ elements );
167
-
168
- // First element has a parent and is the second.
169
- if ( $ elements [ $ keys [0 ] ][0 ] && $ keys [1 ] === $ elements [ $ keys [0 ] ][0 ] ) {
170
- // Swap.
171
- $ elements = array_reverse ( $ elements , true );
172
-
173
- // Set the second as 'moved'.
174
- $ elements [ $ keys [1 ] ][2 ] = true ;
149
+ private function sort_elements ( &$ elements ) {
150
+ $ sort_callback = function ( $ a , $ b ) use ( &$ elements ) {
151
+ $ parent_a = $ elements [ $ a ][0 ];
152
+ $ parent_b = $ elements [ $ b ][0 ];
153
+
154
+ if ( ! $ parent_a && ! $ parent_b ) {
155
+ // No parents.
156
+ return 0 ;
157
+ } elseif ( $ a === $ parent_b ) {
158
+ // A is the parent of B.
159
+ return -1 ;
160
+ } elseif ( $ b === $ parent_a ) {
161
+ // B is the parent of A.
162
+ return 1 ;
175
163
}
176
164
177
- return ;
178
- }
179
-
180
- foreach ( $ elements as $ id => $ element ) {
181
- if ( empty ( $ element [0 ] ) ) {
182
- $ this ->move_element ( $ elements , $ id , $ position );
183
- }
184
- }
185
- }
186
-
187
- /**
188
- * Move an element to a new position.
189
- *
190
- * @param array $elements The elements to sort.
191
- * @param int $id The ID of the element to move.
192
- * @param int $position The new position of the element.
193
- *
194
- * @return void
195
- */
196
- private function move_element ( &$ elements , $ id , &$ position ) {
197
- if ( ! isset ( $ elements [ $ id ] ) ) {
198
- return ;
199
- }
200
-
201
- $ element = $ elements [ $ id ];
165
+ return 0 ;
166
+ };
202
167
203
- if ( $ id < $ position ) {
204
- // Already in the correct position.
205
- return ;
206
- }
207
-
208
- // Move the element to the current position.
209
- unset( $ elements [ $ id ] );
210
-
211
- // Set as 'moved'.
212
- $ element [2 ] = true ;
213
-
214
- // Generate the new array.
215
- $ elements = array_slice ( $ elements , 0 , $ position , true ) +
216
- array ( $ id => $ element ) +
217
- array_slice ( $ elements , $ position , null , true );
218
-
219
- ++$ position ;
220
-
221
- // Move children.
222
- foreach ( $ elements as $ child_id => $ child_element ) {
223
- if ( $ id === $ child_element [0 ] ) {
224
- $ this ->move_element ( $ elements , $ child_id , $ position );
225
- }
226
- }
168
+ /**
169
+ * @TODO: PHP uses quicksort: https://github.com/php/php-src/blob/master/Zend/zend_sort.c
170
+ * WordPress export posts by ID and so are likely to be already in order.
171
+ * Quicksort performs badly on already sorted arrays, O(n^2) is the worst case.
172
+ * Let's consider using a different sorting algorithm.
173
+ */
174
+ uksort ( $ elements , $ sort_callback );
227
175
}
228
176
229
177
/**
0 commit comments