tinyimg 1.0.0
Lightweight image manipulation library for Cloudflare Workers
Loading...
Searching...
No Matches
memory.h File Reference

Lightweight memory management implementatins in C. More...

#include <stddef.h>
#include <stdint.h>

Go to the source code of this file.

Classes

struct  TinyHeapStats
 A snapshot of heap occupancy. More...
struct  TinyArenaMark
 A saved arena position. More...

Macros

#define TINYIMG_MAX_PIXELS   16000000u
 Maximum number of pixels allowed in an image, whatever its channel count. Bounds decode time, which scales with pixels rather than bytes.
#define TINYIMG_MAX_IMAGE_BYTES   33554432u
 Largest pixel buffer a single image may hold.
#define TINYIMG_ALIGNMENT   16u
 Alignment every allocation is rounded up to.
#define TINYIMG_HEAP_MAX   67108864u
 Largest heap the host build reserves, matching the wasm module's –max-memory.
#define TINYIMG_MAX_BLOBS   8
 How many blobs can be resident at once.
#define TINYIMG_BLOB_ID_MAX   32
 Longest blob id, including the terminator.

Typedefs

typedef enum TinyBlobKind TinyBlobKind
 Kinds of data the library reads but does not ship.

Enumerations

enum  TinyBlobKind { TINYIMG_BLOB_FONT = 0 , TINYIMG_BLOB_ICC = 1 , TINYIMG_BLOB_CASCADE = 2 }
 Kinds of data the library reads but does not ship. More...

Functions

void * tiny_memcpy (void *dest, const void *src, size_t n)
 Replicates the behavior of the standard memcpy function, copying n bytes from src to dest.
void * tiny_memset (void *s, int c, size_t n)
 Replicates the behavior of the standard memset function, filling the first n bytes of the memory area pointed to by s with the constant byte c.
void * tiny_memmove (void *dest, const void *src, size_t n)
 Replicates the behavior of the standard memmove function, copying n bytes from src to dest. Unlike memcpy, memmove is safe to use when the source and destination memory areas overlap.
int tiny_memcmp (const void *s1, const void *s2, size_t n)
 Replicates the behavior of the standard memcmp function, comparing the first n bytes of the memory areas pointed to by s1 and s2.
int tiny_heap_init (void *memory, size_t size)
 Installs a caller supplied block as the heap.
void tiny_heap_bootstrap (void)
 Installs the platform's default heap if no heap exists yet.
int tiny_heap_stats (TinyHeapStats *stats)
 Reads the current heap occupancy.
void * tiny_alloc (size_t size)
 Allocates a block from the heap.
void * tiny_realloc (void *pointer, size_t size)
 Resizes a block, moving it only when it cannot grow in place.
void tiny_free (void *pointer)
 Returns a block to the heap, coalescing it with free neighbors.
size_t tiny_alloc_size (const void *pointer)
 Usable size of a block, which may exceed what was asked for.
void * tiny_arena_alloc (size_t size, size_t alignment)
 Allocates a block from the arena, aligned to the requested boundary.
void tiny_arena_mark (TinyArenaMark *mark)
 Records the current arena position.
void tiny_arena_release (const TinyArenaMark *mark)
 Rewinds the arena to a recorded position.
void tiny_arena_reset (void)
 Releases every block the arena has handed out.
size_t tiny_arena_reserved (void)
 Bytes the arena currently holds from the heap.
int tiny_blob_load (TinyBlobKind kind, const char *id, const uint8_t *data, size_t size)
 Registers a blob under an id.
const uint8_t * tiny_blob_get (TinyBlobKind kind, const char *id, size_t *size)
 Looks up a resident blob.
const uint8_t * tiny_blob_at (TinyBlobKind kind, uint32_t index, const char **id, size_t *size)
 Walks the resident blobs of one kind.
int tiny_blob_free (TinyBlobKind kind, const char *id)
 Releases one resident blob.
void tiny_blob_free_all (void)
 Releases every resident blob.

Detailed Description

Lightweight memory management implementatins in C.

Author
Gregory Mitchell (me@gm.nosp@m.itch.nosp@m.215.x.nosp@m.yz)
Version
1.0.0
Date
2026-08-31

Macro Definition Documentation

◆ TINYIMG_ALIGNMENT

#define TINYIMG_ALIGNMENT   16u

Alignment every allocation is rounded up to.

Sixteen bytes so a pixel buffer can be read with aligned SIMD128 loads.

◆ TINYIMG_MAX_IMAGE_BYTES

#define TINYIMG_MAX_IMAGE_BYTES   33554432u

Largest pixel buffer a single image may hold.

The pixel cap alone cannot express the constraint that actually fails: an allocation is bytes, so a 15 megapixel RGBA image passes a 16 megapixel check and then dies in the allocator. Half the heap leaves room for the encoded source, a decoder's component planes and one scratch buffer.

