libpromeki 1.0.0-alpha
PROfessional MEdia toolKIt
 
Loading...
Searching...
No Matches
buffer.h
Go to the documentation of this file.
1
8#pragma once
9
10
11#include <promeki/config.h>
12#if PROMEKI_ENABLE_CORE
13#include <cassert>
14#include <cstddef>
15#include <cstdint>
16#include <promeki/namespace.h>
17#include <promeki/list.h>
18#include <promeki/error.h>
19#include <promeki/result.h>
20#include <promeki/sharedptr.h>
21#include <promeki/memspace.h>
22#include <promeki/memdomain.h>
24#include <promeki/bufferimpl.h>
27
28PROMEKI_NAMESPACE_BEGIN
29
30class String;
31
103class Buffer {
104 public:
106 using List = ::promeki::List<Buffer>;
107
112 static size_t getPageSize();
113
115 static const size_t DefaultAlign;
116
118 Buffer() = default;
119
135 Buffer(size_t sz, size_t an = DefaultAlign, const MemSpace &ms = MemSpace::Default)
136 : _d(makeBufferImpl(ms, sz, an)) {}
137
153 static Buffer wrapHost(void *p, size_t sz, size_t an = 0, const MemSpace &ms = MemSpace::Default);
154
161 static Buffer fromImpl(BufferImpl *impl) {
162 Buffer b;
163 if (impl != nullptr) b._d = BufferImplPtr::takeOwnership(impl);
164 return b;
165 }
166
185 static Result<Buffer> fromHex(const String &hex);
186
200 String toHex(const String &sep) const;
201
203 String toHex() const;
204
211 bool isValid() const { return _d.isValid() && _d->allocSize() > 0; }
212
232 void *data() {
233 if (!_d.isValid()) return nullptr;
234 void *base = _d->mappedHostData();
235 if (base == nullptr) return nullptr;
236 return static_cast<uint8_t *>(base) + _d->shift();
237 }
238
240 const void *data() const {
241 if (!_d.isValid()) return nullptr;
242 const void *base = _d->mappedHostData();
243 if (base == nullptr) return nullptr;
244 return static_cast<const uint8_t *>(base) + _d->shift();
245 }
246
256 void *odata() {
257 if (!_d.isValid()) return nullptr;
258 return _d->mappedHostData();
259 }
260
262 const void *odata() const {
263 if (!_d.isValid()) return nullptr;
264 return _d->mappedHostData();
265 }
266
273 size_t size() const { return _d.isValid() ? _d->logicalSize() : 0; }
274
283 void setSize(size_t s) const {
284 assert(s <= availSize());
285 if (_d.isValid()) _d->setLogicalSize(s);
286 // setLogicalSize is a const method on BufferImpl
287 // (mutates a `mutable` member), so `_d->` const
288 // operator-> reaches it without modify().
289 }
290
296 size_t availSize() const {
297 if (!_d.isValid()) return 0;
298 size_t total = _d->allocSize();
299 size_t shift = _d->shift();
300 return shift > total ? 0 : total - shift;
301 }
302
304 size_t allocSize() const { return _d.isValid() ? _d->allocSize() : 0; }
305
307 size_t align() const { return _d.isValid() ? _d->align() : 0; }
308
315 MemSpace memSpace() const { return _d.isValid() ? _d->memSpace() : MemSpace(MemSpace::System); }
316
328 void shiftData(size_t bytes) {
329 assert(_d.isValid());
330 assert(bytes <= _d->allocSize());
331 _d.modify()->setShift(bytes);
332 }
333
337 size_t shift() const { return _d.isValid() ? _d->shift() : 0; }
338
339 // ---- Mapping ----
340
345 bool isMapped(MemDomain domain = MemDomain::Host) const {
346 return _d.isValid() && _d->isMapped(domain);
347 }
348
354 bool isHostAccessible() const { return isMapped(MemDomain::Host); }
355
367 BufferRequest mapAcquire(MemDomain domain = MemDomain::Host, MapFlags flags = MapFlags::Read) {
368 if (!_d.isValid()) return BufferRequest::resolved(Error::Invalid);
369 return _d.modify()->mapAcquire(domain, flags);
370 }
371
382 BufferRequest mapRelease(MemDomain domain = MemDomain::Host) {
383 if (!_d.isValid()) return BufferRequest::resolved(Error::Invalid);
384 return _d.modify()->mapRelease(domain);
385 }
386
387 // ---- Mutation ----
388
397 Error fill(char value) const {
398 if (!_d.isValid()) return Error::Invalid;
399 return _d.modify()->fill(value, _d->shift(), availSize());
400 }
401
414 Error copyFrom(const void *src, size_t bytes, size_t offset = 0) const;
415
438 BufferRequest copyTo(Buffer &dst, size_t bytes, size_t srcOffset = 0, size_t dstOffset = 0) const;
439
440 // ---- Detach ----
441
452 void ensureExclusive() {
453 if (!_d.isValid()) return;
454 if (_d.referenceCount() < 2) return;
455 if (!_d->canClone()) return;
456 _d.detach();
457 }
458
468 Error ensureExclusiveError() {
469 if (!_d.isValid()) return Error::Invalid;
470 if (_d.referenceCount() < 2) return Error::Ok;
471 if (!_d->canClone()) return Error::NotSupported;
472 _d.detach();
473 return Error::Ok;
474 }
475
477 bool isExclusive() const { return _d.isValid() && _d.referenceCount() < 2; }
478
488 bool isShared() const { return _d.isValid() && _d.referenceCount() >= 2; }
489
511 [[nodiscard]] Error seal() const {
512 if (!_d.isValid()) return Error::Invalid;
513 return _d->seal();
514 }
515
525 size_t residentBytes() const {
526 return _d.isValid() ? _d->residentBytes() : 0;
527 }
528
540 bool isCowBacked() const {
541 return _d.isValid() && _d->isCowBacked();
542 }
543
551 const BufferImplPtr &impl() const { return _d; }
552
571 bool operator==(const Buffer &o) const;
572
574 bool operator!=(const Buffer &o) const { return !(*this == o); }
575
577 explicit operator bool() const { return _d.isValid(); }
578
579 private:
580 // mutable so const-on-method mutators (setSize, fill,
581 // copyFrom) can call _d.modify() to reach the
582 // BufferImpl's non-const interface without
583 // const_cast. The Buffer wrapper's own identity (the
584 // impl pointer) is never reassigned through a const
585 // path; only the pointed-to BufferImpl is mutated.
586 mutable BufferImplPtr _d;
587};
588
589PROMEKI_NAMESPACE_END
590
591#endif // PROMEKI_ENABLE_CORE