@@ -249,20 +249,47 @@ impl TokenStream {
249249 0 => TokenStream :: empty ( ) ,
250250 1 => streams. pop ( ) . unwrap ( ) ,
251251 _ => {
252- // rust-lang/rust#57735: pre-allocate vector to avoid
253- // quadratic blow-up due to on-the-fly reallocations.
254- let tree_count = streams. iter ( )
255- . map ( |ts| match & ts. 0 { None => 0 , Some ( s) => s. len ( ) } )
252+ // We are going to extend the first stream in `streams` with
253+ // the elements from the subsequent streams. This requires
254+ // using `make_mut()` on the first stream, and in practice this
255+ // doesn't cause cloning 99.9% of the time.
256+ //
257+ // One very common use case is when `streams` has two elements,
258+ // where the first stream has any number of elements within
259+ // (often 1, but sometimes many more) and the second stream has
260+ // a single element within.
261+
262+ // Determine how much the first stream will be extended.
263+ // Needed to avoid quadratic blow up from on-the-fly
264+ // reallocations (#57735).
265+ let num_appends = streams. iter ( )
266+ . skip ( 1 )
267+ . map ( |ts| ts. len ( ) )
256268 . sum ( ) ;
257- let mut vec = Vec :: with_capacity ( tree_count) ;
258269
259- for stream in streams {
260- match stream. 0 {
261- None => { } ,
262- Some ( stream2) => vec. extend ( stream2. iter ( ) . cloned ( ) ) ,
270+ // Get the first stream. If it's `None`, create an empty
271+ // stream.
272+ let mut iter = streams. drain ( ) ;
273+ let mut first_stream_lrc = match iter. next ( ) . unwrap ( ) . 0 {
274+ Some ( first_stream_lrc) => first_stream_lrc,
275+ None => Lrc :: new ( vec ! [ ] ) ,
276+ } ;
277+
278+ // Append the elements to the first stream, after reserving
279+ // space for them.
280+ let first_vec_mut = Lrc :: make_mut ( & mut first_stream_lrc) ;
281+ first_vec_mut. reserve ( num_appends) ;
282+ for stream in iter {
283+ if let Some ( stream) = stream. 0 {
284+ first_vec_mut. extend ( stream. iter ( ) . cloned ( ) ) ;
263285 }
264286 }
265- TokenStream :: new ( vec)
287+
288+ // Create the final `TokenStream`.
289+ match first_vec_mut. len ( ) {
290+ 0 => TokenStream ( None ) ,
291+ _ => TokenStream ( Some ( first_stream_lrc) ) ,
292+ }
266293 }
267294 }
268295 }
@@ -363,25 +390,6 @@ impl TokenStream {
363390 . collect ( ) )
364391 } ) )
365392 }
366-
367- fn first_tree_and_joint ( & self ) -> Option < TreeAndJoint > {
368- self . 0 . as_ref ( ) . map ( |stream| {
369- stream. first ( ) . unwrap ( ) . clone ( )
370- } )
371- }
372-
373- fn last_tree_if_joint ( & self ) -> Option < TokenTree > {
374- match self . 0 {
375- None => None ,
376- Some ( ref stream) => {
377- if let ( tree, Joint ) = stream. last ( ) . unwrap ( ) {
378- Some ( tree. clone ( ) )
379- } else {
380- None
381- }
382- }
383- }
384- }
385393}
386394
387395// 99.5%+ of the time we have 1 or 2 elements in this vector.
@@ -394,18 +402,49 @@ impl TokenStreamBuilder {
394402 }
395403
396404 pub fn push < T : Into < TokenStream > > ( & mut self , stream : T ) {
397- let stream = stream. into ( ) ;
398- let last_tree_if_joint = self . 0 . last ( ) . and_then ( TokenStream :: last_tree_if_joint) ;
399- if let Some ( TokenTree :: Token ( last_token) ) = last_tree_if_joint {
400- if let Some ( ( TokenTree :: Token ( token) , is_joint) ) = stream. first_tree_and_joint ( ) {
401- if let Some ( glued_tok) = last_token. glue ( & token) {
402- let last_stream = self . 0 . pop ( ) . unwrap ( ) ;
403- self . push_all_but_last_tree ( & last_stream) ;
404- let glued_tt = TokenTree :: Token ( glued_tok) ;
405- let glued_tokenstream = TokenStream :: new ( vec ! [ ( glued_tt, is_joint) ] ) ;
406- self . 0 . push ( glued_tokenstream) ;
407- self . push_all_but_first_tree ( & stream) ;
408- return
405+ let mut stream = stream. into ( ) ;
406+
407+ // If `self` is not empty and the last tree within the last stream is a
408+ // token tree marked with `Joint`...
409+ if let Some ( TokenStream ( Some ( ref mut last_stream_lrc) ) ) = self . 0 . last_mut ( ) {
410+ if let Some ( ( TokenTree :: Token ( last_token) , Joint ) ) = last_stream_lrc. last ( ) {
411+
412+ // ...and `stream` is not empty and the first tree within it is
413+ // a token tree...
414+ if let TokenStream ( Some ( ref mut stream_lrc) ) = stream {
415+ if let Some ( ( TokenTree :: Token ( token) , is_joint) ) = stream_lrc. first ( ) {
416+
417+ // ...and the two tokens can be glued together...
418+ if let Some ( glued_tok) = last_token. glue ( & token) {
419+
420+ // ...then do so, by overwriting the last token
421+ // tree in `self` and removing the first token tree
422+ // from `stream`. This requires using `make_mut()`
423+ // on the last stream in `self` and on `stream`,
424+ // and in practice this doesn't cause cloning 99.9%
425+ // of the time.
426+
427+ // Overwrite the last token tree with the merged
428+ // token.
429+ let last_vec_mut = Lrc :: make_mut ( last_stream_lrc) ;
430+ * last_vec_mut. last_mut ( ) . unwrap ( ) =
431+ ( TokenTree :: Token ( glued_tok) , * is_joint) ;
432+
433+ // Remove the first token tree from `stream`. (This
434+ // is almost always the only tree in `stream`.)
435+ let stream_vec_mut = Lrc :: make_mut ( stream_lrc) ;
436+ stream_vec_mut. remove ( 0 ) ;
437+
438+ // Don't push `stream` if it's empty -- that could
439+ // block subsequent token gluing, by getting
440+ // between two token trees that should be glued
441+ // together.
442+ if !stream. is_empty ( ) {
443+ self . 0 . push ( stream) ;
444+ }
445+ return ;
446+ }
447+ }
409448 }
410449 }
411450 }
@@ -415,26 +454,6 @@ impl TokenStreamBuilder {
415454 pub fn build ( self ) -> TokenStream {
416455 TokenStream :: from_streams ( self . 0 )
417456 }
418-
419- fn push_all_but_last_tree ( & mut self , stream : & TokenStream ) {
420- if let Some ( ref streams) = stream. 0 {
421- let len = streams. len ( ) ;
422- match len {
423- 1 => { }
424- _ => self . 0 . push ( TokenStream ( Some ( Lrc :: new ( streams[ 0 .. len - 1 ] . to_vec ( ) ) ) ) ) ,
425- }
426- }
427- }
428-
429- fn push_all_but_first_tree ( & mut self , stream : & TokenStream ) {
430- if let Some ( ref streams) = stream. 0 {
431- let len = streams. len ( ) ;
432- match len {
433- 1 => { }
434- _ => self . 0 . push ( TokenStream ( Some ( Lrc :: new ( streams[ 1 .. len] . to_vec ( ) ) ) ) ) ,
435- }
436- }
437- }
438457}
439458
440459#[ derive( Clone ) ]
0 commit comments