Skip to content

Allocationless parsing #30

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

Merged
merged 17 commits into from
Oct 12, 2024
Merged

Allocationless parsing #30

merged 17 commits into from
Oct 12, 2024

Conversation

rsore
Copy link
Owner

@rsore rsore commented Oct 11, 2024

A major goal of this library is to minimize the amount of heap allocations that are done during parsing. Previously, all arguments passed to the parse method of the Parser were inserted into a std::vector. One by one, the front element would be popped off and processed. Though this solution was simple, it was expensive due to two main reasons. First, we allocated a vector to store the elements, which wasn't necessary since we already received the elements in a container—a raw C-string array. Second, erasing elements from the front multiple times is costly, as it requires moving the remaining elements one by one every time.

In this development branch, I have removed the usage of std::vector and replaced it with a view. I use the std::views::counted function, which, when used with a raw array of C-strings, returns a std::span. This change allows us to apply modern container access practices with the plain old array. Instead of removing elements from the original array, I can now shrink the view in each iteration until the view is empty.

The main difference in this branch can be seen by comparing simplified versions of the two implementations.
The old version is as follows:

std::vector<std::string_view> args(argc);
for (int i{}; i < argc; ++i)
{
    arguments[i] = argv[i];
}
while (!args.empty())
{
    // Do some work...
    args.erase(args.begin());
}

In contrast, the new version is:

auto args = std::views::counted(argv, argc);
while (!args.empty())
{
    // Do some work...
    args = std::views::drop(args, 1);
}

Before deciding on this approach, I experimented with a custom container that used std::span internally. While it initially seemed to work, it became unnecessarily complex for my needs. I retained some utility functions I had already written for testing, as they will likely be useful in the future.

This optimization should lead to significant performance improvements, particularly in scenarios involving a large number of arguments.

@rsore rsore added the improvement Improvement to existing feature label Oct 11, 2024
Copy link

clang-tidy review says "All clean, LGTM! 👍"

Copy link

clang-tidy review says "All clean, LGTM! 👍"

@rsore rsore merged commit 059b7aa into main Oct 12, 2024
7 checks passed
@rsore rsore deleted the allocationless-parsing branch October 12, 2024 00:00
rsore added a commit that referenced this pull request Oct 20, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
improvement Improvement to existing feature
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant