aboutsummaryrefslogtreecommitdiff
path: root/fifo.h
blob: 0ed78433791ef572fa8999c555b1a837ede66aef (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
/*************************************************************
 *
 *    streaming external for PD
 *
 * File: fifo.h
 *
 * Description: Implementation of a FIFO template class
 *
 * Author: Thomas Grill (t.grill@gmx.net)
 *
 *************************************************************/

#ifndef _FIFO_H_
#define _FIFO_H_

#include <memory.h>

#include <assert.h>
#define ASSERT assert


/*! FIFO class
	\note not thread-safe
*/
template<class T>
class Fifo
{
public:
	Fifo(int n = 0):  size(n), arr(new T[n]),rd(0),wr(0),have(0) {}
	~Fifo()	{ if(arr) delete[] arr;	}

	//! Clear fifo
	void Clear() { rd = wr = have = 0; }

	//! Get total fifo size
	int Size() const { return size; }
	//! Get number of items in fifo
	int Have() const { return have; }
	//! Get free fifo size
	int Free() const { return size-have; }

	//! Get pointer to beginning of contained data
	T *ReadPtr() const { return arr+rd; }
	//! Get number of items from read pos to end of contiguous space
	int ReadSamples() const { return size-rd; }
	//! Get pointer to beginning of free space
	T *WritePtr() const { return arr+wr; }
	//! Get number of items from write pos to end of contiguous space
	int WriteSamples() const { return size-wr; }

	/*! Resize FIFO
		\param nsz	new FIFO size
		\param keep	keep data?
		\return true if all data could be kept
	*/
	bool Resize(int nsz,bool keep)
	{
		if(keep) {
			bool all = true;
			T *narr = new T[nsz];
			// try to keep newest data
			int s = Have()-nsz;
			if(s > 0) {
				// skip items that don't fit into new buffer
				all = false;
				int r = Read(s,NULL);
				ASSERT(r == s);
			}
			s = Have();
			int r = Read(s,narr);
			ASSERT(r == s);
			
			delete[] arr;
			arr = narr; size = nsz;
			Clear();
			return all;
		}
		else {
			delete[] arr;
			arr = new T[size = nsz];
			Clear();
			return true;
		}
	}

	/*! Write data to fifo 
		\param n	number of items to write
		\param buf	memory buffer containing items
		\return		number of written items
	*/
	int Write(int n,const T *buf)
	{
		if(n > Free()) n = Free();

		if(wr+n >= size) {
			// wrap-over
			int ch1 = size-wr;
			memcpy(arr+wr,buf,ch1*sizeof(T));
			wr = n-ch1;
			memcpy(arr,buf+ch1,wr*sizeof(T));
		}
		else {
			memcpy(arr+wr,buf,n*sizeof(T));
			wr += n;
		}

		have += n;
		return n;
	}

	/*! Read data from fifo 
		\param n	number of items to read
		\param buf	memory buffer to store items (NULL to simply skip items)
		\return		number of read items
	*/
	int Read(int n,T *buf)
	{
		if(n > Have()) n = Have();
		
		if(rd+n >= size) {
			// wrap-over
			int ch1 = size-rd;
			if(buf) memcpy(buf,arr+rd,ch1*sizeof(T));
			rd = n-ch1;
			if(buf) memcpy(buf+ch1,arr,rd*sizeof(T));
		}
		else {
			if(buf) memcpy(buf,arr+rd,n*sizeof(T));
			rd += n;
		}

		have -= n;
		return n;
	}

protected:
	int size;
	int rd,wr,have;
	mutable T *arr;
};

#endif