playbit / docs

Collections


#include <playbit/array.h>

Define an array type with PBArrayType(ElementType) and operate on it via "method" macros.

Example use:

typedef struct {
    int a, b;
} Foo;
typedef PBArrayType(Foo) FooArray;

Type generated by PBArrayType(T):

struct {
    T* nullable v;
    usize       len;
    usize       cap;
}

Predefined array types:

PBI8Array

typedef PBArrayType(i8) PBI8Array;

PBI16Array

typedef PBArrayType(i16) PBI16Array;

PBI32Array

typedef PBArrayType(i32) PBI32Array;

PBI64Array

typedef PBArrayType(i64) PBI64Array;

PBU8Array

typedef PBArrayType(u8) PBU8Array;

PBU16Array

typedef PBArrayType(u16) PBU16Array;

PBU32Array

typedef PBArrayType(u32) PBU32Array;

PBU64Array

typedef PBArrayType(u64) PBU64Array;

PBF32Array

typedef PBArrayType(f32) PBF32Array;

PBF64Array

typedef PBArrayType(f64) PBF64Array;

PBPtrArray

typedef PBArrayType(void*) PBPtrArray;

PBArrayStructStaticAssertLayout

#define PBArrayStructStaticAssertLayout(STRUCT_TYPE)

PBArrayStructStaticAssertLayout is a helper for custom-defined array structs that need to be ABI compatible with PBArray functions. Example: typedef struct { const void* nullable ptr; usize len; usize cap; } MyArray; PBArrayStructStaticAssertLayout(MyArray);

PBAnyArray

typedef PBArrayType(void*) PBAnyArray;

PBAnyArray represents "an array of unknown/any type" The field name is intentionally different from other types to catch mistakes.

PBAnyArrayResize

bool PBAnyArrayResize(PBAnyArray* a,
                      usize       elemSize,
                      PBMem       ma,
                      usize       newCap,
                      u32         maFlags);

PBAnyArrayResize resizes capacity to hold at least newCap elements.

If newCap is smaller than current length, length is truncated.

PBAnyArrayRemove

void PBAnyArrayRemove(PBAnyArray* arg,
                      usize       elemSize,
                      usize       start,
                      usize       len);

PBAnyArrayRemove removes len elements starting at index start.

PBAnyArrayAlloc

void* PBAnyArrayAlloc(PBAnyArray* arg,
                      usize       elemSize,
                      PBMem       arg,
                      usize       len);

PBAnyArrayAlloc appends len uninitialized elements and returns pointer to the first one.

PBAnyArrayAllocAt

void* PBAnyArrayAllocAt(PBAnyArray* arg,
                        usize       elemSize,
                        PBMem       arg,
                        usize       i,
                        usize       len);

PBAnyArrayAllocAt inserts len uninitialized elements at index i.

PBAnyArrayReserve

bool PBAnyArrayReserve(PBAnyArray* arg,
                       usize       elemSize,
                       PBMem       arg,
                       usize       nitems);

PBAnyArrayReserve ensures at least nitems spare capacity beyond current length.

PBAnyArrayReserveExact

bool PBAnyArrayReserveExact(PBAnyArray* arg,
                            usize       elemSize,
                            PBMem       arg,
                            usize       nitems);

PBAnyArrayReserveExact grows capacity to satisfy nitems spare slots without geometric extra growth.

PBAnyArrayGrow

bool PBAnyArrayGrow(PBAnyArray* a,
                    usize       elemSize,
                    PBMem       ma,
                    usize       minavail);

PBAnyArrayGrow grows by at least minavail additional slots.

PBAnyArrayFree

void PBAnyArrayFree(PBAnyArray* a,
                    usize       elemSize,
                    PBMem       ma);

PBAnyArrayFree releases backing storage for a.

PBAnyArrayInsert

bool PBAnyArrayInsert(PBAnyArray* arg,
                      usize       elemSize,
                      PBMem       ma,
                      usize       i,
                      const void* src,
                      usize       len);

