Created
May 21, 2014 10:19
-
-
Save jpcy/b37a344dcc8a1bfe44c3 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* 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