-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathbuffer.cpp
226 lines (206 loc) · 4.48 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
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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
// CEZEO software Ltd. https://www.cezeo.com
#include "buffer.h"
namespace
{
char noMemory[] = "can't allocate memory";
char zeroBuffer[] = "zero size buffer";
char resizeForKeeper[] = "can't resize non owning buffer";
char invalidRange[] = "access invalid range";
} // namespace
buffer::buffer(const size_t size)
{
allocate_copy(size);
// zero sized buffer is not an error
}
buffer::buffer(const uint8_t* ptr, const size_t size, const TYPE type)
{
set(ptr, size, type);
}
buffer::buffer(const buffer& src)
{
if (KEEPER == src.buffer_type)
{
// just copy ptr, size and type
// doesn't hold memory
buffer_ptr = src.buffer_ptr;
buffer_size = src.buffer_size;
}
else
{
// so we should allocate and copy the memory if the source hold it
// allocate new memory if source is holder also copy from buffer
allocate_copy(src.buffer_size, src.buffer_ptr);
}
buffer_type = src.buffer_type;
}
buffer::buffer(buffer&& src) noexcept : buffer()
{
swap(*this, src);
}
buffer::~buffer()
{
destroy();
}
void buffer::allocate_copy(const size_t size, const uint8_t* copy_from_ptr)
{
if (size > 0)
{
uint8_t* new_buffer_ptr = (uint8_t*)malloc(size);
if (nullptr != new_buffer_ptr)
{
// now we can destroy old buffer
destroy();
// assign new buffer to current
buffer_ptr = new_buffer_ptr;
buffer_size = size;
// now we're holder
buffer_type = HOLDER;
if (copy_from_ptr != nullptr)
{
memcpy(buffer_ptr, copy_from_ptr, size);
}
}
else
{
throw std::runtime_error(noMemory);
}
}
else
{
// zero size allocate effectively just destroying the old data if any
destroy();
}
}
void buffer::destroy() noexcept
{
if (KEEPER != buffer_type && nullptr != buffer_ptr)
{
free(buffer_ptr);
}
buffer_ptr = nullptr;
buffer_size = 0;
}
// KEEPER - memory viewer (does not own nor manage memory)
// HOLDER - allocate new memory for data and copy it to this memory
void buffer::set(const uint8_t* ptr, const size_t size, TYPE type)
{
if (HOLDER == type)
{
// allocate new memory if source is holder also copy from buffer
// allocate will destroy old data
allocate_copy(size, ptr);
}
else
{
// KEEPER
destroy();
// keeper just use supplied ptr and size
buffer_ptr = const_cast<uint8_t*>(ptr); // workaround for keeper unmodified buffer
buffer_size = size;
}
buffer_type = type;
}
void buffer::resize(const size_t new_size, bool copy)
{
// allow resize of empty KEEPER
if (KEEPER == buffer_type && !empty())
{
throw std::logic_error(resizeForKeeper);
}
else
{
if (new_size > 0)
{
uint8_t* new_buffer_ptr = (uint8_t*)malloc(new_size);
if (nullptr != new_buffer_ptr)
{
// copy old data to new buffer
if (copy && size() > 0)
{
size_t to_copy = size();
if (size() > new_size)
{
to_copy = new_size;
// copy old data
memcpy(new_buffer_ptr, data(), to_copy);
}
}
// destroy old buffer
destroy();
// assign new buffer to current
buffer_ptr = new_buffer_ptr;
buffer_size = new_size;
// important to set the holder, because we can be here from empty KEEPER(default constructed buffer)
buffer_type = HOLDER;
}
else
{
throw std::runtime_error(noMemory);
}
}
else
{
// just destroy buffer
destroy();
}
}
}
buffer& buffer::operator=(const buffer& src)
{
if (&src != this)
{
buffer temporary(src);
swap(*this, temporary);
}
return *this;
}
uint8_t& buffer::operator[](std::size_t idx)
{
if (idx < size())
{
return buffer_ptr[ idx ];
}
else
{
throw std::out_of_range(invalidRange);
}
}
const uint8_t& buffer::operator[](std::size_t idx) const
{
if (idx < size())
{
return buffer_ptr[ idx ];
}
else
{
throw std::out_of_range(invalidRange);
}
}
uint8_t* buffer::data() const noexcept
{
return buffer_ptr;
}
size_t buffer::size() const noexcept
{
return buffer_size;
}
void buffer::clear() noexcept
{
destroy();
}
bool buffer::empty() const noexcept
{
return nullptr == buffer_ptr || 0 == buffer_size;
}
buffer::TYPE buffer::type() const noexcept
{
return buffer_type;
}
ptr_iterator<uint8_t> buffer::begin() const
{
return ptr_iterator<uint8_t>(data());
}
ptr_iterator<uint8_t> buffer::end() const
{
return ptr_iterator<uint8_t>(data() + size());
}