Message ID | 53b15a0b7932f892505d07a509909b62c473037e.1659122979.git.gitgitgadget@gmail.com (mailing list archive) |
---|---|
State | Superseded |
Headers | show |
Series | log: create tighter default decoration filter | expand |
"Derrick Stolee via GitGitGadget" <gitgitgadget@gmail.com> writes: > From: Derrick Stolee <derrickstolee@github.com> > > The add_ref_decoration() method uses an if/else-if chain to determine if > a ref matches a known ref namespace that has a special decoration > category. That decoration type is later used to assign a color when > writing to stdout. > > The newly-added ref_namespaces array contains all namespaces, along > with information about their decoration type. Check this array instead > of this if/else-if chain. This reduces our dependency on string literals > being embedded in the decoration logic. > > Signed-off-by: Derrick Stolee <derrickstolee@github.com> > --- > log-tree.c | 26 ++++++++++++++++---------- > 1 file changed, 16 insertions(+), 10 deletions(-) > > diff --git a/log-tree.c b/log-tree.c > index bb80f1a94d2..6075bdd334e 100644 > --- a/log-tree.c > +++ b/log-tree.c > @@ -137,6 +137,7 @@ static int ref_filter_match(const char *refname, > static int add_ref_decoration(const char *refname, const struct object_id *oid, > int flags, void *cb_data) > { > + int i; > struct object *obj; > enum object_type objtype; > enum decoration_type deco_type = DECORATION_NONE; > @@ -167,16 +168,21 @@ static int add_ref_decoration(const char *refname, const struct object_id *oid, > return 0; > obj = lookup_object_by_type(the_repository, oid, objtype); > > - if (starts_with(refname, "refs/heads/")) > - deco_type = DECORATION_REF_LOCAL; > - else if (starts_with(refname, "refs/remotes/")) > - deco_type = DECORATION_REF_REMOTE; > - else if (starts_with(refname, "refs/tags/")) > - deco_type = DECORATION_REF_TAG; > - else if (!strcmp(refname, "refs/stash")) > - deco_type = DECORATION_REF_STASH; > - else if (!strcmp(refname, "HEAD")) > - deco_type = DECORATION_REF_HEAD; > + for (i = 0; i < NAMESPACE__COUNT; i++) { > + struct ref_namespace_info *info = &ref_namespaces[i]; > + > + if (!info->decoration) > + continue; > + if (info->exact) { > + if (!strcmp(refname, info->ref)) { > + deco_type = info->decoration; > + break; > + } > + } else if (starts_with(refname, info->ref)) { > + deco_type = info->decoration; > + break; > + } > + } Very nice. The double-dash in the NAMESPACE__COUNT constant somehow looks strange. As we scan through ref_namespace[] array densely, for (i = 0; i < ARRAY_SIZE(ref_namespace); i++) ... without having to use the constant would probably be more in line with the way how the rest of the codebase works.
On 8/3/2022 2:31 AM, Junio C Hamano wrote: > "Derrick Stolee via GitGitGadget" <gitgitgadget@gmail.com> writes: > >> From: Derrick Stolee <derrickstolee@github.com> >> + for (i = 0; i < NAMESPACE__COUNT; i++) { >> + struct ref_namespace_info *info = &ref_namespaces[i]; >> + >> + if (!info->decoration) >> + continue; >> + if (info->exact) { >> + if (!strcmp(refname, info->ref)) { >> + deco_type = info->decoration; >> + break; >> + } >> + } else if (starts_with(refname, info->ref)) { >> + deco_type = info->decoration; >> + break; >> + } >> + } > > Very nice. The double-dash in the NAMESPACE__COUNT constant somehow > looks strange. As we scan through ref_namespace[] array densely, > > for (i = 0; i < ARRAY_SIZE(ref_namespace); i++) > ... > > without having to use the constant would probably be more in line > with the way how the rest of the codebase works. Ah, I did not know about that trick. Thanks! -Stolee
On 8/4/2022 9:31 AM, Derrick Stolee wrote: > On 8/3/2022 2:31 AM, Junio C Hamano wrote: >> "Derrick Stolee via GitGitGadget" <gitgitgadget@gmail.com> writes: >> >>> From: Derrick Stolee <derrickstolee@github.com> >>> + for (i = 0; i < NAMESPACE__COUNT; i++) { >>> + struct ref_namespace_info *info = &ref_namespaces[i]; >>> + >>> + if (!info->decoration) >>> + continue; >>> + if (info->exact) { >>> + if (!strcmp(refname, info->ref)) { >>> + deco_type = info->decoration; >>> + break; >>> + } >>> + } else if (starts_with(refname, info->ref)) { >>> + deco_type = info->decoration; >>> + break; >>> + } >>> + } >> >> Very nice. The double-dash in the NAMESPACE__COUNT constant somehow >> looks strange. As we scan through ref_namespace[] array densely, >> >> for (i = 0; i < ARRAY_SIZE(ref_namespace); i++) >> ... >> >> without having to use the constant would probably be more in line >> with the way how the rest of the codebase works. > > Ah, I did not know about that trick. Thanks! ...except that it doesn't work because the array is declared as 'extern' so we don't know its size outside of refs.c. This motivates the use of NAMESPACE__COUNT (and the double underscores differentiates the "COUNT" from other namespaces, so there is no confusion about "COUNT" being a namespace). If there is another way around this, then I would love to hear it! Thanks, -Stolee
On 8/4/2022 10:34 AM, Derrick Stolee wrote: > On 8/4/2022 9:31 AM, Derrick Stolee wrote: >> On 8/3/2022 2:31 AM, Junio C Hamano wrote: >>> Very nice. The double-dash in the NAMESPACE__COUNT constant somehow >>> looks strange. As we scan through ref_namespace[] array densely, >>> >>> for (i = 0; i < ARRAY_SIZE(ref_namespace); i++) >>> ... >>> >>> without having to use the constant would probably be more in line >>> with the way how the rest of the codebase works. >> >> Ah, I did not know about that trick. Thanks! > > ...except that it doesn't work because the array is declared as > 'extern' so we don't know its size outside of refs.c. > > This motivates the use of NAMESPACE__COUNT (and the double > underscores differentiates the "COUNT" from other namespaces, so > there is no confusion about "COUNT" being a namespace). If there > is another way around this, then I would love to hear it! My current workaround is to define the size of the array in the header file: --- enum ref_namespace { NAMESPACE_HEAD, NAMESPACE_BRANCHES, NAMESPACE_TAGS, NAMESPACE_REMOTE_REFS, NAMESPACE_STASH, NAMESPACE_REPLACE, NAMESPACE_NOTES, NAMESPACE_PREFETCH, NAMESPACE_REWRITTEN, /* Must be last */ NAMESPACE__COUNT }; /* See refs.c for the contents of this array. */ extern struct ref_namespace_info ref_namespaces[NAMESPACE__COUNT]; --- Then ARRAY_SIZE(ref_namespaces) works properly. Thanks, -Stolee
Derrick Stolee <derrickstolee@github.com> writes: > My current workaround is to define the size of the array in the > header file: > > --- > > enum ref_namespace { > NAMESPACE_HEAD, > NAMESPACE_BRANCHES, > NAMESPACE_TAGS, > NAMESPACE_REMOTE_REFS, > NAMESPACE_STASH, > NAMESPACE_REPLACE, > NAMESPACE_NOTES, > NAMESPACE_PREFETCH, > NAMESPACE_REWRITTEN, > > /* Must be last */ > NAMESPACE__COUNT > }; > > /* See refs.c for the contents of this array. */ > extern struct ref_namespace_info ref_namespaces[NAMESPACE__COUNT]; Because there is no reason why we want to keep the size of the array opaque in this particular case, it may even be preferrable over the original ref_namespace[] array of unspecified size. Nice. BTW, I prefer to name my arrays with a singular noun, when the predominant use of it in the code that is an API customer is to name an individual element and use it. In this case, many API users do things like ref_namespace[NAMESPACE_NOTES}.ref = ...; so a singular name would be more appropriate. thing[4] that means the fourth thing feels more intuitive than things[4], at least to me. On the other hand, when API customers mostly pass the whole thing around as an almost opaque collection to the API function, then a plural name is more appropriate. The reason why I focus on API customers is because API implementation of course has to go in to each individual element of the array and work on it at some level, and "individual access means singular name" rule would become non workable. The names are mostly to help API customers, so if an array is perceived by them as mostly a collection of things, then naming it in plural would make it more natural.
On 8/4/2022 1:40 PM, Junio C Hamano wrote: > Derrick Stolee <derrickstolee@github.com> writes: > >> My current workaround is to define the size of the array in the >> header file: >> >> --- >> >> enum ref_namespace { >> NAMESPACE_HEAD, >> NAMESPACE_BRANCHES, >> NAMESPACE_TAGS, >> NAMESPACE_REMOTE_REFS, >> NAMESPACE_STASH, >> NAMESPACE_REPLACE, >> NAMESPACE_NOTES, >> NAMESPACE_PREFETCH, >> NAMESPACE_REWRITTEN, >> >> /* Must be last */ >> NAMESPACE__COUNT >> }; >> >> /* See refs.c for the contents of this array. */ >> extern struct ref_namespace_info ref_namespaces[NAMESPACE__COUNT]; > > Because there is no reason why we want to keep the size of the array > opaque in this particular case, it may even be preferrable over the > original ref_namespace[] array of unspecified size. Nice. > > BTW, I prefer to name my arrays with a singular noun, when the > predominant use of it in the code that is an API customer is to name > an individual element and use it. > > In this case, many API users do things like > > ref_namespace[NAMESPACE_NOTES}.ref = ...; > > so a singular name would be more appropriate. thing[4] that means > the fourth thing feels more intuitive than things[4], at least to > me. This makes sense to me. > On the other hand, when API customers mostly pass the whole thing > around as an almost opaque collection to the API function, then a > plural name is more appropriate. The reason why I focus on API > customers is because API implementation of course has to go in to > each individual element of the array and work on it at some level, > and "individual access means singular name" rule would become non > workable. The names are mostly to help API customers, so if an > array is perceived by them as mostly a collection of things, then > naming it in plural would make it more natural. Understood. I think this array does not seem to fit this second case, so I will change it to be singular. Thanks, -Stolee
diff --git a/log-tree.c b/log-tree.c index bb80f1a94d2..6075bdd334e 100644 --- a/log-tree.c +++ b/log-tree.c @@ -137,6 +137,7 @@ static int ref_filter_match(const char *refname, static int add_ref_decoration(const char *refname, const struct object_id *oid, int flags, void *cb_data) { + int i; struct object *obj; enum object_type objtype; enum decoration_type deco_type = DECORATION_NONE; @@ -167,16 +168,21 @@ static int add_ref_decoration(const char *refname, const struct object_id *oid, return 0; obj = lookup_object_by_type(the_repository, oid, objtype); - if (starts_with(refname, "refs/heads/")) - deco_type = DECORATION_REF_LOCAL; - else if (starts_with(refname, "refs/remotes/")) - deco_type = DECORATION_REF_REMOTE; - else if (starts_with(refname, "refs/tags/")) - deco_type = DECORATION_REF_TAG; - else if (!strcmp(refname, "refs/stash")) - deco_type = DECORATION_REF_STASH; - else if (!strcmp(refname, "HEAD")) - deco_type = DECORATION_REF_HEAD; + for (i = 0; i < NAMESPACE__COUNT; i++) { + struct ref_namespace_info *info = &ref_namespaces[i]; + + if (!info->decoration) + continue; + if (info->exact) { + if (!strcmp(refname, info->ref)) { + deco_type = info->decoration; + break; + } + } else if (starts_with(refname, info->ref)) { + deco_type = info->decoration; + break; + } + } add_name_decoration(deco_type, refname, obj); while (obj->type == OBJ_TAG) {