diff --git a/crates/engine_bibtex/src/buffer.rs b/crates/engine_bibtex/src/buffer.rs index b3523157e..7d31775e7 100644 --- a/crates/engine_bibtex/src/buffer.rs +++ b/crates/engine_bibtex/src/buffer.rs @@ -31,7 +31,7 @@ pub(crate) struct GlobalBuffer { buffer: Buffer, sv_buffer: Buffer, ex_buf: Buffer, - out_buf: Buffer, + out_buf: Vec, name_sep_char: Buffer, name_tok: Vec, } @@ -44,7 +44,7 @@ impl GlobalBuffer { buffer: Buffer::new(buf_len), sv_buffer: Buffer::new(buf_len), ex_buf: Buffer::new(buf_len), - out_buf: Buffer::new(buf_len), + out_buf: Vec::new(), name_sep_char: Buffer::new(buf_len), name_tok: vec![0; buf_len + 1], } @@ -59,7 +59,6 @@ impl GlobalBuffer { BufTy::Base => self.buffer.ptr.as_mut_ptr(), BufTy::Sv => self.sv_buffer.ptr.as_mut_ptr(), BufTy::Ex => self.ex_buf.ptr.as_mut_ptr(), - BufTy::Out => self.out_buf.ptr.as_mut_ptr(), BufTy::NameSep => self.name_sep_char.ptr.as_mut_ptr(), } } @@ -69,7 +68,6 @@ impl GlobalBuffer { BufTy::Base => &self.buffer.ptr, BufTy::Sv => &self.sv_buffer.ptr, BufTy::Ex => &self.ex_buf.ptr, - BufTy::Out => &self.out_buf.ptr, BufTy::NameSep => &self.name_sep_char.ptr, } } @@ -79,11 +77,14 @@ impl GlobalBuffer { BufTy::Base => &mut self.buffer.ptr, BufTy::Sv => &mut self.sv_buffer.ptr, BufTy::Ex => &mut self.ex_buf.ptr, - BufTy::Out => &mut self.out_buf.ptr, BufTy::NameSep => &mut self.name_sep_char.ptr, } } + pub fn out(&mut self) -> &mut Vec { + &mut self.out_buf + } + fn copy_within_same(&mut self, ty: BufTy, from: usize, to: usize, len: usize) { let buf = self.buffer_mut(ty); buf.copy_within(from..from + len, to); @@ -130,7 +131,7 @@ impl GlobalBuffer { match ty { BufTy::Base => self.buffer.offset[offset - 1] = val, BufTy::Ex => self.ex_buf.offset[offset - 1] = val, - BufTy::Sv | BufTy::Out | BufTy::NameSep => { + BufTy::Sv | BufTy::NameSep => { unreachable!("Buffer {:?} has no offsets", ty) } } @@ -148,7 +149,7 @@ impl GlobalBuffer { match ty { BufTy::Base => self.buffer.offset[offset - 1], BufTy::Ex => self.ex_buf.offset[offset - 1], - BufTy::Sv | BufTy::Out | BufTy::NameSep => { + BufTy::Sv | BufTy::NameSep => { unreachable!("Buffer {:?} has no offsets", ty) } } @@ -159,7 +160,6 @@ impl GlobalBuffer { BufTy::Base => self.buffer.init, BufTy::Sv => self.sv_buffer.init, BufTy::Ex => self.ex_buf.init, - BufTy::Out => self.out_buf.init, BufTy::NameSep => self.name_sep_char.init, } } @@ -169,7 +169,6 @@ impl GlobalBuffer { BufTy::Base => self.buffer.init = val, BufTy::Sv => self.sv_buffer.init = val, BufTy::Ex => self.ex_buf.init = val, - BufTy::Out => self.out_buf.init = val, BufTy::NameSep => self.name_sep_char.init = val, } } @@ -179,7 +178,6 @@ impl GlobalBuffer { self.buffer.grow(BUF_SIZE); self.sv_buffer.grow(BUF_SIZE); self.ex_buf.grow(BUF_SIZE); - self.out_buf.grow(BUF_SIZE); self.name_sep_char.grow(BUF_SIZE); self.name_tok.resize(self.name_tok.len() + BUF_SIZE, 0); self.buf_len = new_len; @@ -191,6 +189,5 @@ pub(crate) enum BufTy { Base, Sv, Ex, - Out, NameSep, } diff --git a/crates/engine_bibtex/src/exec.rs b/crates/engine_bibtex/src/exec.rs index 85e4a5110..c3fb3a08b 100644 --- a/crates/engine_bibtex/src/exec.rs +++ b/crates/engine_bibtex/src/exec.rs @@ -324,6 +324,8 @@ pub(crate) fn figure_out_the_formatted_name( let str = pool.get_str(s1); let mut idx = 0; + buffers.set_init(BufTy::Ex, 0); + add_buf_pool(pool, buffers, s1); buffers.set_offset(BufTy::Ex, 1, 0); while idx < str.len() { @@ -651,23 +653,17 @@ pub(crate) fn add_out_pool( str: StrNumber, ) { let str = pool.get_str(str); + let out = buffers.out(); - while buffers.init(BufTy::Out) + str.len() > buffers.len() { - buffers.grow_all(); - } - - let out_offset = buffers.init(BufTy::Out); - buffers.copy_from(BufTy::Out, out_offset, str); - buffers.set_init(BufTy::Out, out_offset + str.len()); + out.extend(str); let mut unbreakable_tail = false; - while buffers.init(BufTy::Out) > MAX_PRINT_LINE && !unbreakable_tail { - let end_ptr = buffers.init(BufTy::Out); + while out.len() > MAX_PRINT_LINE && !unbreakable_tail { + let end_ptr = out.len(); let mut out_offset = MAX_PRINT_LINE; let mut break_pt_found = false; - while LexClass::of(buffers.at(BufTy::Out, out_offset)) != LexClass::Whitespace - && out_offset >= MIN_PRINT_LINE + while LexClass::of(out[out_offset]) != LexClass::Whitespace && out_offset >= MIN_PRINT_LINE { out_offset -= 1; } @@ -675,7 +671,7 @@ pub(crate) fn add_out_pool( if out_offset == MIN_PRINT_LINE - 1 { out_offset = MAX_PRINT_LINE + 1; while out_offset < end_ptr { - if LexClass::of(buffers.at(BufTy::Out, out_offset)) != LexClass::Whitespace { + if LexClass::of(out[out_offset]) != LexClass::Whitespace { out_offset += 1; } else { break; @@ -687,8 +683,7 @@ pub(crate) fn add_out_pool( } else { break_pt_found = true; while out_offset + 1 < end_ptr { - if LexClass::of(buffers.at(BufTy::Out, out_offset + 1)) == LexClass::Whitespace - { + if LexClass::of(out[out_offset + 1]) == LexClass::Whitespace { out_offset += 1; } else { break; @@ -699,15 +694,15 @@ pub(crate) fn add_out_pool( break_pt_found = true; } + // Write `out` up to break, then prepend two spaces to the rest and shift it left if break_pt_found { - buffers.set_init(BufTy::Out, out_offset); - let break_ptr = buffers.init(BufTy::Out) + 1; - output_bbl_line(ctx, buffers); - buffers.set_at(BufTy::Out, 0, b' '); - buffers.set_at(BufTy::Out, 1, b' '); + let break_ptr = out_offset + 1; + output_bbl_line(ctx, &out[..out_offset]); + out[0] = b' '; + out[1] = b' '; let len = end_ptr - break_ptr; - buffers.copy_within(BufTy::Out, BufTy::Out, break_ptr, 2, len); - buffers.set_init(BufTy::Out, len + 2); + out.copy_within(break_ptr..end_ptr, 2); + out.truncate(len + 2); } } } @@ -1421,19 +1416,18 @@ fn interp_format_name( let mut brace_level = 0; let mut xptr = 0; - buffers.set_init(BufTy::Ex, 0); - add_buf_pool(pool, buffers, s3); - buffers.set_offset(BufTy::Ex, 1, 0); + let str = pool.get_str(s3); + let mut str_idx = 0; let mut num_names = 0; - while num_names < i2 && buffers.offset(BufTy::Ex, 1) < buffers.init(BufTy::Ex) { + while num_names < i2 && str_idx < str.len() { num_names += 1; - xptr = buffers.offset(BufTy::Ex, 1); - name_scan_for_and(ctx, pool, buffers, cites, s3, &mut brace_level)?; + xptr = str_idx; + name_scan_for_and(ctx, pool, cites, str, &mut str_idx, s3, &mut brace_level)?; } - if buffers.offset(BufTy::Ex, 1) < buffers.init(BufTy::Ex) { - buffers.set_offset(BufTy::Ex, 1, buffers.offset(BufTy::Ex, 1) - 4); + if str_idx < str.len() { + str_idx -= 4; } if num_names < i2 { @@ -1447,18 +1441,18 @@ fn interp_format_name( bst_ex_warn_print(ctx, pool, cites)?; } - while buffers.offset(BufTy::Ex, 1) > xptr { - match LexClass::of(buffers.at(BufTy::Ex, buffers.offset(BufTy::Ex, 1) - 1)) { + while str_idx > xptr { + match LexClass::of(str[str_idx - 1]) { LexClass::Whitespace | LexClass::Sep => { - buffers.set_offset(BufTy::Ex, 1, buffers.offset(BufTy::Ex, 1) - 1); + str_idx -= 1; } _ => { - if buffers.at(BufTy::Ex, buffers.offset(BufTy::Ex, 1) - 1) == b',' { + if str[str_idx - 1] == b',' { ctx.write_logs(&format!("Name {i2} in \"")); print_a_pool_str(ctx, s3, pool)?; ctx.write_logs("\" has a comma at the end"); bst_ex_warn_print(ctx, pool, cites)?; - buffers.set_offset(BufTy::Ex, 1, buffers.offset(BufTy::Ex, 1) - 1); + str_idx -= 1; } else { break; } @@ -1477,8 +1471,8 @@ fn interp_format_name( let mut name_ptr = 0; let mut token_starting = true; - while xptr < buffers.offset(BufTy::Ex, 1) { - match buffers.at(BufTy::Ex, xptr) { + while xptr < str_idx { + match str[xptr] { b',' => { match commas { Commas::None => { @@ -1505,16 +1499,16 @@ fn interp_format_name( buffers.set_name_tok(num_tokens, name_ptr); num_tokens += 1; } - buffers.set_at(BufTy::Sv, name_ptr, buffers.at(BufTy::Ex, xptr)); + buffers.set_at(BufTy::Sv, name_ptr, str[xptr]); name_ptr += 1; xptr += 1; - while brace_level > 0 && xptr < buffers.offset(BufTy::Ex, 1) { - match buffers.at(BufTy::Ex, xptr) { + while brace_level > 0 && xptr < str_idx { + match str[xptr] { b'{' => brace_level += 1, b'}' => brace_level -= 1, _ => (), } - buffers.set_at(BufTy::Sv, name_ptr, buffers.at(BufTy::Ex, xptr)); + buffers.set_at(BufTy::Sv, name_ptr, str[xptr]); name_ptr += 1; xptr += 1; } @@ -1533,7 +1527,7 @@ fn interp_format_name( xptr += 1; token_starting = false; } - _ => match LexClass::of(buffers.at(BufTy::Ex, xptr)) { + _ => match LexClass::of(str[xptr]) { LexClass::Whitespace => { if !token_starting { buffers.set_at(BufTy::NameSep, num_tokens, b' '); @@ -1543,7 +1537,7 @@ fn interp_format_name( } LexClass::Sep => { if !token_starting { - buffers.set_at(BufTy::NameSep, num_tokens, buffers.at(BufTy::Ex, xptr)); + buffers.set_at(BufTy::NameSep, num_tokens, str[xptr]); } xptr += 1; token_starting = true; @@ -1553,7 +1547,7 @@ fn interp_format_name( buffers.set_name_tok(num_tokens, name_ptr); num_tokens += 1; } - buffers.set_at(BufTy::Sv, name_ptr, buffers.at(BufTy::Ex, xptr)); + buffers.set_at(BufTy::Sv, name_ptr, str[xptr]); name_ptr += 1; xptr += 1; token_starting = false; @@ -1645,8 +1639,6 @@ fn interp_format_name( } } - buffers.set_init(BufTy::Ex, 0); - add_buf_pool(pool, buffers, s1); figure_out_the_formatted_name( ctx, buffers, @@ -1751,20 +1743,18 @@ fn interp_missing( fn interp_num_names( ctx: &mut ExecCtx<'_, '_, '_>, pool: &mut StringPool, - buffers: &mut GlobalBuffer, hash: &HashData, cites: &CiteInfo, ) -> Result<(), BibtexError> { let pop1 = ctx.pop_stack(pool, cites)?; match pop1 { ExecVal::String(s1) => { - buffers.set_init(BufTy::Ex, 0); - add_buf_pool(pool, buffers, s1); - buffers.set_offset(BufTy::Ex, 1, 0); + let str = pool.get_str(s1); + let mut idx = 0; let mut num_names = 0; - while buffers.offset(BufTy::Ex, 1) < buffers.init(BufTy::Ex) { + while idx < str.len() { let mut brace_level = 0; - name_scan_for_and(ctx, pool, buffers, cites, s1, &mut brace_level)?; + name_scan_for_and(ctx, pool, cites, str, &mut idx, s1, &mut brace_level)?; num_names += 1; } ctx.push_stack(ExecVal::Integer(num_names)) @@ -2388,16 +2378,14 @@ pub(crate) fn execute_fn( } BstBuiltin::Missing => interp_missing(ctx, globals.pool, globals.hash, globals.cites), BstBuiltin::Newline => { - output_bbl_line(ctx, globals.buffers); + let to_print = globals.buffers.out(); + output_bbl_line(ctx, to_print); + to_print.clear(); Ok(()) } - BstBuiltin::NumNames => interp_num_names( - ctx, - globals.pool, - globals.buffers, - globals.hash, - globals.cites, - ), + BstBuiltin::NumNames => { + interp_num_names(ctx, globals.pool, globals.hash, globals.cites) + } BstBuiltin::Pop => ctx.pop_stack(globals.pool, globals.cites).map(|_| ()), BstBuiltin::Preamble => interp_preamble(ctx, globals.pool, globals.bibs), BstBuiltin::Purify => interp_purify(ctx, globals.pool, globals.hash, globals.cites), diff --git a/crates/engine_bibtex/src/log.rs b/crates/engine_bibtex/src/log.rs index 1014d2ba9..e5e864845 100644 --- a/crates/engine_bibtex/src/log.rs +++ b/crates/engine_bibtex/src/log.rs @@ -588,29 +588,22 @@ pub(crate) fn nonexistent_cross_reference_error( Ok(()) } -pub(crate) fn output_bbl_line(ctx: &mut Bibtex<'_, '_>, buffers: &mut GlobalBuffer) { - if buffers.init(BufTy::Out) != 0 { - let mut init = buffers.init(BufTy::Out); - while init > 0 { - if LexClass::of(buffers.at(BufTy::Out, init - 1)) == LexClass::Whitespace { - init -= 1; - } else { - break; - } - } - buffers.set_init(BufTy::Out, init); - if init == 0 { +pub(crate) fn output_bbl_line(ctx: &mut Bibtex<'_, '_>, line: &[u8]) { + if !line.is_empty() { + let pos = line + .iter() + .rposition(|b| LexClass::of(*b) != LexClass::Whitespace) + .unwrap_or(0); + if pos == 0 { return; } - let slice = &buffers.buffer(BufTy::Out)[..init]; ctx.engine .get_output(ctx.bbl_file.unwrap()) - .write_all(slice) + .write_all(&line[..pos + 1]) .unwrap(); } writeln!(ctx.engine.get_output(ctx.bbl_file.unwrap())).unwrap(); ctx.bbl_line_num += 1; - buffers.set_init(BufTy::Out, 0); } pub(crate) fn skip_token_print( diff --git a/crates/engine_bibtex/src/scan.rs b/crates/engine_bibtex/src/scan.rs index a0513375b..d268a3f3a 100644 --- a/crates/engine_bibtex/src/scan.rs +++ b/crates/engine_bibtex/src/scan.rs @@ -842,19 +842,11 @@ pub(crate) fn scan_and_store_the_field_value_and_eat_white( .set_field(field_ptr, globals.hash.get(res.loc).text()); if field == globals.other.crossref_num() && !ctx.all_entries { let end = globals.buffers.offset(BufTy::Ex, 1); - // Move Ex to Out, at the same position - globals.buffers.copy_within( - BufTy::Ex, - BufTy::Out, - ex_buf_xptr, - ex_buf_xptr, - end - ex_buf_xptr, - ); - globals.buffers.buffer_mut(BufTy::Out)[ex_buf_xptr..end].make_ascii_lowercase(); - let str = &globals.buffers.buffer(BufTy::Out)[ex_buf_xptr..end]; + let str = + globals.buffers.buffer(BufTy::Ex)[ex_buf_xptr..end].to_ascii_lowercase(); let lc_res = globals.hash.lookup_str_insert::( globals.pool, - str, + &str, HashPointer::default(), ); if let Some(cite_out) = cite_out { @@ -935,54 +927,51 @@ pub(crate) fn check_brace_level( pub(crate) fn name_scan_for_and( ctx: &mut ExecCtx<'_, '_, '_>, pool: &StringPool, - buffers: &mut GlobalBuffer, cites: &CiteInfo, + buf: &[u8], + idx: &mut usize, pop_lit_var: StrNumber, brace_level: &mut i32, ) -> Result<(), BibtexError> { let mut preceding_white = false; let mut and_found = false; - while !and_found && buffers.offset(BufTy::Ex, 1) < buffers.init(BufTy::Ex) { - match buffers.at_offset(BufTy::Ex, 1) { + while !and_found && *idx < buf.len() { + match buf[*idx] { b'A' | b'a' => { - buffers.set_offset(BufTy::Ex, 1, buffers.offset(BufTy::Ex, 1) + 1); + *idx += 1; if preceding_white - && buffers.offset(BufTy::Ex, 1) <= buffers.init(BufTy::Ex).saturating_sub(3) - && buffers.at_offset(BufTy::Ex, 1).eq_ignore_ascii_case(&b'n') - && buffers - .at(BufTy::Ex, buffers.offset(BufTy::Ex, 1) + 1) - .eq_ignore_ascii_case(&b'd') - && LexClass::of(buffers.at(BufTy::Ex, buffers.offset(BufTy::Ex, 1) + 2)) - == LexClass::Whitespace + && *idx <= buf.len().saturating_sub(3) + && buf[*idx].eq_ignore_ascii_case(&b'n') + && buf[*idx + 1].eq_ignore_ascii_case(&b'd') + && LexClass::of(buf[*idx + 2]) == LexClass::Whitespace { - buffers.set_offset(BufTy::Ex, 1, buffers.offset(BufTy::Ex, 1) + 2); + *idx += 2; and_found = true; } preceding_white = false; } b'{' => { *brace_level += 1; - buffers.set_offset(BufTy::Ex, 1, buffers.offset(BufTy::Ex, 1) + 1); - while *brace_level > 0 && buffers.offset(BufTy::Ex, 1) < buffers.init(BufTy::Ex) { - match buffers.at_offset(BufTy::Ex, 1) { + *idx += 1; + while *brace_level > 0 && *idx < buf.len() { + match buf[*idx] { b'{' => *brace_level += 1, b'}' => *brace_level -= 1, _ => (), } - buffers.set_offset(BufTy::Ex, 1, buffers.offset(BufTy::Ex, 1) + 1); + *idx += 1; } preceding_white = false; } b'}' => { decr_brace_level(ctx, pool, cites, pop_lit_var, brace_level)?; - buffers.set_offset(BufTy::Ex, 1, buffers.offset(BufTy::Ex, 1) + 1); + *idx += 1; preceding_white = false; } _ => { - preceding_white = - LexClass::of(buffers.at_offset(BufTy::Ex, 1)) == LexClass::Whitespace; - buffers.set_offset(BufTy::Ex, 1, buffers.offset(BufTy::Ex, 1) + 1); + preceding_white = LexClass::of(buf[*idx]) == LexClass::Whitespace; + *idx += 1; } } }