VCS Dev Docs Class heap_mem<typename T>

A C++ wrapper for the memory subsystem interface.

More...

Public member functions

heap_mem(const unsigned numElements, const char *const reason=nullptr)
heap_mem(void)
allocate(const int elementCount, const char *const reason=nullptr)
unsignedcount(void) const
T*data(void) const
boolis_null(void) const
T&operator[](const unsigned idx) const
point_to(heap_mem<T> &other)
point_to(T *const dataPtr, const int numElements)
release(void)
unsignedsize(void) const
unsignedsize_check(const unsigned size) const

Detailed description

A C++ wrapper for the memory subsystem interface.

This wrapper provides a C++ API over the C-style memory subsystem interface, as well as runtime bounds-checking.

The wrapper consists of an object with a templated C++ interface operating a memory buffer acquired via the memory subsystem interface. Whereas the original interface operates on raw bytes (returning void* pointers and requiring explicit type-casting), this wrapper operates natively on built-in data types (e.g. char and short) and internally translates them into/from the original interface's plain byte arrays.

Warning:

The memory interface is for POD data only; i.e. anything you wouldn't mind using memset() on.

Usage

  1. Allocate memory for POD data types:
    // Allocate memory for 2 ints.heap_mem<int> ints(2); // Create an object but delay its memory allocation.heap_mem<double> doubles;doubles.allocate(11); // It's recommended that you provide a string describing your intended// purpose for the allocation. It may be used for descriptive debug// messages etc.heap_mem<char> scratch(640*480, "Scratch buffer for color conversion");
  2. Use the allocated memory:
    heap_mem<int> ints(2);heap_mem<char> chars(10); // These memory accesses are bounds-checked at runtime if the RELEASE_BUILD// build flag isn't defined; otherwise, no bounds-checking is done.ints[1] = 1234;chars[0] = 82;int a = ints[1]; // a == 1234.char b = chars[0]; // b == 82. // We allocated memory for 2 ints, so this overflows. It triggers a bounds-// checking assertion failure if the RELEASE_BUILD build flag isn't defined.int c = ints[9]; // The underlying memory pointer (of type T) is also available.int *exposedBuffer = ints.data();
  3. Release the allocated memory when you no longer need it:
    heap_mem<char> chars(10);// chars.is_null() == false. chars.release();// chars.is_null() == true. // Attempting to access null (in this case, released) memory. Triggers an// assertion failure if the RELEASE_BUILD build flag isn't defined;// otherwise results in undefined behavior.chars[0] = 15;

Public member function documentation

heap_mem(const unsigned numElements, const char *const reason)

Initializes the object and allocates numElements count of elements of type T for its data buffer.

This function calls kmem_allocate() to perform the memory allocation. See that function's documentation for more information about the memory it allocates.

heap_mem<char> buffer(10);// buffer.is_null() == false.// buffer.count() == 10.// buffer[0] == 0.
See also kmem_allocate()

heap_mem(void)

Initializes the object without allocating memory for its data buffer. The memory can be allocated later with allocate().

heap_mem<char> buffer;// buffer.is_null() == true.// buffer.count() == 0.
Note:

Attempting to dereference the object's unallocated data buffer (e.g. with heap_mem::operator[]) will result in a bounds-checking assertion failure if the RELEASE_BUILD build flag isn't defined, and undefined behavior otherwise.

See also allocate()

allocate(const int elementCount, const char *const reason)

Allocates memory for the data buffer.

// Allocate memory for 10 ints using the constructor.heap_mem<int> ints(10); // Allocate memory for 10 ints using allocate().heap_mem<int> ints2;ints2.allocate(10); // Allocate memory for 10 ints, then re-allocate for only 5 ints.{    heap_mem<int> ints3(10);    // ints3.count() == 10.     ints3.release();    // ints3.count() == 0.     ints3.allocate(5);    // ints3.count() == 5.}
Warning:

Call release() before re-allocating. Attempting to allocate over an existing data buffer will trigger an assertion failure.

unsigned count(void)

Returns the number of elements (of type T) allocated for the data buffer.

heap_mem<int> ints(11);// ints.count() == 11.// ints.size() == (11 * sizeof(int)).
heap_mem<int> ints;// ints.count() == 0.
See also size()

T* data(void)

Returns a pointer (of type T) to the first byte in the data buffer.

