1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-27 11:07:44 +00:00

ls: Avoid additional String creation/copy in display_date

From code provided in #7852 by @BurntSushi.

Depending on the benchmarks, there is _still_ a small performance
difference (~4%) vs main, but it's seen mostly on small trees
getting printed repeatedly, which is probably not a terribly
interesting use case.
This commit is contained in:
Nicolas Boichat 2025-04-30 00:56:22 +08:00
parent c599363242
commit 10fb220c72

View file

@ -3,7 +3,7 @@
// For the full copyright and license information, please view the LICENSE // For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code. // file that was distributed with this source code.
// spell-checker:ignore (ToDO) somegroup nlink tabsize dired subdired dtype colorterm stringly nohash // spell-checker:ignore (ToDO) somegroup nlink tabsize dired subdired dtype colorterm stringly nohash strtime
use std::iter; use std::iter;
#[cfg(windows)] #[cfg(windows)]
@ -31,6 +31,8 @@ use clap::{
builder::{NonEmptyStringValueParser, PossibleValue, ValueParser}, builder::{NonEmptyStringValueParser, PossibleValue, ValueParser},
}; };
use glob::{MatchOptions, Pattern}; use glob::{MatchOptions, Pattern};
use jiff::fmt::StdIoWrite;
use jiff::fmt::strtime::BrokenDownTime;
use jiff::{Timestamp, Zoned}; use jiff::{Timestamp, Zoned};
use lscolors::LsColors; use lscolors::LsColors;
use term_grid::{DEFAULT_SEPARATOR_SIZE, Direction, Filling, Grid, GridOptions, SPACES_IN_TAB}; use term_grid::{DEFAULT_SEPARATOR_SIZE, Direction, Filling, Grid, GridOptions, SPACES_IN_TAB};
@ -279,21 +281,29 @@ fn is_recent(time: Timestamp, state: &mut ListState) -> bool {
impl TimeStyle { impl TimeStyle {
/// Format the given time according to this time format style. /// Format the given time according to this time format style.
fn format(&self, date: Zoned, state: &mut ListState) -> String { fn format(
&self,
date: Zoned,
out: &mut Vec<u8>,
state: &mut ListState,
) -> Result<(), jiff::Error> {
let recent = is_recent(date.timestamp(), state); let recent = is_recent(date.timestamp(), state);
let tm = BrokenDownTime::from(&date);
let out = StdIoWrite(out);
match (self, recent) { match (self, recent) {
(Self::FullIso, _) => date.strftime("%Y-%m-%d %H:%M:%S.%f %z").to_string(), (Self::FullIso, _) => tm.format("%Y-%m-%d %H:%M:%S.%f %z", out),
(Self::LongIso, _) => date.strftime("%Y-%m-%d %H:%M").to_string(), (Self::LongIso, _) => tm.format("%Y-%m-%d %H:%M", out),
(Self::Iso, true) => date.strftime("%m-%d %H:%M").to_string(), (Self::Iso, true) => tm.format("%m-%d %H:%M", out),
(Self::Iso, false) => date.strftime("%Y-%m-%d ").to_string(), (Self::Iso, false) => tm.format("%Y-%m-%d ", out),
// spell-checker:ignore (word) datetime // spell-checker:ignore (word) datetime
//In this version of chrono translating can be done //In this version of chrono translating can be done
//The function is chrono::datetime::DateTime::format_localized //The function is chrono::datetime::DateTime::format_localized
//However it's currently still hard to get the current pure-rust-locale //However it's currently still hard to get the current pure-rust-locale
//So it's not yet implemented //So it's not yet implemented
(Self::Locale, true) => date.strftime("%b %e %H:%M").to_string(), (Self::Locale, true) => tm.format("%b %e %H:%M", out),
(Self::Locale, false) => date.strftime("%b %e %Y").to_string(), (Self::Locale, false) => tm.format("%b %e %Y", out),
(Self::Format(fmt), _) => date.strftime(&fmt).to_string(), (Self::Format(fmt), _) => tm.format(&fmt, out),
} }
} }
} }
@ -2869,7 +2879,7 @@ fn display_item_long(
}; };
output_display.extend(b" "); output_display.extend(b" ");
output_display.extend(display_date(md, config, state).as_bytes()); display_date(md, config, state, &mut output_display)?;
output_display.extend(b" "); output_display.extend(b" ");
let item_name = display_item_name( let item_name = display_item_name(
@ -3073,10 +3083,22 @@ fn get_time(md: &Metadata, config: &Config) -> Option<Zoned> {
time.try_into().ok() time.try_into().ok()
} }
fn display_date(metadata: &Metadata, config: &Config, state: &mut ListState) -> String { fn display_date(
metadata: &Metadata,
config: &Config,
state: &mut ListState,
out: &mut Vec<u8>,
) -> UResult<()> {
match get_time(metadata, config) { match get_time(metadata, config) {
Some(time) => config.time_style.format(time, state), // TODO: Some fancier error conversion might be nice.
None => "???".into(), Some(time) => config
.time_style
.format(time, out, state)
.map_err(|x| USimpleError::new(1, x.to_string())),
None => {
out.extend(b"???");
Ok(())
}
} }
} }