1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-29 12:07:46 +00:00

tr: stream output instead of buffering

This should lower memory consumption, and fixes OOM in some scenarios.
This commit is contained in:
Ben Wiederhake 2024-02-25 12:52:21 +01:00 committed by Sylvestre Ledru
parent 6c29ed037b
commit 9cbe6055fa
2 changed files with 39 additions and 25 deletions

View file

@ -339,6 +339,32 @@ impl Sequence {
pub trait SymbolTranslator { pub trait SymbolTranslator {
fn translate(&mut self, current: u8) -> Option<u8>; fn translate(&mut self, current: u8) -> Option<u8>;
/// Takes two SymbolTranslators and creates a new SymbolTranslator over both in sequence.
///
/// This behaves pretty much identical to [`Iterator::chain`].
fn chain<T>(self, other: T) -> ChainedSymbolTranslator<Self, T>
where
Self: Sized,
{
ChainedSymbolTranslator::<Self, T> {
stage_a: self,
stage_b: other,
}
}
}
pub struct ChainedSymbolTranslator<A, B> {
stage_a: A,
stage_b: B,
}
impl<A: SymbolTranslator, B: SymbolTranslator> SymbolTranslator for ChainedSymbolTranslator<A, B> {
fn translate(&mut self, current: u8) -> Option<u8> {
self.stage_a
.translate(current)
.and_then(|c| self.stage_b.translate(c))
}
} }
#[derive(Debug)] #[derive(Debug)]

View file

@ -9,9 +9,10 @@ mod operation;
mod unicode_table; mod unicode_table;
use clap::{crate_version, Arg, ArgAction, Command}; use clap::{crate_version, Arg, ArgAction, Command};
use nom::AsBytes; use operation::{
use operation::{translate_input, Sequence, SqueezeOperation, TranslateOperation}; translate_input, Sequence, SqueezeOperation, SymbolTranslator, TranslateOperation,
use std::io::{stdin, stdout, BufReader, BufWriter}; };
use std::io::{stdin, stdout, BufWriter};
use uucore::{format_usage, help_about, help_section, help_usage, show}; use uucore::{format_usage, help_about, help_section, help_usage, show};
use crate::operation::DeleteOperation; use crate::operation::DeleteOperation;
@ -117,19 +118,13 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
truncate_set1_flag, truncate_set1_flag,
)?; )?;
// '*_op' are the operations that need to be applied, in order.
if delete_flag { if delete_flag {
if squeeze_flag { if squeeze_flag {
let mut delete_buffer = vec![]; let delete_op = DeleteOperation::new(set1, complement_flag);
{ let squeeze_op = SqueezeOperation::new(set2, false);
let mut delete_writer = BufWriter::new(&mut delete_buffer); let op = delete_op.chain(squeeze_op);
let delete_op = DeleteOperation::new(set1, complement_flag); translate_input(&mut locked_stdin, &mut buffered_stdout, op);
translate_input(&mut locked_stdin, &mut delete_writer, delete_op);
}
{
let mut squeeze_reader = BufReader::new(delete_buffer.as_bytes());
let op = SqueezeOperation::new(set2, false);
translate_input(&mut squeeze_reader, &mut buffered_stdout, op);
}
} else { } else {
let op = DeleteOperation::new(set1, complement_flag); let op = DeleteOperation::new(set1, complement_flag);
translate_input(&mut locked_stdin, &mut buffered_stdout, op); translate_input(&mut locked_stdin, &mut buffered_stdout, op);
@ -139,17 +134,10 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
let op = SqueezeOperation::new(set1, complement_flag); let op = SqueezeOperation::new(set1, complement_flag);
translate_input(&mut locked_stdin, &mut buffered_stdout, op); translate_input(&mut locked_stdin, &mut buffered_stdout, op);
} else { } else {
let mut translate_buffer = vec![]; let translate_op = TranslateOperation::new(set1, set2.clone(), complement_flag)?;
{ let squeeze_op = SqueezeOperation::new(set2, false);
let mut writer = BufWriter::new(&mut translate_buffer); let op = translate_op.chain(squeeze_op);
let op = TranslateOperation::new(set1, set2.clone(), complement_flag)?; translate_input(&mut locked_stdin, &mut buffered_stdout, op);
translate_input(&mut locked_stdin, &mut writer, op);
}
{
let mut reader = BufReader::new(translate_buffer.as_bytes());
let squeeze_op = SqueezeOperation::new(set2, false);
translate_input(&mut reader, &mut buffered_stdout, squeeze_op);
}
} }
} else { } else {
let op = TranslateOperation::new(set1, set2, complement_flag)?; let op = TranslateOperation::new(set1, set2, complement_flag)?;