authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-09-20 10:29:02-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2025-09-20 10:29:02-07:00
log4d1b15bd9d4175127a63595f4fd80761c2e6564c
tree9b206e8d72212d4f7195c247ad8508f7c0ce0b32
parent14fc4d481151d6ac0fb433d625cc97b4c2fe3eba
parent1eeb8fabe5ed49c2e334c82ece741818f5d37412
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #25298 from ziglang/SegmentedList-orphaned-again

std: delete SegmentedList again

5 files changed, 11 insertions(+), 749 deletions(-)

lib/std/segmented_list.zig deleted-531
...@@ -1,531 +0,0 @@
1const std = @import("std.zig");
2const assert = std.debug.assert;
3const testing = std.testing;
4const mem = std.mem;
5const Allocator = std.mem.Allocator;
6
7// Imagine that `fn at(self: *Self, index: usize) &T` is a customer asking for a box
8// from a warehouse, based on a flat array, boxes ordered from 0 to N - 1.
9// But the warehouse actually stores boxes in shelves of increasing powers of 2 sizes.
10// So when the customer requests a box index, we have to translate it to shelf index
11// and box index within that shelf. Illustration:
12//
13// customer indexes:
14// shelf 0: 0
15// shelf 1: 1 2
16// shelf 2: 3 4 5 6
17// shelf 3: 7 8 9 10 11 12 13 14
18// shelf 4: 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
19// shelf 5: 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
20// ...
21//
22// warehouse indexes:
23// shelf 0: 0
24// shelf 1: 0 1
25// shelf 2: 0 1 2 3
26// shelf 3: 0 1 2 3 4 5 6 7
27// shelf 4: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
28// shelf 5: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
29// ...
30//
31// With this arrangement, here are the equations to get the shelf index and
32// box index based on customer box index:
33//
34// shelf_index = floor(log2(customer_index + 1))
35// shelf_count = ceil(log2(box_count + 1))
36// box_index = customer_index + 1 - 2 ** shelf
37// shelf_size = 2 ** shelf_index
38//
39// Now we complicate it a little bit further by adding a preallocated shelf, which must be
40// a power of 2:
41// prealloc=4
42//
43// customer indexes:
44// prealloc: 0 1 2 3
45// shelf 0: 4 5 6 7 8 9 10 11
46// shelf 1: 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
47// shelf 2: 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
48// ...
49//
50// warehouse indexes:
51// prealloc: 0 1 2 3
52// shelf 0: 0 1 2 3 4 5 6 7
53// shelf 1: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
54// shelf 2: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
55// ...
56//
57// Now the equations are:
58//
59// shelf_index = floor(log2(customer_index + prealloc)) - log2(prealloc) - 1
60// shelf_count = ceil(log2(box_count + prealloc)) - log2(prealloc) - 1
61// box_index = customer_index + prealloc - 2 ** (log2(prealloc) + 1 + shelf)
62// shelf_size = prealloc * 2 ** (shelf_index + 1)
63
64/// This is a stack data structure where pointers to indexes have the same lifetime as the data structure
65/// itself, unlike ArrayList where append() invalidates all existing element pointers.
66/// The tradeoff is that elements are not guaranteed to be contiguous. For that, use ArrayList.
67/// Note however that most elements are contiguous, making this data structure cache-friendly.
68///
69/// Because it never has to copy elements from an old location to a new location, it does not require
70/// its elements to be copyable, and it avoids wasting memory when backed by an ArenaAllocator.
71/// Note that the append() and pop() convenience methods perform a copy, but you can instead use
72/// addOne(), at(), setCapacity(), and shrinkCapacity() to avoid copying items.
73///
74/// This data structure has O(1) append and O(1) pop.
75///
76/// It supports preallocated elements, making it especially well suited when the expected maximum
77/// size is small. `prealloc_item_count` must be 0, or a power of 2.
78pub fn SegmentedList(comptime T: type, comptime prealloc_item_count: usize) type {
79 return struct {
80 const Self = @This();
81 const ShelfIndex = std.math.Log2Int(usize);
82
83 const prealloc_exp: ShelfIndex = blk: {
84 // we don't use the prealloc_exp constant when prealloc_item_count is 0
85 // but lazy-init may still be triggered by other code so supply a value
86 if (prealloc_item_count == 0) {
87 break :blk 0;
88 } else {
89 assert(std.math.isPowerOfTwo(prealloc_item_count));
90 const value = std.math.log2_int(usize, prealloc_item_count);
91 break :blk value;
92 }
93 };
94
95 prealloc_segment: [prealloc_item_count]T = undefined,
96 dynamic_segments: [][*]T = &[_][*]T{},
97 len: usize = 0,
98
99 pub const prealloc_count = prealloc_item_count;
100
101 fn AtType(comptime SelfType: type) type {
102 if (@typeInfo(SelfType).pointer.is_const) {
103 return *const T;
104 } else {
105 return *T;
106 }
107 }
108
109 pub fn deinit(self: *Self, allocator: Allocator) void {
110 self.freeShelves(allocator, @as(ShelfIndex, @intCast(self.dynamic_segments.len)), 0);
111 allocator.free(self.dynamic_segments);
112 self.* = undefined;
113 }
114
115 pub fn at(self: anytype, i: usize) AtType(@TypeOf(self)) {
116 assert(i < self.len);
117 return self.uncheckedAt(i);
118 }
119
120 pub fn count(self: Self) usize {
121 return self.len;
122 }
123
124 pub fn append(self: *Self, allocator: Allocator, item: T) Allocator.Error!void {
125 const new_item_ptr = try self.addOne(allocator);
126 new_item_ptr.* = item;
127 }
128
129 pub fn appendSlice(self: *Self, allocator: Allocator, items: []const T) Allocator.Error!void {
130 for (items) |item| {
131 try self.append(allocator, item);
132 }
133 }
134
135 pub fn pop(self: *Self) ?T {
136 if (self.len == 0) return null;
137
138 const index = self.len - 1;
139 const result = uncheckedAt(self, index).*;
140 self.len = index;
141 return result;
142 }
143
144 pub fn addOne(self: *Self, allocator: Allocator) Allocator.Error!*T {
145 const new_length = self.len + 1;
146 try self.growCapacity(allocator, new_length);
147 const result = uncheckedAt(self, self.len);
148 self.len = new_length;
149 return result;
150 }
151
152 /// Reduce length to `new_len`.
153 /// Invalidates pointers for the elements at index new_len and beyond.
154 pub fn shrinkRetainingCapacity(self: *Self, new_len: usize) void {
155 assert(new_len <= self.len);
156 self.len = new_len;
157 }
158
159 /// Invalidates all element pointers.
160 pub fn clearRetainingCapacity(self: *Self) void {
161 self.len = 0;
162 }
163
164 /// Invalidates all element pointers.
165 pub fn clearAndFree(self: *Self, allocator: Allocator) void {
166 self.setCapacity(allocator, 0) catch unreachable;
167 self.len = 0;
168 }
169
170 /// Grows or shrinks capacity to match usage.
171 /// TODO update this and related methods to match the conventions set by ArrayList
172 pub fn setCapacity(self: *Self, allocator: Allocator, new_capacity: usize) Allocator.Error!void {
173 if (prealloc_item_count != 0) {
174 if (new_capacity <= @as(usize, 1) << (prealloc_exp + @as(ShelfIndex, @intCast(self.dynamic_segments.len)))) {
175 return self.shrinkCapacity(allocator, new_capacity);
176 }
177 }
178 return self.growCapacity(allocator, new_capacity);
179 }
180
181 /// Only grows capacity, or retains current capacity.
182 pub fn growCapacity(self: *Self, allocator: Allocator, new_capacity: usize) Allocator.Error!void {
183 const new_cap_shelf_count = shelfCount(new_capacity);
184 const old_shelf_count = @as(ShelfIndex, @intCast(self.dynamic_segments.len));
185 if (new_cap_shelf_count <= old_shelf_count) return;
186
187 const new_dynamic_segments = try allocator.alloc([*]T, new_cap_shelf_count);
188 errdefer allocator.free(new_dynamic_segments);
189
190 var i: ShelfIndex = 0;
191 while (i < old_shelf_count) : (i += 1) {
192 new_dynamic_segments[i] = self.dynamic_segments[i];
193 }
194 errdefer while (i > old_shelf_count) : (i -= 1) {
195 allocator.free(new_dynamic_segments[i][0..shelfSize(i)]);
196 };
197 while (i < new_cap_shelf_count) : (i += 1) {
198 new_dynamic_segments[i] = (try allocator.alloc(T, shelfSize(i))).ptr;
199 }
200
201 allocator.free(self.dynamic_segments);
202 self.dynamic_segments = new_dynamic_segments;
203 }
204
205 /// Only shrinks capacity or retains current capacity.
206 /// It may fail to reduce the capacity in which case the capacity will remain unchanged.
207 pub fn shrinkCapacity(self: *Self, allocator: Allocator, new_capacity: usize) void {
208 if (new_capacity <= prealloc_item_count) {
209 const len = @as(ShelfIndex, @intCast(self.dynamic_segments.len));
210 self.freeShelves(allocator, len, 0);
211 allocator.free(self.dynamic_segments);
212 self.dynamic_segments = &[_][*]T{};
213 return;
214 }
215
216 const new_cap_shelf_count = shelfCount(new_capacity);
217 const old_shelf_count = @as(ShelfIndex, @intCast(self.dynamic_segments.len));
218 assert(new_cap_shelf_count <= old_shelf_count);
219 if (new_cap_shelf_count == old_shelf_count) return;
220
221 // freeShelves() must be called before resizing the dynamic
222 // segments, but we don't know if resizing the dynamic segments
223 // will work until we try it. So we must allocate a fresh memory
224 // buffer in order to reduce capacity.
225 const new_dynamic_segments = allocator.alloc([*]T, new_cap_shelf_count) catch return;
226 self.freeShelves(allocator, old_shelf_count, new_cap_shelf_count);
227 if (allocator.resize(self.dynamic_segments, new_cap_shelf_count)) {
228 // We didn't need the new memory allocation after all.
229 self.dynamic_segments = self.dynamic_segments[0..new_cap_shelf_count];
230 allocator.free(new_dynamic_segments);
231 } else {
232 // Good thing we allocated that new memory slice.
233 @memcpy(new_dynamic_segments, self.dynamic_segments[0..new_cap_shelf_count]);
234 allocator.free(self.dynamic_segments);
235 self.dynamic_segments = new_dynamic_segments;
236 }
237 }
238
239 pub fn shrink(self: *Self, new_len: usize) void {
240 assert(new_len <= self.len);
241 // TODO take advantage of the new realloc semantics
242 self.len = new_len;
243 }
244
245 pub fn writeToSlice(self: *Self, dest: []T, start: usize) void {
246 const end = start + dest.len;
247 assert(end <= self.len);
248
249 var i = start;
250 if (end <= prealloc_item_count) {
251 const src = self.prealloc_segment[i..end];
252 @memcpy(dest[i - start ..][0..src.len], src);
253 return;
254 } else if (i < prealloc_item_count) {
255 const src = self.prealloc_segment[i..];
256 @memcpy(dest[i - start ..][0..src.len], src);
257 i = prealloc_item_count;
258 }
259
260 while (i < end) {
261 const shelf_index = shelfIndex(i);
262 const copy_start = boxIndex(i, shelf_index);
263 const copy_end = @min(shelfSize(shelf_index), copy_start + end - i);
264 const src = self.dynamic_segments[shelf_index][copy_start..copy_end];
265 @memcpy(dest[i - start ..][0..src.len], src);
266 i += (copy_end - copy_start);
267 }
268 }
269
270 pub fn uncheckedAt(self: anytype, index: usize) AtType(@TypeOf(self)) {
271 if (index < prealloc_item_count) {
272 return &self.prealloc_segment[index];
273 }
274 const shelf_index = shelfIndex(index);
275 const box_index = boxIndex(index, shelf_index);
276 return &self.dynamic_segments[shelf_index][box_index];
277 }
278
279 fn shelfCount(box_count: usize) ShelfIndex {
280 if (prealloc_item_count == 0) {
281 return log2_int_ceil(usize, box_count + 1);
282 }
283 return log2_int_ceil(usize, box_count + prealloc_item_count) - prealloc_exp - 1;
284 }
285
286 fn shelfSize(shelf_index: ShelfIndex) usize {
287 if (prealloc_item_count == 0) {
288 return @as(usize, 1) << shelf_index;
289 }
290 return @as(usize, 1) << (shelf_index + (prealloc_exp + 1));
291 }
292
293 fn shelfIndex(list_index: usize) ShelfIndex {
294 if (prealloc_item_count == 0) {
295 return std.math.log2_int(usize, list_index + 1);
296 }
297 return std.math.log2_int(usize, list_index + prealloc_item_count) - prealloc_exp - 1;
298 }
299
300 fn boxIndex(list_index: usize, shelf_index: ShelfIndex) usize {
301 if (prealloc_item_count == 0) {
302 return (list_index + 1) - (@as(usize, 1) << shelf_index);
303 }
304 return list_index + prealloc_item_count - (@as(usize, 1) << ((prealloc_exp + 1) + shelf_index));
305 }
306
307 fn freeShelves(self: *Self, allocator: Allocator, from_count: ShelfIndex, to_count: ShelfIndex) void {
308 var i = from_count;
309 while (i != to_count) {
310 i -= 1;
311 allocator.free(self.dynamic_segments[i][0..shelfSize(i)]);
312 }
313 }
314
315 pub const Iterator = BaseIterator(*Self, *T);
316 pub const ConstIterator = BaseIterator(*const Self, *const T);
317 fn BaseIterator(comptime SelfType: type, comptime ElementPtr: type) type {
318 return struct {
319 list: SelfType,
320 index: usize,
321 box_index: usize,
322 shelf_index: ShelfIndex,
323 shelf_size: usize,
324
325 pub fn next(it: *@This()) ?ElementPtr {
326 if (it.index >= it.list.len) return null;
327 if (it.index < prealloc_item_count) {
328 const ptr = &it.list.prealloc_segment[it.index];
329 it.index += 1;
330 if (it.index == prealloc_item_count) {
331 it.box_index = 0;
332 it.shelf_index = 0;
333 it.shelf_size = prealloc_item_count * 2;
334 }
335 return ptr;
336 }
337
338 const ptr = &it.list.dynamic_segments[it.shelf_index][it.box_index];
339 it.index += 1;
340 it.box_index += 1;
341 if (it.box_index == it.shelf_size) {
342 it.shelf_index += 1;
343 it.box_index = 0;
344 it.shelf_size *= 2;
345 }
346 return ptr;
347 }
348
349 pub fn prev(it: *@This()) ?ElementPtr {
350 if (it.index == 0) return null;
351
352 it.index -= 1;
353 if (it.index < prealloc_item_count) return &it.list.prealloc_segment[it.index];
354
355 if (it.box_index == 0) {
356 it.shelf_index -= 1;
357 it.shelf_size /= 2;
358 it.box_index = it.shelf_size - 1;
359 } else {
360 it.box_index -= 1;
361 }
362
363 return &it.list.dynamic_segments[it.shelf_index][it.box_index];
364 }
365
366 pub fn peek(it: *@This()) ?ElementPtr {
367 if (it.index >= it.list.len)
368 return null;
369 if (it.index < prealloc_item_count)
370 return &it.list.prealloc_segment[it.index];
371
372 return &it.list.dynamic_segments[it.shelf_index][it.box_index];
373 }
374
375 pub fn set(it: *@This(), index: usize) void {
376 it.index = index;
377 if (index < prealloc_item_count) return;
378 it.shelf_index = shelfIndex(index);
379 it.box_index = boxIndex(index, it.shelf_index);
380 it.shelf_size = shelfSize(it.shelf_index);
381 }
382 };
383 }
384
385 pub fn iterator(self: *Self, start_index: usize) Iterator {
386 var it = Iterator{
387 .list = self,
388 .index = undefined,
389 .shelf_index = undefined,
390 .box_index = undefined,
391 .shelf_size = undefined,
392 };
393 it.set(start_index);
394 return it;
395 }
396
397 pub fn constIterator(self: *const Self, start_index: usize) ConstIterator {
398 var it = ConstIterator{
399 .list = self,
400 .index = undefined,
401 .shelf_index = undefined,
402 .box_index = undefined,
403 .shelf_size = undefined,
404 };
405 it.set(start_index);
406 return it;
407 }
408 };
409}
410
411test "basic usage" {
412 try testSegmentedList(0);
413 try testSegmentedList(1);
414 try testSegmentedList(2);
415 try testSegmentedList(4);
416 try testSegmentedList(8);
417 try testSegmentedList(16);
418}
419
420fn testSegmentedList(comptime prealloc: usize) !void {
421 var list = SegmentedList(i32, prealloc){};
422 defer list.deinit(testing.allocator);
423
424 {
425 var i: usize = 0;
426 while (i < 100) : (i += 1) {
427 try list.append(testing.allocator, @as(i32, @intCast(i + 1)));
428 try testing.expect(list.len == i + 1);
429 }
430 }
431
432 {
433 var i: usize = 0;
434 while (i < 100) : (i += 1) {
435 try testing.expect(list.at(i).* == @as(i32, @intCast(i + 1)));
436 }
437 }
438
439 {
440 var it = list.iterator(0);
441 var x: i32 = 0;
442 while (it.next()) |item| {
443 x += 1;
444 try testing.expect(item.* == x);
445 }
446 try testing.expect(x == 100);
447 while (it.prev()) |item| : (x -= 1) {
448 try testing.expect(item.* == x);
449 }
450 try testing.expect(x == 0);
451 }
452
453 {
454 var it = list.constIterator(0);
455 var x: i32 = 0;
456 while (it.next()) |item| {
457 x += 1;
458 try testing.expect(item.* == x);
459 }
460 try testing.expect(x == 100);
461 while (it.prev()) |item| : (x -= 1) {
462 try testing.expect(item.* == x);
463 }
464 try testing.expect(x == 0);
465 }
466
467 try testing.expect(list.pop().? == 100);
468 try testing.expect(list.len == 99);
469
470 try list.appendSlice(testing.allocator, &[_]i32{ 1, 2, 3 });
471 try testing.expect(list.len == 102);
472 try testing.expect(list.pop().? == 3);
473 try testing.expect(list.pop().? == 2);
474 try testing.expect(list.pop().? == 1);
475 try testing.expect(list.len == 99);
476
477 try list.appendSlice(testing.allocator, &[_]i32{});
478 try testing.expect(list.len == 99);
479
480 {
481 var i: i32 = 99;
482 while (list.pop()) |item| : (i -= 1) {
483 try testing.expect(item == i);
484 list.shrinkCapacity(testing.allocator, list.len);
485 }
486 }
487
488 {
489 var control: [100]i32 = undefined;
490 var dest: [100]i32 = undefined;
491
492 var i: i32 = 0;
493 while (i < 100) : (i += 1) {
494 try list.append(testing.allocator, i + 1);
495 control[@as(usize, @intCast(i))] = i + 1;
496 }
497
498 @memset(dest[0..], 0);
499 list.writeToSlice(dest[0..], 0);
500 try testing.expect(mem.eql(i32, control[0..], dest[0..]));
501
502 @memset(dest[0..], 0);
503 list.writeToSlice(dest[50..], 50);
504 try testing.expect(mem.eql(i32, control[50..], dest[50..]));
505 }
506
507 try list.setCapacity(testing.allocator, 0);
508}
509
510test "clearRetainingCapacity" {
511 var list = SegmentedList(i32, 1){};
512 defer list.deinit(testing.allocator);
513
514 try list.appendSlice(testing.allocator, &[_]i32{ 4, 5 });
515 list.clearRetainingCapacity();
516 try list.append(testing.allocator, 6);
517 try testing.expect(list.at(0).* == 6);
518 try testing.expect(list.len == 1);
519 list.clearRetainingCapacity();
520 try testing.expect(list.len == 0);
521}
522
523/// TODO look into why this std.math function was changed in
524/// fc9430f56798a53f9393a697f4ccd6bf9981b970.
525fn log2_int_ceil(comptime T: type, x: T) std.math.Log2Int(T) {
526 assert(x != 0);
527 const log2_val = std.math.log2_int(T, x);
528 if (@as(T, 1) << log2_val == x)
529 return log2_val;
530 return log2_val + 1;
531}
lib/std/std.zig-1
...@@ -26,7 +26,6 @@ pub const PriorityQueue = @import("priority_queue.zig").PriorityQueue;...@@ -26,7 +26,6 @@ pub const PriorityQueue = @import("priority_queue.zig").PriorityQueue;
26pub const PriorityDequeue = @import("priority_dequeue.zig").PriorityDequeue;26pub const PriorityDequeue = @import("priority_dequeue.zig").PriorityDequeue;
27pub const Progress = @import("Progress.zig");27pub const Progress = @import("Progress.zig");
28pub const Random = @import("Random.zig");28pub const Random = @import("Random.zig");
29pub const SegmentedList = @import("segmented_list.zig").SegmentedList;
30pub const SemanticVersion = @import("SemanticVersion.zig");29pub const SemanticVersion = @import("SemanticVersion.zig");
31pub const SinglyLinkedList = @import("SinglyLinkedList.zig");30pub const SinglyLinkedList = @import("SinglyLinkedList.zig");
32pub const StaticBitSet = bit_set.StaticBitSet;31pub const StaticBitSet = bit_set.StaticBitSet;
test/src/Debugger.zig-181
...@@ -2188,187 +2188,6 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void {...@@ -2188,187 +2188,6 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void {
2188 \\1 breakpoints deleted; 0 breakpoint locations disabled.2188 \\1 breakpoints deleted; 0 breakpoint locations disabled.
2189 },2189 },
2190 );2190 );
2191 db.addLldbTest(
2192 "segmented_list",
2193 target,
2194 &.{
2195 .{
2196 .path = "main.zig",
2197 .source =
2198 \\const std = @import("std");
2199 \\fn testSegmentedList() void {}
2200 \\pub fn main() !void {
2201 \\ var list0: std.SegmentedList(usize, 0) = .{};
2202 \\ defer list0.deinit(std.heap.page_allocator);
2203 \\
2204 \\ var list1: std.SegmentedList(usize, 1) = .{};
2205 \\ defer list1.deinit(std.heap.page_allocator);
2206 \\
2207 \\ var list2: std.SegmentedList(usize, 2) = .{};
2208 \\ defer list2.deinit(std.heap.page_allocator);
2209 \\
2210 \\ var list4: std.SegmentedList(usize, 4) = .{};
2211 \\ defer list4.deinit(std.heap.page_allocator);
2212 \\
2213 \\ for (0..32) |i| {
2214 \\ try list0.append(std.heap.page_allocator, i);
2215 \\ try list1.append(std.heap.page_allocator, i);
2216 \\ try list2.append(std.heap.page_allocator, i);
2217 \\ try list4.append(std.heap.page_allocator, i);
2218 \\ }
2219 \\ testSegmentedList();
2220 \\}
2221 \\
2222 ,
2223 },
2224 },
2225 \\breakpoint set --file main.zig --source-pattern-regexp 'testSegmentedList\(\);'
2226 \\process launch
2227 \\frame variable -- list0 list1 list2 list4
2228 \\breakpoint delete --force 1
2229 ,
2230 &.{
2231 \\(lldb) frame variable -- list0 list1 list2 list4
2232 \\(std.segmented_list.SegmentedList(usize,0)) list0 = len=32 {
2233 \\ [0] = 0
2234 \\ [1] = 1
2235 \\ [2] = 2
2236 \\ [3] = 3
2237 \\ [4] = 4
2238 \\ [5] = 5
2239 \\ [6] = 6
2240 \\ [7] = 7
2241 \\ [8] = 8
2242 \\ [9] = 9
2243 \\ [10] = 10
2244 \\ [11] = 11
2245 \\ [12] = 12
2246 \\ [13] = 13
2247 \\ [14] = 14
2248 \\ [15] = 15
2249 \\ [16] = 16
2250 \\ [17] = 17
2251 \\ [18] = 18
2252 \\ [19] = 19
2253 \\ [20] = 20
2254 \\ [21] = 21
2255 \\ [22] = 22
2256 \\ [23] = 23
2257 \\ [24] = 24
2258 \\ [25] = 25
2259 \\ [26] = 26
2260 \\ [27] = 27
2261 \\ [28] = 28
2262 \\ [29] = 29
2263 \\ [30] = 30
2264 \\ [31] = 31
2265 \\}
2266 \\(std.segmented_list.SegmentedList(usize,1)) list1 = len=32 {
2267 \\ [0] = 0
2268 \\ [1] = 1
2269 \\ [2] = 2
2270 \\ [3] = 3
2271 \\ [4] = 4
2272 \\ [5] = 5
2273 \\ [6] = 6
2274 \\ [7] = 7
2275 \\ [8] = 8
2276 \\ [9] = 9
2277 \\ [10] = 10
2278 \\ [11] = 11
2279 \\ [12] = 12
2280 \\ [13] = 13
2281 \\ [14] = 14
2282 \\ [15] = 15
2283 \\ [16] = 16
2284 \\ [17] = 17
2285 \\ [18] = 18
2286 \\ [19] = 19
2287 \\ [20] = 20
2288 \\ [21] = 21
2289 \\ [22] = 22
2290 \\ [23] = 23
2291 \\ [24] = 24
2292 \\ [25] = 25
2293 \\ [26] = 26
2294 \\ [27] = 27
2295 \\ [28] = 28
2296 \\ [29] = 29
2297 \\ [30] = 30
2298 \\ [31] = 31
2299 \\}
2300 \\(std.segmented_list.SegmentedList(usize,2)) list2 = len=32 {
2301 \\ [0] = 0
2302 \\ [1] = 1
2303 \\ [2] = 2
2304 \\ [3] = 3
2305 \\ [4] = 4
2306 \\ [5] = 5
2307 \\ [6] = 6
2308 \\ [7] = 7
2309 \\ [8] = 8
2310 \\ [9] = 9
2311 \\ [10] = 10
2312 \\ [11] = 11
2313 \\ [12] = 12
2314 \\ [13] = 13
2315 \\ [14] = 14
2316 \\ [15] = 15
2317 \\ [16] = 16
2318 \\ [17] = 17
2319 \\ [18] = 18
2320 \\ [19] = 19
2321 \\ [20] = 20
2322 \\ [21] = 21
2323 \\ [22] = 22
2324 \\ [23] = 23
2325 \\ [24] = 24
2326 \\ [25] = 25
2327 \\ [26] = 26
2328 \\ [27] = 27
2329 \\ [28] = 28
2330 \\ [29] = 29
2331 \\ [30] = 30
2332 \\ [31] = 31
2333 \\}
2334 \\(std.segmented_list.SegmentedList(usize,4)) list4 = len=32 {
2335 \\ [0] = 0
2336 \\ [1] = 1
2337 \\ [2] = 2
2338 \\ [3] = 3
2339 \\ [4] = 4
2340 \\ [5] = 5
2341 \\ [6] = 6
2342 \\ [7] = 7
2343 \\ [8] = 8
2344 \\ [9] = 9
2345 \\ [10] = 10
2346 \\ [11] = 11
2347 \\ [12] = 12
2348 \\ [13] = 13
2349 \\ [14] = 14
2350 \\ [15] = 15
2351 \\ [16] = 16
2352 \\ [17] = 17
2353 \\ [18] = 18
2354 \\ [19] = 19
2355 \\ [20] = 20
2356 \\ [21] = 21
2357 \\ [22] = 22
2358 \\ [23] = 23
2359 \\ [24] = 24
2360 \\ [25] = 25
2361 \\ [26] = 26
2362 \\ [27] = 27
2363 \\ [28] = 28
2364 \\ [29] = 29
2365 \\ [30] = 30
2366 \\ [31] = 31
2367 \\}
2368 \\(lldb) breakpoint delete --force 1
2369 \\1 breakpoints deleted; 0 breakpoint locations disabled.
2370 },
2371 );
2372}2191}
23732192
2374const File = struct { import: ?[]const u8 = null, path: []const u8, source: []const u8 };2193const File = struct { import: ?[]const u8 = null, path: []const u8, source: []const u8 };
tools/lldb_pretty_printers.py-28
...@@ -206,33 +206,6 @@ class zig_TaggedUnion_SynthProvider:...@@ -206,33 +206,6 @@ class zig_TaggedUnion_SynthProvider:
206206
207# Define Zig Standard Library207# Define Zig Standard Library
208208
209class std_SegmentedList_SynthProvider:
210 def __init__(self, value, _=None): self.value = value
211 def update(self):
212 try:
213 self.prealloc_segment = self.value.GetChildMemberWithName('prealloc_segment')
214 self.dynamic_segments = zig_Slice_SynthProvider(self.value.GetChildMemberWithName('dynamic_segments'))
215 self.dynamic_segments.update()
216 self.len = self.value.GetChildMemberWithName('len').unsigned
217 except: pass
218 def has_children(self): return True
219 def num_children(self): return self.len
220 def get_child_index(self, name):
221 try: return int(name.removeprefix('[').removesuffix(']'))
222 except: return -1
223 def get_child_at_index(self, index):
224 try:
225 if index not in range(self.len): return None
226 prealloc_item_count = len(self.prealloc_segment)
227 if index < prealloc_item_count: return self.prealloc_segment.child[index]
228 prealloc_exp = prealloc_item_count.bit_length() - 1
229 shelf_index = log2_int(index + 1) if prealloc_item_count == 0 else log2_int(index + prealloc_item_count) - prealloc_exp - 1
230 shelf = self.dynamic_segments.get_child_at_index(shelf_index)
231 box_index = (index + 1) - (1 << shelf_index) if prealloc_item_count == 0 else index + prealloc_item_count - (1 << ((prealloc_exp + 1) + shelf_index))
232 elem_type = shelf.type.GetPointeeType()
233 return shelf.CreateChildAtOffset('[%d]' % index, box_index * elem_type.size, elem_type)
234 except: return None
235
236class std_MultiArrayList_SynthProvider:209class std_MultiArrayList_SynthProvider:
237 def __init__(self, value, _=None): self.value = value210 def __init__(self, value, _=None): self.value = value
238 def update(self):211 def update(self):
...@@ -936,7 +909,6 @@ def __lldb_init_module(debugger, _=None):...@@ -936,7 +909,6 @@ def __lldb_init_module(debugger, _=None):
936909
937 # Initialize Zig Standard Library910 # Initialize Zig Standard Library
938 add(debugger, category='zig.std', type='mem.Allocator', summary='${var.ptr}')911 add(debugger, category='zig.std', type='mem.Allocator', summary='${var.ptr}')
939 add(debugger, category='zig.std', regex=True, type='^segmented_list\\.SegmentedList\\(.*\\)$', identifier='std_SegmentedList', synth=True, expand=True, summary='len=${var.len}')
940 add(debugger, category='zig.std', regex=True, type='^multi_array_list\\.MultiArrayList\\(.*\\)$', identifier='std_MultiArrayList', synth=True, expand=True, summary='len=${var.len} capacity=${var.capacity}')912 add(debugger, category='zig.std', regex=True, type='^multi_array_list\\.MultiArrayList\\(.*\\)$', identifier='std_MultiArrayList', synth=True, expand=True, summary='len=${var.len} capacity=${var.capacity}')
941 add(debugger, category='zig.std', regex=True, type='^multi_array_list\\.MultiArrayList\\(.*\\)\\.Slice$', identifier='std_MultiArrayList_Slice', synth=True, expand=True, summary='len=${var.len} capacity=${var.capacity}')913 add(debugger, category='zig.std', regex=True, type='^multi_array_list\\.MultiArrayList\\(.*\\)\\.Slice$', identifier='std_MultiArrayList_Slice', synth=True, expand=True, summary='len=${var.len} capacity=${var.capacity}')
942 add(debugger, category='zig.std', regex=True, type=MultiArrayList_Entry('.*'), identifier='std_Entry', synth=True, inline_children=True, summary=True)914 add(debugger, category='zig.std', regex=True, type=MultiArrayList_Entry('.*'), identifier='std_Entry', synth=True, inline_children=True, summary=True)
tools/update_cpu_features.zig+11-8
...@@ -1737,10 +1737,11 @@ fn processOneTarget(job: Job) void {...@@ -1737,10 +1737,11 @@ fn processOneTarget(job: Job) void {
1737 const collate_progress = progress_node.start("collating LLVM data", 0);1737 const collate_progress = progress_node.start("collating LLVM data", 0);
17381738
1739 // So far, LLVM only has a few aliases for the same CPU.1739 // So far, LLVM only has a few aliases for the same CPU.
1740 var cpu_aliases = std.StringHashMap(std.SegmentedList(struct {1740 const Alias = struct {
1741 llvm: []const u8,1741 llvm: []const u8,
1742 zig: []const u8,1742 zig: []const u8,
1743 }, 4)).init(arena);1743 };
1744 var cpu_aliases = std.StringHashMap(std.ArrayList(*Alias)).init(arena);
17441745
1745 {1746 {
1746 var it = root_map.iterator();1747 var it = root_map.iterator();
...@@ -1756,12 +1757,16 @@ fn processOneTarget(job: Job) void {...@@ -1756,12 +1757,16 @@ fn processOneTarget(job: Job) void {
17561757
1757 const gop = try cpu_aliases.getOrPut(try llvmNameToZigName(arena, llvm_name));1758 const gop = try cpu_aliases.getOrPut(try llvmNameToZigName(arena, llvm_name));
17581759
1759 if (!gop.found_existing) gop.value_ptr.* = .{};1760 if (!gop.found_existing) {
1761 gop.value_ptr.* = .empty;
1762 }
17601763
1761 try gop.value_ptr.append(arena, .{1764 const alias = try arena.create(Alias);
1765 alias.* = .{
1762 .llvm = llvm_alias,1766 .llvm = llvm_alias,
1763 .zig = try llvmNameToZigName(arena, llvm_alias),1767 .zig = try llvmNameToZigName(arena, llvm_alias),
1764 });1768 };
1769 try gop.value_ptr.append(arena, alias);
1765 }1770 }
1766 }1771 }
1767 }1772 }
...@@ -1918,9 +1923,7 @@ fn processOneTarget(job: Job) void {...@@ -1918,9 +1923,7 @@ fn processOneTarget(job: Job) void {
1918 });1923 });
19191924
1920 if (cpu_aliases.get(zig_name)) |aliases| {1925 if (cpu_aliases.get(zig_name)) |aliases| {
1921 var alias_it = aliases.constIterator(0);1926 alias_it: for (aliases.items) |alias| {
1922
1923 alias_it: while (alias_it.next()) |alias| {
1924 for (target.omit_cpus) |omit_cpu_name| {1927 for (target.omit_cpus) |omit_cpu_name| {
1925 if (mem.eql(u8, omit_cpu_name, alias.llvm)) continue :alias_it;1928 if (mem.eql(u8, omit_cpu_name, alias.llvm)) continue :alias_it;
1926 }1929 }