PBAnyArrayInsert inserts len elements copied from src at index i.

PBAnyArrayMove

macro void PBAnyArrayMove(PBAnyArray* a, usize elemSize, usize dst, usize start, usize end)

PBAnyArrayRot

void PBAnyArrayRot(usize stride,
                   void* v,
                   usize first,
                   usize mid,
                   usize last);

PBAnyArrayRot rotates range [first,last) around pivot mid for elements of size stride bytes.

PBAnyArrayRot32

void PBAnyArrayRot32(const u32* v,
                     usize      first,
                     usize      mid,
                     usize      last);

PBAnyArrayRot32 rotates range [first,last) around mid for arrays of u32 elements.

PBAnyArrayRot64

void PBAnyArrayRot64(const u64* v,
                     usize      first,
                     usize      mid,
                     usize      last);

PBAnyArrayRot64 rotates range [first,last) around mid for arrays of u64 elements.

PBAnyArray_INIT_WITH_STORAGE

macro void PBAnyArray_INIT_WITH_STORAGE(T* structPtr, NAME arrayField, NAME storageField)

PBAnyArray_INIT_WITH_STORAGE allows initializing struct-member arrays with external storage. This is particularly useful when the common case is know up front and space can be allocated ahead of time. When the array needs to grow, the array implementation will check for storage pointing to directly before itself to determine if it owns that memory or not.

Initial storage must be located directly before the array struct. The array implementation relies on this to avoid free'ing your storage as the array grows.

Example:

struct MyThing {
    int x;
};
struct MyThings {
    MyThing              thingsStorage[4];
    PBArrayType(MyThing) things;
};
void example(void) {
    MyThings m = { 0 };
    PBAnyArray_INIT_WITH_STORAGE(&m, things, thingsStorage);
}

PBArrayInit

macro void PBArrayInit(ArrayType* array)

Initializes array to zero in preparation for use.

PBArrayFrom

macro ArrayType PBArrayFrom(ArrayType, PBMem ma, T* src, usize len)

PBArrayFree

macro void PBArrayFree(ArrayType* array, PBMem ma)

Frees the backing memory associated with the array instance pointed to by array.

PBArrayClear

macro void PBArrayClear(ArrayType* array)

Resets length of the array pointed to by array to zero.

PBArrayAt

macro T PBArrayAt(ArrayType* array, usize at)

PBArrayRefAt

macro T* PBArrayRefAt(ArrayType* array, usize at)

PBArrayPush

macro bool PBArrayPush(ArrayType* array, PBMem ma, T item)

Pushes item onto the end of the array pointed to by array.

PBArrayPop

macro T PBArrayPop(ArrayType* array)

Removes the last item in the array.

PBArrayAlloc

macro T* PBArrayAlloc(ArrayType* array, PBMem ma, usize len)

Appends len uninitialized elements to the array pointed to by array.

PBArrayAllocAt

macro T* PBArrayAllocAt(ArrayType* array, PBMem ma, usize at, usize len)

Inserts len uninitialized elements into the array pointed to by array at index at.

PBArrayResize

macro bool PBArrayResize(ArrayType* array, PBMem ma, usize newCap, u32 maFlags)

Resizes capacity to hold at least newCap elements. If newCap is smaller than current length, length is truncated.

PBArrayReserve

macro bool PBArrayReserve(ArrayType* array, PBMem ma, usize nItems)

Ensures at least nItems spare capacity beyond current length.

PBArrayReserveExact

macro bool PBArrayReserveExact(ArrayType* array, PBMem ma, usize nItems)

Grows capacity to satisfy nItems spare slots without geometric extra growth.

PBArrayShrinkwrap

macro bool PBArrayShrinkwrap(ArrayType* array, PBMem ma)

Resizes memory so that cap=len. Note that cap>len might still be true depending on the memory allocator's implementation.

PBArrayAppend

macro bool PBArrayAppend(ArrayType* array, PBMem ma, T* src, usize srcLen)

