tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

ring_buffer.c (6617B)


      1 /*
      2 *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
      3 *
      4 *  Use of this source code is governed by a BSD-style license
      5 *  that can be found in the LICENSE file in the root of the source
      6 *  tree. An additional intellectual property rights grant can be found
      7 *  in the file PATENTS.  All contributing project authors may
      8 *  be found in the AUTHORS file in the root of the source tree.
      9 */
     10 
     11 // A ring buffer to hold arbitrary data. Provides no thread safety. Unless
     12 // otherwise specified, functions return 0 on success and -1 on error.
     13 
     14 #include "common_audio/ring_buffer.h"
     15 
     16 #include <stddef.h>  // size_t
     17 #include <stdlib.h>
     18 #include <string.h>
     19 
     20 // Get address of region(s) from which we can read data.
     21 // If the region is contiguous, `data_ptr_bytes_2` will be zero.
     22 // If non-contiguous, `data_ptr_bytes_2` will be the size in bytes of the second
     23 // region. Returns room available to be read or `element_count`, whichever is
     24 // smaller.
     25 static size_t GetBufferReadRegions(RingBuffer* buf,
     26                                   size_t element_count,
     27                                   void** data_ptr_1,
     28                                   size_t* data_ptr_bytes_1,
     29                                   void** data_ptr_2,
     30                                   size_t* data_ptr_bytes_2) {
     31  const size_t readable_elements = WebRtc_available_read(buf);
     32  const size_t read_elements =
     33      (readable_elements < element_count ? readable_elements : element_count);
     34  const size_t margin = buf->element_count - buf->read_pos;
     35 
     36  // Check to see if read is not contiguous.
     37  if (read_elements > margin) {
     38    // Write data in two blocks that wrap the buffer.
     39    *data_ptr_1 = buf->data + buf->read_pos * buf->element_size;
     40    *data_ptr_bytes_1 = margin * buf->element_size;
     41    *data_ptr_2 = buf->data;
     42    *data_ptr_bytes_2 = (read_elements - margin) * buf->element_size;
     43  } else {
     44    *data_ptr_1 = buf->data + buf->read_pos * buf->element_size;
     45    *data_ptr_bytes_1 = read_elements * buf->element_size;
     46    *data_ptr_2 = NULL;
     47    *data_ptr_bytes_2 = 0;
     48  }
     49 
     50  return read_elements;
     51 }
     52 
     53 RingBuffer* WebRtc_CreateBuffer(size_t element_count, size_t element_size) {
     54  RingBuffer* self = NULL;
     55  if (element_count == 0 || element_size == 0) {
     56    return NULL;
     57  }
     58 
     59  self = malloc(sizeof(RingBuffer));
     60  if (!self) {
     61    return NULL;
     62  }
     63 
     64  self->data = malloc(element_count * element_size);
     65  if (!self->data) {
     66    free(self);
     67    self = NULL;
     68    return NULL;
     69  }
     70 
     71  self->element_count = element_count;
     72  self->element_size = element_size;
     73  WebRtc_InitBuffer(self);
     74 
     75  return self;
     76 }
     77 
     78 void WebRtc_InitBuffer(RingBuffer* self) {
     79  self->read_pos = 0;
     80  self->write_pos = 0;
     81  self->rw_wrap = SAME_WRAP;
     82 
     83  // Initialize buffer to zeros
     84  memset(self->data, 0, self->element_count * self->element_size);
     85 }
     86 
     87 void WebRtc_FreeBuffer(void* handle) {
     88  RingBuffer* self = (RingBuffer*)handle;
     89  if (!self) {
     90    return;
     91  }
     92 
     93  free(self->data);
     94  free(self);
     95 }
     96 
     97 size_t WebRtc_ReadBuffer(RingBuffer* self,
     98                         void** data_ptr,
     99                         void* data,
    100                         size_t element_count) {
    101  if (self == NULL) {
    102    return 0;
    103  }
    104  if (data == NULL) {
    105    return 0;
    106  }
    107 
    108  {
    109    void* buf_ptr_1 = NULL;
    110    void* buf_ptr_2 = NULL;
    111    size_t buf_ptr_bytes_1 = 0;
    112    size_t buf_ptr_bytes_2 = 0;
    113    const size_t read_count =
    114        GetBufferReadRegions(self, element_count, &buf_ptr_1, &buf_ptr_bytes_1,
    115                             &buf_ptr_2, &buf_ptr_bytes_2);
    116    if (buf_ptr_bytes_2 > 0) {
    117      // We have a wrap around when reading the buffer. Copy the buffer data to
    118      // `data` and point to it.
    119      memcpy(data, buf_ptr_1, buf_ptr_bytes_1);
    120      memcpy(((char*)data) + buf_ptr_bytes_1, buf_ptr_2, buf_ptr_bytes_2);
    121      buf_ptr_1 = data;
    122    } else if (!data_ptr) {
    123      // No wrap, but a memcpy was requested.
    124      memcpy(data, buf_ptr_1, buf_ptr_bytes_1);
    125    }
    126    if (data_ptr) {
    127      // `buf_ptr_1` == `data` in the case of a wrap.
    128      *data_ptr = read_count == 0 ? NULL : buf_ptr_1;
    129    }
    130 
    131    // Update read position
    132    WebRtc_MoveReadPtr(self, (int)read_count);
    133 
    134    return read_count;
    135  }
    136 }
    137 
    138 size_t WebRtc_WriteBuffer(RingBuffer* self,
    139                          const void* data,
    140                          size_t element_count) {
    141  if (!self) {
    142    return 0;
    143  }
    144  if (!data) {
    145    return 0;
    146  }
    147 
    148  {
    149    const size_t free_elements = WebRtc_available_write(self);
    150    const size_t write_elements =
    151        (free_elements < element_count ? free_elements : element_count);
    152    size_t n = write_elements;
    153    const size_t margin = self->element_count - self->write_pos;
    154 
    155    if (write_elements > margin) {
    156      // Buffer wrap around when writing.
    157      memcpy(self->data + self->write_pos * self->element_size, data,
    158             margin * self->element_size);
    159      self->write_pos = 0;
    160      n -= margin;
    161      self->rw_wrap = DIFF_WRAP;
    162    }
    163    memcpy(self->data + self->write_pos * self->element_size,
    164           ((const char*)data) + ((write_elements - n) * self->element_size),
    165           n * self->element_size);
    166    self->write_pos += n;
    167 
    168    return write_elements;
    169  }
    170 }
    171 
    172 int WebRtc_MoveReadPtr(RingBuffer* self, int element_count) {
    173  if (!self) {
    174    return 0;
    175  }
    176 
    177  {
    178    // We need to be able to take care of negative changes, hence use "int"
    179    // instead of "size_t".
    180    const int free_elements = (int)WebRtc_available_write(self);
    181    const int readable_elements = (int)WebRtc_available_read(self);
    182    int read_pos = (int)self->read_pos;
    183 
    184    if (element_count > readable_elements) {
    185      element_count = readable_elements;
    186    }
    187    if (element_count < -free_elements) {
    188      element_count = -free_elements;
    189    }
    190 
    191    read_pos += element_count;
    192    if (read_pos > (int)self->element_count) {
    193      // Buffer wrap around. Restart read position and wrap indicator.
    194      read_pos -= (int)self->element_count;
    195      self->rw_wrap = SAME_WRAP;
    196    }
    197    if (read_pos < 0) {
    198      // Buffer wrap around. Restart read position and wrap indicator.
    199      read_pos += (int)self->element_count;
    200      self->rw_wrap = DIFF_WRAP;
    201    }
    202 
    203    self->read_pos = (size_t)read_pos;
    204 
    205    return element_count;
    206  }
    207 }
    208 
    209 size_t WebRtc_available_read(const RingBuffer* self) {
    210  if (!self) {
    211    return 0;
    212  }
    213 
    214  if (self->rw_wrap == SAME_WRAP) {
    215    return self->write_pos - self->read_pos;
    216  } else {
    217    return self->element_count - self->read_pos + self->write_pos;
    218  }
    219 }
    220 
    221 size_t WebRtc_available_write(const RingBuffer* self) {
    222  if (!self) {
    223    return 0;
    224  }
    225 
    226  return self->element_count - WebRtc_available_read(self);
    227 }