heap_mem<int> buffer(10);int *rawPointer = buffer.data(); // These refer to the same memory element, but the direct pointer access// never does bounds-checking.buffer[1];rawPointer[1]; // You could use the pointer e.g. with the mem* functions.std::memset(buffer.data(), 0, buffer.size());
Note:

If the RELEASE_BUILD build flag isn't defined, calling this function when the data buffer is unallocated (is_null() returns true) will result in an assertion failure.

bool is_null(void)

Returns true if the memory object currently has a null data buffer; false otherwise.

// The default constructor doesn't allocate the data buffer.heap_mem<int> ints;// ints.is_null() == true. ints.allocate(1);// ints.is_null() == false. ints.release();// ints.is_null() == true.
heap_mem<int> ints(2);// ints.is_null() == false. heap_mem<int> intsRef;// intsRef.is_null() == true. intsRef.point_to(ints);// intsRef.is_null() == false.
See also allocate()

T& operator[](const unsigned idx)

Returns a reference to the element at index idx in the data buffer, bounds-checking the offset unless the RELEASE_BUILD build flag is set.

If the bounds check fails, triggers an assertion failure.

// Allocate 10 ints.heap_mem<int> buffer(10); // Set the value of the 2nd int in the data buffer. This access will// be bounds-checked if the RELEASE_BUILD build flag isn't defined.buffer[1] = 0; // An overflowing write that attempts to modify the 11th element when only// 10 elements have been allocated. Triggers an assertion failure if the// RELEASE_BUILD build flag isn't defined.buffer[10] = 0;
See also data()

point_to(heap_mem<T> &other)

Sets the data buffer pointer to point to the first byte of the data buffer of the other memory object.

Warning:

Releasing the data buffer of other doesn't update pointers that point to it. Accessing the released memory via these pointers will result in undefined behavior that bypasses runtime bounds checks.

heap_mem<int> ints(2); heap_mem<int> intsRef;intsRef.point_to(ints); ints[0] = 1234;// intsRef[0] == 1234. intsRef[0] = 1;// ints[0] == 1. ints.release();// ints.is_null() == true.// intsRef.is_null() == false. // Undefined behavior, because the source buffer was released. The runtime// bounds-checking of operator[] doesn't work, because it still thinks the// data buffer exists.intsRef[0]; intsRef.release();// intsRef.is_null() == true. // Will now correctly trigger the bounds-checking in operator[].intsRef[0];

point_to(T *const dataPtr, const int numElements)

Sets the data buffer pointer to point to a region of memory pointed to by dataPtr and which holds numElements elements of type T.

int ints[10];heap_mem<int> intsRef; intsRef.point_to(ints, 10); ints[0] = 1234;// intsRef[0] == 1234.

release(void)

Releases the memory allocated to the data buffer.

This function calls kmem_release() to release the memory. See that function's documentation for more information about the process.

If called on a data buffer allocated with point_to(), will only mark this memory object's data buffer as null without releasing the memory to which it points.

Note:

Requests to release a null data buffer will be ignored.

heap_mem<int> ints;// ints.is_null() == true. ints.allocate(1);// ints.is_null() == false. ints.release();// ints.is_null() == true. // This call is ignored, because the buffer has already been released.ints.release();// ints.is_null() == true.
heap_mem<int> ints(2); heap_mem<int> intsRef;intsRef.point_to(ints); // Calling release() on a data buffer allocated with point_to()// only sets that memory object's data pointer to null without releasing// the buffer.intsRef.release();// intsRef.is_null() == true.// ints.is_null() == false.
See also kmem_release()

unsigned size(void)

Returns the number of bytes allocated for the data buffer.

heap_mem<int> ints(11);// ints.size() == (11 * sizeof(int)).// ints.count() == 11.
See also count()

unsigned size_check(const unsigned size)

Compares size against the size() of the data buffer. If size is larger, triggers an assertion failure. Otherwise, returns size.

This function's intended use case is to act as a drop-in bounds-check for e.g. the mem* functions.

heap_mem<char> buffer(1000); unsigned x = 10;unsigned y = 5; // We want to memset x*y bytes of the data buffer. The size_check() function// ensures that this value doesn't exceed the buffer's maximum byte capacity.std::memset(buffer.data(), 0, buffer.size_check(x * y));