Skip to content

Instantly share code, notes, and snippets.

@jpcy
Created May 21, 2014 10:19
Show Gist options
  • Save jpcy/b37a344dcc8a1bfe44c3 to your computer and use it in GitHub Desktop.
Save jpcy/b37a344dcc8a1bfe44c3 to your computer and use it in GitHub Desktop.
/* stb-2.23 - Sean's Tool Box -- public domain -- http://nothings.org/stb.h
no warranty is offered or implied; use this code at your own risk
This is a single header file with a bunch of useful utilities
for getting stuff done in C/C++.
Email bug reports, feature requests, etc. to 'sean' at the same site.
Documentation: http://nothings.org/stb/stb_h.html
Unit tests: http://nothings.org/stb/stb.c
============================================================================
You MUST
#define STB_DEFINE
in EXACTLY _one_ C or C++ file that includes this header, BEFORE the
include, like this:
#define STB_DEFINE
#include "stb.h"
All other files should just #include "stb.h" without the #define.
============================================================================
Version History
2.23 fix 2.22
2.22 64-bit fixes from '!='; fix stb_sdict_copy() to have preferred name
2.21 utf-8 decoder rejects "overlong" encodings; attempted 64-bit improvements
2.20 fix to hash "copy" function--reported by someone with handle "!="
2.19 ???
2.18 stb_readdir_subdirs_mask
2.17 stb_cfg_dir
2.16 fix stb_bgio_, add stb_bgio_stat(); begin a streaming wrapper
2.15 upgraded hash table template to allow:
- aggregate keys (explicit comparison func for EMPTY and DEL keys)
- "static" implementations (so they can be culled if unused)
2.14 stb_mprintf
2.13 reduce identifiable strings in STB_NO_STB_STRINGS
2.12 fix STB_ONLY -- lots of uint32s, TRUE/FALSE things had crept in
2.11 fix bug in stb_dirtree_get() which caused "c://path" sorts of stuff
2.10 STB_F(), STB_I() inline constants (also KI,KU,KF,KD)
2.09 stb_box_face_vertex_axis_side
2.08 bugfix stb_trimwhite()
2.07 colored printing in windows (why are we in 1985?)
2.06 comparison functions are now functions-that-return-functions and
accept a struct-offset as a parameter (not thread-safe)
2.05 compile and pass tests under Linux (but no threads); thread cleanup
2.04 stb_cubic_bezier_1d, smoothstep, avoid dependency on registry
2.03 ?
2.02 remove integrated documentation
2.01 integrate various fixes; stb_force_uniprocessor
2.00 revised stb_dupe to use multiple hashes
1.99 stb_charcmp
1.98 stb_arr_deleten, stb_arr_insertn
1.97 fix stb_newell_normal()
1.96 stb_hash_number()
1.95 hack stb__rec_max; clean up recursion code to use new functions
1.94 stb_dirtree; rename stb_extra to stb_ptrmap
1.93 stb_sem_new() API cleanup (no blockflag-starts blocked; use 'extra')
1.92 stb_threadqueue--multi reader/writer queue, fixed size or resizeable
1.91 stb_bgio_* for reading disk asynchronously
1.90 stb_mutex uses CRITICAL_REGION; new stb_sync primitive for thread
joining; workqueue supports stb_sync instead of stb_semaphore
1.89 support ';' in constant-string wildcards; stb_mutex wrapper (can
implement with EnterCriticalRegion eventually)
1.88 portable threading API (only for win32 so far); worker thread queue
1.87 fix wildcard handling in stb_readdir_recursive
1.86 support ';' in wildcards
1.85 make stb_regex work with non-constant strings;
beginnings of stb_introspect()
1.84 (forgot to make notes)
1.83 whoops, stb_keep_if_different wasn't deleting the temp file
1.82 bring back stb_compress from stb_file.h for cmirror
1.81 various bugfixes, STB_FASTMALLOC_INIT inits FASTMALLOC in release
1.80 stb_readdir returns utf8; write own utf8-utf16 because lib was wrong
1.79 stb_write
1.78 calloc() support for malloc wrapper, STB_FASTMALLOC
1.77 STB_FASTMALLOC
1.76 STB_STUA - Lua-like language; (stb_image, stb_csample, stb_bilinear)
1.75 alloc/free array of blocks; stb_hheap bug; a few stb_ps_ funcs;
hash*getkey, hash*copy; stb_bitset; stb_strnicmp; bugfix stb_bst
1.74 stb_replaceinplace; use stdlib C function to convert utf8 to UTF-16
1.73 fix performance bug & leak in stb_ischar (C++ port lost a 'static')
1.72 remove stb_block, stb_block_manager, stb_decompress (to stb_file.h)
1.71 stb_trimwhite, stb_tokens_nested, etc.
1.70 back out 1.69 because it might problemize mixed builds; stb_filec()
1.69 (stb_file returns 'char *' in C++)
1.68 add a special 'tree root' data type for stb_bst; stb_arr_end
1.67 full C++ port. (stb_block_manager)
1.66 stb_newell_normal
1.65 stb_lex_item_wild -- allow wildcard items which MUST match entirely
1.64 stb_data
1.63 stb_log_name
1.62 stb_define_sort; C++ cleanup
1.61 stb_hash_fast -- Paul Hsieh's hash function (beats Bob Jenkins'?)
1.60 stb_delete_directory_recursive
1.59 stb_readdir_recursive
1.58 stb_bst variant with parent pointer for O(1) iteration, not O(log N)
1.57 replace LCG random with Mersenne Twister (found a public domain one)
1.56 stb_perfect_hash, stb_ischar, stb_regex
1.55 new stb_bst API allows multiple BSTs per node (e.g. secondary keys)
1.54 bugfix: stb_define_hash, stb_wildmatch, regexp
1.53 stb_define_hash; recoded stb_extra, stb_sdict use it
1.52 stb_rand_define, stb_bst, stb_reverse
1.51 fix 'stb_arr_setlen(NULL, 0)'
1.50 stb_wordwrap
1.49 minor improvements to enable the scripting language
1.48 better approach for stb_arr using malloc; more invasive, clearer
1.47 stb_lex (lexes stb.h at 1.5ML/s on 3Ghz P4; 60/70% of optimal/flex)
1.46 stb_wrapper_*, STB_MALLOC_WRAPPER
1.45 lightly tested DFA acceleration of regexp searching
1.44 wildcard matching & searching; regexp matching & searching
1.43 stb_temp
1.42 allow stb_arr to use malloc/realloc; note this is global
1.41 make it compile in C++; (disable stb_arr in C++)
1.40 stb_dupe tweak; stb_swap; stb_substr
1.39 stb_dupe; improve stb_file_max to be less stupid
1.38 stb_sha1_file: generate sha1 for file, even > 4GB
1.37 stb_file_max; partial support for utf8 filenames in Windows
1.36 remove STB__NO_PREFIX - poor interaction with IDE, not worth it
streamline stb_arr to make it separately publishable
1.35 bugfixes for stb_sdict, malloc(0), stristr
1.34 (streaming interfaces for stb_compress)
1.33 stb_alloc; bug in stb_getopt; remove stb_overflow
1.32 (stb_compress returns, smaller&faster; encode window & 64-bit len)
1.31 stb_prefix_count
1.30 (STB__NO_PREFIX - remove stb_ prefixes for personal projects)
1.29 stb_fput_varlen64, etc.
1.28 stb_sha1
1.27 ?
1.26 stb_extra
1.25 ?
1.24 stb_copyfile
1.23 stb_readdir
1.22 ?
1.21 ?
1.20 ?
1.19 ?
1.18 ?
1.17 ?
1.16 ?
1.15 stb_fixpath, stb_splitpath, stb_strchr2
1.14 stb_arr
1.13 ?stb, stb_log, stb_fatal
1.12 ?stb_hash2
1.11 miniML
1.10 stb_crc32, stb_adler32
1.09 stb_sdict
1.08 stb_bitreverse, stb_ispow2, stb_big32
stb_fopen, stb_fput_varlen, stb_fput_ranged
stb_fcmp, stb_feq
1.07 (stb_encompress)
1.06 stb_compress
1.05 stb_tokens, (stb_hheap)
1.04 stb_rand
1.03 ?(s-strings)
1.02 ?stb_filelen, stb_tokens
1.01 stb_tolower
1.00 stb_hash, stb_intcmp
stb_file, stb_stringfile, stb_fgets
stb_prefix, stb_strlower, stb_strtok
stb_image
(stb_array), (stb_arena)
Parenthesized items have since been removed.
*/
#ifndef STB__INCLUDE_STB_H
#define STB__INCLUDE_STB_H
#include <stdlib.h>
#include <string.h>
#ifdef __cplusplus
#define STB_EXTERN extern "C"
#else
#define STB_EXTERN extern
#endif
#define stb_min(a,b) ((a) < (b) ? (a) : (b))
//////////////////////////////////////////////////////////////////////////////
//
// stb_arr
//
// An stb_arr is directly useable as a pointer (use the actual type in your
// definition), but when it resizes, it returns a new pointer and you can't
// use the old one, so you have to be careful to copy-in-out as necessary.
//
// Use a NULL pointer as a 0-length array.
//
// float *my_array = NULL, *temp;
//
// // add elements on the end one at a time
// stb_arr_push(my_array, 0.0f);
// stb_arr_push(my_array, 1.0f);
// stb_arr_push(my_array, 2.0f);
//
// assert(my_array[1] == 2.0f);
//
// // add an uninitialized element at the end, then assign it
// *stb_arr_add(my_array) = 3.0f;
//
// // add three uninitialized elements at the end
// temp = stb_arr_addn(my_array,3);
// temp[0] = 4.0f;
// temp[1] = 5.0f;
// temp[2] = 6.0f;
//
// assert(my_array[5] == 5.0f);
//
// // remove the last one
// stb_arr_pop(my_array);
//
// assert(stb_arr_len(my_array) == 6);
#ifdef STB_MALLOC_WRAPPER
#define STB__PARAMS , char *file, int line
#define STB__ARGS , file, line
#else
#define STB__PARAMS
#define STB__ARGS
#endif
// calling this function allocates an empty stb_arr attached to p
// (whereas NULL isn't attached to anything)
STB_EXTERN void stb_arr_malloc(void **target, void *context);
// call this function with a non-NULL value to have all successive
// stbs that are created be attached to the associated parent. Note
// that once a given stb_arr is non-empty, it stays attached to its
// current parent, even if you call this function again.
// it turns the previous value, so you can restore it
STB_EXTERN void* stb_arr_malloc_parent(void *p);
// simple functions written on top of other functions
#define stb_arr_empty(a) ( stb_arr_len(a) == 0 )
#define stb_arr_add(a) ( stb_arr_addn((a),1) )
#define stb_arr_push(a,v) ( *stb_arr_add(a)=(v) )
typedef struct
{
int len, limit;
unsigned int signature;
} stb__arr;
#define stb_arr_signature 0x51bada7b // ends with 0123 in decimal
// access the header block stored before the data
#define stb_arrhead(a) /*lint --e(826)*/ (((stb__arr *) (a)) - 1)
#define stb_arrhead2(a) /*lint --e(826)*/ (((stb__arr *) (a)) - 1)
#ifdef STB_DEBUG
#define stb_arr_check(a) assert(!a || stb_arrhead(a)->signature == stb_arr_signature)
#define stb_arr_check2(a) assert(!a || stb_arrhead2(a)->signature == stb_arr_signature)
#else
#define stb_arr_check(a) 0
#define stb_arr_check2(a) 0
#endif
// ARRAY LENGTH
// get the array length; special case if pointer is NULL
#define stb_arr_len(a) (a ? stb_arrhead(a)->len : 0)
#define stb_arr_len2(a) ((stb__arr *) (a) ? stb_arrhead2(a)->len : 0)
#define stb_arr_lastn(a) (stb_arr_len(a)-1)
// check whether a given index is valid -- tests 0 <= i < stb_arr_len(a)
#define stb_arr_valid(a,i) (a ? (int) (i) < stb_arrhead(a)->len : 0)
// change the array length so is is exactly N entries long, creating
// uninitialized entries as needed
#define stb_arr_setlen(a,n) \
(stb__arr_setlen((void **) &(a), sizeof(a[0]), (n)))
// change the array length so that N is a valid index (that is, so
// it is at least N entries long), creating uninitialized entries as needed
#define stb_arr_makevalid(a,n) \
(stb_arr_len(a) < (n)+1 ? stb_arr_setlen(a,(n)+1),(a) : (a))
// remove the last element of the array, returning it
#define stb_arr_pop(a) ((stb_arr_check(a), (a))[--stb_arrhead(a)->len])
// access the last element in the array
#define stb_arr_last(a) ((stb_arr_check(a), (a))[stb_arr_len(a)-1])
// is iterator at end of list?
#define stb_arr_end(a,i) ((i) >= &(a)[stb_arr_len(a)])
// (internal) change the allocated length of the array
#define stb_arr__grow(a,n) (stb_arr_check(a), stb_arrhead(a)->len += (n))
// add N new unitialized elements to the end of the array
#define stb_arr__addn(a,n) /*lint --e(826)*/ \
((stb_arr_len(a)+(n) > stb_arrcurmax(a)) \
? (stb__arr_addlen((void **) &(a),sizeof(*a),(n)),0) \
: ((stb_arr__grow(a,n), 0)))
// add N new unitialized elements to the end of the array, and return
// a pointer to the first new one
#define stb_arr_addn(a,n) (stb_arr__addn((a),n),(a)+stb_arr_len(a)-(n))
// add N new uninitialized elements starting at index 'i'
#define stb_arr_insertn(a,i,n) (stb__arr_insertn((void **) &(a), sizeof(*a), i, n))
// insert an element at i
#define stb_arr_insert(a,i,v) (stb__arr_insertn((void **) &(a), sizeof(*a), i, n), ((a)[i] = v))
// delete N elements from the middle starting at index 'i'
#define stb_arr_deleten(a,i,n) (stb__arr_deleten((void **) &(a), sizeof(*a), i, n))
// delete the i'th element
#define stb_arr_delete(a,i) stb_arr_deleten(a,i,1)
// delete the i'th element, swapping down from the end
#define stb_arr_fastdelete(a,i) \
(stb_swap(&a[i], &a[stb_arrhead(a)->len-1], sizeof(*a)), stb_arr_pop(a))
// ARRAY STORAGE
// get the array maximum storage; special case if NULL
#define stb_arrcurmax(a) (a ? stb_arrhead(a)->limit : 0)
#define stb_arrcurmax2(a) (a ? stb_arrhead2(a)->limit : 0)
// set the maxlength of the array to n in anticipation of further growth
#define stb_arr_setsize(a,n) (stb_arr_check(a), stb__arr_setsize((void **) &(a),sizeof((a)[0]),n))
// make sure maxlength is large enough for at least N new allocations
#define stb_arr_atleast(a,n) (stb_arr_len(a)+(n) > stb_arrcurmax(a) \
? stb_arr_setsize((a), (n)) : 0)
// make a copy of a given array (copies contents via 'memcpy'!)
#define stb_arr_copy(a) stb__arr_copy(a, sizeof((a)[0]))
// compute the storage needed to store all the elements of the array
#define stb_arr_storage(a) (stb_arr_len(a) * sizeof((a)[0]))
#define stb_arr_for(v,arr) for((v)=(arr); (v) < (arr)+stb_arr_len(arr); ++(v))
// IMPLEMENTATION
STB_EXTERN void stb_arr_free_(void **p);
STB_EXTERN void *stb__arr_copy_(void *p, int elem_size);
STB_EXTERN void stb__arr_setsize_(void **p, int size, int limit STB__PARAMS);
STB_EXTERN void stb__arr_setlen_(void **p, int size, int newlen STB__PARAMS);
STB_EXTERN void stb__arr_addlen_(void **p, int size, int addlen STB__PARAMS);
STB_EXTERN void stb__arr_deleten_(void **p, int size, int loc, int n STB__PARAMS);
STB_EXTERN void stb__arr_insertn_(void **p, int size, int loc, int n STB__PARAMS);
#define stb_arr_free(p) stb_arr_free_((void **) &(p))
#define stb__arr_copy stb__arr_copy_
#ifndef STB_MALLOC_WRAPPER
#define stb__arr_setsize stb__arr_setsize_
#define stb__arr_setlen stb__arr_setlen_
#define stb__arr_addlen stb__arr_addlen_
#define stb__arr_deleten stb__arr_deleten_
#define stb__arr_insertn stb__arr_insertn_
#else
#define stb__arr_addlen(p,s,n) stb__arr_addlen_(p,s,n,__FILE__,__LINE__)
#define stb__arr_setlen(p,s,n) stb__arr_setlen_(p,s,n,__FILE__,__LINE__)
#define stb__arr_setsize(p,s,n) stb__arr_setsize_(p,s,n,__FILE__,__LINE__)
#define stb__arr_deleten(p,s,i,n) stb__arr_deleten_(p,s,i,n,__FILE__,__LINE__)
#define stb__arr_insertn(p,s,i,n) stb__arr_insertn_(p,s,i,n,__FILE__,__LINE__)
#endif
#ifdef STB_DEFINE
static void * stb__arr_malloc(int size)
{
return malloc(size);
}
void * stb__arr_copy_(void *p, int elem_size)
{
stb__arr *q;
if (p == NULL) return p;
q = (stb__arr *) stb__arr_malloc(sizeof(*q) + elem_size * stb_arrhead2(p)->limit);
stb_arr_check2(p);
memcpy(q, stb_arrhead2(p), sizeof(*q) + elem_size * stb_arrhead2(p)->len);
return q+1;
}
void stb_arr_free_(void **pp)
{
void *p = *pp;
stb_arr_check2(p);
if (p) {
stb__arr *q = stb_arrhead2(p);
free(q);
}
*pp = NULL;
}
static void stb__arrsize_(void **pp, int size, int limit, int len STB__PARAMS)
{
void *p = *pp;
stb__arr *a;
stb_arr_check2(p);
if (p == NULL) {
if (len == 0 && size == 0) return;
a = (stb__arr *) stb__arr_malloc(sizeof(*a) + size*limit);
a->limit = limit;
a->len = len;
a->signature = stb_arr_signature;
} else {
a = stb_arrhead2(p);
a->len = len;
if (a->limit < limit) {
void *p;
if (a->limit >= 4 && limit < a->limit * 2)
limit = a->limit * 2;
#ifdef STB_MALLOC_WRAPPER
p = stb__realloc(a, sizeof(*a) + limit*size, file, line);
#else
p = realloc(a, sizeof(*a) + limit*size);
#endif
if (p) {
a = (stb__arr *) p;
a->limit = limit;
} else {
// throw an error!
}
}
}
a->len = stb_min(a->len, a->limit);
*pp = a+1;
}
void stb__arr_setsize_(void **pp, int size, int limit STB__PARAMS)
{
void *p = *pp;
stb_arr_check2(p);
stb__arrsize_(pp, size, limit, stb_arr_len2(p) STB__ARGS);
}
void stb__arr_setlen_(void **pp, int size, int newlen STB__PARAMS)
{
void *p = *pp;
stb_arr_check2(p);
if (stb_arrcurmax2(p) < newlen || p == NULL) {
stb__arrsize_(pp, size, newlen, newlen STB__ARGS);
} else {
stb_arrhead2(p)->len = newlen;
}
}
void stb__arr_addlen_(void **p, int size, int addlen STB__PARAMS)
{
stb__arr_setlen_(p, size, stb_arr_len2(*p) + addlen STB__ARGS);
}
void stb__arr_insertn_(void **pp, int size, int i, int n STB__PARAMS)
{
void *p = *pp;
if (n) {
int z;
if (p == NULL) {
stb__arr_addlen_(pp, size, n STB__ARGS);
return;
}
z = stb_arr_len2(p);
stb__arr_addlen_(&p, size, i STB__ARGS);
memmove((char *) p + (i+n)*size, (char *) p + i*size, size * (z-i));
}
*pp = p;
}
void stb__arr_deleten_(void **pp, int size, int i, int n STB__PARAMS)
{
void *p = *pp;
if (n) {
memmove((char *) p + i*size, (char *) p + (i+n)*size, size * (stb_arr_len2(p)-i));
stb_arrhead2(p)->len -= n;
}
*pp = p;
}
#endif
#endif // STB_INCLUDE_STB_H
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment