cirbuf.cpp
2.58 KB
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
143
#include "cirbuf.h"
#include <time.h>
#include <iostream>
#include <exception>
#include <stdexcept>
#include <cassert>
#include <cstring>
CirBuf::CirBuf(size_t size) :
size(size)
{
buf = (char*)malloc(size);
if (buf == NULL)
throw std::runtime_error("Malloc error constructing buffer.");
#ifndef NDEBUG
memset(buf, 0, size);
#endif
}
CirBuf::~CirBuf()
{
if (buf)
free(buf);
}
uint32_t CirBuf::usedBytes() const
{
int result = (head - tail) & (size-1);
return result;
}
uint32_t CirBuf::freeSpace() const
{
int result = (tail - (head + 1)) & (size-1);
return result;
}
uint32_t CirBuf::maxWriteSize() const
{
int end = size - 1 - head;
int n = (end + tail) & (size-1);
int result = n <= end ? n : end+1;
return result;
}
uint32_t CirBuf::maxReadSize() const
{
int end = size - tail;
int n = (head + end) & (size-1);
int result = n < end ? n : end;
return result;
}
char *CirBuf::headPtr()
{
return &buf[head];
}
char *CirBuf::tailPtr()
{
return &buf[tail];
}
void CirBuf::advanceHead(uint32_t n)
{
head = (head + n) & (size -1);
assert(tail != head); // Putting things in the buffer must never end on tail, because tail == head == empty.
}
void CirBuf::advanceTail(uint32_t n)
{
tail = (tail + n) & (size -1);
}
char CirBuf::peakAhead(uint32_t offset) const
{
int b = buf[(tail + offset) & (size - 1)];
return b;
}
void CirBuf::doubleSize()
{
uint newSize = size * 2;
char *newBuf = (char*)realloc(buf, newSize);
if (newBuf == NULL)
throw std::runtime_error("Malloc error doubling buffer size.");
uint maxRead = maxReadSize();
buf = newBuf;
if (head < tail)
{
std::memcpy(&buf[tail + maxRead], buf, head);
}
head = tail + usedBytes();
size = newSize;
#ifndef NDEBUG
std::cout << "New buf size: " << size << std::endl;
#endif
#ifdef TESTING
memset(&buf[head], 5, maxWriteSize() + 2);
#endif
resizedAt = time(NULL);
}
uint32_t CirBuf::getSize() const
{
return size;
}
time_t CirBuf::bufferLastResizedSecondsAgo() const
{
return time(NULL) - resizedAt;
}
void CirBuf::resetSize(size_t newSize)
{
assert(usedBytes() == 0);
if (this->size == newSize)
return;
char *newBuf = (char*)malloc(newSize);
if (newBuf == NULL)
throw std::runtime_error("Malloc error resizing buffer.");
free(buf);
buf = newBuf;
this->size = newSize;
head = 0;
tail = 0;
resizedAt = time(NULL);
#ifndef NDEBUG
std::cout << "Reset buf size: " << size << std::endl;
memset(buf, 0, newSize);
#endif
}