Pushes srcLen items from src to the end of the array pointed to by array.

PBArrayInsert

macro bool PBArrayInsert(ArrayType* array, PBMem ma, usize at, T* src, usize srcLen)

Inserts srcLen items from src into the array pointed to by array starting at index at.

PBArrayRemove

macro void PBArrayRemove(ArrayType* array, usize start, usize len)

Removes len items from the array pointed to by array starting at index start.

PBArrayMove

macro void PBArrayMove(ArrayType* array, usize dstPos, usize start, usize end)

Moves the items within the array pointed at by array between [start, end) to the new index dstPos.

PBArrayEq

macro bool PBArrayEq(ArrayType* array, T* ptr, usize ptrLen)

PBArrayCmp

macro int PBArrayCmp(ArrayType* array, T* ptr, usize ptrLen)

PBArrayFromSlice

macro ArrayType PBArrayFromSlice(ArrayType, PBMem ma, SliceType slice)

PBArraySlice

macro SliceType PBArraySlice(SliceType, ArrayType* array, usize start, usize rangeLen)

#include <playbit/buf.h>

PBBuf

typedef PBArrayType(u8) PBBuf;

PBBuf is a growable byte buffer, binary compatible with PBU8Array

PBBufFromStrSlice

PBBuf PBBufFromStrSlice(PBMem      ma,
                        PBStrSlice source);

PBBufCStr

char* PBBufCStr(PBBuf* buf,
                PBMem  ma);

PBBufCStr inserts a trailing \0, but does not increment len. Thus, the \0 byte will be overwritten by future modifications.

PBBufAppendHex

bool PBBufAppendHex(PBBuf*    buf,
                    PBMem     ma,
                    const u8* bytes,
                    usize     len);

PBBufAppendHex appends hexadecimal encoding of bytes to buf. buf->len will be extended by len * 2.

PBBufOf

PBBuf PBBufOf(PBMem       ma,
              const void* value,
              ...);

PBBufOf allocates a copy of value using memory allocator ma. It's implemented as a generic macro, with the following effective signature: PBBuf PBBufOf<T is PBStrSlice|PBStr|PBBuf|const char*>(T v[, usize start, [usize len]]) The caller should check for OOM, e.g. if (buf.len == 0 && from.len > 0) panic("OOM");

PBBufEq

#define PBBufEq

PBBufEq is implemented as a generic macro, with the following effective signature: bool PBBufEq<A is convertible to PBStrSlice, B is convertible to PBStrSlice>(A a, B b)

PBBuf_INIT_WITH_STORAGE

#define PBBuf_INIT_WITH_STORAGE

void PBBuf_INIT_WITH_STORAGE(T* structPtr, NAME bufField, NAME storageField)

PBBuf_INIT_WITH_STORAGE allows initializing struct-member buffer with external storage. This is particularly useful when the common case is know up front and space can be allocated ahead of time. When the buffer needs to grow, the buffer implementation will check for storage pointing to directly before itself to determine if it owns that memory or not.

Initial storage storageField must be located directly before the PBBuf bufField in your struct. The buffer implementation relies on this to avoid free'ing your storage as the buffer grows.

Example:

struct MyFormatter {
    u8    bufStorage[64];
    PBBuf buf;
};
void example(void) {
    MyFormatter formatter = { 0 };
    PBAnyArray_INIT_WITH_STORAGE(&formatter, buf, bufStorage);
}

#include <playbit/ringbuf.h>

PBRingBuf

typedef struct PBRingBuf {
    u8* nullable v;
    usize        cap;
    usize        off;
    usize        len;
} PBRingBuf;

PBRingBufEnsureWriteCapacity

bool PBRingBufEnsureWriteCapacity(PBRingBuf* rb,
                                  PBMem      ma,
                                  usize      minLen,
                                  usize      align);

PBRingBufWriteReserve

u8* PBRingBufWriteReserve(PBRingBuf* rb,
                          PBMem      ma,
                          usize      minLen,
                          usize      align);

PBRingBufWriteReserve returns contiguous space for at least minLen bytes at the logical tail. The caller must follow with PBRingBufProduce after writing bytes into the returned storage. The returned pointer is aligned to align, which must be 0, 1, or a power of two.

PBRingBufProduce

void PBRingBufProduce(PBRingBuf* rb,
                      usize      n);

PBRingBufProduce makes n newly written bytes visible at the tail. The caller must have previously reserved enough space with PBRingBufWriteReserve.

PBRingBufConsume

usize PBRingBufConsume(PBRingBuf* rb,
                       usize      n);

PBRingBufConsume removes up to n bytes from the logical head.


#include <playbit/hashtable.h>

Fundamental hash table

PBHashTableEqFn

typedef bool (*PBHashTableEqFn)(const void * _Nonnull, const void * _Nonnull);

PBHashTableHashFn

typedef usize (*PBHashTableHashFn)(usize, const void * _Nonnull);

PBHashTable

typedef struct PBHashTable {
    PBMem ma;
    usize seed; // hash seed passed to hashfn
    usize cap;  // capacity
    usize load; // current number of entries stored in the table
    void* entries;
} PBHashTable;

PBHashTableInit

bool PBHashTableInit(PBHashTable* arg,
                     int          ma,
                     usize        entsize,
                     usize        capHint);

PBHashTableInit initializes ht with capacity hint capHint.

PBHashTableFree

void PBHashTableFree(PBHashTable* ht);

PBHashTableFree releases all memory owned by ht.

PBHashTableClear

void PBHashTableClear(PBHashTable* ht,
                      usize        entsize);

PBHashTableClear removes all entries from the hashtable

PBHashTableAssign

void* PBHashTableAssign(PBHashTable*      ht,
                        usize             entsize,
                        PBHashTableHashFn hashfn,
                        PBHashTableEqFn   eqfn,
                        const void*       keyEntry,
                        bool*             added);

PBHashTableAssign returns a pointer to the entry, or NULL if out of memory. If an entry equivalent to keyent is found, *added is set to false. Otherwise a new entry is inserted and keyent is copied to it, *added is true.

PBHashTableLookup

void* PBHashTableLookup(const PBHashTable* ht,
                        usize              entsize,
                        PBHashTableHashFn  hashfn,
                        PBHashTableEqFn    eqfn,
                        const void*        keyEntry);

PBHashTableLookup returns a pointer to an entry equivalent to keyent, or NULL if not found.

PBHashTableDelete

bool PBHashTableDelete(PBHashTable*      ht,
                       usize             entsize,
                       PBHashTableHashFn hashfn,
                       PBHashTableEqFn   eqfn,
                       const void*       keyent);

PBHashTableDelete removes an entry equivalent to keyent.

Optimization detail: if keyent is a pointer to an entry in ht, for example from PBHashTableLookup, no additional lookup is performed internally.

PBHashTableIter

#define PBHashTableIter(ht, entryp)

