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

Reduce allocations in Styling API #134

Merged
merged 2 commits into from
Dec 1, 2023

Conversation

SirNickolas
Copy link
Contributor

@SirNickolas SirNickolas commented Nov 29, 2023

  1. TextStyle stores its sequence as a string instead of ubyte[]. Thus it is allocated only once, not on every opCall.
  2. appender + std.conv.toChars are used instead of to!string.
  3. Primitive styles (bold, italic, etc.) are cached in global constants.
  4. ~= is used instead of ~ where possible.
  5. Added another overload of TextStyle.opCall, which writes to an output range. This allows to build strings with no intermediate allocations (see the last unit test for an example).

I have a question. Why do we need StyledText? As far as I can tell, the only place where it would be beneficial is an overload of getUnstyledTextLength(StyledText). But… it is not called from anywhere besides its unit test. I tried removing StyledText, and everything I had to do to deal with it was dropping several .toString() calls.

Copy link

codecov bot commented Nov 29, 2023

Codecov Report

Attention: 1 lines in your changes are missing coverage. Please review.

Comparison is base (e72cb56) 98.43% compared to head (a60213b) 98.40%.

❗ Current head a60213b differs from pull request most recent head 54f4b8a. Consider uploading reports for the commit 54f4b8a to get more accurate results

Files Patch % Lines
source/argparse/ansi.d 98.07% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##              2.x     #134      +/-   ##
==========================================
- Coverage   98.43%   98.40%   -0.03%     
==========================================
  Files          25       25              
  Lines        1721     1759      +38     
==========================================
+ Hits         1694     1731      +37     
- Misses         27       28       +1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@SirNickolas
Copy link
Contributor Author

I thought about making a separate method instead of overloading opCall (that would simplify StyleImpl as well), but how do we name it? bold.writeTo(sink, text);? formatTo? Something else? Plain write/format seem odd to me because it makes more sense to have such methods declared on the sink.

@andrey-zherikov
Copy link
Owner

I have a question. Why do we need StyledText? As far as I can tell, the only place where it would be beneficial is an overload of getUnstyledTextLength(StyledText). But… it is not called from anywhere besides its unit test. I tried removing StyledText, and everything I had to do to deal with it was dropping several .toString() calls.

TBH I don't remember why it was needed. If you can remove it without affecting public interface - go ahead (ideally in separate PR).

@andrey-zherikov
Copy link
Owner

I thought about making a separate method instead of overloading opCall (that would simplify StyleImpl as well), but how do we name it? bold.writeTo(sink, text);? formatTo? Something else? Plain write/format seem odd to me because it makes more sense to have such methods declared on the sink.

Could you clarify what you want to achieve? If you want to replace opCall with something then how will this code look like: "argument "~bold.("name")~" is bold")?

We should make `StyledText` a range instead.
@SirNickolas
Copy link
Contributor Author

Realized there is a more flexible approach: turn StyledText into a range of characters. It’ll definitely go into its own PR; we can discuss in #135 how exactly it should be done. In the meantime, I reverted the addition of new functionality.

@andrey-zherikov andrey-zherikov merged commit a8623c1 into andrey-zherikov:2.x Dec 1, 2023
@SirNickolas SirNickolas deleted the style branch December 1, 2023 16:19
andrey-zherikov added a commit that referenced this pull request Dec 11, 2023
* Refactor (#96)

* Move onError tp api/cli.d

* Improve ANSI styling handling and making AnsiStylingArgument boolean-like

* Make Parser private

* Remove hooks

* Remove subcommands

* Remove argumentparser

* Update readme

* Add unit tests

* Rename Config.helpStyle to Config.styling (#97)

* Add unit test (#98)

* Refactor (#99)

* Small cleanup

* Make Config a template parameter

* Add unit test

* Styling in error messages (#100)

* Add errorMessagePrefix to Style

* Rename Style.namedArgumentName => Style.argumentName

* Styling in error messages

* Add check for argument name (#101)

* Rename Config.namedArgChar to namedArgPrefix (#102)

* Add checks for positional arguments (#103)

* Refactor (#105)

* Add ArgumentInfo.memberSymbol

* Small refactoring

* Move Restriction and RestrictionGroup to internal.restriction

* Remove symbol parameter

* remove partial apply

* Small refactoring

* Small refactoring

* Add unit test

* Pin LDC to 1.34.0 (#108)

* Add '--verbose' to builds

* Refactoring (#127)

* Required positional arguments must come before optional ones

* Optional positional arguments are not allowed with default subcommand

* Rewrite parser (#128)

* Refactor

* Split ArgumentInfo.names to shortNames and longNames

* Add namedArguments and positionalArguments to Arguments

* Rename Arguments.arguments to info

* Refactor Arguments API

* Remove ArgumentInfo.ignoreInDefaultCommand

* Rewrite parser

* unit tests

* Update readme (#121)

* Update readme

* Update the examples as well

* Apply suggested changes to readme

* Declare `Style.Default` with an alternative syntax (#130)

* Turn `main` and `mainComplete` into regular templates (#132)

They don't need advanced features that template mixins provide. (Regular
templates are mixable, too.)
https://dlang.org/spec/template-mixin.html

* Make Styling API `nothrow pure @safe` (#133)

* Reduce allocations in Styling API (#134)

* Reduce allocations in Styling API

* Remove the overload of `TextStyle.opCall` that takes a sink

We should make `StyledText` a range instead.

* Do not depend on `std.regex` (#131)

* Do not depend on `std.regex`

This saves 1.5 MB in the binary, which is desirable since not every
program that uses `argparse` may want to use regexes - or that
particular implementation of regexes.

`argparse.ansi.getUnstyledText` became eager, but the library wasn't
exploiting its laziness anyway.

* Make `getUnstyledText` lazy and `@nogc`

* Use constants instead of hardcoded characters

* Rework the auxiliary function

Co-Authored-By: Andrey Zherikov <[email protected]>

* Remove one mutable variable

* Add a small comment

---------

Co-authored-by: Andrey Zherikov <[email protected]>
Co-authored-by: Andrey Zherikov <[email protected]>

* Improve compilation time and memory (#124)

* Use regular parameters instead of template parameters where possible

This helps in reducing both compilation time and (build-time) memory
requirement.

* Deduplicate `HelpArgumentUDA.parse`

2.3 GB -> 1.7 GB.

* Deduplicate `Complete.CompleteCmd`

1.7 GB -> 1.6 GB.

* Compile the completer on demand

1.6 GB -> 0.8 GB.

* Simplify `CLI!(...).complete`

* Deduplicate `CounterParsingFunction`

* Make some of the config's fields statically known by the parser

So that the compiler can prune dead branches of code.

* Remove `assignChar` from parser's template parameters

* Try to simplify min-max-handling logic in `getMemberArgumentUDA`

* Add a unit test for `getMemberArgumentUDA`

* Move `getArgumentUDA` to `argparse.internal.arguments`

Renamed into `finalize` in the process. It only fills `ArgumentInfo`
so it doesn't have to know about UDAs at all.

* Import non-std modules once per file

---------

Co-authored-by: Nickolay Bukreyev <[email protected]>
Co-authored-by: Andrey Zherikov <[email protected]>
andrey-zherikov pushed a commit that referenced this pull request Dec 12, 2023
* Reduce allocations in Styling API

* Remove the overload of `TextStyle.opCall` that takes a sink

We should make `StyledText` a range instead.
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.

2 participants