Grok 20.3.2
buffer.h
Go to the documentation of this file.
1/*
2 * Copyright (C) 2016-2026 Grok Image Compression Inc.
3 *
4 * This source code is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU Affero General Public License, version 3,
6 * as published by the Free Software Foundation.
7 *
8 * This source code is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Affero General Public License for more details.
12 *
13 * You should have received a copy of the GNU Affero General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 */
17
18#pragma once
19
20#include "geometry.h"
21#include "MemManager.h"
22#include "lanes.h"
23
24namespace grk
25{
26
27template<typename T>
29{
30 T* alloc(size_t elements)
31 {
32 return new T[elements];
33 }
34 void dealloc(T* buf)
35 {
36 delete[] buf;
37 }
38};
39template<typename T>
41{
42 T* alloc(size_t elements)
43 {
44 return (T*)grk_aligned_malloc(elements * sizeof(T));
45 }
46 void dealloc(T* buf)
47 {
49 }
50};
51template<typename T, template<typename TT> typename A>
52struct Buffer : A<T>
53{
54 Buffer(T* buffer, size_t off, size_t length, bool ownsData)
55 : buf_(buffer), offset_(off), num_elts_(length), owns_data_(ownsData)
56 {}
57 Buffer(T* buffer, size_t length) : Buffer(buffer, 0, length, false) {}
58 Buffer() : Buffer(0, 0, 0, false) {}
59 Buffer(T* buffer, size_t length, bool ownsData) : Buffer(buffer, 0, length, ownsData) {}
60 virtual ~Buffer()
61 {
62 // destructor simply deallocates memory
63 if(owns_data_)
65 }
66 explicit Buffer(const Buffer& rhs)
67 {
68 this->operator=(rhs);
69 }
70 Buffer& operator=(const Buffer& rhs) // copy assignment
71 {
72 return operator=(&rhs);
73 }
74 Buffer& operator=(const Buffer* rhs) // copy assignment
75 {
76 if(this != rhs)
77 { // self-assignment check expected
78 buf_ = rhs->buf_;
79 offset_ = rhs->offset();
80 num_elts_ = rhs->num_elts();
81 owns_data_ = false;
82 }
83 return *this;
84 }
85 inline bool canRead(void)
86 {
87 return offset_ < num_elts_;
88 }
89 inline T read(void)
90 {
91 return buf_[offset_++];
92 }
93 inline bool write(T val)
94 {
95 if(offset_ == num_elts_)
96 return false;
97 buf_[offset_++] = val;
98
99 return true;
100 }
101 inline bool write(T* b, size_t size)
102 {
103 if(offset_ + size > num_elts_)
104 return false;
105 memcpy(buf_ + offset_, b, size);
106 offset_ += size;
107
108 return true;
109 }
110 virtual bool alloc(size_t length)
111 {
112 if(buf_ && num_elts_ > length)
113 return true;
114 dealloc();
115 buf_ = A<T>::alloc(length);
116 if(!buf_)
117 return false;
118 num_elts_ = length;
119 offset_ = 0;
120 owns_data_ = true;
121
122 return true;
123 }
124 virtual void dealloc()
125 {
126 if(owns_data_)
127 A<T>::dealloc(buf_);
128 buf_ = nullptr;
129 owns_data_ = false;
130 offset_ = 0;
131 num_elts_ = 0;
132 }
133 // set buf to buf without owning it
134 void attach(T* buffer)
135 {
137 buf_ = buffer;
138 }
139 // transfer buf to buffer, and cease owning it
140 void transfer(T** buffer)
141 {
142 if(buffer)
143 {
144 assert(!buf_ || owns_data_);
145 *buffer = buf_;
146 buf_ = nullptr;
147 owns_data_ = false;
148 num_elts_ = 0;
149 offset_ = 0;
150 }
151 }
152 size_t remainingLength(void) const
153 {
154 return num_elts_ - offset_;
155 }
156 bool increment_offset(std::ptrdiff_t off)
157 {
158 /* we allow the offset to move to one location beyond end of buffer segment*/
159 if(off > 0)
160 {
161 if(offset_ > (size_t)(SIZE_MAX - (size_t)off))
162 {
163 grklog.warn("Buffer8: overflow");
165 }
166 else if(offset_ + (size_t)off > num_elts_)
167 {
168#ifdef DEBUG_SEG_BUF
169 grklog.warn("Buffer8: attempt to increment buffer offset out of bounds");
170#endif
172 return false;
173 }
174 else
175 {
176 offset_ = offset_ + (size_t)off;
177 }
178 }
179 else if(off < 0)
180 {
181 if(offset_ < (size_t)(-off))
182 {
183 grklog.warn("Buffer8: underflow");
184 offset_ = 0;
185 return false;
186 }
187 else
188 {
189 offset_ = (size_t)((std::ptrdiff_t)offset_ + off);
190 }
191 }
192
193 return true;
194 }
195 T* currPtr(void) const
196 {
197 if(!buf_)
198 return nullptr;
199 return buf_ + offset_;
200 }
201 T* currPtr([[maybe_unused]] size_t required_length) const
202 {
203 return currPtr();
204 }
206 {
207 return owns_data_;
208 }
209 void set_owns_data(bool owns)
210 {
211 owns_data_ = owns;
212 }
213 size_t num_elts() const
214 {
215 return num_elts_;
216 }
217 size_t* num_elts_ptr()
218 {
219 return &num_elts_;
220 }
221 void set_num_elts(size_t elts)
222 {
223 assert(!owns_data_ || elts <= num_elts_);
224 num_elts_ = elts;
225 }
226
227 size_t offset() const
228 {
229 return offset_;
230 }
231 void set_offset(size_t off)
232 {
233 offset_ = off;
234 }
235 T* buf() const
236 {
237 return buf_;
238 }
240 {
241 return &buf_;
242 }
243 void set_buf(T* buf, size_t elts)
244 {
245 assert(!buf_);
246 buf_ = buf;
247 num_elts_ = elts;
248 }
249
250protected:
251 T* buf_; /* internal array*/
252 size_t offset_; /* current offset into array */
253 size_t num_elts_; /* number of elements in array */
254 bool owns_data_; /* true if buffer manages the buf array */
255};
256
259
260template<typename T>
262{
263 Buffer2dSimple() : Buffer2dSimple(nullptr, 0, 0) {}
264 Buffer2dSimple(T* buf, uint32_t stride, uint32_t height)
265 : buf_(buf), stride_(stride), height_(height)
266 {
267 assert(buf || !stride);
268 }
270 {
271 buf_ += deltaX;
272
273 return *this;
274 }
276 {
277 buf_ += deltaY * stride_;
278
279 return *this;
280 }
282 uint32_t stride_;
283 uint32_t height_;
284};
285
286template<typename T, template<typename TT> typename A>
287struct Buffer2d : protected Buffer<T, A>, public Rect32
288{
289 Buffer2d(T* buffer, bool ownsData, uint32_t w, uint32_t strd, uint32_t h)
290 : Buffer<T, A>(buffer, ownsData), Rect32(0, 0, w, h), stride(strd)
291 {
292 assert(buffer || !strd);
293 }
294 Buffer2d(uint32_t w, uint32_t h) : Buffer2d(nullptr, false, w, 0, h) {}
295 explicit Buffer2d(const Rect32* b)
296 : Buffer<T, A>(nullptr, false), Rect32(b->x0, b->y0, b->x1, b->y1), stride(0)
297 {}
298 explicit Buffer2d(const Rect32& b)
299 : Buffer<T, A>(nullptr, false), Rect32(b.x0, b.y0, b.x1, b.y1), stride(0)
300 {}
301 Buffer2d(const Rect32& b, [[maybe_unused]] bool useOrigin)
302 : Buffer<T, A>(nullptr, false), Rect32(b), stride(0)
303 {}
304 Buffer2d(void) : Buffer2d(nullptr, 0, 0, 0, false) {}
305 explicit Buffer2d(const Buffer2d& rhs)
306 : Buffer<T, A>(nullptr, 0, 0, false), Rect32(rhs), stride(rhs.stride)
307 {
308 if(rhs.buf_)
309 {
310 // Calculate the required buffer size based on stride and height
311 uint64_t eltsNeeded = (uint64_t)rhs.stride * rhs.height();
312
313 // Allocate memory using the allocator
314 if(!Buffer<T, A>::alloc(eltsNeeded))
315 {
316 throw std::runtime_error("Failed to allocate memory for Buffer2d copy constructor.");
317 }
318
319 // Copy data from the source buffer
320 const T* srcPtr = rhs.buf_;
321 T* dstPtr = this->buf_;
322 for(uint32_t j = 0; j < rhs.height(); ++j)
323 {
324 memcpy(dstPtr, srcPtr, rhs.width() * sizeof(T));
325 srcPtr += rhs.stride; // Move source pointer to the next row
326 dstPtr += rhs.stride; // Move destination pointer to the next row
327 }
328
329 this->set_owns_data(true); // This buffer owns the allocated data
330 }
331 else
332 {
333 // Handle case when rhs.buf is null
334 this->stride = 0;
335 this->buf_ = nullptr;
336 this->set_owns_data(false);
337 }
338 }
339
346 Buffer2d(Buffer2d& rhs, bool transferBuffer) : Buffer<T, A>(nullptr, 0, 0, false), Rect32(rhs)
347 {
348 if(transferBuffer && rhs.buf_)
349 {
350 rhs.transfer(&this->buf_, &this->stride);
351 }
352 else
353 {
354 throw std::invalid_argument(
355 "Buffer transfer failed: Source buffer is empty or transfer not requested.");
356 }
357 }
358
360 {
361 return Buffer2dSimple<T>(this->buf_, this->stride, this->height());
362 }
364 {
365 return Buffer2dSimple<float>((float*)this->buf_, this->stride, this->height());
366 }
367 Buffer2d& operator=(const Buffer2d& rhs) // copy assignment
368 {
369 return operator=(&rhs);
370 }
371 Buffer2d& operator=(const Buffer2d* rhs) // copy assignment
372 {
373 if(this != rhs)
374 { // self-assignment check expected
377 if(rhs->buf_)
378 stride = rhs->stride;
379 }
380 return *this;
381 }
382 virtual ~Buffer2d() override = default;
383 size_t length(void)
384 {
385 return this->num_elts();
386 }
387 bool alloc2d(uint32_t w, uint32_t str, uint32_t h, bool clear)
388 {
389 setRect(Rect32(0, 0, w, h));
390 stride = str;
391 bool rc = alloc2d(clear);
392 if(rc)
393 stride = str;
394
395 return rc;
396 }
397 void clear(void)
398 {
399 uint64_t bytesNeeded = (uint64_t)stride * height() * sizeof(T);
400 memset(this->buf_, 0, bytesNeeded);
401 }
402 uint32_t alignedBufferWidth(uint32_t width)
403 {
404 static uint32_t align = grok::NumLanes();
405 return (uint32_t)((((uint64_t)width + align - 1) / align) * align);
406 }
407 bool alloc2d(bool clear)
408 {
409 if(!height() || !width())
410 return true;
411 uint32_t newStride = stride ? stride : alignedBufferWidth(width());
412 uint64_t eltsNeeded = (uint64_t)newStride * height();
413 // avoid reallocation
414 if(!eltsNeeded || eltsNeeded <= this->num_elts())
415 return true;
416
417 if(!Buffer<T, A>::alloc(eltsNeeded))
418 {
419 grk::grklog.error("Failed to allocate aligned memory buffer of dimensions %u x %u", newStride,
420 height());
421 return false;
422 }
423 stride = newStride;
424 if(clear)
425 this->clear();
426
427 return true;
428 }
429 void dealloc() override
430 {
432 stride = 0;
433 }
434 // set buf to buffer without owning it
435 void attach(T* buffer, uint32_t strd)
436 {
437 Buffer<T, A>::attach(buffer);
438 if(buffer)
439 stride = strd;
440 }
441 void attach(Buffer2d& rhs, uint32_t x, uint32_t y)
442 {
443 attach(&rhs, x, y);
444 }
445 void attach(Buffer2d& rhs)
446 {
447 attach(&rhs, 0, 0);
448 }
449 void attach(Buffer2d* rhs, uint32_t x, uint32_t y)
450 {
451 if(!rhs)
452 return;
454 this->buf_ = rhs->address(x, y);
455 this->num_elts_ = rhs->num_elts();
456 this->owns_data_ = false;
457 if(this->buf_)
458 stride = rhs->stride;
459 }
460 void attach(Buffer2d* rhs)
461 {
462 attach(rhs, 0, 0);
463 }
464 // transfer buf to buffer, and cease owning it
465 void transfer(T** buffer, uint32_t* strd)
466 {
467 if(buffer)
468 {
470 *strd = stride;
471 stride = 0;
472 }
473 }
474
475 // rhs coordinates are in "this" coordinate system
476 template<typename F>
477 void copyFrom(const Buffer2d& src, F filter)
478 {
479 return copyFrom(&src, filter);
480 }
481 // rhs coordinates are in "this" coordinate system
482 template<typename F>
483 void copyFrom(const Buffer2d* src, F filter)
484 {
485 auto inter = intersection(src);
486 if(inter.empty())
487 return;
488
489 if(!src->buf_)
490 return;
491
492 T* ptr = this->buf_ + (inter.y0 * stride + inter.x0);
493 T* srcPtr = src->buf_ + ((inter.y0 - src->y0) * src->stride + inter.x0 - src->x0);
494 uint32_t len = inter.width();
495 for(uint32_t j = inter.y0; j < inter.y1; ++j)
496 {
497 filter.copy(ptr, srcPtr, len);
498 ptr += stride;
499 srcPtr += src->stride;
500 }
501 }
502 // Cross-type copy from a wider source type (e.g., int32_t → int16_t narrowing)
503 template<typename SrcT, template<class> class SrcA, typename F>
504 void copyFromNarrow(const Buffer2d<SrcT, SrcA>* src, F filter)
505 {
506 auto inter = intersection(src);
507 if(inter.empty())
508 return;
509
510 auto srcSimple = src->simple();
511 if(!srcSimple.buf_)
512 return;
513
514 T* ptr = this->buf_ + (inter.y0 * stride + inter.x0);
515 SrcT* srcPtr = srcSimple.buf_ + ((inter.y0 - src->y0) * srcSimple.stride_ + inter.x0 - src->x0);
516 uint32_t len = inter.width();
517 for(uint32_t j = inter.y0; j < inter.y1; ++j)
518 {
519 filter.copy(ptr, srcPtr, len);
520 ptr += stride;
521 srcPtr += srcSimple.stride_;
522 }
523 }
525 {
526 void copy(T* dst, const T* src, uint32_t len)
527 {
528 memcpy(dst, src, len);
529 }
530 };
531 void copyFrom(const Buffer2d& src)
532 {
533 copy(src, memcpy_from());
534 }
535 T* getBuffer(void) const
536 {
537 return this->currPtr();
538 }
539 T* address(uint32_t x, uint32_t y)
540 {
541 return this->currPtr() + (uint64_t)x + (uint64_t)y * stride;
542 }
543 uint32_t getStride()
544 {
545 assert(this->buf() || !stride);
546 return stride;
547 }
548
549protected:
550 uint32_t stride;
551};
552
554
555} // namespace grk
#define SIZE_MAX
Definition MemManager.h:37
ResWindow.
Definition CompressedChunkCache.h:36
void * grk_aligned_malloc(size_t bytes)
Definition MemManager.h:308
Buffer< uint8_t, AllocatorAligned > BufferAligned8
Definition buffer.h:258
ILogger & grklog
Definition Logger.cpp:24
Rect< uint32_t > Rect32
Definition geometry.h:64
Buffer2d< int32_t, AllocatorAligned > Buffer2dAligned32
Definition buffer.h:553
Buffer< uint8_t, AllocatorVanilla > Buffer8
Definition buffer.h:257
void grk_aligned_free(void *ptr)
Definition MemManager.h:324
uint32_t NumLanes(void)
Definition buffer.h:41
void dealloc(T *buf)
Definition buffer.h:46
T * alloc(size_t elements)
Definition buffer.h:42
Definition buffer.h:29
T * alloc(size_t elements)
Definition buffer.h:30
void dealloc(T *buf)
Definition buffer.h:34
Definition buffer.h:525
void copy(T *dst, const T *src, uint32_t len)
Definition buffer.h:526
Definition buffer.h:288
void attach(T *buffer, uint32_t strd)
Definition buffer.h:435
Buffer2d(const Rect32 &b)
Definition buffer.h:298
void copyFrom(const Buffer2d &src, F filter)
Definition buffer.h:477
void copyFromNarrow(const Buffer2d< SrcT, SrcA > *src, F filter)
Definition buffer.h:504
uint32_t getStride()
Definition buffer.h:543
Buffer2d(const Rect32 &b, bool useOrigin)
Definition buffer.h:301
Buffer2d(const Rect32 *b)
Definition buffer.h:295
Buffer2d(uint32_t w, uint32_t h)
Definition buffer.h:294
bool alloc2d(uint32_t w, uint32_t str, uint32_t h, bool clear)
Definition buffer.h:387
void attach(Buffer2d *rhs, uint32_t x, uint32_t y)
Definition buffer.h:449
size_t length(void)
Definition buffer.h:383
void dealloc() override
Definition buffer.h:429
Buffer2dSimple< float > simpleF(void) const
Definition buffer.h:363
void attach(Buffer2d &rhs, uint32_t x, uint32_t y)
Definition buffer.h:441
uint32_t alignedBufferWidth(uint32_t width)
Definition buffer.h:402
bool alloc2d(bool clear)
Definition buffer.h:407
Buffer2d(const Buffer2d &rhs)
Definition buffer.h:305
Buffer2d(T *buffer, bool ownsData, uint32_t w, uint32_t strd, uint32_t h)
Definition buffer.h:289
uint32_t stride
Definition buffer.h:550
Buffer2d(void)
Definition buffer.h:304
virtual ~Buffer2d() override=default
T * address(uint32_t x, uint32_t y)
Definition buffer.h:539
T * getBuffer(void) const
Definition buffer.h:535
void attach(Buffer2d *rhs)
Definition buffer.h:460
void transfer(T **buffer, uint32_t *strd)
Definition buffer.h:465
Buffer2dSimple< T > simple(void) const
Definition buffer.h:359
Buffer2d(Buffer2d &rhs, bool transferBuffer)
Construct a new Buffer2d object Copies Rect32 and transfers buffer.
Definition buffer.h:346
void copyFrom(const Buffer2d *src, F filter)
Definition buffer.h:483
void copyFrom(const Buffer2d &src)
Definition buffer.h:531
void attach(Buffer2d &rhs)
Definition buffer.h:445
Buffer2d & operator=(const Buffer2d *rhs)
Definition buffer.h:371
Buffer2d & operator=(const Buffer2d &rhs)
Definition buffer.h:367
void clear(void)
Definition buffer.h:397
Definition buffer.h:262
Buffer2dSimple(T *buf, uint32_t stride, uint32_t height)
Definition buffer.h:264
uint32_t height_
Definition buffer.h:283
uint32_t stride_
Definition buffer.h:282
T * buf_
Definition buffer.h:281
Buffer2dSimple()
Definition buffer.h:263
Buffer2dSimple & incX_IN_PLACE(size_t deltaX)
Definition buffer.h:269
Buffer2dSimple & incY_IN_PLACE(size_t deltaY)
Definition buffer.h:275
Definition buffer.h:53
Buffer()
Definition buffer.h:58
void set_offset(size_t off)
Definition buffer.h:231
Buffer(T *buffer, size_t length, bool ownsData)
Definition buffer.h:59
uint8_t * buf_
Definition buffer.h:251
bool write(T *b, size_t size)
Definition buffer.h:101
Buffer & operator=(const Buffer &rhs)
Definition buffer.h:70
size_t offset() const
Definition buffer.h:227
size_t num_elts_
Definition buffer.h:253
bool write(T val)
Definition buffer.h:93
T * currPtr(size_t required_length) const
Definition buffer.h:201
virtual bool alloc(size_t length)
Definition buffer.h:110
T * currPtr(void) const
Definition buffer.h:195
T read(void)
Definition buffer.h:89
void transfer(T **buffer)
Definition buffer.h:140
void set_buf(T *buf, size_t elts)
Definition buffer.h:243
Buffer(T *buffer, size_t length)
Definition buffer.h:57
T ** ptr_to_buf()
Definition buffer.h:239
T * buf() const
Definition buffer.h:235
virtual ~Buffer()
Definition buffer.h:60
void set_num_elts(size_t elts)
Definition buffer.h:221
bool canRead(void)
Definition buffer.h:85
size_t num_elts() const
Definition buffer.h:213
Buffer(const Buffer &rhs)
Definition buffer.h:66
void set_owns_data(bool owns)
Definition buffer.h:209
bool increment_offset(std::ptrdiff_t off)
Definition buffer.h:156
Buffer & operator=(const Buffer *rhs)
Definition buffer.h:74
virtual void dealloc()
Definition buffer.h:124
bool owns_data_
Definition buffer.h:254
size_t * num_elts_ptr()
Definition buffer.h:217
Buffer(T *buffer, size_t off, size_t length, bool ownsData)
Definition buffer.h:54
size_t offset_
Definition buffer.h:252
void attach(T *buffer)
Definition buffer.h:134
size_t remainingLength(void) const
Definition buffer.h:152
bool owns_data()
Definition buffer.h:205
uint32_t width() const
Definition geometry.h:411
uint32_t x1
Definition geometry.h:192
T height() const
Definition geometry.h:415
Rect< uint32_t > intersection(const Rect< uint32_t > &rhs) const
Definition geometry.h:347
void setRect(const Rect *rhs)
Definition geometry.h:297
uint32_t x0
Definition geometry.h:192
Rect< uint32_t > & operator=(const Rect &rhs)
Definition geometry.h:262
uint32_t y0
Definition geometry.h:192
uint32_t y1
Definition geometry.h:192