PBHashTableIter iterates over entries of a hash table (in undefined order.) To begin iteration, set entryp=NULL. Example: for (const MyEntry entry = NULL; PBHashTableIter(&ht, &entry);) { print(">> %u", entry->value); bool PBHashTableIter(const PBHashTable* ht, T** entryp)

PBHashTableIterx

bool PBHashTableIterx(const PBHashTable* ht,
                      usize              entsize,
                      const void*        entryp);

PBHashTableIterx advances iteration of ht in unspecified order.

Set *entryp = NULL before first call. Returns false when iteration is complete.


#include <playbit/pool.h>

PBPool maps data to dense indices. It's like a slab allocator that uses u32 integers as addresses. Think "file descriptor allocator" rather than "virtual-memory allocator." Tries to be cache friendly by using the smallest free index during allocation.

Note: PBSlotTable (slot_table.h) may be a more fitting container if you need stable addresses (pointers) for entries. Pointers to entries of a PBPool are only valid until the next modification of the pool.

PBPool

typedef struct PBPool {
    u32 cap;      // capacity, a multiple of 64
    u32 maxidx;   // max allocated index
    u64 freebm[]; // bitmap; bit=1 means entries[bit] is free
    // TYPE entries[];
} PBPool;

PBPoolCreate

bool PBPoolCreate(PBPool* pp,
                  usize   elemSize,
                  PBMem   ma,
                  u32     cap);

PBPoolCreate creates a new pool. *pp is assumed to be NULL.

PBPoolFree

void PBPoolFree(PBPool* p,
                int     ma);

PBPoolFree recycles the memory of p back to memory allocator ma.

PBPoolEntryAlloc

void* PBPoolEntryAlloc(PBPool* pp,
                       usize   elemSize,
                       int     ma,
                       u32*    idxOut);

PBPoolEntryAlloc allocates an entry with the lowest index in the pool *pp. If the pool is full, the pool's memory at *pp is resized (and likely moved). The returned pointer (address) is valid until the next modification of the pool. Use PBPoolEntryFree to recycle an allocated entry.

PBPoolEntryAllocIfRoom

void* PBPoolEntryAllocIfRoom(PBPool* p,
                             usize   elemSize,
                             int     ma,
                             u32*    idxOut);

PBPoolEntryAllocIfRoom allocates an entry with the lowest index in the pool *pp. The returned pointer (address) is valid until the next modification of the pool. Use PBPoolEntryFree to recycle an allocated entry.

PBPoolEntryFree

void PBPoolEntryFree(PBPool* p,
                     u32     idx);

PBPoolEntryFree frees the entry at idx. Panics if idx is out of bounds or points to an already free entry.

PBPoolEntryFreeAll

void PBPoolEntryFreeAll(PBPool* p);

PBPoolEntryFreeAll frees all entries of the pool in one very cheap operation.

PBPoolEntryIsFree

bool PBPoolEntryIsFree(const PBPool* p,
                       u32           idx);

PBPoolEntryIsFree returns true when idx currently refers to a free slot.

PBPoolEntries

u8* PBPoolEntries(const PBPool* p);

PBPoolEntries returns a pointer to the array of entries. You can index directly into this with: MyEntry* entry = &((MyEntry*)PBPoolEntries(p))[idx-1] The returned array is valid until the next modification of the pool.

PBPoolEntry

void* PBPoolEntry(const PBPool* p,
                  usize         elemSize,
                  u32           idx);

PBPoolEntry accesses entry with index idx. Panics if idx is out of bounds.

PBPoolFindEntry

u32 PBPoolFindEntry(const PBPool* p,
                    usize         elemSize,
                    const void*   entryPtr);

PBPoolFindEntry performs a reverse lookup, finding the idx for an entry with identical bytes of memory as the memory at entryPtr. Basically a linear scan with memcmp.

PBPoolIdxIsDead

bool PBPoolIdxIsDead(const PBPool* p,
                     u32           idx);

PBPoolIdxIsDead reports whether idx has never been allocated in the current lifetime of p


#include <playbit/slot_table.h>

PBSlotTable maps data to dense indices. It's like a slab allocator that uses u32 integers as addresses. Think "file descriptor allocator" rather than "virtual-memory allocator."

Tries to be cache friendly by using the smallest free index during allocation.

PBSlotTable is an evolution of PBPool with the main difference being stable pointers, i.e. a pointer returned by PBSlotTableGet remains valid for the lifetime of the table, even when the table grows. PBPool does not have the same guarantee.

PBSlotTableCreate

#define PBSlotTableCreate(T, ma, cap)

PBSlotTableCreate creates a new table with initial capacity for cap entries of elemSize size.

Note that the table is implemented as a list of blocks of entries, each holding cap entries. This means that cap should be a reasonably large number. cap will be rounded up to the nearest multiple of 64.

PBSlotTable* nullable PBSlotTableCreate(type T, PBMem ma, u32 cap)

PBSlotTableFree

void PBSlotTableFree(PBSlotTable* table,
                     PBMem        ma);

PBSlotTableFree frees table back to memory allocator ma

PBSlotTableAdd

#define PBSlotTableAdd(T, table, ma, idxOut)

PBSlotTableAdd allocates an entry with the lowest index in the table.

On success, the returned memory region is zeroed and guaranteed to remain valid until either the entry is freed by a call to PBSlotTableDel, the table is cleared with PBSlotTableClear or the table is freed. I.e. even when the table grows, to accommodate more entires, the address of existing entries remain valid. This is a really useful invariant when you want to hold on to pointers.

T PBSlotTableAdd(type T, PBSlotTable* table, PBMem ma, u32* idxOut)

PBSlotTableDel

void PBSlotTableDel(PBSlotTable* table,
                    u32          idx);

PBSlotTableDel frees the entry at idx.

PBSlotTableGet

#define PBSlotTableGet(T, table, idx)

PBSlotTableGet accesses entry with index idx.

T* PBSlotTableGet(type T, PBSlotTable* table, u32 idx)

PBSlotTableIsUsed

bool PBSlotTableIsUsed(PBSlotTable* table,
                       u32          idx);

PBSlotTableIsUsed returns true if entry at idx is in use (i.e. is not free.) Note: Returns true if idx is out of bounds (rather than panicing.)

PBSlotTableClear

void PBSlotTableClear(PBSlotTable* table);

PBSlotTableClear frees all entries in one efficient operation.

PBSlotTableBlock

struct PBSlotTableBlock {
    PBSlotTableBlock* nullable next;
    u8                         entries[];
};

PBSlotTable

struct PBSlotTable {
    u32              cap;      // capacity of entire table
    u32              blockCap; // capacity of one block
    u32              maxidx;   // max allocated index
    u64*             freebm;   // bitmap; bit=1 means entries[bit] is free
    PBSlotTableBlock block;
};

PBSlotTableCreate1

PBSlotTable* PBSlotTableCreate1(usize elemSize,
                                PBMem ma,
                                u32   cap);

PBSlotTableCreate1 is the size-based worker behind PBSlotTableCreate.

PBSlotTableAdd1

void* PBSlotTableAdd1(PBSlotTable* table,
                      usize        elemSize,
                      PBMem        ma,
                      u32*         idxOut);

PBSlotTableAdd1 is the size-based worker behind PBSlotTableAdd.

PBSlotTableGet1

void* PBSlotTableGet1(PBSlotTable* table,
                      usize        elemSize,
                      u32          idx);

PBSlotTableGet1 is the size-based worker behind PBSlotTableGet.


#include <playbit/queue.h>

A ring buffer, aka circular buffer aka FIFO. Note: PBQueue is not thread safe; single producer, single consumer only.

PBQueueAny

typedef PBQueue(void) PBQueueAny;

PBQueueAnyInit

PBSysErr PBQueueAnyInit(PBQueueAny* q,
                        u32         entrySize,
                        PBMem       ma,
                        u32         cap);

PBQueueAnyInit initializes q with usable capacity cap entries of size entrySize.

PBQueueAnyFree

void PBQueueAnyFree(PBQueueAny* q,
                    PBMem       ma);

PBQueueAnyFree releases storage owned by q.

PBQueueAnyLen

u32 PBQueueAnyLen(const PBQueueAny* q);

PBQueueAnyLen returns number of queued entries currently available to pop/remove.

PBQueueAnyPushIfRoom

void* PBQueueAnyPushIfRoom(PBQueueAny* q,
                           u32         entrySize);

PBQueueAnyPushIfRoom reserves one entry slot at tail without growing q.

PBQueueAnyPush

void* PBQueueAnyPush(PBQueueAny* q,
                     u32         entrySize,
                     PBMem       ma);

PBQueueAnyPush reserves one entry slot at tail, growing q when necessary.

PBQueueAnyPop

void* PBQueueAnyPop(PBQueueAny* q,
                    u32         entrySize);

PBQueueAnyPop removes one entry from head and returns pointer to its storage.

PBQueueAnyPopMany

u32 PBQueueAnyPopMany(PBQueueAny* q,
                      u32         entrySize,
                      void*       dst,
                      u32         dstCap);

PBQueueAnyPopMany pops up to dstCap entries from head into dst.

PBQueueAnyRemove

u32 PBQueueAnyRemove(PBQueueAny* q,
                     u32         limit);

PBQueueAnyRemove removes up to limit newest entries from tail.

PBQueueIter

typedef struct PBQueueIter {
    u32 i;         // current index
    u32 remaining; // entries left
} PBQueueIter;

PBQueueAnyIterCreate

PBQueueIter PBQueueAnyIterCreate(const PBQueueAny* q,
                                 u32               entrySize);

PBQueueAnyIterCreate snapshots iteration state for q at this instant.

Later pushes or pops do not update this iterator; iteration walks the queued entries visible when the iterator was created.

PBQueueAnyIterNext

void* PBQueueAnyIterNext(const PBQueueAny* q,
                         PBQueueIter*      it,
                         u32               entrySize);

#include <playbit/vector.h>

Multi-dimensional vector types with SIMD acceleration.

These types are special N dimensional vector types which directly maps to target-CPU-agnostic SIMD types. They enables efficient SIMD operations and is usable in general-purpose code.

Vector types may not be available for all compilation targets: PB_HAS_VECTOR_TYPES is set to 1 if vector types are supported, 0 if not.

These types allow element access via:

StaticExpect(PB_HAS_VECTOR_TYPES, "vector type support");
PBF32x4 v = {1.1, 2.2, 3.3, 4.4};
expect(v.x == 1.1f); expect(v[0] == 1.1f);
expect(v.y == 2.2f); expect(v[1] == 2.2f);
expect(v.z == 3.3f); expect(v[2] == 3.3f);
expect(v.w == 4.4f); expect(v[3] == 4.4f);

Note that all these types have at least 16 byte alignment. Use alignof(T or expr) to access actual alignment.

PBU16x4

typedef u16 __attribute__((ext_vector_type(4))) PBU16x4;

PBF32x2

typedef f32 __attribute__((ext_vector_type(2))) PBF32x2;

PBF32x3

typedef f32 __attribute__((ext_vector_type(3))) PBF32x3;

PBF32x4

typedef f32 __attribute__((ext_vector_type(4))) PBF32x4;

PBF32x6

typedef f32 __attribute__((ext_vector_type(6))) PBF32x6;

PBF32x8

typedef f32 __attribute__((ext_vector_type(8))) PBF32x8;

PBF32x16

typedef f32 __attribute__((ext_vector_type(16))) PBF32x16;

PBF32x32

typedef f32 __attribute__((ext_vector_type(32))) PBF32x32;

PBF32x64

typedef f32 __attribute__((ext_vector_type(64))) PBF32x64;

PBF16x2

typedef f16 __attribute__((ext_vector_type(2))) PBF16x2;

PBF16x3

typedef f16 __attribute__((ext_vector_type(3))) PBF16x3;

PBF16x4

typedef f16 __attribute__((ext_vector_type(4))) PBF16x4;

PBF16x6

typedef f16 __attribute__((ext_vector_type(6))) PBF16x6;

PBF16x8

typedef f16 __attribute__((ext_vector_type(8))) PBF16x8;

PBF16x16

typedef f16 __attribute__((ext_vector_type(16))) PBF16x16;

PBF16x32

typedef f16 __attribute__((ext_vector_type(32))) PBF16x32;

PBF16x64

typedef f16 __attribute__((ext_vector_type(64))) PBF16x64;

PBF16x128

typedef f16 __attribute__((ext_vector_type(128))) PBF16x128;