Add ability to customize "num items" inlining heuristic
The "expand for more than 4 items heuristic" is useful, but I'd like to play around with that a bit more for my codebase.
Would it be easy to make the 'number of items' limit customizable, ideally both globally in the .gersemirc file and per-function through extensions / cmakeparseargs hints? It seems like this might be a customization point that would provide a lot of control to users while adding minimal maintenance complexity.
4 is suitable for most situations, but there are cases where I really want to force expansion. For example, I'd like add_library to always expand when there's more than one source file specified, and being able to set the max_inline_items to 3 for this function via an extension would accomplish this:
add_library(bar OBJECT source1.cpp)
add_library(
foo
OBJECT
source1.cpp
source2.cpp
)
Same with target_link_libraries:
target_link_libraries(kramble PRIVATE jaam)
target_link_libraries(
foo
PUBLIC
bar
baz
)
I was about to file another issue requesting the ability to customize favour-expansion vs favour-inlining per function, but then noticed that all of my desired example usecases would actually be implementable by just overriding max_inline_items per function. I think this feature would give a lot of value.
Usually, in these rare cases, when I really want to force expansion I just use empty comment:
target_link_libraries(
foo
PUBLIC #
bar
baz
)
It's worth noting that similar thing works with clang-format. I usually use it in cases like this one:
bool condition()
{
return a() //
or b() //
or c() //
or d() //
or e();
}
I'll think about this issue but it's somewhere in the territory "I need to add another knob" and I try my best to avoid visiting this territory. Of course extensions were meant to be the solution where user knows better, so to speak, but I'm a little bit cautious about what should be exposed there.
One cool thing I've noticed about what your proposal is that, more or less, it's a natural extension to current favour-<x> because as far as I remember the implementation does this:
-
favour-inlining==max-inline-items: 4 -
favour-expansion==max-inline-items: 1
That workaround will do nicely for these examples, thanks!
The other situation I encountered where I would like to modify this is for disabling expansion. For function and macro, I prefer to have all of the arguments inline unless they'd break the line length:
function(my_function arg_a arg_b arg_c arg_d arg_e ...)
Setting max-inline-items to a very large value would accomplish this, and I don't see a good workaround for this usecase currently. I can live with the expansion, but it'd be a nice QoL improvement to have control over this.
Another oddity I ran into with the # workaround -- it seems to break the keyword formatters and produces:
set_target_properties(
some_target_with_a_long_name
PROPERTIES #
CXX_STANDARD
20
CXX_STANDARD_REQUIRED
ON
)
instead of:
set_target_properties(
some_target_with_a_long_name
PROPERTIES #
CXX_STANDARD 20
CXX_STANDARD_REQUIRED ON
)
Nice catch. I've fixed in that 0.23.1.
That workaround will do nicely for these examples, thanks!
The other situation I encountered where I would like to modify this is for disabling expansion. For
functionandmacro, I prefer to have all of the arguments inline unless they'd break the line length:function(my_function arg_a arg_b arg_c arg_d arg_e ...)
Setting
max-inline-itemsto a very large value would accomplish this, and I don't see a good workaround for this usecase currently. I can live with the expansion, but it'd be a nice QoL improvement to have control over this.
See for yourself using this branch. For the sake of this demo I've used the name inlining_heuristic instead of max_inline_items because I feel this would be a little more descriptive what's going on. If you happen to do the experiment on NVIDIA/cccl or any other repository please let me know, perhaps seeing the advantages will convince me to just release this as a feature.
Short summary:
-
favour-inliningeffectively is like setting"inlining_heuristic": 4for all commands -
favour-expansioneffectively is like setting"inlining_heuristic": 1for almost all of commands, exceptions areblock/foreach/function/macro/if/elseif/else/endif/while/endwhilewhere it remains as"inlining_heuristic": 4 - this demo branch has 0.23.9999 version for convenience
If something looks "funny" we can refine this experiment.
Thanks! I got a chance to try this out today. I noticed #82 while adjusting cmake_parse_arguments, but I think that's unrelated to this branch.
I'm trying to force target_link_libraries to always expand when more than one library is listed in a group, e.g, these would be valid:
# Inline for a single target:
target_link_libraries(foo PRIVATE bar)
# List multiple targets:
target_link_libraries(foo
PRIVATE
bar
baz
)
I can't find a heuristic setting that would allow this:
# inlining_heuristic unset:
target_link_libraries(foo PRIVATE bar baz)
# inlining_heuristic = 1
target_link_libraries(
foo
PRIVATE bar baz
)
I'd like this to be the same for target_compile_definitions, target_compile_options, target_include_directories -- inline when only a single lib/def/opt/dir is given, but expanded for multiple. I find this much more readable and less "soupy" when there's more than one multivalue keyword. Is this doable?
My current approach:
from gersemi.builtin_commands import builtin_commands
def set_max_inline_items(command, max_inline_items):
command["inlining_heuristic"] = max_inline_items
return command
command_definitions = {
"target_link_libraries": set_max_inline_items(builtin_commands["target_link_libraries"], 1),
}
Setting to 9999 for function and macro works as desired to force-inline all args under the line limit.
Interestingly, add_library with a heuristic of 1 behaves how I'd want:
# default
add_library(foo OBJECT foo.cpp)
add_library(bar OBJECT bar.cpp baz.cpp)
# heuristic = 1
add_library(foo OBJECT foo.cpp)
add_library(
bar
OBJECT
bar.cpp
baz.cpp
)
Maybe something like a per-keyword keyword_inlining_heuristic property to compliment formatters / preprocessors would give a nice interface with the level of customization I'm looking for.
Status update: I'm interested in pursuing this topic further but I need to suspend it for some time. I'm still open to issues found along the way (like #82) since bug fixing is a priority for me.
I came across this exact issue, which motivated me to disable the custom definitions. +1 for this feature.