wanproxy/common/ring_buffer.h
2015-08-31 14:01:44 +02:00

151 lines
3.7 KiB
C++

////////////////////////////////////////////////////////////////////////////////
// //
// File: ring_buffer.h //
// Description: circular buffer for unlocked exchange of data //
// Project: WANProxy XTech //
// Author: Andreu Vidal Bramfeld-Software //
// Last modified: 2015-04-01 //
// //
////////////////////////////////////////////////////////////////////////////////
#ifndef COMMON_RING_BUFFER_H
#define COMMON_RING_BUFFER_H
#define STANDARD_RING_BUFFER_CAPACITY 32768
#define ITEM_SIZE ((int) sizeof (T))
template<typename T, int N = STANDARD_RING_BUFFER_CAPACITY> class RingBuffer
{
private:
unsigned char buffer[N * ITEM_SIZE];
unsigned char* reader;
unsigned char* writer;
public:
RingBuffer ();
int read (T& trg);
int write (const T& src);
bool is_empty () { return (reader == writer); }
int data_size () { return (writer >= reader ? writer - reader : sizeof buffer - (reader - writer)); }
};
template<typename T, int N> RingBuffer<T, N>::RingBuffer ()
{
reader = writer = buffer;
}
template<typename T, int N> int RingBuffer<T, N>::read (T& trg)
{
unsigned char* r;
unsigned char* w;
int s, t, n1, n2;
r = reader;
w = writer;
s = (w >= r ? (w - r) : sizeof buffer - (r - w));
if (s >= ITEM_SIZE)
{
t = buffer + sizeof buffer - r;
if (ITEM_SIZE <= t)
n1 = ITEM_SIZE, n2 = 0;
else
n1 = t, n2 = ITEM_SIZE - t;
memcpy (&trg, r, n1);
if (n2)
memcpy (((char*) &trg) + n1, buffer, n2);
reader = (ITEM_SIZE < t ? r + n1 : buffer + n2);
return ITEM_SIZE;
}
return 0;
}
template<typename T, int N> int RingBuffer<T, N>::write (const T& src)
{
unsigned char* r;
unsigned char* w;
int s, t, n1, n2;
r = reader;
w = writer;
s = (w >= r ? sizeof buffer - (w - r) : (r - w));
if (s > ITEM_SIZE)
{
t = buffer + sizeof buffer - w;
if (ITEM_SIZE <= t)
n1 = ITEM_SIZE, n2 = 0;
else
n1 = t, n2 = ITEM_SIZE - t;
memcpy (w, &src, n1);
if (n2)
memcpy (buffer, ((const char*) &src) + n1, n2);
writer = (ITEM_SIZE < t ? w + n1 : buffer + n2);
return ITEM_SIZE;
}
return 0;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include <pthread.h>
template<typename T> class WaitBuffer
{
private:
RingBuffer<T> ring;
pthread_mutex_t mutex;
pthread_cond_t ready;
public:
WaitBuffer ();
~WaitBuffer ();
int read (T& trg);
int write (const T& src);
void wakeup () { if (ring.is_empty ()) pthread_cond_signal (&ready); }
};
template<typename T> WaitBuffer<T>::WaitBuffer ()
{
pthread_mutex_init (&mutex, 0);
pthread_cond_init (&ready, 0);
}
template<typename T> WaitBuffer<T>::~WaitBuffer ()
{
pthread_mutex_destroy (&mutex);
pthread_cond_destroy (&ready);
}
template<typename T> int WaitBuffer<T>::read (T& trg)
{
if (ring.is_empty ())
{
pthread_mutex_lock (&mutex);
if (ring.is_empty ())
pthread_cond_wait (&ready, &mutex);
pthread_mutex_unlock (&mutex);
}
return ring.read (trg);
}
template<typename T> int WaitBuffer<T>::write (const T& src)
{
int rsl = ring.write (src);
if (rsl && ring.data_size () == ITEM_SIZE)
{
pthread_mutex_lock (&mutex);
pthread_cond_signal (&ready);
pthread_mutex_unlock (&mutex);
}
return rsl;
}
#endif /* !COMMON_RING_BUFFER_H */