Skip to content

Instantly share code, notes, and snippets.

@schellingb
Created February 13, 2019 17:08
Show Gist options
  • Save schellingb/2b6e54383a58ae6eb2684cadd74a9797 to your computer and use it in GitHub Desktop.
Save schellingb/2b6e54383a58ae6eb2684cadd74a9797 to your computer and use it in GitHub Desktop.
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#define BufLen(b) ((b) ? _Buf__Hdr(b)->len : 0)
#define BufCap(b) ((b) ? _Buf__Hdr(b)->cap : 0)
#define BufEnd(b) ((b) ? (b)+_Buf__Hdr(b)->len : NULL)
#define BufFree(b) ((b) ? (free(_Buf__Hdr(b)), (void)((b) = NULL)) : (void)0)
#define BufClear(b) ((b) ? _Buf__Hdr(b)->len = 0 : (void)0)
#define BufFit(b, n) ((b) && (n) <= _Buf__Hdr(b)->cap ? (b) : (*(void**)(&(b)) = _Buf__Grow(b, n, _Buf__TypeSize(b))))
#define BufPush(b, v) (BufFit(b, BufLen(b) + (1)), (b)[_Buf__Hdr(b)->len] = (v), (b)+(_Buf__Hdr(b)->len++))
#define BufAddUninit(b, n) (BufFit(b, BufLen(b) + (n)), (b)+(_Buf__Hdr(b)->len += (n))-(n))
#define BufAddZeroed(b, n) (BufFit(b, BufLen(b) + (n)), memset((b)+_Buf__Hdr(b)->len, 0, (n)*sizeof(*(b))), (b)+(_Buf__Hdr(b)->len += (n))-(n))
#define BufMakeGap(b, i, n) (BufFit(b, BufLen(b) + (n)), memmove((b)+(i)+(n), (b)+(i), (char*)((b)+_Buf__Hdr(b)->len)-(char*)((b)+(i))), _Buf__Hdr(b)->len += (n), (b)+(i))
#define BufSizeOf(b) (BufLen(b) * sizeof(*b))
struct BufHdr { size_t len; size_t cap; };
#define _Buf__Hdr(b) (((struct BufHdr*)(b))-1)
#define _Buf__TypeSize(b) sizeof(*(b))
#if defined(_MSC_VER) && _MSC_VER >= 1800 && defined(__cplusplus) && !defined(NDEBUG)
#undef _Buf__TypeSize //A template for natvis debug watch helpers in Visual Studio
template<typename T> struct BUFDBG { typedef T type; enum { size = sizeof(T) }; };
template<typename T> struct BUFDBG<T&> { typedef T noref; };
#define _Buf__TypeSize(b) BUFDBG<BUFDBG<decltype(*(b))>::noref>::size
#endif
void *_Buf__Grow(const void *buf, size_t new_len, size_t elem_size)
{
size_t cap2 = BufCap(buf) * 2, new_cap = (cap2 < 16 || new_len < 16 ? 16 : (cap2 < new_len ? new_len : cap2));
assert(new_len <= new_cap && BufCap(buf) <= ((size_t)~0-1)/2 && new_cap <= ((size_t)~0-sizeof(struct BufHdr))/elem_size);
size_t new_size = sizeof(struct BufHdr) + new_cap*elem_size;
struct BufHdr *new_hdr = (struct BufHdr*)realloc((buf ? _Buf__Hdr(buf) : NULL), new_size);
if (!cap2) new_hdr->len = 0;
new_hdr->cap = new_cap;
return new_hdr+1;
}
#include <stdio.h>
int main()
{
short *buf = NULL;
BufAddZeroed(buf, 1);
*BufAddUninit(buf, 1) = 2;
BufPush(buf, 3);
*BufMakeGap(buf, 1, 1) = 1;
printf("Contents: %d, %d, %d, %d\n", buf[0], buf[1], buf[2], buf[3]); //Prints 'Contents: 0, 1, 2, 3'
printf("Length: %d - Capacity: %d - SizeOf: %d\n", (int)BufLen(buf), (int)BufCap(buf), (int)BufSizeOf(buf)); //Prints 'Length: 4 - Capacity: 16 - SizeOf: 8'
BufFree(buf);
printf("Length: %d - Capacity: %d - SizeOf: %d\n", (int)BufLen(buf), (int)BufCap(buf), (int)BufSizeOf(buf)); //Prints 'Length: 0 - Capacity: 0 - SizeOf: 0'
return 0;
}
/*
To use the debug visualizer for Visual Studio, add the definition below to a .natvis file.
Then during debugging, the data can be viewed with this watch expression: (BUFDBG<short>*)buf
<Type Name="BUFDBG&lt;*&gt;">
<DisplayString>{{ length={this ? (((_twfcBufHdr*)(this))-1)->len : 0}, capacity={this ? (((_twfcBufHdr*)(this))-1)->cap : 0} }}</DisplayString>
<Expand>
<Item Name="[length]">this ? (((_twfcBufHdr*)(this))-1)->len : 0</Item>
<Item Name="[capacity]">this ? (((_twfcBufHdr*)(this))-1)->cap : 0</Item>
<ArrayItems><Size>this ? (((_twfcBufHdr*)(this))-1)->len : 0</Size><ValuePointer>(((type*)(this)))</ValuePointer></ArrayItems>
</Expand>
</Type>
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment