| ... | @@ -207,6 +207,7 @@ pub fn init(file: Io.File, gpa: Allocator, io: Io) (Allocator.Error || Io.Cancel | ... | @@ -207,6 +207,7 @@ pub fn init(file: Io.File, gpa: Allocator, io: Io) (Allocator.Error || Io.Cancel |
| 207 | .resized = false, | 207 | .resized = false, |
| 208 | .next_moved = false, | 208 | .next_moved = false, |
| 209 | .has_content = false, | 209 | .has_content = false, |
| | 210 | .updated = false, |
| 210 | }, | 211 | }, |
| 211 | .location_payload = switch (root_location) { | 212 | .location_payload = switch (root_location) { |
| 212 | .small => |small| .{ .small = small }, | 213 | .small => |small| .{ .small = small }, |
| ... | @@ -287,7 +288,14 @@ pub const Node = extern struct { | ... | @@ -287,7 +288,14 @@ pub const Node = extern struct { |
| 287 | next_moved: bool, | 288 | next_moved: bool, |
| 288 | /// Whether this node might contain initialized bytes. | 289 | /// Whether this node might contain initialized bytes. |
| 289 | has_content: bool, | 290 | has_content: bool, |
| 290 | unused: u17 = 0, | 291 | |
| | 292 | /// Whether this node is currently in `updates`. Usually this is just equal to whether any |
| | 293 | /// of `moved`, `resized`, or `next_moved` is set, but when a node is deleted and later |
| | 294 | /// reused, it may still be in `updates`, so preserving this flag through the deletion |
| | 295 | /// prevents us from adding it to `updates` a second time. |
| | 296 | updated: bool, |
| | 297 | |
| | 298 | unused: u16 = 0, |
| 291 | }; | 299 | }; |
| 292 | | 300 | |
| 293 | pub const Location = union(enum(u1)) { | 301 | pub const Location = union(enum(u1)) { |
| ... | @@ -494,6 +502,11 @@ pub const Node = extern struct { | ... | @@ -494,6 +502,11 @@ pub const Node = extern struct { |
| 494 | } | 502 | } |
| 495 | } | 503 | } |
| 496 | | 504 | |
| | 505 | pub fn cleanUpdated(ni: Node.Index, mf: *MappedFile) void { |
| | 506 | assert(ni.get(mf).flags.updated); |
| | 507 | ni.get(mf).flags.updated = false; |
| | 508 | } |
| | 509 | |
| 497 | pub fn hasMoved(ni: Node.Index, mf: *const MappedFile) bool { | 510 | pub fn hasMoved(ni: Node.Index, mf: *const MappedFile) bool { |
| 498 | var cur_ni = ni; | 511 | var cur_ni = ni; |
| 499 | while (cur_ni != .root) { | 512 | while (cur_ni != .root) { |
| ... | @@ -518,9 +531,11 @@ pub const Node = extern struct { | ... | @@ -518,9 +531,11 @@ pub const Node = extern struct { |
| 518 | if (node.prev.unwrap()) |prev_ni| prev_ni.nextMovedAssumeCapacity(mf); | 531 | if (node.prev.unwrap()) |prev_ni| prev_ni.nextMovedAssumeCapacity(mf); |
| 519 | if (ni.hasMoved(mf)) return; | 532 | if (ni.hasMoved(mf)) return; |
| 520 | node.flags.moved = true; | 533 | node.flags.moved = true; |
| 521 | if (node.flags.resized or node.flags.next_moved) return; | 534 | if (!node.flags.updated) { |
| 522 | mf.updates.appendAssumeCapacity(ni); | 535 | node.flags.updated = true; |
| 523 | mf.update_prog_node.increaseEstimatedTotalItems(1); | 536 | mf.updates.appendAssumeCapacity(ni); |
| | 537 | mf.update_prog_node.increaseEstimatedTotalItems(1); |
| | 538 | } |
| 524 | } | 539 | } |
| 525 | | 540 | |
| 526 | pub fn hasResized(ni: Node.Index, mf: *const MappedFile) bool { | 541 | pub fn hasResized(ni: Node.Index, mf: *const MappedFile) bool { |
| ... | @@ -539,9 +554,11 @@ pub const Node = extern struct { | ... | @@ -539,9 +554,11 @@ pub const Node = extern struct { |
| 539 | const node = ni.get(mf); | 554 | const node = ni.get(mf); |
| 540 | if (node.flags.resized) return; | 555 | if (node.flags.resized) return; |
| 541 | node.flags.resized = true; | 556 | node.flags.resized = true; |
| 542 | if (node.flags.moved or node.flags.next_moved) return; | 557 | if (!node.flags.updated) { |
| 543 | mf.updates.appendAssumeCapacity(ni); | 558 | node.flags.updated = true; |
| 544 | mf.update_prog_node.increaseEstimatedTotalItems(1); | 559 | mf.updates.appendAssumeCapacity(ni); |
| | 560 | mf.update_prog_node.increaseEstimatedTotalItems(1); |
| | 561 | } |
| 545 | } | 562 | } |
| 546 | | 563 | |
| 547 | pub fn hasNextMoved(ni: Node.Index, mf: *const MappedFile) bool { | 564 | pub fn hasNextMoved(ni: Node.Index, mf: *const MappedFile) bool { |
| ... | @@ -560,9 +577,11 @@ pub const Node = extern struct { | ... | @@ -560,9 +577,11 @@ pub const Node = extern struct { |
| 560 | const node = ni.get(mf); | 577 | const node = ni.get(mf); |
| 561 | if (!node.flags.enable_next_moved or node.flags.next_moved) return; | 578 | if (!node.flags.enable_next_moved or node.flags.next_moved) return; |
| 562 | node.flags.next_moved = true; | 579 | node.flags.next_moved = true; |
| 563 | if (node.flags.moved or node.flags.resized) return; | 580 | if (!node.flags.updated) { |
| 564 | mf.updates.appendAssumeCapacity(ni); | 581 | node.flags.updated = true; |
| 565 | mf.update_prog_node.increaseEstimatedTotalItems(1); | 582 | mf.updates.appendAssumeCapacity(ni); |
| | 583 | mf.update_prog_node.increaseEstimatedTotalItems(1); |
| | 584 | } |
| 566 | } | 585 | } |
| 567 | | 586 | |
| 568 | pub fn alignment(ni: Node.Index, mf: *const MappedFile) Alignment { | 587 | pub fn alignment(ni: Node.Index, mf: *const MappedFile) Alignment { |
| ... | @@ -647,19 +666,30 @@ pub const Node = extern struct { | ... | @@ -647,19 +666,30 @@ pub const Node = extern struct { |
| 647 | pub fn delete(ni: Node.Index, gpa: Allocator, mf: *MappedFile) Allocator.Error!void { | 666 | pub fn delete(ni: Node.Index, gpa: Allocator, mf: *MappedFile) Allocator.Error!void { |
| 648 | const node = ni.get(mf); | 667 | const node = ni.get(mf); |
| 649 | assert(node.first == .none and node.last == .none); // has children | 668 | assert(node.first == .none and node.last == .none); // has children |
| 650 | mf.removeNodesFromChildList(gpa, ni, ni); | 669 | try mf.removeNodesFromChildList(gpa, ni, ni); |
| 651 | const updated = node.flags.moved or node.flags.resized or node.flags.next_moved; | 670 | node.* = .{ |
| 652 | node.* = undefined; | 671 | .parent = undefined, |
| 653 | node.next = ni.toOptional(); | 672 | .prev = undefined, |
| 654 | if (!updated) assert(ni.pendingDelete(mf)); | 673 | .next = mf.free_ni, |
| 655 | } | 674 | .first = undefined, |
| 656 | | 675 | .last = undefined, |
| 657 | pub fn pendingDelete(ni: Node.Index, mf: *MappedFile) bool { | 676 | .flags = .{ |
| 658 | const node = ni.get(mf); | 677 | .position = .floating, |
| 659 | if (node.next != ni.toOptional()) return false; | 678 | .alignment = .@"1", |
| 660 | node.next = mf.free_ni; | 679 | .bubbles_moved = false, |
| | 680 | .enable_next_moved = false, |
| | 681 | .location_tag = .small, |
| | 682 | .moved = false, |
| | 683 | .resized = false, |
| | 684 | .next_moved = false, |
| | 685 | .has_content = false, |
| | 686 | // It is important that we preserve this flag! When the node gets reused, this |
| | 687 | // prevents it being redundantly added to `mf.updates` if it is already there. |
| | 688 | .updated = node.flags.updated, |
| | 689 | }, |
| | 690 | .location_payload = undefined, |
| | 691 | }; |
| 661 | mf.free_ni = ni.toOptional(); | 692 | mf.free_ni = ni.toOptional(); |
| 662 | return true; | | |
| 663 | } | 693 | } |
| 664 | | 694 | |
| 665 | /// Ensures that the size of `ni` is at least `min_size`. Valid for any node. | 695 | /// Ensures that the size of `ni` is at least `min_size`. Valid for any node. |
| ... | @@ -946,6 +976,7 @@ fn addNode(mf: *MappedFile, gpa: Allocator, opts: struct { | ... | @@ -946,6 +976,7 @@ fn addNode(mf: *MappedFile, gpa: Allocator, opts: struct { |
| 946 | .resized = false, | 976 | .resized = false, |
| 947 | .next_moved = false, | 977 | .next_moved = false, |
| 948 | .has_content = false, | 978 | .has_content = false, |
| | 979 | .updated = false, |
| 949 | }, | 980 | }, |
| 950 | .location_payload = switch (location) { | 981 | .location_payload = switch (location) { |
| 951 | .small => |small| .{ .small = small }, | 982 | .small => |small| .{ .small = small }, |