LCOV - code coverage report
Current view: top level - AP_HAL/utility - RingBuffer.h (source / functions) Hit Total Coverage
Test: lcov.info Lines: 132 146 90.4 %
Date: 2026-09-09 11:02:08 Functions: 125 173 72.3 %

          Line data    Source code
       1             : #pragma once
       2             : 
       3             : #include <atomic>
       4             : #include <stdint.h>
       5             : #include <AP_HAL/AP_HAL_Boards.h>
       6             : #include <AP_HAL/AP_HAL_Macros.h>
       7             : #include <AP_HAL/Semaphores.h>
       8             : 
       9             : /*
      10             :  * Circular buffer of bytes.
      11             :  */
      12             : class ByteBuffer {
      13             : public:
      14             :     ByteBuffer(uint32_t size);
      15           2 :     ByteBuffer(uint8_t* _buf, uint32_t _size) :
      16           2 :     buf(_buf),
      17           2 :     size(_size),
      18           2 :     external_buf(true)
      19           2 :     {}
      20             :     ~ByteBuffer(void);
      21             : 
      22             :     // number of bytes available to be read
      23             :     uint32_t available(void) const;
      24             : 
      25             :     // Discards the buffer content, emptying it.
      26             :     void clear(void);
      27             : 
      28             :     // number of bytes space available to write
      29             :     uint32_t space(void) const;
      30             : 
      31             :     // true if available() is zero
      32             :     bool is_empty(void) const WARN_IF_UNUSED;
      33             : 
      34             :     // write bytes to ringbuffer. Returns number of bytes written
      35             :     uint32_t write(const uint8_t *data, uint32_t len);
      36             : 
      37             :     // read bytes from ringbuffer. Returns number of bytes read
      38             :     uint32_t read(uint8_t *data, uint32_t len);
      39             : 
      40             :     // read a byte from ring buffer. Returns true on success, false otherwise
      41             :     bool read_byte(uint8_t *data) WARN_IF_UNUSED;
      42             : 
      43             :     /*
      44             :       update bytes at the read pointer. Used to update an object without
      45             :       popping it
      46             :     */
      47             :     bool update(const uint8_t *data, uint32_t len);
      48             : 
      49             :     // return size of ringbuffer
      50   192255345 :     uint32_t get_size(void) const { return size; }
      51             : 
      52             :     // set size of ringbuffer, caller responsible for locking
      53             :     bool set_size(uint32_t size);
      54             : 
      55             :     // set size of ringbuffer, reducing down if size can't be achieved
      56             :     bool set_size_best(uint32_t size);
      57             :     
      58             :     // advance the read pointer (discarding bytes)
      59             :     bool advance(uint32_t n);
      60             : 
      61             :     // Returns the pointer and size to a contiguous read of the next available data
      62             :     const uint8_t *readptr(uint32_t &available_bytes);
      63             : 
      64             :     // peek one byte without advancing read pointer. Return byte
      65             :     // or -1 if none available
      66             :     int16_t peek(uint32_t ofs) const;
      67             : 
      68             :     /*
      69             :       read len bytes without advancing the read pointer
      70             :     */
      71             :     uint32_t peekbytes(uint8_t *data, uint32_t len);
      72             : 
      73             :     // Similar to peekbytes(), but will fill out IoVec struct with
      74             :     // both parts of the ring buffer if wraparound is happening, or
      75             :     // just one part. Returns the number of parts written to.
      76             :     struct IoVec {
      77             :         uint8_t *data;
      78             :         uint32_t len;
      79             :     };
      80             :     uint8_t peekiovec(IoVec vec[2], uint32_t len);
      81             : 
      82             :     // Reserve `len` bytes and fills out `vec` with both parts of the
      83             :     // ring buffer (if wraparound is happening), or just one contiguous
      84             :     // part. Returns the number of `vec` elements filled out. Can be used
      85             :     // with system calls such as `readv()`.
      86             :     //
      87             :     // After a call to 'reserve()', 'write()' should never be called
      88             :     // until 'commit()' is called!
      89             :     uint8_t reserve(IoVec vec[2], uint32_t len);
      90             : 
      91             :     /*
      92             :      * "Releases" the memory previously reserved by 'reserve()' to be read.
      93             :      * Committer must inform how many bytes were actually written in 'len'.
      94             :      */
      95             :     bool commit(uint32_t len);
      96             : 
      97             : private:
      98             :     uint8_t *buf;
      99             :     uint32_t size;
     100             : 
     101             :     std::atomic<uint32_t> head{0}; // where to read data
     102             :     std::atomic<uint32_t> tail{0}; // where to write data
     103             : 
     104             :     bool external_buf;
     105             : };
     106             : 
     107             : /*
     108             :   ring buffer class for objects of fixed size
     109             :   !!! Note ObjectBuffer_TS is a duplicate of this update, in both places !!!
     110             :  */
     111             : template <class T>
     112             : class ObjectBuffer {
     113             : public:
     114       42200 :     ObjectBuffer(uint32_t _size = 0) {
     115             :         // we set size to 1 more than requested as the byte buffer
     116             :         // gives one less byte than requested. We round up to a full
     117             :         // multiple of the object size so that we always get aligned
     118             :         // elements, which makes the readptr() method possible
     119       42200 :         buffer = NEW_NOTHROW ByteBuffer(((_size+1) * sizeof(T)));
     120       42200 :         external_buf = false;
     121       42200 :     }
     122             : 
     123             :     ObjectBuffer(ByteBuffer *_buffer) :
     124             :     buffer(_buffer),
     125             :     external_buf(true)
     126             :     {}
     127             : 
     128        7567 :     ~ObjectBuffer(void) {
     129        7567 :         if (!external_buf)
     130        7567 :             delete buffer;
     131        7567 :     }
     132             : 
     133             :     // return size of ringbuffer
     134    10610263 :     uint32_t get_size(void) const {
     135    10610263 :         if (buffer == nullptr) {
     136           0 :             return 0;
     137             :         }
     138    10610263 :         uint32_t size = buffer->get_size() / sizeof(T);
     139    10610263 :         return size>0?size-1:0;
     140             :     }
     141             : 
     142             :     // set size of ringbuffer, caller responsible for locking
     143         191 :     bool set_size(uint32_t size) { return buffer->set_size(((size+1) * sizeof(T))); }
     144             : 
     145             :     // read len objects without advancing the read pointer
     146      281246 :     uint32_t peek(T *data, uint32_t len) { return buffer->peekbytes((uint8_t*)data, len * sizeof(T)) / sizeof(T); }
     147             : 
     148             :     // Discards the buffer content, emptying it.
     149             :     // !!! Note ObjectBuffer_TS is a duplicate of this update, in both places !!!
     150        1769 :     void clear(void)
     151             :     {
     152        1769 :         buffer->clear();
     153        1769 :     }
     154             : 
     155             :     // return number of objects available to be read from the front of the queue
     156             :     // !!! Note ObjectBuffer_TS is a duplicate of this update, in both places !!!
     157   536514815 :     uint32_t available(void) const {
     158   536514815 :         return buffer->available() / sizeof(T);
     159             :     }
     160             : 
     161             :     // return number of objects that could be written to the back of the queue
     162             :     // !!! Note ObjectBuffer_TS is a duplicate of this update, in both places !!!
     163   255021019 :     uint32_t space(void) const {
     164   255021019 :         return buffer->space() / sizeof(T);
     165             :     }
     166             : 
     167             :     // true is available() == 0
     168             :     // !!! Note ObjectBuffer_TS is a duplicate of this update, in both places !!!
     169        2390 :     bool is_empty(void) const WARN_IF_UNUSED {
     170        2390 :         return buffer->is_empty();
     171             :     }
     172             : 
     173             :     // push one object onto the back of the queue
     174             :     // !!! Note ObjectBuffer_TS is a duplicate of this update, in both places !!!
     175    31630102 :     bool push(const T &object) {
     176    31630102 :         if (buffer->space() < sizeof(T)) {
     177     5634685 :             return false;
     178             :         }
     179    25995417 :         return buffer->write((uint8_t*)&object, sizeof(T)) == sizeof(T);
     180             :     }
     181             : 
     182             :     // push N objects onto the back of the queue
     183             :     // !!! Note ObjectBuffer_TS is a duplicate of this update, in both places !!!
     184             :     bool push(const T *object, uint32_t n) {
     185             :         if (buffer->space() < n*sizeof(T)) {
     186             :             return false;
     187             :         }
     188             :         return buffer->write((uint8_t*)object, n*sizeof(T)) == n*sizeof(T);
     189             :     }
     190             :     
     191             :     /*
     192             :       throw away an object from the front of the queue
     193             :      */
     194             :     // !!! Note ObjectBuffer_TS is a duplicate of this update, in both places !!!
     195       25297 :     bool pop(void) {
     196       25297 :         return buffer->advance(sizeof(T));
     197             :     }
     198             : 
     199             :     /*
     200             :       pop earliest object off the front of the queue
     201             :      */
     202             :     // !!! Note ObjectBuffer_TS is a duplicate of this update, in both places !!!
     203   254343839 :     bool pop(T &object) WARN_IF_UNUSED {
     204   254343839 :         if (buffer->available() < sizeof(T)) {
     205   234002237 :             return false;
     206             :         }
     207    20341602 :         return buffer->read((uint8_t*)&object, sizeof(T)) == sizeof(T);
     208             :     }
     209             : 
     210             : 
     211             :     /*
     212             :      * push_force() is semantically equivalent to:
     213             :      *   if (!push(t)) { pop(); push(t); }
     214             :      */
     215             :     // !!! Note ObjectBuffer_TS is a duplicate of this update, in both places !!!
     216         113 :     bool push_force(const T &object) {
     217         113 :         if (buffer->space() < sizeof(T)) {
     218          86 :             buffer->advance(sizeof(T));
     219             :         }
     220         113 :         return push(object);
     221             :     }
     222             : 
     223             :     /*
     224             :      * push_force() N objects
     225             :      */
     226             :     // !!! Note ObjectBuffer_TS is a duplicate of this update, in both places !!!
     227             :     bool push_force(const T *object, uint32_t n) {
     228             :         uint32_t _space = buffer->space();
     229             :         if (_space < sizeof(T)*n) {
     230             :             buffer->advance(sizeof(T)*(n-_space));
     231             :         }
     232             :         return push(object, n);
     233             :     }
     234             :     
     235             :     /*
     236             :       peek copies an object out from the front of the queue without advancing the read pointer
     237             :      */
     238             :     // !!! Note ObjectBuffer_TS is a duplicate of this update, in both places !!!
     239     1648500 :     bool peek(T &object) WARN_IF_UNUSED {
     240     1648500 :         return buffer->peekbytes((uint8_t*)&object, sizeof(T)) == sizeof(T);
     241             :     }
     242             : 
     243             :     /*
     244             :       return a pointer to first contiguous array of available
     245             :       objects. Return nullptr if none available
     246             :      */
     247             :     // !!! Note ObjectBuffer_TS is a duplicate of this, update in both places !!!
     248             :     const T *readptr(uint32_t &n) {
     249             :         uint32_t avail_bytes = 0;
     250             :         #pragma GCC diagnostic push
     251             :         #pragma GCC diagnostic ignored "-Wcast-align"
     252             :         const T *ret = (const T *)buffer->readptr(avail_bytes);
     253             :         #pragma GCC diagnostic pop
     254             :         if (!ret || avail_bytes < sizeof(T)) {
     255             :             return nullptr;
     256             :         }
     257             :         n = avail_bytes / sizeof(T);
     258             :         return ret;
     259             :     }
     260             : 
     261             :     // advance the read pointer (discarding objects)
     262             :     // !!! Note ObjectBuffer_TS is a duplicate of this, update in both places !!!
     263      281527 :     bool advance(uint32_t n) {
     264      281527 :         return buffer->advance(n * sizeof(T));
     265             :     }
     266             :     
     267             :     /* update the object at the front of the queue (the one that would
     268             :        be fetched by pop()) */
     269             :     // !!! Note ObjectBuffer_TS is a duplicate of this, update in both places !!!
     270             :     bool update(const T &object) {
     271             :         return buffer->update((uint8_t*)&object, sizeof(T));
     272             :     }
     273             : 
     274             : private:
     275             :     ByteBuffer *buffer = nullptr;
     276             :     bool external_buf = true;
     277             : };
     278             : 
     279             : /*
     280             :   Thread safe ring buffer class for objects of fixed size
     281             :   !!! Note this is a duplicate of ObjectBuffer with semaphore, update in both places !!!
     282             :  */
     283             : template <class T>
     284             : class ObjectBuffer_TS {
     285             : public:
     286        4392 :     ObjectBuffer_TS(uint32_t _size = 0) {
     287             :         // we set size to 1 more than requested as the byte buffer
     288             :         // gives one less byte than requested. We round up to a full
     289             :         // multiple of the object size so that we always get aligned
     290             :         // elements, which makes the readptr() method possible
     291        4392 :         buffer = NEW_NOTHROW ByteBuffer(((_size+1) * sizeof(T)));
     292        4392 :     }
     293        1106 :     ~ObjectBuffer_TS(void) {
     294        1106 :         delete buffer;
     295        1106 :     }
     296             : 
     297             :     // return size of ringbuffer
     298             :     uint32_t get_size(void) {
     299             :         WITH_SEMAPHORE(sem);
     300             :         if (buffer == nullptr) {
     301             :             return 0;
     302             :         }
     303             :         uint32_t size = buffer->get_size() / sizeof(T);
     304             :         return size>0?size-1:0;
     305             :     }
     306             : 
     307             :     // set size of ringbuffer, caller responsible for locking
     308             :     bool set_size(uint32_t size) {
     309             :         WITH_SEMAPHORE(sem);
     310             :         return buffer->set_size(((size+1) * sizeof(T)));
     311             :     }
     312             : 
     313             :     // read len objects without advancing the read pointer
     314             :     uint32_t peek(T *data, uint32_t len) {
     315             :         WITH_SEMAPHORE(sem);
     316             :         return buffer->peekbytes((uint8_t*)data, len * sizeof(T)) / sizeof(T);
     317             :     }
     318             : 
     319             : 
     320             :     // Discards the buffer content, emptying it.
     321             :     // !!! Note this is a duplicate of ObjectBuffer with semaphore, update in both places !!!
     322             :     void clear(void)
     323             :     {
     324             :         WITH_SEMAPHORE(sem);
     325             :         buffer->clear();
     326             :     }
     327             : 
     328             :     // return number of objects available to be read from the front of the queue
     329             :     // !!! Note this is a duplicate of ObjectBuffer with semaphore, update in both places !!!
     330       39460 :     uint32_t available(void) {
     331       39460 :         WITH_SEMAPHORE(sem);
     332       39460 :         return buffer->available() / sizeof(T);
     333       39460 :     }
     334             : 
     335             :     // return number of objects that could be written to the back of the queue
     336             :     // !!! Note this is a duplicate of ObjectBuffer with semaphore, update in both places !!!
     337           6 :     uint32_t space(void) {
     338           6 :         WITH_SEMAPHORE(sem);
     339           6 :         return buffer->space() / sizeof(T);
     340           6 :     }
     341             : 
     342             :     // true is available() == 0
     343             :     // !!! Note this is a duplicate of ObjectBuffer with semaphore, update in both places !!!
     344         474 :     bool is_empty(void) WARN_IF_UNUSED {
     345         474 :         WITH_SEMAPHORE(sem);
     346         474 :         return buffer->is_empty();
     347         474 :     }
     348             : 
     349             :     // push one object onto the back of the queue
     350             :     // !!! Note this is a duplicate of ObjectBuffer with semaphore, update in both places !!!
     351       70811 :     bool push(const T &object) {
     352       70811 :         WITH_SEMAPHORE(sem);
     353       70811 :         if (buffer->space() < sizeof(T)) {
     354           3 :             return false;
     355             :         }
     356       70808 :         return buffer->write((uint8_t*)&object, sizeof(T)) == sizeof(T);
     357       70811 :     }
     358             : 
     359             :     // push N objects onto the back of the queue
     360             :     // !!! Note this is a duplicate of ObjectBuffer with semaphore, update in both places !!!
     361             :     bool push(const T *object, uint32_t n) {
     362             :         WITH_SEMAPHORE(sem);
     363             :         if (buffer->space() < n*sizeof(T)) {
     364             :             return false;
     365             :         }
     366             :         return buffer->write((uint8_t*)object, n*sizeof(T)) == n*sizeof(T);
     367             :     }
     368             : 
     369             :     /*
     370             :       throw away an object from the front of the queue
     371             :      */
     372             :     // !!! Note this is a duplicate of ObjectBuffer with semaphore, update in both places !!!
     373          18 :     bool pop(void) {
     374          18 :         WITH_SEMAPHORE(sem);
     375          18 :         return buffer->advance(sizeof(T));
     376          18 :     }
     377             : 
     378             :     /*
     379             :       pop earliest object off the front of the queue
     380             :      */
     381             :     // !!! Note this is a duplicate of ObjectBuffer with semaphore, update in both places !!!
     382   243617842 :     bool pop(T &object) WARN_IF_UNUSED {
     383   243617842 :         WITH_SEMAPHORE(sem);
     384   243617842 :         if (buffer->available() < sizeof(T)) {
     385   243547062 :             return false;
     386             :         }
     387       70780 :         return buffer->read((uint8_t*)&object, sizeof(T)) == sizeof(T);
     388   243617842 :     }
     389             : 
     390             :     /*
     391             :      * push_force() is semantically equivalent to:
     392             :      *   if (!push(t)) { pop(); push(t); }
     393             :      */
     394             :     // !!! Note this is a duplicate of ObjectBuffer with semaphore, update in both places !!!
     395          19 :     bool push_force(const T &object) {
     396          19 :         WITH_SEMAPHORE(sem);
     397          19 :         if (buffer->space() < sizeof(T)) {
     398           0 :             buffer->advance(sizeof(T));
     399             :         }
     400          19 :         return push(object);
     401          19 :     }
     402             : 
     403             :     /*
     404             :      * push_force() N objects
     405             :      */
     406             :     // !!! Note this is a duplicate of ObjectBuffer with semaphore, update in both places !!!
     407             :     bool push_force(const T *object, uint32_t n) {
     408             :         WITH_SEMAPHORE(sem);
     409             :         uint32_t _space = buffer->space();
     410             :         if (_space < sizeof(T)*n) {
     411             :             buffer->advance(sizeof(T)*(n-_space));
     412             :         }
     413             :         return push(object, n);
     414             :     }
     415             : 
     416             :     /*
     417             :       peek copies an object out from the front of the queue without advancing the read pointer
     418             :      */
     419             :     // !!! Note this is a duplicate of ObjectBuffer with semaphore, update in both places !!!
     420       73143 :     bool peek(T &object) WARN_IF_UNUSED {
     421       73143 :         WITH_SEMAPHORE(sem);
     422       73143 :         return buffer->peekbytes((uint8_t*)&object, sizeof(T)) == sizeof(T);
     423       73143 :     }
     424             : 
     425             :     /*
     426             :       return a pointer to first contiguous array of available
     427             :       objects. Return nullptr if none available
     428             :      */
     429             :     // !!! Note this is a duplicate of ObjectBuffer with semaphore, update in both places !!!
     430             :     const T *readptr(uint32_t &n) {
     431             :         WITH_SEMAPHORE(sem);
     432             :         uint32_t avail_bytes = 0;
     433             :         #pragma GCC diagnostic push
     434             :         #pragma GCC diagnostic ignored "-Wcast-align"
     435             :         const T *ret = (const T *)buffer->readptr(avail_bytes);
     436             :         #pragma GCC diagnostic pop
     437             :         if (!ret || avail_bytes < sizeof(T)) {
     438             :             return nullptr;
     439             :         }
     440             :         n = avail_bytes / sizeof(T);
     441             :         return ret;
     442             :     }
     443             : 
     444             :     // advance the read pointer (discarding objects)
     445             :     // !!! Note this is a duplicate of ObjectBuffer with semaphore, update in both places !!!
     446             :     bool advance(uint32_t n) {
     447             :         WITH_SEMAPHORE(sem);
     448             :         return buffer->advance(n * sizeof(T));
     449             :     }
     450             : 
     451             :     /* update the object at the front of the queue (the one that would
     452             :        be fetched by pop()) */
     453             :     // !!! Note this is a duplicate of ObjectBuffer with semaphore, update in both places !!!
     454             :     bool update(const T &object) {
     455             :         WITH_SEMAPHORE(sem);
     456             :         return buffer->update((uint8_t*)&object, sizeof(T));
     457             :     }
     458             : 
     459             : private:
     460             :     ByteBuffer *buffer = nullptr;
     461             :     HAL_Semaphore sem;
     462             : };
     463             : 
     464             : /*
     465             :   ring buffer class for objects of fixed size with pointer
     466             :   access. Note that this is not thread safe, buf offers efficient
     467             :   array-like access
     468             :  */
     469             : template <class T>
     470             : class ObjectArray {
     471             : public:
     472        6228 :     ObjectArray(uint16_t size_) {
     473        6228 :         _size = size_;
     474        6228 :         _head = _count = 0;
     475       17218 :         _buffer = NEW_NOTHROW T[_size];
     476        6228 :     }
     477         963 :     ~ObjectArray(void) {
     478         963 :         delete[] _buffer;
     479         963 :     }
     480             : 
     481             :     // return total number of objects
     482             :     uint16_t size(void) const {
     483             :         return _size;
     484             :     }
     485             : 
     486             :     // return number of objects available to be read
     487    37696100 :     uint16_t available(void) const {
     488    37696100 :         return _count;
     489             :     }
     490             : 
     491             :     // return number of objects that could be written
     492     1227925 :     uint16_t space(void) const {
     493     1227925 :         return _size - _count;
     494             :     }
     495             : 
     496             :     // true is available() == 0
     497    42728266 :     bool is_empty(void) const WARN_IF_UNUSED {
     498    42728266 :         return _count == 0;
     499             :     }
     500             : 
     501             :     // push one object
     502      623070 :     bool push(const T &object) {
     503      623070 :         if (space() == 0) {
     504           0 :             return false;
     505             :         }
     506      623070 :         _buffer[(_head+_count)%_size] = object;
     507      623070 :         _count++;
     508      623070 :         return true;
     509             :     }
     510             : 
     511             :     /*
     512             :       throw away an object
     513             :      */
     514      584760 :     bool pop(void) WARN_IF_UNUSED {
     515      584760 :         if (is_empty()) {
     516           0 :             return false;
     517             :         }
     518      584760 :         _head = (_head+1) % _size;
     519      584760 :         _count--;
     520      584760 :         return true;
     521             :     }
     522             : 
     523             :     // Discards the buffer content, emptying it.
     524           0 :     void clear(void)
     525             :     {
     526           0 :         _head = _count = 0;
     527           0 :     }
     528             : 
     529             :     /*
     530             :       pop earliest object off the queue
     531             :      */
     532           0 :     bool pop(T &object) WARN_IF_UNUSED {
     533           0 :         if (is_empty()) {
     534           0 :             return false;
     535             :         }
     536           0 :         object = _buffer[_head];
     537           0 :         return pop();
     538             :     }
     539             : 
     540             : 
     541             :     /*
     542             :      * push_force() is semantically equivalent to:
     543             :      *   if (!push(t)) { pop(); push(t); }
     544             :      */
     545      604855 :     bool push_force(const T &object) {
     546      604855 :         if (space() == 0) {
     547      475765 :             UNUSED_RESULT(pop());
     548             :         }
     549      604855 :         return push(object);
     550             :     }
     551             : 
     552             :     /*
     553             :       remove the Nth element from the array. First element is zero
     554             :      */
     555      123046 :     bool remove(uint16_t n) {
     556      123046 :         if (n >= _count) {
     557           0 :             return false;
     558             :         }
     559      123046 :         if (n == _count-1) {
     560             :             // remove last element
     561       31653 :             _count--;
     562       31653 :             return true;
     563             :         }
     564       91393 :         if (n == 0) {
     565             :             // remove first element
     566       90780 :             return pop();
     567             :         }
     568             :         // take advantage of the [] operator for simple shift of the array elements
     569        1300 :         for (uint16_t i=n; i<_count-1; i++) {
     570         687 :             *(*this)[i] = *(*this)[i+1];
     571             :         }
     572         613 :         _count--;
     573         613 :         return true;
     574             :     }
     575             : 
     576             :     // allow array indexing, based on current head. Returns a pointer
     577             :     // to the object or nullptr
     578    22565012 :     T * operator[](uint16_t i) {
     579    22565012 :         if (i >= _count) {
     580           0 :             return nullptr;
     581             :         }
     582    22565012 :         return &_buffer[(_head+i)%_size];
     583             :     }
     584             : 
     585             : private:
     586             :     T *_buffer;
     587             :     uint16_t _size;  // total buffer size
     588             :     uint16_t _count; // number in buffer now
     589             :     uint16_t _head;  // first element
     590             : };
     591             : 
     592             : typedef ObjectBuffer<float> FloatBuffer;
     593             : typedef ObjectBuffer_TS<float> FloatBuffer_TS;
     594             : typedef ObjectArray<float> FloatArray;

Generated by: LCOV version 1.14