Measured full-decode ceilings against the 64 MiB heap, which is what this number is set from: JPEG 4:2:0 13.81 Mpx, 4:2:2 12.28, 4:4:4 10.32, PNG RGB 10.97, PNG RGBA 8.56. Every one of those failed in the allocator before this cap existed, so the specific error was unreachable for all of them.

◆ TINYIMG_MAX_PIXELS

#define TINYIMG_MAX_PIXELS   16000000u

Maximum number of pixels allowed in an image, whatever its channel count. Bounds decode time, which scales with pixels rather than bytes.

A grayscale image is the only one that reaches this, because TINYIMG_MAX_IMAGE_BYTES binds first at every wider channel count.

Typedef Documentation

◆ TinyBlobKind

typedef enum TinyBlobKind TinyBlobKind

Kinds of data the library reads but does not ship.

Anything large enough to dominate the module, or only needed by some callers, arrives at runtime instead of being linked in. The host either imports it as a wrangler Data module or fetches it from a bucket; the library only ever sees bytes already in linear memory.

Enumeration Type Documentation

◆ TinyBlobKind

Kinds of data the library reads but does not ship.

Anything large enough to dominate the module, or only needed by some callers, arrives at runtime instead of being linked in. The host either imports it as a wrangler Data module or fetches it from a bucket; the library only ever sees bytes already in linear memory.

Enumerator
TINYIMG_BLOB_FONT 

A TrueType, OpenType, PSF or BDF face.

TINYIMG_BLOB_ICC 

An ICC color profile.

TINYIMG_BLOB_CASCADE 

A packed detection cascade.

Function Documentation

◆ tiny_alloc()

void * tiny_alloc ( size_t size)

Allocates a block from the heap.

First fit over an address ordered block list, so the cost is linear in the number of live blocks rather than constant. An image pipeline holds a handful of blocks at a time; a workload that holds thousands would want a size bucketed free list instead.

The returned block is aligned to TINYIMG_ALIGNMENT and its contents are undefined.

Parameters
sizeNumber of bytes to allocate. Zero returns NULL.
Returns
void* The block, or NULL when the heap could not grow enough.

◆ tiny_alloc_size()

size_t tiny_alloc_size ( const void * pointer)

Usable size of a block, which may exceed what was asked for.

Parameters
pointerThe block.
Returns
size_t The payload size, or 0 if the pointer is not a live block.

◆ tiny_arena_alloc()

void * tiny_arena_alloc ( size_t size,
size_t alignment )

Allocates a block from the arena, aligned to the requested boundary.

The arena never frees an individual block. It is reclaimed in bulk, either back to a saved position with tiny_arena_release or entirely with tiny_arena_reset. Use it for scratch that lives no longer than the call that asked for it.

Amortized O(1) time complexity. The arena takes chunks from the heap as it needs them, so an allocation never invalidates a pointer it handed out earlier.

Parameters
sizeNumber of bytes to allocate.
alignmentRequired alignment in bytes. Must be a power of two; zero means TINYIMG_ALIGNMENT.
Returns
void* Pointer to the block, or NULL if the heap has no room.

◆ tiny_arena_mark()

void tiny_arena_mark ( TinyArenaMark * mark)

Records the current arena position.

Parameters
markReceives the position.

◆ tiny_arena_release()

void tiny_arena_release ( const TinyArenaMark * mark)

Rewinds the arena to a recorded position.

Any pointer handed out after the mark was taken is dangling afterwards.

Parameters
markA position from tiny_arena_mark.

◆ tiny_arena_reserved()

size_t tiny_arena_reserved ( void )

Bytes the arena currently holds from the heap.

Returns
size_t The total size of the arena's chunks.

◆ tiny_arena_reset()

void tiny_arena_reset ( void )

Releases every block the arena has handed out.

O(n) time complexity, where n is the number of chunks. Any pointer previously returned by tiny_arena_alloc is dangling afterwards.

◆ tiny_blob_at()

const uint8_t * tiny_blob_at ( TinyBlobKind kind,
uint32_t index,
const char ** id,
size_t * size )

Walks the resident blobs of one kind.

The way to act on every blob of a kind without knowing what any of them is called. Face detection needs it: a caller loads whichever cascades they have and the detector runs all of them, so nothing in the library names a blob.

The order is the slot order, which is not the load order once a blob has been freed and its slot reused.

Parameters
kindWhat to walk.
indexWhich one, from zero.
idReceives the id it was loaded under. May be NULL.
sizeReceives the byte length. May be NULL.
Returns
const uint8_t* The bytes, or NULL once index is past the last one.

◆ tiny_blob_free()

int tiny_blob_free ( TinyBlobKind kind,
const char * id )

Releases one resident blob.

Parameters
kindWhat to release.
idThe id it was loaded under, or NULL for the first blob of that kind.
Returns
int TINYIMG_OK or TINYIMG_ERR_NOT_FOUND.

◆ tiny_blob_get()

const uint8_t * tiny_blob_get ( TinyBlobKind kind,
const char * id,
size_t * size )

Looks up a resident blob.

