]> git.ipfire.org Git - thirdparty/coreutils.git/commitdiff
ls: cache name width determination
authorPádraig Brady <P@draigBrady.com>
Sat, 10 Apr 2021 15:54:03 +0000 (16:54 +0100)
committerPádraig Brady <P@draigBrady.com>
Sun, 11 Apr 2021 13:58:45 +0000 (14:58 +0100)
This is especially important now for --sort=width,
as that can greatly increase how often this
expensive quote_name_width() function is called per file.

This also helps the default invocation of ls,
or specifically the --format={across,vertical} cases
(when --width is not set to 0),
to avoid two calls to this function per file.

Note the only case where we later compute the width,
is for --format=commas.  That's only done once though,
so we leave the computation close to use to
maximize hardware caching.

* src/ls.c (struct fileinfo): Add a WIDTH member to cache
the screen width of the file name.
(update_current_files_info): Set the WIDTH members for cases
they're needed multiple times.  Note we do this explicitly here,
rather than caching at use, so that the fileinfo
structures can remain const in the sorting and presentation functions.
(sort_files): Call the new update_current_files_info() in this
initialization function.
(fileinfo_name_width): Renamed from fileinfo_width,
and adjusted to return the cached value if available.

src/ls.c

index b9fde25d57fd010d3757975ff311c3b49db61da5..2db72417389bcabc4bb2230f14f5f01126882a15 100644 (file)
--- a/src/ls.c
+++ b/src/ls.c
@@ -235,6 +235,9 @@ struct fileinfo
 
     /* Whether file name needs quoting. tri-state with -1 == unknown.  */
     int quoted;
+
+    /* Cached screen width (including quoting).  */
+    size_t width;
   };
 
 #define LEN_STR_PAIR(s) sizeof (s) - 1, s
@@ -3883,17 +3886,22 @@ cmp_extension (struct fileinfo const *a, struct fileinfo const *b,
   return diff ? diff : cmp (a->name, b->name);
 }
 
+/* Return the (cached) screen width,
+   for the NAME associated with the passed fileinfo F.  */
+
 static inline size_t
-fileinfo_width (struct fileinfo const *f)
+fileinfo_name_width (struct fileinfo const *f)
 {
-  return quote_name_width (f->name, filename_quoting_options, f->quoted);
+  return f->width
+         ? f->width
+         : quote_name_width (f->name, filename_quoting_options, f->quoted);
 }
 
 static inline int
 cmp_width (struct fileinfo const *a, struct fileinfo const *b,
           int (*cmp) (char const *, char const *))
 {
-  int diff = fileinfo_width (a) - fileinfo_width (b);
+  int diff = fileinfo_name_width (a) - fileinfo_name_width (b);
   return diff ? diff : cmp (a->name, b->name);
 }
 
@@ -4003,6 +4011,24 @@ initialize_ordering_vector (void)
     sorted_file[i] = &cwd_file[i];
 }
 
+/* Cache values based on attributes global to all files.  */
+
+static void
+update_current_files_info (void)
+{
+  /* Cache screen width of name, if needed multiple times.  */
+  if (sort_type == sort_width
+      || (line_length && (format == many_per_line || format == horizontal)))
+    {
+      size_t i;
+      for (i = 0; i < cwd_n_used; i++)
+        {
+          struct fileinfo *f = sorted_file[i];
+          f->width = fileinfo_name_width (f);
+        }
+    }
+}
+
 /* Sort the files now in the table.  */
 
 static void
@@ -4019,6 +4045,8 @@ sort_files (void)
 
   initialize_ordering_vector ();
 
+  update_current_files_info ();
+
   if (sort_type == sort_none)
     return;
 
@@ -5055,7 +5083,7 @@ length_of_file_name_and_frills (const struct fileinfo *f)
   if (print_scontext)
     len += 1 + (format == with_commas ? strlen (f->scontext) : scontext_width);
 
-  len += quote_name_width (f->name, filename_quoting_options, f->quoted);
+  len += fileinfo_name_width (f);
 
   if (indicator_style != none)
     {