LCOV - code coverage report
Current view: top level - gcc/rust/util - rust-buffered-queue.h (source / functions) Coverage Total Hit
Test: gcc.info Lines: 98.1 % 53 52
Test Date: 2026-02-28 14:20:25 Functions: 100.0 % 6 6
Legend: Lines:     hit not hit

            Line data    Source code
       1              : // Copyright (C) 2020-2026 Free Software Foundation, Inc.
       2              : 
       3              : // This file is part of GCC.
       4              : 
       5              : // GCC is free software; you can redistribute it and/or modify it under
       6              : // the terms of the GNU General Public License as published by the Free
       7              : // Software Foundation; either version 3, or (at your option) any later
       8              : // version.
       9              : 
      10              : // GCC is distributed in the hope that it will be useful, but WITHOUT ANY
      11              : // WARRANTY; without even the implied warranty of MERCHANTABILITY or
      12              : // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      13              : // for more details.
      14              : 
      15              : // You should have received a copy of the GNU General Public License
      16              : // along with GCC; see the file COPYING3.  If not see
      17              : // <http://www.gnu.org/licenses/>.
      18              : 
      19              : #ifndef RUST_BUFFERED_QUEUE_H
      20              : #define RUST_BUFFERED_QUEUE_H
      21              : 
      22              : #include "rust-system.h"
      23              : 
      24              : namespace Rust {
      25              : /* Buffered queue implementation. Items are of type T, queue source is of type
      26              :  * Source. Note that this is owning of the source. */
      27         4791 : template <typename T, typename Source> class buffered_queue
      28              : {
      29              : public:
      30              :   // Construct empty queue from Source src.
      31         4690 :   buffered_queue (Source src) : source (src), start (0), end (0), buffer () {}
      32              : 
      33              :   /* disable copying (since source is probably non-copyable)
      34              :    * TODO is this actually a good idea? If source is non-copyable, it would
      35              :    * just delete the copy constructor anyway.*/
      36              :   buffered_queue (const buffered_queue &other) = delete;
      37              :   buffered_queue &operator= (const buffered_queue &other) = delete;
      38              : 
      39              :   // enable moving
      40              :   buffered_queue (buffered_queue &&other) = default;
      41              :   buffered_queue &operator= (buffered_queue &&other) = default;
      42              : 
      43              :   // Returns token at position start + n (i.e. n tokens ahead).
      44     11387906 :   T peek (int n)
      45              :   {
      46              :     // n should not be behind
      47     11387906 :     rust_assert (n >= 0);
      48              : 
      49     11387906 :     int num_queued_items = end - start;
      50     11387906 :     int num_items_required = n + 1;
      51              : 
      52              :     // if required items go past end of queue, add them to queue
      53     11387906 :     if (num_items_required > num_queued_items)
      54              :       {
      55      4183832 :         int num_items_to_read = num_items_required - num_queued_items;
      56              : 
      57              :         /* if queue length + extra items is larger than buffer size, expand
      58              :          * buffer */
      59      4183832 :         if (end + num_items_to_read > (int) buffer.size ())
      60              :           {
      61              :             // Resize the buffer by 1.5x
      62        23634 :             int new_size = (buffer.size () + num_items_to_read);
      63        23634 :             new_size += (new_size >> 1);
      64              : 
      65              :             // old method:
      66              :             /*
      67              :                   // create new queue buffer with new size
      68              :                   std::vector<T> new_queue (new_size);
      69              :                   std::copy (buffer.begin () + start, buffer.begin () + end,
      70              :                              new_queue.begin ());
      71              :                   start = 0;
      72              :                   end = num_queued_items;
      73              :                   // TODO: would move be better here? optimisation for move with
      74              :                   // shared pointer?
      75              : 
      76              :                   // swap member buffer and new queue buffer
      77              :                   std::swap (buffer, new_queue);
      78              :             */
      79              : 
      80              :             // TODO: determine overhead of this approach vs copy. Should be
      81              :             // lower.
      82        23634 :             std::vector<T> new_queue;
      83        23634 :             new_queue.reserve (new_size);
      84        23634 :             new_queue.insert (new_queue.begin (),
      85        23634 :                               std::make_move_iterator (buffer.begin () + start),
      86        23634 :                               std::make_move_iterator (buffer.begin () + end));
      87        23634 :             start = 0;
      88        23634 :             end = num_queued_items;
      89              :             // fill up rest of vector with junk so that indexing can work
      90        33159 :             new_queue.insert (new_queue.begin () + end,
      91        23634 :                               new_size - new_queue.size (), T ());
      92              : 
      93        23634 :             buffer = std::move (new_queue);
      94              :             /* this should be best method - std::move(range) would have
      95              :              * allocation problems; initial construction would require
      96              :              * reallocation upon resizing */
      97              : 
      98              :             // validate that buffer is large enough now
      99        23634 :             rust_assert (end + num_items_to_read <= (int) buffer.size ());
     100        23634 :           }
     101              : 
     102              :         /* iterate through buffer and invoke operator () on source on values
     103              :          * past original end */
     104      8406493 :         for (int i = 0; i < num_items_to_read; i++)
     105      4222661 :           buffer[end + i] = source.get ().next ();
     106              : 
     107              :         // move end based on additional items added
     108      4183832 :         end += num_items_to_read;
     109              :       }
     110              : 
     111     11387906 :     rust_assert (0 <= start);
     112     11387906 :     rust_assert (start <= end);
     113     11387906 :     rust_assert (end <= (int) buffer.size ());
     114              : 
     115     11387906 :     rust_assert (start + n < end);
     116              : 
     117              :     // return value at start + n in buffer
     118     11387906 :     return buffer[start + n];
     119              :   }
     120              : 
     121              :   /* TODO: add faster peek current token to remove overhead of conditional
     122              :    * branches? */
     123              : 
     124              :   // Advances start by n + 1.
     125      4204290 :   void skip (int n)
     126              :   {
     127              :     // Call peek to ensure requested n is actually in queue.
     128      4204290 :     peek (n);
     129              : 
     130              :     // Clear queue values from start to n (inclusive).
     131      8421908 :     for (int i = 0; i < (n + 1); i++)
     132      4217618 :       buffer[start + i] = T ();
     133              : 
     134              :     // Move start forward by n + 1.
     135      4204290 :     start += (n + 1);
     136              : 
     137              :     // Ensure start is not impossible somehow
     138      4204290 :     rust_assert (0 <= start);
     139      4204290 :     rust_assert (start <= end);
     140              : 
     141              :     // Compact buffer if empty
     142      4204290 :     if (start == end)
     143      4030345 :       start = end = 0;
     144      4204290 :   }
     145              : 
     146              :   /* Inserts element at front of vector. Really dirty hack with terrible
     147              :    * performance, only use when really needed. */
     148              :   void insert_at_front (T elem_to_insert)
     149              :   {
     150              :     // TODO: test as this may not work properly
     151              : 
     152              :     // Insert actual element in buffer at start.
     153              :     buffer.insert (buffer.begin (), elem_to_insert);
     154              : 
     155              :     /* Increase the end number since added element means all others have shifted
     156              :      * one along */
     157              :     end++;
     158              :   }
     159              : 
     160              :   // Insert at arbitrary position (attempt)
     161          103 :   void insert (int index, T elem_to_insert)
     162              :   {
     163              :     // TODO: test as this may not work properly
     164              : 
     165              :     // n should not be behind
     166          103 :     rust_assert (index >= 0);
     167              : 
     168              :     // call peek to ensure that the items behind this (at least) are in queue
     169          103 :     if (index >= 1)
     170          206 :       peek (index - 1);
     171              :     else
     172            0 :       peek (index);
     173              : 
     174          103 :     buffer.insert (buffer.begin () + start + index, std::move (elem_to_insert));
     175              : 
     176          103 :     end++;
     177          103 :   }
     178              : 
     179              :   // Replaces the current value in the buffer. Total HACK.
     180          102 :   void replace_current_value (T replacement)
     181              :   {
     182              :     // call peek to ensure value exists
     183          102 :     peek (0);
     184              : 
     185          102 :     buffer[start] = std::move (replacement);
     186              : 
     187              :     // don't move start or end
     188          102 :   }
     189              : 
     190              : private:
     191              :   // Source of tokens for queue.
     192              :   Source source;
     193              : 
     194              :   // Begin of range in buffer, inclusive.
     195              :   int start;
     196              :   // End of range in buffer, exclusive.
     197              :   int end;
     198              : 
     199              :   // Queue buffer.
     200              :   std::vector<T> buffer;
     201              : };
     202              : } // namespace Rust
     203              : 
     204              : #endif
        

Generated by: LCOV version 2.4-beta

LCOV profile is generated on x86_64 machine using following configure options: configure --disable-bootstrap --enable-coverage=opt --enable-languages=c,c++,fortran,go,jit,lto,rust,m2 --enable-host-shared. GCC test suite is run with the built compiler.