-
Notifications
You must be signed in to change notification settings - Fork 22
/
Buffer.cpp
98 lines (86 loc) · 2.39 KB
/
Buffer.cpp
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
// must be first include because of Python stuff, see musicplayer.h comment
#include "PyThreading.hpp" // mlock
#include <algorithm>
#include "Buffer.hpp"
Buffer::Chunk::Chunk() : start(0), end(0) { mlock(this, sizeof(*this)); }
Buffer::Buffer() : _size(0) { mlock(this, sizeof(*this)); }
void Buffer::resize_smaller(size_t newSize) {
assert(newSize <= _size);
_size = newSize;
for(auto chunkPtr = chunks.back(); chunkPtr && chunkPtr->isData() && newSize > 0; ) {
Chunk& chunk = chunkPtr->value;
if(newSize >= chunk.size()) {
newSize -= chunk.size();
auto prevChunkPtr = chunkPtr->getPrev();
chunkPtr->popOut();
chunkPtr = prevChunkPtr;
continue;
}
chunk.end -= newSize;
assert(chunk.start <= chunk.end);
newSize = 0;
break;
}
assert(newSize == 0);
}
size_t Buffer::pop(uint8_t* target, size_t target_size, bool doCleanup) {
size_t c = 0;
for(Chunk& chunk : chunks) {
Chunk::Idx chunkEnd = chunk.end;
if(chunk.start == 0 && chunkEnd == 0) {
// push() but not yet any data added
break;
}
int s = chunkEnd - chunk.start;
if(s == 0) continue;
if((size_t)s > target_size) s = (int)target_size;
memcpy(target, chunk.data + chunk.start, s);
chunk.start += s;
_size -= s;
target += s;
target_size -= s;
c += s;
if(chunk.start < chunkEnd) {
assert(target_size == 0);
break;
}
if(chunkEnd < Chunk::BufferSize()) {
// push() would have filled it further
break;
}
assert(chunk.start == chunkEnd);
assert(chunkEnd == Chunk::BufferSize());
// This can be heavy (the `free`ing), so we might want to do it elsewhere.
if(doCleanup)
chunks.pop_front();
}
return c;
}
void Buffer::push(const uint8_t* data, size_t size) {
while(size > 0) {
auto chunkBackPtr = chunks.back();
if(!chunkBackPtr) // it means chunks is empty
chunks.push_back();
else if(!chunkBackPtr->value.freeDataAvailable())
chunks.push_back();
auto chunkPtr = chunks.back();
assert(chunkPtr && chunkPtr->isData(false));
Chunk& chunk = chunkPtr->value;
size_t s = std::min(size, (size_t)chunk.freeDataAvailable());
assert(s > 0);
memcpy(chunk.data + chunk.end, data, s);
data += s;
size -= s;
chunk.end += s;
_size += s;
}
}
void Buffer::cleanup() {
while(!chunks.empty()) {
auto chunkPtr = chunks.front();
Chunk& chunk = chunkPtr->value;
if(chunk.end < Chunk::BufferSize()) break;
if(chunk.size() > 0) break;
chunks.pop_front();
}
}