LCOV - code coverage report
Current view: top level - include/utils - Buffer.h (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 2bf808 Lines: 35 38 92.1 %
Date: 2025-07-17 01:28:37 Functions: 17 20 85.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //* This file is part of the MOOSE framework
       2             : //* https://mooseframework.inl.gov
       3             : //*
       4             : //* All rights reserved, see COPYRIGHT for full restrictions
       5             : //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
       6             : //*
       7             : //* Licensed under LGPL 2.1, please see LICENSE for details
       8             : //* https://www.gnu.org/licenses/lgpl-2.1.html
       9             : 
      10             : #pragma once
      11             : 
      12             : #include "MooseError.h"
      13             : 
      14             : #include <vector>
      15             : 
      16             : namespace MooseUtils
      17             : {
      18             : 
      19             : /**
      20             :  * Base class for a buffer.
      21             :  *
      22             :  * Enables the controlled access of an underlying raw vector
      23             :  * for storage, which can be used to limit memory allocation
      24             :  * and copies for various buffer types while providing a
      25             :  * useful public API.
      26             :  */
      27             : template <typename T>
      28             : class Buffer
      29             : {
      30             : public:
      31             :   typedef typename std::vector<T>::iterator iterator;
      32             :   typedef typename std::vector<T>::const_iterator const_iterator;
      33             : 
      34             :   /**
      35             :    * Create an empty buffer
      36             :    */
      37             :   Buffer();
      38             : 
      39             :   /**
      40             :    * Create a buffer with a specific capacity
      41             :    */
      42             :   Buffer(const std::size_t capacity);
      43             : 
      44           2 :   virtual ~Buffer() {}
      45             : 
      46             :   /**
      47             :    * Resize the capacity
      48             :    */
      49           2 :   void setCapacity(const std::size_t capacity) { this->_data.resize(capacity); }
      50             :   /**
      51             :    * Get the capacity
      52             :    */
      53          14 :   std::size_t capacity() const { return this->_data.size(); }
      54             : 
      55             :   /**
      56             :    * Set the size
      57             :    */
      58             :   void setSize(const std::size_t size) { this->_end_pos = this->newEnd(this->_begin_pos + size); }
      59             :   /**
      60             :    * Get the size
      61             :    */
      62          52 :   std::size_t size() const { return this->_end_pos - this->_begin_pos; }
      63             : 
      64             :   /**
      65             :    * Whether or not the buffer is empty
      66             :    */
      67           6 :   bool empty() const { return !size(); }
      68             : 
      69             :   /**
      70             :    * Add a new entry on the end
      71             :    */
      72             :   void push_back(const T & value);
      73             : 
      74             :   /**
      75             :    * Moves the object into the buffer (calls std::move())
      76             :    */
      77             :   void move(T & value);
      78             : 
      79             :   /**
      80             :    * Add new entries to the end
      81             :    *
      82             :    * Everything in [in_begin, in_end) is appended
      83             :    */
      84             :   void append(const_iterator in_begin, const_iterator in_end);
      85             :   /**
      86             :    * Add new entries to the end
      87             :    */
      88             :   void append(const std::vector<T> & vals);
      89             : 
      90             :   /**
      91             :    * Remove all entries (does not change the capacity)
      92             :    * Note: this does NOT at all free any entries
      93             :    */
      94             :   void clear();
      95             : 
      96             :   /**
      97             :    * Remove the first num elements
      98             :    *
      99             :    * Note that erased items are not guaranteed to be freed immediately
     100             :    */
     101             :   virtual void erase(const std::size_t num) = 0;
     102             :   /*
     103             :    * Similar to erase(), but if the chunk size is larger than the current size,
     104             :    * no error (all elements are erased gracefully).
     105             :    *
     106             :    * Note that erased items are not guaranteed to be freed immediately
     107             :    */
     108             :   virtual void eraseChunk(const std::size_t chunk_size) = 0;
     109             : 
     110             :   /**
     111             :    * Iterator for the first entry in the buffer
     112             :    */
     113          17 :   iterator begin() { return this->_data.begin() + this->_begin_pos; }
     114             :   /**
     115             :    * Const iterator for the first entry in the buffer
     116             :    */
     117           0 :   const_iterator begin() const { return this->_data.begin() + this->_begin_pos; }
     118             : 
     119             :   /**
     120             :    * Iterator for the last entry in the buffer
     121             :    */
     122          29 :   iterator end() { return this->_data.begin() + this->_end_pos; }
     123             :   /**
     124             :    * Const iterator for the last entry in the buffer
     125             :    */
     126           0 :   const_iterator end() const { return this->_data.begin() + this->_end_pos; }
     127             : 
     128             :   /**
     129             :    * Iterator for the first entry with a given chunk size in the buffer
     130             :    * If chunk_size is greater than the size of the buffer, the full range will be given.
     131             :    */
     132             :   virtual iterator beginChunk(const std::size_t chunk_size) = 0;
     133             :   /**
     134             :    * Const iterator for the first entry with a given chunk size in the buffer
     135             :    * If chunk_size is greater than the size of the buffer, the full range will be given.
     136             :    */
     137             :   virtual const_iterator beginChunk(const std::size_t chunk_size) const = 0;
     138             : 
     139             :   /**
     140             :    * Iterator for the last entry of a chunk size in the buffer
     141             :    * If chunk_size is greater than the size of the buffer, the full range will be given.
     142             :    */
     143             :   virtual iterator endChunk(const std::size_t chunk_size) = 0;
     144             :   /**
     145             :    * Const iterator for the last entry of a chunk size in the buffer
     146             :    * If chunk_size is greater than the size of the buffer, the full range will be given.
     147             :    */
     148             :   virtual const_iterator endChunk(const std::size_t chunk_size) const = 0;
     149             : 
     150             :   /**
     151             :    * Access an entry at index
     152             :    */
     153             :   T & operator[](const std::size_t index);
     154             :   /**
     155             :    * Const access an entry at an index
     156             :    */
     157             :   const T & operator[](const std::size_t index) const;
     158             : 
     159             :   /**
     160             :    * Use in_data as our data vector
     161             :    */
     162             :   void swap(std::vector<T> & in_data);
     163             : 
     164             :   /**
     165             :    * Access the raw underlying storage.
     166             :    *
     167             :    * This is considered an advanced interface. Typically, you
     168             :    * should use the begin(), beginChunk(), end(), and endChunk()
     169             :    * methods for accessing the data. This should really only
     170             :    * be used in unit tests for verifying the underlying storage.
     171             :    */
     172           2 :   const std::vector<T> & data() { return _data; }
     173             : 
     174             :   /**
     175             :    * The current beginning position of the buffer in data().
     176             :    *
     177             :    * This is considered an advanced interface because data()
     178             :    * is the internal storage for the buffer. It should really
     179             :    * only be used in unit tests for verifying the underlying
     180             :    * storage.
     181             :    */
     182          26 :   std::size_t dataBeginPos() const { return _begin_pos; }
     183             : 
     184             :   /**
     185             :    * The current end position of the buffer in data().
     186             :    *
     187             :    * This is considered an advanced interface because data()
     188             :    * is the internal storage for the buffer. It should really
     189             :    * only be used in unit tests for verifying the underlying
     190             :    * storage.
     191             :    */
     192          24 :   std::size_t dataEndPos() const { return _end_pos; }
     193             : 
     194             : protected:
     195             :   /**
     196             :    * Find out where the new end will be.
     197             :    * This will resize/copy data as necessary
     198             :    *
     199             :    * @param new_end the proposed new_end position
     200             :    * @return The actual position of the new ending
     201             :    */
     202             :   virtual std::size_t newEnd(const std::size_t new_end) = 0;
     203             : 
     204             :   /// The raw data
     205             :   std::vector<T> _data;
     206             : 
     207             :   /// The beginning position
     208             :   std::size_t _begin_pos;
     209             :   /// The ending position
     210             :   std::size_t _end_pos;
     211             : };
     212             : 
     213             : template <typename T>
     214             : Buffer<T>::Buffer() : _begin_pos(0), _end_pos(0)
     215             : {
     216             : }
     217             : 
     218             : template <typename T>
     219           2 : Buffer<T>::Buffer(const std::size_t capacity) : _data(capacity), _begin_pos(0), _end_pos(0)
     220             : {
     221           2 : }
     222             : 
     223             : template <typename T>
     224             : void
     225          76 : Buffer<T>::push_back(const T & value)
     226             : {
     227          76 :   this->_end_pos = newEnd(this->_end_pos + 1);
     228          76 :   this->_data[this->_end_pos - 1] = value;
     229          76 : }
     230             : 
     231             : template <typename T>
     232             : void
     233             : Buffer<T>::move(T & value)
     234             : {
     235             :   this->_end_pos = newEnd(this->_end_pos + 1);
     236             :   this->_data[this->_end_pos - 1] = std::move(value);
     237             : }
     238             : 
     239             : template <typename T>
     240             : void
     241           2 : Buffer<T>::append(const_iterator in_begin, const_iterator in_end)
     242             : {
     243           2 :   const auto additional_size = std::distance(in_begin, in_end);
     244           2 :   if (additional_size == 0)
     245           0 :     return;
     246             : 
     247           2 :   this->_end_pos = this->newEnd(this->_end_pos + additional_size);
     248           2 :   std::copy(in_begin, in_end, this->end() - additional_size);
     249             : }
     250             : 
     251             : template <typename T>
     252             : void
     253           2 : Buffer<T>::append(const std::vector<T> & vals)
     254             : {
     255           2 :   this->append(vals.begin(), vals.end());
     256           2 : }
     257             : 
     258             : template <typename T>
     259             : void
     260           6 : Buffer<T>::clear()
     261             : {
     262           6 :   this->_begin_pos = 0;
     263           6 :   this->_end_pos = 0;
     264           6 : }
     265             : 
     266             : template <typename T>
     267             : T &
     268          22 : Buffer<T>::operator[](const std::size_t index)
     269             : {
     270             :   mooseAssert(this->_begin_pos + index < this->_end_pos, "Attempt to access off end of Buffer!");
     271          22 :   return this->_data[this->_begin_pos + index];
     272             : }
     273             : 
     274             : template <typename T>
     275             : const T &
     276             : Buffer<T>::operator[](const std::size_t index) const
     277             : {
     278             :   mooseAssert(this->_begin_pos + index < this->_end_pos, "Attempt to access off end of Buffer!");
     279             :   return this->_data[this->_begin_pos + index];
     280             : }
     281             : 
     282             : template <typename T>
     283             : void
     284           2 : Buffer<T>::swap(std::vector<T> & in_data)
     285             : {
     286           2 :   std::swap(in_data, _data);
     287           2 :   this->_begin_pos = 0;
     288           2 :   this->_end_pos = this->_data.size();
     289           2 : }
     290             : 
     291             : }

Generated by: LCOV version 1.14