Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

std.PriorityQueue: Convert to an 'unmanaged'-style API #21433

Open
wants to merge 5 commits into
base: master
Choose a base branch
from

Conversation

saltzm
Copy link

@saltzm saltzm commented Sep 17, 2024

Resolves: #21432.

Removed the allocator field from the PriorityQueue struct and adapted functions to take an allocator where needed.

Updated tests accordingly.

If these changes look good, I'll make corresponding changes to PriorityDequeue and include them in a follow-up patch.

Resolves: ziglang#21432.

Removed the allocator field from the PriorityQueue struct and
adapted functions to take an allocator where needed.

Updated tests accordingly.
lib/std/priority_queue.zig Outdated Show resolved Hide resolved
Removed the allocator field from the PriorityDequeue struct
and adapted functions to take an allocator where needed.

Updated tests accordingly.
pub fn deinit(self: Self) void {
self.allocator.free(self.items);
pub fn deinit(self: Self, allocator: std.mem.Allocator) void {
if (self.items.len > 0) {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't strictly necessary since free checks for 0-length slices but it still seemed odd to me to intentionally free something that was not a result of a call to alloc so I added this check.

pub fn deinit(self: Self) void {
self.allocator.free(self.allocatedSlice());
pub fn deinit(self: Self, allocator: std.mem.Allocator) void {
if (self.items.len > 0) {
Copy link
Author

@saltzm saltzm Sep 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't strictly necessary since free checks for 0-length slices but it still seemed odd to me to intentionally free something that was not a result of a call to alloc so I added this check.

@saltzm
Copy link
Author

saltzm commented Sep 17, 2024

I added back the PriorityQueue.init() function and changed PriorityDequeue to be unmanaged.

I also noticed that what PriorityQueue was doing with the capacity field was a bit odd and did not match PriorityDequeue. It was tracking its current size by modifying the items.len field, and then reconstituting the "allocated slice" by taking self.items.ptr[0..self.capacity]. This seemed a little odd to me so I changed it to match the way PriorityDequeue is implemented, tracking the length separately and having items always be the full backing array/slice of data. The capacity is then accessed using queue.items.len.

PriorityQueue and PriorityDequeue still have a count() function that returns the size of the queue, and PriorityDequeue still has a capacity() function. Before changing it I wanted to ask what y'all thought the best API would be. In my mind there are two options:

  1. Provide both count() and capacity() functions
  2. Provide neither functions. The user gets the count by doing queue.len and gets the capacity by doing queue.items.len

The latter I think matches the rest of the standard library more, though as a user I have sometimes found it a little odd that I need to access fields directly for this information rather than calling some consistent function.

What do y'all think the best move would be here?

@andrewrk
Copy link
Member

I also noticed that what PriorityQueue was doing with the capacity field was a bit odd and did not match PriorityDequeue. It was tracking its current size by modifying the items.len field, and then reconstituting the "allocated slice" by taking self.items.ptr[0..self.capacity]. This seemed a little odd to me so I changed it to match the way PriorityDequeue is implemented, tracking the length separately and having items always be the full backing array/slice of data. The capacity is then accessed using queue.items.len.

This is probably motivated by what ArrayList does and I think people generally agree (myself included) that it's preferred over the alternative because it means that your items field is always safe to access directly, and you have to be a bit more intentional to access uninitialized memory.

@saltzm
Copy link
Author

saltzm commented Sep 17, 2024

This is probably motivated by what ArrayList does and I think people generally agree (myself included) that it's preferred over the alternative because it means that your items field is always safe to access directly, and you have to be a bit more intentional to access uninitialized memory.

Okay, I put it in its own commit so it's easy to undo. I'll undo it.

Comment on lines +22 to +23
/// The capacity of the queue. This may be read directly, but must not
/// be modified directly.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • "the capacity of the queue" is 100% redundant with the name of the data structure and the field. Delete it.
  • documentation should be descriptive, not prescriptive. Instead of telling the person what they should/shouldn't do, may or may not do, just document how it works.
Suggested change
/// The capacity of the queue. This may be read directly, but must not
/// be modified directly.
/// Tracks the allocated slice of memory when combined with `items.ptr`.

You can see how this comment is more useful, and the programmer can infer that they can read it directly, and that modifying it directly is in fact possible if they also modify items appropriately.

Missing documentation is acceptable. Documentation that violates the redundancy principle or descriptive principle is not. When in doubt, delete the documentation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add a PriorityQueueUnmanaged type to the standard library
4 participants