Parameters
kindWhat to look for.
idThe id it was loaded under, or NULL for the first blob of that kind.
sizeReceives the byte length. May be NULL.
Returns
const uint8_t* The bytes, or NULL when nothing matches.

◆ tiny_blob_load()

int tiny_blob_load ( TinyBlobKind kind,
const char * id,
const uint8_t * data,
size_t size )

Registers a blob under an id.

The library takes ownership of data, which must have come from tiny_alloc, and releases it with tiny_blob_free or tiny_blob_free_all. Loading over an existing kind and id replaces it and frees what was there.

Parameters
kindWhat the bytes are.
idName the caller will ask for it by. Truncated at TINYIMG_BLOB_ID_MAX.
dataThe bytes, owned by the library from here on.
sizeNumber of bytes.
Returns
int TINYIMG_OK, TINYIMG_ERR_NULL, or TINYIMG_ERR_MEMORY when all TINYIMG_MAX_BLOBS slots are taken.

◆ tiny_free()

void tiny_free ( void * pointer)

Returns a block to the heap, coalescing it with free neighbors.

A NULL pointer, a pointer the heap never handed out, and a second free of the same pointer are all ignored rather than corrupting the block list.

Parameters
pointerThe block to free.

◆ tiny_heap_bootstrap()

void tiny_heap_bootstrap ( void )

Installs the platform's default heap if no heap exists yet.

On wasm the heap starts at __heap_base and grows through memory.grow up to the module's –max-memory. On a host build it is one reservation of TINYIMG_HEAP_MAX, which stays untouched address space until written to.

Idempotent, and called by every allocation, so nothing has to remember to initialize the library before using it.

◆ tiny_heap_init()

int tiny_heap_init ( void * memory,
size_t size )

Installs a caller supplied block as the heap.

The block is never grown, which is what makes it the right choice for a test that wants exhaustion to happen at a predictable size. A wasm module or a host process should call tiny_heap_bootstrap instead and let the heap grow.

Any pointer handed out by a previous heap is dangling afterwards.

Parameters
memoryPointer to the memory block to be used for the heap.
sizeSize of the memory block in bytes.
Returns
int TINYIMG_OK, or TINYIMG_ERR_RANGE when the block is too small to hold a single allocation.

◆ tiny_heap_stats()

int tiny_heap_stats ( TinyHeapStats * stats)

Reads the current heap occupancy.

O(n) time complexity, where n is the number of blocks.

Parameters
statsReceives the snapshot.
Returns
int TINYIMG_OK or a negative TinyImageError.

◆ tiny_memcmp()

int tiny_memcmp ( const void * s1,
const void * s2,
size_t n )

Replicates the behavior of the standard memcmp function, comparing the first n bytes of the memory areas pointed to by s1 and s2.

O(n) time complexity, where n is the number of bytes to compare.

Parameters
s1Pointer to the first memory area to be compared.
s2Pointer to the second memory area to be compared.
nNumber of bytes to compare.
Returns
int An integer less than, equal to, or greater than zero if the first n bytes of s1 are found, respectively, to be less than, equal to, or greater than the first n bytes of s2.

◆ tiny_memcpy()

void * tiny_memcpy ( void * dest,
const void * src,
size_t n )

Replicates the behavior of the standard memcpy function, copying n bytes from src to dest.

O(n) time complexity, where n is the number of bytes to copy.

Parameters
destDestination buffer where the content is to be copied.
srcSource buffer from which the content is to be copied.
nNumber of bytes to copy from src to dest.
Returns
void* Pointer to the destination buffer dest.

◆ tiny_memmove()

void * tiny_memmove ( void * dest,
const void * src,
size_t n )

Replicates the behavior of the standard memmove function, copying n bytes from src to dest. Unlike memcpy, memmove is safe to use when the source and destination memory areas overlap.

O(n) time complexity, where n is the number of bytes to copy.

Parameters
destDestination buffer where the content is to be copied.
srcSource buffer from which the content is to be copied.
nNumber of bytes to copy from src to dest.
Returns
void* Pointer to the destination buffer dest.

◆ tiny_memset()

void * tiny_memset ( void * s,
int c,
size_t n )

Replicates the behavior of the standard memset function, filling the first n bytes of the memory area pointed to by s with the constant byte c.

O(n) time complexity, where n is the number of bytes to set.

Parameters
sPointer to the memory area to be filled.
cConstant byte value to fill the memory area with.
nNumber of bytes to fill in the memory area.
Returns
void* Pointer to the memory area s.

◆ tiny_realloc()

void * tiny_realloc ( void * pointer,
size_t size )

Resizes a block, moving it only when it cannot grow in place.

A block whose successor is free absorbs it rather than moving, which is what keeps an append heavy TinyWriter from copying on every doubling.

Parameters
pointerBlock to resize, or NULL to allocate.
sizeNew size in bytes. Zero frees the block and returns NULL.
Returns
void* The block, or NULL on failure. The original block is left untouched when the call fails.