|
1 | 1 | // @ts-self-types="./ext.d.ts" |
2 | 2 |
|
3 | 3 | import {ExtListBase, PtrBase} from './nodes.js'; |
4 | | -import {pop, extract, splice} from './basics.js'; |
| 4 | +import {pop, extract, splice, append} from './basics.js'; |
| 5 | +import SList from './core.js'; |
5 | 6 | import {addAliases, normalizeIterator} from '../meta-utils.js'; |
6 | 7 |
|
7 | 8 | export class Ptr extends PtrBase { |
@@ -171,66 +172,18 @@ export class ExtSList extends ExtListBase { |
171 | 172 | sort(lessFn) { |
172 | 173 | if (this.isOneOrEmpty) return this; |
173 | 174 |
|
174 | | - const leftHead = {}, |
175 | | - rightHead = {}; |
176 | | - leftHead[this.nextName] = leftHead; |
177 | | - rightHead[this.nextName] = rightHead; |
178 | | - |
179 | | - const left = this.make(leftHead), |
180 | | - right = this.make(rightHead); |
181 | | - |
182 | | - // split into two sublists |
183 | | - let isLeft = true; |
184 | | - for (const current of this.getNodeIterator()) { |
185 | | - current[this.nextName] = current; // make stand-alone |
186 | | - if (isLeft) { |
187 | | - left.addNodeAfter(current); |
188 | | - left.next(); |
189 | | - } else { |
190 | | - right.addNodeAfter(current); |
191 | | - right.next(); |
192 | | - } |
193 | | - isLeft = !isLeft; |
194 | | - } |
195 | | - left.removeNodeAfter(); // remove the head node |
196 | | - right.removeNodeAfter(); // remove the head node |
| 175 | + // delegate to the hosted stable natural merge sort; head lands on the sorted first node |
| 176 | + // (SList.fromExtList is unsuitable: the SLL ext range starts at head.next — a rotation |
| 177 | + // that would break stability relative to the original order) |
| 178 | + const list = new SList(this), |
| 179 | + back = this.getBack(); |
| 180 | + append(list, list, {prevFrom: back, to: back}); |
| 181 | + list.last = back; |
197 | 182 | this.clear(); |
198 | | - // the list is empty now |
199 | | - |
200 | | - // sort sublists |
201 | | - left.next().sort(lessFn); |
202 | | - right.next().sort(lessFn); |
203 | | - |
204 | | - // merge sublists |
205 | | - const leftIterator = left.getNodeIterator()[Symbol.iterator](), |
206 | | - rightIterator = right.getNodeIterator()[Symbol.iterator](); |
207 | | - let leftItem = leftIterator.next(), |
208 | | - rightItem = rightIterator.next(); |
209 | | - while (!leftItem.done && !rightItem.done) { |
210 | | - let node; |
211 | | - if (lessFn(leftItem.value, rightItem.value)) { |
212 | | - node = leftItem.value; |
213 | | - leftItem = leftIterator.next(); |
214 | | - } else { |
215 | | - node = rightItem.value; |
216 | | - rightItem = rightIterator.next(); |
217 | | - } |
218 | | - node[this.nextName] = node; // make stand-alone |
219 | | - this.addNodeAfter(node); |
220 | | - this.next(); |
221 | | - } |
222 | | - for (; !leftItem.done; this.next(), leftItem = leftIterator.next()) { |
223 | | - const node = leftItem.value; |
224 | | - node[this.nextName] = node; // make stand-alone |
225 | | - this.addNodeAfter(node); |
226 | | - } |
227 | | - for (; !rightItem.done; this.next(), rightItem = rightIterator.next()) { |
228 | | - const node = rightItem.value; |
229 | | - node[this.nextName] = node; // make stand-alone |
230 | | - this.addNodeAfter(node); |
231 | | - } |
| 183 | + list.sort(lessFn); |
| 184 | + this.attach(list.releaseRawList()); |
232 | 185 |
|
233 | | - return this.next(); |
| 186 | + return this; |
234 | 187 | } |
235 | 188 |
|
236 | 189 | [Symbol.iterator]() { |
|
0 commit comments