1 /* stb.h - v2.28 - Sean's Tool Box -- public domain -- http://nothings.org/stb.h
2 no warranty is offered or implied; use this code at your own risk
4 This is a single header file with a bunch of useful utilities
5 for getting stuff done in C/C++.
7 Documentation: http://nothings.org/stb/stb_h.html
8 Unit tests: http://nothings.org/stb/stb.c
11 ============================================================================
16 in EXACTLY _one_ C or C++ file that includes this header, BEFORE the
22 All other files should just #include "stb.h" without the #define.
23 ============================================================================
28 2.28 various new functionality
29 2.27 test _WIN32 not WIN32 in STB_THREADS
30 2.26 various warning & bugfixes
31 2.25 various warning & bugfixes
32 2.24 various warning & bugfixes
34 2.22 64-bit fixes from '!='; fix stb_sdict_copy() to have preferred name
35 2.21 utf-8 decoder rejects "overlong" encodings; attempted 64-bit improvements
36 2.20 fix to hash "copy" function--reported by someone with handle "!="
38 2.18 stb_readdir_subdirs_mask
40 2.16 fix stb_bgio_, add stb_bgio_stat(); begin a streaming wrapper
41 2.15 upgraded hash table template to allow:
42 - aggregate keys (explicit comparison func for EMPTY and DEL keys)
43 - "static" implementations (so they can be culled if unused)
45 2.13 reduce identifiable strings in STB_NO_STB_STRINGS
46 2.12 fix STB_ONLY -- lots of uint32s, TRUE/FALSE things had crept in
47 2.11 fix bug in stb_dirtree_get() which caused "c://path" sorts of stuff
48 2.10 STB_F(), STB_I() inline constants (also KI,KU,KF,KD)
49 2.09 stb_box_face_vertex_axis_side
50 2.08 bugfix stb_trimwhite()
51 2.07 colored printing in windows (why are we in 1985?)
52 2.06 comparison functions are now functions-that-return-functions and
53 accept a struct-offset as a parameter (not thread-safe)
54 2.05 compile and pass tests under Linux (but no threads); thread cleanup
55 2.04 stb_cubic_bezier_1d, smoothstep, avoid dependency on registry
57 2.02 remove integrated documentation
58 2.01 integrate various fixes; stb_force_uniprocessor
59 2.00 revised stb_dupe to use multiple hashes
61 1.98 stb_arr_deleten, stb_arr_insertn
62 1.97 fix stb_newell_normal()
63 1.96 stb_hash_number()
64 1.95 hack stb__rec_max; clean up recursion code to use new functions
65 1.94 stb_dirtree; rename stb_extra to stb_ptrmap
66 1.93 stb_sem_new() API cleanup (no blockflag-starts blocked; use 'extra')
67 1.92 stb_threadqueue--multi reader/writer queue, fixed size or resizeable
68 1.91 stb_bgio_* for reading disk asynchronously
69 1.90 stb_mutex uses CRITICAL_REGION; new stb_sync primitive for thread
70 joining; workqueue supports stb_sync instead of stb_semaphore
71 1.89 support ';' in constant-string wildcards; stb_mutex wrapper (can
72 implement with EnterCriticalRegion eventually)
73 1.88 portable threading API (only for win32 so far); worker thread queue
74 1.87 fix wildcard handling in stb_readdir_recursive
75 1.86 support ';' in wildcards
76 1.85 make stb_regex work with non-constant strings;
77 beginnings of stb_introspect()
78 1.84 (forgot to make notes)
79 1.83 whoops, stb_keep_if_different wasn't deleting the temp file
80 1.82 bring back stb_compress from stb_file.h for cmirror
81 1.81 various bugfixes, STB_FASTMALLOC_INIT inits FASTMALLOC in release
82 1.80 stb_readdir returns utf8; write own utf8-utf16 because lib was wrong
84 1.78 calloc() support for malloc wrapper, STB_FASTMALLOC
86 1.76 STB_STUA - Lua-like language; (stb_image, stb_csample, stb_bilinear)
87 1.75 alloc/free array of blocks; stb_hheap bug; a few stb_ps_ funcs;
88 hash*getkey, hash*copy; stb_bitset; stb_strnicmp; bugfix stb_bst
89 1.74 stb_replaceinplace; use stdlib C function to convert utf8 to UTF-16
90 1.73 fix performance bug & leak in stb_ischar (C++ port lost a 'static')
91 1.72 remove stb_block, stb_block_manager, stb_decompress (to stb_file.h)
92 1.71 stb_trimwhite, stb_tokens_nested, etc.
93 1.70 back out 1.69 because it might problemize mixed builds; stb_filec()
94 1.69 (stb_file returns 'char *' in C++)
95 1.68 add a special 'tree root' data type for stb_bst; stb_arr_end
96 1.67 full C++ port. (stb_block_manager)
97 1.66 stb_newell_normal
98 1.65 stb_lex_item_wild -- allow wildcard items which MUST match entirely
101 1.62 stb_define_sort; C++ cleanup
102 1.61 stb_hash_fast -- Paul Hsieh's hash function (beats Bob Jenkins'?)
103 1.60 stb_delete_directory_recursive
104 1.59 stb_readdir_recursive
105 1.58 stb_bst variant with parent pointer for O(1) iteration, not O(log N)
106 1.57 replace LCG random with Mersenne Twister (found a public domain one)
107 1.56 stb_perfect_hash, stb_ischar, stb_regex
108 1.55 new stb_bst API allows multiple BSTs per node (e.g. secondary keys)
109 1.54 bugfix: stb_define_hash, stb_wildmatch, regexp
110 1.53 stb_define_hash; recoded stb_extra, stb_sdict use it
111 1.52 stb_rand_define, stb_bst, stb_reverse
112 1.51 fix 'stb_arr_setlen(NULL, 0)'
114 1.49 minor improvements to enable the scripting language
115 1.48 better approach for stb_arr using stb_malloc; more invasive, clearer
116 1.47 stb_lex (lexes stb.h at 1.5ML/s on 3Ghz P4; 60/70% of optimal/flex)
117 1.46 stb_wrapper_*, STB_MALLOC_WRAPPER
118 1.45 lightly tested DFA acceleration of regexp searching
119 1.44 wildcard matching & searching; regexp matching & searching
121 1.42 allow stb_arr to use stb_malloc/realloc; note this is global
122 1.41 make it compile in C++; (disable stb_arr in C++)
123 1.40 stb_dupe tweak; stb_swap; stb_substr
124 1.39 stb_dupe; improve stb_file_max to be less stupid
125 1.38 stb_sha1_file: generate sha1 for file, even > 4GB
126 1.37 stb_file_max; partial support for utf8 filenames in Windows
127 1.36 remove STB__NO_PREFIX - poor interaction with IDE, not worth it
128 streamline stb_arr to make it separately publishable
129 1.35 bugfixes for stb_sdict, stb_malloc(0), stristr
130 1.34 (streaming interfaces for stb_compress)
131 1.33 stb_alloc; bug in stb_getopt; remove stb_overflow
132 1.32 (stb_compress returns, smaller&faster; encode window & 64-bit len)
133 1.31 stb_prefix_count
134 1.30 (STB__NO_PREFIX - remove stb_ prefixes for personal projects)
135 1.29 stb_fput_varlen64, etc.
149 1.15 stb_fixpath, stb_splitpath, stb_strchr2
151 1.13 ?stb, stb_log, stb_fatal
154 1.10 stb_crc32, stb_adler32
156 1.08 stb_bitreverse, stb_ispow2, stb_big32
157 stb_fopen, stb_fput_varlen, stb_fput_ranged
159 1.07 (stb_encompress)
161 1.05 stb_tokens, (stb_hheap)
164 1.02 ?stb_filelen, stb_tokens
166 1.00 stb_hash, stb_intcmp
167 stb_file, stb_stringfile, stb_fgets
168 stb_prefix, stb_strlower, stb_strtok
170 (stb_array), (stb_arena)
172 Parenthesized items have since been removed.
176 This software is dual-licensed to the public domain and under the following
177 license: you are granted a perpetual, irrevocable license to copy, modify,
178 publish, and distribute this file as you see fit.
182 Written by Sean Barrett.
197 #ifndef STB__INCLUDE_STB_H
198 #define STB__INCLUDE_STB_H
200 #define STB_VERSION 1
202 #ifdef STB_INTROSPECT
206 #ifdef STB_DEFINE_THREADS
215 #if defined(_WIN32) && !defined(__MINGW32__)
216 #ifndef _CRT_SECURE_NO_WARNINGS
217 #define _CRT_SECURE_NO_WARNINGS
219 #ifndef _CRT_NONSTDC_NO_DEPRECATE
220 #define _CRT_NONSTDC_NO_DEPRECATE
222 #ifndef _CRT_NON_CONFORMING_SWPRINTFS
223 #define _CRT_NON_CONFORMING_SWPRINTFS
225 #if !defined(_MSC_VER) || _MSC_VER > 1700
226 #include <intrin.h> // _BitScanReverse
230 #include <stdlib.h> // stdlib could have min/max
231 #include <stdio.h> // need FILE
232 #include <string.h> // stb_define_hash needs memcpy/memset
233 #include <time.h> // stb_dirtree
235 #include <fcntl.h> // O_RDWR
244 #ifdef STB_MALLOC_WRAPPER_PAGED
245 #define STB_MALLOC_WRAPPER_DEBUG
247 #ifdef STB_MALLOC_WRAPPER_DEBUG
248 #define STB_MALLOC_WRAPPER
250 #ifdef STB_MALLOC_WRAPPER_FASTMALLOC
251 #define STB_FASTMALLOC
252 #define STB_MALLOC_WRAPPER
255 #ifdef STB_FASTMALLOC
257 #undef STB_FASTMALLOC
270 #include <io.h> // _mktemp
271 #include <direct.h> // _rmdir
273 #include <sys/types.h> // stat()/_stat()
274 #include <sys/stat.h> // stat()/_stat()
277 #define stb_min(a,b) ((a) < (b) ? (a) : (b))
278 #define stb_max(a,b) ((a) > (b) ? (a) : (b))
281 #if !defined(__cplusplus) && !defined(min) && !defined(max)
282 #define min(x,y) stb_min(x,y)
283 #define max(x,y) stb_max(x,y)
287 #define M_PI 3.14159265358979323846f
296 #define deg2rad(a) ((a)*(M_PI/180))
299 #define rad2deg(a) ((a)*(180/M_PI))
304 #define swap(TYPE,a,b) \
305 do { TYPE stb__t; stb__t = (a); (a) = (b); (b) = stb__t; } while (0)
309 typedef unsigned char uint8
;
310 typedef signed char int8
;
311 typedef unsigned short uint16
;
312 typedef signed short int16
;
313 #if defined(STB_USE_LONG_FOR_32_BIT_INT) || defined(STB_LONG32)
314 typedef unsigned long uint32
;
315 typedef signed long int32
;
317 typedef unsigned int uint32
;
318 typedef signed int int32
;
321 typedef unsigned char uchar
;
322 typedef unsigned short ushort
;
323 typedef unsigned int uint
;
324 typedef unsigned long ulong
;
326 // produce compile errors if the sizes aren't right
327 typedef char stb__testsize16
[sizeof(int16
)==2];
328 typedef char stb__testsize32
[sizeof(int32
)==4];
336 // if we're STB_ONLY, can't rely on uint32 or even uint, so all the
337 // variables we'll use herein need typenames prefixed with 'stb':
338 typedef unsigned char stb_uchar
;
339 typedef unsigned char stb_uint8
;
340 typedef unsigned int stb_uint
;
341 typedef unsigned short stb_uint16
;
342 typedef short stb_int16
;
343 typedef signed char stb_int8
;
344 #if defined(STB_USE_LONG_FOR_32_BIT_INT) || defined(STB_LONG32)
345 typedef unsigned long stb_uint32
;
346 typedef long stb_int32
;
348 typedef unsigned int stb_uint32
;
349 typedef int stb_int32
;
351 typedef char stb__testsize2_16
[sizeof(stb_uint16
)==2 ? 1 : -1];
352 typedef char stb__testsize2_32
[sizeof(stb_uint32
)==4 ? 1 : -1];
355 typedef unsigned __int64 stb_uint64
;
356 typedef __int64 stb_int64
;
357 #define STB_IMM_UINT64(literalui64) (literalui64##ui64)
358 #define STB_IMM_INT64(literali64) (literali64##i64)
361 typedef unsigned long long stb_uint64
;
362 typedef long long stb_int64
;
363 #define STB_IMM_UINT64(literalui64) (literalui64##ULL)
364 #define STB_IMM_INT64(literali64) (literali64##LL)
366 typedef char stb__testsize2_64
[sizeof(stb_uint64
)==8 ? 1 : -1];
368 // add platform-specific ways of checking for sizeof(char*) == 8,
369 // and make those define STB_PTR64
370 #if defined(_WIN64) || defined(__x86_64__) || defined(__ia64__) || defined(__LP64__)
375 typedef char stb__testsize2_ptr
[sizeof(char *) == 8];
376 typedef stb_uint64 stb_uinta
;
377 typedef stb_int64 stb_inta
;
379 typedef char stb__testsize2_ptr
[sizeof(char *) == 4];
380 typedef stb_uint32 stb_uinta
;
381 typedef stb_int32 stb_inta
;
383 typedef char stb__testsize2_uinta
[sizeof(stb_uinta
)==sizeof(char*) ? 1 : -1];
385 // if so, we should define an int type that is the pointer size. until then,
386 // we'll have to make do with this (which is not the same at all!)
396 #define STB_EXTERN extern "C"
398 #define STB_EXTERN extern
401 // check for well-known debug defines
402 #if defined(DEBUG) || defined(_DEBUG) || defined(DBG)
413 STB_EXTERN
void stb_wrapper_malloc(void *newp
, int sz
, char *file
, int line
);
414 STB_EXTERN
void stb_wrapper_free(void *oldp
, char *file
, int line
);
415 STB_EXTERN
void stb_wrapper_realloc(void *oldp
, void *newp
, int sz
, char *file
, int line
);
416 STB_EXTERN
void stb_wrapper_calloc(size_t num
, size_t sz
, char *file
, int line
);
417 STB_EXTERN
void stb_wrapper_listall(void (*func
)(void *ptr
, int sz
, char *file
, int line
));
418 STB_EXTERN
void stb_wrapper_dump(char *filename
);
419 STB_EXTERN
int stb_wrapper_allocsize(void *oldp
);
420 STB_EXTERN
void stb_wrapper_check(void *oldp
);
423 // this is a special function used inside malloc wrapper
424 // to do allocations that aren't tracked (to avoid
425 // reentrancy). Of course if someone _else_ wraps realloc,
426 // this breaks, but if they're doing that AND the malloc
427 // wrapper they need to explicitly check for reentrancy.
429 // only define realloc_raw() and we do realloc(NULL,sz)
430 // for malloc() and realloc(p,0) for free().
431 static void * stb__realloc_raw(void *p
, int sz
)
433 if (p
== NULL
) return malloc(sz
);
434 if (sz
== 0) { free(p
); return NULL
; }
435 return realloc(p
,sz
);
440 STB_EXTERN
void * stb_smalloc(size_t sz
);
441 STB_EXTERN
void stb_sfree(void *p
);
442 STB_EXTERN
void * stb_srealloc(void *p
, size_t sz
);
443 STB_EXTERN
void * stb_scalloc(size_t n
, size_t sz
);
444 STB_EXTERN
char * stb_sstrdup(char *s
);
447 #ifdef STB_FASTMALLOC
448 #define malloc stb_smalloc
449 #define free stb_sfree
450 #define realloc stb_srealloc
451 #define strdup stb_sstrdup
452 #define calloc stb_scalloc
455 #ifndef STB_MALLOC_ALLCHECK
456 #define stb__check(p) 1
458 #ifndef STB_MALLOC_WRAPPER
459 #error STB_MALLOC_ALLCHECK requires STB_MALLOC_WRAPPER
461 #define stb__check(p) stb_mcheck(p)
465 #ifdef STB_MALLOC_WRAPPER
466 STB_EXTERN
void * stb__malloc(int, char *, int);
467 STB_EXTERN
void * stb__realloc(void *, int, char *, int);
468 STB_EXTERN
void * stb__calloc(size_t n
, size_t s
, char *, int);
469 STB_EXTERN
void stb__free(void *, char *file
, int);
470 STB_EXTERN
char * stb__strdup(char *s
, char *file
, int);
471 STB_EXTERN
void stb_malloc_checkall(void);
472 STB_EXTERN
void stb_malloc_check_counter(int init_delay
, int rep_delay
);
473 #ifndef STB_MALLOC_WRAPPER_DEBUG
474 #define stb_mcheck(p) 1
476 STB_EXTERN
int stb_mcheck(void *);
482 #ifdef STB_MALLOC_WRAPPER_DEBUG
485 #define STB__SIG 0x51b01234
486 #define STB__FIXSIZE(sz) (((sz+3) & ~3) + STB__PAD)
487 #define STB__ptr(x,y) ((char *) (x) + (y))
489 #define STB__ptr(x,y) (x)
490 #define STB__FIXSIZE(sz) (sz)
493 #ifdef STB_MALLOC_WRAPPER_DEBUG
494 int stb_mcheck(void *p
)
497 if (p
== NULL
) return 1;
498 p
= ((char *) p
) - STB__BIAS
;
499 sz
= * (unsigned int *) p
;
500 assert(* (unsigned int *) STB__ptr(p
,4) == STB__SIG
);
501 assert(* (unsigned int *) STB__ptr(p
,8) == STB__SIG
);
502 assert(* (unsigned int *) STB__ptr(p
,12) == STB__SIG
);
503 assert(* (unsigned int *) STB__ptr(p
,sz
-4) == STB__SIG
+1);
504 assert(* (unsigned int *) STB__ptr(p
,sz
-8) == STB__SIG
+1);
505 assert(* (unsigned int *) STB__ptr(p
,sz
-12) == STB__SIG
+1);
506 assert(* (unsigned int *) STB__ptr(p
,sz
-16) == STB__SIG
+1);
507 stb_wrapper_check(STB__ptr(p
, STB__BIAS
));
511 static void stb__check2(void *p
, int sz
, char *file
, int line
)
516 void stb_malloc_checkall(void)
518 stb_wrapper_listall(stb__check2
);
521 void stb_malloc_checkall(void) { }
524 static int stb__malloc_wait
=(1 << 30), stb__malloc_next_wait
= (1 << 30), stb__malloc_iter
;
525 void stb_malloc_check_counter(int init_delay
, int rep_delay
)
527 stb__malloc_wait
= init_delay
;
528 stb__malloc_next_wait
= rep_delay
;
531 void stb_mcheck_all(void)
533 #ifdef STB_MALLOC_WRAPPER_DEBUG
535 if (--stb__malloc_wait
<= 0) {
536 stb_malloc_checkall();
537 stb__malloc_wait
= stb__malloc_next_wait
;
542 #ifdef STB_MALLOC_WRAPPER_PAGED
543 #define STB__WINDOWS_PAGE (1 << 12)
545 STB_EXTERN
__declspec(dllimport
) void * __stdcall
VirtualAlloc(void *p
, unsigned long size
, unsigned long type
, unsigned long protect
);
546 STB_EXTERN
__declspec(dllimport
) int __stdcall
VirtualFree(void *p
, unsigned long size
, unsigned long freetype
);
550 static void *stb__malloc_final(int sz
)
552 #ifdef STB_MALLOC_WRAPPER_PAGED
553 int aligned
= (sz
+ STB__WINDOWS_PAGE
- 1) & ~(STB__WINDOWS_PAGE
-1);
554 char *p
= VirtualAlloc(NULL
, aligned
+ STB__WINDOWS_PAGE
, 0x2000, 0x04); // RESERVE, READWRITE
555 if (p
== NULL
) return p
;
556 VirtualAlloc(p
, aligned
, 0x1000, 0x04); // COMMIT, READWRITE
563 static void stb__free_final(void *p
)
565 #ifdef STB_MALLOC_WRAPPER_PAGED
566 VirtualFree(p
, 0, 0x8000); // RELEASE
572 int stb__malloc_failure
;
573 static void *stb__realloc_final(void *p
, int sz
, int old_sz
)
575 #ifdef STB_MALLOC_WRAPPER_PAGED
576 void *q
= stb__malloc_final(sz
);
578 return ++stb__malloc_failure
, q
;
579 // @TODO: deal with p being smaller!
580 memcpy(q
, p
, sz
< old_sz
? sz
: old_sz
);
584 return realloc(p
,sz
);
588 void stb__free(void *p
, char *file
, int line
)
592 #ifdef STB_MALLOC_WRAPPER_DEBUG
595 stb_wrapper_free(p
,file
,line
);
596 #ifdef STB_MALLOC_WRAPPER_DEBUG
597 p
= STB__ptr(p
,-STB__BIAS
);
598 * (unsigned int *) STB__ptr(p
,0) = 0xdeadbeef;
599 * (unsigned int *) STB__ptr(p
,4) = 0xdeadbeef;
600 * (unsigned int *) STB__ptr(p
,8) = 0xdeadbeef;
601 * (unsigned int *) STB__ptr(p
,12) = 0xdeadbeef;
606 void * stb__malloc(int sz
, char *file
, int line
)
610 if (sz
== 0) return NULL
;
611 p
= stb__malloc_final(STB__FIXSIZE(sz
));
612 if (p
== NULL
) p
= stb__malloc_final(STB__FIXSIZE(sz
));
613 if (p
== NULL
) p
= stb__malloc_final(STB__FIXSIZE(sz
));
615 ++stb__malloc_failure
;
616 #ifdef STB_MALLOC_WRAPPER_DEBUG
617 stb_malloc_checkall();
621 #ifdef STB_MALLOC_WRAPPER_DEBUG
622 * (int *) STB__ptr(p
,0) = STB__FIXSIZE(sz
);
623 * (unsigned int *) STB__ptr(p
,4) = STB__SIG
;
624 * (unsigned int *) STB__ptr(p
,8) = STB__SIG
;
625 * (unsigned int *) STB__ptr(p
,12) = STB__SIG
;
626 * (unsigned int *) STB__ptr(p
,STB__FIXSIZE(sz
)-4) = STB__SIG
+1;
627 * (unsigned int *) STB__ptr(p
,STB__FIXSIZE(sz
)-8) = STB__SIG
+1;
628 * (unsigned int *) STB__ptr(p
,STB__FIXSIZE(sz
)-12) = STB__SIG
+1;
629 * (unsigned int *) STB__ptr(p
,STB__FIXSIZE(sz
)-16) = STB__SIG
+1;
630 p
= STB__ptr(p
, STB__BIAS
);
632 stb_wrapper_malloc(p
,sz
,file
,line
);
636 void * stb__realloc(void *p
, int sz
, char *file
, int line
)
641 if (p
== NULL
) return stb__malloc(sz
,file
,line
);
642 if (sz
== 0 ) { stb__free(p
,file
,line
); return NULL
; }
644 #ifdef STB_MALLOC_WRAPPER_DEBUG
646 p
= STB__ptr(p
,-STB__BIAS
);
648 #ifdef STB_MALLOC_WRAPPER_PAGED
650 int n
= stb_wrapper_allocsize(STB__ptr(p
,STB__BIAS
));
652 stb_wrapper_check(STB__ptr(p
,STB__BIAS
));
653 q
= stb__realloc_final(p
, STB__FIXSIZE(sz
), STB__FIXSIZE(n
));
656 q
= realloc(p
, STB__FIXSIZE(sz
));
659 return ++stb__malloc_failure
, q
;
660 #ifdef STB_MALLOC_WRAPPER_DEBUG
661 * (int *) STB__ptr(q
,0) = STB__FIXSIZE(sz
);
662 * (unsigned int *) STB__ptr(q
,4) = STB__SIG
;
663 * (unsigned int *) STB__ptr(q
,8) = STB__SIG
;
664 * (unsigned int *) STB__ptr(q
,12) = STB__SIG
;
665 * (unsigned int *) STB__ptr(q
,STB__FIXSIZE(sz
)-4) = STB__SIG
+1;
666 * (unsigned int *) STB__ptr(q
,STB__FIXSIZE(sz
)-8) = STB__SIG
+1;
667 * (unsigned int *) STB__ptr(q
,STB__FIXSIZE(sz
)-12) = STB__SIG
+1;
668 * (unsigned int *) STB__ptr(q
,STB__FIXSIZE(sz
)-16) = STB__SIG
+1;
670 q
= STB__ptr(q
, STB__BIAS
);
671 p
= STB__ptr(p
, STB__BIAS
);
673 stb_wrapper_realloc(p
,q
,sz
,file
,line
);
677 STB_EXTERN
int stb_log2_ceil(unsigned int);
678 static void *stb__calloc(size_t n
, size_t sz
, char *file
, int line
)
682 if (n
== 0 || sz
== 0) return NULL
;
683 if (stb_log2_ceil(n
) + stb_log2_ceil(sz
) >= 32) return NULL
;
684 q
= stb__malloc(n
*sz
, file
, line
);
685 if (q
) memset(q
, 0, n
*sz
);
689 char * stb__strdup(char *s
, char *file
, int line
)
693 p
= stb__malloc(strlen(s
)+1, file
, line
);
700 #ifdef STB_FASTMALLOC
708 // include everything that might define these, BEFORE making macros
713 #define malloc(s) stb__malloc ( s, __FILE__, __LINE__)
714 #define realloc(p,s) stb__realloc(p,s, __FILE__, __LINE__)
715 #define calloc(n,s) stb__calloc (n,s, __FILE__, __LINE__)
716 #define free(p) stb__free (p, __FILE__, __LINE__)
717 #define strdup(p) stb__strdup (p, __FILE__, __LINE__)
721 //////////////////////////////////////////////////////////////////////////////
723 // Windows pretty display
726 STB_EXTERN
void stbprint(const char *fmt
, ...);
727 STB_EXTERN
char *stb_sprintf(const char *fmt
, ...);
728 STB_EXTERN
char *stb_mprintf(const char *fmt
, ...);
729 STB_EXTERN
int stb_snprintf(char *s
, size_t n
, const char *fmt
, ...);
730 STB_EXTERN
int stb_vsnprintf(char *s
, size_t n
, const char *fmt
, va_list v
);
734 int stb_vsnprintf(char *s
, size_t n
, const char *fmt
, va_list v
)
738 // Could use "_vsnprintf_s(s, n, _TRUNCATE, fmt, v)" ?
739 res
= _vsnprintf(s
,n
,fmt
,v
);
741 res
= vsnprintf(s
,n
,fmt
,v
);
744 // Unix returns length output would require, Windows returns negative when truncated.
745 return (res
>= (int) n
|| res
< 0) ? -1 : res
;
748 int stb_snprintf(char *s
, size_t n
, const char *fmt
, ...)
753 res
= stb_vsnprintf(s
, n
, fmt
, v
);
758 char *stb_sprintf(const char *fmt
, ...)
760 static char buffer
[1024];
763 stb_vsnprintf(buffer
,1024,fmt
,v
);
768 char *stb_mprintf(const char *fmt
, ...)
770 static char buffer
[1024];
773 stb_vsnprintf(buffer
,1024,fmt
,v
);
775 return strdup(buffer
);
781 STB_EXTERN
__declspec(dllimport
) int __stdcall
WriteConsoleA(void *, const void *, unsigned int, unsigned int *, void *);
782 STB_EXTERN
__declspec(dllimport
) void * __stdcall
GetStdHandle(unsigned int);
783 STB_EXTERN
__declspec(dllimport
) int __stdcall
SetConsoleTextAttribute(void *, unsigned short);
786 static void stb__print_one(void *handle
, char *s
, int len
)
789 if (WriteConsoleA(handle
, s
, len
, NULL
,NULL
))
790 fwrite(s
, 1, len
, stdout
); // if it fails, maybe redirected, so do normal
793 static void stb__print(char *s
)
795 void *handle
= GetStdHandle((unsigned int) -11); // STD_OUTPUT_HANDLE
796 int pad
=0; // number of padding characters to add
801 while (*s
&& *s
!= '{') {
803 if (*s
== '\r' || *s
== '\n')
805 else if (s
[0] == ' ' && s
[1] == ' ') {
806 stb__print_one(handle
, t
, s
-t
);
809 stb__print_one(handle
, t
, 1);
817 stb__print_one(handle
, t
, s
-t
);
827 SetConsoleTextAttribute(handle
, s
[2] - '0');
829 SetConsoleTextAttribute(handle
, tolower(s
[2]) - 'a' + 10);
831 SetConsoleTextAttribute(handle
, 0x0f);
834 } else if (s
[1] == '!') {
835 SetConsoleTextAttribute(handle
, 0x0c);
837 } else if (s
[1] == '@') {
838 SetConsoleTextAttribute(handle
, 0x09);
840 } else if (s
[1] == '$') {
841 SetConsoleTextAttribute(handle
, 0x0a);
844 SetConsoleTextAttribute(handle
, 0x08); // 0,7,8,15 => shades of grey
850 while (*s
&& *s
!= '}') ++s
;
852 stb__print_one(handle
, t
, s
-t
);
860 SetConsoleTextAttribute(handle
, 0x07);
862 stb__print_one(handle
, t
, s
-t
);
863 SetConsoleTextAttribute(handle
, 0x07);
866 void stbprint(const char *fmt
, ...)
874 res
= stb_vsnprintf(buffer
, sizeof(buffer
), fmt
, v
);
878 tbuf
= (char *) malloc(16384);
880 res
= _vsnprintf(tbuf
,16384, fmt
, v
);
892 void stbprint(const char *fmt
, ...)
904 //////////////////////////////////////////////////////////////////////////////
906 // Windows UTF8 filename handling
908 // Windows stupidly treats 8-bit filenames as some dopey code page,
909 // rather than utf-8. If we want to use utf8 filenames, we have to
910 // convert them to WCHAR explicitly and call WCHAR versions of the
911 // file functions. So, ok, we do.
915 #define stb__fopen(x,y) _wfopen((const wchar_t *)stb__from_utf8(x), (const wchar_t *)stb__from_utf8_alt(y))
916 #define stb__windows(x,y) x
918 #define stb__fopen(x,y) fopen(x,y)
919 #define stb__windows(x,y) y
923 typedef unsigned short stb__wchar
;
925 STB_EXTERN stb__wchar
* stb_from_utf8(stb__wchar
*buffer
, char *str
, int n
);
926 STB_EXTERN
char * stb_to_utf8 (char *buffer
, stb__wchar
*str
, int n
);
928 STB_EXTERN stb__wchar
*stb__from_utf8(char *str
);
929 STB_EXTERN stb__wchar
*stb__from_utf8_alt(char *str
);
930 STB_EXTERN
char *stb__to_utf8(stb__wchar
*str
);
934 stb__wchar
* stb_from_utf8(stb__wchar
*buffer
, char *ostr
, int n
)
936 unsigned char *str
= (unsigned char *) ostr
;
944 buffer
[i
++] = *str
++;
945 else if ((*str
& 0xe0) == 0xc0) {
946 if (*str
< 0xc2) return NULL
;
947 c
= (*str
++ & 0x1f) << 6;
948 if ((*str
& 0xc0) != 0x80) return NULL
;
949 buffer
[i
++] = c
+ (*str
++ & 0x3f);
950 } else if ((*str
& 0xf0) == 0xe0) {
951 if (*str
== 0xe0 && (str
[1] < 0xa0 || str
[1] > 0xbf)) return NULL
;
952 if (*str
== 0xed && str
[1] > 0x9f) return NULL
; // str[1] < 0x80 is checked below
953 c
= (*str
++ & 0x0f) << 12;
954 if ((*str
& 0xc0) != 0x80) return NULL
;
955 c
+= (*str
++ & 0x3f) << 6;
956 if ((*str
& 0xc0) != 0x80) return NULL
;
957 buffer
[i
++] = c
+ (*str
++ & 0x3f);
958 } else if ((*str
& 0xf8) == 0xf0) {
959 if (*str
> 0xf4) return NULL
;
960 if (*str
== 0xf0 && (str
[1] < 0x90 || str
[1] > 0xbf)) return NULL
;
961 if (*str
== 0xf4 && str
[1] > 0x8f) return NULL
; // str[1] < 0x80 is checked below
962 c
= (*str
++ & 0x07) << 18;
963 if ((*str
& 0xc0) != 0x80) return NULL
;
964 c
+= (*str
++ & 0x3f) << 12;
965 if ((*str
& 0xc0) != 0x80) return NULL
;
966 c
+= (*str
++ & 0x3f) << 6;
967 if ((*str
& 0xc0) != 0x80) return NULL
;
968 c
+= (*str
++ & 0x3f);
969 // utf-8 encodings of values used in surrogate pairs are invalid
970 if ((c
& 0xFFFFF800) == 0xD800) return NULL
;
973 if (i
+ 2 > n
) return NULL
;
974 buffer
[i
++] = 0xD800 | (0x3ff & (c
>> 10));
975 buffer
[i
++] = 0xDC00 | (0x3ff & (c
));
984 char * stb_to_utf8(char *buffer
, stb__wchar
*str
, int n
)
990 if (i
+1 > n
) return NULL
;
991 buffer
[i
++] = (char) *str
++;
992 } else if (*str
< 0x800) {
993 if (i
+2 > n
) return NULL
;
994 buffer
[i
++] = 0xc0 + (*str
>> 6);
995 buffer
[i
++] = 0x80 + (*str
& 0x3f);
997 } else if (*str
>= 0xd800 && *str
< 0xdc00) {
999 if (i
+4 > n
) return NULL
;
1000 c
= ((str
[0] - 0xd800) << 10) + ((str
[1]) - 0xdc00) + 0x10000;
1001 buffer
[i
++] = 0xf0 + (c
>> 18);
1002 buffer
[i
++] = 0x80 + ((c
>> 12) & 0x3f);
1003 buffer
[i
++] = 0x80 + ((c
>> 6) & 0x3f);
1004 buffer
[i
++] = 0x80 + ((c
) & 0x3f);
1006 } else if (*str
>= 0xdc00 && *str
< 0xe000) {
1009 if (i
+3 > n
) return NULL
;
1010 buffer
[i
++] = 0xe0 + (*str
>> 12);
1011 buffer
[i
++] = 0x80 + ((*str
>> 6) & 0x3f);
1012 buffer
[i
++] = 0x80 + ((*str
) & 0x3f);
1020 stb__wchar
*stb__from_utf8(char *str
)
1022 static stb__wchar buffer
[4096];
1023 return stb_from_utf8(buffer
, str
, 4096);
1026 stb__wchar
*stb__from_utf8_alt(char *str
)
1028 static stb__wchar buffer
[64];
1029 return stb_from_utf8(buffer
, str
, 64);
1032 char *stb__to_utf8(stb__wchar
*str
)
1034 static char buffer
[4096];
1035 return stb_to_utf8(buffer
, str
, 4096);
1040 //////////////////////////////////////////////////////////////////////////////
1045 STB_EXTERN
void stb_fatal(char *fmt
, ...);
1046 STB_EXTERN
void stb_(char *fmt
, ...);
1047 STB_EXTERN
void stb_append_to_file(char *file
, char *fmt
, ...);
1048 STB_EXTERN
void stb_log(int active
);
1049 STB_EXTERN
void stb_log_fileline(int active
);
1050 STB_EXTERN
void stb_log_name(char *filename
);
1052 STB_EXTERN
void stb_swap(void *p
, void *q
, size_t sz
);
1053 STB_EXTERN
void *stb_copy(void *p
, size_t sz
);
1054 STB_EXTERN
void stb_pointer_array_free(void *p
, int len
);
1055 STB_EXTERN
void **stb_array_block_alloc(int count
, int blocksize
);
1057 #define stb_arrcount(x) (sizeof(x)/sizeof((x)[0]))
1060 STB_EXTERN
int stb__record_fileline(char *f
, int n
);
1064 static char *stb__file
;
1065 static int stb__line
;
1067 int stb__record_fileline(char *f
, int n
)
1074 void stb_fatal(char *s
, ...)
1078 fprintf(stderr
, "[%s:%d] ", stb__file
, stb__line
);
1080 fputs("Fatal error: ", stderr
);
1081 vfprintf(stderr
, s
, a
);
1083 fputs("\n", stderr
);
1087 __asm
int 3; // trap to debugger!
1098 static int stb__log_active
=1, stb__log_fileline
=1;
1100 void stb_log(int active
)
1102 stb__log_active
= active
;
1105 void stb_log_fileline(int active
)
1107 stb__log_fileline
= active
;
1110 #ifdef STB_NO_STB_STRINGS
1111 char *stb__log_filename
= "temp.log";
1113 char *stb__log_filename
= "stb.log";
1116 void stb_log_name(char *s
)
1118 stb__log_filename
= s
;
1121 void stb_(char *s
, ...)
1123 if (stb__log_active
) {
1124 FILE *f
= fopen(stb__log_filename
, "a");
1127 if (stb__log_fileline
&& stb__file
)
1128 fprintf(f
, "[%s:%4d] ", stb__file
, stb__line
);
1138 void stb_append_to_file(char *filename
, char *s
, ...)
1140 FILE *f
= fopen(filename
, "a");
1152 typedef struct { char d
[4]; } stb__4
;
1153 typedef struct { char d
[8]; } stb__8
;
1155 // optimize the small cases, though you shouldn't be calling this for those!
1156 void stb_swap(void *p
, void *q
, size_t sz
)
1161 stb__4 temp
= * ( stb__4
*) p
;
1162 * (stb__4
*) p
= * ( stb__4
*) q
;
1163 * (stb__4
*) q
= temp
;
1165 } else if (sz
== 8) {
1166 stb__8 temp
= * ( stb__8
*) p
;
1167 * (stb__8
*) p
= * ( stb__8
*) q
;
1168 * (stb__8
*) q
= temp
;
1172 while (sz
> sizeof(buffer
)) {
1173 stb_swap(p
, q
, sizeof(buffer
));
1174 p
= (char *) p
+ sizeof(buffer
);
1175 q
= (char *) q
+ sizeof(buffer
);
1176 sz
-= sizeof(buffer
);
1179 memcpy(buffer
, p
, sz
);
1181 memcpy(q
, buffer
, sz
);
1184 void *stb_copy(void *p
, size_t sz
)
1186 void *q
= malloc(sz
);
1191 void stb_pointer_array_free(void *q
, int len
)
1193 void **p
= (void **) q
;
1195 for (i
=0; i
< len
; ++i
)
1199 void **stb_array_block_alloc(int count
, int blocksize
)
1202 char *p
= (char *) malloc(sizeof(void *) * count
+ count
* blocksize
);
1204 if (p
== NULL
) return NULL
;
1206 p
+= sizeof(void *) * count
;
1207 for (i
=0; i
< count
; ++i
)
1208 q
[i
] = p
+ i
* blocksize
;
1214 // tricky hack to allow recording FILE,LINE even in varargs functions
1215 #define STB__RECORD_FILE(x) (stb__record_fileline(__FILE__, __LINE__),(x))
1216 #define stb_log STB__RECORD_FILE(stb_log)
1217 #define stb_ STB__RECORD_FILE(stb_)
1218 #ifndef STB_FATAL_CLEAN
1219 #define stb_fatal STB__RECORD_FILE(stb_fatal)
1221 #define STB__DEBUG(x) x
1223 #define STB__DEBUG(x)
1226 //////////////////////////////////////////////////////////////////////////////
1231 #define stb_temp(block, sz) stb__temp(block, sizeof(block), (sz))
1233 STB_EXTERN
void * stb__temp(void *b
, int b_sz
, int want_sz
);
1234 STB_EXTERN
void stb_tempfree(void *block
, void *ptr
);
1238 void * stb__temp(void *b
, int b_sz
, int want_sz
)
1240 if (b_sz
>= want_sz
)
1243 return malloc(want_sz
);
1246 void stb_tempfree(void *b
, void *p
)
1254 //////////////////////////////////////////////////////////////////////////////
1256 // math/sampling operations
1260 #define stb_lerp(t,a,b) ( (a) + (t) * (float) ((b)-(a)) )
1261 #define stb_unlerp(t,a,b) ( ((t) - (a)) / (float) ((b) - (a)) )
1263 #define stb_clamp(x,xmin,xmax) ((x) < (xmin) ? (xmin) : (x) > (xmax) ? (xmax) : (x))
1265 STB_EXTERN
void stb_newell_normal(float *normal
, int num_vert
, float **vert
, int normalize
);
1266 STB_EXTERN
int stb_box_face_vertex_axis_side(int face_number
, int vertex_number
, int axis
);
1267 STB_EXTERN
void stb_linear_controller(float *curpos
, float target_pos
, float acc
, float deacc
, float dt
);
1269 STB_EXTERN
int stb_float_eq(float x
, float y
, float delta
, int max_ulps
);
1270 STB_EXTERN
int stb_is_prime(unsigned int m
);
1271 STB_EXTERN
unsigned int stb_power_of_two_nearest_prime(int n
);
1273 STB_EXTERN
float stb_smoothstep(float t
);
1274 STB_EXTERN
float stb_cubic_bezier_1d(float t
, float p0
, float p1
, float p2
, float p3
);
1276 STB_EXTERN
double stb_linear_remap(double x
, double a
, double b
,
1277 double c
, double d
);
1280 float stb_smoothstep(float t
)
1282 return (3 - 2*t
)*(t
*t
);
1285 float stb_cubic_bezier_1d(float t
, float p0
, float p1
, float p2
, float p3
)
1288 return it
*it
*it
*p0
+ 3*it
*it
*t
*p1
+ 3*it
*t
*t
*p2
+ t
*t
*t
*p3
;
1291 void stb_newell_normal(float *normal
, int num_vert
, float **vert
, int normalize
)
1295 normal
[0] = normal
[1] = normal
[2] = 0;
1296 for (i
=num_vert
-1,j
=0; j
< num_vert
; i
=j
++) {
1299 normal
[0] += (u
[1] - v
[1]) * (u
[2] + v
[2]);
1300 normal
[1] += (u
[2] - v
[2]) * (u
[0] + v
[0]);
1301 normal
[2] += (u
[0] - v
[0]) * (u
[1] + v
[1]);
1304 p
= normal
[0]*normal
[0] + normal
[1]*normal
[1] + normal
[2]*normal
[2];
1305 p
= (float) (1.0 / sqrt(p
));
1312 int stb_box_face_vertex_axis_side(int face_number
, int vertex_number
, int axis
)
1314 static int box_vertices
[6][4][3] =
1316 { { 1,1,1 }, { 1,0,1 }, { 1,0,0 }, { 1,1,0 } },
1317 { { 0,0,0 }, { 0,0,1 }, { 0,1,1 }, { 0,1,0 } },
1318 { { 0,0,0 }, { 0,1,0 }, { 1,1,0 }, { 1,0,0 } },
1319 { { 0,0,0 }, { 1,0,0 }, { 1,0,1 }, { 0,0,1 } },
1320 { { 1,1,1 }, { 0,1,1 }, { 0,0,1 }, { 1,0,1 } },
1321 { { 1,1,1 }, { 1,1,0 }, { 0,1,0 }, { 0,1,1 } },
1323 assert(face_number
>= 0 && face_number
< 6);
1324 assert(vertex_number
>= 0 && vertex_number
< 4);
1325 assert(axis
>= 0 && axis
< 3);
1326 return box_vertices
[face_number
][vertex_number
][axis
];
1329 void stb_linear_controller(float *curpos
, float target_pos
, float acc
, float deacc
, float dt
)
1331 float sign
= 1, p
, cp
= *curpos
;
1332 if (cp
== target_pos
) return;
1333 if (target_pos
< cp
) {
1334 target_pos
= -target_pos
;
1340 p
= cp
+ deacc
* dt
;
1343 dt
= dt
- cp
/ deacc
;
1352 if (p
> target_pos
) p
= target_pos
;
1357 float stb_quadratic_controller(float target_pos
, float curpos
, float maxvel
, float maxacc
, float dt
, float *curvel
)
1362 int stb_float_eq(float x
, float y
, float delta
, int max_ulps
)
1364 if (fabs(x
-y
) <= delta
) return 1;
1365 if (abs(*(int *)&x
- *(int *)&y
) <= max_ulps
) return 1;
1369 int stb_is_prime(unsigned int m
)
1372 if (m
< 2) return 0;
1373 if (m
== 2) return 1;
1374 if (!(m
& 1)) return 0;
1375 if (m
% 3 == 0) return (m
== 3);
1376 for (i
=5; (j
=i
*i
), j
<= m
&& j
> i
; i
+= 6) {
1377 if (m
% i
== 0) return 0;
1378 if (m
% (i
+2) == 0) return 0;
1383 unsigned int stb_power_of_two_nearest_prime(int n
)
1385 static signed char tab
[32] = { 0,0,0,0,1,0,-1,0,1,-1,-1,3,-1,0,-1,2,1,
1386 0,2,0,-1,-4,-1,5,-1,18,-2,15,2,-1,2,0 };
1389 for (i
=0; i
< 32; ++i
)
1390 tab
[i
] = (1 << i
) + 2*tab
[i
] - 1;
1394 if (n
>= 32) return 0xfffffffb;
1398 double stb_linear_remap(double x
, double x_min
, double x_max
,
1399 double out_min
, double out_max
)
1401 return stb_lerp(stb_unlerp(x
,x_min
,x_max
),out_min
,out_max
);
1405 // create a macro so it's faster, but you can get at the function pointer
1406 #define stb_linear_remap(t,a,b,c,d) stb_lerp(stb_unlerp(t,a,b),c,d)
1409 //////////////////////////////////////////////////////////////////////////////
1414 #define stb_big32(c) (((c)[0]<<24) + (c)[1]*65536 + (c)[2]*256 + (c)[3])
1415 #define stb_little32(c) (((c)[3]<<24) + (c)[2]*65536 + (c)[1]*256 + (c)[0])
1416 #define stb_big16(c) ((c)[0]*256 + (c)[1])
1417 #define stb_little16(c) ((c)[1]*256 + (c)[0])
1419 STB_EXTERN
int stb_bitcount(unsigned int a
);
1420 STB_EXTERN
unsigned int stb_bitreverse8(unsigned char n
);
1421 STB_EXTERN
unsigned int stb_bitreverse(unsigned int n
);
1423 STB_EXTERN
int stb_is_pow2(unsigned int n
);
1424 STB_EXTERN
int stb_log2_ceil(unsigned int n
);
1425 STB_EXTERN
int stb_log2_floor(unsigned int n
);
1427 STB_EXTERN
int stb_lowbit8(unsigned int n
);
1428 STB_EXTERN
int stb_highbit8(unsigned int n
);
1431 int stb_bitcount(unsigned int a
)
1433 a
= (a
& 0x55555555) + ((a
>> 1) & 0x55555555); // max 2
1434 a
= (a
& 0x33333333) + ((a
>> 2) & 0x33333333); // max 4
1435 a
= (a
+ (a
>> 4)) & 0x0f0f0f0f; // max 8 per 4, now 8 bits
1436 a
= (a
+ (a
>> 8)); // max 16 per 8 bits
1437 a
= (a
+ (a
>> 16)); // max 32 per 8 bits
1441 unsigned int stb_bitreverse8(unsigned char n
)
1443 n
= ((n
& 0xAA) >> 1) + ((n
& 0x55) << 1);
1444 n
= ((n
& 0xCC) >> 2) + ((n
& 0x33) << 2);
1445 return (unsigned char) ((n
>> 4) + (n
<< 4));
1448 unsigned int stb_bitreverse(unsigned int n
)
1450 n
= ((n
& 0xAAAAAAAA) >> 1) | ((n
& 0x55555555) << 1);
1451 n
= ((n
& 0xCCCCCCCC) >> 2) | ((n
& 0x33333333) << 2);
1452 n
= ((n
& 0xF0F0F0F0) >> 4) | ((n
& 0x0F0F0F0F) << 4);
1453 n
= ((n
& 0xFF00FF00) >> 8) | ((n
& 0x00FF00FF) << 8);
1454 return (n
>> 16) | (n
<< 16);
1457 int stb_is_pow2(unsigned int n
)
1459 return (n
& (n
-1)) == 0;
1462 // tricky use of 4-bit table to identify 5 bit positions (note the '-1')
1463 // 3-bit table would require another tree level; 5-bit table wouldn't save one
1464 #if defined(_WIN32) && !defined(__MINGW32__)
1465 #pragma warning(push)
1466 #pragma warning(disable: 4035) // disable warning about no return value
1467 int stb_log2_floor(unsigned int n
)
1471 _BitScanReverse(&i
, n
);
1472 return i
!= 0 ? i
: -1;
1482 #pragma warning(pop)
1484 int stb_log2_floor(unsigned int n
)
1486 static signed char log2_4
[16] = { -1,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3 };
1488 // 2 compares if n < 16, 3 compares otherwise
1490 if (n
< (1U << 4)) return 0 + log2_4
[n
];
1491 else if (n
< (1U << 9)) return 5 + log2_4
[n
>> 5];
1492 else return 10 + log2_4
[n
>> 10];
1493 else if (n
< (1U << 24))
1494 if (n
< (1U << 19)) return 15 + log2_4
[n
>> 15];
1495 else return 20 + log2_4
[n
>> 20];
1496 else if (n
< (1U << 29)) return 25 + log2_4
[n
>> 25];
1497 else return 30 + log2_4
[n
>> 30];
1501 // define ceil from floor
1502 int stb_log2_ceil(unsigned int n
)
1504 if (stb_is_pow2(n
)) return stb_log2_floor(n
);
1505 else return 1 + stb_log2_floor(n
);
1508 int stb_highbit8(unsigned int n
)
1510 return stb_log2_ceil(n
&255);
1513 int stb_lowbit8(unsigned int n
)
1515 static signed char lowbit4
[16] = { -1,0,1,0, 2,0,1,0, 3,0,1,0, 2,0,1,0 };
1516 int k
= lowbit4
[n
& 15];
1517 if (k
>= 0) return k
;
1518 k
= lowbit4
[(n
>> 4) & 15];
1519 if (k
>= 0) return k
+4;
1526 //////////////////////////////////////////////////////////////////////////////
1528 // qsort Compare Routines
1532 #define stb_stricmp(a,b) stricmp(a,b)
1533 #define stb_strnicmp(a,b,n) strnicmp(a,b,n)
1535 #define stb_stricmp(a,b) strcasecmp(a,b)
1536 #define stb_strnicmp(a,b,n) strncasecmp(a,b,n)
1540 STB_EXTERN
int (*stb_intcmp(int offset
))(const void *a
, const void *b
);
1541 STB_EXTERN
int (*stb_qsort_strcmp(int offset
))(const void *a
, const void *b
);
1542 STB_EXTERN
int (*stb_qsort_stricmp(int offset
))(const void *a
, const void *b
);
1543 STB_EXTERN
int (*stb_floatcmp(int offset
))(const void *a
, const void *b
);
1544 STB_EXTERN
int (*stb_doublecmp(int offset
))(const void *a
, const void *b
);
1545 STB_EXTERN
int (*stb_charcmp(int offset
))(const void *a
, const void *b
);
1548 static int stb__intcmpoffset
, stb__charcmpoffset
, stb__strcmpoffset
;
1549 static int stb__floatcmpoffset
, stb__doublecmpoffset
;
1551 int stb__intcmp(const void *a
, const void *b
)
1553 const int p
= *(const int *) ((const char *) a
+ stb__intcmpoffset
);
1554 const int q
= *(const int *) ((const char *) b
+ stb__intcmpoffset
);
1555 return p
< q
? -1 : p
> q
;
1558 int stb__charcmp(const void *a
, const void *b
)
1560 const int p
= *(const unsigned char *) ((const char *) a
+ stb__charcmpoffset
);
1561 const int q
= *(const unsigned char *) ((const char *) b
+ stb__charcmpoffset
);
1562 return p
< q
? -1 : p
> q
;
1565 int stb__floatcmp(const void *a
, const void *b
)
1567 const float p
= *(const float *) ((const char *) a
+ stb__floatcmpoffset
);
1568 const float q
= *(const float *) ((const char *) b
+ stb__floatcmpoffset
);
1569 return p
< q
? -1 : p
> q
;
1572 int stb__doublecmp(const void *a
, const void *b
)
1574 const double p
= *(const double *) ((const char *) a
+ stb__doublecmpoffset
);
1575 const double q
= *(const double *) ((const char *) b
+ stb__doublecmpoffset
);
1576 return p
< q
? -1 : p
> q
;
1579 int stb__qsort_strcmp(const void *a
, const void *b
)
1581 const char *p
= *(const char **) ((const char *) a
+ stb__strcmpoffset
);
1582 const char *q
= *(const char **) ((const char *) b
+ stb__strcmpoffset
);
1586 int stb__qsort_stricmp(const void *a
, const void *b
)
1588 const char *p
= *(const char **) ((const char *) a
+ stb__strcmpoffset
);
1589 const char *q
= *(const char **) ((const char *) b
+ stb__strcmpoffset
);
1590 return stb_stricmp(p
,q
);
1593 int (*stb_intcmp(int offset
))(const void *, const void *)
1595 stb__intcmpoffset
= offset
;
1596 return &stb__intcmp
;
1599 int (*stb_charcmp(int offset
))(const void *, const void *)
1601 stb__charcmpoffset
= offset
;
1602 return &stb__charcmp
;
1605 int (*stb_qsort_strcmp(int offset
))(const void *, const void *)
1607 stb__strcmpoffset
= offset
;
1608 return &stb__qsort_strcmp
;
1611 int (*stb_qsort_stricmp(int offset
))(const void *, const void *)
1613 stb__strcmpoffset
= offset
;
1614 return &stb__qsort_stricmp
;
1617 int (*stb_floatcmp(int offset
))(const void *, const void *)
1619 stb__floatcmpoffset
= offset
;
1620 return &stb__floatcmp
;
1623 int (*stb_doublecmp(int offset
))(const void *, const void *)
1625 stb__doublecmpoffset
= offset
;
1626 return &stb__doublecmp
;
1631 //////////////////////////////////////////////////////////////////////////////
1633 // Binary Search Toolkit
1638 int minval
, maxval
, guess
;
1642 STB_EXTERN
int stb_search_binary(stb_search
*s
, int minv
, int maxv
, int find_smallest
);
1643 STB_EXTERN
int stb_search_open(stb_search
*s
, int minv
, int find_smallest
);
1644 STB_EXTERN
int stb_probe(stb_search
*s
, int compare
, int *result
); // return 0 when done
1649 STB_probe_binary_smallest
,
1650 STB_probe_binary_largest
,
1651 STB_probe_open_smallest
,
1652 STB_probe_open_largest
,
1655 static int stb_probe_guess(stb_search
*s
, int *result
)
1658 case STB_probe_binary_largest
:
1659 if (s
->minval
== s
->maxval
) {
1660 *result
= s
->minval
;
1663 assert(s
->minval
< s
->maxval
);
1664 // if a < b, then a < p <= b
1665 s
->guess
= s
->minval
+ (((unsigned) s
->maxval
- s
->minval
+ 1) >> 1);
1668 case STB_probe_binary_smallest
:
1669 if (s
->minval
== s
->maxval
) {
1670 *result
= s
->minval
;
1673 assert(s
->minval
< s
->maxval
);
1674 // if a < b, then a <= p < b
1675 s
->guess
= s
->minval
+ (((unsigned) s
->maxval
- s
->minval
) >> 1);
1677 case STB_probe_open_smallest
:
1678 case STB_probe_open_largest
:
1679 s
->guess
= s
->maxval
; // guess the current maxval
1686 int stb_probe(stb_search
*s
, int compare
, int *result
)
1689 case STB_probe_open_smallest
:
1690 case STB_probe_open_largest
: {
1692 // then it lies within minval & maxval
1693 if (s
->mode
== STB_probe_open_smallest
)
1694 s
->mode
= STB_probe_binary_smallest
;
1696 s
->mode
= STB_probe_binary_largest
;
1698 // otherwise, we need to probe larger
1699 s
->minval
= s
->maxval
+ 1;
1700 s
->maxval
= s
->minval
+ s
->step
;
1705 case STB_probe_binary_smallest
: {
1706 // if compare < 0, then s->minval <= a < p
1707 // if compare = 0, then s->minval <= a <= p
1708 // if compare > 0, then p < a <= s->maxval
1710 s
->maxval
= s
->guess
;
1712 s
->minval
= s
->guess
+1;
1715 case STB_probe_binary_largest
: {
1716 // if compare < 0, then s->minval <= a < p
1717 // if compare = 0, then p <= a <= s->maxval
1718 // if compare > 0, then p < a <= s->maxval
1720 s
->maxval
= s
->guess
-1;
1722 s
->minval
= s
->guess
;
1726 return stb_probe_guess(s
, result
);
1729 int stb_search_binary(stb_search
*s
, int minv
, int maxv
, int find_smallest
)
1732 if (maxv
< minv
) return minv
-1;
1735 s
->mode
= find_smallest
? STB_probe_binary_smallest
: STB_probe_binary_largest
;
1736 stb_probe_guess(s
, &r
);
1740 int stb_search_open(stb_search
*s
, int minv
, int find_smallest
)
1745 s
->maxval
= minv
+s
->step
;
1746 s
->mode
= find_smallest
? STB_probe_open_smallest
: STB_probe_open_largest
;
1747 stb_probe_guess(s
, &r
);
1752 //////////////////////////////////////////////////////////////////////////////
1754 // String Processing
1757 #define stb_prefixi(s,t) (0==stb_strnicmp((s),(t),strlen(t)))
1759 enum stb_splitpath_flag
1764 STB_PATH_FILE
= STB_PATH
+ STB_FILE
,
1765 STB_FILE_EXT
= STB_FILE
+ STB_EXT
,
1766 STB_EXT_NO_PERIOD
= 8,
1769 STB_EXTERN
char * stb_skipwhite(char *s
);
1770 STB_EXTERN
char * stb_trimwhite(char *s
);
1771 STB_EXTERN
char * stb_skipnewline(char *s
);
1772 STB_EXTERN
char * stb_strncpy(char *s
, char *t
, int n
);
1773 STB_EXTERN
char * stb_substr(char *t
, int n
);
1774 STB_EXTERN
char * stb_duplower(char *s
);
1775 STB_EXTERN
void stb_tolower (char *s
);
1776 STB_EXTERN
char * stb_strchr2 (char *s
, char p1
, char p2
);
1777 STB_EXTERN
char * stb_strrchr2(char *s
, char p1
, char p2
);
1778 STB_EXTERN
char * stb_strtok(char *output
, char *src
, char *delimit
);
1779 STB_EXTERN
char * stb_strtok_keep(char *output
, char *src
, char *delimit
);
1780 STB_EXTERN
char * stb_strtok_invert(char *output
, char *src
, char *allowed
);
1781 STB_EXTERN
char * stb_dupreplace(char *s
, char *find
, char *replace
);
1782 STB_EXTERN
void stb_replaceinplace(char *s
, char *find
, char *replace
);
1783 STB_EXTERN
char * stb_splitpath(char *output
, char *src
, int flag
);
1784 STB_EXTERN
char * stb_splitpathdup(char *src
, int flag
);
1785 STB_EXTERN
char * stb_replacedir(char *output
, char *src
, char *dir
);
1786 STB_EXTERN
char * stb_replaceext(char *output
, char *src
, char *ext
);
1787 STB_EXTERN
void stb_fixpath(char *path
);
1788 STB_EXTERN
char * stb_shorten_path_readable(char *path
, int max_len
);
1789 STB_EXTERN
int stb_suffix (char *s
, char *t
);
1790 STB_EXTERN
int stb_suffixi(char *s
, char *t
);
1791 STB_EXTERN
int stb_prefix (char *s
, char *t
);
1792 STB_EXTERN
char * stb_strichr(char *s
, char t
);
1793 STB_EXTERN
char * stb_stristr(char *s
, char *t
);
1794 STB_EXTERN
int stb_prefix_count(char *s
, char *t
);
1795 STB_EXTERN
char * stb_plural(int n
); // "s" or ""
1796 STB_EXTERN
size_t stb_strscpy(char *d
, const char *s
, size_t n
);
1798 STB_EXTERN
char **stb_tokens(char *src
, char *delimit
, int *count
);
1799 STB_EXTERN
char **stb_tokens_nested(char *src
, char *delimit
, int *count
, char *nest_in
, char *nest_out
);
1800 STB_EXTERN
char **stb_tokens_nested_empty(char *src
, char *delimit
, int *count
, char *nest_in
, char *nest_out
);
1801 STB_EXTERN
char **stb_tokens_allowempty(char *src
, char *delimit
, int *count
);
1802 STB_EXTERN
char **stb_tokens_stripwhite(char *src
, char *delimit
, int *count
);
1803 STB_EXTERN
char **stb_tokens_withdelim(char *src
, char *delimit
, int *count
);
1804 STB_EXTERN
char **stb_tokens_quoted(char *src
, char *delimit
, int *count
);
1805 // with 'quoted', allow delimiters to appear inside quotation marks, and don't
1806 // strip whitespace inside them (and we delete the quotation marks unless they
1807 // appear back to back, in which case they're considered escaped)
1811 size_t stb_strscpy(char *d
, const char *s
, size_t n
)
1813 size_t len
= strlen(s
);
1822 char *stb_plural(int n
)
1824 return n
== 1 ? "" : "s";
1827 int stb_prefix(char *s
, char *t
)
1835 int stb_prefix_count(char *s
, char *t
)
1846 int stb_suffix(char *s
, char *t
)
1848 size_t n
= strlen(s
);
1849 size_t m
= strlen(t
);
1851 return 0 == strcmp(s
+n
-m
, t
);
1856 int stb_suffixi(char *s
, char *t
)
1858 size_t n
= strlen(s
);
1859 size_t m
= strlen(t
);
1861 return 0 == stb_stricmp(s
+n
-m
, t
);
1866 // originally I was using this table so that I could create known sentinel
1867 // values--e.g. change whitetable[0] to be true if I was scanning for whitespace,
1868 // and false if I was scanning for nonwhite. I don't appear to be using that
1869 // functionality anymore (I do for tokentable, though), so just replace it
1871 char *stb_skipwhite(char *s
)
1873 while (isspace((unsigned char) *s
)) ++s
;
1877 char *stb_skipnewline(char *s
)
1879 if (s
[0] == '\r' || s
[0] == '\n') {
1880 if (s
[0]+s
[1] == '\r' + '\n') ++s
;
1886 char *stb_trimwhite(char *s
)
1889 s
= stb_skipwhite(s
);
1890 n
= (int) strlen(s
);
1891 for (i
=n
-1; i
>= 0; --i
)
1898 char *stb_strncpy(char *s
, char *t
, int n
)
1905 char *stb_substr(char *t
, int n
)
1908 int z
= (int) strlen(t
);
1910 a
= (char *) malloc(n
+1);
1916 char *stb_duplower(char *s
)
1918 char *p
= strdup(s
), *q
= p
;
1926 void stb_tolower(char *s
)
1934 char *stb_strchr2(char *s
, char x
, char y
)
1937 if (*s
== x
|| *s
== y
)
1942 char *stb_strrchr2(char *s
, char x
, char y
)
1946 if (*s
== x
|| *s
== y
)
1951 char *stb_strichr(char *s
, char t
)
1953 if (tolower(t
) == toupper(t
))
1955 return stb_strchr2(s
, (char) tolower(t
), (char) toupper(t
));
1958 char *stb_stristr(char *s
, char *t
)
1960 size_t n
= strlen(t
);
1963 while ((z
= stb_strichr(s
, *t
)) != NULL
) {
1964 if (0==stb_strnicmp(z
, t
, n
))
1971 static char *stb_strtok_raw(char *output
, char *src
, char *delimit
, int keep
, int invert
)
1974 while (*src
&& strchr(delimit
, *src
) != NULL
) {
1978 while (*src
&& strchr(delimit
, *src
) == NULL
) {
1986 return *src
? src
+1 : src
;
1989 char *stb_strtok(char *output
, char *src
, char *delimit
)
1991 return stb_strtok_raw(output
, src
, delimit
, 0, 0);
1994 char *stb_strtok_keep(char *output
, char *src
, char *delimit
)
1996 return stb_strtok_raw(output
, src
, delimit
, 1, 0);
1999 char *stb_strtok_invert(char *output
, char *src
, char *delimit
)
2001 return stb_strtok_raw(output
, src
, delimit
, 1,1);
2004 static char **stb_tokens_raw(char *src_
, char *delimit
, int *count
,
2005 int stripwhite
, int allow_empty
, char *start
, char *end
)
2008 unsigned char *src
= (unsigned char *) src_
;
2009 static char stb_tokentable
[256]; // rely on static initializion to 0
2010 static char stable
[256],etable
[256];
2016 s
= (unsigned char *) delimit
; while (*s
) stb_tokentable
[*s
++] = 1;
2018 s
= (unsigned char *) start
; while (*s
) stable
[*s
++] = 1;
2019 s
= (unsigned char *) end
; if (s
) while (*s
) stable
[*s
++] = 1;
2020 s
= (unsigned char *) end
; if (s
) while (*s
) etable
[*s
++] = 1;
2024 // two passes through: the first time, counting how many
2025 s
= (unsigned char *) src
;
2027 // state: just found delimiter
2028 // skip further delimiters
2030 stb_tokentable
[0] = 0;
2031 while (stb_tokentable
[*s
])
2036 // skip further non-delimiters
2037 stb_tokentable
[0] = 1;
2038 if (stripwhite
== 2) { // quoted strings
2039 while (!stb_tokentable
[*s
]) {
2045 ++s
; // "" -> ", not start a string
2050 if (s
[1] == '"') s
+= 2; // "" -> "
2051 else { ++s
; break; } // terminating "
2059 while (nested
|| !stb_tokentable
[*s
]) {
2062 if (end
? etable
[*s
] : nested
)
2073 // now num has the actual count... malloc our output structure
2074 // need space for all the strings: strings won't be any longer than
2075 // original input, since for every '\0' there's at least one delimiter
2076 result
= (char **) malloc(sizeof(*result
) * (num
+1) + (s
-src
+1));
2077 if (result
== NULL
) return result
;
2078 out
= (char *) (result
+ (num
+1));
2079 // second pass: copy out the data
2080 s
= (unsigned char *) src
;
2084 char *last_nonwhite
;
2085 // state: just found delimiter
2086 // skip further delimiters
2088 stb_tokentable
[0] = 0;
2090 while (stb_tokentable
[*s
] || isspace(*s
))
2093 while (stb_tokentable
[*s
])
2095 } else if (stripwhite
) {
2096 while (isspace(*s
)) ++s
;
2099 // we're past any leading delimiters and whitespace
2102 // copy non-delimiters
2103 stb_tokentable
[0] = 1;
2104 last_nonwhite
= out
-1;
2105 if (stripwhite
== 2) {
2106 while (!stb_tokentable
[*s
]) {
2108 if (!isspace(*s
)) last_nonwhite
= out
;
2113 if (!isspace(*s
)) last_nonwhite
= out
;
2114 *out
++ = *s
++; // "" -> ", not start string
2116 // begin a quoted string
2119 if (s
[1] == '"') { *out
++ = *s
; s
+= 2; }
2120 else { ++s
; break; } // terminating "
2124 last_nonwhite
= out
-1; // all in quotes counts as non-white
2129 while (nested
|| !stb_tokentable
[*s
]) {
2130 if (!isspace(*s
)) last_nonwhite
= out
;
2133 if (end
? etable
[*s
] : nested
)
2142 if (stripwhite
) // rewind to last non-whitespace char
2143 out
= last_nonwhite
+1;
2146 if (*s
) ++s
; // skip delimiter
2148 s
= (unsigned char *) delimit
; while (*s
) stb_tokentable
[*s
++] = 0;
2150 s
= (unsigned char *) start
; while (*s
) stable
[*s
++] = 1;
2151 s
= (unsigned char *) end
; if (s
) while (*s
) stable
[*s
++] = 1;
2152 s
= (unsigned char *) end
; if (s
) while (*s
) etable
[*s
++] = 1;
2154 if (count
!= NULL
) *count
= num
;
2159 char **stb_tokens(char *src
, char *delimit
, int *count
)
2161 return stb_tokens_raw(src
,delimit
,count
,0,0,0,0);
2164 char **stb_tokens_nested(char *src
, char *delimit
, int *count
, char *nest_in
, char *nest_out
)
2166 return stb_tokens_raw(src
,delimit
,count
,0,0,nest_in
,nest_out
);
2169 char **stb_tokens_nested_empty(char *src
, char *delimit
, int *count
, char *nest_in
, char *nest_out
)
2171 return stb_tokens_raw(src
,delimit
,count
,0,1,nest_in
,nest_out
);
2174 char **stb_tokens_allowempty(char *src
, char *delimit
, int *count
)
2176 return stb_tokens_raw(src
,delimit
,count
,0,1,0,0);
2179 char **stb_tokens_stripwhite(char *src
, char *delimit
, int *count
)
2181 return stb_tokens_raw(src
,delimit
,count
,1,1,0,0);
2184 char **stb_tokens_quoted(char *src
, char *delimit
, int *count
)
2186 return stb_tokens_raw(src
,delimit
,count
,2,1,0,0);
2189 char *stb_dupreplace(char *src
, char *find
, char *replace
)
2191 size_t len_find
= strlen(find
);
2192 size_t len_replace
= strlen(replace
);
2197 s
= strstr(src
, find
);
2198 if (s
== NULL
) return strdup(src
);
2201 s
= strstr(s
+ len_find
, find
);
2202 } while (s
!= NULL
);
2204 p
= (char *) malloc(strlen(src
) + count
* (len_replace
- len_find
) + 1);
2205 if (p
== NULL
) return p
;
2209 char *t
= strstr(s
, find
);
2212 assert(strlen(p
) == strlen(src
) + count
*(len_replace
-len_find
));
2217 memcpy(q
, replace
, len_replace
);
2223 void stb_replaceinplace(char *src
, char *find
, char *replace
)
2225 size_t len_find
= strlen(find
);
2226 size_t len_replace
= strlen(replace
);
2231 delta
= len_replace
- len_find
;
2233 if (delta
> 0) return;
2235 p
= strstr(src
, find
);
2236 if (p
== NULL
) return;
2240 memcpy(q
, replace
, len_replace
);
2243 s
= strstr(p
, find
);
2244 if (s
== NULL
) s
= p
+ strlen(p
);
2252 void stb_fixpath(char *path
)
2254 for(; *path
; ++path
)
2259 void stb__add_section(char *buffer
, char *data
, int curlen
, int newlen
)
2261 if (newlen
< curlen
) {
2262 int z1
= newlen
>> 1, z2
= newlen
-z1
;
2263 memcpy(buffer
, data
, z1
-1);
2266 memcpy(buffer
+z1
+1, data
+curlen
-z2
+1, z2
-1);
2268 memcpy(buffer
, data
, curlen
);
2271 char * stb_shorten_path_readable(char *path
, int len
)
2273 static char buffer
[1024];
2274 int n
= strlen(path
),n1
,n2
,r1
,r2
;
2276 if (n
<= len
) return path
;
2277 if (len
> 1024) return path
;
2278 s
= stb_strrchr2(path
, '/', '\\');
2288 // now we need to reduce r1 and r2 so that they fit in len
2292 } else if (n2
< len
>> 1) {
2298 if (r1
< len
>>2) r1
= len
>>2, r2
= len
-r1
;
2299 if (r2
< len
>>2) r2
= len
>>2, r1
= len
-r2
;
2301 assert(r1
<= n1
&& r2
<= n2
);
2303 stb__add_section(buffer
, path
, n1
, r1
);
2304 stb__add_section(buffer
+r1
, s
, n2
, r2
);
2309 static char *stb__splitpath_raw(char *buffer
, char *path
, int flag
)
2311 int len
=0,x
,y
, n
= (int) strlen(path
), f1
,f2
;
2312 char *s
= stb_strrchr2(path
, '/', '\\');
2313 char *t
= strrchr(path
, '.');
2314 if (s
&& t
&& t
< s
) t
= NULL
;
2317 if (flag
== STB_EXT_NO_PERIOD
)
2320 if (!(flag
& (STB_PATH
| STB_FILE
| STB_EXT
))) return NULL
;
2322 f1
= s
== NULL
? 0 : s
-path
; // start of filename
2323 f2
= t
== NULL
? n
: t
-path
; // just past end of filename
2325 if (flag
& STB_PATH
) {
2326 x
= 0; if (f1
== 0 && flag
== STB_PATH
) len
=2;
2327 } else if (flag
& STB_FILE
) {
2331 if (flag
& STB_EXT_NO_PERIOD
)
2332 if (buffer
[x
] == '.')
2338 else if (flag
& STB_FILE
)
2343 if (buffer
== NULL
) {
2344 buffer
= (char *) malloc(y
-x
+ len
+ 1);
2345 if (!buffer
) return NULL
;
2348 if (len
) { strcpy(buffer
, "./"); return buffer
; }
2349 strncpy(buffer
, path
+x
, y
-x
);
2354 char *stb_splitpath(char *output
, char *src
, int flag
)
2356 return stb__splitpath_raw(output
, src
, flag
);
2359 char *stb_splitpathdup(char *src
, int flag
)
2361 return stb__splitpath_raw(NULL
, src
, flag
);
2364 char *stb_replacedir(char *output
, char *src
, char *dir
)
2367 stb_splitpath(buffer
, src
, STB_FILE
| STB_EXT
);
2369 sprintf(output
, "%s/%s", dir
, buffer
);
2371 strcpy(output
, buffer
);
2375 char *stb_replaceext(char *output
, char *src
, char *ext
)
2378 stb_splitpath(buffer
, src
, STB_PATH
| STB_FILE
);
2380 sprintf(output
, "%s.%s", buffer
, ext
[0] == '.' ? ext
+1 : ext
);
2382 strcpy(output
, buffer
);
2387 //////////////////////////////////////////////////////////////////////////////
2389 // stb_alloc - hierarchical allocator
2391 // inspired by http://swapped.cc/halloc
2394 // When you alloc a given block through stb_alloc, you have these choices:
2396 // 1. does it have a parent?
2397 // 2. can it have children?
2398 // 3. can it be freed directly?
2399 // 4. is it transferrable?
2400 // 5. what is its alignment?
2402 // Here are interesting combinations of those:
2404 // children free transfer alignment
2406 // no-overhead, chunked N N N normal
2407 // string pool alloc N N N 1
2408 // parent-ptr, chunked Y N N normal
2409 // low-overhead, unchunked N Y Y normal
2410 // general purpose alloc Y Y Y normal
2412 // Unchunked allocations will probably return 16-aligned pointers. If
2413 // we 16-align the results, we have room for 4 pointers. For smaller
2414 // allocations that allow finer alignment, we can reduce the pointers.
2416 // The strategy is that given a pointer, assuming it has a header (only
2417 // the no-overhead allocations have no header), we can determine the
2418 // type of the header fields, and the number of them, by stepping backwards
2419 // through memory and looking at the tags in the bottom bits.
2421 // Implementation strategy:
2422 // chunked allocations come from the middle of chunks, and can't
2423 // be freed. thefore they do not need to be on a sibling chain.
2424 // they may need child pointers if they have children.
2426 // chunked, with-children
2429 // unchunked, no-children -- reduced storage
2430 // void *next_sibling;
2431 // void *prev_sibling_nextp;
2433 // unchunked, general
2434 // void *first_child;
2435 // void *next_sibling;
2436 // void *prev_sibling_nextp;
2439 // so, if we code each of these fields with different bit patterns
2440 // (actually same one for next/prev/child), then we can identify which
2441 // each one is from the last field.
2443 STB_EXTERN
void stb_free(void *p
);
2444 STB_EXTERN
void *stb_malloc_global(size_t size
);
2445 STB_EXTERN
void *stb_malloc(void *context
, size_t size
);
2446 STB_EXTERN
void *stb_malloc_nofree(void *context
, size_t size
);
2447 STB_EXTERN
void *stb_malloc_leaf(void *context
, size_t size
);
2448 STB_EXTERN
void *stb_malloc_raw(void *context
, size_t size
);
2449 STB_EXTERN
void *stb_realloc(void *ptr
, size_t newsize
);
2451 STB_EXTERN
void stb_reassign(void *new_context
, void *ptr
);
2452 STB_EXTERN
void stb_malloc_validate(void *p
, void *parent
);
2454 extern int stb_alloc_chunk_size
;
2455 extern int stb_alloc_count_free
;
2456 extern int stb_alloc_count_alloc
;
2457 extern int stb_alloc_alignment
;
2461 int stb_alloc_chunk_size
= 65536;
2462 int stb_alloc_count_free
= 0;
2463 int stb_alloc_count_alloc
= 0;
2464 int stb_alloc_alignment
= -16;
2466 typedef struct stb__chunk
2468 struct stb__chunk
*next
;
2492 #define STB__PARENT 1
2493 #define STB__CHUNKS 2
2497 STB__nochildren
= 0,
2498 STB__chunked
= STB__PARENT
,
2499 STB__alloc
= STB__CHUNKS
,
2504 // these functions set the bottom bits of a pointer efficiently
2505 #define STB__DECODE(x,v) ((void *) ((char *) (x) - (v)))
2506 #define STB__ENCODE(x,v) ((void *) ((char *) (x) + (v)))
2508 #define stb__parent(z) (stb__alloc *) STB__DECODE((z)->parent, STB__PARENT)
2509 #define stb__chunks(z) (stb__chunk *) STB__DECODE((z)->chunks, STB__CHUNKS)
2511 #define stb__setparent(z,p) (z)->parent = (stb__alloc *) STB__ENCODE((p), STB__PARENT)
2512 #define stb__setchunks(z,c) (z)->chunks = (stb__chunk *) STB__ENCODE((c), STB__CHUNKS)
2514 static stb__alloc stb__alloc_global
=
2519 (stb__chunk
*) STB__ENCODE(NULL
, STB__CHUNKS
)
2522 static stb__alloc_type
stb__identify(void *p
)
2524 void **q
= (void **) p
;
2525 return (stb__alloc_type
) ((stb_uinta
) q
[-1] & 3);
2528 static void *** stb__prevn(void *p
)
2530 if (stb__identify(p
) == STB__alloc
) {
2531 stb__alloc
*s
= (stb__alloc
*) p
- 1;
2534 stb__nochildren
*s
= (stb__nochildren
*) p
- 1;
2539 void stb_free(void *p
)
2541 if (p
== NULL
) return;
2543 // count frees so that unit tests can see what's happening
2544 ++stb_alloc_count_free
;
2546 switch(stb__identify(p
)) {
2548 // freeing a chunked-block with children does nothing;
2549 // they only get freed when the parent does
2550 // surely this is wrong, and it should free them immediately?
2551 // otherwise how are they getting put on the right chain?
2553 case STB__nochildren
: {
2554 stb__nochildren
*s
= (stb__nochildren
*) p
- 1;
2555 // unlink from sibling chain
2556 *(s
->prevn
) = s
->next
;
2558 *stb__prevn(s
->next
) = s
->prevn
;
2563 stb__alloc
*s
= (stb__alloc
*) p
- 1;
2567 // unlink from sibling chain, if any
2568 *(s
->prevn
) = s
->next
;
2570 *stb__prevn(s
->next
) = s
->prevn
;
2572 // first free chunks
2573 c
= (stb__chunk
*) stb__chunks(s
);
2576 stb_alloc_count_free
+= c
->alloc
;
2582 stb__setchunks(s
,NULL
);
2586 // now free children
2587 while ((q
= s
->child
) != NULL
) {
2596 assert(0); /* NOTREACHED */
2600 void stb_malloc_validate(void *p
, void *parent
)
2602 if (p
== NULL
) return;
2604 switch(stb__identify(p
)) {
2607 case STB__nochildren
: {
2608 stb__nochildren
*n
= (stb__nochildren
*) p
- 1;
2610 assert(*n
->prevn
== p
);
2612 assert(*stb__prevn(n
->next
) == &n
->next
);
2613 stb_malloc_validate(n
, parent
);
2618 stb__alloc
*s
= (stb__alloc
*) p
- 1;
2621 assert(*s
->prevn
== p
);
2624 assert(*stb__prevn(s
->child
) == &s
->child
);
2625 stb_malloc_validate(s
->child
, p
);
2629 assert(*stb__prevn(s
->next
) == &s
->next
);
2630 stb_malloc_validate(s
->next
, parent
);
2635 assert(0); /* NOTREACHED */
2639 static void * stb__try_chunk(stb__chunk
*c
, int size
, int align
, int pre_align
)
2641 char *memblock
= (char *) (c
+1), *q
;
2645 // we going to allocate at the end of the chunk, not the start. confusing,
2646 // but it means we don't need both a 'limit' and a 'cur', just a 'cur'.
2647 // the block ends at: p + c->data_left
2648 // then we move back by size
2649 start_offset
= c
->data_left
- size
;
2651 // now we need to check the alignment of that
2652 q
= memblock
+ start_offset
;
2654 assert(sizeof(q
) == sizeof(iq
));
2656 // suppose align = 2
2657 // then we need to retreat iq far enough that (iq & (2-1)) == 0
2658 // to get (iq & (align-1)) = 0 requires subtracting (iq & (align-1))
2660 start_offset
-= iq
& (align
-1);
2661 assert(((stb_uinta
) (memblock
+start_offset
) & (align
-1)) == 0);
2663 // now, if that + pre_align works, go for it!
2664 start_offset
-= pre_align
;
2666 if (start_offset
>= 0) {
2667 c
->data_left
= start_offset
;
2668 return memblock
+ start_offset
;
2674 static void stb__sort_chunks(stb__alloc
*src
)
2676 // of the first two chunks, put the chunk with more data left in it first
2677 stb__chunk
*c
= stb__chunks(src
), *d
;
2678 if (c
== NULL
) return;
2680 if (d
== NULL
) return;
2681 if (c
->data_left
> d
->data_left
) return;
2685 stb__setchunks(src
, d
);
2688 static void * stb__alloc_chunk(stb__alloc
*src
, int size
, int align
, int pre_align
)
2691 stb__chunk
*c
= stb__chunks(src
);
2693 if (c
&& size
<= stb_alloc_chunk_size
) {
2695 p
= stb__try_chunk(c
, size
, align
, pre_align
);
2696 if (p
) { ++c
->alloc
; return p
; }
2698 // try a second chunk to reduce wastage
2700 p
= stb__try_chunk(c
->next
, size
, align
, pre_align
);
2701 if (p
) { ++c
->alloc
; return p
; }
2703 // put the bigger chunk first, since the second will get buried
2704 // the upshot of this is that, until it gets allocated from, chunk #2
2705 // is always the largest remaining chunk. (could formalize
2706 // this with a heap!)
2707 stb__sort_chunks(src
);
2708 c
= stb__chunks(src
);
2712 // allocate a new chunk
2716 int chunk_size
= stb_alloc_chunk_size
;
2717 // we're going to allocate a new chunk to put this in
2718 if (size
> chunk_size
)
2721 assert(sizeof(*n
) + pre_align
<= 16);
2723 // loop trying to allocate a large enough chunk
2724 // the loop is because the alignment may cause problems if it's big...
2725 // and we don't know what our chunk alignment is going to be
2727 n
= (stb__chunk
*) malloc(16 + chunk_size
);
2728 if (n
== NULL
) return NULL
;
2730 n
->data_left
= chunk_size
- sizeof(*n
);
2732 p
= stb__try_chunk(n
, size
, align
, pre_align
);
2735 stb__setchunks(src
, n
);
2737 // if we just used up the whole block immediately,
2738 // move the following chunk up
2740 if (size
== chunk_size
)
2741 stb__sort_chunks(src
);
2747 chunk_size
+= 16+align
;
2752 static stb__alloc
* stb__get_context(void *context
)
2754 if (context
== NULL
) {
2755 return &stb__alloc_global
;
2757 int u
= stb__identify(context
);
2758 // if context is chunked, grab parent
2759 if (u
== STB__chunked
) {
2760 stb__chunked
*s
= (stb__chunked
*) context
- 1;
2761 return stb__parent(s
);
2763 return (stb__alloc
*) context
- 1;
2768 static void stb__insert_alloc(stb__alloc
*src
, stb__alloc
*s
)
2770 s
->prevn
= &src
->child
;
2771 s
->next
= src
->child
;
2774 *stb__prevn(s
->next
) = &s
->next
;
2777 static void stb__insert_nochild(stb__alloc
*src
, stb__nochildren
*s
)
2779 s
->prevn
= &src
->child
;
2780 s
->next
= src
->child
;
2783 *stb__prevn(s
->next
) = &s
->next
;
2786 static void * malloc_base(void *context
, size_t size
, stb__alloc_type t
, int align
)
2790 stb__alloc
*src
= stb__get_context(context
);
2793 // compute worst-case C packed alignment
2794 // e.g. a 24-byte struct is 8-aligned
2795 int align_proposed
= 1 << stb_lowbit8(size
);
2797 if (align_proposed
< 0)
2800 if (align_proposed
== 0) {
2804 align_proposed
= 256;
2807 // a negative alignment means 'don't align any larger
2808 // than this'; so -16 means we align 1,2,4,8, or 16
2811 if (align_proposed
> -align
)
2812 align_proposed
= -align
;
2815 align
= align_proposed
;
2818 assert(stb_is_pow2(align
));
2820 // don't cause misalignment when allocating nochildren
2821 if (t
== STB__nochildren
&& align
> 8)
2826 stb__alloc
*s
= (stb__alloc
*) malloc(size
+ sizeof(*s
));
2827 if (s
== NULL
) return NULL
;
2830 stb__insert_alloc(src
, s
);
2832 stb__setchunks(s
,NULL
);
2836 case STB__nochildren
: {
2837 stb__nochildren
*s
= (stb__nochildren
*) malloc(size
+ sizeof(*s
));
2838 if (s
== NULL
) return NULL
;
2840 stb__insert_nochild(src
, s
);
2844 case STB__chunk_raw
: {
2845 p
= stb__alloc_chunk(src
, size
, align
, 0);
2846 if (p
== NULL
) return NULL
;
2850 case STB__chunked
: {
2852 if (align
< sizeof(stb_uintptr
)) align
= sizeof(stb_uintptr
);
2853 s
= (stb__chunked
*) stb__alloc_chunk(src
, size
, align
, sizeof(*s
));
2854 if (s
== NULL
) return NULL
;
2855 stb__setparent(s
, src
);
2860 default: p
= NULL
; assert(0); /* NOTREACHED */
2863 ++stb_alloc_count_alloc
;
2867 void *stb_malloc_global(size_t size
)
2869 return malloc_base(NULL
, size
, STB__alloc
, stb_alloc_alignment
);
2872 void *stb_malloc(void *context
, size_t size
)
2874 return malloc_base(context
, size
, STB__alloc
, stb_alloc_alignment
);
2877 void *stb_malloc_nofree(void *context
, size_t size
)
2879 return malloc_base(context
, size
, STB__chunked
, stb_alloc_alignment
);
2882 void *stb_malloc_leaf(void *context
, size_t size
)
2884 return malloc_base(context
, size
, STB__nochildren
, stb_alloc_alignment
);
2887 void *stb_malloc_raw(void *context
, size_t size
)
2889 return malloc_base(context
, size
, STB__chunk_raw
, stb_alloc_alignment
);
2892 char *stb_malloc_string(void *context
, size_t size
)
2894 return (char *) malloc_base(context
, size
, STB__chunk_raw
, 1);
2897 void *stb_realloc(void *ptr
, size_t newsize
)
2901 if (ptr
== NULL
) return stb_malloc(NULL
, newsize
);
2902 if (newsize
== 0) { stb_free(ptr
); return NULL
; }
2904 t
= stb__identify(ptr
);
2905 assert(t
== STB__alloc
|| t
== STB__nochildren
);
2907 if (t
== STB__alloc
) {
2908 stb__alloc
*s
= (stb__alloc
*) ptr
- 1;
2910 s
= (stb__alloc
*) realloc(s
, newsize
+ sizeof(*s
));
2911 if (s
== NULL
) return NULL
;
2918 *stb__prevn(s
->next
) = &s
->next
;
2921 *stb__prevn(s
->child
) = &s
->child
;
2925 stb__nochildren
*s
= (stb__nochildren
*) ptr
- 1;
2927 s
= (stb__nochildren
*) realloc(ptr
, newsize
+ sizeof(s
));
2928 if (s
== NULL
) return NULL
;
2933 *stb__prevn(s
->next
) = &s
->next
;
2939 void *stb_realloc_c(void *context
, void *ptr
, size_t newsize
)
2941 if (ptr
== NULL
) return stb_malloc(context
, newsize
);
2942 if (newsize
== 0) { stb_free(ptr
); return NULL
; }
2943 // @TODO: verify you haven't changed contexts
2944 return stb_realloc(ptr
, newsize
);
2947 void stb_reassign(void *new_context
, void *ptr
)
2949 stb__alloc
*src
= stb__get_context(new_context
);
2951 stb__alloc_type t
= stb__identify(ptr
);
2952 assert(t
== STB__alloc
|| t
== STB__nochildren
);
2954 if (t
== STB__alloc
) {
2955 stb__alloc
*s
= (stb__alloc
*) ptr
- 1;
2958 *(s
->prevn
) = s
->next
;
2960 *stb__prevn(s
->next
) = s
->prevn
;
2962 stb__insert_alloc(src
, s
);
2964 stb__nochildren
*s
= (stb__nochildren
*) ptr
- 1;
2967 *(s
->prevn
) = s
->next
;
2969 *stb__prevn(s
->next
) = s
->prevn
;
2971 stb__insert_nochild(src
, s
);
2978 //////////////////////////////////////////////////////////////////////////////
2982 // An stb_arr is directly useable as a pointer (use the actual type in your
2983 // definition), but when it resizes, it returns a new pointer and you can't
2984 // use the old one, so you have to be careful to copy-in-out as necessary.
2986 // Use a NULL pointer as a 0-length array.
2988 // float *my_array = NULL, *temp;
2990 // // add elements on the end one at a time
2991 // stb_arr_push(my_array, 0.0f);
2992 // stb_arr_push(my_array, 1.0f);
2993 // stb_arr_push(my_array, 2.0f);
2995 // assert(my_array[1] == 2.0f);
2997 // // add an uninitialized element at the end, then assign it
2998 // *stb_arr_add(my_array) = 3.0f;
3000 // // add three uninitialized elements at the end
3001 // temp = stb_arr_addn(my_array,3);
3006 // assert(my_array[5] == 5.0f);
3008 // // remove the last one
3009 // stb_arr_pop(my_array);
3011 // assert(stb_arr_len(my_array) == 6);
3014 #ifdef STB_MALLOC_WRAPPER
3015 #define STB__PARAMS , char *file, int line
3016 #define STB__ARGS , file, line
3022 // calling this function allocates an empty stb_arr attached to p
3023 // (whereas NULL isn't attached to anything)
3024 STB_EXTERN
void stb_arr_malloc(void **target
, void *context
);
3026 // call this function with a non-NULL value to have all successive
3027 // stbs that are created be attached to the associated parent. Note
3028 // that once a given stb_arr is non-empty, it stays attached to its
3029 // current parent, even if you call this function again.
3030 // it turns the previous value, so you can restore it
3031 STB_EXTERN
void* stb_arr_malloc_parent(void *p
);
3033 // simple functions written on top of other functions
3034 #define stb_arr_empty(a) ( stb_arr_len(a) == 0 )
3035 #define stb_arr_add(a) ( stb_arr_addn((a),1) )
3036 #define stb_arr_push(a,v) ( *stb_arr_add(a)=(v) )
3042 unsigned int signature
;
3045 #define stb_arr_signature 0x51bada7b // ends with 0123 in decimal
3047 // access the header block stored before the data
3048 #define stb_arrhead(a) /*lint --e(826)*/ (((stb__arr *) (a)) - 1)
3049 #define stb_arrhead2(a) /*lint --e(826)*/ (((stb__arr *) (a)) - 1)
3052 #define stb_arr_check(a) assert(!a || stb_arrhead(a)->signature == stb_arr_signature)
3053 #define stb_arr_check2(a) assert(!a || stb_arrhead2(a)->signature == stb_arr_signature)
3055 #define stb_arr_check(a) ((void) 0)
3056 #define stb_arr_check2(a) ((void) 0)
3061 // get the array length; special case if pointer is NULL
3062 #define stb_arr_len(a) (a ? stb_arrhead(a)->len : 0)
3063 #define stb_arr_len2(a) ((stb__arr *) (a) ? stb_arrhead2(a)->len : 0)
3064 #define stb_arr_lastn(a) (stb_arr_len(a)-1)
3066 // check whether a given index is valid -- tests 0 <= i < stb_arr_len(a)
3067 #define stb_arr_valid(a,i) (a ? (int) (i) < stb_arrhead(a)->len : 0)
3069 // change the array length so is is exactly N entries long, creating
3070 // uninitialized entries as needed
3071 #define stb_arr_setlen(a,n) \
3072 (stb__arr_setlen((void **) &(a), sizeof(a[0]), (n)))
3074 // change the array length so that N is a valid index (that is, so
3075 // it is at least N entries long), creating uninitialized entries as needed
3076 #define stb_arr_makevalid(a,n) \
3077 (stb_arr_len(a) < (n)+1 ? stb_arr_setlen(a,(n)+1),(a) : (a))
3079 // remove the last element of the array, returning it
3080 #define stb_arr_pop(a) ((stb_arr_check(a), (a))[--stb_arrhead(a)->len])
3082 // access the last element in the array
3083 #define stb_arr_last(a) ((stb_arr_check(a), (a))[stb_arr_len(a)-1])
3085 // is iterator at end of list?
3086 #define stb_arr_end(a,i) ((i) >= &(a)[stb_arr_len(a)])
3088 // (internal) change the allocated length of the array
3089 #define stb_arr__grow(a,n) (stb_arr_check(a), stb_arrhead(a)->len += (n))
3091 // add N new unitialized elements to the end of the array
3092 #define stb_arr__addn(a,n) /*lint --e(826)*/ \
3093 ((stb_arr_len(a)+(n) > stb_arrcurmax(a)) \
3094 ? (stb__arr_addlen((void **) &(a),sizeof(*a),(n)),0) \
3095 : ((stb_arr__grow(a,n), 0)))
3097 // add N new unitialized elements to the end of the array, and return
3098 // a pointer to the first new one
3099 #define stb_arr_addn(a,n) (stb_arr__addn((a),n),(a)+stb_arr_len(a)-(n))
3101 // add N new uninitialized elements starting at index 'i'
3102 #define stb_arr_insertn(a,i,n) (stb__arr_insertn((void **) &(a), sizeof(*a), i, n))
3104 // insert an element at i
3105 #define stb_arr_insert(a,i,v) (stb__arr_insertn((void **) &(a), sizeof(*a), i, 1), ((a)[i] = v))
3107 // delete N elements from the middle starting at index 'i'
3108 #define stb_arr_deleten(a,i,n) (stb__arr_deleten((void **) &(a), sizeof(*a), i, n))
3110 // delete the i'th element
3111 #define stb_arr_delete(a,i) stb_arr_deleten(a,i,1)
3113 // delete the i'th element, swapping down from the end
3114 #define stb_arr_fastdelete(a,i) \
3115 (stb_swap(&a[i], &a[stb_arrhead(a)->len-1], sizeof(*a)), stb_arr_pop(a))
3120 // get the array maximum storage; special case if NULL
3121 #define stb_arrcurmax(a) (a ? stb_arrhead(a)->limit : 0)
3122 #define stb_arrcurmax2(a) (a ? stb_arrhead2(a)->limit : 0)
3124 // set the maxlength of the array to n in anticipation of further growth
3125 #define stb_arr_setsize(a,n) (stb_arr_check(a), stb__arr_setsize((void **) &(a),sizeof((a)[0]),n))
3127 // make sure maxlength is large enough for at least N new allocations
3128 #define stb_arr_atleast(a,n) (stb_arr_len(a)+(n) > stb_arrcurmax(a) \
3129 ? stb_arr_setsize((a), (n)) : 0)
3131 // make a copy of a given array (copies contents via 'memcpy'!)
3132 #define stb_arr_copy(a) stb__arr_copy(a, sizeof((a)[0]))
3134 // compute the storage needed to store all the elements of the array
3135 #define stb_arr_storage(a) (stb_arr_len(a) * sizeof((a)[0]))
3137 #define stb_arr_for(v,arr) for((v)=(arr); (v) < (arr)+stb_arr_len(arr); ++(v))
3141 STB_EXTERN
void stb_arr_free_(void **p
);
3142 STB_EXTERN
void *stb__arr_copy_(void *p
, int elem_size
);
3143 STB_EXTERN
void stb__arr_setsize_(void **p
, int size
, int limit STB__PARAMS
);
3144 STB_EXTERN
void stb__arr_setlen_(void **p
, int size
, int newlen STB__PARAMS
);
3145 STB_EXTERN
void stb__arr_addlen_(void **p
, int size
, int addlen STB__PARAMS
);
3146 STB_EXTERN
void stb__arr_deleten_(void **p
, int size
, int loc
, int n STB__PARAMS
);
3147 STB_EXTERN
void stb__arr_insertn_(void **p
, int size
, int loc
, int n STB__PARAMS
);
3149 #define stb_arr_free(p) stb_arr_free_((void **) &(p))
3150 #define stb__arr_copy stb__arr_copy_
3152 #ifndef STB_MALLOC_WRAPPER
3153 #define stb__arr_setsize stb__arr_setsize_
3154 #define stb__arr_setlen stb__arr_setlen_
3155 #define stb__arr_addlen stb__arr_addlen_
3156 #define stb__arr_deleten stb__arr_deleten_
3157 #define stb__arr_insertn stb__arr_insertn_
3159 #define stb__arr_addlen(p,s,n) stb__arr_addlen_(p,s,n,__FILE__,__LINE__)
3160 #define stb__arr_setlen(p,s,n) stb__arr_setlen_(p,s,n,__FILE__,__LINE__)
3161 #define stb__arr_setsize(p,s,n) stb__arr_setsize_(p,s,n,__FILE__,__LINE__)
3162 #define stb__arr_deleten(p,s,i,n) stb__arr_deleten_(p,s,i,n,__FILE__,__LINE__)
3163 #define stb__arr_insertn(p,s,i,n) stb__arr_insertn_(p,s,i,n,__FILE__,__LINE__)
3167 static void *stb__arr_context
;
3169 void *stb_arr_malloc_parent(void *p
)
3171 void *q
= stb__arr_context
;
3172 stb__arr_context
= p
;
3176 void stb_arr_malloc(void **target
, void *context
)
3178 stb__arr
*q
= (stb__arr
*) stb_malloc(context
, sizeof(*q
));
3179 q
->len
= q
->limit
= 0;
3181 q
->signature
= stb_arr_signature
;
3182 *target
= (void *) (q
+1);
3185 static void * stb__arr_malloc(int size
)
3187 if (stb__arr_context
)
3188 return stb_malloc(stb__arr_context
, size
);
3189 return malloc(size
);
3192 void * stb__arr_copy_(void *p
, int elem_size
)
3195 if (p
== NULL
) return p
;
3196 q
= (stb__arr
*) stb__arr_malloc(sizeof(*q
) + elem_size
* stb_arrhead2(p
)->limit
);
3198 memcpy(q
, stb_arrhead2(p
), sizeof(*q
) + elem_size
* stb_arrhead2(p
)->len
);
3199 q
->stb_malloc
= !!stb__arr_context
;
3203 void stb_arr_free_(void **pp
)
3208 stb__arr
*q
= stb_arrhead2(p
);
3217 static void stb__arrsize_(void **pp
, int size
, int limit
, int len STB__PARAMS
)
3223 if (len
== 0 && size
== 0) return;
3224 a
= (stb__arr
*) stb__arr_malloc(sizeof(*a
) + size
*limit
);
3227 a
->stb_malloc
= !!stb__arr_context
;
3228 a
->signature
= stb_arr_signature
;
3230 a
= stb_arrhead2(p
);
3232 if (a
->limit
< limit
) {
3234 if (a
->limit
>= 4 && limit
< a
->limit
* 2)
3235 limit
= a
->limit
* 2;
3237 p
= stb_realloc(a
, sizeof(*a
) + limit
*size
);
3239 #ifdef STB_MALLOC_WRAPPER
3240 p
= stb__realloc(a
, sizeof(*a
) + limit
*size
, file
, line
);
3242 p
= realloc(a
, sizeof(*a
) + limit
*size
);
3252 a
->len
= stb_min(a
->len
, a
->limit
);
3256 void stb__arr_setsize_(void **pp
, int size
, int limit STB__PARAMS
)
3260 stb__arrsize_(pp
, size
, limit
, stb_arr_len2(p
) STB__ARGS
);
3263 void stb__arr_setlen_(void **pp
, int size
, int newlen STB__PARAMS
)
3267 if (stb_arrcurmax2(p
) < newlen
|| p
== NULL
) {
3268 stb__arrsize_(pp
, size
, newlen
, newlen STB__ARGS
);
3270 stb_arrhead2(p
)->len
= newlen
;
3274 void stb__arr_addlen_(void **p
, int size
, int addlen STB__PARAMS
)
3276 stb__arr_setlen_(p
, size
, stb_arr_len2(*p
) + addlen STB__ARGS
);
3279 void stb__arr_insertn_(void **pp
, int size
, int i
, int n STB__PARAMS
)
3286 stb__arr_addlen_(pp
, size
, n STB__ARGS
);
3290 z
= stb_arr_len2(p
);
3291 stb__arr_addlen_(&p
, size
, n STB__ARGS
);
3292 memmove((char *) p
+ (i
+n
)*size
, (char *) p
+ i
*size
, size
* (z
-i
));
3297 void stb__arr_deleten_(void **pp
, int size
, int i
, int n STB__PARAMS
)
3301 memmove((char *) p
+ i
*size
, (char *) p
+ (i
+n
)*size
, size
* (stb_arr_len2(p
)-(i
+n
)));
3302 stb_arrhead2(p
)->len
-= n
;
3309 //////////////////////////////////////////////////////////////////////////////
3313 // typical use for this is to make a power-of-two hash table.
3315 // let N = size of table (2^n)
3316 // let H = stb_hash(str)
3317 // let S = stb_rehash(H) | 1
3319 // then hash probe sequence P(i) for i=0..N-1
3320 // P(i) = (H + S*i) & (N-1)
3322 // the idea is that H has 32 bits of hash information, but the
3323 // table has only, say, 2^20 entries so only uses 20 of the bits.
3324 // then by rehashing the original H we get 2^12 different probe
3325 // sequences for a given initial probe location. (So it's optimal
3326 // for 64K tables and its optimality decreases past that.)
3328 // ok, so I've added something that generates _two separate_
3329 // 32-bit hashes simultaneously which should scale better to
3330 // very large tables.
3333 STB_EXTERN
unsigned int stb_hash(char *str
);
3334 STB_EXTERN
unsigned int stb_hashptr(void *p
);
3335 STB_EXTERN
unsigned int stb_hashlen(char *str
, int len
);
3336 STB_EXTERN
unsigned int stb_rehash_improved(unsigned int v
);
3337 STB_EXTERN
unsigned int stb_hash_fast(void *p
, int len
);
3338 STB_EXTERN
unsigned int stb_hash2(char *str
, unsigned int *hash2_ptr
);
3339 STB_EXTERN
unsigned int stb_hash_number(unsigned int hash
);
3341 #define stb_rehash(x) ((x) + ((x) >> 6) + ((x) >> 19))
3344 unsigned int stb_hash(char *str
)
3346 unsigned int hash
= 0;
3348 hash
= (hash
<< 7) + (hash
>> 25) + *str
++;
3349 return hash
+ (hash
>> 16);
3352 unsigned int stb_hashlen(char *str
, int len
)
3354 unsigned int hash
= 0;
3355 while (len
-- > 0 && *str
)
3356 hash
= (hash
<< 7) + (hash
>> 25) + *str
++;
3357 return hash
+ (hash
>> 16);
3360 unsigned int stb_hashptr(void *p
)
3362 unsigned int x
= (unsigned int) p
;
3364 // typically lacking in low bits and high bits
3368 // pearson's shuffle
3374 return stb_rehash(x
);
3377 unsigned int stb_rehash_improved(unsigned int v
)
3379 return stb_hashptr((void *)(size_t) v
);
3382 unsigned int stb_hash2(char *str
, unsigned int *hash2_ptr
)
3384 unsigned int hash1
= 0x3141592c;
3385 unsigned int hash2
= 0x77f044ed;
3387 hash1
= (hash1
<< 7) + (hash1
>> 25) + *str
;
3388 hash2
= (hash2
<< 11) + (hash2
>> 21) + *str
;
3391 *hash2_ptr
= hash2
+ (hash1
>> 16);
3392 return hash1
+ (hash2
>> 16);
3396 #define stb__get16_slow(p) ((p)[0] + ((p)[1] << 8))
3397 #if defined(_MSC_VER)
3398 #define stb__get16(p) (*((unsigned short *) (p)))
3400 #define stb__get16(p) stb__get16_slow(p)
3403 unsigned int stb_hash_fast(void *p
, int len
)
3405 unsigned char *q
= (unsigned char *) p
;
3406 unsigned int hash
= len
;
3408 if (len
<= 0 || q
== NULL
) return 0;
3411 if (((int) q
& 1) == 0) {
3412 for (;len
> 3; len
-= 4) {
3414 hash
+= stb__get16(q
);
3415 val
= (stb__get16(q
+2) << 11);
3416 hash
= (hash
<< 16) ^ hash
^ val
;
3421 for (;len
> 3; len
-= 4) {
3423 hash
+= stb__get16_slow(q
);
3424 val
= (stb__get16_slow(q
+2) << 11);
3425 hash
= (hash
<< 16) ^ hash
^ val
;
3431 /* Handle end cases */
3433 case 3: hash
+= stb__get16_slow(q
);
3438 case 2: hash
+= stb__get16_slow(q
);
3442 case 1: hash
+= q
[0];
3449 /* Force "avalanching" of final 127 bits */
3460 unsigned int stb_hash_number(unsigned int hash
)
3473 //////////////////////////////////////////////////////////////////////////////
3475 // Perfect hashing for ints/pointers
3477 // This is mainly useful for making faster pointer-indexed tables
3478 // that don't change frequently. E.g. for stb_ischar().
3484 stb_uint multiplicand
;
3486 stb_uint8 small_bmap
[16];
3487 stb_uint16
*large_bmap
;
3489 stb_uint table_mask
;
3493 STB_EXTERN
int stb_perfect_create(stb_perfect
*,unsigned int*,int n
);
3494 STB_EXTERN
void stb_perfect_destroy(stb_perfect
*);
3495 STB_EXTERN
int stb_perfect_hash(stb_perfect
*, unsigned int x
);
3496 extern int stb_perfect_hash_max_failures
;
3500 int stb_perfect_hash_max_failures
;
3502 int stb_perfect_hash(stb_perfect
*p
, unsigned int x
)
3504 stb_uint m
= x
* p
->multiplicand
;
3505 stb_uint y
= x
>> 16;
3506 stb_uint bv
= (m
>> 24) + y
;
3507 stb_uint av
= (m
+ y
) >> 12;
3508 if (p
->table
== NULL
) return -1; // uninitialized table fails
3510 av
&= p
->table_mask
;
3512 av
^= p
->large_bmap
[bv
];
3514 av
^= p
->small_bmap
[bv
];
3515 return p
->table
[av
] == x
? av
: -1;
3518 static void stb__perfect_prehash(stb_perfect
*p
, stb_uint x
, stb_uint16
*a
, stb_uint16
*b
)
3520 stb_uint m
= x
* p
->multiplicand
;
3521 stb_uint y
= x
>> 16;
3522 stb_uint bv
= (m
>> 24) + y
;
3523 stb_uint av
= (m
+ y
) >> 12;
3525 av
&= p
->table_mask
;
3530 static unsigned long stb__perfect_rand(void)
3532 static unsigned long stb__rand
;
3533 stb__rand
= stb__rand
* 2147001325 + 715136305;
3534 return 0x31415926 ^ ((stb__rand
>> 16) + (stb__rand
<< 16));
3538 unsigned short count
;
3541 unsigned short *entries
;
3544 static int stb__slot_compare(const void *p
, const void *q
)
3546 stb__slot
*a
= (stb__slot
*) p
;
3547 stb__slot
*b
= (stb__slot
*) q
;
3548 return a
->count
> b
->count
? -1 : a
->count
< b
->count
; // sort large to small
3551 int stb_perfect_create(stb_perfect
*p
, unsigned int *v
, int n
)
3553 unsigned int buffer1
[64], buffer2
[64], buffer3
[64], buffer4
[64], buffer5
[32];
3554 unsigned short *as
= (unsigned short *) stb_temp(buffer1
, sizeof(*v
)*n
);
3555 unsigned short *bs
= (unsigned short *) stb_temp(buffer2
, sizeof(*v
)*n
);
3556 unsigned short *entries
= (unsigned short *) stb_temp(buffer4
, sizeof(*entries
) * n
);
3557 int size
= 1 << stb_log2_ceil(n
), bsize
=8;
3558 int failure
= 0,i
,j
,k
;
3561 p
->large_bmap
= NULL
;
3564 stb__slot
*bcount
= (stb__slot
*) stb_temp(buffer3
, sizeof(*bcount
) * bsize
);
3565 unsigned short *bloc
= (unsigned short *) stb_temp(buffer5
, sizeof(*bloc
) * bsize
);
3569 p
->addend
= stb__perfect_rand();
3570 p
->multiplicand
= stb__perfect_rand() | 1;
3571 p
->table_mask
= size
-1;
3572 p
->b_mask
= bsize
-1;
3573 p
->table
= (stb_uint32
*) malloc(size
* sizeof(*p
->table
));
3575 for (i
=0; i
< bsize
; ++i
) {
3577 bcount
[i
].count
= 0;
3580 for (i
=0; i
< n
; ++i
) {
3581 stb__perfect_prehash(p
, v
[i
], as
+i
, bs
+i
);
3582 ++bcount
[bs
[i
]].count
;
3584 qsort(bcount
, bsize
, sizeof(*bcount
), stb__slot_compare
);
3585 e
= entries
; // now setup up their entries index
3586 for (i
=0; i
< bsize
; ++i
) {
3587 bcount
[i
].entries
= e
;
3588 e
+= bcount
[i
].count
;
3589 bcount
[i
].count
= 0;
3590 bloc
[bcount
[i
].b
] = i
;
3592 // now fill them out
3593 for (i
=0; i
< n
; ++i
) {
3596 bcount
[w
].entries
[bcount
[w
].count
++] = i
;
3598 stb_tempfree(buffer5
,bloc
);
3600 for (i
=0; i
< bsize
; ++i
)
3601 for (j
=0; j
< bcount
[i
].count
; ++j
)
3602 assert(bs
[bcount
[i
].entries
[j
]] == bcount
[i
].b
);
3603 memset(p
->table
, 0, size
*sizeof(*p
->table
));
3605 // check if any b has duplicate a
3606 for (i
=0; i
< bsize
; ++i
) {
3607 if (bcount
[i
].count
> 1) {
3608 for (j
=0; j
< bcount
[i
].count
; ++j
) {
3609 if (p
->table
[as
[bcount
[i
].entries
[j
]]])
3611 p
->table
[as
[bcount
[i
].entries
[j
]]] = 1;
3613 for (j
=0; j
< bcount
[i
].count
; ++j
) {
3614 p
->table
[as
[bcount
[i
].entries
[j
]]] = 0;
3621 // go through the bs and populate the table, first fit
3622 for (i
=0; i
< bsize
; ++i
) {
3623 if (bcount
[i
].count
) {
3624 // go through the candidate table[b] values
3625 for (j
=0; j
< size
; ++j
) {
3626 // go through the a values and see if they fit
3627 for (k
=0; k
< bcount
[i
].count
; ++k
) {
3628 int a
= as
[bcount
[i
].entries
[k
]];
3629 if (p
->table
[(a
^j
)&p
->table_mask
]) {
3633 // if succeeded, accept
3634 if (k
== bcount
[i
].count
) {
3636 for (k
=0; k
< bcount
[i
].count
; ++k
) {
3637 int a
= as
[bcount
[i
].entries
[k
]];
3638 p
->table
[(a
^j
)&p
->table_mask
] = 1;
3644 break; // no match for i'th entry, so break out in failure
3648 // success... fill out map
3649 if (bsize
<= 16 && size
<= 256) {
3650 p
->large_bmap
= NULL
;
3651 for (i
=0; i
< bsize
; ++i
)
3652 p
->small_bmap
[bcount
[i
].b
] = (stb_uint8
) bcount
[i
].map
;
3654 p
->large_bmap
= (unsigned short *) malloc(sizeof(*p
->large_bmap
) * bsize
);
3655 for (i
=0; i
< bsize
; ++i
)
3656 p
->large_bmap
[bcount
[i
].b
] = bcount
[i
].map
;
3659 // initialize table to v[0], so empty slots will fail
3660 for (i
=0; i
< size
; ++i
)
3663 for (i
=0; i
< n
; ++i
)
3665 p
->table
[as
[i
] ^ p
->large_bmap
[bs
[i
]]] = v
[i
];
3667 p
->table
[as
[i
] ^ p
->small_bmap
[bs
[i
]]] = v
[i
];
3669 // and now validate that none of them collided
3670 for (i
=0; i
< n
; ++i
)
3671 assert(stb_perfect_hash(p
, v
[i
]) >= 0);
3673 stb_tempfree(buffer3
, bcount
);
3679 stb_tempfree(buffer3
, bcount
);
3682 if (failure
>= 4 && bsize
< size
) bsize
*= 2;
3683 if (failure
>= 8 && (failure
& 3) == 0 && size
< 4*n
) {
3688 // make sure the input data is unique, so we don't infinite loop
3689 unsigned int *data
= (unsigned int *) stb_temp(buffer3
, n
* sizeof(*data
));
3690 memcpy(data
, v
, sizeof(*data
) * n
);
3691 qsort(data
, n
, sizeof(*data
), stb_intcmp(0));
3692 for (i
=1; i
< n
; ++i
) {
3693 if (data
[i
] == data
[i
-1])
3694 size
= 0; // size is return value, so 0 it
3696 stb_tempfree(buffer3
, data
);
3701 if (failure
> stb_perfect_hash_max_failures
)
3702 stb_perfect_hash_max_failures
= failure
;
3704 stb_tempfree(buffer1
, as
);
3705 stb_tempfree(buffer2
, bs
);
3706 stb_tempfree(buffer4
, entries
);
3711 void stb_perfect_destroy(stb_perfect
*p
)
3713 if (p
->large_bmap
) free(p
->large_bmap
);
3714 if (p
->table
) free(p
->table
);
3715 p
->large_bmap
= NULL
;
3722 //////////////////////////////////////////////////////////////////////////////
3724 // Perfect hash clients
3726 STB_EXTERN
int stb_ischar(char s
, char *set
);
3730 int stb_ischar(char c
, char *set
)
3732 static unsigned char bit
[8] = { 1,2,4,8,16,32,64,128 };
3733 static stb_perfect p
;
3734 static unsigned char (*tables
)[256];
3735 static char ** sets
= NULL
;
3737 int z
= stb_perfect_hash(&p
, (int) set
);
3740 // special code that means free all existing data
3745 stb_perfect_destroy(&p
);
3748 stb_arr_push(sets
, set
);
3749 stb_perfect_destroy(&p
);
3750 n
= stb_perfect_create(&p
, (unsigned int *) (char **) sets
, stb_arr_len(sets
));
3753 tables
= (unsigned char (*)[256]) realloc(tables
, sizeof(*tables
) * k
);
3754 memset(tables
, 0, sizeof(*tables
) * k
);
3755 for (i
=0; i
< stb_arr_len(sets
); ++i
) {
3756 k
= stb_perfect_hash(&p
, (int) sets
[i
]);
3760 for (j
=0; !j
|| sets
[i
][j
]; ++j
) {
3761 tables
[n
][(unsigned char) sets
[i
][j
]] |= f
;
3764 z
= stb_perfect_hash(&p
, (int) set
);
3766 return tables
[z
>> 3][(unsigned char) c
] & bit
[z
& 7];
3771 //////////////////////////////////////////////////////////////////////////////
3773 // Instantiated data structures
3775 // This is an attempt to implement a templated data structure.
3777 // Hash table: call stb_define_hash(TYPE,N,KEY,K1,K2,HASH,VALUE)
3778 // TYPE -- will define a structure type containing the hash table
3779 // N -- the name, will prefix functions named:
3783 // N set, N add, N update,
3785 // KEY -- the type of the key. 'x == y' must be valid
3786 // K1,K2 -- keys never used by the app, used as flags in the hashtable
3787 // HASH -- a piece of code ending with 'return' that hashes key 'k'
3788 // VALUE -- the type of the value. 'x = y' must be valid
3790 // Note that stb_define_hash_base can be used to define more sophisticated
3791 // hash tables, e.g. those that make copies of the key or use special
3792 // comparisons (e.g. strcmp).
3794 #define STB_(prefix,name) stb__##prefix##name
3795 #define STB__(prefix,name) prefix##name
3796 #define STB__use(x) x
3797 #define STB__skip(x)
3799 #define stb_declare_hash(PREFIX,TYPE,N,KEY,VALUE) \
3800 typedef struct stb__st_##TYPE TYPE;\
3801 PREFIX int STB__(N, init)(TYPE *h, int count);\
3802 PREFIX int STB__(N, memory_usage)(TYPE *h);\
3803 PREFIX TYPE * STB__(N, create)(void);\
3804 PREFIX TYPE * STB__(N, copy)(TYPE *h);\
3805 PREFIX void STB__(N, destroy)(TYPE *h);\
3806 PREFIX int STB__(N,get_flag)(TYPE *a, KEY k, VALUE *v);\
3807 PREFIX VALUE STB__(N,get)(TYPE *a, KEY k);\
3808 PREFIX int STB__(N, set)(TYPE *a, KEY k, VALUE v);\
3809 PREFIX int STB__(N, add)(TYPE *a, KEY k, VALUE v);\
3810 PREFIX int STB__(N, update)(TYPE*a,KEY k,VALUE v);\
3811 PREFIX int STB__(N, remove)(TYPE *a, KEY k, VALUE *v);
3813 #define STB_nocopy(x) (x)
3814 #define STB_nodelete(x) 0
3815 #define STB_nofields
3816 #define STB_nonullvalue(x)
3817 #define STB_nullvalue(x) x
3818 #define STB_safecompare(x) x
3819 #define STB_nosafe(x)
3820 #define STB_noprefix
3823 #define STB__nogcc(x)
3825 #define STB__nogcc(x) x
3828 #define stb_define_hash_base(PREFIX,TYPE,FIELDS,N,NC,LOAD_FACTOR, \
3829 KEY,EMPTY,DEL,COPY,DISPOSE,SAFE, \
3830 VCOMPARE,CCOMPARE,HASH, \
3831 VALUE,HASVNULL,VNULL) \
3837 } STB_(N,_hashpair); \
3839 STB__nogcc( typedef struct stb__st_##TYPE TYPE; ) \
3840 struct stb__st_##TYPE { \
3842 STB_(N,_hashpair) *table; \
3843 unsigned int mask; \
3847 int delete_threshhold; \
3848 int grow_threshhold; \
3849 int shrink_threshhold; \
3850 unsigned char alloced, has_empty, has_del; \
3851 VALUE ev; VALUE dv; \
3854 static unsigned int STB_(N, hash)(KEY k) \
3859 PREFIX int STB__(N, init)(TYPE *h, int count) \
3862 if (count < 4) count = 4; \
3865 h->mask = count-1; \
3867 h->grow_threshhold = (int) (count * LOAD_FACTOR); \
3868 h->has_empty = h->has_del = 0; \
3871 h->shrink_threshhold = 0; \
3873 h->shrink_threshhold = (int) (count * (LOAD_FACTOR/2.25)); \
3874 h->delete_threshhold = (int) (count * (1-LOAD_FACTOR)/2); \
3875 h->table = (STB_(N,_hashpair)*) malloc(sizeof(h->table[0]) * count); \
3876 if (h->table == NULL) return 0; \
3877 /* ideally this gets turned into a memset32 automatically */ \
3878 for (i=0; i < count; ++i) \
3879 h->table[i].k = EMPTY; \
3883 PREFIX int STB__(N, memory_usage)(TYPE *h) \
3885 return sizeof(*h) + h->limit * sizeof(h->table[0]); \
3888 PREFIX TYPE * STB__(N, create)(void) \
3890 TYPE *h = (TYPE *) malloc(sizeof(*h)); \
3892 if (STB__(N, init)(h, 16)) \
3894 else { free(h); h=NULL; } \
3899 PREFIX void STB__(N, destroy)(TYPE *a) \
3902 for (i=0; i < a->limit; ++i) \
3903 if (!CCOMPARE(a->table[i].k,EMPTY) && !CCOMPARE(a->table[i].k, DEL)) \
3904 DISPOSE(a->table[i].k); \
3910 static void STB_(N, rehash)(TYPE *a, int count); \
3912 PREFIX int STB__(N,get_flag)(TYPE *a, KEY k, VALUE *v) \
3914 unsigned int h = STB_(N, hash)(k); \
3915 unsigned int n = h & a->mask, s; \
3916 if (CCOMPARE(k,EMPTY)){ if (a->has_empty) *v = a->ev; return a->has_empty;}\
3917 if (CCOMPARE(k,DEL)) { if (a->has_del ) *v = a->dv; return a->has_del; }\
3918 if (CCOMPARE(a->table[n].k,EMPTY)) return 0; \
3919 SAFE(if (!CCOMPARE(a->table[n].k,DEL))) \
3920 if (VCOMPARE(a->table[n].k,k)) { *v = a->table[n].v; return 1; } \
3921 s = stb_rehash(h) | 1; \
3923 n = (n + s) & a->mask; \
3924 if (CCOMPARE(a->table[n].k,EMPTY)) return 0; \
3925 SAFE(if (CCOMPARE(a->table[n].k,DEL)) continue;) \
3926 if (VCOMPARE(a->table[n].k,k)) \
3927 { *v = a->table[n].v; return 1; } \
3932 PREFIX VALUE STB__(N,get)(TYPE *a, KEY k) \
3935 if (STB__(N,get_flag)(a,k,&v)) return v; \
3936 else return VNULL; \
3940 PREFIX int STB__(N,getkey)(TYPE *a, KEY k, KEY *kout) \
3942 unsigned int h = STB_(N, hash)(k); \
3943 unsigned int n = h & a->mask, s; \
3944 if (CCOMPARE(k,EMPTY)||CCOMPARE(k,DEL)) return 0; \
3945 if (CCOMPARE(a->table[n].k,EMPTY)) return 0; \
3946 SAFE(if (!CCOMPARE(a->table[n].k,DEL))) \
3947 if (VCOMPARE(a->table[n].k,k)) { *kout = a->table[n].k; return 1; } \
3948 s = stb_rehash(h) | 1; \
3950 n = (n + s) & a->mask; \
3951 if (CCOMPARE(a->table[n].k,EMPTY)) return 0; \
3952 SAFE(if (CCOMPARE(a->table[n].k,DEL)) continue;) \
3953 if (VCOMPARE(a->table[n].k,k)) \
3954 { *kout = a->table[n].k; return 1; } \
3958 static int STB_(N,addset)(TYPE *a, KEY k, VALUE v, \
3959 int allow_new, int allow_old, int copy) \
3961 unsigned int h = STB_(N, hash)(k); \
3962 unsigned int n = h & a->mask; \
3964 if (CCOMPARE(k,EMPTY)) { \
3965 if (a->has_empty ? allow_old : allow_new) { \
3966 n=a->has_empty; a->ev = v; a->has_empty = 1; return !n; \
3969 if (CCOMPARE(k,DEL)) { \
3970 if (a->has_del ? allow_old : allow_new) { \
3971 n=a->has_del; a->dv = v; a->has_del = 1; return !n; \
3974 if (!CCOMPARE(a->table[n].k, EMPTY)) { \
3976 if (CCOMPARE(a->table[n].k, DEL)) \
3978 else if (VCOMPARE(a->table[n].k,k)) { \
3980 a->table[n].v = v; \
3981 return !allow_new; \
3983 s = stb_rehash(h) | 1; \
3985 n = (n + s) & a->mask; \
3986 if (CCOMPARE(a->table[n].k, EMPTY)) break; \
3987 if (CCOMPARE(a->table[n].k, DEL)) { \
3989 } else if (VCOMPARE(a->table[n].k,k)) { \
3991 a->table[n].v = v; \
3992 return !allow_new; \
3996 if (!allow_new) return 0; \
3997 if (b < 0) b = n; else --a->deleted; \
3998 a->table[b].k = copy ? COPY(k) : k; \
3999 a->table[b].v = v; \
4001 if (a->count > a->grow_threshhold) \
4002 STB_(N,rehash)(a, a->limit*2); \
4006 PREFIX int STB__(N, set)(TYPE *a, KEY k, VALUE v){return STB_(N,addset)(a,k,v,1,1,1);}\
4007 PREFIX int STB__(N, add)(TYPE *a, KEY k, VALUE v){return STB_(N,addset)(a,k,v,1,0,1);}\
4008 PREFIX int STB__(N, update)(TYPE*a,KEY k,VALUE v){return STB_(N,addset)(a,k,v,0,1,1);}\
4010 PREFIX int STB__(N, remove)(TYPE *a, KEY k, VALUE *v) \
4012 unsigned int h = STB_(N, hash)(k); \
4013 unsigned int n = h & a->mask, s; \
4014 if (CCOMPARE(k,EMPTY)) { if (a->has_empty) { if(v)*v = a->ev; a->has_empty=0; return 1; } return 0; } \
4015 if (CCOMPARE(k,DEL)) { if (a->has_del ) { if(v)*v = a->dv; a->has_del =0; return 1; } return 0; } \
4016 if (CCOMPARE(a->table[n].k,EMPTY)) return 0; \
4017 if (SAFE(CCOMPARE(a->table[n].k,DEL) || ) !VCOMPARE(a->table[n].k,k)) { \
4018 s = stb_rehash(h) | 1; \
4020 n = (n + s) & a->mask; \
4021 if (CCOMPARE(a->table[n].k,EMPTY)) return 0; \
4022 SAFE(if (CCOMPARE(a->table[n].k, DEL)) continue;) \
4023 if (VCOMPARE(a->table[n].k,k)) break; \
4026 DISPOSE(a->table[n].k); \
4027 a->table[n].k = DEL; \
4031 *v = a->table[n].v; \
4032 if (a->count < a->shrink_threshhold) \
4033 STB_(N, rehash)(a, a->limit >> 1); \
4034 else if (a->deleted > a->delete_threshhold) \
4035 STB_(N, rehash)(a, a->limit); \
4039 PREFIX TYPE * STB__(NC, copy)(TYPE *a) \
4042 TYPE *h = (TYPE *) malloc(sizeof(*h)); \
4043 if (!h) return NULL; \
4044 if (!STB__(N, init)(h, a->limit)) { free(h); return NULL; } \
4045 h->count = a->count; \
4046 h->deleted = a->deleted; \
4048 h->ev = a->ev; h->dv = a->dv; \
4049 h->has_empty = a->has_empty; h->has_del = a->has_del; \
4050 memcpy(h->table, a->table, h->limit * sizeof(h->table[0])); \
4051 for (i=0; i < a->limit; ++i) \
4052 if (!CCOMPARE(h->table[i].k,EMPTY) && !CCOMPARE(h->table[i].k,DEL)) \
4053 h->table[i].k = COPY(h->table[i].k); \
4057 static void STB_(N, rehash)(TYPE *a, int count) \
4061 STB__(N, init)(&b, count); \
4062 for (i=0; i < a->limit; ++i) \
4063 if (!CCOMPARE(a->table[i].k,EMPTY) && !CCOMPARE(a->table[i].k,DEL)) \
4064 STB_(N,addset)(&b, a->table[i].k, a->table[i].v,1,1,0); \
4066 a->table = b.table; \
4068 a->count = b.count; \
4069 a->limit = b.limit; \
4070 a->deleted = b.deleted; \
4071 a->delete_threshhold = b.delete_threshhold; \
4072 a->grow_threshhold = b.grow_threshhold; \
4073 a->shrink_threshhold = b.shrink_threshhold; \
4076 #define STB_equal(a,b) ((a) == (b))
4078 #define stb_define_hash(TYPE,N,KEY,EMPTY,DEL,HASH,VALUE) \
4079 stb_define_hash_base(STB_noprefix, TYPE,STB_nofields,N,NC,0.85f, \
4080 KEY,EMPTY,DEL,STB_nocopy,STB_nodelete,STB_nosafe, \
4081 STB_equal,STB_equal,HASH, \
4082 VALUE,STB_nonullvalue,0)
4084 #define stb_define_hash_vnull(TYPE,N,KEY,EMPTY,DEL,HASH,VALUE,VNULL) \
4085 stb_define_hash_base(STB_noprefix, TYPE,STB_nofields,N,NC,0.85f, \
4086 KEY,EMPTY,DEL,STB_nocopy,STB_nodelete,STB_nosafe, \
4087 STB_equal,STB_equal,HASH, \
4088 VALUE,STB_nullvalue,VNULL)
4090 //////////////////////////////////////////////////////////////////////////////
4094 // An stb_ptrmap data structure is an O(1) hash table between pointers. One
4095 // application is to let you store "extra" data associated with pointers,
4096 // which is why it was originally called stb_extra.
4098 stb_declare_hash(STB_EXTERN
, stb_ptrmap
, stb_ptrmap_
, void *, void *)
4099 stb_declare_hash(STB_EXTERN
, stb_idict
, stb_idict_
, stb_int32
, stb_int32
)
4101 STB_EXTERN
void stb_ptrmap_delete(stb_ptrmap
*e
, void (*free_func
)(void *));
4102 STB_EXTERN stb_ptrmap
*stb_ptrmap_new(void);
4104 STB_EXTERN stb_idict
* stb_idict_new_size(int size
);
4105 STB_EXTERN
void stb_idict_remove_all(stb_idict
*e
);
4109 #define STB_EMPTY ((void *) 2)
4110 #define STB_EDEL ((void *) 6)
4112 stb_define_hash_base(STB_noprefix
,stb_ptrmap
, STB_nofields
, stb_ptrmap_
,stb_ptrmap_
,0.85f
,
4113 void *,STB_EMPTY
,STB_EDEL
,STB_nocopy
,STB_nodelete
,STB_nosafe
,
4114 STB_equal
,STB_equal
,return stb_hashptr(k
);,
4115 void *,STB_nullvalue
,NULL
)
4117 stb_ptrmap
*stb_ptrmap_new(void)
4119 return stb_ptrmap_create();
4122 void stb_ptrmap_delete(stb_ptrmap
*e
, void (*free_func
)(void *))
4126 for (i
=0; i
< e
->limit
; ++i
)
4127 if (e
->table
[i
].k
!= STB_EMPTY
&& e
->table
[i
].k
!= STB_EDEL
) {
4128 if (free_func
== free
)
4129 free(e
->table
[i
].v
); // allow STB_MALLOC_WRAPPER to operate
4131 free_func(e
->table
[i
].v
);
4133 stb_ptrmap_destroy(e
);
4136 // extra fields needed for stua_dict
4137 #define STB_IEMPTY ((int) 1)
4138 #define STB_IDEL ((int) 3)
4139 stb_define_hash_base(STB_noprefix
, stb_idict
, short type
; short gc
; STB_nofields
, stb_idict_
,stb_idict_
,0.85f
,
4140 stb_int32
,STB_IEMPTY
,STB_IDEL
,STB_nocopy
,STB_nodelete
,STB_nosafe
,
4141 STB_equal
,STB_equal
,
4142 return stb_rehash_improved(k
);,stb_int32
,STB_nonullvalue
,0)
4144 stb_idict
* stb_idict_new_size(int size
)
4146 stb_idict
*e
= (stb_idict
*) malloc(sizeof(*e
));
4148 if (!stb_is_pow2(size
))
4149 size
= 1 << stb_log2_ceil(size
);
4150 stb_idict_init(e
, size
);
4156 void stb_idict_remove_all(stb_idict
*e
)
4159 for (n
=0; n
< e
->limit
; ++n
)
4160 e
->table
[n
].k
= STB_IEMPTY
;
4161 e
->has_empty
= e
->has_del
= 0;
4165 //////////////////////////////////////////////////////////////////////////////
4167 // stb_sparse_ptr_matrix
4169 // An stb_ptrmap data structure is an O(1) hash table storing an arbitrary
4170 // block of data for a given pair of pointers.
4172 // If create=0, returns
4174 typedef struct stb__st_stb_spmatrix stb_spmatrix
;
4176 STB_EXTERN stb_spmatrix
* stb_sparse_ptr_matrix_new(int val_size
);
4177 STB_EXTERN
void stb_sparse_ptr_matrix_free(stb_spmatrix
*z
);
4178 STB_EXTERN
void * stb_sparse_ptr_matrix_get(stb_spmatrix
*z
, void *a
, void *b
, int create
);
4187 static stb__ptrpair stb__ptrpair_empty
= { (void *) 1, (void *) 1 };
4188 static stb__ptrpair stb__ptrpair_del
= { (void *) 2, (void *) 2 };
4190 #define STB__equal_ptrpair(x,y) ((x).a == (y).a && (x).b == (y).b)
4192 stb_define_hash_base(static, stb_spmatrix
, int val_size
; void *arena
;, stb__spmatrix_
,stb__spmatrix_
, 0.85,
4193 stb__ptrpair
, stb__ptrpair_empty
, stb__ptrpair_del
,
4194 STB_nocopy
, STB_nodelete
, STB_nosafe
,
4195 STB__equal_ptrpair
, STB__equal_ptrpair
, return stb_rehash(stb_hashptr(k
.a
))+stb_hashptr(k
.b
);,
4196 void *, STB_nullvalue
, 0)
4198 stb_spmatrix
*stb_sparse_ptr_matrix_new(int val_size
)
4200 stb_spmatrix
*m
= stb__spmatrix_create();
4201 if (m
) m
->val_size
= val_size
;
4202 if (m
) m
->arena
= stb_malloc_global(1);
4206 void stb_sparse_ptr_matrix_free(stb_spmatrix
*z
)
4208 if (z
->arena
) stb_free(z
->arena
);
4209 stb__spmatrix_destroy(z
);
4212 void *stb_sparse_ptr_matrix_get(stb_spmatrix
*z
, void *a
, void *b
, int create
)
4214 stb__ptrpair t
= { a
,b
};
4215 void *data
= stb__spmatrix_get(z
, t
);
4216 if (!data
&& create
) {
4217 data
= stb_malloc_raw(z
->arena
, z
->val_size
);
4218 if (!data
) return NULL
;
4219 memset(data
, 0, z
->val_size
);
4220 stb__spmatrix_add(z
, t
, data
);
4228 //////////////////////////////////////////////////////////////////////////////
4230 // SDICT: Hash Table for Strings (symbol table)
4232 // if "use_arena=1", then strings will be copied
4233 // into blocks and never freed until the sdict is freed;
4234 // otherwise they're malloc()ed and free()d on the fly.
4235 // (specify use_arena=1 if you never stb_sdict_remove)
4237 stb_declare_hash(STB_EXTERN
, stb_sdict
, stb_sdict_
, char *, void *)
4239 STB_EXTERN stb_sdict
* stb_sdict_new(int use_arena
);
4240 STB_EXTERN stb_sdict
* stb_sdict_copy(stb_sdict
*);
4241 STB_EXTERN
void stb_sdict_delete(stb_sdict
*);
4242 STB_EXTERN
void * stb_sdict_change(stb_sdict
*, char *str
, void *p
);
4243 STB_EXTERN
int stb_sdict_count(stb_sdict
*d
);
4245 #define stb_sdict_for(d,i,q,z) \
4246 for(i=0; i < (d)->limit ? q=(d)->table[i].k,z=(d)->table[i].v,1 : 0; ++i) \
4247 if (q==NULL||q==(void *) 1);else // reversed makes macro friendly
4251 #define STB_DEL ((void *) 1)
4252 #define STB_SDEL ((char *) 1)
4254 #define stb_sdict__copy(x) \
4255 strcpy(a->arena ? stb_malloc_string(a->arena, strlen(x)+1) \
4256 : (char *) malloc(strlen(x)+1), x)
4258 #define stb_sdict__dispose(x) if (!a->arena) free(x)
4260 stb_define_hash_base(STB_noprefix
, stb_sdict
, void*arena
;, stb_sdict_
,stb_sdictinternal_
, 0.85f
,
4261 char *, NULL
, STB_SDEL
, stb_sdict__copy
, stb_sdict__dispose
,
4262 STB_safecompare
, !strcmp
, STB_equal
, return stb_hash(k
);,
4263 void *, STB_nullvalue
, NULL
)
4265 int stb_sdict_count(stb_sdict
*a
)
4270 stb_sdict
* stb_sdict_new(int use_arena
)
4272 stb_sdict
*d
= stb_sdict_create();
4273 if (d
== NULL
) return NULL
;
4274 d
->arena
= use_arena
? stb_malloc_global(1) : NULL
;
4278 stb_sdict
* stb_sdict_copy(stb_sdict
*old
)
4281 void *old_arena
= old
->arena
;
4282 void *new_arena
= old_arena
? stb_malloc_global(1) : NULL
;
4283 old
->arena
= new_arena
;
4284 n
= stb_sdictinternal_copy(old
);
4285 old
->arena
= old_arena
;
4287 n
->arena
= new_arena
;
4289 stb_free(new_arena
);
4294 void stb_sdict_delete(stb_sdict
*d
)
4298 stb_sdict_destroy(d
);
4301 void * stb_sdict_change(stb_sdict
*d
, char *str
, void *p
)
4303 void *q
= stb_sdict_get(d
, str
);
4304 stb_sdict_set(d
, str
, p
);
4309 //////////////////////////////////////////////////////////////////////////////
4311 // Instantiated data structures
4313 // This is an attempt to implement a templated data structure.
4314 // What you do is define a struct foo, and then include several
4315 // pointer fields to struct foo in your struct. Then you call
4316 // the instantiator, which creates the functions that implement
4317 // the data structure. This requires massive undebuggable #defines,
4318 // so we limit the cases where we do this.
4320 // AA tree is an encoding of a 2-3 tree whereas RB trees encode a 2-3-4 tree;
4321 // much simpler code due to fewer cases.
4323 #define stb__bst_parent(x) x
4324 #define stb__bst_noparent(x)
4326 #define stb_bst_fields(N) \
4327 *STB_(N,left), *STB_(N,right); \
4328 unsigned char STB_(N,level)
4330 #define stb_bst_fields_parent(N) \
4331 *STB_(N,left), *STB_(N,right), *STB_(N,parent); \
4332 unsigned char STB_(N,level)
4334 #define STB__level(N,x) ((x) ? (x)->STB_(N,level) : 0)
4336 #define stb_bst_base(TYPE, N, TREE, M, compare, PAR) \
4338 static int STB_(N,_compare)(TYPE *p, TYPE *q) \
4343 static void STB_(N,setleft)(TYPE *q, TYPE *v) \
4345 q->STB_(N,left) = v; \
4346 PAR(if (v) v->STB_(N,parent) = q;) \
4349 static void STB_(N,setright)(TYPE *q, TYPE *v) \
4351 q->STB_(N,right) = v; \
4352 PAR(if (v) v->STB_(N,parent) = q;) \
4355 static TYPE *STB_(N,skew)(TYPE *q) \
4357 if (q == NULL) return q; \
4358 if (q->STB_(N,left) \
4359 && q->STB_(N,left)->STB_(N,level) == q->STB_(N,level)) { \
4360 TYPE *p = q->STB_(N,left); \
4361 STB_(N,setleft)(q, p->STB_(N,right)); \
4362 STB_(N,setright)(p, q); \
4368 static TYPE *STB_(N,split)(TYPE *p) \
4370 TYPE *q = p->STB_(N,right); \
4371 if (q && q->STB_(N,right) \
4372 && q->STB_(N,right)->STB_(N,level) == p->STB_(N,level)) { \
4373 STB_(N,setright)(p, q->STB_(N,left)); \
4374 STB_(N,setleft)(q,p); \
4375 ++q->STB_(N,level); \
4381 TYPE *STB__(N,insert)(TYPE *tree, TYPE *item) \
4384 if (tree == NULL) { \
4385 item->STB_(N,left) = NULL; \
4386 item->STB_(N,right) = NULL; \
4387 item->STB_(N,level) = 1; \
4388 PAR(item->STB_(N,parent) = NULL;) \
4391 c = STB_(N,_compare)(item,tree); \
4393 if (item != tree) { \
4394 STB_(N,setleft)(item, tree->STB_(N,left)); \
4395 STB_(N,setright)(item, tree->STB_(N,right)); \
4396 item->STB_(N,level) = tree->STB_(N,level); \
4397 PAR(item->STB_(N,parent) = NULL;) \
4402 STB_(N,setleft )(tree, STB__(N,insert)(tree->STB_(N,left), item)); \
4404 STB_(N,setright)(tree, STB__(N,insert)(tree->STB_(N,right), item)); \
4405 tree = STB_(N,skew)(tree); \
4406 tree = STB_(N,split)(tree); \
4407 PAR(tree->STB_(N,parent) = NULL;) \
4411 TYPE *STB__(N,remove)(TYPE *tree, TYPE *item) \
4413 static TYPE *delnode, *leaf, *restore; \
4414 if (tree == NULL) return NULL; \
4416 if (STB_(N,_compare)(item, tree) < 0) { \
4417 STB_(N,setleft)(tree, STB__(N,remove)(tree->STB_(N,left), item)); \
4421 r = STB__(N,remove)(tree->STB_(N,right), item); \
4422 /* maybe move 'leaf' up to this location */ \
4423 if (restore == tree) { tree = leaf; leaf = restore = NULL; } \
4424 STB_(N,setright)(tree,r); \
4425 assert(tree->STB_(N,right) != tree); \
4427 if (tree == leaf) { \
4428 if (delnode == item) { \
4429 tree = tree->STB_(N,right); \
4430 assert(leaf->STB_(N,left) == NULL); \
4431 /* move leaf (the right sibling) up to delnode */ \
4432 STB_(N,setleft )(leaf, item->STB_(N,left )); \
4433 STB_(N,setright)(leaf, item->STB_(N,right)); \
4434 leaf->STB_(N,level) = item->STB_(N,level); \
4436 restore = delnode; \
4440 if (STB__level(N,tree->STB_(N,left) ) < tree->STB_(N,level)-1 || \
4441 STB__level(N,tree->STB_(N,right)) < tree->STB_(N,level)-1) { \
4442 --tree->STB_(N,level); \
4443 if (STB__level(N,tree->STB_(N,right)) > tree->STB_(N,level)) \
4444 tree->STB_(N,right)->STB_(N,level) = tree->STB_(N,level); \
4445 tree = STB_(N,skew)(tree); \
4446 STB_(N,setright)(tree, STB_(N,skew)(tree->STB_(N,right))); \
4447 if (tree->STB_(N,right)) \
4448 STB_(N,setright)(tree->STB_(N,right), \
4449 STB_(N,skew)(tree->STB_(N,right)->STB_(N,right))); \
4450 tree = STB_(N,split)(tree); \
4451 if (tree->STB_(N,right)) \
4452 STB_(N,setright)(tree, STB_(N,split)(tree->STB_(N,right))); \
4455 PAR(if (tree) tree->STB_(N,parent) = NULL;) \
4459 TYPE *STB__(N,last)(TYPE *tree) \
4462 while (tree->STB_(N,right)) tree = tree->STB_(N,right); \
4466 TYPE *STB__(N,first)(TYPE *tree) \
4469 while (tree->STB_(N,left)) tree = tree->STB_(N,left); \
4473 TYPE *STB__(N,next)(TYPE *tree, TYPE *item) \
4475 TYPE *next = NULL; \
4476 if (item->STB_(N,right)) \
4477 return STB__(N,first)(item->STB_(N,right)); \
4479 while(item->STB_(N,parent)) { \
4480 TYPE *up = item->STB_(N,parent); \
4481 if (up->STB_(N,left) == item) return up; \
4486 while (tree != item) { \
4487 if (STB_(N,_compare)(item, tree) < 0) { \
4489 tree = tree->STB_(N,left); \
4491 tree = tree->STB_(N,right); \
4497 TYPE *STB__(N,prev)(TYPE *tree, TYPE *item) \
4499 TYPE *next = NULL; \
4500 if (item->STB_(N,left)) \
4501 return STB__(N,last)(item->STB_(N,left)); \
4503 while(item->STB_(N,parent)) { \
4504 TYPE *up = item->STB_(N,parent); \
4505 if (up->STB_(N,right) == item) return up; \
4510 while (tree != item) { \
4511 if (STB_(N,_compare)(item, tree) < 0) { \
4512 tree = tree->STB_(N,left); \
4515 tree = tree->STB_(N,right); \
4522 void STB__(N,_validate)(TYPE *tree, int root) \
4524 if (tree == NULL) return; \
4525 PAR(if(root) assert(tree->STB_(N,parent) == NULL);) \
4526 assert(STB__level(N,tree->STB_(N,left) ) == tree->STB_(N,level)-1); \
4527 assert(STB__level(N,tree->STB_(N,right)) <= tree->STB_(N,level)); \
4528 assert(STB__level(N,tree->STB_(N,right)) >= tree->STB_(N,level)-1); \
4529 if (tree->STB_(N,right)) { \
4530 assert(STB__level(N,tree->STB_(N,right)->STB_(N,right)) \
4531 != tree->STB_(N,level)); \
4532 PAR(assert(tree->STB_(N,right)->STB_(N,parent) == tree);) \
4534 PAR(if(tree->STB_(N,left)) assert(tree->STB_(N,left)->STB_(N,parent) == tree);) \
4535 STB__(N,_validate)(tree->STB_(N,left) ,0); \
4536 STB__(N,_validate)(tree->STB_(N,right),0); \
4545 void STB__(M,Insert)(TREE *tree, TYPE *item) \
4546 { tree->root = STB__(N,insert)(tree->root, item); } \
4547 void STB__(M,Remove)(TREE *tree, TYPE *item) \
4548 { tree->root = STB__(N,remove)(tree->root, item); } \
4549 TYPE *STB__(M,Next)(TREE *tree, TYPE *item) \
4550 { return STB__(N,next)(tree->root, item); } \
4551 TYPE *STB__(M,Prev)(TREE *tree, TYPE *item) \
4552 { return STB__(N,prev)(tree->root, item); } \
4553 TYPE *STB__(M,First)(TREE *tree) { return STB__(N,first)(tree->root); } \
4554 TYPE *STB__(M,Last) (TREE *tree) { return STB__(N,last) (tree->root); } \
4555 void STB__(M,Init)(TREE *tree) { tree->root = NULL; }
4558 #define stb_bst_find(N,tree,fcompare) \
4561 while (tree != NULL) { \
4563 if (c == 0) return tree; \
4564 if (c < 0) tree = tree->STB_(N,left); \
4565 else tree = tree->STB_(N,right); \
4570 #define stb_bst_raw(TYPE,N,TREE,M,vfield,VTYPE,compare,PAR) \
4571 stb_bst_base(TYPE,N,TREE,M, \
4572 VTYPE a = p->vfield; VTYPE b = q->vfield; return (compare);, PAR ) \
4574 TYPE *STB__(N,find)(TYPE *tree, VTYPE a) \
4575 stb_bst_find(N,tree,VTYPE b = tree->vfield; c = (compare);) \
4576 TYPE *STB__(M,Find)(TREE *tree, VTYPE a) \
4577 { return STB__(N,find)(tree->root, a); }
4579 #define stb_bst(TYPE,N,TREE,M,vfield,VTYPE,compare) \
4580 stb_bst_raw(TYPE,N,TREE,M,vfield,VTYPE,compare,stb__bst_noparent)
4581 #define stb_bst_parent(TYPE,N,TREE,M,vfield,VTYPE,compare) \
4582 stb_bst_raw(TYPE,N,TREE,M,vfield,VTYPE,compare,stb__bst_parent)
4586 //////////////////////////////////////////////////////////////////////////////
4590 // This lets you automatically NULL dangling pointers to "registered"
4591 // objects. Note that you have to make sure you call the appropriate
4592 // functions when you free or realloc blocks of memory that contain
4593 // pointers or pointer targets. stb.h can automatically do this for
4594 // stb_arr, or for all frees/reallocs if it's wrapping them.
4599 STB_EXTERN
void stb_nptr_set(void *address_of_pointer
, void *value_to_write
);
4600 STB_EXTERN
void stb_nptr_didset(void *address_of_pointer
);
4602 STB_EXTERN
void stb_nptr_didfree(void *address_being_freed
, int len
);
4603 STB_EXTERN
void stb_nptr_free(void *address_being_freed
, int len
);
4605 STB_EXTERN
void stb_nptr_didrealloc(void *new_address
, void *old_address
, int len
);
4606 STB_EXTERN
void stb_nptr_recache(void); // recache all known pointers
4607 // do this after pointer sets outside your control, slow
4610 // for fast updating on free/realloc, we need to be able to find
4611 // all the objects (pointers and targets) within a given block;
4612 // this precludes hashing
4614 // we use a three-level hierarchy of memory to minimize storage:
4615 // level 1: 65536 pointers to stb__memory_node (always uses 256 KB)
4616 // level 2: each stb__memory_node represents a 64K block of memory
4617 // with 256 stb__memory_leafs (worst case 64MB)
4618 // level 3: each stb__memory_leaf represents 256 bytes of memory
4619 // using a list of target locations and a list of pointers
4620 // (which are hopefully fairly short normally!)
4622 // this approach won't work in 64-bit, which has a much larger address
4623 // space. need to redesign
4625 #define STB__NPTR_ROOT_LOG2 16
4626 #define STB__NPTR_ROOT_NUM (1 << STB__NPTR_ROOT_LOG2)
4627 #define STB__NPTR_ROOT_SHIFT (32 - STB__NPTR_ROOT_LOG2)
4629 #define STB__NPTR_NODE_LOG2 5
4630 #define STB__NPTR_NODE_NUM (1 << STB__NPTR_NODE_LOG2)
4631 #define STB__NPTR_NODE_MASK (STB__NPTR_NODE_NUM-1)
4632 #define STB__NPTR_NODE_SHIFT (STB__NPTR_ROOT_SHIFT - STB__NPTR_NODE_LOG2)
4633 #define STB__NPTR_NODE_OFFSET(x) (((x) >> STB__NPTR_NODE_SHIFT) & STB__NPTR_NODE_MASK)
4635 typedef struct stb__st_nptr
4637 void *ptr
; // address of actual pointer
4638 struct stb__st_nptr
*next
; // next pointer with same target
4639 struct stb__st_nptr
**prev
; // prev pointer with same target, address of 'next' field (or first)
4640 struct stb__st_nptr
*next_in_block
;
4643 typedef struct stb__st_nptr_target
4645 void *ptr
; // address of target
4646 stb__nptr
*first
; // address of first nptr pointing to this
4647 struct stb__st_nptr_target
*next_in_block
;
4652 stb__nptr
*pointers
;
4653 stb__nptr_target
*targets
;
4658 stb__memory_leaf
*children
[STB__NPTR_NODE_NUM
];
4661 stb__memory_node
*stb__memtab_root
[STB__NPTR_ROOT_NUM
];
4663 static stb__memory_leaf
*stb__nptr_find_leaf(void *mem
)
4665 stb_uint32 address
= (stb_uint32
) mem
;
4666 stb__memory_node
*z
= stb__memtab_root
[address
>> STB__NPTR_ROOT_SHIFT
];
4668 return z
->children
[STB__NPTR_NODE_OFFSET(address
)];
4673 static void * stb__nptr_alloc(int size
)
4675 return stb__realloc_raw(0,size
);
4678 static void stb__nptr_free(void *p
)
4680 stb__realloc_raw(p
,0);
4683 static stb__memory_leaf
*stb__nptr_make_leaf(void *mem
)
4685 stb_uint32 address
= (stb_uint32
) mem
;
4686 stb__memory_node
*z
= stb__memtab_root
[address
>> STB__NPTR_ROOT_SHIFT
];
4687 stb__memory_leaf
*f
;
4690 z
= (stb__memory_node
*) stb__nptr_alloc(sizeof(*stb__memtab_root
[0]));
4691 stb__memtab_root
[address
>> STB__NPTR_ROOT_SHIFT
] = z
;
4692 for (i
=0; i
< 256; ++i
)
4695 f
= (stb__memory_leaf
*) stb__nptr_alloc(sizeof(*f
));
4696 z
->children
[STB__NPTR_NODE_OFFSET(address
)] = f
;
4702 static stb__nptr_target
*stb__nptr_find_target(void *target
, int force
)
4704 stb__memory_leaf
*p
= stb__nptr_find_leaf(target
);
4706 stb__nptr_target
*t
= p
->targets
;
4708 if (t
->ptr
== target
)
4710 t
= t
->next_in_block
;
4714 stb__nptr_target
*t
= (stb__nptr_target
*) stb__nptr_alloc(sizeof(*t
));
4715 if (!p
) p
= stb__nptr_make_leaf(target
);
4718 t
->next_in_block
= p
->targets
;
4725 static stb__nptr
*stb__nptr_find_pointer(void *ptr
, int force
)
4727 stb__memory_leaf
*p
= stb__nptr_find_leaf(ptr
);
4729 stb__nptr
*t
= p
->pointers
;
4733 t
= t
->next_in_block
;
4737 stb__nptr
*t
= (stb__nptr
*) stb__nptr_alloc(sizeof(*t
));
4738 if (!p
) p
= stb__nptr_make_leaf(ptr
);
4742 t
->next_in_block
= p
->pointers
;
4749 void stb_nptr_set(void *address_of_pointer
, void *value_to_write
)
4751 if (*(void **)address_of_pointer
!= value_to_write
) {
4752 *(void **) address_of_pointer
= value_to_write
;
4753 stb_nptr_didset(address_of_pointer
);
4757 void stb_nptr_didset(void *address_of_pointer
)
4759 // first unlink from old chain
4761 stb__nptr
*p
= stb__nptr_find_pointer(address_of_pointer
, 1); // force building if doesn't exist
4762 if (p
->prev
) { // if p->prev is NULL, we just built it, or it was NULL
4763 *(p
->prev
) = p
->next
;
4764 if (p
->next
) p
->next
->prev
= p
->prev
;
4766 // now add to new chain
4767 new_address
= *(void **)address_of_pointer
;
4768 if (new_address
!= NULL
) {
4769 stb__nptr_target
*t
= stb__nptr_find_target(new_address
, 1);
4771 if (p
->next
) p
->next
->prev
= &p
->next
;
4772 p
->prev
= &t
->first
;
4780 void stb__nptr_block(void *address
, int len
, void (*function
)(stb__memory_leaf
*f
, int datum
, void *start
, void *end
), int datum
)
4782 void *end_address
= (void *) ((char *) address
+ len
- 1);
4783 stb__memory_node
*n
;
4784 stb_uint32 start
= (stb_uint32
) address
;
4785 stb_uint32 end
= start
+ len
- 1;
4787 int b0
= start
>> STB__NPTR_ROOT_SHIFT
;
4788 int b1
= end
>> STB__NPTR_ROOT_SHIFT
;
4791 e0
= STB__NPTR_NODE_OFFSET(start
);
4795 n
= stb__memtab_root
[b0
];
4798 e1
= STB__NPTR_NODE_NUM
-1;
4800 e1
= STB__NPTR_NODE_OFFSET(end
);
4801 for (i
=e0
; i
<= e1
; ++i
)
4803 function(n
->children
[i
], datum
, address
, end_address
);
4806 // blocks other than the first and last block
4807 for (b
=b0
+1; b
< b1
; ++b
) {
4808 n
= stb__memtab_root
[b
];
4810 for (i
=0; i
<= STB__NPTR_NODE_NUM
-1; ++i
)
4812 function(n
->children
[i
], datum
, address
, end_address
);
4815 n
= stb__memtab_root
[b1
];
4817 e1
= STB__NPTR_NODE_OFFSET(end
);
4818 for (i
=0; i
<= e1
; ++i
)
4820 function(n
->children
[i
], datum
, address
, end_address
);
4826 n
= stb__memtab_root
[b1
];
4828 e1
= STB__NPTR_NODE_OFFSET(end
);
4829 for (i
=e1
; i
>= 0; --i
)
4831 function(n
->children
[i
], datum
, address
, end_address
);
4833 // blocks other than the first and last block
4834 for (b
=b1
-1; b
> b0
; --b
) {
4835 n
= stb__memtab_root
[b
];
4837 for (i
=STB__NPTR_NODE_NUM
-1; i
>= 0; --i
)
4839 function(n
->children
[i
], datum
, address
, end_address
);
4843 n
= stb__memtab_root
[b0
];
4846 e1
= STB__NPTR_NODE_NUM
-1;
4848 e1
= STB__NPTR_NODE_OFFSET(end
);
4849 for (i
=e1
; i
>= e0
; --i
)
4851 function(n
->children
[i
], datum
, address
, end_address
);
4856 static void stb__nptr_delete_pointers(stb__memory_leaf
*f
, int offset
, void *start
, void *end
)
4858 stb__nptr
**p
= &f
->pointers
;
4861 if (n
->ptr
>= start
&& n
->ptr
<= end
) {
4864 *(n
->prev
) = n
->next
;
4865 if (n
->next
) n
->next
->prev
= n
->prev
;
4867 *p
= n
->next_in_block
;
4870 p
= &(n
->next_in_block
);
4874 static void stb__nptr_delete_targets(stb__memory_leaf
*f
, int offset
, void *start
, void *end
)
4876 stb__nptr_target
**p
= &f
->targets
;
4878 stb__nptr_target
*n
= *p
;
4879 if (n
->ptr
>= start
&& n
->ptr
<= end
) {
4881 stb__nptr
*z
= n
->first
;
4883 stb__nptr
*y
= z
->next
;
4886 *(void **) z
->ptr
= NULL
;
4889 // unlink this target
4890 *p
= n
->next_in_block
;
4893 p
= &(n
->next_in_block
);
4897 void stb_nptr_didfree(void *address_being_freed
, int len
)
4899 // step one: delete all pointers in this block
4900 stb__nptr_block(address_being_freed
, len
, stb__nptr_delete_pointers
, 0);
4901 // step two: NULL all pointers to this block; do this second to avoid NULLing deleted pointers
4902 stb__nptr_block(address_being_freed
, len
, stb__nptr_delete_targets
, 0);
4905 void stb_nptr_free(void *address_being_freed
, int len
)
4907 free(address_being_freed
);
4908 stb_nptr_didfree(address_being_freed
, len
);
4911 static void stb__nptr_move_targets(stb__memory_leaf
*f
, int offset
, void *start
, void *end
)
4913 stb__nptr_target
**t
= &f
->targets
;
4915 stb__nptr_target
*n
= *t
;
4916 if (n
->ptr
>= start
&& n
->ptr
<= end
) {
4918 stb__memory_leaf
*f
;
4920 *t
= n
->next_in_block
;
4921 // update n to new address
4922 n
->ptr
= (void *) ((char *) n
->ptr
+ offset
);
4923 f
= stb__nptr_find_leaf(n
->ptr
);
4924 if (!f
) f
= stb__nptr_make_leaf(n
->ptr
);
4925 n
->next_in_block
= f
->targets
;
4927 // now go through all pointers and make them point here
4930 *(void**) z
->ptr
= n
->ptr
;
4934 t
= &(n
->next_in_block
);
4938 static void stb__nptr_move_pointers(stb__memory_leaf
*f
, int offset
, void *start
, void *end
)
4940 stb__nptr
**p
= &f
->pointers
;
4943 if (n
->ptr
>= start
&& n
->ptr
<= end
) {
4945 *p
= n
->next_in_block
;
4946 n
->ptr
= (void *) ((int) n
->ptr
+ offset
);
4947 // move to new block
4948 f
= stb__nptr_find_leaf(n
->ptr
);
4949 if (!f
) f
= stb__nptr_make_leaf(n
->ptr
);
4950 n
->next_in_block
= f
->pointers
;
4953 p
= &(n
->next_in_block
);
4957 void stb_nptr_realloc(void *new_address
, void *old_address
, int len
)
4959 if (new_address
== old_address
) return;
4961 // have to move the pointers first, because moving the targets
4962 // requires writing to the pointers-to-the-targets, and if some of those moved too,
4963 // we need to make sure we don't write to the old memory
4965 // step one: move all pointers within the block
4966 stb__nptr_block(old_address
, len
, stb__nptr_move_pointers
, (char *) new_address
- (char *) old_address
);
4967 // step two: move all targets within the block
4968 stb__nptr_block(old_address
, len
, stb__nptr_move_targets
, (char *) new_address
- (char *) old_address
);
4971 void stb_nptr_move(void *new_address
, void *old_address
)
4973 stb_nptr_realloc(new_address
, old_address
, 1);
4976 void stb_nptr_recache(void)
4979 for (i
=0; i
< STB__NPTR_ROOT_NUM
; ++i
)
4980 if (stb__memtab_root
[i
])
4981 for (j
=0; j
< STB__NPTR_NODE_NUM
; ++j
)
4982 if (stb__memtab_root
[i
]->children
[j
]) {
4983 stb__nptr
*p
= stb__memtab_root
[i
]->children
[j
]->pointers
;
4985 stb_nptr_didset(p
->ptr
);
4986 p
= p
->next_in_block
;
4991 #endif // STB_DEFINE
4995 //////////////////////////////////////////////////////////////////////////////
5002 #define stb_rename(x,y) _wrename((const wchar_t *)stb__from_utf8(x), (const wchar_t *)stb__from_utf8_alt(y))
5003 #define stb_mktemp _mktemp
5005 #define stb_mktemp mktemp
5006 #define stb_rename rename
5009 STB_EXTERN
void stb_fput_varlen64(FILE *f
, stb_uint64 v
);
5010 STB_EXTERN stb_uint64
stb_fget_varlen64(FILE *f
);
5011 STB_EXTERN
int stb_size_varlen64(stb_uint64 v
);
5014 #define stb_filec (char *) stb_file
5015 #define stb_fileu (unsigned char *) stb_file
5016 STB_EXTERN
void * stb_file(char *filename
, size_t *length
);
5017 STB_EXTERN
void * stb_file_max(char *filename
, size_t *length
);
5018 STB_EXTERN
size_t stb_filelen(FILE *f
);
5019 STB_EXTERN
int stb_filewrite(char *filename
, void *data
, size_t length
);
5020 STB_EXTERN
int stb_filewritestr(char *filename
, char *data
);
5021 STB_EXTERN
char ** stb_stringfile(char *filename
, int *len
);
5022 STB_EXTERN
char ** stb_stringfile_trimmed(char *name
, int *len
, char comm
);
5023 STB_EXTERN
char * stb_fgets(char *buffer
, int buflen
, FILE *f
);
5024 STB_EXTERN
char * stb_fgets_malloc(FILE *f
);
5025 STB_EXTERN
int stb_fexists(char *filename
);
5026 STB_EXTERN
int stb_fcmp(char *s1
, char *s2
);
5027 STB_EXTERN
int stb_feq(char *s1
, char *s2
);
5028 STB_EXTERN
time_t stb_ftimestamp(char *filename
);
5030 STB_EXTERN
int stb_fullpath(char *abs
, int abs_size
, char *rel
);
5031 STB_EXTERN
FILE * stb_fopen(char *filename
, char *mode
);
5032 STB_EXTERN
int stb_fclose(FILE *f
, int keep
);
5038 stb_keep_if_different
= 2,
5041 STB_EXTERN
int stb_copyfile(char *src
, char *dest
);
5043 STB_EXTERN
void stb_fput_varlen64(FILE *f
, stb_uint64 v
);
5044 STB_EXTERN stb_uint64
stb_fget_varlen64(FILE *f
);
5045 STB_EXTERN
int stb_size_varlen64(stb_uint64 v
);
5047 STB_EXTERN
void stb_fwrite32(FILE *f
, stb_uint32 datum
);
5048 STB_EXTERN
void stb_fput_varlen (FILE *f
, int v
);
5049 STB_EXTERN
void stb_fput_varlenu(FILE *f
, unsigned int v
);
5050 STB_EXTERN
int stb_fget_varlen (FILE *f
);
5051 STB_EXTERN stb_uint
stb_fget_varlenu(FILE *f
);
5052 STB_EXTERN
void stb_fput_ranged (FILE *f
, int v
, int b
, stb_uint n
);
5053 STB_EXTERN
int stb_fget_ranged (FILE *f
, int b
, stb_uint n
);
5054 STB_EXTERN
int stb_size_varlen (int v
);
5055 STB_EXTERN
int stb_size_varlenu(unsigned int v
);
5056 STB_EXTERN
int stb_size_ranged (int b
, stb_uint n
);
5058 STB_EXTERN
int stb_fread(void *data
, size_t len
, size_t count
, void *f
);
5059 STB_EXTERN
int stb_fwrite(void *data
, size_t len
, size_t count
, void *f
);
5071 STB_EXTERN STBF
*stb_tfopen(char *filename
, char *mode
);
5072 STB_EXTERN
int stb_tfread(void *data
, size_t len
, size_t count
, STBF
*f
);
5073 STB_EXTERN
int stb_tfwrite(void *data
, size_t len
, size_t count
, STBF
*f
);
5079 STBF
*stb_tfopen(char *filename
, char *mode
)
5082 FILE *f
= fopen(filename
, mode
);
5083 if (!f
) return NULL
;
5084 z
= (STBF
*) malloc(sizeof(*z
));
5085 if (!z
) { fclose(f
); return NULL
; }
5087 if (!strcmp(mode
, "rb") || !strcmp(mode
, "wb")) {
5088 z
->buffer_size
= 4096;
5089 z
->buffer_off
= z
->buffer_size
;
5091 z
->buffer
= malloc(z
->buffer_size
);
5092 if (!z
->buffer
) { free(z
); fclose(f
); return NULL
; }
5101 int stb_tfread(void *data
, size_t len
, size_t count
, STBF
*f
)
5103 int total
= len
*count
, done
=0;
5104 if (!total
) return 0;
5105 if (total
<= z
->buffer_left
) {
5106 memcpy(data
, z
->buffer
+ z
->buffer_off
, total
);
5107 z
->buffer_off
+= total
;
5108 z
->buffer_left
-= total
;
5111 char *out
= (char *) data
;
5113 // consume all buffered data
5114 memcpy(data
, z
->buffer
+ z
->buffer_off
, z
->buffer_left
);
5115 done
= z
->buffer_left
;
5116 out
+= z
->buffer_left
;
5119 if (total
-done
> (z
->buffer_size
>> 1)) {
5126 void stb_fwrite32(FILE *f
, stb_uint32 x
)
5128 fwrite(&x
, 4, 1, f
);
5131 #if defined(_MSC_VER) || defined(__MINGW32__)
5132 #define stb__stat _stat
5134 #define stb__stat stat
5137 int stb_fexists(char *filename
)
5139 struct stb__stat buf
;
5140 return stb__windows(
5141 _wstat((const wchar_t *)stb__from_utf8(filename
), &buf
),
5146 time_t stb_ftimestamp(char *filename
)
5148 struct stb__stat buf
;
5150 _wstat((const wchar_t *)stb__from_utf8(filename
), &buf
),
5154 return buf
.st_mtime
;
5160 size_t stb_filelen(FILE *f
)
5164 fseek(f
, 0, SEEK_END
);
5166 fseek(f
, pos
, SEEK_SET
);
5170 void *stb_file(char *filename
, size_t *length
)
5172 FILE *f
= stb__fopen(filename
, "rb");
5175 if (!f
) return NULL
;
5176 len
= stb_filelen(f
);
5177 buffer
= (char *) malloc(len
+2); // nul + extra
5178 len2
= fread(buffer
, 1, len
, f
);
5180 if (length
) *length
= len
;
5190 int stb_filewrite(char *filename
, void *data
, size_t length
)
5192 FILE *f
= stb_fopen(filename
, "wb");
5194 unsigned char *data_ptr
= (unsigned char *) data
;
5195 size_t remaining
= length
;
5196 while (remaining
> 0) {
5197 size_t len2
= remaining
> 65536 ? 65536 : remaining
;
5198 size_t len3
= fwrite(data_ptr
, 1, len2
, f
);
5200 fprintf(stderr
, "Failed while writing %s\n", filename
);
5206 stb_fclose(f
, stb_keep_if_different
);
5211 int stb_filewritestr(char *filename
, char *data
)
5213 return stb_filewrite(filename
, data
, strlen(data
));
5216 void * stb_file_max(char *filename
, size_t *length
)
5218 FILE *f
= stb__fopen(filename
, "rb");
5221 if (!f
) return NULL
;
5223 buffer
= (char *) malloc(maxlen
+1);
5224 len
= fread(buffer
, 1, maxlen
, f
);
5231 char ** stb_stringfile(char *filename
, int *plen
)
5233 FILE *f
= stb__fopen(filename
, "rb");
5234 char *buffer
, **list
=NULL
, *s
;
5235 size_t len
, count
, i
;
5237 if (!f
) return NULL
;
5238 len
= stb_filelen(f
);
5239 buffer
= (char *) malloc(len
+1);
5240 len
= fread(buffer
, 1, len
, f
);
5244 // two passes through: first time count lines, second time set them
5245 for (i
=0; i
< 2; ++i
) {
5251 if (*s
== '\n' || *s
== '\r') {
5252 // detect if both cr & lf are together
5253 int crlf
= (s
[0] + s
[1]) == ('\n' + '\r');
5256 if (s
[1]) { // it's not over yet
5257 if (i
== 1) list
[count
] = s
+1;
5264 list
= (char **) malloc(sizeof(*list
) * (count
+1) + len
+1);
5265 if (!list
) return NULL
;
5267 // recopy the file so there's just a single allocation to free
5268 memcpy(&list
[count
+1], buffer
, len
+1);
5270 buffer
= (char *) &list
[count
+1];
5271 if (plen
) *plen
= count
;
5277 char ** stb_stringfile_trimmed(char *name
, int *len
, char comment
)
5280 char **s
= stb_stringfile(name
, &n
);
5281 if (s
== NULL
) return NULL
;
5282 for (i
=0; i
< n
; ++i
) {
5283 char *p
= stb_skipwhite(s
[i
]);
5284 if (*p
&& *p
!= comment
)
5292 char * stb_fgets(char *buffer
, int buflen
, FILE *f
)
5296 p
= fgets(buffer
, buflen
, f
);
5298 int n
= strlen(p
)-1;
5306 char * stb_fgets_malloc(FILE *f
)
5308 // avoid reallocing for small strings
5309 char quick_buffer
[800];
5310 quick_buffer
[sizeof(quick_buffer
)-2] = 0;
5311 if (!fgets(quick_buffer
, sizeof(quick_buffer
), f
))
5314 if (quick_buffer
[sizeof(quick_buffer
)-2] == 0) {
5315 int n
= strlen(quick_buffer
);
5316 if (n
> 0 && quick_buffer
[n
-1] == '\n')
5317 quick_buffer
[n
-1] = 0;
5318 return strdup(quick_buffer
);
5321 char *a
= strdup(quick_buffer
);
5322 int len
= sizeof(quick_buffer
)-1;
5325 if (a
[len
-1] == '\n') break;
5326 a
= (char *) realloc(a
, len
*2);
5329 if (!fgets(p
, len
, f
))
5331 if (p
[len
-2] == 0) {
5335 len
= len
+ (len
-1);
5337 if (a
[len
-1] == '\n')
5343 int stb_fullpath(char *abs
, int abs_size
, char *rel
)
5346 return _fullpath(abs
, rel
, abs_size
) != NULL
;
5348 if (rel
[0] == '/' || rel
[0] == '~') {
5349 if ((int) strlen(rel
) >= abs_size
)
5355 getcwd(abs
, abs_size
);
5357 if (n
+(int) strlen(rel
)+2 <= abs_size
) {
5359 strcpy(abs
+n
+1, rel
);
5368 static int stb_fcmp_core(FILE *f
, FILE *g
)
5370 char buf1
[1024],buf2
[1024];
5374 n1
= fread(buf1
, 1, sizeof(buf1
), f
);
5375 n2
= fread(buf2
, 1, sizeof(buf2
), g
);
5376 res
= memcmp(buf1
,buf2
,stb_min(n1
,n2
));
5380 res
= n1
< n2
? -1 : 1;
5392 int stb_fcmp(char *s1
, char *s2
)
5394 FILE *f
= stb__fopen(s1
, "rb");
5395 FILE *g
= stb__fopen(s2
, "rb");
5397 if (f
== NULL
|| g
== NULL
) {
5406 return stb_fcmp_core(f
,g
);
5409 int stb_feq(char *s1
, char *s2
)
5411 FILE *f
= stb__fopen(s1
, "rb");
5412 FILE *g
= stb__fopen(s2
, "rb");
5414 if (f
== NULL
|| g
== NULL
) {
5420 // feq is faster because it shortcuts if they're different length
5421 if (stb_filelen(f
) != stb_filelen(g
)) {
5427 return !stb_fcmp_core(f
,g
);
5430 static stb_ptrmap
*stb__files
;
5439 FILE * stb_fopen(char *filename
, char *mode
)
5442 char name_full
[4096];
5443 char temp_full
[sizeof(name_full
) + 12];
5448 if (mode
[0] != 'w' && !strchr(mode
, '+'))
5449 return stb__fopen(filename
, mode
);
5451 // save away the full path to the file so if the program
5452 // changes the cwd everything still works right! unix has
5453 // better ways to do this, but we have to work in windows
5454 name_full
[0] = '\0'; // stb_fullpath reads name_full[0]
5455 if (stb_fullpath(name_full
, sizeof(name_full
), filename
)==0)
5458 // try to generate a temporary file in the same directory
5459 p
= strlen(name_full
)-1;
5460 while (p
> 0 && name_full
[p
] != '/' && name_full
[p
] != '\\'
5461 && name_full
[p
] != ':' && name_full
[p
] != '~')
5465 memcpy(temp_full
, name_full
, p
);
5468 // try multiple times to make a temp file... just in
5469 // case some other process makes the name first
5470 for (j
=0; j
< 32; ++j
) {
5471 strcpy(temp_full
+p
, "stmpXXXXXX");
5472 if (stb_mktemp(temp_full
) == NULL
)
5475 f
= fopen(temp_full
, mode
);
5481 strcpy(temp_full
+p
, "stmpXXXXXX");
5483 int fd
= open(mktemp(temp_full
), O_RDWR
);
5485 int fd
= mkstemp(temp_full
);
5487 if (fd
== -1) return NULL
;
5488 f
= fdopen(fd
, mode
);
5497 stb__file_data
*d
= (stb__file_data
*) malloc(sizeof(*d
));
5498 if (!d
) { assert(0); /* NOTREACHED */fclose(f
); return NULL
; }
5499 if (stb__files
== NULL
) stb__files
= stb_ptrmap_create();
5500 d
->temp_name
= strdup(temp_full
);
5501 d
->name
= strdup(name_full
);
5503 stb_ptrmap_add(stb__files
, f
, d
);
5510 int stb_fclose(FILE *f
, int keep
)
5515 if (f
== NULL
) return 0;
5522 if (stb__files
&& stb_ptrmap_remove(stb__files
, f
, (void **) &d
)) {
5523 if (stb__files
->count
== 0) {
5524 stb_ptrmap_destroy(stb__files
);
5528 return STB_TRUE
; // not special
5530 if (keep
== stb_keep_if_different
) {
5531 // check if the files are identical
5532 if (stb_feq(d
->name
, d
->temp_name
)) {
5534 ok
= STB_TRUE
; // report success if no change
5538 if (keep
!= stb_keep_no
) {
5539 if (stb_fexists(d
->name
) && remove(d
->name
)) {
5540 // failed to delete old, so don't keep new
5543 if (!stb_rename(d
->temp_name
, d
->name
))
5550 if (keep
== stb_keep_no
)
5551 remove(d
->temp_name
);
5560 int stb_copyfile(char *src
, char *dest
)
5562 char raw_buffer
[1024];
5564 int buf_size
= 65536;
5568 // if file already exists at destination, do nothing
5569 if (stb_feq(src
, dest
)) return STB_TRUE
;
5572 f
= stb__fopen(src
, "rb");
5573 if (f
== NULL
) return STB_FALSE
;
5575 // open file for writing
5576 g
= stb__fopen(dest
, "wb");
5582 buffer
= (char *) malloc(buf_size
);
5583 if (buffer
== NULL
) {
5584 buffer
= raw_buffer
;
5585 buf_size
= sizeof(raw_buffer
);
5589 int n
= fread(buffer
, 1, buf_size
, f
);
5591 fwrite(buffer
, 1, n
, g
);
5595 if (buffer
!= raw_buffer
)
5603 // v' = (v >> 31) + (v < 0 ? ~v : v)<<1; // small abs(v) => small v'
5604 // output v as big endian v'+k for v' <= k:
5605 // 1 byte : v' <= 0x00000080 ( -64 <= v < 64) 7 bits
5606 // 2 bytes: v' <= 0x00004000 (-8192 <= v < 8192) 14 bits
5607 // 3 bytes: v' <= 0x00200000 21 bits
5608 // 4 bytes: v' <= 0x10000000 28 bits
5609 // the number of most significant 1-bits in the first byte
5610 // equals the number of bytes after the first
5612 #define stb__varlen_xform(v) (v<0 ? (~v << 1)+1 : (v << 1))
5614 int stb_size_varlen(int v
) { return stb_size_varlenu(stb__varlen_xform(v
)); }
5615 int stb_size_varlenu(unsigned int v
)
5617 if (v
< 0x00000080) return 1;
5618 if (v
< 0x00004000) return 2;
5619 if (v
< 0x00200000) return 3;
5620 if (v
< 0x10000000) return 4;
5624 void stb_fput_varlen(FILE *f
, int v
) { stb_fput_varlenu(f
, stb__varlen_xform(v
)); }
5626 void stb_fput_varlenu(FILE *f
, unsigned int z
)
5628 if (z
>= 0x10000000) fputc(0xF0,f
);
5629 if (z
>= 0x00200000) fputc((z
< 0x10000000 ? 0xE0 : 0)+(z
>>24),f
);
5630 if (z
>= 0x00004000) fputc((z
< 0x00200000 ? 0xC0 : 0)+(z
>>16),f
);
5631 if (z
>= 0x00000080) fputc((z
< 0x00004000 ? 0x80 : 0)+(z
>> 8),f
);
5635 #define stb_fgetc(f) ((unsigned char) fgetc(f))
5637 int stb_fget_varlen(FILE *f
)
5639 unsigned int z
= stb_fget_varlenu(f
);
5640 return (z
& 1) ? ~(z
>>1) : (z
>>1);
5643 unsigned int stb_fget_varlenu(FILE *f
)
5652 if (d
== 0xf0) z
= stb_fgetc(f
) << 24;
5653 else z
= (d
- 0xe0) << 24;
5654 z
+= stb_fgetc(f
) << 16;
5657 z
= (d
- 0xc0) << 16;
5658 z
+= stb_fgetc(f
) << 8;
5660 z
= (d
- 0x80) << 8;
5667 stb_uint64
stb_fget_varlen64(FILE *f
)
5681 z
= (stb_uint64
) stb_fgetc(f
) << 56;
5683 z
= (stb_uint64
) (d
- 0xfe) << 56;
5684 z
|= (stb_uint64
) stb_fgetc(f
) << 48;
5685 } else z
= (stb_uint64
) (d
- 0xfc) << 48;
5686 z
|= (stb_uint64
) stb_fgetc(f
) << 40;
5687 } else z
= (stb_uint64
) (d
- 0xf8) << 40;
5688 z
|= (stb_uint64
) stb_fgetc(f
) << 32;
5689 } else z
= (stb_uint64
) (d
- 0xf0) << 32;
5690 z
|= (stb_uint
) stb_fgetc(f
) << 24;
5691 } else z
= (stb_uint
) (d
- 0xe0) << 24;
5692 z
|= (stb_uint
) stb_fgetc(f
) << 16;
5693 } else z
= (stb_uint
) (d
- 0xc0) << 16;
5694 z
|= (stb_uint
) stb_fgetc(f
) << 8;
5695 } else z
= (stb_uint
) (d
- 0x80) << 8;
5700 return (z
& 1) ? ~(z
>> 1) : (z
>> 1);
5703 int stb_size_varlen64(stb_uint64 v
)
5705 if (v
< 0x00000080) return 1;
5706 if (v
< 0x00004000) return 2;
5707 if (v
< 0x00200000) return 3;
5708 if (v
< 0x10000000) return 4;
5709 if (v
< STB_IMM_UINT64(0x0000000800000000)) return 5;
5710 if (v
< STB_IMM_UINT64(0x0000040000000000)) return 6;
5711 if (v
< STB_IMM_UINT64(0x0002000000000000)) return 7;
5712 if (v
< STB_IMM_UINT64(0x0100000000000000)) return 8;
5716 void stb_fput_varlen64(FILE *f
, stb_uint64 v
)
5718 stb_uint64 z
= stb__varlen_xform(v
);
5720 if (z
>= STB_IMM_UINT64(0x100000000000000)) {
5724 if (z
>= STB_IMM_UINT64(0x02000000000000)) fputc((first
? 0xFE : 0)+(char)(z
>>56),f
), first
=0;
5725 if (z
>= STB_IMM_UINT64(0x00040000000000)) fputc((first
? 0xFC : 0)+(char)(z
>>48),f
), first
=0;
5726 if (z
>= STB_IMM_UINT64(0x00000800000000)) fputc((first
? 0xF8 : 0)+(char)(z
>>40),f
), first
=0;
5727 if (z
>= STB_IMM_UINT64(0x00000010000000)) fputc((first
? 0xF0 : 0)+(char)(z
>>32),f
), first
=0;
5728 if (z
>= STB_IMM_UINT64(0x00000000200000)) fputc((first
? 0xE0 : 0)+(char)(z
>>24),f
), first
=0;
5729 if (z
>= STB_IMM_UINT64(0x00000000004000)) fputc((first
? 0xC0 : 0)+(char)(z
>>16),f
), first
=0;
5730 if (z
>= STB_IMM_UINT64(0x00000000000080)) fputc((first
? 0x80 : 0)+(char)(z
>> 8),f
), first
=0;
5734 void stb_fput_ranged(FILE *f
, int v
, int b
, stb_uint n
)
5738 assert((stb_uint
) v
< n
);
5739 if (n
> (1 << 24)) fputc(v
>> 24, f
);
5740 if (n
> (1 << 16)) fputc(v
>> 16, f
);
5741 if (n
> (1 << 8)) fputc(v
>> 8, f
);
5745 int stb_fget_ranged(FILE *f
, int b
, stb_uint n
)
5748 if (n
> (1 << 24)) v
+= stb_fgetc(f
) << 24;
5749 if (n
> (1 << 16)) v
+= stb_fgetc(f
) << 16;
5750 if (n
> (1 << 8)) v
+= stb_fgetc(f
) << 8;
5755 int stb_size_ranged(int b
, stb_uint n
)
5757 if (n
> (1 << 24)) return 4;
5758 if (n
> (1 << 16)) return 3;
5759 if (n
> (1 << 8)) return 2;
5763 void stb_fput_string(FILE *f
, char *s
)
5765 int len
= strlen(s
);
5766 stb_fput_varlenu(f
, len
);
5767 fwrite(s
, 1, len
, f
);
5770 // inverse of the above algorithm
5771 char *stb_fget_string(FILE *f
, void *p
)
5774 int len
= stb_fget_varlenu(f
);
5775 if (len
> 4096) return NULL
;
5776 s
= p
? stb_malloc_string(p
, len
+1) : (char *) malloc(len
+1);
5777 fread(s
, 1, len
, f
);
5782 char *stb_strdup(char *str
, void *pool
)
5784 int len
= strlen(str
);
5785 char *p
= stb_malloc_string(pool
, len
+1);
5790 // strip the trailing '/' or '\\' from a directory so we can refer to it
5791 // as a file for _stat()
5792 char *stb_strip_final_slash(char *t
)
5795 char *z
= t
+ strlen(t
) - 1;
5796 // *z is the last character
5797 if (*z
== '\\' || *z
== '/')
5798 if (z
!= t
+2 || t
[1] != ':') // but don't strip it if it's e.g. "c:/"
5801 *z
= '/'; // canonicalize to make sure it matches db
5806 char *stb_strip_final_slash_regardless(char *t
)
5809 char *z
= t
+ strlen(t
) - 1;
5810 // *z is the last character
5811 if (*z
== '\\' || *z
== '/')
5814 *z
= '/'; // canonicalize to make sure it matches db
5820 //////////////////////////////////////////////////////////////////////////////
5825 STB_EXTERN
char **stb_getopt_param(int *argc
, char **argv
, char *param
);
5826 STB_EXTERN
char **stb_getopt(int *argc
, char **argv
);
5827 STB_EXTERN
void stb_getopt_free(char **opts
);
5831 void stb_getopt_free(char **opts
)
5835 for (i
=0; i
< stb_arr_len(o2
); ++i
)
5840 char **stb_getopt(int *argc
, char **argv
)
5842 return stb_getopt_param(argc
, argv
, "");
5845 char **stb_getopt_param(int *argc
, char **argv
, char *param
)
5849 for (i
=1; i
< *argc
; ++i
) {
5850 if (argv
[i
][0] != '-') {
5851 argv
[j
++] = argv
[i
];
5853 if (argv
[i
][1] == 0) { // plain - == don't parse further options
5856 argv
[j
++] = argv
[i
++];
5860 char *q
= argv
[i
]; // traverse options list
5861 for (k
=1; q
[k
]; ++k
) {
5863 if (strchr(param
, q
[k
])) { // does it take a parameter?
5864 char *t
= &q
[k
+1], z
= q
[k
];
5867 if (i
== *argc
-1) { // takes a parameter, but none found
5869 stb_getopt_free(opts
);
5876 s
= (char *) malloc(len
+2);
5877 if (!s
) return NULL
;
5882 s
= (char *) malloc(2);
5883 if (!s
) return NULL
;
5887 stb_arr_push(opts
, s
);
5892 stb_arr_push(opts
, NULL
);
5899 //////////////////////////////////////////////////////////////////////////////
5901 // Portable directory reading
5904 STB_EXTERN
char **stb_readdir_files (char *dir
);
5905 STB_EXTERN
char **stb_readdir_files_mask(char *dir
, char *wild
);
5906 STB_EXTERN
char **stb_readdir_subdirs(char *dir
);
5907 STB_EXTERN
char **stb_readdir_subdirs_mask(char *dir
, char *wild
);
5908 STB_EXTERN
void stb_readdir_free (char **files
);
5909 STB_EXTERN
char **stb_readdir_recursive(char *dir
, char *filespec
);
5910 STB_EXTERN
void stb_delete_directory_recursive(char *dir
);
5921 void stb_readdir_free(char **files
)
5925 for (i
=0; i
< stb_arr_len(f2
); ++i
)
5930 static int isdotdirname(char *name
)
5933 return (name
[1] == '.') ? !name
[2] : !name
[1];
5937 STB_EXTERN
int stb_wildmatchi(char *expr
, char *candidate
);
5938 static char **readdir_raw(char *dir
, int return_subdirs
, char *mask
)
5940 char **results
= NULL
;
5941 char buffer
[4096], with_slash
[4096];
5946 struct _wfinddata_t data
;
5948 const intptr_t none
= -1;
5951 const long none
= -1;
5955 const DIR *none
= NULL
;
5959 n
= stb_strscpy(buffer
,dir
,sizeof(buffer
));
5960 if (!n
|| n
>= sizeof(buffer
))
5962 stb_fixpath(buffer
);
5965 if (n
> 0 && (buffer
[n
-1] != '/')) {
5969 if (!stb_strscpy(with_slash
,buffer
,sizeof(with_slash
)))
5973 if (!stb_strscpy(buffer
+n
,"*.*",sizeof(buffer
)-n
))
5975 ws
= stb__from_utf8(buffer
);
5976 z
= _wfindfirst((const wchar_t *)ws
, &data
);
5982 int nonempty
= STB_TRUE
;
5984 struct dirent
*data
= readdir(z
);
5985 nonempty
= (data
!= NULL
);
5993 char *name
= stb__to_utf8((stb__wchar
*)data
.name
);
5995 fprintf(stderr
, "%s to convert '%S' to %s!\n", "Unable", data
.name
, "utf8");
5998 is_subdir
= !!(data
.attrib
& _A_SUBDIR
);
6000 char *name
= data
->d_name
;
6001 if (!stb_strscpy(buffer
+n
,name
,sizeof(buffer
)-n
))
6003 // Could follow DT_LNK, but would need to check for recursive links.
6004 is_subdir
= !!(data
->d_type
& DT_DIR
);
6007 if (is_subdir
== return_subdirs
) {
6008 if (!is_subdir
|| !isdotdirname(name
)) {
6009 if (!mask
|| stb_wildmatchi(mask
, name
)) {
6010 char buffer
[4096],*p
=buffer
;
6011 if ( stb_snprintf(buffer
, sizeof(buffer
), "%s%s", with_slash
, name
) < 0 )
6013 if (buffer
[0] == '.' && buffer
[1] == '/')
6015 stb_arr_push(results
, strdup(p
));
6021 while (0 == _wfindnext(z
, &data
));
6023 while ((data
= readdir(z
)) != NULL
);
6035 char **stb_readdir_files (char *dir
) { return readdir_raw(dir
, 0, NULL
); }
6036 char **stb_readdir_subdirs(char *dir
) { return readdir_raw(dir
, 1, NULL
); }
6037 char **stb_readdir_files_mask(char *dir
, char *wild
) { return readdir_raw(dir
, 0, wild
); }
6038 char **stb_readdir_subdirs_mask(char *dir
, char *wild
) { return readdir_raw(dir
, 1, wild
); }
6040 int stb__rec_max
=0x7fffffff;
6041 static char **stb_readdir_rec(char **sofar
, char *dir
, char *filespec
)
6047 if (stb_arr_len(sofar
) >= stb__rec_max
) return sofar
;
6049 files
= stb_readdir_files_mask(dir
, filespec
);
6050 stb_arr_for(p
, files
) {
6051 stb_arr_push(sofar
, strdup(*p
));
6052 if (stb_arr_len(sofar
) >= stb__rec_max
) break;
6054 stb_readdir_free(files
);
6055 if (stb_arr_len(sofar
) >= stb__rec_max
) return sofar
;
6057 dirs
= stb_readdir_subdirs(dir
);
6058 stb_arr_for(p
, dirs
)
6059 sofar
= stb_readdir_rec(sofar
, *p
, filespec
);
6060 stb_readdir_free(dirs
);
6064 char **stb_readdir_recursive(char *dir
, char *filespec
)
6066 return stb_readdir_rec(NULL
, dir
, filespec
);
6069 void stb_delete_directory_recursive(char *dir
)
6071 char **list
= stb_readdir_subdirs(dir
);
6073 for (i
=0; i
< stb_arr_len(list
); ++i
)
6074 stb_delete_directory_recursive(list
[i
]);
6076 list
= stb_readdir_files(dir
);
6077 for (i
=0; i
< stb_arr_len(list
); ++i
)
6078 if (!remove(list
[i
])) {
6079 // on windows, try again after making it writeable; don't ALWAYS
6080 // do this first since that would be slow in the normal case
6082 _chmod(list
[i
], _S_IWRITE
);
6087 stb__windows(_rmdir
,rmdir
)(dir
);
6092 //////////////////////////////////////////////////////////////////////////////
6094 // construct trees from filenames; useful for cmirror summaries
6096 typedef struct stb_dirtree2 stb_dirtree2
;
6100 stb_dirtree2
**subdirs
;
6102 // make convenient for stb_summarize_tree
6112 STB_EXTERN stb_dirtree2
*stb_dirtree2_from_files_relative(char *src
, char **filelist
, int count
);
6113 STB_EXTERN stb_dirtree2
*stb_dirtree2_from_files(char **filelist
, int count
);
6114 STB_EXTERN
int stb_dir_is_prefix(char *dir
, int dirlen
, char *file
);
6118 int stb_dir_is_prefix(char *dir
, int dirlen
, char *file
)
6120 if (dirlen
== 0) return STB_TRUE
;
6121 if (stb_strnicmp(dir
, file
, dirlen
)) return STB_FALSE
;
6122 if (file
[dirlen
] == '/' || file
[dirlen
] == '\\') return STB_TRUE
;
6126 stb_dirtree2
*stb_dirtree2_from_files_relative(char *src
, char **filelist
, int count
)
6130 int dlen
= strlen(src
), elen
;
6132 char ** descendents
= NULL
;
6133 char ** files
= NULL
;
6135 if (!count
) return NULL
;
6136 // first find all the ones that belong here... note this is will take O(NM) with N files and M subdirs
6137 for (i
=0; i
< count
; ++i
) {
6138 if (stb_dir_is_prefix(src
, dlen
, filelist
[i
])) {
6139 stb_arr_push(descendents
, filelist
[i
]);
6142 if (descendents
== NULL
)
6145 // skip a leading slash
6146 if (elen
== 0 && (descendents
[0][0] == '/' || descendents
[0][0] == '\\'))
6150 // now extract all the ones that have their root here
6151 for (i
=0; i
< stb_arr_len(descendents
);) {
6152 if (!stb_strchr2(descendents
[i
]+elen
, '/', '\\')) {
6153 stb_arr_push(files
, descendents
[i
]);
6154 descendents
[i
] = descendents
[stb_arr_len(descendents
)-1];
6155 stb_arr_pop(descendents
);
6159 // now create a record
6160 d
= (stb_dirtree2
*) malloc(sizeof(*d
));
6163 d
->fullpath
= strdup(src
);
6164 s
= stb_strrchr2(d
->fullpath
, '/', '\\');
6170 // now create the children
6171 qsort(descendents
, stb_arr_len(descendents
), sizeof(char *), stb_qsort_stricmp(0));
6173 for (i
=0; i
< stb_arr_len(descendents
); ++i
) {
6175 char *s
= descendents
[i
] + elen
, *t
;
6176 t
= stb_strchr2(s
, '/', '\\');
6178 stb_strncpy(buffer2
, descendents
[i
], t
-descendents
[i
]+1);
6179 if (stb_stricmp(buffer1
, buffer2
)) {
6180 stb_dirtree2
*t
= stb_dirtree2_from_files_relative(buffer2
, descendents
, stb_arr_len(descendents
));
6182 strcpy(buffer1
, buffer2
);
6183 stb_arr_push(d
->subdirs
, t
);
6186 d
->num_subdir
= stb_arr_len(d
->subdirs
);
6191 stb_dirtree2
*stb_dirtree2_from_files(char **filelist
, int count
)
6193 return stb_dirtree2_from_files_relative("", filelist
, count
);
6197 //////////////////////////////////////////////////////////////////////////////
6199 // Checksums: CRC-32, ADLER32, SHA-1
6201 // CRC-32 and ADLER32 allow streaming blocks
6202 // SHA-1 requires either a complete buffer, max size 2^32 - 73
6203 // or it can checksum directly from a file, max 2^61
6205 #define STB_ADLER32_SEED 1
6206 #define STB_CRC32_SEED 0 // note that we logical NOT this in the code
6209 stb_adler32(stb_uint adler32
, stb_uchar
*buffer
, stb_uint buflen
);
6211 stb_crc32_block(stb_uint crc32
, stb_uchar
*buffer
, stb_uint len
);
6212 STB_EXTERN stb_uint
stb_crc32(unsigned char *buffer
, stb_uint len
);
6214 STB_EXTERN
void stb_sha1(
6215 unsigned char output
[20], unsigned char *buffer
, unsigned int len
);
6216 STB_EXTERN
int stb_sha1_file(unsigned char output
[20], char *file
);
6218 STB_EXTERN
void stb_sha1_readable(char display
[27], unsigned char sha
[20]);
6221 stb_uint
stb_crc32_block(stb_uint crc
, unsigned char *buffer
, stb_uint len
)
6223 static stb_uint crc_table
[256];
6227 if (crc_table
[1] == 0)
6228 for(i
=0; i
< 256; i
++) {
6229 for (s
=i
, j
=0; j
< 8; ++j
)
6230 s
= (s
>> 1) ^ (s
& 1 ? 0xedb88320 : 0);
6233 for (i
=0; i
< len
; ++i
)
6234 crc
= (crc
>> 8) ^ crc_table
[buffer
[i
] ^ (crc
& 0xff)];
6238 stb_uint
stb_crc32(unsigned char *buffer
, stb_uint len
)
6240 return stb_crc32_block(0, buffer
, len
);
6243 stb_uint
stb_adler32(stb_uint adler32
, stb_uchar
*buffer
, stb_uint buflen
)
6245 const unsigned long ADLER_MOD
= 65521;
6246 unsigned long s1
= adler32
& 0xffff, s2
= adler32
>> 16;
6247 unsigned long blocklen
, i
;
6249 blocklen
= buflen
% 5552;
6251 for (i
=0; i
+ 7 < blocklen
; i
+= 8) {
6252 s1
+= buffer
[0], s2
+= s1
;
6253 s1
+= buffer
[1], s2
+= s1
;
6254 s1
+= buffer
[2], s2
+= s1
;
6255 s1
+= buffer
[3], s2
+= s1
;
6256 s1
+= buffer
[4], s2
+= s1
;
6257 s1
+= buffer
[5], s2
+= s1
;
6258 s1
+= buffer
[6], s2
+= s1
;
6259 s1
+= buffer
[7], s2
+= s1
;
6264 for (; i
< blocklen
; ++i
)
6265 s1
+= *buffer
++, s2
+= s1
;
6267 s1
%= ADLER_MOD
, s2
%= ADLER_MOD
;
6271 return (s2
<< 16) + s1
;
6274 static void stb__sha1(stb_uchar
*chunk
, stb_uint h
[5])
6280 for (i
=0; i
< 16; ++i
)
6281 w
[i
] = stb_big32(&chunk
[i
*4]);
6282 for (i
=16; i
< 80; ++i
) {
6284 t
= w
[i
-3] ^ w
[i
-8] ^ w
[i
-14] ^ w
[i
-16];
6285 w
[i
] = (t
+ t
) | (t
>> 31);
6294 #define STB__SHA1(k,f) \
6296 stb_uint temp = (a << 5) + (a >> 27) + (f) + e + (k) + w[i]; \
6299 c = (b << 30) + (b >> 2); \
6305 for (; i
< 20; ++i
) STB__SHA1(0x5a827999, d
^ (b
& (c
^ d
)) );
6306 for (; i
< 40; ++i
) STB__SHA1(0x6ed9eba1, b
^ c
^ d
);
6307 for (; i
< 60; ++i
) STB__SHA1(0x8f1bbcdc, (b
& c
) + (d
& (b
^ c
)) );
6308 for (; i
< 80; ++i
) STB__SHA1(0xca62c1d6, b
^ c
^ d
);
6319 void stb_sha1(stb_uchar output
[20], stb_uchar
*buffer
, stb_uint len
)
6321 unsigned char final_block
[128];
6322 stb_uint end_start
, final_len
, j
;
6333 // we need to write padding to the last one or two
6334 // blocks, so build those first into 'final_block'
6336 // we have to write one special byte, plus the 8-byte length
6338 // compute the block where the data runs out
6339 end_start
= len
& ~63;
6341 // compute the earliest we can encode the length
6342 if (((len
+9) & ~63) == end_start
) {
6343 // it all fits in one block, so fill a second-to-last block
6347 final_len
= end_start
+ 128;
6349 // now we need to copy the data in
6350 assert(end_start
+ 128 >= len
+9);
6351 assert(end_start
< len
|| len
< 64-9);
6354 if (end_start
> len
)
6355 j
= (stb_uint
) - (int) end_start
;
6357 for (; end_start
+ j
< len
; ++j
)
6358 final_block
[j
] = buffer
[end_start
+ j
];
6359 final_block
[j
++] = 0x80;
6360 while (j
< 128-5) // 5 byte length, so write 4 extra padding bytes
6361 final_block
[j
++] = 0;
6363 final_block
[j
++] = len
>> 29;
6364 final_block
[j
++] = len
>> 21;
6365 final_block
[j
++] = len
>> 13;
6366 final_block
[j
++] = len
>> 5;
6367 final_block
[j
++] = len
<< 3;
6368 assert(j
== 128 && end_start
+ j
== final_len
);
6370 for (j
=0; j
< final_len
; j
+= 64) { // 512-bit chunks
6371 if (j
+64 >= end_start
+64)
6372 stb__sha1(&final_block
[j
- end_start
], h
);
6374 stb__sha1(&buffer
[j
], h
);
6377 for (i
=0; i
< 5; ++i
) {
6378 output
[i
*4 + 0] = h
[i
] >> 24;
6379 output
[i
*4 + 1] = h
[i
] >> 16;
6380 output
[i
*4 + 2] = h
[i
] >> 8;
6381 output
[i
*4 + 3] = h
[i
] >> 0;
6386 int stb_sha1_file(stb_uchar output
[20], char *file
)
6389 stb_uint64 length
=0;
6390 unsigned char buffer
[128];
6392 FILE *f
= stb__fopen(file
, "rb");
6395 if (f
== NULL
) return 0; // file not found
6404 int n
= fread(buffer
, 1, 64, f
);
6406 stb__sha1(buffer
, h
);
6415 // if there isn't enough room for the length, double the block
6420 memset(buffer
+n
, 0, block
-8-n
);
6423 buffer
[i
++] = (stb_uchar
) (length
>> 53);
6424 buffer
[i
++] = (stb_uchar
) (length
>> 45);
6425 buffer
[i
++] = (stb_uchar
) (length
>> 37);
6426 buffer
[i
++] = (stb_uchar
) (length
>> 29);
6427 buffer
[i
++] = (stb_uchar
) (length
>> 21);
6428 buffer
[i
++] = (stb_uchar
) (length
>> 13);
6429 buffer
[i
++] = (stb_uchar
) (length
>> 5);
6430 buffer
[i
++] = (stb_uchar
) (length
<< 3);
6432 stb__sha1(buffer
, h
);
6434 stb__sha1(buffer
+64, h
);
6436 assert(block
== 64);
6442 for (i
=0; i
< 5; ++i
) {
6443 output
[i
*4 + 0] = h
[i
] >> 24;
6444 output
[i
*4 + 1] = h
[i
] >> 16;
6445 output
[i
*4 + 2] = h
[i
] >> 8;
6446 output
[i
*4 + 3] = h
[i
] >> 0;
6453 // client can truncate this wherever they like
6454 void stb_sha1_readable(char display
[27], unsigned char sha
[20])
6456 char encoding
[65] = "0123456789abcdefghijklmnopqrstuv"
6457 "wxyzABCDEFGHIJKLMNOPQRSTUVWXYZ%$";
6458 int num_bits
= 0, acc
=0;
6462 // expand the accumulator
6465 acc
+= sha
[i
++] << num_bits
;
6468 v
= acc
& ((1 << 6) - 1);
6469 display
[o
++] = encoding
[v
];
6473 assert(num_bits
== 20*8 - 26*6);
6474 display
[o
++] = encoding
[acc
];
6477 #endif // STB_DEFINE
6479 ///////////////////////////////////////////////////////////
6481 // simplified WINDOWS registry interface... hopefully
6482 // we'll never actually use this?
6486 STB_EXTERN
void * stb_reg_open(char *mode
, char *where
); // mode: "rHKLM" or "rHKCU" or "w.."
6487 STB_EXTERN
void stb_reg_close(void *reg
);
6488 STB_EXTERN
int stb_reg_read(void *zreg
, char *str
, void *data
, unsigned long len
);
6489 STB_EXTERN
int stb_reg_read_string(void *zreg
, char *str
, char *data
, int len
);
6490 STB_EXTERN
void stb_reg_write(void *zreg
, char *str
, void *data
, unsigned long len
);
6491 STB_EXTERN
void stb_reg_write_string(void *zreg
, char *str
, char *data
);
6493 #if defined(STB_DEFINE) && !defined(STB_NO_REGISTRY)
6495 #define STB_HAS_REGISTRY
6501 STB_EXTERN
__declspec(dllimport
) long __stdcall
RegCloseKey ( HKEY hKey
);
6502 STB_EXTERN
__declspec(dllimport
) long __stdcall
RegCreateKeyExA ( HKEY hKey
, const char * lpSubKey
,
6503 int Reserved
, char * lpClass
, int dwOptions
,
6504 int samDesired
, void *lpSecurityAttributes
, HKEY
* phkResult
, int * lpdwDisposition
);
6505 STB_EXTERN
__declspec(dllimport
) long __stdcall
RegDeleteKeyA ( HKEY hKey
, const char * lpSubKey
);
6506 STB_EXTERN
__declspec(dllimport
) long __stdcall
RegQueryValueExA ( HKEY hKey
, const char * lpValueName
,
6507 int * lpReserved
, unsigned long * lpType
, unsigned char * lpData
, unsigned long * lpcbData
);
6508 STB_EXTERN
__declspec(dllimport
) long __stdcall
RegSetValueExA ( HKEY hKey
, const char * lpValueName
,
6509 int Reserved
, int dwType
, const unsigned char* lpData
, int cbData
);
6510 STB_EXTERN
__declspec(dllimport
) long __stdcall
RegOpenKeyExA ( HKEY hKey
, const char * lpSubKey
,
6511 int ulOptions
, int samDesired
, HKEY
* phkResult
);
6515 #define STB__REG_OPTION_NON_VOLATILE 0
6516 #define STB__REG_KEY_ALL_ACCESS 0x000f003f
6517 #define STB__REG_KEY_READ 0x00020019
6519 void *stb_reg_open(char *mode
, char *where
)
6524 if (!stb_stricmp(mode
+1, "cu") || !stb_stricmp(mode
+1, "hkcu"))
6525 base
= (HKEY
) 0x80000001; // HKCU
6526 else if (!stb_stricmp(mode
+1, "lm") || !stb_stricmp(mode
+1, "hklm"))
6527 base
= (HKEY
) 0x80000002; // HKLM
6532 res
= RegOpenKeyExA(base
, where
, 0, STB__REG_KEY_READ
, &zreg
);
6533 else if (mode
[0] == 'w')
6534 res
= RegCreateKeyExA(base
, where
, 0, NULL
, STB__REG_OPTION_NON_VOLATILE
, STB__REG_KEY_ALL_ACCESS
, NULL
, &zreg
, NULL
);
6538 return res
? NULL
: zreg
;
6541 void stb_reg_close(void *reg
)
6543 RegCloseKey((HKEY
) reg
);
6546 #define STB__REG_SZ 1
6547 #define STB__REG_BINARY 3
6548 #define STB__REG_DWORD 4
6550 int stb_reg_read(void *zreg
, char *str
, void *data
, unsigned long len
)
6553 unsigned long alen
= len
;
6554 if (0 == RegQueryValueExA((HKEY
) zreg
, str
, 0, &type
, (unsigned char *) data
, &len
))
6555 if (type
== STB__REG_BINARY
|| type
== STB__REG_SZ
|| type
== STB__REG_DWORD
) {
6557 *((char *) data
+ len
) = 0;
6563 void stb_reg_write(void *zreg
, char *str
, void *data
, unsigned long len
)
6566 RegSetValueExA((HKEY
) zreg
, str
, 0, STB__REG_BINARY
, (const unsigned char *) data
, len
);
6569 int stb_reg_read_string(void *zreg
, char *str
, char *data
, int len
)
6571 if (!stb_reg_read(zreg
, str
, data
, len
)) return 0;
6572 data
[len
-1] = 0; // force a 0 at the end of the string no matter what
6576 void stb_reg_write_string(void *zreg
, char *str
, char *data
)
6579 RegSetValueExA((HKEY
) zreg
, str
, 0, STB__REG_SZ
, (const unsigned char *) data
, strlen(data
)+1);
6581 #endif // STB_DEFINE
6585 //////////////////////////////////////////////////////////////////////////////
6587 // stb_cfg - This is like the registry, but the config info
6588 // is all stored in plain old files where we can
6589 // backup and restore them easily. The LOCATION of
6590 // the config files is gotten from... the registry!
6592 #ifndef STB_NO_STB_STRINGS
6593 typedef struct stb_cfg_st stb_cfg
;
6595 STB_EXTERN stb_cfg
* stb_cfg_open(char *config
, char *mode
); // mode = "r", "w"
6596 STB_EXTERN
void stb_cfg_close(stb_cfg
*cfg
);
6597 STB_EXTERN
int stb_cfg_read(stb_cfg
*cfg
, char *key
, void *value
, int len
);
6598 STB_EXTERN
void stb_cfg_write(stb_cfg
*cfg
, char *key
, void *value
, int len
);
6599 STB_EXTERN
int stb_cfg_read_string(stb_cfg
*cfg
, char *key
, char *value
, int len
);
6600 STB_EXTERN
void stb_cfg_write_string(stb_cfg
*cfg
, char *key
, char *value
);
6601 STB_EXTERN
int stb_cfg_delete(stb_cfg
*cfg
, char *key
);
6602 STB_EXTERN
void stb_cfg_set_directory(char *dir
);
6615 stb__cfg_item
*data
;
6616 char *loaded_file
; // this needs to be freed
6617 FILE *f
; // write the data to this file on close
6620 static char *stb__cfg_sig
= "sTbCoNfIg!\0\0";
6621 static char stb__cfg_dir
[512];
6622 STB_EXTERN
void stb_cfg_set_directory(char *dir
)
6624 strcpy(stb__cfg_dir
, dir
);
6627 STB_EXTERN stb_cfg
* stb_cfg_open(char *config
, char *mode
)
6632 if (mode
[0] != 'r' && mode
[0] != 'w') return NULL
;
6634 if (!stb__cfg_dir
[0]) {
6636 strcpy(stb__cfg_dir
, "c:/stb");
6638 strcpy(stb__cfg_dir
, "~/.stbconfig");
6641 #ifdef STB_HAS_REGISTRY
6643 void *reg
= stb_reg_open("rHKLM", "Software\\SilverSpaceship\\stb");
6645 stb_reg_read_string(reg
, "config_dir", stb__cfg_dir
, sizeof(stb__cfg_dir
));
6652 sprintf(file
, "%s/%s.cfg", stb__cfg_dir
, config
);
6654 z
= (stb_cfg
*) stb_malloc(0, sizeof(*z
));
6657 z
->loaded_file
= stb_filec(file
, &len
);
6658 if (z
->loaded_file
) {
6659 char *s
= z
->loaded_file
;
6660 if (!memcmp(s
, stb__cfg_sig
, 12)) {
6661 char *s
= z
->loaded_file
+ 12;
6662 while (s
< z
->loaded_file
+ len
) {
6664 int n
= *(stb_int16
*) s
;
6667 a
.value_len
= *(int *) s
;
6671 stb_arr_push(z
->data
, a
);
6673 assert(s
== z
->loaded_file
+ len
);
6678 z
->f
= fopen(file
, "wb");
6685 void stb_cfg_close(stb_cfg
*z
)
6689 // write the file out
6690 fwrite(stb__cfg_sig
, 12, 1, z
->f
);
6691 for (i
=0; i
< stb_arr_len(z
->data
); ++i
) {
6692 stb_int16 n
= strlen(z
->data
[i
].key
)+1;
6693 fwrite(&n
, 2, 1, z
->f
);
6694 fwrite(z
->data
[i
].key
, n
, 1, z
->f
);
6695 fwrite(&z
->data
[i
].value_len
, 4, 1, z
->f
);
6696 fwrite(z
->data
[i
].value
, z
->data
[i
].value_len
, 1, z
->f
);
6700 stb_arr_free(z
->data
);
6704 int stb_cfg_read(stb_cfg
*z
, char *key
, void *value
, int len
)
6707 for (i
=0; i
< stb_arr_len(z
->data
); ++i
) {
6708 if (!stb_stricmp(z
->data
[i
].key
, key
)) {
6709 int n
= stb_min(len
, z
->data
[i
].value_len
);
6710 memcpy(value
, z
->data
[i
].value
, n
);
6712 *((char *) value
+ n
) = 0;
6719 void stb_cfg_write(stb_cfg
*z
, char *key
, void *value
, int len
)
6722 for (i
=0; i
< stb_arr_len(z
->data
); ++i
)
6723 if (!stb_stricmp(z
->data
[i
].key
, key
))
6725 if (i
== stb_arr_len(z
->data
)) {
6727 p
.key
= stb_strdup(key
, z
);
6730 stb_arr_push(z
->data
, p
);
6732 z
->data
[i
].value
= stb_malloc(z
, len
);
6733 z
->data
[i
].value_len
= len
;
6734 memcpy(z
->data
[i
].value
, value
, len
);
6737 int stb_cfg_delete(stb_cfg
*z
, char *key
)
6740 for (i
=0; i
< stb_arr_len(z
->data
); ++i
)
6741 if (!stb_stricmp(z
->data
[i
].key
, key
)) {
6742 stb_arr_fastdelete(z
->data
, i
);
6748 int stb_cfg_read_string(stb_cfg
*z
, char *key
, char *value
, int len
)
6750 if (!stb_cfg_read(z
, key
, value
, len
)) return 0;
6755 void stb_cfg_write_string(stb_cfg
*z
, char *key
, char *value
)
6757 stb_cfg_write(z
, key
, value
, strlen(value
)+1);
6761 //////////////////////////////////////////////////////////////////////////////
6763 // stb_dirtree - load a description of a directory tree
6764 // uses a cache and stat()s the directories for changes
6765 // MUCH faster on NTFS, _wrong_ on FAT32, so should
6766 // ignore the db on FAT32
6772 char * path
; // full path from passed-in root
6773 time_t last_modified
;
6780 char *name
; // name relative to path
6781 int dir
; // index into dirs[] array
6782 stb_int64 size
; // size, max 4GB
6783 time_t last_modified
;
6789 stb_dirtree_dir
*dirs
;
6790 stb_dirtree_file
*files
;
6793 void * string_pool
; // used to free data en masse
6796 extern void stb_dirtree_free ( stb_dirtree
*d
);
6797 extern stb_dirtree
*stb_dirtree_get ( char *dir
);
6798 extern stb_dirtree
*stb_dirtree_get_dir ( char *dir
, char *cache_dir
);
6799 extern stb_dirtree
*stb_dirtree_get_with_file ( char *dir
, char *cache_file
);
6801 // get a list of all the files recursively underneath 'dir'
6803 // cache_file is used to store a copy of the directory tree to speed up
6804 // later calls. It must be unique to 'dir' and the current working
6805 // directory! Otherwise who knows what will happen (a good solution
6806 // is to put it _in_ dir, but this API doesn't force that).
6808 // Also, it might be possible to break this if you have two different processes
6809 // do a call to stb_dirtree_get() with the same cache file at about the same
6810 // time, but I _think_ it might just work.
6812 // i needed to build an identical data structure representing the state of
6813 // a mirrored copy WITHOUT bothering to rescan it (i.e. we're mirroring to
6814 // it WITHOUT scanning it, e.g. it's over the net), so this requires access
6815 // to all of the innards.
6816 extern void stb_dirtree_db_add_dir(stb_dirtree
*active
, char *path
, time_t last
);
6817 extern void stb_dirtree_db_add_file(stb_dirtree
*active
, char *name
, int dir
, stb_int64 size
, time_t last
);
6818 extern void stb_dirtree_db_read(stb_dirtree
*target
, char *filename
, char *dir
);
6819 extern void stb_dirtree_db_write(stb_dirtree
*target
, char *filename
, char *dir
);
6822 static void stb__dirtree_add_dir(char *path
, time_t last
, stb_dirtree
*active
)
6825 d
.last_modified
= last
;
6827 d
.path
= stb_strdup(path
, active
->string_pool
);
6828 stb_arr_push(active
->dirs
, d
);
6831 static void stb__dirtree_add_file(char *name
, int dir
, stb_int64 size
, time_t last
, stb_dirtree
*active
)
6836 f
.last_modified
= last
;
6837 f
.name
= stb_strdup(name
, active
->string_pool
);
6838 ++active
->dirs
[dir
].num_files
;
6839 stb_arr_push(active
->files
, f
);
6842 // version 02 supports > 4GB files
6843 static char stb__signature
[12] = { 's', 'T', 'b', 'D', 'i', 'R', 't', 'R', 'e', 'E', '0', '2' };
6845 static void stb__dirtree_save_db(char *filename
, stb_dirtree
*data
, char *root
)
6847 int i
, num_dirs_final
=0, num_files_final
;
6848 char *info
= root
? root
: "";
6850 FILE *f
= fopen(filename
, "wb");
6853 fwrite(stb__signature
, sizeof(stb__signature
), 1, f
);
6854 fwrite(info
, strlen(info
)+1, 1, f
);
6855 // need to be slightly tricky and not write out NULLed directories, nor the root
6857 // build remapping table of all dirs we'll be writing out
6858 remap
= (int *) malloc(sizeof(remap
[0]) * stb_arr_len(data
->dirs
));
6859 for (i
=0; i
< stb_arr_len(data
->dirs
); ++i
) {
6860 if (data
->dirs
[i
].path
== NULL
|| (root
&& 0==stb_stricmp(data
->dirs
[i
].path
, root
))) {
6863 remap
[i
] = num_dirs_final
++;
6867 fwrite(&num_dirs_final
, 4, 1, f
);
6868 for (i
=0; i
< stb_arr_len(data
->dirs
); ++i
) {
6869 if (remap
[i
] >= 0) {
6870 fwrite(&data
->dirs
[i
].last_modified
, 4, 1, f
);
6871 stb_fput_string(f
, data
->dirs
[i
].path
);
6875 num_files_final
= 0;
6876 for (i
=0; i
< stb_arr_len(data
->files
); ++i
)
6877 if (remap
[data
->files
[i
].dir
] >= 0 && data
->files
[i
].name
)
6880 fwrite(&num_files_final
, 4, 1, f
);
6881 for (i
=0; i
< stb_arr_len(data
->files
); ++i
) {
6882 if (remap
[data
->files
[i
].dir
] >= 0 && data
->files
[i
].name
) {
6883 stb_fput_ranged(f
, remap
[data
->files
[i
].dir
], 0, num_dirs_final
);
6884 stb_fput_varlen64(f
, data
->files
[i
].size
);
6885 fwrite(&data
->files
[i
].last_modified
, 4, 1, f
);
6886 stb_fput_string(f
, data
->files
[i
].name
);
6893 // note: stomps any existing data, rather than appending
6894 static void stb__dirtree_load_db(char *filename
, stb_dirtree
*data
, char *dir
)
6898 FILE *f
= fopen(filename
, "rb");
6902 data
->string_pool
= stb_malloc(0,1);
6904 fread(sig
, sizeof(stb__signature
), 1, f
);
6905 if (memcmp(stb__signature
, sig
, sizeof(stb__signature
))) { fclose(f
); return; }
6906 if (!fread(sig
, strlen(dir
)+1, 1, f
)) { fclose(f
); return; }
6907 if (stb_stricmp(sig
,dir
)) { fclose(f
); return; }
6909 // we can just read them straight in, because they're guaranteed to be valid
6911 stb_arr_setlen(data
->dirs
, n
);
6912 for(i
=0; i
< stb_arr_len(data
->dirs
); ++i
) {
6913 fread(&data
->dirs
[i
].last_modified
, 4, 1, f
);
6914 data
->dirs
[i
].path
= stb_fget_string(f
, data
->string_pool
);
6915 if (data
->dirs
[i
].path
== NULL
) goto bail
;
6918 stb_arr_setlen(data
->files
, n
);
6919 for (i
=0; i
< stb_arr_len(data
->files
); ++i
) {
6920 data
->files
[i
].dir
= stb_fget_ranged(f
, 0, stb_arr_len(data
->dirs
));
6921 data
->files
[i
].size
= stb_fget_varlen64(f
);
6922 fread(&data
->files
[i
].last_modified
, 4, 1, f
);
6923 data
->files
[i
].name
= stb_fget_string(f
, data
->string_pool
);
6924 if (data
->files
[i
].name
== NULL
) goto bail
;
6929 stb_arr_free(data
->dirs
);
6930 stb_arr_free(data
->files
);
6935 static int stb__dircount
, stb__dircount_mask
, stb__showfile
;
6936 static void stb__dirtree_scandir(char *path
, time_t last_time
, stb_dirtree
*active
)
6938 // this is dumb depth first; theoretically it might be faster
6939 // to fully traverse each directory before visiting its children,
6940 // but it's complicated and didn't seem like a gain in the test app
6944 struct _wfinddatai64_t c_file
;
6946 stb__wchar full_path
[1024];
6948 if (stb__showfile
) printf("<");
6950 has_slash
= (path
[0] && path
[strlen(path
)-1] == '/');
6952 swprintf(full_path
, L
"%s*", stb__from_utf8(path
));
6954 swprintf(full_path
, L
"%s/*", stb__from_utf8(path
));
6956 // it's possible this directory is already present: that means it was in the
6957 // cache, but its parent wasn't... in that case, we're done with it
6958 if (stb__showfile
) printf("C[%d]", stb_arr_len(active
->dirs
));
6959 for (n
=0; n
< stb_arr_len(active
->dirs
); ++n
)
6960 if (0 == stb_stricmp(active
->dirs
[n
].path
, path
)) {
6961 if (stb__showfile
) printf("D");
6964 if (stb__showfile
) printf("E");
6966 // otherwise, we need to add it
6967 stb__dirtree_add_dir(path
, last_time
, active
);
6968 n
= stb_arr_lastn(active
->dirs
);
6970 if (stb__showfile
) printf("[");
6971 if( (hFile
= _wfindfirsti64( full_path
, &c_file
)) != -1L ) {
6973 if (stb__showfile
) printf(")");
6974 if (c_file
.attrib
& _A_SUBDIR
) {
6975 // ignore subdirectories starting with '.', e.g. "." and ".."
6976 if (c_file
.name
[0] != '.') {
6977 char *new_path
= (char *) full_path
;
6978 char *temp
= stb__to_utf8(c_file
.name
);
6981 sprintf(new_path
, "%s%s", path
, temp
);
6983 sprintf(new_path
, "%s/%s", path
, temp
);
6985 if (stb__dircount_mask
) {
6987 if (!(stb__dircount
& stb__dircount_mask
)) {
6988 printf("%s\r", new_path
);
6992 stb__dirtree_scandir(new_path
, c_file
.time_write
, active
);
6995 char *temp
= stb__to_utf8(c_file
.name
);
6996 stb__dirtree_add_file(temp
, n
, c_file
.size
, c_file
.time_write
, active
);
6998 if (stb__showfile
) printf("(");
6999 } while( _wfindnexti64( hFile
, &c_file
) == 0 );
7000 if (stb__showfile
) printf("]");
7001 _findclose( hFile
);
7003 if (stb__showfile
) printf(">\n");
7006 // scan the database and see if it's all valid
7007 static int stb__dirtree_update_db(stb_dirtree
*db
, stb_dirtree
*active
)
7009 int changes_detected
= STB_FALSE
;
7013 remap
= (int *) malloc(sizeof(remap
[0]) * stb_arr_len(db
->dirs
));
7014 memset(remap
, 0, sizeof(remap
[0]) * stb_arr_len(db
->dirs
));
7017 for (i
=0; i
< stb_arr_len(db
->dirs
); ++i
) {
7019 if (stb__dircount_mask
) {
7021 if (!(stb__dircount
& stb__dircount_mask
)) {
7025 if (0 == _stat(db
->dirs
[i
].path
, &info
)) {
7026 if (info
.st_mode
& _S_IFDIR
) {
7027 // it's still a directory, as expected
7028 int n
= abs(info
.st_mtime
- db
->dirs
[i
].last_modified
);
7029 if (n
> 1 && n
!= 3600) { // the 3600 is a hack because sometimes this jumps for no apparent reason, even when no time zone or DST issues are at play
7030 // it's changed! force a rescan
7031 // we don't want to scan it until we've stat()d its
7032 // subdirs, though, so we queue it
7033 if (stb__showfile
) printf("Changed: %s - %08x:%08x\n", db
->dirs
[i
].path
, db
->dirs
[i
].last_modified
, info
.st_mtime
);
7034 stb_arr_push(rescan
, i
);
7035 // update the last_mod time
7036 db
->dirs
[i
].last_modified
= info
.st_mtime
;
7037 // ignore existing files in this dir
7039 changes_detected
= STB_TRUE
;
7041 // it hasn't changed, just copy it through unchanged
7042 stb__dirtree_add_dir(db
->dirs
[i
].path
, db
->dirs
[i
].last_modified
, active
);
7043 remap
[i
] = stb_arr_lastn(active
->dirs
);
7046 // this path used to refer to a directory, but now it's a file!
7047 // assume that the parent directory is going to be forced to rescan anyway
7052 // directory no longer exists, so don't copy it
7053 // we don't free it because it's in the string pool now
7054 db
->dirs
[i
].path
= NULL
;
7056 changes_detected
= STB_TRUE
;
7060 // at this point, we have:
7062 // <rescan> holds a list of directory indices that need to be scanned due to being out of date
7063 // <remap> holds the directory index in <active> for each dir in <db>, if it exists; -1 if not
7064 // directories in <rescan> are not in <active> yet
7066 // so we can go ahead and remap all the known files right now
7067 for (i
=0; i
< stb_arr_len(db
->files
); ++i
) {
7068 int dir
= db
->files
[i
].dir
;
7069 if (remap
[dir
] >= 0) {
7070 stb__dirtree_add_file(db
->files
[i
].name
, remap
[dir
], db
->files
[i
].size
, db
->files
[i
].last_modified
, active
);
7074 // at this point we're done with db->files, and done with remap
7077 // now scan those directories using the standard scan
7078 for (i
=0; i
< stb_arr_len(rescan
); ++i
) {
7080 stb__dirtree_scandir(db
->dirs
[z
].path
, db
->dirs
[z
].last_modified
, active
);
7082 stb_arr_free(rescan
);
7084 return changes_detected
;
7087 static void stb__dirtree_free_raw(stb_dirtree
*d
)
7089 stb_free(d
->string_pool
);
7090 stb_arr_free(d
->dirs
);
7091 stb_arr_free(d
->files
);
7094 stb_dirtree
*stb_dirtree_get_with_file(char *dir
, char *cache_file
)
7096 stb_dirtree
*output
= (stb_dirtree
*) malloc(sizeof(*output
));
7097 stb_dirtree db
,active
;
7098 int prev_dir_count
, cache_mismatch
;
7100 char *stripped_dir
; // store the directory name without a trailing '/' or '\\'
7102 // load the database of last-known state on disk
7103 db
.string_pool
= NULL
;
7107 stripped_dir
= stb_strip_final_slash(strdup(dir
));
7109 if (cache_file
!= NULL
)
7110 stb__dirtree_load_db(cache_file
, &db
, stripped_dir
);
7111 else if (stb__showfile
)
7112 printf("No cache file\n");
7114 active
.files
= NULL
;
7116 active
.string_pool
= stb_malloc(0,1); // @TODO: share string pools between both?
7118 // check all the directories in the database; make note if
7119 // anything we scanned had changed, and rescan those things
7120 cache_mismatch
= stb__dirtree_update_db(&db
, &active
);
7122 // check the root tree
7123 prev_dir_count
= stb_arr_len(active
.dirs
); // record how many directories we've seen
7125 stb__dirtree_scandir(stripped_dir
, 0, &active
); // no last_modified time available for root
7127 if (stb__dircount_mask
)
7130 // done with the DB; write it back out if any changes, i.e. either
7131 // 1. any inconsistency found between cached information and actual disk
7132 // or 2. if scanning the root found any new directories--which we detect because
7133 // more than one directory got added to the active db during that scan
7134 if (cache_mismatch
|| stb_arr_len(active
.dirs
) > prev_dir_count
+1)
7135 stb__dirtree_save_db(cache_file
, &active
, stripped_dir
);
7139 stb__dirtree_free_raw(&db
);
7145 stb_dirtree
*stb_dirtree_get_dir(char *dir
, char *cache_dir
)
7149 char dir_lower
[1024];
7150 char cache_file
[1024],*s
;
7151 if (cache_dir
== NULL
)
7152 return stb_dirtree_get_with_file(dir
, NULL
);
7153 strcpy(dir_lower
, dir
);
7154 stb_tolower(dir_lower
);
7155 stb_sha1(sha
, (unsigned char *) dir_lower
, strlen(dir_lower
));
7156 strcpy(cache_file
, cache_dir
);
7157 s
= cache_file
+ strlen(cache_file
);
7158 if (s
[-1] != '//' && s
[-1] != '\\') *s
++ = '/';
7159 strcpy(s
, "dirtree_");
7161 for (i
=0; i
< 8; ++i
) {
7162 char *hex
= "0123456789abcdef";
7163 stb_uint z
= sha
[i
];
7168 return stb_dirtree_get_with_file(dir
, cache_file
);
7171 stb_dirtree
*stb_dirtree_get(char *dir
)
7173 char cache_dir
[256];
7174 strcpy(cache_dir
, "c:/stb");
7175 #ifdef STB_HAS_REGISTRY
7177 void *reg
= stb_reg_open("rHKLM", "Software\\SilverSpaceship\\stb");
7179 stb_reg_read(reg
, "dirtree", cache_dir
, sizeof(cache_dir
));
7184 return stb_dirtree_get_dir(dir
, cache_dir
);
7187 void stb_dirtree_free(stb_dirtree
*d
)
7189 stb__dirtree_free_raw(d
);
7193 void stb_dirtree_db_add_dir(stb_dirtree
*active
, char *path
, time_t last
)
7195 stb__dirtree_add_dir(path
, last
, active
);
7198 void stb_dirtree_db_add_file(stb_dirtree
*active
, char *name
, int dir
, stb_int64 size
, time_t last
)
7200 stb__dirtree_add_file(name
, dir
, size
, last
, active
);
7203 void stb_dirtree_db_read(stb_dirtree
*target
, char *filename
, char *dir
)
7205 char *s
= stb_strip_final_slash(strdup(dir
));
7208 target
->string_pool
= 0;
7209 stb__dirtree_load_db(filename
, target
, s
);
7213 void stb_dirtree_db_write(stb_dirtree
*target
, char *filename
, char *dir
)
7215 stb__dirtree_save_db(filename
, target
, 0); // don't strip out any directories
7218 #endif // STB_DEFINE
7221 #endif // STB_NO_STB_STRINGS
7223 //////////////////////////////////////////////////////////////////////////////
7225 // STB_MALLOC_WRAPPER
7227 // you can use the wrapper functions with your own malloc wrapper,
7228 // or define STB_MALLOC_WRAPPER project-wide to have
7229 // malloc/free/realloc/strdup all get vectored to it
7231 // this has too many very specific error messages you could google for and find in stb.h,
7232 // so don't use it if they don't want any stb.h-identifiable strings
7233 #if defined(STB_DEFINE) && !defined(STB_NO_STB_STRINGS)
7241 } stb_malloc_record
;
7243 #ifndef STB_MALLOC_HISTORY_COUNT
7244 #define STB_MALLOC_HISTORY_COUNT 50 // 800 bytes
7247 stb_malloc_record
*stb__allocations
;
7248 static int stb__alloc_size
, stb__alloc_limit
, stb__alloc_mask
;
7249 int stb__alloc_count
;
7251 stb_malloc_record stb__alloc_history
[STB_MALLOC_HISTORY_COUNT
];
7252 int stb__history_pos
;
7254 static int stb__hashfind(void *p
)
7256 stb_uint32 h
= stb_hashptr(p
);
7257 int s
,n
= h
& stb__alloc_mask
;
7258 if (stb__allocations
[n
].p
== p
)
7260 s
= stb_rehash(h
)|1;
7262 if (stb__allocations
[n
].p
== NULL
)
7264 n
= (n
+s
) & stb__alloc_mask
;
7265 if (stb__allocations
[n
].p
== p
)
7270 int stb_wrapper_allocsize(void *p
)
7272 int n
= stb__hashfind(p
);
7273 if (n
< 0) return 0;
7274 return stb__allocations
[n
].size
;
7277 static int stb__historyfind(void *p
)
7279 int n
= stb__history_pos
;
7281 for (i
=0; i
< STB_MALLOC_HISTORY_COUNT
; ++i
) {
7282 if (--n
< 0) n
= STB_MALLOC_HISTORY_COUNT
-1;
7283 if (stb__alloc_history
[n
].p
== p
)
7289 static void stb__add_alloc(void *p
, int sz
, char *file
, int line
);
7290 static void stb__grow_alloc(void)
7292 int i
,old_num
= stb__alloc_size
;
7293 stb_malloc_record
*old
= stb__allocations
;
7294 if (stb__alloc_size
== 0)
7295 stb__alloc_size
= 64;
7297 stb__alloc_size
*= 2;
7299 stb__allocations
= (stb_malloc_record
*) stb__realloc_raw(NULL
, stb__alloc_size
* sizeof(stb__allocations
[0]));
7300 if (stb__allocations
== NULL
)
7301 stb_fatal("Internal error: couldn't grow malloc wrapper table");
7302 memset(stb__allocations
, 0, stb__alloc_size
* sizeof(stb__allocations
[0]));
7303 stb__alloc_limit
= (stb__alloc_size
*3)>>2;
7304 stb__alloc_mask
= stb__alloc_size
-1;
7306 stb__alloc_count
= 0;
7308 for (i
=0; i
< old_num
; ++i
)
7309 if (old
[i
].p
> STB_DEL
) {
7310 stb__add_alloc(old
[i
].p
, old
[i
].size
, old
[i
].file
, old
[i
].line
);
7311 assert(stb__hashfind(old
[i
].p
) >= 0);
7313 for (i
=0; i
< old_num
; ++i
)
7314 if (old
[i
].p
> STB_DEL
)
7315 assert(stb__hashfind(old
[i
].p
) >= 0);
7316 stb__realloc_raw(old
, 0);
7319 static void stb__add_alloc(void *p
, int sz
, char *file
, int line
)
7323 if (stb__alloc_count
>= stb__alloc_limit
)
7326 n
= h
& stb__alloc_mask
;
7327 if (stb__allocations
[n
].p
> STB_DEL
) {
7328 int s
= stb_rehash(h
)|1;
7330 n
= (n
+s
) & stb__alloc_mask
;
7331 } while (stb__allocations
[n
].p
> STB_DEL
);
7333 assert(stb__allocations
[n
].p
== NULL
|| stb__allocations
[n
].p
== STB_DEL
);
7334 stb__allocations
[n
].p
= p
;
7335 stb__allocations
[n
].size
= sz
;
7336 stb__allocations
[n
].line
= line
;
7337 stb__allocations
[n
].file
= file
;
7341 static void stb__remove_alloc(int n
, char *file
, int line
)
7343 stb__alloc_history
[stb__history_pos
] = stb__allocations
[n
];
7344 stb__alloc_history
[stb__history_pos
].file
= file
;
7345 stb__alloc_history
[stb__history_pos
].line
= line
;
7346 if (++stb__history_pos
== STB_MALLOC_HISTORY_COUNT
)
7347 stb__history_pos
= 0;
7348 stb__allocations
[n
].p
= STB_DEL
;
7352 void stb_wrapper_malloc(void *p
, int sz
, char *file
, int line
)
7355 stb__add_alloc(p
,sz
,file
,line
);
7358 void stb_wrapper_free(void *p
, char *file
, int line
)
7362 if (p
== NULL
) return;
7364 n
= stb__hashfind(p
);
7367 stb__remove_alloc(n
, file
, line
);
7369 // tried to free something we hadn't allocated!
7370 n
= stb__historyfind(p
);
7371 assert(0); /* NOTREACHED */
7373 stb_fatal("Attempted to free %d-byte block %p at %s:%d previously freed/realloced at %s:%d",
7374 stb__alloc_history
[n
].size
, p
,
7376 stb__alloc_history
[n
].file
, stb__alloc_history
[n
].line
);
7378 stb_fatal("Attempted to free unknown block %p at %s:%d", p
, file
,line
);
7382 void stb_wrapper_check(void *p
)
7386 if (p
== NULL
) return;
7388 n
= stb__hashfind(p
);
7392 for (n
=0; n
< stb__alloc_size
; ++n
)
7393 if (stb__allocations
[n
].p
== p
)
7394 stb_fatal("Internal error: pointer %p was allocated, but hash search failed", p
);
7396 // tried to free something that wasn't allocated!
7397 n
= stb__historyfind(p
);
7399 stb_fatal("Checked %d-byte block %p previously freed/realloced at %s:%d",
7400 stb__alloc_history
[n
].size
, p
,
7401 stb__alloc_history
[n
].file
, stb__alloc_history
[n
].line
);
7402 stb_fatal("Checked unknown block %p");
7405 void stb_wrapper_realloc(void *p
, void *q
, int sz
, char *file
, int line
)
7408 if (p
== NULL
) { stb_wrapper_malloc(q
, sz
, file
, line
); return; }
7409 if (q
== NULL
) return; // nothing happened
7411 n
= stb__hashfind(p
);
7413 // tried to free something we hadn't allocated!
7414 // this is weird, though, because we got past the realloc!
7415 n
= stb__historyfind(p
);
7416 assert(0); /* NOTREACHED */
7418 stb_fatal("Attempted to realloc %d-byte block %p at %s:%d previously freed/realloced at %s:%d",
7419 stb__alloc_history
[n
].size
, p
,
7421 stb__alloc_history
[n
].file
, stb__alloc_history
[n
].line
);
7423 stb_fatal("Attempted to realloc unknown block %p at %s:%d", p
, file
,line
);
7426 stb__allocations
[n
].size
= sz
;
7427 stb__allocations
[n
].file
= file
;
7428 stb__allocations
[n
].line
= line
;
7430 stb__remove_alloc(n
, file
, line
);
7431 stb__add_alloc(q
,sz
,file
,line
);
7436 void stb_wrapper_listall(void (*func
)(void *ptr
, int sz
, char *file
, int line
))
7439 for (i
=0; i
< stb__alloc_size
; ++i
)
7440 if (stb__allocations
[i
].p
> STB_DEL
)
7441 func(stb__allocations
[i
].p
, stb__allocations
[i
].size
,
7442 stb__allocations
[i
].file
, stb__allocations
[i
].line
);
7445 void stb_wrapper_dump(char *filename
)
7448 FILE *f
= fopen(filename
, "w");
7450 for (i
=0; i
< stb__alloc_size
; ++i
)
7451 if (stb__allocations
[i
].p
> STB_DEL
)
7452 fprintf(f
, "%p %7d - %4d %s\n",
7453 stb__allocations
[i
].p
, stb__allocations
[i
].size
,
7454 stb__allocations
[i
].line
, stb__allocations
[i
].file
);
7456 #endif // STB_DEFINE
7459 //////////////////////////////////////////////////////////////////////////////
7464 // For data structures that support querying by key, data structure
7465 // classes always hand-wave away the issue of what to do if two entries
7466 // have the same key: basically, store a linked list of all the nodes
7467 // which have the same key (a LISP-style list).
7469 // The thing is, it's not that trivial. If you have an O(log n)
7470 // lookup data structure, but then n/4 items have the same value,
7471 // you don't want to spend O(n) time scanning that list when
7472 // deleting an item if you already have a pointer to the item.
7473 // (You have to spend O(n) time enumerating all the items with
7474 // a given key, sure, and you can't accelerate deleting a particular
7475 // item if you only have the key, not a pointer to the item.)
7477 // I'm going to call this data structure, whatever it turns out to
7478 // be, a "pointer set", because we don't store any associated data for
7479 // items in this data structure, we just answer the question of
7480 // whether an item is in it or not (it's effectively one bit per pointer).
7481 // Technically they don't have to be pointers; you could cast ints
7482 // to (void *) if you want, but you can't store 0 or 1 because of the
7485 // Since the fastest data structure we might want to add support for
7486 // identical-keys to is a hash table with O(1)-ish lookup time,
7487 // that means that the conceptual "linked list of all items with
7488 // the same indexed value" that we build needs to have the same
7489 // performance; that way when we index a table we think is arbitrary
7490 // ints, but in fact half of them are 0, we don't get screwed.
7492 // Therefore, it needs to be a hash table, at least when it gets
7493 // large. On the other hand, when the data has totally arbitrary ints
7494 // or floats, there won't be many collisions, and we'll have tons of
7495 // 1-item bitmaps. That will be grossly inefficient as hash tables;
7496 // trade-off; the hash table is reasonably efficient per-item when
7497 // it's large, but not when it's small. So we need to do something
7498 // Judy-like and use different strategies depending on the size.
7500 // Like Judy, we'll use the bottom bit to encode the strategy:
7503 // 00 - direct pointer
7504 // 01 - 4-item bucket (16 bytes, no length, NULLs)
7505 // 10 - N-item array
7508 typedef struct stb_ps stb_ps
;
7510 STB_EXTERN
int stb_ps_find (stb_ps
*ps
, void *value
);
7511 STB_EXTERN stb_ps
* stb_ps_add (stb_ps
*ps
, void *value
);
7512 STB_EXTERN stb_ps
* stb_ps_remove(stb_ps
*ps
, void *value
);
7513 STB_EXTERN stb_ps
* stb_ps_remove_any(stb_ps
*ps
, void **value
);
7514 STB_EXTERN
void stb_ps_delete(stb_ps
*ps
);
7515 STB_EXTERN
int stb_ps_count (stb_ps
*ps
);
7517 STB_EXTERN stb_ps
* stb_ps_copy (stb_ps
*ps
);
7518 STB_EXTERN
int stb_ps_subset(stb_ps
*bigger
, stb_ps
*smaller
);
7519 STB_EXTERN
int stb_ps_eq (stb_ps
*p0
, stb_ps
*p1
);
7521 STB_EXTERN
void ** stb_ps_getlist (stb_ps
*ps
, int *count
);
7522 STB_EXTERN
int stb_ps_writelist(stb_ps
*ps
, void **list
, int size
);
7524 // enum and fastlist don't allocate storage, but you must consume the
7525 // list before there's any chance the data structure gets screwed up;
7526 STB_EXTERN
int stb_ps_enum (stb_ps
*ps
, void *data
,
7527 int (*func
)(void *value
, void*data
) );
7528 STB_EXTERN
void ** stb_ps_fastlist(stb_ps
*ps
, int *count
);
7530 // returns a list, *count is the length of that list,
7531 // but some entries of the list may be invalid;
7532 // test with 'stb_ps_fastlist_valid(x)'
7534 #define stb_ps_fastlist_valid(x) ((stb_uinta) (x) > 1)
7546 #define STB_BUCKET_SIZE 4
7550 void *p
[STB_BUCKET_SIZE
];
7552 #define GetBucket(p) ((stb_ps_bucket *) ((char *) (p) - STB_ps_bucket))
7553 #define EncodeBucket(p) ((stb_ps *) ((char *) (p) + STB_ps_bucket))
7555 static void stb_bucket_free(stb_ps_bucket
*b
)
7560 static stb_ps_bucket
*stb_bucket_create2(void *v0
, void *v1
)
7562 stb_ps_bucket
*b
= (stb_ps_bucket
*) malloc(sizeof(*b
));
7570 static stb_ps_bucket
* stb_bucket_create3(void **v
)
7572 stb_ps_bucket
*b
= (stb_ps_bucket
*) malloc(sizeof(*b
));
7581 // could use stb_arr, but this will save us memory
7587 #define GetArray(p) ((stb_ps_array *) ((char *) (p) - STB_ps_array))
7588 #define EncodeArray(p) ((stb_ps *) ((char *) (p) + STB_ps_array))
7590 static int stb_ps_array_max
= 13;
7595 int count
, count_deletes
;
7596 int grow_threshhold
;
7597 int shrink_threshhold
;
7598 int rehash_threshhold
;
7602 #define GetHash(p) ((stb_ps_hash *) ((char *) (p) - STB_ps_hash))
7603 #define EncodeHash(p) ((stb_ps *) ((char *) (p) + STB_ps_hash))
7605 #define stb_ps_empty(v) (((stb_uint32) v) <= 1)
7607 static stb_ps_hash
*stb_ps_makehash(int size
, int old_size
, void **old_data
)
7610 stb_ps_hash
*h
= (stb_ps_hash
*) malloc(sizeof(*h
) + (size
-1) * sizeof(h
->table
[0]));
7611 assert(stb_is_pow2(size
));
7614 h
->shrink_threshhold
= (int) (0.3f
* size
);
7615 h
-> grow_threshhold
= (int) (0.8f
* size
);
7616 h
->rehash_threshhold
= (int) (0.9f
* size
);
7618 h
->count_deletes
= 0;
7620 memset(h
->table
, 0, size
* sizeof(h
->table
[0]));
7621 for (i
=0; i
< old_size
; ++i
)
7622 if (!stb_ps_empty(old_data
[i
]))
7623 stb_ps_add(EncodeHash(h
), old_data
[i
]);
7627 void stb_ps_delete(stb_ps
*ps
)
7629 switch (3 & (int) ps
) {
7630 case STB_ps_direct
: break;
7631 case STB_ps_bucket
: stb_bucket_free(GetBucket(ps
)); break;
7632 case STB_ps_array
: free(GetArray(ps
)); break;
7633 case STB_ps_hash
: free(GetHash(ps
)); break;
7637 stb_ps
*stb_ps_copy(stb_ps
*ps
)
7640 // not a switch: order based on expected performance/power-law distribution
7641 switch (3 & (int) ps
) {
7642 case STB_ps_direct
: return ps
;
7643 case STB_ps_bucket
: {
7644 stb_ps_bucket
*n
= (stb_ps_bucket
*) malloc(sizeof(*n
));
7645 *n
= *GetBucket(ps
);
7646 return EncodeBucket(n
);
7648 case STB_ps_array
: {
7649 stb_ps_array
*a
= GetArray(ps
);
7650 stb_ps_array
*n
= (stb_ps_array
*) malloc(sizeof(*n
) + stb_ps_array_max
* sizeof(n
->p
[0]));
7651 n
->count
= a
->count
;
7652 for (i
=0; i
< a
->count
; ++i
)
7654 return EncodeArray(n
);
7657 stb_ps_hash
*h
= GetHash(ps
);
7658 stb_ps_hash
*n
= stb_ps_makehash(h
->size
, h
->size
, h
->table
);
7659 return EncodeHash(n
);
7662 assert(0); /* NOTREACHED */
7666 int stb_ps_find(stb_ps
*ps
, void *value
)
7668 int i
, code
= 3 & (int) ps
;
7669 assert((3 & (int) value
) == STB_ps_direct
);
7670 assert(stb_ps_fastlist_valid(value
));
7671 // not a switch: order based on expected performance/power-law distribution
7672 if (code
== STB_ps_direct
)
7674 if (code
== STB_ps_bucket
) {
7675 stb_ps_bucket
*b
= GetBucket(ps
);
7676 assert(STB_BUCKET_SIZE
== 4);
7677 if (b
->p
[0] == value
|| b
->p
[1] == value
||
7678 b
->p
[2] == value
|| b
->p
[3] == value
)
7682 if (code
== STB_ps_array
) {
7683 stb_ps_array
*a
= GetArray(ps
);
7684 for (i
=0; i
< a
->count
; ++i
)
7685 if (a
->p
[i
] == value
)
7689 stb_ps_hash
*h
= GetHash(ps
);
7690 stb_uint32 hash
= stb_hashptr(value
);
7691 stb_uint32 s
, n
= hash
& h
->mask
;
7692 void **t
= h
->table
;
7693 if (t
[n
] == value
) return STB_TRUE
;
7694 if (t
[n
] == NULL
) return STB_FALSE
;
7695 s
= stb_rehash(hash
) | 1;
7697 n
= (n
+ s
) & h
->mask
;
7698 if (t
[n
] == value
) return STB_TRUE
;
7699 } while (t
[n
] != NULL
);
7704 stb_ps
* stb_ps_add (stb_ps
*ps
, void *value
)
7707 assert(!stb_ps_find(ps
,value
));
7709 if (value
== NULL
) return ps
; // ignore NULL adds to avoid bad breakage
7710 assert((3 & (int) value
) == STB_ps_direct
);
7711 assert(stb_ps_fastlist_valid(value
));
7712 assert(value
!= STB_DEL
); // STB_DEL is less likely
7714 switch (3 & (int) ps
) {
7716 if (ps
== NULL
) return (stb_ps
*) value
;
7717 return EncodeBucket(stb_bucket_create2(ps
,value
));
7719 case STB_ps_bucket
: {
7720 stb_ps_bucket
*b
= GetBucket(ps
);
7722 assert(STB_BUCKET_SIZE
== 4);
7723 if (b
->p
[0] == NULL
) { b
->p
[0] = value
; return ps
; }
7724 if (b
->p
[1] == NULL
) { b
->p
[1] = value
; return ps
; }
7725 if (b
->p
[2] == NULL
) { b
->p
[2] = value
; return ps
; }
7726 if (b
->p
[3] == NULL
) { b
->p
[3] = value
; return ps
; }
7727 a
= (stb_ps_array
*) malloc(sizeof(*a
) + 7 * sizeof(a
->p
[0])); // 8 slots, must be 2^k
7728 memcpy(a
->p
, b
, sizeof(*b
));
7732 return EncodeArray(a
);
7735 case STB_ps_array
: {
7736 stb_ps_array
*a
= GetArray(ps
);
7737 if (a
->count
== stb_ps_array_max
) {
7738 // promote from array to hash
7739 stb_ps_hash
*h
= stb_ps_makehash(2 << stb_log2_ceil(a
->count
), a
->count
, a
->p
);
7741 return stb_ps_add(EncodeHash(h
), value
);
7743 // do we need to resize the array? the array doubles in size when it
7744 // crosses a power-of-two
7745 if ((a
->count
& (a
->count
-1))==0) {
7746 int newsize
= a
->count
*2;
7747 // clamp newsize to max if:
7748 // 1. it's larger than max
7749 // 2. newsize*1.5 is larger than max (to avoid extra resizing)
7750 if (newsize
+ a
->count
> stb_ps_array_max
)
7751 newsize
= stb_ps_array_max
;
7752 a
= (stb_ps_array
*) realloc(a
, sizeof(*a
) + (newsize
-1) * sizeof(a
->p
[0]));
7754 a
->p
[a
->count
++] = value
;
7755 return EncodeArray(a
);
7758 stb_ps_hash
*h
= GetHash(ps
);
7759 stb_uint32 hash
= stb_hashptr(value
);
7760 stb_uint32 n
= hash
& h
->mask
;
7761 void **t
= h
->table
;
7762 // find first NULL or STB_DEL entry
7763 if (!stb_ps_empty(t
[n
])) {
7764 stb_uint32 s
= stb_rehash(hash
) | 1;
7766 n
= (n
+ s
) & h
->mask
;
7767 } while (!stb_ps_empty(t
[n
]));
7769 if (t
[n
] == STB_DEL
)
7770 -- h
->count_deletes
;
7773 if (h
->count
== h
->grow_threshhold
) {
7774 stb_ps_hash
*h2
= stb_ps_makehash(h
->size
*2, h
->size
, t
);
7776 return EncodeHash(h2
);
7778 if (h
->count
+ h
->count_deletes
== h
->rehash_threshhold
) {
7779 stb_ps_hash
*h2
= stb_ps_makehash(h
->size
, h
->size
, t
);
7781 return EncodeHash(h2
);
7786 return NULL
; /* NOTREACHED */
7789 stb_ps
*stb_ps_remove(stb_ps
*ps
, void *value
)
7792 assert(stb_ps_find(ps
, value
));
7794 assert((3 & (int) value
) == STB_ps_direct
);
7795 if (value
== NULL
) return ps
; // ignore NULL removes to avoid bad breakage
7796 switch (3 & (int) ps
) {
7798 return ps
== value
? NULL
: ps
;
7799 case STB_ps_bucket
: {
7800 stb_ps_bucket
*b
= GetBucket(ps
);
7802 assert(STB_BUCKET_SIZE
== 4);
7803 if (b
->p
[0] == value
) b
->p
[0] = NULL
; else count
+= (b
->p
[0] != NULL
);
7804 if (b
->p
[1] == value
) b
->p
[1] = NULL
; else count
+= (b
->p
[1] != NULL
);
7805 if (b
->p
[2] == value
) b
->p
[2] = NULL
; else count
+= (b
->p
[2] != NULL
);
7806 if (b
->p
[3] == value
) b
->p
[3] = NULL
; else count
+= (b
->p
[3] != NULL
);
7807 if (count
== 1) { // shrink bucket at size 1
7809 if (value
== NULL
) value
= b
->p
[1];
7810 if (value
== NULL
) value
= b
->p
[2];
7811 if (value
== NULL
) value
= b
->p
[3];
7812 assert(value
!= NULL
);
7814 return (stb_ps
*) value
; // return STB_ps_direct of value
7818 case STB_ps_array
: {
7819 stb_ps_array
*a
= GetArray(ps
);
7821 for (i
=0; i
< a
->count
; ++i
) {
7822 if (a
->p
[i
] == value
) {
7823 a
->p
[i
] = a
->p
[--a
->count
];
7824 if (a
->count
== 3) { // shrink to bucket!
7825 stb_ps_bucket
*b
= stb_bucket_create3(a
->p
);
7827 return EncodeBucket(b
);
7835 stb_ps_hash
*h
= GetHash(ps
);
7836 stb_uint32 hash
= stb_hashptr(value
);
7837 stb_uint32 s
, n
= hash
& h
->mask
;
7838 void **t
= h
->table
;
7839 if (t
[n
] != value
) {
7840 s
= stb_rehash(hash
) | 1;
7842 n
= (n
+ s
) & h
->mask
;
7843 } while (t
[n
] != value
);
7847 ++ h
->count_deletes
;
7848 // should we shrink down to an array?
7849 if (h
->count
< stb_ps_array_max
) {
7850 int n
= 1 << stb_log2_floor(stb_ps_array_max
);
7852 stb_ps_array
*a
= (stb_ps_array
*) malloc(sizeof(*a
) + (n
-1) * sizeof(a
->p
[0]));
7854 for (i
=0; i
< h
->size
; ++i
)
7855 if (!stb_ps_empty(t
[i
]))
7857 assert(j
== h
->count
);
7860 return EncodeArray(a
);
7863 if (h
->count
== h
->shrink_threshhold
) {
7864 stb_ps_hash
*h2
= stb_ps_makehash(h
->size
>> 1, h
->size
, t
);
7866 return EncodeHash(h2
);
7871 return ps
; /* NOTREACHED */
7874 stb_ps
*stb_ps_remove_any(stb_ps
*ps
, void **value
)
7877 switch (3 & (int) ps
) {
7881 case STB_ps_bucket
: {
7882 stb_ps_bucket
*b
= GetBucket(ps
);
7883 int count
=0, slast
=0, last
=0;
7884 assert(STB_BUCKET_SIZE
== 4);
7885 if (b
->p
[0]) { ++count
; last
= 0; }
7886 if (b
->p
[1]) { ++count
; slast
= last
; last
= 1; }
7887 if (b
->p
[2]) { ++count
; slast
= last
; last
= 2; }
7888 if (b
->p
[3]) { ++count
; slast
= last
; last
= 3; }
7889 *value
= b
->p
[last
];
7892 void *leftover
= b
->p
[slast
]; // second to last
7894 return (stb_ps
*) leftover
;
7898 case STB_ps_array
: {
7899 stb_ps_array
*a
= GetArray(ps
);
7900 *value
= a
->p
[a
->count
-1];
7902 return stb_ps_remove(ps
, *value
);
7907 stb_ps_hash
*h
= GetHash(ps
);
7908 void **t
= h
->table
;
7909 stb_uint32 n
= h
->any_offset
;
7910 while (stb_ps_empty(t
[n
]))
7911 n
= (n
+ 1) & h
->mask
;
7913 h
->any_offset
= (n
+1) & h
->mask
;
7914 // check if we need to skip down to the previous type
7915 if (h
->count
-1 < stb_ps_array_max
|| h
->count
-1 == h
->shrink_threshhold
)
7916 return stb_ps_remove(ps
, *value
);
7919 ++ h
->count_deletes
;
7923 return ps
; /* NOTREACHED */
7927 void ** stb_ps_getlist(stb_ps
*ps
, int *count
)
7931 switch (3 & (int) ps
) {
7933 if (ps
== NULL
) { *count
= 0; return NULL
; }
7934 p
= (void **) malloc(sizeof(*p
) * 1);
7938 case STB_ps_bucket
: {
7939 stb_ps_bucket
*b
= GetBucket(ps
);
7940 p
= (void **) malloc(sizeof(*p
) * STB_BUCKET_SIZE
);
7941 for (i
=0; i
< STB_BUCKET_SIZE
; ++i
)
7942 if (b
->p
[i
] != NULL
)
7946 case STB_ps_array
: {
7947 stb_ps_array
*a
= GetArray(ps
);
7948 p
= (void **) malloc(sizeof(*p
) * a
->count
);
7949 memcpy(p
, a
->p
, sizeof(*p
) * a
->count
);
7954 stb_ps_hash
*h
= GetHash(ps
);
7955 p
= (void **) malloc(sizeof(*p
) * h
->count
);
7956 for (i
=0; i
< h
->size
; ++i
)
7957 if (!stb_ps_empty(h
->table
[i
]))
7958 p
[n
++] = h
->table
[i
];
7966 int stb_ps_writelist(stb_ps
*ps
, void **list
, int size
)
7969 switch (3 & (int) ps
) {
7971 if (ps
== NULL
|| size
<= 0) return 0;
7974 case STB_ps_bucket
: {
7975 stb_ps_bucket
*b
= GetBucket(ps
);
7976 for (i
=0; i
< STB_BUCKET_SIZE
; ++i
)
7977 if (b
->p
[i
] != NULL
&& n
< size
)
7978 list
[n
++] = b
->p
[i
];
7981 case STB_ps_array
: {
7982 stb_ps_array
*a
= GetArray(ps
);
7983 n
= stb_min(size
, a
->count
);
7984 memcpy(list
, a
->p
, sizeof(*list
) * n
);
7988 stb_ps_hash
*h
= GetHash(ps
);
7989 if (size
<= 0) return 0;
7990 for (i
=0; i
< h
->count
; ++i
) {
7991 if (!stb_ps_empty(h
->table
[i
])) {
7992 list
[n
++] = h
->table
[i
];
7993 if (n
== size
) break;
7999 return 0; /* NOTREACHED */
8002 int stb_ps_enum(stb_ps
*ps
, void *data
, int (*func
)(void *value
, void *data
))
8005 switch (3 & (int) ps
) {
8007 if (ps
== NULL
) return STB_TRUE
;
8008 return func(ps
, data
);
8009 case STB_ps_bucket
: {
8010 stb_ps_bucket
*b
= GetBucket(ps
);
8011 for (i
=0; i
< STB_BUCKET_SIZE
; ++i
)
8012 if (b
->p
[i
] != NULL
)
8013 if (!func(b
->p
[i
], data
))
8017 case STB_ps_array
: {
8018 stb_ps_array
*a
= GetArray(ps
);
8019 for (i
=0; i
< a
->count
; ++i
)
8020 if (!func(a
->p
[i
], data
))
8025 stb_ps_hash
*h
= GetHash(ps
);
8026 for (i
=0; i
< h
->count
; ++i
)
8027 if (!stb_ps_empty(h
->table
[i
]))
8028 if (!func(h
->table
[i
], data
))
8033 return STB_TRUE
; /* NOTREACHED */
8036 int stb_ps_count (stb_ps
*ps
)
8038 switch (3 & (int) ps
) {
8041 case STB_ps_bucket
: {
8042 stb_ps_bucket
*b
= GetBucket(ps
);
8043 return (b
->p
[0] != NULL
) + (b
->p
[1] != NULL
) +
8044 (b
->p
[2] != NULL
) + (b
->p
[3] != NULL
);
8046 case STB_ps_array
: {
8047 stb_ps_array
*a
= GetArray(ps
);
8051 stb_ps_hash
*h
= GetHash(ps
);
8058 void ** stb_ps_fastlist(stb_ps
*ps
, int *count
)
8060 static void *storage
;
8062 switch (3 & (int) ps
) {
8064 if (ps
== NULL
) { *count
= 0; return NULL
; }
8068 case STB_ps_bucket
: {
8069 stb_ps_bucket
*b
= GetBucket(ps
);
8070 *count
= STB_BUCKET_SIZE
;
8073 case STB_ps_array
: {
8074 stb_ps_array
*a
= GetArray(ps
);
8079 stb_ps_hash
*h
= GetHash(ps
);
8084 return NULL
; /* NOTREACHED */
8087 int stb_ps_subset(stb_ps
*bigger
, stb_ps
*smaller
)
8090 void **list
= stb_ps_fastlist(smaller
, &listlen
);
8091 for(i
=0; i
< listlen
; ++i
)
8092 if (stb_ps_fastlist_valid(list
[i
]))
8093 if (!stb_ps_find(bigger
, list
[i
]))
8098 int stb_ps_eq(stb_ps
*p0
, stb_ps
*p1
)
8100 if (stb_ps_count(p0
) != stb_ps_count(p1
))
8102 return stb_ps_subset(p0
, p1
);
8116 //////////////////////////////////////////////////////////////////////////////
8118 // Random Numbers via Meresenne Twister or LCG
8121 STB_EXTERN
unsigned long stb_srandLCG(unsigned long seed
);
8122 STB_EXTERN
unsigned long stb_randLCG(void);
8123 STB_EXTERN
double stb_frandLCG(void);
8125 STB_EXTERN
void stb_srand(unsigned long seed
);
8126 STB_EXTERN
unsigned long stb_rand(void);
8127 STB_EXTERN
double stb_frand(void);
8128 STB_EXTERN
void stb_shuffle(void *p
, size_t n
, size_t sz
,
8129 unsigned long seed
);
8130 STB_EXTERN
void stb_reverse(void *p
, size_t n
, size_t sz
);
8132 STB_EXTERN
unsigned long stb_randLCG_explicit(unsigned long seed
);
8134 #define stb_rand_define(x,y) \
8136 unsigned long x(void) \
8138 static unsigned long stb__rand = y; \
8139 stb__rand = stb__rand * 2147001325 + 715136305; /* BCPL */ \
8140 return 0x31415926 ^ ((stb__rand >> 16) + (stb__rand << 16)); \
8144 unsigned long stb_randLCG_explicit(unsigned long seed
)
8146 return seed
* 2147001325 + 715136305;
8149 static unsigned long stb__rand_seed
=0;
8151 unsigned long stb_srandLCG(unsigned long seed
)
8153 unsigned long previous
= stb__rand_seed
;
8154 stb__rand_seed
= seed
;
8158 unsigned long stb_randLCG(void)
8160 stb__rand_seed
= stb__rand_seed
* 2147001325 + 715136305; // BCPL generator
8161 // shuffle non-random bits to the middle, and xor to decorrelate with seed
8162 return 0x31415926 ^ ((stb__rand_seed
>> 16) + (stb__rand_seed
<< 16));
8165 double stb_frandLCG(void)
8167 return stb_randLCG() / ((double) (1 << 16) * (1 << 16));
8170 void stb_shuffle(void *p
, size_t n
, size_t sz
, unsigned long seed
)
8173 unsigned long old_seed
;
8176 old_seed
= stb_srandLCG(seed
);
8177 a
= (char *) p
+ (n
-1) * sz
;
8179 for (i
=n
; i
> 1; --i
) {
8180 int j
= stb_randLCG() % i
;
8181 stb_swap(a
, (char *) p
+ j
* sz
, sz
);
8185 stb_srandLCG(old_seed
);
8188 void stb_reverse(void *p
, size_t n
, size_t sz
)
8191 for (i
=0; i
< j
; ++i
,--j
) {
8192 stb_swap((char *) p
+ i
* sz
, (char *) p
+ j
* sz
, sz
);
8196 // public domain Mersenne Twister by Michael Brundage
8197 #define STB__MT_LEN 624
8199 int stb__mt_index
= STB__MT_LEN
*sizeof(unsigned long)+1;
8200 unsigned long stb__mt_buffer
[STB__MT_LEN
];
8202 void stb_srand(unsigned long seed
)
8205 unsigned long old
= stb_srandLCG(seed
);
8206 for (i
= 0; i
< STB__MT_LEN
; i
++)
8207 stb__mt_buffer
[i
] = stb_randLCG();
8209 stb__mt_index
= STB__MT_LEN
*sizeof(unsigned long);
8212 #define STB__MT_IA 397
8213 #define STB__MT_IB (STB__MT_LEN - STB__MT_IA)
8214 #define STB__UPPER_MASK 0x80000000
8215 #define STB__LOWER_MASK 0x7FFFFFFF
8216 #define STB__MATRIX_A 0x9908B0DF
8217 #define STB__TWIST(b,i,j) ((b)[i] & STB__UPPER_MASK) | ((b)[j] & STB__LOWER_MASK)
8218 #define STB__MAGIC(s) (((s)&1)*STB__MATRIX_A)
8220 unsigned long stb_rand()
8222 unsigned long * b
= stb__mt_buffer
;
8223 int idx
= stb__mt_index
;
8227 if (idx
>= STB__MT_LEN
*sizeof(unsigned long)) {
8228 if (idx
> STB__MT_LEN
*sizeof(unsigned long))
8232 for (; i
< STB__MT_IB
; i
++) {
8233 s
= STB__TWIST(b
, i
, i
+1);
8234 b
[i
] = b
[i
+ STB__MT_IA
] ^ (s
>> 1) ^ STB__MAGIC(s
);
8236 for (; i
< STB__MT_LEN
-1; i
++) {
8237 s
= STB__TWIST(b
, i
, i
+1);
8238 b
[i
] = b
[i
- STB__MT_IB
] ^ (s
>> 1) ^ STB__MAGIC(s
);
8241 s
= STB__TWIST(b
, STB__MT_LEN
-1, 0);
8242 b
[STB__MT_LEN
-1] = b
[STB__MT_IA
-1] ^ (s
>> 1) ^ STB__MAGIC(s
);
8244 stb__mt_index
= idx
+ sizeof(unsigned long);
8246 r
= *(unsigned long *)((unsigned char *)b
+ idx
);
8249 r
^= (r
<< 7) & 0x9D2C5680;
8250 r
^= (r
<< 15) & 0xEFC60000;
8256 double stb_frand(void)
8258 return stb_rand() / ((double) (1 << 16) * (1 << 16));
8264 //////////////////////////////////////////////////////////////////////////////
8268 // stb_dupe is a duplicate-finding system for very, very large data
8269 // structures--large enough that sorting is too slow, but not so large
8270 // that we can't keep all the data in memory. using it works as follows:
8272 // 1. create an stb_dupe:
8273 // provide a hash function
8274 // provide an equality function
8275 // provide an estimate for the size
8276 // optionally provide a comparison function
8278 // 2. traverse your data, 'adding' pointers to the stb_dupe
8280 // 3. finish and ask for duplicates
8282 // the stb_dupe will discard its intermediate data and build
8283 // a collection of sorted lists of duplicates, with non-duplicate
8284 // entries omitted entirely
8287 // Implementation strategy:
8289 // while collecting the N items, we keep a hash table of approximate
8290 // size sqrt(N). (if you tell use the N up front, the hash table is
8291 // just that size exactly)
8293 // each entry in the hash table is just an stb__arr of pointers (no need
8294 // to use stb_ps, because we don't need to delete from these)
8296 // for step 3, for each entry in the hash table, we apply stb_dupe to it
8297 // recursively. once the size gets small enough (or doesn't decrease
8298 // significantly), we switch to either using qsort() on the comparison
8299 // function, or else we just do the icky N^2 gather
8302 typedef struct stb_dupe stb_dupe
;
8304 typedef int (*stb_compare_func
)(void *a
, void *b
);
8305 typedef int (*stb_hash_func
)(void *a
, unsigned int seed
);
8307 STB_EXTERN
void stb_dupe_free(stb_dupe
*sd
);
8308 STB_EXTERN stb_dupe
*stb_dupe_create(stb_hash_func hash
,
8309 stb_compare_func eq
, int size
, stb_compare_func ineq
);
8310 STB_EXTERN
void stb_dupe_add(stb_dupe
*sd
, void *item
);
8311 STB_EXTERN
void stb_dupe_finish(stb_dupe
*sd
);
8312 STB_EXTERN
int stb_dupe_numsets(stb_dupe
*sd
);
8313 STB_EXTERN
void **stb_dupe_set(stb_dupe
*sd
, int num
);
8314 STB_EXTERN
int stb_dupe_set_count(stb_dupe
*sd
, int num
);
8326 stb_compare_func eq
;
8327 stb_compare_func ineq
;
8334 int stb_dupe_numsets(stb_dupe
*sd
)
8336 assert(sd
->hash_table
== NULL
);
8337 return stb_arr_len(sd
->dupes
);
8340 void **stb_dupe_set(stb_dupe
*sd
, int num
)
8342 assert(sd
->hash_table
== NULL
);
8343 return sd
->dupes
[num
];
8346 int stb_dupe_set_count(stb_dupe
*sd
, int num
)
8348 assert(sd
->hash_table
== NULL
);
8349 return stb_arr_len(sd
->dupes
[num
]);
8352 stb_dupe
*stb_dupe_create(stb_hash_func hash
, stb_compare_func eq
, int size
,
8353 stb_compare_func ineq
)
8356 stb_dupe
*sd
= (stb_dupe
*) malloc(sizeof(*sd
));
8359 hsize
= 1 << sd
->size_log2
;
8360 while (hsize
* hsize
< size
) {
8371 sd
->hash_size
= hsize
;
8372 sd
->hash_table
= (void ***) malloc(sizeof(*sd
->hash_table
) * hsize
);
8373 for (i
=0; i
< hsize
; ++i
)
8374 sd
->hash_table
[i
] = NULL
;
8381 void stb_dupe_add(stb_dupe
*sd
, void *item
)
8383 stb_uint32 hash
= sd
->hash(item
, sd
->hash_shift
);
8384 int z
= hash
& (sd
->hash_size
-1);
8385 stb_arr_push(sd
->hash_table
[z
], item
);
8389 void stb_dupe_free(stb_dupe
*sd
)
8392 for (i
=0; i
< stb_arr_len(sd
->dupes
); ++i
)
8394 stb_arr_free(sd
->dupes
[i
]);
8395 stb_arr_free(sd
->dupes
);
8399 static stb_compare_func stb__compare
;
8401 static int stb__dupe_compare(const void *a
, const void *b
)
8403 void *p
= *(void **) a
;
8404 void *q
= *(void **) b
;
8406 return stb__compare(p
,q
);
8409 void stb_dupe_finish(stb_dupe
*sd
)
8412 assert(sd
->dupes
== NULL
);
8413 for (i
=0; i
< sd
->hash_size
; ++i
) {
8414 void ** list
= sd
->hash_table
[i
];
8416 int n
= stb_arr_len(list
);
8417 // @TODO: measure to find good numbers instead of just making them up!
8418 int thresh
= (sd
->ineq
? 200 : 20);
8419 // if n is large enough to be worth it, and n is smaller than
8420 // before (so we can guarantee we'll use a smaller hash table);
8421 // and there are enough hash bits left, assuming full 32-bit hash
8422 if (n
> thresh
&& n
< (sd
->population
>> 3) && sd
->hash_shift
+ sd
->size_log2
*2 < 32) {
8424 // recursively process this row using stb_dupe, O(N log log N)
8426 stb_dupe
*d
= stb_dupe_create(sd
->hash
, sd
->eq
, n
, sd
->ineq
);
8427 d
->hash_shift
= stb_randLCG_explicit(sd
->hash_shift
);
8428 for (j
=0; j
< n
; ++j
)
8429 stb_dupe_add(d
, list
[j
]);
8430 stb_arr_free(sd
->hash_table
[i
]);
8432 for (j
=0; j
< stb_arr_len(d
->dupes
); ++j
) {
8433 stb_arr_push(sd
->dupes
, d
->dupes
[j
]);
8434 d
->dupes
[j
] = NULL
; // take over ownership
8438 } else if (sd
->ineq
) {
8440 // process this row using qsort(), O(N log N)
8441 stb__compare
= sd
->ineq
;
8442 qsort(list
, n
, sizeof(list
[0]), stb__dupe_compare
);
8444 // find equal subsequences of the list
8445 for (j
=0; j
< n
-1; ) {
8446 // find a subsequence from j..k
8447 for (k
=j
; k
< n
; ++k
)
8448 // only use ineq so eq can be left undefined
8449 if (sd
->ineq(list
[j
], list
[k
]))
8451 // k is the first one not in the subsequence
8453 void **mylist
= NULL
;
8454 stb_arr_setlen(mylist
, k
-j
);
8455 memcpy(mylist
, list
+j
, sizeof(list
[j
]) * (k
-j
));
8456 stb_arr_push(sd
->dupes
, mylist
);
8460 stb_arr_free(sd
->hash_table
[i
]);
8463 // process this row using eq(), O(N^2)
8464 for (j
=0; j
< n
; ++j
) {
8465 if (list
[j
] != NULL
) {
8466 void **output
= NULL
;
8467 for (k
=j
+1; k
< n
; ++k
) {
8468 if (sd
->eq(list
[j
], list
[k
])) {
8470 stb_arr_push(output
, list
[j
]);
8471 stb_arr_push(output
, list
[k
]);
8477 stb_arr_push(sd
->dupes
, output
);
8480 stb_arr_free(sd
->hash_table
[i
]);
8484 free(sd
->hash_table
);
8485 sd
->hash_table
= NULL
;
8489 //////////////////////////////////////////////////////////////////////////////
8491 // templatized Sort routine
8493 // This is an attempt to implement a templated sorting algorithm.
8494 // To use it, you have to explicitly instantiate it as a _function_,
8495 // then you call that function. This allows the comparison to be inlined,
8496 // giving the sort similar performance to C++ sorts.
8498 // It implements quicksort with three-way-median partitioning (generally
8499 // well-behaved), with a final insertion sort pass.
8501 // When you define the compare expression, you should assume you have
8502 // elements of your array pointed to by 'a' and 'b', and perform the comparison
8503 // on those. OR you can use one or more statements; first say '0;', then
8504 // write whatever code you want, and compute the result into a variable 'c'.
8506 #define stb_declare_sort(FUNCNAME, TYPE) \
8507 void FUNCNAME(TYPE *p, int n)
8508 #define stb_define_sort(FUNCNAME,TYPE,COMPARE) \
8509 stb__define_sort( void, FUNCNAME,TYPE,COMPARE)
8510 #define stb_define_sort_static(FUNCNAME,TYPE,COMPARE) \
8511 stb__define_sort(static void, FUNCNAME,TYPE,COMPARE)
8513 #define stb__define_sort(MODE, FUNCNAME, TYPE, COMPARE) \
8515 static void STB_(FUNCNAME,_ins_sort)(TYPE *p, int n) \
8518 for (i=1; i < n; ++i) { \
8519 TYPE t = p[i], *a = &t; \
8522 TYPE *b = &p[j-1]; \
8533 static void STB_(FUNCNAME,_quicksort)(TYPE *p, int n) \
8535 /* threshhold for transitioning to insertion sort */ \
8538 int c01,c12,c,m,i,j; \
8540 /* compute median of three */ \
8550 /* if 0 >= mid >= end, or 0 < mid < end, then use mid */ \
8552 /* otherwise, we'll need to swap something else to middle */ \
8557 /* 0>mid && mid<n: 0>n => n; 0<n => 0 */ \
8558 /* 0<mid && mid>n: 0>n => 0; 0<n => n */ \
8559 z = (c == c12) ? 0 : n-1; \
8564 /* now p[m] is the median-of-three */ \
8565 /* swap it to the beginning so it won't move around */ \
8570 /* partition loop */ \
8574 /* handling of equality is crucial here */ \
8575 /* for sentinels & efficiency with duplicates */ \
8588 /* make sure we haven't crossed */ \
8589 if (i >= j) break; \
8597 /* recurse on smaller side, iterate on larger */ \
8599 STB_(FUNCNAME,_quicksort)(p,j); \
8603 STB_(FUNCNAME,_quicksort)(p+i, n-i); \
8609 MODE FUNCNAME(TYPE *p, int n) \
8611 STB_(FUNCNAME, _quicksort)(p, n); \
8612 STB_(FUNCNAME, _ins_sort)(p, n); \
8616 //////////////////////////////////////////////////////////////////////////////
8618 // stb_bitset an array of booleans indexed by integers
8621 typedef stb_uint32 stb_bitset
;
8623 STB_EXTERN stb_bitset
*stb_bitset_new(int value
, int len
);
8625 #define stb_bitset_clearall(arr,len) (memset(arr, 0, 4 * (len)))
8626 #define stb_bitset_setall(arr,len) (memset(arr, 255, 4 * (len)))
8628 #define stb_bitset_setbit(arr,n) ((arr)[(n) >> 5] |= (1 << (n & 31)))
8629 #define stb_bitset_clearbit(arr,n) ((arr)[(n) >> 5] &= ~(1 << (n & 31)))
8630 #define stb_bitset_testbit(arr,n) ((arr)[(n) >> 5] & (1 << (n & 31)))
8632 STB_EXTERN stb_bitset
*stb_bitset_union(stb_bitset
*p0
, stb_bitset
*p1
, int len
);
8634 STB_EXTERN
int *stb_bitset_getlist(stb_bitset
*out
, int start
, int end
);
8636 STB_EXTERN
int stb_bitset_eq(stb_bitset
*p0
, stb_bitset
*p1
, int len
);
8637 STB_EXTERN
int stb_bitset_disjoint(stb_bitset
*p0
, stb_bitset
*p1
, int len
);
8638 STB_EXTERN
int stb_bitset_disjoint_0(stb_bitset
*p0
, stb_bitset
*p1
, int len
);
8639 STB_EXTERN
int stb_bitset_subset(stb_bitset
*bigger
, stb_bitset
*smaller
, int len
);
8640 STB_EXTERN
int stb_bitset_unioneq_changed(stb_bitset
*p0
, stb_bitset
*p1
, int len
);
8643 int stb_bitset_eq(stb_bitset
*p0
, stb_bitset
*p1
, int len
)
8646 for (i
=0; i
< len
; ++i
)
8647 if (p0
[i
] != p1
[i
]) return 0;
8651 int stb_bitset_disjoint(stb_bitset
*p0
, stb_bitset
*p1
, int len
)
8654 for (i
=0; i
< len
; ++i
)
8655 if (p0
[i
] & p1
[i
]) return 0;
8659 int stb_bitset_disjoint_0(stb_bitset
*p0
, stb_bitset
*p1
, int len
)
8662 for (i
=0; i
< len
; ++i
)
8663 if ((p0
[i
] | p1
[i
]) != 0xffffffff) return 0;
8667 int stb_bitset_subset(stb_bitset
*bigger
, stb_bitset
*smaller
, int len
)
8670 for (i
=0; i
< len
; ++i
)
8671 if ((bigger
[i
] & smaller
[i
]) != smaller
[i
]) return 0;
8675 stb_bitset
*stb_bitset_union(stb_bitset
*p0
, stb_bitset
*p1
, int len
)
8678 stb_bitset
*d
= (stb_bitset
*) malloc(sizeof(*d
) * len
);
8679 for (i
=0; i
< len
; ++i
) d
[i
] = p0
[i
] | p1
[i
];
8683 int stb_bitset_unioneq_changed(stb_bitset
*p0
, stb_bitset
*p1
, int len
)
8686 for (i
=0; i
< len
; ++i
) {
8687 stb_bitset d
= p0
[i
] | p1
[i
];
8696 stb_bitset
*stb_bitset_new(int value
, int len
)
8699 stb_bitset
*d
= (stb_bitset
*) malloc(sizeof(*d
) * len
);
8700 if (value
) value
= 0xffffffff;
8701 for (i
=0; i
< len
; ++i
) d
[i
] = value
;
8705 int *stb_bitset_getlist(stb_bitset
*out
, int start
, int end
)
8709 for (i
=start
; i
< end
; ++i
)
8710 if (stb_bitset_testbit(out
, i
))
8711 stb_arr_push(list
, i
);
8716 //////////////////////////////////////////////////////////////////////////////
8718 // stb_wordwrap quality word-wrapping for fixed-width fonts
8721 STB_EXTERN
int stb_wordwrap(int *pairs
, int pair_max
, int count
, char *str
);
8722 STB_EXTERN
int *stb_wordwrapalloc(int count
, char *str
);
8726 int stb_wordwrap(int *pairs
, int pair_max
, int count
, char *str
)
8728 int n
=0,i
=0, start
=0,nonwhite
=0;
8729 if (pairs
== NULL
) pair_max
= 0x7ffffff0;
8733 int s
=i
; // first whitespace char; last nonwhite+1
8734 int w
; // word start
8735 // accept whitespace
8736 while (isspace(str
[i
])) {
8737 if (str
[i
] == '\n' || str
[i
] == '\r') {
8738 if (str
[i
] + str
[i
+1] == '\n' + '\r') ++i
;
8739 if (n
>= pair_max
) return -1;
8740 if (pairs
) pairs
[n
] = start
, pairs
[n
+1] = s
-start
;
8748 if (i
>= start
+count
) {
8749 // we've gone off the end using whitespace
8751 if (n
>= pair_max
) return -1;
8752 if (pairs
) pairs
[n
] = start
, pairs
[n
+1] = s
-start
;
8757 // output all the whitespace
8758 while (i
>= start
+count
) {
8759 if (n
>= pair_max
) return -1;
8760 if (pairs
) pairs
[n
] = start
, pairs
[n
+1] = count
;
8768 if (str
[i
] == 0) break;
8769 // now scan out a word and see if it fits
8771 while (str
[i
] && !isspace(str
[i
])) {
8775 if (i
> start
+ count
) {
8778 if (n
>= pair_max
) return -1;
8779 if (pairs
) pairs
[n
] = start
, pairs
[n
+1] = s
-start
;
8783 // This word is longer than one line. If we wrap it onto N lines
8784 // there are leftover chars. do those chars fit on the cur line?
8785 // But if we have leading whitespace, we force it to start here.
8786 if ((w
-start
) + ((i
-w
) % count
) <= count
|| !nonwhite
) {
8787 // output a full line
8788 if (n
>= pair_max
) return -1;
8789 if (pairs
) pairs
[n
] = start
, pairs
[n
+1] = count
;
8794 // output a partial line, trimming trailing whitespace
8796 if (n
>= pair_max
) return -1;
8797 if (pairs
) pairs
[n
] = start
, pairs
[n
+1] = s
-start
;
8802 // now output full lines as needed
8803 while (start
+ count
<= i
) {
8804 if (n
>= pair_max
) return -1;
8805 if (pairs
) pairs
[n
] = start
, pairs
[n
+1] = count
;
8814 if (n
>= pair_max
) return -1;
8815 if (pairs
) pairs
[n
] = start
, pairs
[n
+1] = i
-start
;
8821 int *stb_wordwrapalloc(int count
, char *str
)
8823 int n
= stb_wordwrap(NULL
,0,count
,str
);
8825 stb_arr_setlen(z
, n
*2);
8826 stb_wordwrap(z
, n
, count
, str
);
8832 //////////////////////////////////////////////////////////////////////////////
8834 // stb_match: wildcards and regexping
8837 STB_EXTERN
int stb_wildmatch (char *expr
, char *candidate
);
8838 STB_EXTERN
int stb_wildmatchi(char *expr
, char *candidate
);
8839 STB_EXTERN
int stb_wildfind (char *expr
, char *candidate
);
8840 STB_EXTERN
int stb_wildfindi (char *expr
, char *candidate
);
8842 STB_EXTERN
int stb_regex(char *regex
, char *candidate
);
8844 typedef struct stb_matcher stb_matcher
;
8846 STB_EXTERN stb_matcher
*stb_regex_matcher(char *regex
);
8847 STB_EXTERN
int stb_matcher_match(stb_matcher
*m
, char *str
);
8848 STB_EXTERN
int stb_matcher_find(stb_matcher
*m
, char *str
);
8849 STB_EXTERN
void stb_matcher_free(stb_matcher
*f
);
8851 STB_EXTERN stb_matcher
*stb_lex_matcher(void);
8852 STB_EXTERN
int stb_lex_item(stb_matcher
*m
, char *str
, int result
);
8853 STB_EXTERN
int stb_lex_item_wild(stb_matcher
*matcher
, char *regex
, int result
);
8854 STB_EXTERN
int stb_lex(stb_matcher
*m
, char *str
, int *len
);
8860 static int stb__match_qstring(char *candidate
, char *qstring
, int qlen
, int insensitive
)
8864 for (i
=0; i
< qlen
; ++i
)
8865 if (qstring
[i
] == '?') {
8866 if (!candidate
[i
]) return 0;
8868 if (tolower(qstring
[i
]) != tolower(candidate
[i
]))
8871 for (i
=0; i
< qlen
; ++i
)
8872 if (qstring
[i
] == '?') {
8873 if (!candidate
[i
]) return 0;
8875 if (qstring
[i
] != candidate
[i
])
8881 static int stb__find_qstring(char *candidate
, char *qstring
, int qlen
, int insensitive
)
8886 while (*qstring
== '?') {
8890 if (qlen
== 0) return 0;
8891 if (*candidate
== 0) return -1;
8896 if (insensitive
) c
= tolower(c
);
8898 while (candidate
[offset
]) {
8899 if (c
== (insensitive
? tolower(candidate
[offset
]) : candidate
[offset
]))
8900 if (stb__match_qstring(candidate
+offset
+1, qstring
, qlen
, insensitive
))
8908 int stb__wildmatch_raw2(char *expr
, char *candidate
, int search
, int insensitive
)
8914 // parse to first '*'
8917 while (*expr
!= '*') {
8919 return *candidate
== 0 ? 0 : -1;
8921 if (!*candidate
) return -1;
8924 if (tolower(*candidate
) != tolower(*expr
))
8927 if (*candidate
!= *expr
)
8930 ++candidate
, ++expr
, ++where
;
8933 // 0-length search string
8938 assert(search
|| *expr
== '*');
8942 // implicit '*' at this point
8946 // combine redundant * characters
8947 while (expr
[0] == '*') ++expr
;
8949 // ok, at this point, expr[-1] == '*',
8950 // and expr[0] != '*'
8952 if (!expr
[0]) return start
>= 0 ? start
: 0;
8954 // now find next '*'
8956 while (expr
[o
] != '*') {
8961 // if no '*', scan to end, then match at end
8962 if (expr
[o
] == 0 && !search
) {
8964 for (z
=0; z
< o
; ++z
)
8965 if (candidate
[z
] == 0)
8967 while (candidate
[z
])
8969 // ok, now check if they match
8970 if (stb__match_qstring(candidate
+z
-o
, expr
, o
, insensitive
))
8971 return start
>= 0 ? start
: 0;
8974 // if yes '*', then do stb__find_qmatch on the intervening chars
8975 int n
= stb__find_qstring(candidate
, expr
, o
, insensitive
);
8989 assert(*expr
== '*');
8993 return start
>= 0 ? start
: 0;
8996 int stb__wildmatch_raw(char *expr
, char *candidate
, int search
, int insensitive
)
8999 // handle multiple search strings
9000 char *s
= strchr(expr
, ';');
9004 // need to allow for non-writeable strings... assume they're small
9005 if (s
- last
< 256) {
9006 stb_strncpy(buffer
, last
, s
-last
+1);
9007 z
= stb__wildmatch_raw2(buffer
, candidate
, search
, insensitive
);
9010 z
= stb__wildmatch_raw2(last
, candidate
, search
, insensitive
);
9013 if (z
>= 0) return z
;
9015 s
= strchr(last
, ';');
9017 return stb__wildmatch_raw2(last
, candidate
, search
, insensitive
);
9020 int stb_wildmatch(char *expr
, char *candidate
)
9022 return stb__wildmatch_raw(expr
, candidate
, 0,0) >= 0;
9025 int stb_wildmatchi(char *expr
, char *candidate
)
9027 return stb__wildmatch_raw(expr
, candidate
, 0,1) >= 0;
9030 int stb_wildfind(char *expr
, char *candidate
)
9032 return stb__wildmatch_raw(expr
, candidate
, 1,0);
9035 int stb_wildfindi(char *expr
, char *candidate
)
9037 return stb__wildmatch_raw(expr
, candidate
, 1,1);
9042 stb_int16 transition
[256];
9045 // an NFA node represents a state you're in; it then has
9046 // an arbitrary number of edges dangling off of it
9047 // note this isn't utf8-y
9050 stb_int16 match
; // character/set to match
9051 stb_uint16 node
; // output node to go to
9056 stb_int16 goal
; // does reaching this win the prize?
9057 stb_uint8 active
; // is this in the active list
9059 stb_uint16
*eps
; // list of epsilon closures
9062 #define STB__DFA_UNDEF -1
9063 #define STB__DFA_GOAL -2
9064 #define STB__DFA_END -3
9065 #define STB__DFA_MGOAL -4
9066 #define STB__DFA_VALID 0
9068 #define STB__NFA_STOP_GOAL -1
9073 stb_uint16 start_node
;
9074 stb_int16 dfa_start
;
9075 stb_uint32
*charset
;
9078 stb_nfa_node
*nodes
;
9083 stb_uint32
* dfa_mapping
;
9084 stb_int16
* dfa_result
;
9085 int num_words_per_dfa
;
9088 static int stb__add_node(stb_matcher
*matcher
)
9095 stb_arr_push(matcher
->nodes
, z
);
9096 return stb_arr_len(matcher
->nodes
)-1;
9099 static void stb__add_epsilon(stb_matcher
*matcher
, int from
, int to
)
9102 if (matcher
->nodes
[from
].eps
== NULL
)
9103 stb_arr_malloc((void **) &matcher
->nodes
[from
].eps
, matcher
);
9104 stb_arr_push(matcher
->nodes
[from
].eps
, to
);
9107 static void stb__add_edge(stb_matcher
*matcher
, int from
, int to
, int type
)
9109 stb_nfa_edge z
= { type
, to
};
9110 if (matcher
->nodes
[from
].out
== NULL
)
9111 stb_arr_malloc((void **) &matcher
->nodes
[from
].out
, matcher
);
9112 stb_arr_push(matcher
->nodes
[from
].out
, z
);
9115 static char *stb__reg_parse_alt(stb_matcher
*m
, int s
, char *r
, stb_uint16
*e
);
9116 static char *stb__reg_parse(stb_matcher
*matcher
, int start
, char *regex
, stb_uint16
*end
)
9119 int last_start
= -1;
9120 stb_uint16 last_end
= start
;
9125 last_start
= last_end
;
9126 regex
= stb__reg_parse_alt(matcher
, last_end
, regex
+1, &last_end
);
9127 if (regex
== NULL
|| *regex
!= ')')
9138 if (last_start
< 0) return NULL
;
9139 stb__add_epsilon(matcher
, last_start
, last_end
);
9144 if (last_start
< 0) return NULL
;
9145 stb__add_epsilon(matcher
, last_start
, last_end
);
9150 if (last_start
< 0) return NULL
;
9151 stb__add_epsilon(matcher
, last_end
, last_start
);
9152 // prevent links back to last_end from chaining to last_start
9153 n
= stb__add_node(matcher
);
9154 stb__add_epsilon(matcher
, last_end
, n
);
9159 case '{': // not supported!
9160 // @TODO: given {n,m}, clone last_start to last_end m times,
9161 // and include epsilons from start to first m-n blocks
9166 if (!*regex
) return NULL
;
9169 default: // match exactly this character
9170 n
= stb__add_node(matcher
);
9171 stb__add_edge(matcher
, last_end
, n
, *regex
);
9172 last_start
= last_end
;
9178 n
= stb__add_node(matcher
);
9179 stb__add_edge(matcher
, last_end
, n
, '\n');
9180 last_start
= last_end
;
9186 n
= stb__add_node(matcher
);
9187 stb__add_edge(matcher
, last_end
, n
, -1);
9188 last_start
= last_end
;
9194 stb_uint8 flags
[256];
9197 if (matcher
->num_charset
== 0) {
9198 matcher
->charset
= (stb_uint
*) stb_malloc(matcher
, sizeof(*matcher
->charset
) * 256);
9199 memset(matcher
->charset
, 0, sizeof(*matcher
->charset
) * 256);
9202 memset(flags
,0,sizeof(flags
));
9204 // leading ^ is special
9206 ++regex
, invert
= 1;
9208 // leading ] is special
9209 if (*regex
== ']') {
9213 while (*regex
!= ']') {
9215 if (!*regex
) return NULL
;
9217 if (regex
[0] == '-' && regex
[1] != ']') {
9218 stb_uint i
,b
= regex
[1];
9220 if (b
== 0) return NULL
;
9221 if (a
> b
) return NULL
;
9222 for (i
=a
; i
<= b
; ++i
)
9230 for (i
=0; i
< 256; ++i
)
9231 flags
[i
] = 1-flags
[i
];
9234 // now check if any existing charset matches
9235 for (z
=0; z
< matcher
->num_charset
; ++z
) {
9236 int i
, k
[2] = { 0, 1 << z
};
9237 for (i
=0; i
< 256; ++i
) {
9238 unsigned int f
= k
[flags
[i
]];
9239 if ((matcher
->charset
[i
] & k
[1]) != f
)
9242 if (i
== 256) break;
9245 if (z
== matcher
->num_charset
) {
9247 ++matcher
->num_charset
;
9248 if (matcher
->num_charset
> 32) {
9249 assert(0); /* NOTREACHED */
9250 return NULL
; // too many charsets, oops
9252 for (i
=0; i
< 256; ++i
)
9254 matcher
->charset
[i
] |= (1 << z
);
9257 n
= stb__add_node(matcher
);
9258 stb__add_edge(matcher
, last_end
, n
, -2 - z
);
9259 last_start
= last_end
;
9269 static char *stb__reg_parse_alt(stb_matcher
*matcher
, int start
, char *regex
, stb_uint16
*end
)
9271 stb_uint16 last_end
= start
;
9272 stb_uint16 main_end
;
9276 head
= stb__add_node(matcher
);
9277 stb__add_epsilon(matcher
, start
, head
);
9279 regex
= stb__reg_parse(matcher
, head
, regex
, &last_end
);
9280 if (regex
== NULL
) return NULL
;
9281 if (*regex
== 0 || *regex
== ')') {
9286 main_end
= last_end
;
9287 tail
= stb__add_node(matcher
);
9289 stb__add_epsilon(matcher
, last_end
, tail
);
9291 // start alternatives from the same starting node; use epsilon
9292 // transitions to combine their endings
9293 while(*regex
&& *regex
!= ')') {
9294 assert(*regex
== '|');
9295 head
= stb__add_node(matcher
);
9296 stb__add_epsilon(matcher
, start
, head
);
9297 regex
= stb__reg_parse(matcher
, head
, regex
+1, &last_end
);
9300 stb__add_epsilon(matcher
, last_end
, tail
);
9307 static char *stb__wild_parse(stb_matcher
*matcher
, int start
, char *str
, stb_uint16
*end
)
9310 stb_uint16 last_end
;
9312 last_end
= stb__add_node(matcher
);
9313 stb__add_epsilon(matcher
, start
, last_end
);
9318 default: // match exactly this character
9319 n
= stb__add_node(matcher
);
9320 if (toupper(*str
) == tolower(*str
)) {
9321 stb__add_edge(matcher
, last_end
, n
, *str
);
9323 stb__add_edge(matcher
, last_end
, n
, tolower(*str
));
9324 stb__add_edge(matcher
, last_end
, n
, toupper(*str
));
9331 n
= stb__add_node(matcher
);
9332 stb__add_edge(matcher
, last_end
, n
, -1);
9338 n
= stb__add_node(matcher
);
9339 stb__add_edge(matcher
, last_end
, n
, -1);
9340 stb__add_epsilon(matcher
, last_end
, n
);
9341 stb__add_epsilon(matcher
, n
, last_end
);
9348 // now require end of string to match
9349 n
= stb__add_node(matcher
);
9350 stb__add_edge(matcher
, last_end
, n
, 0);
9357 static int stb__opt(stb_matcher
*m
, int n
)
9360 stb_nfa_node
*p
= &m
->nodes
[n
];
9361 if (p
->goal
) return n
;
9362 if (stb_arr_len(p
->out
)) return n
;
9363 if (stb_arr_len(p
->eps
) != 1) return n
;
9368 static void stb__optimize(stb_matcher
*m
)
9370 // if the target of any edge is a node with exactly
9371 // one out-epsilon, shorten it
9373 for (i
=0; i
< stb_arr_len(m
->nodes
); ++i
) {
9374 stb_nfa_node
*p
= &m
->nodes
[i
];
9375 for (j
=0; j
< stb_arr_len(p
->out
); ++j
)
9376 p
->out
[j
].node
= stb__opt(m
,p
->out
[j
].node
);
9377 for (j
=0; j
< stb_arr_len(p
->eps
); ++j
)
9378 p
->eps
[j
] = stb__opt(m
,p
->eps
[j
] );
9380 m
->start_node
= stb__opt(m
,m
->start_node
);
9383 void stb_matcher_free(stb_matcher
*f
)
9388 static stb_matcher
*stb__alloc_matcher(void)
9390 stb_matcher
*matcher
= (stb_matcher
*) stb_malloc(0,sizeof(*matcher
));
9392 matcher
->start_node
= 0;
9393 stb_arr_malloc((void **) &matcher
->nodes
, matcher
);
9394 matcher
->num_charset
= 0;
9395 matcher
->match_start
= 0;
9396 matcher
->does_lex
= 0;
9398 matcher
->dfa_start
= STB__DFA_UNDEF
;
9399 stb_arr_malloc((void **) &matcher
->dfa
, matcher
);
9400 stb_arr_malloc((void **) &matcher
->dfa_mapping
, matcher
);
9401 stb_arr_malloc((void **) &matcher
->dfa_result
, matcher
);
9403 stb__add_node(matcher
);
9408 static void stb__lex_reset(stb_matcher
*matcher
)
9410 // flush cached dfa data
9411 stb_arr_setlen(matcher
->dfa
, 0);
9412 stb_arr_setlen(matcher
->dfa_mapping
, 0);
9413 stb_arr_setlen(matcher
->dfa_result
, 0);
9414 matcher
->dfa_start
= STB__DFA_UNDEF
;
9417 stb_matcher
*stb_regex_matcher(char *regex
)
9421 stb_matcher
*matcher
= stb__alloc_matcher();
9422 if (*regex
== '^') {
9423 matcher
->match_start
= 1;
9427 z
= stb__reg_parse_alt(matcher
, matcher
->start_node
, regex
, &end
);
9434 ((matcher
->nodes
)[(int) end
]).goal
= STB__NFA_STOP_GOAL
;
9439 stb_matcher
*stb_lex_matcher(void)
9441 stb_matcher
*matcher
= stb__alloc_matcher();
9443 matcher
->match_start
= 1;
9444 matcher
->does_lex
= 1;
9449 int stb_lex_item(stb_matcher
*matcher
, char *regex
, int result
)
9454 z
= stb__reg_parse_alt(matcher
, matcher
->start_node
, regex
, &end
);
9459 stb__lex_reset(matcher
);
9461 matcher
->nodes
[(int) end
].goal
= result
;
9465 int stb_lex_item_wild(stb_matcher
*matcher
, char *regex
, int result
)
9470 z
= stb__wild_parse(matcher
, matcher
->start_node
, regex
, &end
);
9475 stb__lex_reset(matcher
);
9477 matcher
->nodes
[(int) end
].goal
= result
;
9481 static void stb__clear(stb_matcher
*m
, stb_uint16
*list
)
9484 for (i
=0; i
< stb_arr_len(list
); ++i
)
9485 m
->nodes
[(int) list
[i
]].active
= 0;
9488 static int stb__clear_goalcheck(stb_matcher
*m
, stb_uint16
*list
)
9491 for (i
=0; i
< stb_arr_len(list
); ++i
) {
9492 t
+= m
->nodes
[(int) list
[i
]].goal
;
9493 m
->nodes
[(int) list
[i
]].active
= 0;
9498 static stb_uint16
* stb__add_if_inactive(stb_matcher
*m
, stb_uint16
*list
, int n
)
9500 if (!m
->nodes
[n
].active
) {
9501 stb_arr_push(list
, n
);
9502 m
->nodes
[n
].active
= 1;
9507 static stb_uint16
* stb__eps_closure(stb_matcher
*m
, stb_uint16
*list
)
9509 int i
,n
= stb_arr_len(list
);
9511 for(i
=0; i
< n
; ++i
) {
9512 stb_uint16
*e
= m
->nodes
[(int) list
[i
]].eps
;
9514 int j
,k
= stb_arr_len(e
);
9515 for (j
=0; j
< k
; ++j
)
9516 list
= stb__add_if_inactive(m
, list
, e
[j
]);
9517 n
= stb_arr_len(list
);
9524 int stb_matcher_match(stb_matcher
*m
, char *str
)
9528 stb_uint16
*previous
= NULL
;
9529 stb_uint16
*current
= NULL
;
9532 stb_arr_setsize(previous
, 4);
9533 stb_arr_setsize(current
, 4);
9535 previous
= stb__add_if_inactive(m
, previous
, m
->start_node
);
9536 previous
= stb__eps_closure(m
,previous
);
9537 stb__clear(m
, previous
);
9539 while (*str
&& stb_arr_len(previous
)) {
9540 y
= stb_arr_len(previous
);
9541 for (i
=0; i
< y
; ++i
) {
9542 stb_nfa_node
*n
= &m
->nodes
[(int) previous
[i
]];
9543 z
= stb_arr_len(n
->out
);
9544 for (j
=0; j
< z
; ++j
) {
9545 if (n
->out
[j
].match
>= 0) {
9546 if (n
->out
[j
].match
== *str
)
9547 current
= stb__add_if_inactive(m
, current
, n
->out
[j
].node
);
9548 } else if (n
->out
[j
].match
== -1) {
9550 current
= stb__add_if_inactive(m
, current
, n
->out
[j
].node
);
9551 } else if (n
->out
[j
].match
< -1) {
9552 int z
= -n
->out
[j
].match
- 2;
9553 if (m
->charset
[(stb_uint8
) *str
] & (1 << z
))
9554 current
= stb__add_if_inactive(m
, current
, n
->out
[j
].node
);
9558 stb_arr_setlen(previous
, 0);
9564 previous
= stb__eps_closure(m
,previous
);
9565 stb__clear(m
, previous
);
9570 // transition to pick up a '$' at the end
9571 y
= stb_arr_len(previous
);
9572 for (i
=0; i
< y
; ++i
)
9573 m
->nodes
[(int) previous
[i
]].active
= 1;
9575 for (i
=0; i
< y
; ++i
) {
9576 stb_nfa_node
*n
= &m
->nodes
[(int) previous
[i
]];
9577 z
= stb_arr_len(n
->out
);
9578 for (j
=0; j
< z
; ++j
) {
9579 if (n
->out
[j
].match
== '\n')
9580 current
= stb__add_if_inactive(m
, current
, n
->out
[j
].node
);
9584 previous
= stb__eps_closure(m
,previous
);
9585 stb__clear(m
, previous
);
9587 y
= stb_arr_len(previous
);
9588 for (i
=0; i
< y
; ++i
)
9589 if (m
->nodes
[(int) previous
[i
]].goal
)
9592 stb_arr_free(previous
);
9593 stb_arr_free(current
);
9595 return result
&& *str
== 0;
9598 stb_int16
stb__get_dfa_node(stb_matcher
*m
, stb_uint16
*list
)
9601 stb_uint32 data
[8], *state
, *newstate
;
9604 state
= (stb_uint32
*) stb_temp(data
, m
->num_words_per_dfa
* 4);
9605 memset(state
, 0, m
->num_words_per_dfa
*4);
9607 n
= stb_arr_len(list
);
9608 for (i
=0; i
< n
; ++i
) {
9610 state
[x
>> 5] |= 1 << (x
& 31);
9613 // @TODO use a hash table
9614 n
= stb_arr_len(m
->dfa_mapping
);
9616 for(; j
< n
; ++i
, j
+= m
->num_words_per_dfa
) {
9617 // @TODO special case for <= 32
9618 if (!memcmp(state
, m
->dfa_mapping
+ j
, m
->num_words_per_dfa
*4)) {
9624 assert(stb_arr_len(m
->dfa
) == i
);
9627 newstate
= stb_arr_addn(m
->dfa_mapping
, m
->num_words_per_dfa
);
9628 memcpy(newstate
, state
, m
->num_words_per_dfa
*4);
9630 // set all transitions to 'unknown'
9631 stb_arr_add(m
->dfa
);
9632 memset(m
->dfa
[i
].transition
, -1, sizeof(m
->dfa
[i
].transition
));
9636 n
= stb_arr_len(list
);
9637 for (i
=0; i
< n
; ++i
) {
9638 if (m
->nodes
[(int) list
[i
]].goal
> result
)
9639 result
= m
->nodes
[(int) list
[i
]].goal
;
9642 stb_arr_push(m
->dfa_result
, result
);
9646 stb_tempfree(data
, state
);
9650 static int stb__matcher_dfa(stb_matcher
*m
, char *str_c
, int *len
)
9652 stb_uint8
*str
= (stb_uint8
*) str_c
;
9653 stb_int16 node
,prevnode
;
9655 int match_length
= 0;
9656 stb_int16 match_result
=0;
9658 if (m
->dfa_start
== STB__DFA_UNDEF
) {
9661 m
->num_words_per_dfa
= (stb_arr_len(m
->nodes
)+31) >> 5;
9664 list
= stb__add_if_inactive(m
, NULL
, m
->start_node
);
9665 list
= stb__eps_closure(m
,list
);
9667 m
->dfa_start
= stb__get_dfa_node(m
,list
);
9668 stb__clear(m
, list
);
9669 // DON'T allow start state to be a goal state!
9670 // this allows people to specify regexes that can match 0
9671 // characters without them actually matching (also we don't
9672 // check _before_ advancing anyway
9673 if (m
->dfa_start
<= STB__DFA_MGOAL
)
9674 m
->dfa_start
= -(m
->dfa_start
- STB__DFA_MGOAL
);
9676 if (stb__clear_goalcheck(m
, list
))
9677 m
->dfa_start
= STB__DFA_GOAL
;
9679 m
->dfa_start
= stb__get_dfa_node(m
,list
);
9684 prevnode
= STB__DFA_UNDEF
;
9685 node
= m
->dfa_start
;
9688 if (m
->dfa_start
== STB__DFA_GOAL
)
9692 assert(node
>= STB__DFA_VALID
);
9694 // fast inner DFA loop; especially if STB__DFA_VALID is 0
9698 node
= trans
[node
].transition
[*str
++];
9699 } while (node
>= STB__DFA_VALID
);
9701 assert(node
>= STB__DFA_MGOAL
- stb_arr_len(m
->dfa
));
9702 assert(node
< stb_arr_len(m
->dfa
));
9704 // special case for lex: need _longest_ match, so notice goal
9705 // state without stopping
9706 if (node
<= STB__DFA_MGOAL
) {
9707 match_length
= str
- (stb_uint8
*) str_c
;
9708 node
= -(node
- STB__DFA_MGOAL
);
9709 match_result
= node
;
9713 // slow NFA->DFA conversion
9715 // or we hit the goal or the end of the string, but those
9716 // can only happen once per search...
9718 if (node
== STB__DFA_UNDEF
) {
9719 // build a list -- @TODO special case <= 32 states
9720 // heck, use a more compact data structure for <= 16 and <= 8 ?!
9722 // @TODO keep states/newstates around instead of reallocating them
9723 stb_uint16
*states
= NULL
;
9724 stb_uint16
*newstates
= NULL
;
9726 stb_uint32
*flags
= &m
->dfa_mapping
[prevnode
* m
->num_words_per_dfa
];
9727 assert(prevnode
!= STB__DFA_UNDEF
);
9728 stb_arr_setsize(states
, 4);
9729 stb_arr_setsize(newstates
,4);
9730 for (j
=0; j
< m
->num_words_per_dfa
; ++j
) {
9731 for (i
=0; i
< 32; ++i
) {
9732 if (*flags
& (1 << i
))
9733 stb_arr_push(states
, j
*32+i
);
9737 // states is now the states we were in in the previous node;
9738 // so now we can compute what node it transitions to on str[-1]
9740 y
= stb_arr_len(states
);
9741 for (i
=0; i
< y
; ++i
) {
9742 stb_nfa_node
*n
= &m
->nodes
[(int) states
[i
]];
9743 z
= stb_arr_len(n
->out
);
9744 for (j
=0; j
< z
; ++j
) {
9745 if (n
->out
[j
].match
>= 0) {
9746 if (n
->out
[j
].match
== str
[-1] || (str
[-1] == 0 && n
->out
[j
].match
== '\n'))
9747 newstates
= stb__add_if_inactive(m
, newstates
, n
->out
[j
].node
);
9748 } else if (n
->out
[j
].match
== -1) {
9749 if (str
[-1] != '\n' && str
[-1])
9750 newstates
= stb__add_if_inactive(m
, newstates
, n
->out
[j
].node
);
9751 } else if (n
->out
[j
].match
< -1) {
9752 int z
= -n
->out
[j
].match
- 2;
9753 if (m
->charset
[str
[-1]] & (1 << z
))
9754 newstates
= stb__add_if_inactive(m
, newstates
, n
->out
[j
].node
);
9758 // AND add in the start state!
9759 if (!m
->match_start
|| (str
[-1] == '\n' && !m
->does_lex
))
9760 newstates
= stb__add_if_inactive(m
, newstates
, m
->start_node
);
9761 // AND epsilon close it
9762 newstates
= stb__eps_closure(m
, newstates
);
9763 // if it's a goal state, then that's all there is to it
9764 if (stb__clear_goalcheck(m
, newstates
)) {
9766 match_length
= str
- (stb_uint8
*) str_c
;
9767 node
= stb__get_dfa_node(m
,newstates
);
9768 match_result
= node
;
9769 node
= -node
+ STB__DFA_MGOAL
;
9770 trans
= m
->dfa
; // could have gotten realloc()ed
9772 node
= STB__DFA_GOAL
;
9773 } else if (str
[-1] == 0 || stb_arr_len(newstates
) == 0) {
9774 node
= STB__DFA_END
;
9776 node
= stb__get_dfa_node(m
,newstates
);
9777 trans
= m
->dfa
; // could have gotten realloc()ed
9779 trans
[prevnode
].transition
[str
[-1]] = node
;
9780 if (node
<= STB__DFA_MGOAL
)
9781 node
= -(node
- STB__DFA_MGOAL
);
9782 stb_arr_free(newstates
);
9783 stb_arr_free(states
);
9786 if (node
== STB__DFA_GOAL
) {
9789 if (node
== STB__DFA_END
) {
9792 if (len
) *len
= match_length
;
9793 return m
->dfa_result
[(int) match_result
];
9799 assert(node
!= STB__DFA_UNDEF
);
9803 int stb_matcher_find(stb_matcher
*m
, char *str
)
9805 assert(m
->does_lex
== 0);
9806 return stb__matcher_dfa(m
, str
, NULL
);
9809 int stb_lex(stb_matcher
*m
, char *str
, int *len
)
9811 assert(m
->does_lex
);
9812 return stb__matcher_dfa(m
, str
, len
);
9815 int stb_regex(char *regex
, char *str
)
9817 static stb_perfect p
;
9818 static stb_matcher
** matchers
;
9819 static char ** regexps
;
9820 static char ** regexp_cache
;
9821 static unsigned short *mapping
;
9822 int z
= stb_perfect_hash(&p
, (int) regex
);
9824 if (strcmp(regex
, regexp_cache
[(int) mapping
[z
]])) {
9826 stb_matcher_free(matchers
[i
]);
9827 free(regexp_cache
[i
]);
9829 regexp_cache
[i
] = strdup(regex
);
9830 matchers
[i
] = stb_regex_matcher(regex
);
9834 if (regex
== NULL
) {
9835 for (i
=0; i
< stb_arr_len(matchers
); ++i
) {
9836 stb_matcher_free(matchers
[i
]);
9837 free(regexp_cache
[i
]);
9839 stb_arr_free(matchers
);
9840 stb_arr_free(regexps
);
9841 stb_arr_free(regexp_cache
);
9842 stb_perfect_destroy(&p
);
9843 free(mapping
); mapping
= NULL
;
9846 stb_arr_push(regexps
, regex
);
9847 stb_arr_push(regexp_cache
, strdup(regex
));
9848 stb_arr_push(matchers
, stb_regex_matcher(regex
));
9849 stb_perfect_destroy(&p
);
9850 n
= stb_perfect_create(&p
, (unsigned int *) (char **) regexps
, stb_arr_len(regexps
));
9851 mapping
= (unsigned short *) realloc(mapping
, n
* sizeof(*mapping
));
9852 for (i
=0; i
< stb_arr_len(regexps
); ++i
)
9853 mapping
[stb_perfect_hash(&p
, (int) regexps
[i
])] = i
;
9854 z
= stb_perfect_hash(&p
, (int) regex
);
9856 return stb_matcher_find(matchers
[(int) mapping
[z
]], str
);
9859 #endif // STB_DEFINE
9863 //////////////////////////////////////////////////////////////////////////////
9865 // C source-code introspection
9868 // runtime structure
9872 char *type
; // base type
9873 char *comment
; // content of comment field
9874 int size
; // size of base type
9875 int offset
; // field offset
9876 int arrcount
[8]; // array sizes; -1 = pointer indirection; 0 = end of list
9884 stb_info_field
*fields
;
9887 extern stb_info_struct stb_introspect_output
[];
9891 STB_EXTERN
void stb_introspect_precompiled(stb_info_struct
*compiled
);
9892 STB_EXTERN
void stb__introspect(char *path
, char *file
);
9894 #define stb_introspect_ship() stb__introspect(NULL, NULL, stb__introspect_output)
9897 #define stb_introspect() stb_introspect_ship()
9898 #define stb_introspect_path(p) stb_introspect_ship()
9900 // bootstrapping: define stb_introspect() (or 'path') the first time
9901 #define stb_introspect() stb__introspect(NULL, __FILE__, NULL)
9902 #define stb_introspect_auto() stb__introspect(NULL, __FILE__, stb__introspect_output)
9904 #define stb_introspect_path(p) stb__introspect(p, __FILE__, NULL)
9905 #define stb_introspect_path(p) stb__introspect(p, __FILE__, NULL)
9910 #ifndef STB_INTROSPECT_CPP
9912 #define STB_INTROSPECT_CPP 1
9914 #define STB_INTROSPECT_CPP 0
9918 void stb_introspect_precompiled(stb_info_struct
*compiled
)
9924 static void stb__introspect_filename(char *buffer
, char *path
)
9926 #if STB_INTROSPECT_CPP
9927 sprintf(buffer
, "%s/stb_introspect.cpp", path
);
9929 sprintf(buffer
, "%s/stb_introspect.c", path
);
9933 static void stb__introspect_compute(char *path
, char *file
)
9936 char ** include_list
= NULL
;
9937 char ** introspect_list
= NULL
;
9939 f
= fopen(file
, "w");
9942 fputs("// if you get compiler errors, change the following 0 to a 1:\n", f
);
9943 fputs("#define STB_INTROSPECT_INVALID 0\n\n", f
);
9944 fputs("// this will force the code to compile, and force the introspector\n", f
);
9945 fputs("// to run and then exit, allowing you to recompile\n\n\n", f
);
9946 fputs("#include \"stb.h\"\n\n",f
);
9947 fputs("#if STB_INTROSPECT_INVALID\n", f
);
9948 fputs(" stb_info_struct stb__introspect_output[] = { (void *) 1 }\n", f
);
9949 fputs("#else\n\n", f
);
9950 for (i
=0; i
< stb_arr_len(include_list
); ++i
)
9951 fprintf(f
, " #include \"%s\"\n", include_list
[i
]);
9953 fputs(" stb_info_struct stb__introspect_output[] =\n{\n", f
);
9954 for (i
=0; i
< stb_arr_len(introspect_list
); ++i
)
9955 fprintf(f
, " stb_introspect_%s,\n", introspect_list
[i
]);
9957 fputs("#endif\n", f
);
9961 static stb_info_struct
*stb__introspect_info
;
9967 void stb__introspect(char *path
, char *file
, stb_info_struct
*compiled
)
9973 stb__introspect_info
= compiled
;
9977 int bail_flag
= compiled
&& compiled
[0].structname
== (void *) 1;
9978 int needs_building
= bail_flag
;
9979 struct stb__stat st
;
9980 char buffer
[1024], buffer2
[1024];
9982 stb_splitpath(buffer
, file
, STB_PATH
);
9985 // bail if the source path doesn't exist
9986 if (!stb_fexists(path
)) return;
9988 stb__introspect_filename(buffer2
, path
);
9990 // get source/include files timestamps, compare to output-file timestamp;
9991 // if mismatched, regenerate
9993 if (stb__stat(buffer2
, &st
))
9994 needs_building
= STB_TRUE
;
9997 // find any file that contains an introspection command and is newer
9998 // if needs_building is already true, we don't need to do this test,
9999 // but we still need these arrays, so go ahead and get them
10001 all
[0] = stb_readdir_files_mask(path
, "*.h");
10002 all
[1] = stb_readdir_files_mask(path
, "*.c");
10003 all
[2] = stb_readdir_files_mask(path
, "*.cpp");
10005 if (needs_building
) {
10006 for (j
=0; j
< 3; ++j
) {
10007 for (i
=0; i
< stb_arr_len(all
[j
]); ++i
) {
10008 struct stb__stat st2
;
10009 if (!stb__stat(all
[j
][i
], &st2
)) {
10010 if (st
.st_mtime
< st2
.st_mtime
) {
10011 char *z
= stb_filec(all
[j
][i
], NULL
);
10012 int found
=STB_FALSE
;
10014 y
= strstr(y
, "//si");
10015 if (y
&& isspace(y
[4])) {
10020 needs_building
= STB_TRUE
;
10028 char *z
= stb_filec(all
[i
], NULL
), *y
= z
;
10029 int found
=STB_FALSE
;
10031 y
= strstr(y
, "//si");
10032 if (y
&& isspace(y
[4])) {
10038 stb_arr_push(introspect_h
, strdup(all
[i
]));
10042 stb_readdir_free(all
);
10043 if (!needs_building
) {
10044 for (i
=0; i
< stb_arr_len(introspect_h
); ++i
) {
10045 struct stb__stat st2
;
10046 if (!stb__stat(introspect_h
[i
], &st2
))
10047 if (st
.st_mtime
< st2
.st_mtime
)
10048 needs_building
= STB_TRUE
;
10052 if (needs_building
) {
10053 stb__introspect_compute(path
, buffer2
);
10062 #ifdef STB_INTROSPECT
10063 // compile-time code-generator
10064 #define INTROSPECT(x) int main(int argc, char **argv) { stb__introspect(__FILE__); return 0; }
10067 void stb__introspect(char *filename
)
10069 char *file
= stb_file(filename
, NULL
);
10070 char *s
= file
, *t
, **p
;
10071 char *out_name
= "stb_introspect.c";
10073 STB_ARR(char) filelist
= NULL
;
10075 if (!file
) stb_fatal("Couldn't open %s", filename
);
10077 out_path
= stb_splitpathdup(filename
, STB_PATH
);
10079 // search for the macros
10082 while (*s
&& !isupper(*s
)) ++s
;
10083 s
= stb_strtok_invert(buffer
, s
, "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
10084 s
= stb_skipwhite(s
);
10087 t
= strchr(s
, ')');
10088 if (t
== NULL
) stb_fatal("Error parsing %s", filename
);
10099 //////////////////////////////////////////////////////////////////////////////
10101 // STB-C sliding-window dictionary compression
10103 // This uses a DEFLATE-style sliding window, but no bitwise entropy.
10104 // Everything is on byte boundaries, so you could then apply a byte-wise
10105 // entropy code, though that's nowhere near as effective.
10107 // An STB-C stream begins with a 16-byte header:
10108 // 4 bytes: 0x57 0xBC 0x00 0x00
10109 // 8 bytes: big-endian size of decompressed data, 64-bits
10110 // 4 bytes: big-endian size of window (how far back decompressor may need)
10112 // The following symbols appear in the stream (these were determined ad hoc,
10113 // not by analysis):
10115 // [dict] 00000100 yyyyyyyy yyyyyyyy yyyyyyyy xxxxxxxx xxxxxxxx
10116 // [END] 00000101 11111010 cccccccc cccccccc cccccccc cccccccc
10117 // [dict] 00000110 yyyyyyyy yyyyyyyy yyyyyyyy xxxxxxxx
10118 // [literals] 00000111 zzzzzzzz zzzzzzzz
10119 // [literals] 00001zzz zzzzzzzz
10120 // [dict] 00010yyy yyyyyyyy yyyyyyyy xxxxxxxx xxxxxxxx
10121 // [dict] 00011yyy yyyyyyyy yyyyyyyy xxxxxxxx
10122 // [literals] 001zzzzz
10123 // [dict] 01yyyyyy yyyyyyyy xxxxxxxx
10124 // [dict] 1xxxxxxx yyyyyyyy
10126 // xxxxxxxx: match length - 1
10127 // yyyyyyyy: backwards distance - 1
10128 // zzzzzzzz: num literals - 1
10129 // cccccccc: adler32 checksum of decompressed data
10130 // (all big-endian)
10133 STB_EXTERN stb_uint
stb_decompress_length(stb_uchar
*input
);
10134 STB_EXTERN stb_uint
stb_decompress(stb_uchar
*out
,stb_uchar
*in
,stb_uint len
);
10135 STB_EXTERN stb_uint
stb_compress (stb_uchar
*out
,stb_uchar
*in
,stb_uint len
);
10136 STB_EXTERN
void stb_compress_window(int z
);
10137 STB_EXTERN
void stb_compress_hashsize(unsigned int z
);
10139 STB_EXTERN
int stb_compress_tofile(char *filename
, char *in
, stb_uint len
);
10140 STB_EXTERN
int stb_compress_intofile(FILE *f
, char *input
, stb_uint len
);
10141 STB_EXTERN
char *stb_decompress_fromfile(char *filename
, stb_uint
*len
);
10143 STB_EXTERN
int stb_compress_stream_start(FILE *f
);
10144 STB_EXTERN
void stb_compress_stream_end(int close
);
10145 STB_EXTERN
void stb_write(char *data
, int data_len
);
10149 stb_uint
stb_decompress_length(stb_uchar
*input
)
10151 return (input
[8] << 24) + (input
[9] << 16) + (input
[10] << 8) + input
[11];
10154 //////////////////// decompressor ///////////////////////
10156 // simple implementation that just writes whole thing into big block
10158 static unsigned char *stb__barrier
;
10159 static unsigned char *stb__barrier2
;
10160 static unsigned char *stb__barrier3
;
10161 static unsigned char *stb__barrier4
;
10163 static stb_uchar
*stb__dout
;
10164 static void stb__match(stb_uchar
*data
, stb_uint length
)
10166 // INVERSE of memmove... write each byte before copying the next...
10167 assert (stb__dout
+ length
<= stb__barrier
);
10168 if (stb__dout
+ length
> stb__barrier
) { stb__dout
+= length
; return; }
10169 if (data
< stb__barrier4
) { stb__dout
= stb__barrier
+1; return; }
10170 while (length
--) *stb__dout
++ = *data
++;
10173 static void stb__lit(stb_uchar
*data
, stb_uint length
)
10175 assert (stb__dout
+ length
<= stb__barrier
);
10176 if (stb__dout
+ length
> stb__barrier
) { stb__dout
+= length
; return; }
10177 if (data
< stb__barrier2
) { stb__dout
= stb__barrier
+1; return; }
10178 memcpy(stb__dout
, data
, length
);
10179 stb__dout
+= length
;
10182 #define stb__in2(x) ((i[x] << 8) + i[(x)+1])
10183 #define stb__in3(x) ((i[x] << 16) + stb__in2((x)+1))
10184 #define stb__in4(x) ((i[x] << 24) + stb__in3((x)+1))
10186 static stb_uchar
*stb_decompress_token(stb_uchar
*i
)
10188 if (*i
>= 0x20) { // use fewer if's for cases that expand small
10189 if (*i
>= 0x80) stb__match(stb__dout
-i
[1]-1, i
[0] - 0x80 + 1), i
+= 2;
10190 else if (*i
>= 0x40) stb__match(stb__dout
-(stb__in2(0) - 0x4000 + 1), i
[2]+1), i
+= 3;
10191 else /* *i >= 0x20 */ stb__lit(i
+1, i
[0] - 0x20 + 1), i
+= 1 + (i
[0] - 0x20 + 1);
10192 } else { // more ifs for cases that expand large, since overhead is amortized
10193 if (*i
>= 0x18) stb__match(stb__dout
-(stb__in3(0) - 0x180000 + 1), i
[3]+1), i
+= 4;
10194 else if (*i
>= 0x10) stb__match(stb__dout
-(stb__in3(0) - 0x100000 + 1), stb__in2(3)+1), i
+= 5;
10195 else if (*i
>= 0x08) stb__lit(i
+2, stb__in2(0) - 0x0800 + 1), i
+= 2 + (stb__in2(0) - 0x0800 + 1);
10196 else if (*i
== 0x07) stb__lit(i
+3, stb__in2(1) + 1), i
+= 3 + (stb__in2(1) + 1);
10197 else if (*i
== 0x06) stb__match(stb__dout
-(stb__in3(1)+1), i
[4]+1), i
+= 5;
10198 else if (*i
== 0x04) stb__match(stb__dout
-(stb__in3(1)+1), stb__in2(4)+1), i
+= 6;
10203 stb_uint
stb_decompress(stb_uchar
*output
, stb_uchar
*i
, stb_uint length
)
10206 if (stb__in4(0) != 0x57bC0000) return 0;
10207 if (stb__in4(4) != 0) return 0; // error! stream is > 4GB
10208 olen
= stb_decompress_length(i
);
10210 stb__barrier3
= i
+length
;
10211 stb__barrier
= output
+ olen
;
10212 stb__barrier4
= output
;
10215 stb__dout
= output
;
10217 stb_uchar
*old_i
= i
;
10218 i
= stb_decompress_token(i
);
10220 if (*i
== 0x05 && i
[1] == 0xfa) {
10221 assert(stb__dout
== output
+ olen
);
10222 if (stb__dout
!= output
+ olen
) return 0;
10223 if (stb_adler32(1, output
, olen
) != (stb_uint
) stb__in4(2))
10227 assert(0); /* NOTREACHED */
10231 assert(stb__dout
<= output
+ olen
);
10232 if (stb__dout
> output
+ olen
)
10237 char *stb_decompress_fromfile(char *filename
, unsigned int *len
)
10242 FILE *f
= fopen(filename
, "rb"); if (f
== NULL
) return NULL
;
10243 fseek(f
, 0, SEEK_END
);
10245 fseek(f
, 0, SEEK_SET
);
10246 p
= (unsigned char * ) malloc(n
); if (p
== NULL
) return NULL
;
10249 if (p
== NULL
) return NULL
;
10250 if (p
[0] != 0x57 || p
[1] != 0xBc || p
[2] || p
[3]) { free(p
); return NULL
; }
10251 q
= (char *) malloc(stb_decompress_length(p
)+1);
10252 if (!q
) { free(p
); return NULL
; }
10253 *len
= stb_decompress((unsigned char *) q
, p
, n
);
10254 if (*len
) q
[*len
] = 0;
10260 // streaming decompressor
10264 stb__uchar
*in_buffer
;
10267 stb__uint pending_literals
;
10268 stb__uint pending_match
;
10273 static void stb__match(stb_uchar
*data
, stb_uint length
)
10275 // INVERSE of memmove... write each byte before copying the next...
10276 assert (stb__dout
+ length
<= stb__barrier
);
10277 if (stb__dout
+ length
> stb__barrier
) { stb__dout
+= length
; return; }
10278 if (data
< stb__barrier2
) { stb__dout
= stb__barrier
+1; return; }
10279 while (length
--) *stb__dout
++ = *data
++;
10282 static void stb__lit(stb_uchar
*data
, stb_uint length
)
10284 assert (stb__dout
+ length
<= stb__barrier
);
10285 if (stb__dout
+ length
> stb__barrier
) { stb__dout
+= length
; return; }
10286 if (data
< stb__barrier2
) { stb__dout
= stb__barrier
+1; return; }
10287 memcpy(stb__dout
, data
, length
);
10288 stb__dout
+= length
;
10291 static void sx_match(stb_uchar
*data
, stb_uint length
)
10294 xx
.pending_match
= length
;
10297 static void sx_lit(stb_uchar
*data
, stb_uint length
)
10299 xx
.pending_lit
= length
;
10302 static int stb_decompress_token_state(void)
10304 stb__uchar
*i
= xx
.in_buffer
;
10306 if (*i
>= 0x20) { // use fewer if's for cases that expand small
10307 if (*i
>= 0x80) sx_match(stb__dout
-i
[1]-1, i
[0] - 0x80 + 1), i
+= 2;
10308 else if (*i
>= 0x40) sx_match(stb__dout
-(stb__in2(0) - 0x4000 + 1), i
[2]+1), i
+= 3;
10309 else /* *i >= 0x20 */ sx_lit(i
+1, i
[0] - 0x20 + 1), i
+= 1;
10310 } else { // more ifs for cases that expand large, since overhead is amortized
10311 if (*i
>= 0x18) sx_match(stb__dout
-(stb__in3(0) - 0x180000 + 1), i
[3]+1), i
+= 4;
10312 else if (*i
>= 0x10) sx_match(stb__dout
-(stb__in3(0) - 0x100000 + 1), stb__in2(3)+1), i
+= 5;
10313 else if (*i
>= 0x08) sx_lit(i
+2, stb__in2(0) - 0x0800 + 1), i
+= 2;
10314 else if (*i
== 0x07) sx_lit(i
+3, stb__in2(1) + 1), i
+= 3;
10315 else if (*i
== 0x06) sx_match(stb__dout
-(stb__in3(1)+1), i
[4]+1), i
+= 5;
10316 else if (*i
== 0x04) sx_match(stb__dout
-(stb__in3(1)+1), stb__in2(4)+1), i
+= 6;
10326 //////////////////// compressor ///////////////////////
10328 static unsigned int stb_matchlen(stb_uchar
*m1
, stb_uchar
*m2
, stb_uint maxlen
)
10331 for (i
=0; i
< maxlen
; ++i
)
10332 if (m1
[i
] != m2
[i
]) return i
;
10336 // simple implementation that just takes the source data in a big block
10338 static stb_uchar
*stb__out
;
10339 static FILE *stb__outfile
;
10340 static stb_uint stb__outbytes
;
10342 static void stb__write(unsigned char v
)
10344 fputc(v
, stb__outfile
);
10348 #define stb_out(v) (stb__out ? *stb__out++ = (stb_uchar) (v) : stb__write((stb_uchar) (v)))
10350 static void stb_out2(stb_uint v
)
10356 static void stb_out3(stb_uint v
) { stb_out(v
>> 16); stb_out(v
>> 8); stb_out(v
); }
10357 static void stb_out4(stb_uint v
) { stb_out(v
>> 24); stb_out(v
>> 16);
10358 stb_out(v
>> 8 ); stb_out(v
); }
10360 static void outliterals(stb_uchar
*in
, int numlit
)
10362 while (numlit
> 65536) {
10363 outliterals(in
,65536);
10369 else if (numlit
<= 32) stb_out (0x000020 + numlit
-1);
10370 else if (numlit
<= 2048) stb_out2(0x000800 + numlit
-1);
10371 else /* numlit <= 65536) */ stb_out3(0x070000 + numlit
-1);
10374 memcpy(stb__out
,in
,numlit
);
10375 stb__out
+= numlit
;
10377 fwrite(in
, 1, numlit
, stb__outfile
);
10380 static int stb__window
= 0x40000; // 256K
10381 void stb_compress_window(int z
)
10383 if (z
>= 0x1000000) z
= 0x1000000; // limit of implementation
10384 if (z
< 0x100) z
= 0x100; // insanely small
10388 static int stb_not_crap(int best
, int dist
)
10390 return ((best
> 2 && dist
<= 0x00100)
10391 || (best
> 5 && dist
<= 0x04000)
10392 || (best
> 7 && dist
<= 0x80000));
10395 static stb_uint stb__hashsize
= 32768;
10396 void stb_compress_hashsize(unsigned int y
)
10398 unsigned int z
= 1024;
10399 while (z
< y
) z
<<= 1;
10400 stb__hashsize
= z
>> 2; // pass in bytes, store #pointers
10403 // note that you can play with the hashing functions all you
10404 // want without needing to change the decompressor
10405 #define stb__hc(q,h,c) (((h) << 7) + ((h) >> 25) + q[c])
10406 #define stb__hc2(q,h,c,d) (((h) << 14) + ((h) >> 18) + (q[c] << 7) + q[d])
10407 #define stb__hc3(q,c,d,e) ((q[c] << 14) + (q[d] << 7) + q[e])
10409 static stb_uint32 stb__running_adler
;
10411 static int stb_compress_chunk(stb_uchar
*history
,
10415 int *pending_literals
,
10419 int window
= stb__window
;
10420 stb_uint match_max
;
10421 stb_uchar
*lit_start
= start
- *pending_literals
;
10422 stb_uchar
*q
= start
;
10424 #define STB__SCRAMBLE(h) (((h) + ((h) >> 16)) & mask)
10426 // stop short of the end so we don't scan off the end doing
10427 // the hashing; this means we won't compress the last few bytes
10428 // unless they were part of something longer
10429 while (q
< start
+length
&& q
+12 < end
) {
10431 stb_uint h1
,h2
,h3
,h4
, h
;
10433 int best
= 2, dist
=0;
10440 #define stb__nc(b,d) ((d) <= window && ((b) > 9 || stb_not_crap(b,d)))
10442 #define STB__TRY(t,p) /* avoid retrying a match we already tried */ \
10443 if (p ? dist != q-t : 1) \
10444 if ((m = stb_matchlen(t, q, match_max)) > best) \
10445 if (stb__nc(m,q-(t))) \
10446 best = m, dist = q - (t)
10448 // rather than search for all matches, only try 4 candidate locations,
10449 // chosen based on 4 different hash functions of different lengths.
10450 // this strategy is inspired by LZO; hashing is unrolled here using the
10452 h
= stb__hc3(q
,0, 1, 2); h1
= STB__SCRAMBLE(h
);
10453 t
= chash
[h1
]; if (t
) STB__TRY(t
,0);
10454 h
= stb__hc2(q
,h
, 3, 4); h2
= STB__SCRAMBLE(h
);
10455 h
= stb__hc2(q
,h
, 5, 6); t
= chash
[h2
]; if (t
) STB__TRY(t
,1);
10456 h
= stb__hc2(q
,h
, 7, 8); h3
= STB__SCRAMBLE(h
);
10457 h
= stb__hc2(q
,h
, 9,10); t
= chash
[h3
]; if (t
) STB__TRY(t
,1);
10458 h
= stb__hc2(q
,h
,11,12); h4
= STB__SCRAMBLE(h
);
10459 t
= chash
[h4
]; if (t
) STB__TRY(t
,1);
10461 // because we use a shared hash table, can only update it
10462 // _after_ we've probed all of them
10463 chash
[h1
] = chash
[h2
] = chash
[h3
] = chash
[h4
] = q
;
10468 // see if our best match qualifies
10469 if (best
< 3) { // fast path literals
10471 } else if (best
> 2 && best
<= 0x80 && dist
<= 0x100) {
10472 outliterals(lit_start
, q
-lit_start
); lit_start
= (q
+= best
);
10473 stb_out(0x80 + best
-1);
10475 } else if (best
> 5 && best
<= 0x100 && dist
<= 0x4000) {
10476 outliterals(lit_start
, q
-lit_start
); lit_start
= (q
+= best
);
10477 stb_out2(0x4000 + dist
-1);
10479 } else if (best
> 7 && best
<= 0x100 && dist
<= 0x80000) {
10480 outliterals(lit_start
, q
-lit_start
); lit_start
= (q
+= best
);
10481 stb_out3(0x180000 + dist
-1);
10483 } else if (best
> 8 && best
<= 0x10000 && dist
<= 0x80000) {
10484 outliterals(lit_start
, q
-lit_start
); lit_start
= (q
+= best
);
10485 stb_out3(0x100000 + dist
-1);
10487 } else if (best
> 9 && dist
<= 0x1000000) {
10488 if (best
> 65536) best
= 65536;
10489 outliterals(lit_start
, q
-lit_start
); lit_start
= (q
+= best
);
10490 if (best
<= 0x100) {
10499 } else { // fallback literals if no match was a balanced tradeoff
10504 // if we didn't get all the way, add the rest to literals
10505 if (q
-start
< length
)
10508 // the literals are everything from lit_start to q
10509 *pending_literals
= (q
- lit_start
);
10511 stb__running_adler
= stb_adler32(stb__running_adler
, start
, q
- start
);
10515 static int stb_compress_inner(stb_uchar
*input
, stb_uint length
)
10521 chash
= (stb_uchar
**) malloc(stb__hashsize
* sizeof(stb_uchar
*));
10522 if (chash
== NULL
) return 0; // failure
10523 for (i
=0; i
< stb__hashsize
; ++i
)
10526 // stream signature
10527 stb_out(0x57); stb_out(0xbc);
10530 stb_out4(0); // 64-bit length requires 32-bit leading 0
10532 stb_out4(stb__window
);
10534 stb__running_adler
= 1;
10536 len
= stb_compress_chunk(input
, input
, input
+length
, length
, &literals
, chash
, stb__hashsize
-1);
10537 assert(len
== length
);
10539 outliterals(input
+length
- literals
, literals
);
10543 stb_out2(0x05fa); // end opcode
10545 stb_out4(stb__running_adler
);
10547 return 1; // success
10550 stb_uint
stb_compress(stb_uchar
*out
, stb_uchar
*input
, stb_uint length
)
10553 stb__outfile
= NULL
;
10555 stb_compress_inner(input
, length
);
10557 return stb__out
- out
;
10560 int stb_compress_tofile(char *filename
, char *input
, unsigned int length
)
10562 //int maxlen = length + 512 + (length >> 2); // total guess
10563 //char *buffer = (char *) malloc(maxlen);
10564 //int blen = stb_compress((stb_uchar*)buffer, (stb_uchar*)input, length);
10567 stb__outfile
= fopen(filename
, "wb");
10568 if (!stb__outfile
) return 0;
10572 if (!stb_compress_inner((stb_uchar
*)input
, length
))
10575 fclose(stb__outfile
);
10577 return stb__outbytes
;
10580 int stb_compress_intofile(FILE *f
, char *input
, unsigned int length
)
10582 //int maxlen = length + 512 + (length >> 2); // total guess
10583 //char *buffer = (char*)malloc(maxlen);
10584 //int blen = stb_compress((stb_uchar*)buffer, (stb_uchar*)input, length);
10588 if (!stb__outfile
) return 0;
10592 if (!stb_compress_inner((stb_uchar
*)input
, length
))
10595 return stb__outbytes
;
10598 ////////////////////// streaming I/O version /////////////////////
10601 static size_t stb_out_backpatch_id(void)
10604 return (size_t) stb__out
;
10606 return ftell(stb__outfile
);
10609 static void stb_out_backpatch(size_t id
, stb_uint value
)
10611 stb_uchar data
[4] = { value
>> 24, value
>> 16, value
>> 8, value
};
10613 memcpy((void *) id
, data
, 4);
10615 stb_uint where
= ftell(stb__outfile
);
10616 fseek(stb__outfile
, id
, SEEK_SET
);
10617 fwrite(data
, 4, 1, stb__outfile
);
10618 fseek(stb__outfile
, where
, SEEK_SET
);
10622 // ok, the wraparound buffer was a total failure. let's instead
10623 // use a copying-in-place buffer, which lets us share the code.
10624 // This is way less efficient but it'll do for now.
10629 int size
; // physical size of buffer in bytes
10631 int valid
; // amount of valid data in bytes
10632 int start
; // bytes of data already output
10637 int pending_literals
; // bytes not-quite output but counted in start
10640 stb_uint total_bytes
;
10646 static int stb_compress_streaming_start(void)
10649 xtb
.size
= stb__window
* 3;
10650 xtb
.buffer
= (stb_uchar
*)malloc(xtb
.size
);
10651 if (!xtb
.buffer
) return 0;
10653 xtb
.chash
= (stb_uchar
**)malloc(sizeof(*xtb
.chash
) * stb__hashsize
);
10659 for (i
=0; i
< stb__hashsize
; ++i
)
10660 xtb
.chash
[i
] = NULL
;
10662 xtb
.hashmask
= stb__hashsize
-1;
10666 xtb
.window
= stb__window
;
10667 xtb
.fsize
= stb__window
;
10668 xtb
.pending_literals
= 0;
10669 xtb
.total_bytes
= 0;
10671 // stream signature
10672 stb_out(0x57); stb_out(0xbc); stb_out2(0);
10674 stb_out4(0); // 64-bit length requires 32-bit leading 0
10676 xtb
.length_id
= stb_out_backpatch_id();
10677 stb_out4(0); // we don't know the output length yet
10679 stb_out4(stb__window
);
10681 stb__running_adler
= 1;
10686 static int stb_compress_streaming_end(void)
10688 // flush out any remaining data
10689 stb_compress_chunk(xtb
.buffer
, xtb
.buffer
+xtb
.start
, xtb
.buffer
+xtb
.valid
,
10690 xtb
.valid
-xtb
.start
, &xtb
.pending_literals
, xtb
.chash
, xtb
.hashmask
);
10692 // write out pending literals
10693 outliterals(xtb
.buffer
+ xtb
.valid
- xtb
.pending_literals
, xtb
.pending_literals
);
10695 stb_out2(0x05fa); // end opcode
10696 stb_out4(stb__running_adler
);
10698 stb_out_backpatch(xtb
.length_id
, xtb
.total_bytes
);
10705 void stb_write(char *data
, int data_len
)
10709 // @TODO: fast path for filling the buffer and doing nothing else
10710 // if (xtb.valid + data_len < xtb.size)
10712 xtb
.total_bytes
+= data_len
;
10716 if (xtb
.valid
< xtb
.size
) {
10717 int amt
= xtb
.size
- xtb
.valid
;
10718 if (data_len
< amt
) amt
= data_len
;
10719 memcpy(xtb
.buffer
+ xtb
.valid
, data
, amt
);
10724 if (xtb
.valid
< xtb
.size
)
10727 // at this point, the buffer is full
10729 // if we can process some data, go for it; make sure
10730 // we leave an 'fsize's worth of data, though
10731 if (xtb
.start
+ xtb
.fsize
< xtb
.valid
) {
10732 int amount
= (xtb
.valid
- xtb
.fsize
) - xtb
.start
;
10734 assert(amount
> 0);
10735 n
= stb_compress_chunk(xtb
.buffer
, xtb
.buffer
+ xtb
.start
, xtb
.buffer
+ xtb
.valid
,
10736 amount
, &xtb
.pending_literals
, xtb
.chash
, xtb
.hashmask
);
10740 assert(xtb
.start
+ xtb
.fsize
>= xtb
.valid
);
10741 // at this point, our future size is too small, so we
10742 // need to flush some history. we, in fact, flush exactly
10743 // one window's worth of history
10746 int flush
= xtb
.window
;
10747 assert(xtb
.start
>= flush
);
10748 assert(xtb
.valid
>= flush
);
10750 // if 'pending literals' extends back into the shift region,
10752 if (xtb
.start
- xtb
.pending_literals
< flush
) {
10753 outliterals(xtb
.buffer
+ xtb
.start
- xtb
.pending_literals
, xtb
.pending_literals
);
10754 xtb
.pending_literals
= 0;
10757 // now shift the window
10758 memmove(xtb
.buffer
, xtb
.buffer
+ flush
, xtb
.valid
- flush
);
10759 xtb
.start
-= flush
;
10760 xtb
.valid
-= flush
;
10762 for (i
=0; i
<= xtb
.hashmask
; ++i
)
10763 if (xtb
.chash
[i
] < xtb
.buffer
+ flush
)
10764 xtb
.chash
[i
] = NULL
;
10766 xtb
.chash
[i
] -= flush
;
10768 // and now that we've made room for more data, go back to the top
10772 int stb_compress_stream_start(FILE *f
)
10780 if (!stb_compress_streaming_start())
10786 void stb_compress_stream_end(int close
)
10788 stb_compress_streaming_end();
10789 if (close
&& stb__outfile
) {
10790 fclose(stb__outfile
);
10794 #endif // STB_DEFINE
10796 //////////////////////////////////////////////////////////////////////////////
10798 // File abstraction... tired of not having this... we can write
10799 // compressors to be layers over these that auto-close their children.
10802 typedef struct stbfile
10804 int (*getbyte
)(struct stbfile
*); // -1 on EOF
10805 unsigned int (*getdata
)(struct stbfile
*, void *block
, unsigned int len
);
10807 int (*putbyte
)(struct stbfile
*, int byte
);
10808 unsigned int (*putdata
)(struct stbfile
*, void *block
, unsigned int len
);
10810 unsigned int (*size
)(struct stbfile
*);
10812 unsigned int (*tell
)(struct stbfile
*);
10813 void (*backpatch
)(struct stbfile
*, unsigned int tell
, void *block
, unsigned int len
);
10815 void (*close
)(struct stbfile
*);
10817 FILE *f
; // file to fread/fwrite
10818 unsigned char *buffer
; // input/output buffer
10819 unsigned char *indata
, *inend
; // input buffer
10826 STB_EXTERN
unsigned int stb_getc(stbfile
*f
); // read
10827 STB_EXTERN
int stb_putc(stbfile
*f
, int ch
); // write
10828 STB_EXTERN
unsigned int stb_getdata(stbfile
*f
, void *buffer
, unsigned int len
); // read
10829 STB_EXTERN
unsigned int stb_putdata(stbfile
*f
, void *buffer
, unsigned int len
); // write
10830 STB_EXTERN
unsigned int stb_tell(stbfile
*f
); // read
10831 STB_EXTERN
unsigned int stb_size(stbfile
*f
); // read/write
10832 STB_EXTERN
void stb_backpatch(stbfile
*f
, unsigned int tell
, void *buffer
, unsigned int len
); // write
10836 unsigned int stb_getc(stbfile
*f
) { return f
->getbyte(f
); }
10837 int stb_putc(stbfile
*f
, int ch
) { return f
->putbyte(f
, ch
); }
10839 unsigned int stb_getdata(stbfile
*f
, void *buffer
, unsigned int len
)
10841 return f
->getdata(f
, buffer
, len
);
10843 unsigned int stb_putdata(stbfile
*f
, void *buffer
, unsigned int len
)
10845 return f
->putdata(f
, buffer
, len
);
10847 void stb_close(stbfile
*f
)
10852 unsigned int stb_tell(stbfile
*f
) { return f
->tell(f
); }
10853 unsigned int stb_size(stbfile
*f
) { return f
->size(f
); }
10854 void stb_backpatch(stbfile
*f
, unsigned int tell
, void *buffer
, unsigned int len
)
10856 f
->backpatch(f
,tell
,buffer
,len
);
10859 // FILE * implementation
10860 static int stb__fgetbyte(stbfile
*f
) { return fgetc(f
->f
); }
10861 static int stb__fputbyte(stbfile
*f
, int ch
) { return fputc(ch
, f
->f
)==0; }
10862 static unsigned int stb__fgetdata(stbfile
*f
, void *buffer
, unsigned int len
) { return fread(buffer
,1,len
,f
->f
); }
10863 static unsigned int stb__fputdata(stbfile
*f
, void *buffer
, unsigned int len
) { return fwrite(buffer
,1,len
,f
->f
); }
10864 static unsigned int stb__fsize(stbfile
*f
) { return stb_filelen(f
->f
); }
10865 static unsigned int stb__ftell(stbfile
*f
) { return ftell(f
->f
); }
10866 static void stb__fbackpatch(stbfile
*f
, unsigned int where
, void *buffer
, unsigned int len
)
10868 fseek(f
->f
, where
, SEEK_SET
);
10869 fwrite(buffer
, 1, len
, f
->f
);
10870 fseek(f
->f
, 0, SEEK_END
);
10872 static void stb__fclose(stbfile
*f
) { fclose(f
->f
); }
10874 stbfile
*stb_openf(FILE *f
)
10876 stbfile m
= { stb__fgetbyte
, stb__fgetdata
,
10877 stb__fputbyte
, stb__fputdata
,
10878 stb__fsize
, stb__ftell
, stb__fbackpatch
, stb__fclose
,
10880 stbfile
*z
= (stbfile
*) malloc(sizeof(*z
));
10888 static int stb__nogetbyte(stbfile
*f
) { assert(0); return -1; }
10889 static unsigned int stb__nogetdata(stbfile
*f
, void *buffer
, unsigned int len
) { assert(0); return 0; }
10890 static int stb__noputbyte(stbfile
*f
, int ch
) { assert(0); return 0; }
10891 static unsigned int stb__noputdata(stbfile
*f
, void *buffer
, unsigned int len
) { assert(0); return 0; }
10892 static void stb__nobackpatch(stbfile
*f
, unsigned int where
, void *buffer
, unsigned int len
) { assert(0); }
10894 static int stb__bgetbyte(stbfile
*s
)
10896 if (s
->indata
< s
->inend
)
10897 return *s
->indata
++;
10902 static unsigned int stb__bgetdata(stbfile
*s
, void *buffer
, unsigned int len
)
10904 if (s
->indata
+ len
> s
->inend
)
10905 len
= s
->inend
- s
->indata
;
10906 memcpy(buffer
, s
->indata
, len
);
10910 static unsigned int stb__bsize(stbfile
*s
) { return s
->inend
- s
->buffer
; }
10911 static unsigned int stb__btell(stbfile
*s
) { return s
->indata
- s
->buffer
; }
10913 static void stb__bclose(stbfile
*s
)
10919 stbfile
*stb_open_inbuffer(void *buffer
, unsigned int len
)
10921 stbfile m
= { stb__bgetbyte
, stb__bgetdata
,
10922 stb__noputbyte
, stb__noputdata
,
10923 stb__bsize
, stb__btell
, stb__nobackpatch
, stb__bclose
};
10924 stbfile
*z
= (stbfile
*) malloc(sizeof(*z
));
10927 z
->buffer
= (unsigned char *) buffer
;
10928 z
->indata
= z
->buffer
;
10929 z
->inend
= z
->indata
+ len
;
10934 stbfile
*stb_open_inbuffer_free(void *buffer
, unsigned int len
)
10936 stbfile
*z
= stb_open_inbuffer(buffer
, len
);
10938 z
->various
= 1; // free
10942 #ifndef STB_VERSION
10943 // if we've been cut-and-pasted elsewhere, you get a limited
10944 // version of stb_open, without the 'k' flag and utf8 support
10945 static void stb__fclose2(stbfile
*f
)
10950 stbfile
*stb_open(char *filename
, char *mode
)
10952 FILE *f
= fopen(filename
, mode
);
10954 if (f
== NULL
) return NULL
;
10957 s
->close
= stb__fclose2
;
10961 // the full version depends on some code in stb.h; this
10962 // also includes the memory buffer output format implemented with stb_arr
10963 static void stb__fclose2(stbfile
*f
)
10965 stb_fclose(f
->f
, f
->various
);
10968 stbfile
*stb_open(char *filename
, char *mode
)
10970 FILE *f
= stb_fopen(filename
, mode
[0] == 'k' ? mode
+1 : mode
);
10972 if (f
== NULL
) return NULL
;
10975 s
->close
= stb__fclose2
;
10976 s
->various
= mode
[0] == 'k' ? stb_keep_if_different
: stb_keep_yes
;
10981 static int stb__aputbyte(stbfile
*f
, int ch
)
10983 stb_arr_push(f
->buffer
, ch
);
10986 static unsigned int stb__aputdata(stbfile
*f
, void *data
, unsigned int len
)
10988 memcpy(stb_arr_addn(f
->buffer
, (int) len
), data
, len
);
10991 static unsigned int stb__asize(stbfile
*f
) { return stb_arr_len(f
->buffer
); }
10992 static void stb__abackpatch(stbfile
*f
, unsigned int where
, void *data
, unsigned int len
)
10994 memcpy(f
->buffer
+where
, data
, len
);
10996 static void stb__aclose(stbfile
*f
)
10998 *(unsigned char **) f
->ptr
= f
->buffer
;
11001 stbfile
*stb_open_outbuffer(unsigned char **update_on_close
)
11003 stbfile m
= { stb__nogetbyte
, stb__nogetdata
,
11004 stb__aputbyte
, stb__aputdata
,
11005 stb__asize
, stb__asize
, stb__abackpatch
, stb__aclose
};
11006 stbfile
*z
= (stbfile
*) malloc(sizeof(*z
));
11008 z
->ptr
= update_on_close
;
11017 //////////////////////////////////////////////////////////////////////////////
11019 // Arithmetic coder... based on cbloom's notes on the subject, should be
11020 // less code than a huffman code.
11024 unsigned int range_low
;
11025 unsigned int range_high
;
11026 unsigned int code
, range
; // decode
11032 STB_EXTERN
void stb_arith_init_encode(stb_arith
*a
, stbfile
*out
);
11033 STB_EXTERN
void stb_arith_init_decode(stb_arith
*a
, stbfile
*in
);
11034 STB_EXTERN stbfile
*stb_arith_encode_close(stb_arith
*a
);
11035 STB_EXTERN stbfile
*stb_arith_decode_close(stb_arith
*a
);
11037 STB_EXTERN
void stb_arith_encode(stb_arith
*a
, unsigned int totalfreq
, unsigned int freq
, unsigned int cumfreq
);
11038 STB_EXTERN
void stb_arith_encode_log2(stb_arith
*a
, unsigned int totalfreq2
, unsigned int freq
, unsigned int cumfreq
);
11039 STB_EXTERN
unsigned int stb_arith_decode_value(stb_arith
*a
, unsigned int totalfreq
);
11040 STB_EXTERN
void stb_arith_decode_advance(stb_arith
*a
, unsigned int totalfreq
, unsigned int freq
, unsigned int cumfreq
);
11041 STB_EXTERN
unsigned int stb_arith_decode_value_log2(stb_arith
*a
, unsigned int totalfreq2
);
11042 STB_EXTERN
void stb_arith_decode_advance_log2(stb_arith
*a
, unsigned int totalfreq2
, unsigned int freq
, unsigned int cumfreq
);
11044 STB_EXTERN
void stb_arith_encode_byte(stb_arith
*a
, int byte
);
11045 STB_EXTERN
int stb_arith_decode_byte(stb_arith
*a
);
11047 // this is a memory-inefficient way of doing things, but it's
11048 // fast(?) and simple
11051 unsigned short cumfreq
;
11052 unsigned short samples
;
11053 } stb_arith_symstate_item
;
11060 stb_arith_symstate_item data
[1];
11061 } stb_arith_symstate
;
11064 void stb_arith_init_encode(stb_arith
*a
, stbfile
*out
)
11067 a
->range_high
= 0xffffffff;
11068 a
->pending_ffs
= -1; // means no buffered character currently, to speed up normal case
11072 static void stb__arith_carry(stb_arith
*a
)
11075 assert(a
->pending_ffs
!= -1); // can't carry with no data
11076 stb_putc(a
->output
, a
->buffered_u8
);
11077 for (i
=0; i
< a
->pending_ffs
; ++i
)
11078 stb_putc(a
->output
, 0);
11081 static void stb__arith_putbyte(stb_arith
*a
, int byte
)
11083 if (a
->pending_ffs
) {
11084 if (a
->pending_ffs
== -1) { // means no buffered data; encoded for fast path efficiency
11086 stb_putc(a
->output
, byte
); // just write it immediately
11088 a
->buffered_u8
= byte
;
11089 a
->pending_ffs
= 0;
11091 } else if (byte
== 0xff) {
11095 stb_putc(a
->output
, a
->buffered_u8
);
11096 for (i
=0; i
< a
->pending_ffs
; ++i
)
11097 stb_putc(a
->output
, 0xff);
11099 } else if (byte
== 0xff) {
11103 stb_putc(a
->output
, a
->buffered_u8
);
11104 a
->buffered_u8
= byte
;
11108 static void stb__arith_flush(stb_arith
*a
)
11110 if (a
->pending_ffs
>= 0) {
11112 stb_putc(a
->output
, a
->buffered_u8
);
11113 for (i
=0; i
< a
->pending_ffs
; ++i
)
11114 stb_putc(a
->output
, 0xff);
11118 static void stb__renorm_encoder(stb_arith
*a
)
11120 stb__arith_putbyte(a
, a
->range_low
>> 24);
11121 a
->range_low
<<= 8;
11122 a
->range_high
= (a
->range_high
<< 8) | 0xff;
11125 static void stb__renorm_decoder(stb_arith
*a
)
11127 int c
= stb_getc(a
->output
);
11128 a
->code
= (a
->code
<< 8) + (c
>= 0 ? c
: 0); // if EOF, insert 0
11131 void stb_arith_encode(stb_arith
*a
, unsigned int totalfreq
, unsigned int freq
, unsigned int cumfreq
)
11133 unsigned int range
= a
->range_high
- a
->range_low
;
11134 unsigned int old
= a
->range_low
;
11135 range
/= totalfreq
;
11136 a
->range_low
+= range
* cumfreq
;
11137 a
->range_high
= a
->range_low
+ range
*freq
;
11138 if (a
->range_low
< old
)
11139 stb__arith_carry(a
);
11140 while (a
->range_high
- a
->range_low
< 0x1000000)
11141 stb__renorm_encoder(a
);
11144 void stb_arith_encode_log2(stb_arith
*a
, unsigned int totalfreq2
, unsigned int freq
, unsigned int cumfreq
)
11146 unsigned int range
= a
->range_high
- a
->range_low
;
11147 unsigned int old
= a
->range_low
;
11148 range
>>= totalfreq2
;
11149 a
->range_low
+= range
* cumfreq
;
11150 a
->range_high
= a
->range_low
+ range
*freq
;
11151 if (a
->range_low
< old
)
11152 stb__arith_carry(a
);
11153 while (a
->range_high
- a
->range_low
< 0x1000000)
11154 stb__renorm_encoder(a
);
11157 unsigned int stb_arith_decode_value(stb_arith
*a
, unsigned int totalfreq
)
11159 unsigned int freqsize
= a
->range
/ totalfreq
;
11160 unsigned int z
= a
->code
/ freqsize
;
11161 return z
>= totalfreq
? totalfreq
-1 : z
;
11164 void stb_arith_decode_advance(stb_arith
*a
, unsigned int totalfreq
, unsigned int freq
, unsigned int cumfreq
)
11166 unsigned int freqsize
= a
->range
/ totalfreq
; // @OPTIMIZE, share with above divide somehow?
11167 a
->code
-= freqsize
* cumfreq
;
11168 a
->range
= freqsize
* freq
;
11169 while (a
->range
< 0x1000000)
11170 stb__renorm_decoder(a
);
11173 unsigned int stb_arith_decode_value_log2(stb_arith
*a
, unsigned int totalfreq2
)
11175 unsigned int freqsize
= a
->range
>> totalfreq2
;
11176 unsigned int z
= a
->code
/ freqsize
;
11177 return z
>= (1U<<totalfreq2
) ? (1U<<totalfreq2
)-1 : z
;
11180 void stb_arith_decode_advance_log2(stb_arith
*a
, unsigned int totalfreq2
, unsigned int freq
, unsigned int cumfreq
)
11182 unsigned int freqsize
= a
->range
>> totalfreq2
;
11183 a
->code
-= freqsize
* cumfreq
;
11184 a
->range
= freqsize
* freq
;
11185 while (a
->range
< 0x1000000)
11186 stb__renorm_decoder(a
);
11189 stbfile
*stb_arith_encode_close(stb_arith
*a
)
11191 // put exactly as many bytes as we'll read, so we can turn on/off arithmetic coding in a stream
11192 stb__arith_putbyte(a
, a
->range_low
>> 24);
11193 stb__arith_putbyte(a
, a
->range_low
>> 16);
11194 stb__arith_putbyte(a
, a
->range_low
>> 8);
11195 stb__arith_putbyte(a
, a
->range_low
>> 0);
11196 stb__arith_flush(a
);
11200 stbfile
*stb_arith_decode_close(stb_arith
*a
)
11205 // this is a simple power-of-two based model -- using
11206 // power of two means we need one divide per decode,
11208 #define POW2_LIMIT 12
11209 stb_arith_symstate
*stb_arith_state_create(int num_sym
)
11211 stb_arith_symstate
*s
= (stb_arith_symstate
*) malloc(sizeof(*s
) + (num_sym
-1) * sizeof(s
->data
[0]));
11213 int i
, cf
, cf_next
, next
;
11214 int start_freq
, extra
;
11215 s
->num_sym
= num_sym
;
11217 while (s
->pow2
< 15 && (1 << s
->pow2
) < 3*num_sym
) {
11220 start_freq
= (1 << s
->pow2
) / num_sym
;
11221 assert(start_freq
>= 1);
11222 extra
= (1 << s
->pow2
) % num_sym
;
11223 // now set up the initial stats
11225 if (s
->pow2
< POW2_LIMIT
)
11231 for (i
=0; i
< extra
; ++i
) {
11232 s
->data
[i
].cumfreq
= cf
;
11233 s
->data
[i
].samples
= next
;
11234 cf
+= start_freq
+1;
11237 for (; i
< num_sym
; ++i
) {
11238 s
->data
[i
].cumfreq
= cf
;
11239 s
->data
[i
].samples
= next
;
11243 assert(cf
== (1 << s
->pow2
));
11244 // now, how long should we go until we have 2 << s->pow2 samples?
11245 s
->countdown
= (2 << s
->pow2
) - cf
- cf_next
;
11250 static void stb_arith_state_rescale(stb_arith_symstate
*s
)
11252 if (s
->pow2
< POW2_LIMIT
) {
11253 int pcf
, cf
, cf_next
, next
, i
;
11255 if (s
->pow2
< POW2_LIMIT
)
11261 for (i
=0; i
< s
->num_sym
; ++i
) {
11262 int sample
= s
->data
[i
].cumfreq
- pcf
+ s
->data
[i
].samples
;
11263 s
->data
[i
].cumfreq
= cf
;
11265 s
->data
[i
].samples
= next
;
11268 assert(cf
== (1 << s
->pow2
));
11269 s
->countdown
= (2 << s
->pow2
) - cf
- cf_next
;
11271 int pcf
, cf
, cf_next
, i
;
11274 for (i
=0; i
< s
->num_sym
; ++i
) {
11275 int sample
= (s
->data
[i
].cumfreq
- pcf
+ s
->data
[i
].samples
) >> 1;
11276 s
->data
[i
].cumfreq
= cf
;
11278 s
->data
[i
].samples
= 1;
11281 assert(cf
== (1 << s
->pow2
)); // this isn't necessarily true, due to rounding down!
11282 s
->countdown
= (2 << s
->pow2
) - cf
- cf_next
;
11286 void stb_arith_encode_byte(stb_arith
*a
, int byte
)
11290 int stb_arith_decode_byte(stb_arith
*a
)
11296 //////////////////////////////////////////////////////////////////////////////
11303 #error "threads not implemented except for Windows"
11307 // call this function to free any global variables for memory testing
11308 STB_EXTERN
void stb_thread_cleanup(void);
11310 typedef void * (*stb_thread_func
)(void *);
11312 // do not rely on these types, this is an implementation detail.
11313 // compare against STB_THREAD_NULL and ST_SEMAPHORE_NULL
11314 typedef void *stb_thread
;
11315 typedef void *stb_semaphore
;
11316 typedef void *stb_mutex
;
11317 typedef struct stb__sync
*stb_sync
;
11319 #define STB_SEMAPHORE_NULL NULL
11320 #define STB_THREAD_NULL NULL
11321 #define STB_MUTEX_NULL NULL
11322 #define STB_SYNC_NULL NULL
11324 // get the number of processors (limited to those in the affinity mask for this process).
11325 STB_EXTERN
int stb_processor_count(void);
11326 // force to run on a single core -- needed for RDTSC to work, e.g. for iprof
11327 STB_EXTERN
void stb_force_uniprocessor(void);
11329 // stb_work functions: queue up work to be done by some worker threads
11331 // set number of threads to serve the queue; you can change this on the fly,
11332 // but if you decrease it, it won't decrease until things currently on the
11333 // queue are finished
11334 STB_EXTERN
void stb_work_numthreads(int n
);
11335 // set maximum number of units in the queue; you can only set this BEFORE running any work functions
11336 STB_EXTERN
int stb_work_maxunits(int n
);
11337 // enqueue some work to be done (can do this from any thread, or even from a piece of work);
11338 // return value of f is stored in *return_code if non-NULL
11339 STB_EXTERN
int stb_work(stb_thread_func f
, void *d
, volatile void **return_code
);
11340 // as above, but stb_sync_reach is called on 'rel' after work is complete
11341 STB_EXTERN
int stb_work_reach(stb_thread_func f
, void *d
, volatile void **return_code
, stb_sync rel
);
11344 // necessary to call this when using volatile to order writes/reads
11345 STB_EXTERN
void stb_barrier(void);
11347 // support for independent queues with their own threads
11349 typedef struct stb__workqueue stb_workqueue
;
11351 STB_EXTERN stb_workqueue
*stb_workq_new(int numthreads
, int max_units
);
11352 STB_EXTERN stb_workqueue
*stb_workq_new_flags(int numthreads
, int max_units
, int no_add_mutex
, int no_remove_mutex
);
11353 STB_EXTERN
void stb_workq_delete(stb_workqueue
*q
);
11354 STB_EXTERN
void stb_workq_numthreads(stb_workqueue
*q
, int n
);
11355 STB_EXTERN
int stb_workq(stb_workqueue
*q
, stb_thread_func f
, void *d
, volatile void **return_code
);
11356 STB_EXTERN
int stb_workq_reach(stb_workqueue
*q
, stb_thread_func f
, void *d
, volatile void **return_code
, stb_sync rel
);
11357 STB_EXTERN
int stb_workq_length(stb_workqueue
*q
);
11359 STB_EXTERN stb_thread
stb_create_thread (stb_thread_func f
, void *d
);
11360 STB_EXTERN stb_thread
stb_create_thread2(stb_thread_func f
, void *d
, volatile void **return_code
, stb_semaphore rel
);
11361 STB_EXTERN
void stb_destroy_thread(stb_thread t
);
11363 STB_EXTERN stb_semaphore
stb_sem_new(int max_val
);
11364 STB_EXTERN stb_semaphore
stb_sem_new_extra(int max_val
, int start_val
);
11365 STB_EXTERN
void stb_sem_delete (stb_semaphore s
);
11366 STB_EXTERN
void stb_sem_waitfor(stb_semaphore s
);
11367 STB_EXTERN
void stb_sem_release(stb_semaphore s
);
11369 STB_EXTERN stb_mutex
stb_mutex_new(void);
11370 STB_EXTERN
void stb_mutex_delete(stb_mutex m
);
11371 STB_EXTERN
void stb_mutex_begin(stb_mutex m
);
11372 STB_EXTERN
void stb_mutex_end(stb_mutex m
);
11374 STB_EXTERN stb_sync
stb_sync_new(void);
11375 STB_EXTERN
void stb_sync_delete(stb_sync s
);
11376 STB_EXTERN
int stb_sync_set_target(stb_sync s
, int count
);
11377 STB_EXTERN
void stb_sync_reach_and_wait(stb_sync s
); // wait for 'target' reachers
11378 STB_EXTERN
int stb_sync_reach(stb_sync s
);
11380 typedef struct stb__threadqueue stb_threadqueue
;
11381 #define STB_THREADQ_DYNAMIC 0
11382 STB_EXTERN stb_threadqueue
*stb_threadq_new(int item_size
, int num_items
, int many_add
, int many_remove
);
11383 STB_EXTERN
void stb_threadq_delete(stb_threadqueue
*tq
);
11384 STB_EXTERN
int stb_threadq_get(stb_threadqueue
*tq
, void *output
);
11385 STB_EXTERN
void stb_threadq_get_block(stb_threadqueue
*tq
, void *output
);
11386 STB_EXTERN
int stb_threadq_add(stb_threadqueue
*tq
, void *input
);
11387 // can return FALSE if STB_THREADQ_DYNAMIC and attempt to grow fails
11388 STB_EXTERN
int stb_threadq_add_block(stb_threadqueue
*tq
, void *input
);
11397 volatile void **return_val
;
11401 // this is initialized along all possible paths to create threads, therefore
11402 // it's always initialized before any other threads are create, therefore
11403 // it's free of races AS LONG AS you only create threads through stb_*
11404 static stb_mutex stb__threadmutex
, stb__workmutex
;
11406 static void stb__threadmutex_init(void)
11408 if (stb__threadmutex
== STB_SEMAPHORE_NULL
) {
11409 stb__threadmutex
= stb_mutex_new();
11410 stb__workmutex
= stb_mutex_new();
11414 #ifdef STB_THREAD_TEST
11415 volatile float stb__t1
=1, stb__t2
;
11417 static void stb__wait(int n
)
11421 for (i
=0; i
< n
; ++i
)
11422 z
+= 1 / (stb__t1
+i
);
11426 #define stb__wait(x)
11431 // avoid including windows.h -- note that our definitions aren't
11432 // exactly the same (we don't define the security descriptor struct)
11433 // so if you want to include windows.h, make sure you do it first.
11434 #include <process.h>
11436 #ifndef _WINDOWS_ // check windows.h guard
11437 #define STB__IMPORT STB_EXTERN __declspec(dllimport)
11438 #define STB__DW unsigned long
11440 STB__IMPORT
int __stdcall
TerminateThread(void *, STB__DW
);
11441 STB__IMPORT
void * __stdcall
CreateSemaphoreA(void *sec
, long,long,char*);
11442 STB__IMPORT
int __stdcall
CloseHandle(void *);
11443 STB__IMPORT STB__DW __stdcall
WaitForSingleObject(void *, STB__DW
);
11444 STB__IMPORT
int __stdcall
ReleaseSemaphore(void *, long, long *);
11445 STB__IMPORT
void __stdcall
Sleep(STB__DW
);
11448 // necessary to call this when using volatile to order writes/reads
11449 void stb_barrier(void)
11451 #ifdef MemoryBarrier
11455 __asm xchg temp
,eax
;
11459 static void stb__thread_run(void *t
)
11462 stb__thread info
= * (stb__thread
*) t
;
11464 res
= info
.f(info
.d
);
11465 if (info
.return_val
)
11466 *info
.return_val
= res
;
11467 if (info
.sem
!= STB_SEMAPHORE_NULL
)
11468 stb_sem_release(info
.sem
);
11471 static stb_thread
stb_create_thread_raw(stb_thread_func f
, void *d
, volatile void **return_code
, stb_semaphore rel
)
11474 #if defined(STB_FASTMALLOC) && !defined(STB_FASTMALLOC_ITS_OKAY_I_ONLY_MALLOC_IN_ONE_THREAD)
11475 stb_fatal("Error! Cannot use STB_FASTMALLOC with threads.\n");
11476 return STB_THREAD_NULL
;
11479 stb__thread
*data
= (stb__thread
*) malloc(sizeof(*data
));
11480 if (!data
) return NULL
;
11481 stb__threadmutex_init();
11484 data
->return_val
= return_code
;
11486 id
= _beginthread(stb__thread_run
, 0, data
);
11487 if (id
== -1) return NULL
;
11488 return (void *) id
;
11491 #ifdef STB_NO_STB_STRINGS
11492 stb_fatal("Invalid compilation");
11494 stb_fatal("Must compile mult-threaded to use stb_thread/stb_work.");
11500 // trivial win32 wrappers
11501 void stb_destroy_thread(stb_thread t
) { TerminateThread(t
,0); }
11502 stb_semaphore
stb_sem_new(int maxv
) {return CreateSemaphoreA(NULL
,0,maxv
,NULL
); }
11503 stb_semaphore
stb_sem_new_extra(int maxv
,int start
){return CreateSemaphoreA(NULL
,start
,maxv
,NULL
); }
11504 void stb_sem_delete(stb_semaphore s
) { if (s
!= NULL
) CloseHandle(s
); }
11505 void stb_sem_waitfor(stb_semaphore s
) { WaitForSingleObject(s
, 0xffffffff); } // INFINITE
11506 void stb_sem_release(stb_semaphore s
) { ReleaseSemaphore(s
,1,NULL
); }
11507 static void stb__thread_sleep(int ms
) { Sleep(ms
); }
11510 STB__IMPORT
int __stdcall
GetProcessAffinityMask(void *, STB__DW
*, STB__DW
*);
11511 STB__IMPORT
void * __stdcall
GetCurrentProcess(void);
11512 STB__IMPORT
int __stdcall
SetProcessAffinityMask(void *, STB__DW
);
11515 int stb_processor_count(void)
11517 unsigned long proc
,sys
;
11518 GetProcessAffinityMask(GetCurrentProcess(), &proc
, &sys
);
11519 return stb_bitcount(proc
);
11522 void stb_force_uniprocessor(void)
11524 unsigned long proc
,sys
;
11525 GetProcessAffinityMask(GetCurrentProcess(), &proc
, &sys
);
11526 if (stb_bitcount(proc
) > 1) {
11528 for (z
=0; z
< 32; ++z
)
11529 if (proc
& (1 << z
))
11533 SetProcessAffinityMask(GetCurrentProcess(), proc
);
11539 #define STB_MUTEX_NATIVE
11540 void *stb_mutex_new(void)
11542 CRITICAL_SECTION
*p
= (CRITICAL_SECTION
*) malloc(sizeof(*p
));
11544 #if _WIN32_WINNT >= 0x0500
11545 InitializeCriticalSectionAndSpinCount(p
, 500);
11547 InitializeCriticalSection(p
);
11552 void stb_mutex_delete(void *p
)
11555 DeleteCriticalSection((CRITICAL_SECTION
*) p
);
11560 void stb_mutex_begin(void *p
)
11564 EnterCriticalSection((CRITICAL_SECTION
*) p
);
11567 void stb_mutex_end(void *p
)
11570 LeaveCriticalSection((CRITICAL_SECTION
*) p
);
11573 #endif // _WINDOWS_
11576 // for future reference,
11577 // InterlockedCompareExchange for x86:
11578 int cas64_mp(void * dest
, void * xcmp
, void * xxchg
) {
11581 mov esi
, [xxchg
] ; exchange
11585 mov esi
, [xcmp
] ; comparand
11589 mov edi
, [dest
] ; destination
11590 lock cmpxchg8b
[edi
]
11593 mov
[esi
+ 0], eax
;
11594 mov
[esi
+ 4], edx
;
11601 inline unsigned __int64
_InterlockedCompareExchange64(volatile unsigned __int64
*dest
11602 ,unsigned __int64 exchange
11603 ,unsigned __int64 comperand
)
11605 //value returned in eax::edx
11615 lock CMPXCHG8B
[esi
];
11621 stb_thread
stb_create_thread2(stb_thread_func f
, void *d
, volatile void **return_code
, stb_semaphore rel
)
11623 return stb_create_thread_raw(f
,d
,return_code
,rel
);
11626 stb_thread
stb_create_thread(stb_thread_func f
, void *d
)
11628 return stb_create_thread2(f
,d
,NULL
,STB_SEMAPHORE_NULL
);
11631 // mutex implemented by wrapping semaphore
11632 #ifndef STB_MUTEX_NATIVE
11633 stb_mutex
stb_mutex_new(void) { return stb_sem_new_extra(1,1); }
11634 void stb_mutex_delete(stb_mutex m
) { stb_sem_delete (m
); }
11635 void stb_mutex_begin(stb_mutex m
) { stb__wait(500); if (m
) stb_sem_waitfor(m
); }
11636 void stb_mutex_end(stb_mutex m
) { if (m
) stb_sem_release(m
); stb__wait(500); }
11639 // thread merge operation
11642 int target
; // target number of threads to hit it
11643 int sofar
; // total threads that hit it
11644 int waiting
; // total threads waiting
11646 stb_mutex start
; // mutex to prevent starting again before finishing previous
11647 stb_mutex mutex
; // mutex while tweaking state
11648 stb_semaphore release
; // semaphore wake up waiting threads
11649 // we have to wake them up one at a time, rather than using a single release
11650 // call, because win32 semaphores don't let you dynamically change the max count!
11653 stb_sync
stb_sync_new(void)
11655 stb_sync s
= (stb_sync
) malloc(sizeof(*s
));
11658 s
->target
= s
->sofar
= s
->waiting
= 0;
11659 s
->mutex
= stb_mutex_new();
11660 s
->start
= stb_mutex_new();
11661 s
->release
= stb_sem_new(1);
11662 if (s
->mutex
== STB_MUTEX_NULL
|| s
->release
== STB_SEMAPHORE_NULL
|| s
->start
== STB_MUTEX_NULL
) {
11663 stb_mutex_delete(s
->mutex
);
11664 stb_mutex_delete(s
->mutex
);
11665 stb_sem_delete(s
->release
);
11672 void stb_sync_delete(stb_sync s
)
11675 // it's bad to delete while there are threads waiting!
11676 // shall we wait for them to reach, or just bail? just bail
11679 stb_mutex_delete(s
->mutex
);
11680 stb_mutex_delete(s
->release
);
11684 int stb_sync_set_target(stb_sync s
, int count
)
11686 // don't allow setting a target until the last one is fully released;
11687 // note that this can lead to inefficient pipelining, and maybe we'd
11688 // be better off ping-ponging between two internal syncs?
11689 // I tried seeing how often this happened using TryEnterCriticalSection
11690 // and could _never_ get it to happen in imv(stb), even with more threads
11691 // than processors. So who knows!
11692 stb_mutex_begin(s
->start
);
11694 // this mutex is pointless, since it's not valid for threads
11695 // to call reach() before anyone calls set_target() anyway
11696 stb_mutex_begin(s
->mutex
);
11698 assert(s
->target
== 0); // enforced by start mutex
11702 stb_mutex_end(s
->mutex
);
11706 void stb__sync_release(stb_sync s
)
11709 stb_sem_release(s
->release
);
11712 stb_mutex_end(s
->start
);
11716 int stb_sync_reach(stb_sync s
)
11719 stb_mutex_begin(s
->mutex
);
11720 assert(s
->sofar
< s
->target
);
11721 n
= ++s
->sofar
; // record this value to avoid possible race if we did 'return s->sofar';
11722 if (s
->sofar
== s
->target
)
11723 stb__sync_release(s
);
11724 stb_mutex_end(s
->mutex
);
11728 void stb_sync_reach_and_wait(stb_sync s
)
11730 stb_mutex_begin(s
->mutex
);
11731 assert(s
->sofar
< s
->target
);
11733 if (s
->sofar
== s
->target
) {
11734 stb__sync_release(s
);
11735 stb_mutex_end(s
->mutex
);
11737 ++s
->waiting
; // we're waiting, so one more waiter
11738 stb_mutex_end(s
->mutex
); // release the mutex to other threads
11740 stb_sem_waitfor(s
->release
); // wait for merge completion
11742 stb_mutex_begin(s
->mutex
); // on merge completion, grab the mutex
11743 --s
->waiting
; // we're done waiting
11744 stb__sync_release(s
); // restart the next waiter
11745 stb_mutex_end(s
->mutex
); // and now we're done
11746 // this ends the same as the first case, but it's a lot
11747 // clearer to understand without sharing the code
11751 struct stb__threadqueue
11753 stb_mutex add
, remove
;
11754 stb_semaphore nonempty
, nonfull
;
11755 int head_blockers
; // number of threads blocking--used to know whether to release(avail)
11757 int head
, tail
, array_size
, growable
;
11762 static int stb__tq_wrap(volatile stb_threadqueue
*z
, int p
)
11764 if (p
== z
->array_size
)
11765 return p
- z
->array_size
;
11770 int stb__threadq_get_raw(stb_threadqueue
*tq2
, void *output
, int block
)
11772 volatile stb_threadqueue
*tq
= (volatile stb_threadqueue
*) tq2
;
11773 if (tq
->head
== tq
->tail
&& !block
) return 0;
11775 stb_mutex_begin(tq
->remove
);
11777 while (tq
->head
== tq
->tail
) {
11779 stb_mutex_end(tq
->remove
);
11782 ++tq
->head_blockers
;
11783 stb_mutex_end(tq
->remove
);
11785 stb_sem_waitfor(tq
->nonempty
);
11787 stb_mutex_begin(tq
->remove
);
11788 --tq
->head_blockers
;
11791 memcpy(output
, tq
->data
+ tq
->head
*tq
->item_size
, tq
->item_size
);
11793 tq
->head
= stb__tq_wrap(tq
, tq
->head
+1);
11795 stb_sem_release(tq
->nonfull
);
11796 if (tq
->head_blockers
) // can't check if actually non-empty due to race?
11797 stb_sem_release(tq
->nonempty
); // if there are other blockers, wake one
11799 stb_mutex_end(tq
->remove
);
11803 int stb__threadq_grow(volatile stb_threadqueue
*tq
)
11807 assert(tq
->remove
!= STB_MUTEX_NULL
); // must have this to allow growth!
11808 stb_mutex_begin(tq
->remove
);
11810 n
= tq
->array_size
* 2;
11811 p
= (char *) realloc(tq
->data
, n
* tq
->item_size
);
11813 stb_mutex_end(tq
->remove
);
11814 stb_mutex_end(tq
->add
);
11817 if (tq
->tail
< tq
->head
) {
11818 memcpy(p
+ tq
->array_size
* tq
->item_size
, p
, tq
->tail
* tq
->item_size
);
11819 tq
->tail
+= tq
->array_size
;
11822 tq
->array_size
= n
;
11824 stb_mutex_end(tq
->remove
);
11828 int stb__threadq_add_raw(stb_threadqueue
*tq2
, void *input
, int block
)
11831 volatile stb_threadqueue
*tq
= (volatile stb_threadqueue
*) tq2
;
11832 stb_mutex_begin(tq
->add
);
11835 tail
= stb__tq_wrap(tq
, pos
+1);
11836 if (tail
!= tq
->head
) break;
11839 if (tq
->growable
) {
11840 if (!stb__threadq_grow(tq
)) {
11841 stb_mutex_end(tq
->add
);
11842 return STB_FALSE
; // out of memory
11844 } else if (!block
) {
11845 stb_mutex_end(tq
->add
);
11848 ++tq
->tail_blockers
;
11849 stb_mutex_end(tq
->add
);
11851 stb_sem_waitfor(tq
->nonfull
);
11853 stb_mutex_begin(tq
->add
);
11854 --tq
->tail_blockers
;
11857 memcpy(tq
->data
+ tq
->item_size
* pos
, input
, tq
->item_size
);
11860 stb_sem_release(tq
->nonempty
);
11861 if (tq
->tail_blockers
) // can't check if actually non-full due to race?
11862 stb_sem_release(tq
->nonfull
);
11863 stb_mutex_end(tq
->add
);
11867 int stb_threadq_length(stb_threadqueue
*tq2
)
11870 volatile stb_threadqueue
*tq
= (volatile stb_threadqueue
*) tq2
;
11871 stb_mutex_begin(tq
->add
);
11874 n
= tq
->array_size
;
11875 stb_mutex_end(tq
->add
);
11880 int stb_threadq_get(stb_threadqueue
*tq
, void *output
)
11882 return stb__threadq_get_raw(tq
, output
, STB_FALSE
);
11885 void stb_threadq_get_block(stb_threadqueue
*tq
, void *output
)
11887 stb__threadq_get_raw(tq
, output
, STB_TRUE
);
11890 int stb_threadq_add(stb_threadqueue
*tq
, void *input
)
11892 return stb__threadq_add_raw(tq
, input
, STB_FALSE
);
11895 int stb_threadq_add_block(stb_threadqueue
*tq
, void *input
)
11897 return stb__threadq_add_raw(tq
, input
, STB_TRUE
);
11900 void stb_threadq_delete(stb_threadqueue
*tq
)
11904 stb_mutex_delete(tq
->add
);
11905 stb_mutex_delete(tq
->remove
);
11906 stb_sem_delete(tq
->nonempty
);
11907 stb_sem_delete(tq
->nonfull
);
11912 #define STB_THREADQUEUE_DYNAMIC 0
11913 stb_threadqueue
*stb_threadq_new(int item_size
, int num_items
, int many_add
, int many_remove
)
11916 stb_threadqueue
*tq
= (stb_threadqueue
*) malloc(sizeof(*tq
));
11917 if (tq
== NULL
) return NULL
;
11919 if (num_items
== STB_THREADQUEUE_DYNAMIC
) {
11920 tq
->growable
= STB_TRUE
;
11923 tq
->growable
= STB_FALSE
;
11925 tq
->item_size
= item_size
;
11926 tq
->array_size
= num_items
+1;
11928 tq
->add
= tq
->remove
= STB_MUTEX_NULL
;
11929 tq
->nonempty
= tq
->nonfull
= STB_SEMAPHORE_NULL
;
11932 { tq
->add
= stb_mutex_new(); if (tq
->add
== STB_MUTEX_NULL
) goto error
; }
11933 if (many_remove
|| tq
->growable
)
11934 { tq
->remove
= stb_mutex_new(); if (tq
->remove
== STB_MUTEX_NULL
) goto error
; }
11935 tq
->nonempty
= stb_sem_new(1); if (tq
->nonempty
== STB_SEMAPHORE_NULL
) goto error
;
11936 tq
->nonfull
= stb_sem_new(1); if (tq
->nonfull
== STB_SEMAPHORE_NULL
) goto error
;
11937 tq
->data
= (char *) malloc(tq
->item_size
* tq
->array_size
);
11938 if (tq
->data
== NULL
) goto error
;
11940 tq
->head
= tq
->tail
= 0;
11941 tq
->head_blockers
= tq
->tail_blockers
= 0;
11946 stb_threadq_delete(tq
);
11954 volatile void **retval
;
11958 //static volatile stb__workinfo *stb__work;
11960 struct stb__workqueue
11963 stb_threadqueue
*tq
;
11966 static stb_workqueue
*stb__work_global
;
11968 static void *stb__thread_workloop(void *p
)
11970 volatile stb_workqueue
*q
= (volatile stb_workqueue
*) p
;
11974 stb_threadq_get_block(q
->tq
, &w
);
11975 if (w
.f
== NULL
) // null work is a signal to end the thread
11978 if (w
.retval
) { stb_barrier(); *w
.retval
= z
; }
11979 if (w
.sync
!= STB_SYNC_NULL
) stb_sync_reach(w
.sync
);
11983 stb_workqueue
*stb_workq_new(int num_threads
, int max_units
)
11985 return stb_workq_new_flags(num_threads
, max_units
, 0,0);
11988 stb_workqueue
*stb_workq_new_flags(int numthreads
, int max_units
, int no_add_mutex
, int no_remove_mutex
)
11990 stb_workqueue
*q
= (stb_workqueue
*) malloc(sizeof(*q
));
11991 if (q
== NULL
) return NULL
;
11992 q
->tq
= stb_threadq_new(sizeof(stb__workinfo
), max_units
, !no_add_mutex
, !no_remove_mutex
);
11993 if (q
->tq
== NULL
) { free(q
); return NULL
; }
11995 stb_workq_numthreads(q
, numthreads
);
11999 void stb_workq_delete(stb_workqueue
*q
)
12001 while (stb_workq_length(q
) != 0)
12002 stb__thread_sleep(1);
12003 stb_threadq_delete(q
->tq
);
12007 static int stb__work_maxitems
= STB_THREADQUEUE_DYNAMIC
;
12009 static void stb_work_init(int num_threads
)
12011 if (stb__work_global
== NULL
) {
12012 stb__threadmutex_init();
12013 stb_mutex_begin(stb__workmutex
);
12015 if (*(stb_workqueue
* volatile *) &stb__work_global
== NULL
)
12016 stb__work_global
= stb_workq_new(num_threads
, stb__work_maxitems
);
12017 stb_mutex_end(stb__workmutex
);
12021 static int stb__work_raw(stb_workqueue
*q
, stb_thread_func f
, void *d
, volatile void **return_code
, stb_sync rel
)
12026 q
= stb__work_global
;
12030 w
.retval
= return_code
;
12032 return stb_threadq_add(q
->tq
, &w
);
12035 int stb_workq_length(stb_workqueue
*q
)
12037 return stb_threadq_length(q
->tq
);
12040 int stb_workq(stb_workqueue
*q
, stb_thread_func f
, void *d
, volatile void **return_code
)
12042 if (f
== NULL
) return 0;
12043 return stb_workq_reach(q
, f
, d
, return_code
, NULL
);
12046 int stb_workq_reach(stb_workqueue
*q
, stb_thread_func f
, void *d
, volatile void **return_code
, stb_sync rel
)
12048 if (f
== NULL
) return 0;
12049 return stb__work_raw(q
, f
, d
, return_code
, rel
);
12052 static void stb__workq_numthreads(stb_workqueue
*q
, int n
)
12054 while (q
->numthreads
< n
) {
12055 stb_create_thread(stb__thread_workloop
, q
);
12058 while (q
->numthreads
> n
) {
12059 stb__work_raw(q
, NULL
, NULL
, NULL
, NULL
);
12064 void stb_workq_numthreads(stb_workqueue
*q
, int n
)
12066 stb_mutex_begin(stb__threadmutex
);
12067 stb__workq_numthreads(q
,n
);
12068 stb_mutex_end(stb__threadmutex
);
12071 int stb_work_maxunits(int n
)
12073 if (stb__work_global
== NULL
) {
12074 stb__work_maxitems
= n
;
12077 return stb__work_maxitems
;
12080 int stb_work(stb_thread_func f
, void *d
, volatile void **return_code
)
12082 return stb_workq(stb__work_global
, f
,d
,return_code
);
12085 int stb_work_reach(stb_thread_func f
, void *d
, volatile void **return_code
, stb_sync rel
)
12087 return stb_workq_reach(stb__work_global
, f
,d
,return_code
,rel
);
12090 void stb_work_numthreads(int n
)
12092 if (stb__work_global
== NULL
)
12095 stb_workq_numthreads(stb__work_global
, n
);
12097 #endif // STB_DEFINE
12100 //////////////////////////////////////////////////////////////////////////////
12102 // Background disk I/O
12106 #define STB_BGIO_READ_ALL (-1)
12107 STB_EXTERN
int stb_bgio_read (char *filename
, int offset
, int len
, stb_uchar
**result
, int *olen
);
12108 STB_EXTERN
int stb_bgio_readf (FILE *f
, int offset
, int len
, stb_uchar
**result
, int *olen
);
12109 STB_EXTERN
int stb_bgio_read_to (char *filename
, int offset
, int len
, stb_uchar
*buffer
, int *olen
);
12110 STB_EXTERN
int stb_bgio_readf_to(FILE *f
, int offset
, int len
, stb_uchar
*buffer
, int *olen
);
12118 stb_int64 filesize
;
12121 STB_EXTERN
int stb_bgio_stat (char *filename
, stb_bgstat
*result
);
12125 static stb_workqueue
*stb__diskio
;
12126 static stb_mutex stb__diskio_mutex
;
12128 void stb_thread_cleanup(void)
12130 if (stb__work_global
) stb_workq_delete(stb__work_global
); stb__work_global
= NULL
;
12131 if (stb__threadmutex
) stb_mutex_delete(stb__threadmutex
); stb__threadmutex
= NULL
;
12132 if (stb__workmutex
) stb_mutex_delete(stb__workmutex
); stb__workmutex
= NULL
;
12133 if (stb__diskio
) stb_workq_delete(stb__diskio
); stb__diskio
= NULL
;
12134 if (stb__diskio_mutex
)stb_mutex_delete(stb__diskio_mutex
);stb__diskio_mutex
= NULL
;
12145 stb_bgstat
*stat_out
;
12147 stb_uchar
**result
;
12150 } stb__disk_command
;
12152 #define STB__MAX_DISK_COMMAND 100
12153 static stb__disk_command stb__dc_queue
[STB__MAX_DISK_COMMAND
];
12154 static int stb__dc_offset
;
12156 void stb__io_init(void)
12158 if (!stb__diskio
) {
12159 stb__threadmutex_init();
12160 stb_mutex_begin(stb__threadmutex
);
12162 if (*(stb_thread
* volatile *) &stb__diskio
== NULL
) {
12163 stb__diskio_mutex
= stb_mutex_new();
12164 // use many threads so OS can try to schedule seeks
12165 stb__diskio
= stb_workq_new_flags(16,STB__MAX_DISK_COMMAND
,STB_FALSE
,STB_FALSE
);
12167 stb_mutex_end(stb__threadmutex
);
12171 static void * stb__io_error(stb__disk_command
*dc
)
12173 if (dc
->len_output
) *dc
->len_output
= 0;
12174 if (dc
->result
) *dc
->result
= NULL
;
12175 if (dc
->flag
) *dc
->flag
= -1;
12179 static void * stb__io_task(void *p
)
12181 stb__disk_command
*dc
= (stb__disk_command
*) p
;
12186 if (dc
->stat_out
) {
12188 if (!_stati64(dc
->filename
, &s
)) {
12189 dc
->stat_out
->filesize
= s
.st_size
;
12190 dc
->stat_out
->filetime
= s
.st_mtime
;
12191 dc
->stat_out
->is_dir
= s
.st_mode
& _S_IFDIR
;
12192 dc
->stat_out
->is_valid
= (s
.st_mode
& _S_IFREG
) || dc
->stat_out
->is_dir
;
12194 dc
->stat_out
->is_valid
= 0;
12196 dc
->stat_out
->have_data
= 1;
12197 free(dc
->filename
);
12202 f
= _fdopen(_dup(_fileno(dc
->f
)), "rb");
12204 f
= fdopen(dup(fileno(dc
->f
)), "rb");
12207 return stb__io_error(dc
);
12209 f
= fopen(dc
->filename
, "rb");
12210 free(dc
->filename
);
12212 return stb__io_error(dc
);
12217 fseek(f
, 0, SEEK_END
);
12218 len
= ftell(f
) - dc
->offset
;
12221 if (fseek(f
, dc
->offset
, SEEK_SET
)) {
12223 return stb__io_error(dc
);
12229 buf
= (stb_uchar
*) malloc(len
);
12232 return stb__io_error(dc
);
12236 len
= fread(buf
, 1, len
, f
);
12238 if (dc
->len_output
) *dc
->len_output
= len
;
12239 if (dc
->result
) *dc
->result
= buf
;
12240 if (dc
->flag
) *dc
->flag
= 1;
12245 int stb__io_add(char *fname
, FILE *f
, int off
, int len
, stb_uchar
*out
, stb_uchar
**result
, int *olen
, int *flag
, stb_bgstat
*stat
)
12249 // do memory allocation outside of mutex
12250 if (fname
) fname
= strdup(fname
);
12251 stb_mutex_begin(stb__diskio_mutex
);
12253 stb__disk_command
*dc
= &stb__dc_queue
[stb__dc_offset
];
12254 dc
->filename
= fname
;
12259 dc
->result
= result
;
12260 dc
->len_output
= olen
;
12262 dc
->stat_out
= stat
;
12263 res
= stb_workq(stb__diskio
, stb__io_task
, dc
, NULL
);
12265 stb__dc_offset
= (stb__dc_offset
+ 1 == STB__MAX_DISK_COMMAND
? 0 : stb__dc_offset
+1);
12267 stb_mutex_end(stb__diskio_mutex
);
12271 int stb_bgio_read(char *filename
, int offset
, int len
, stb_uchar
**result
, int *olen
)
12273 return stb__io_add(filename
,NULL
,offset
,len
,NULL
,result
,olen
,NULL
,NULL
);
12276 int stb_bgio_readf(FILE *f
, int offset
, int len
, stb_uchar
**result
, int *olen
)
12278 return stb__io_add(NULL
,f
,offset
,len
,NULL
,result
,olen
,NULL
,NULL
);
12281 int stb_bgio_read_to(char *filename
, int offset
, int len
, stb_uchar
*buffer
, int *olen
)
12283 return stb__io_add(filename
,NULL
,offset
,len
,buffer
,NULL
,olen
,NULL
,NULL
);
12286 int stb_bgio_readf_to(FILE *f
, int offset
, int len
, stb_uchar
*buffer
, int *olen
)
12288 return stb__io_add(NULL
,f
,offset
,len
,buffer
,NULL
,olen
,NULL
,NULL
);
12291 STB_EXTERN
int stb_bgio_stat (char *filename
, stb_bgstat
*result
)
12293 result
->have_data
= 0;
12294 return stb__io_add(filename
,NULL
,0,0,0,NULL
,0,NULL
, result
);
12301 //////////////////////////////////////////////////////////////////////////////
12303 // Fast malloc implementation
12305 // This is a clone of TCMalloc, but without the thread support.
12306 // 1. large objects are allocated directly, page-aligned
12307 // 2. small objects are allocated in homogeonous heaps, 0 overhead
12309 // We keep an allocation table for pages a la TCMalloc. This would
12310 // require 4MB for the entire address space, but we only allocate
12311 // the parts that are in use. The overhead from using homogenous heaps
12312 // everywhere is 3MB. (That is, if you allocate 1 object of each size,
12313 // you'll use 3MB.)
12315 #if defined(STB_DEFINE) && (defined(_WIN32) || defined(STB_FASTMALLOC))
12319 #ifndef STB__IMPORT
12320 #define STB__IMPORT STB_EXTERN __declspec(dllimport)
12321 #define STB__DW unsigned long
12323 STB__IMPORT
void * __stdcall
VirtualAlloc(void *p
, unsigned long size
, unsigned long type
, unsigned long protect
);
12324 STB__IMPORT
int __stdcall
VirtualFree(void *p
, unsigned long size
, unsigned long freetype
);
12326 #define stb__alloc_pages_raw(x) (stb_uint32) VirtualAlloc(NULL, (x), 0x3000, 0x04)
12327 #define stb__dealloc_pages_raw(p) VirtualFree((void *) p, 0, 0x8000)
12329 #error "Platform not currently supported"
12332 typedef struct stb__span
12335 struct stb__span
*next
, *prev
;
12337 unsigned short list
; // 1..256 free; 257..511 sizeclass; 0=large block
12338 short allocations
; // # outstanding allocations for sizeclass
12341 static stb__span
**stb__span_for_page
;
12342 static int stb__firstpage
, stb__lastpage
;
12343 static void stb__update_page_range(int first
, int last
)
12347 if (first
>= stb__firstpage
&& last
<= stb__lastpage
) return;
12348 if (stb__span_for_page
== NULL
) {
12350 l
= f
+stb_max(last
-f
, 16384);
12351 l
= stb_min(l
, 1<<20);
12352 } else if (last
> stb__lastpage
) {
12353 f
= stb__firstpage
;
12354 l
= f
+ (stb__lastpage
- f
) * 2;
12355 l
= stb_clamp(last
, l
,1<<20);
12358 f
= l
- (l
- stb__firstpage
) * 2;
12359 f
= stb_clamp(f
, 0,first
);
12361 sfp
= (stb__span
**) stb__alloc_pages_raw(sizeof(void *) * (l
-f
));
12362 for (i
=f
; i
< stb__firstpage
; ++i
) sfp
[i
- f
] = NULL
;
12363 for ( ; i
< stb__lastpage
; ++i
) sfp
[i
- f
] = stb__span_for_page
[i
- stb__firstpage
];
12364 for ( ; i
< l
; ++i
) sfp
[i
- f
] = NULL
;
12365 if (stb__span_for_page
) stb__dealloc_pages_raw(stb__span_for_page
);
12366 stb__firstpage
= f
;
12368 stb__span_for_page
= sfp
;
12371 static stb__span
*stb__span_free
=NULL
;
12372 static stb__span
*stb__span_first
, *stb__span_end
;
12373 static stb__span
*stb__span_alloc(void)
12375 stb__span
*s
= stb__span_free
;
12377 stb__span_free
= s
->next
;
12379 if (!stb__span_first
) {
12380 stb__span_first
= (stb__span
*) stb__alloc_pages_raw(65536);
12381 if (stb__span_first
== NULL
) return NULL
;
12382 stb__span_end
= stb__span_first
+ (65536 / sizeof(stb__span
));
12384 s
= stb__span_first
++;
12385 if (stb__span_first
== stb__span_end
) stb__span_first
= NULL
;
12390 static stb__span
*stb__spanlist
[512];
12392 static void stb__spanlist_unlink(stb__span
*s
)
12395 s
->prev
->next
= s
->next
;
12398 assert(stb__spanlist
[n
] == s
);
12399 stb__spanlist
[n
] = s
->next
;
12402 s
->next
->prev
= s
->prev
;
12403 s
->next
= s
->prev
= NULL
;
12407 static void stb__spanlist_add(int n
, stb__span
*s
)
12410 s
->next
= stb__spanlist
[n
];
12412 stb__spanlist
[n
] = s
;
12413 if (s
->next
) s
->next
->prev
= s
;
12416 #define stb__page_shift 12
12417 #define stb__page_size (1 << stb__page_shift)
12418 #define stb__page_number(x) ((x) >> stb__page_shift)
12419 #define stb__page_address(x) ((x) << stb__page_shift)
12421 static void stb__set_span_for_page(stb__span
*s
)
12424 for (i
=0; i
< s
->len
; ++i
)
12425 stb__span_for_page
[s
->start
+ i
- stb__firstpage
] = s
;
12428 static stb__span
*stb__coalesce(stb__span
*a
, stb__span
*b
)
12430 assert(a
->start
+ a
->len
== b
->start
);
12431 if (a
->list
) stb__spanlist_unlink(a
);
12432 if (b
->list
) stb__spanlist_unlink(b
);
12435 b
->next
= stb__span_free
;
12436 stb__span_free
= b
;
12437 stb__set_span_for_page(a
);
12441 static void stb__free_span(stb__span
*s
)
12443 stb__span
*n
= NULL
;
12444 if (s
->start
> stb__firstpage
) {
12445 n
= stb__span_for_page
[s
->start
-1 - stb__firstpage
];
12446 if (n
&& n
->allocations
== -2 && n
->start
+ n
->len
== s
->start
) s
= stb__coalesce(n
,s
);
12448 if (s
->start
+ s
->len
< stb__lastpage
) {
12449 n
= stb__span_for_page
[s
->start
+ s
->len
- stb__firstpage
];
12450 if (n
&& n
->allocations
== -2 && s
->start
+ s
->len
== n
->start
) s
= stb__coalesce(s
,n
);
12452 s
->allocations
= -2;
12453 stb__spanlist_add(s
->len
> 256 ? 256 : s
->len
, s
);
12456 static stb__span
*stb__alloc_pages(int num
)
12458 stb__span
*s
= stb__span_alloc();
12460 if (!s
) return NULL
;
12461 p
= stb__alloc_pages_raw(num
<< stb__page_shift
);
12462 if (p
== 0) { s
->next
= stb__span_free
; stb__span_free
= s
; return 0; }
12463 assert(stb__page_address(stb__page_number(p
)) == p
);
12464 p
= stb__page_number(p
);
12465 stb__update_page_range(p
, p
+num
);
12470 stb__set_span_for_page(s
);
12474 static stb__span
*stb__alloc_span(int pagecount
)
12477 stb__span
*p
= NULL
;
12478 for(i
=pagecount
; i
< 256; ++i
)
12479 if (stb__spanlist
[i
]) {
12480 p
= stb__spanlist
[i
];
12484 p
= stb__spanlist
[256];
12485 while (p
&& p
->len
< pagecount
)
12489 p
= stb__alloc_pages(pagecount
< 16 ? 16 : pagecount
);
12490 if (p
== NULL
) return 0;
12492 stb__spanlist_unlink(p
);
12494 if (p
->len
> pagecount
) {
12495 stb__span
*q
= stb__span_alloc();
12497 q
->start
= p
->start
+ pagecount
;
12498 q
->len
= p
->len
- pagecount
;
12499 p
->len
= pagecount
;
12500 for (i
=0; i
< q
->len
; ++i
)
12501 stb__span_for_page
[q
->start
+i
- stb__firstpage
] = q
;
12502 stb__spanlist_add(q
->len
> 256 ? 256 : q
->len
, q
);
12508 #define STB__MAX_SMALL_SIZE 32768
12509 #define STB__MAX_SIZE_CLASSES 256
12511 static unsigned char stb__class_base
[32];
12512 static unsigned char stb__class_shift
[32];
12513 static unsigned char stb__pages_for_class
[STB__MAX_SIZE_CLASSES
];
12514 static int stb__size_for_class
[STB__MAX_SIZE_CLASSES
];
12516 stb__span
*stb__get_nonempty_sizeclass(int c
)
12518 int s
= c
+ 256, i
, size
, tsize
; // remap to span-list index
12521 stb__span
*p
= stb__spanlist
[s
];
12523 if (p
->first_free
) return p
; // fast path: it's in the first one in list
12524 for (p
=p
->next
; p
; p
=p
->next
)
12525 if (p
->first_free
) {
12526 // move to front for future queries
12527 stb__spanlist_unlink(p
);
12528 stb__spanlist_add(s
, p
);
12532 // no non-empty ones, so allocate a new one
12533 p
= stb__alloc_span(stb__pages_for_class
[c
]);
12534 if (!p
) return NULL
;
12535 // create the free list up front
12536 size
= stb__size_for_class
[c
];
12537 tsize
= stb__pages_for_class
[c
] << stb__page_shift
;
12539 z
= (char *) stb__page_address(p
->start
);
12541 while (i
+ size
<= tsize
) {
12542 * (void **) z
= q
; q
= z
;
12547 p
->allocations
= 0;
12548 stb__spanlist_add(s
,p
);
12552 static int stb__sizeclass(size_t sz
)
12554 int z
= stb_log2_floor(sz
); // -1 below to group e.g. 13,14,15,16 correctly
12555 return stb__class_base
[z
] + ((sz
-1) >> stb__class_shift
[z
]);
12558 static void stb__init_sizeclass(void)
12560 int i
, size
, overhead
;
12561 int align_shift
= 2; // allow 4-byte and 12-byte blocks as well, vs. TCMalloc
12562 int next_class
= 1;
12565 for (i
= 0; i
< align_shift
; i
++) {
12566 stb__class_base
[i
] = next_class
;
12567 stb__class_shift
[i
] = align_shift
;
12570 for (size
= 1 << align_shift
; size
<= STB__MAX_SMALL_SIZE
; size
+= 1 << align_shift
) {
12571 i
= stb_log2_floor(size
);
12572 if (i
> last_log
) {
12573 if (size
== 16) ++align_shift
; // switch from 4-byte to 8-byte alignment
12574 else if (size
>= 128 && align_shift
< 8) ++align_shift
;
12575 stb__class_base
[i
] = next_class
- ((size
-1) >> align_shift
);
12576 stb__class_shift
[i
] = align_shift
;
12579 stb__size_for_class
[next_class
++] = size
;
12582 for (i
=1; i
<= STB__MAX_SMALL_SIZE
; ++i
)
12583 assert(i
<= stb__size_for_class
[stb__sizeclass(i
)]);
12586 for (i
= 1; i
< next_class
; i
++) {
12587 int s
= stb__size_for_class
[i
];
12588 size
= stb__page_size
;
12589 while (size
% s
> size
>> 3)
12590 size
+= stb__page_size
;
12591 stb__pages_for_class
[i
] = (unsigned char) (size
>> stb__page_shift
);
12594 assert(overhead
< (4 << 20)); // make sure it's under 4MB of overhead
12598 #define stb__smemset(a,b,c) memset((void *) a, b, c)
12599 #elif defined(STB_FASTMALLOC_INIT)
12600 #define stb__smemset(a,b,c) memset((void *) a, b, c)
12602 #define stb__smemset(a,b,c)
12604 void *stb_smalloc(size_t sz
)
12607 if (sz
== 0) return NULL
;
12608 if (stb__size_for_class
[1] == 0) stb__init_sizeclass();
12609 if (sz
> STB__MAX_SMALL_SIZE
) {
12610 s
= stb__alloc_span((sz
+ stb__page_size
- 1) >> stb__page_shift
);
12611 if (s
== NULL
) return NULL
;
12613 s
->next
= s
->prev
= NULL
;
12614 s
->allocations
= -32767;
12615 stb__smemset(stb__page_address(s
->start
), 0xcd, (sz
+3)&~3);
12616 return (void *) stb__page_address(s
->start
);
12619 int c
= stb__sizeclass(sz
);
12620 s
= stb__spanlist
[256+c
];
12621 if (!s
|| !s
->first_free
)
12622 s
= stb__get_nonempty_sizeclass(c
);
12623 if (s
== NULL
) return NULL
;
12625 s
->first_free
= * (void **) p
;
12627 stb__smemset(p
,0xcd, sz
);
12632 int stb_ssize(void *p
)
12635 if (p
== NULL
) return 0;
12636 s
= stb__span_for_page
[stb__page_number((stb_uint
) p
) - stb__firstpage
];
12637 if (s
->list
>= 256) {
12638 return stb__size_for_class
[s
->list
- 256];
12640 assert(s
->list
== 0);
12641 return s
->len
<< stb__page_shift
;
12645 void stb_sfree(void *p
)
12648 if (p
== NULL
) return;
12649 s
= stb__span_for_page
[stb__page_number((stb_uint
) p
) - stb__firstpage
];
12650 if (s
->list
>= 256) {
12651 stb__smemset(p
, 0xfe, stb__size_for_class
[s
->list
-256]);
12652 * (void **) p
= s
->first_free
;
12654 if (--s
->allocations
== 0) {
12655 stb__spanlist_unlink(s
);
12659 assert(s
->list
== 0);
12660 stb__smemset(p
, 0xfe, stb_ssize(p
));
12665 void *stb_srealloc(void *p
, size_t sz
)
12668 if (p
== NULL
) return stb_smalloc(sz
);
12669 if (sz
== 0) { stb_sfree(p
); return NULL
; }
12670 cur_size
= stb_ssize(p
);
12671 if (sz
> cur_size
|| sz
<= (cur_size
>> 1)) {
12673 if (sz
> cur_size
&& sz
< (cur_size
<< 1)) sz
= cur_size
<< 1;
12674 q
= stb_smalloc(sz
); if (q
== NULL
) return NULL
;
12675 memcpy(q
, p
, sz
< cur_size
? sz
: cur_size
);
12682 void *stb_scalloc(size_t n
, size_t sz
)
12685 if (n
== 0 || sz
== 0) return NULL
;
12686 if (stb_log2_ceil(n
) + stb_log2_ceil(n
) >= 32) return NULL
;
12687 p
= stb_smalloc(n
*sz
);
12688 if (p
) memset(p
, 0, n
*sz
);
12692 char *stb_sstrdup(char *s
)
12695 char *p
= (char *) stb_smalloc(n
+1);
12696 if (p
) strcpy(p
,s
);
12699 #endif // STB_DEFINE
12703 //////////////////////////////////////////////////////////////////////////////
12705 // Source code constants
12707 // This is a trivial system to let you specify constants in source code,
12708 // then while running you can change the constants.
12710 // Note that you can't wrap the #defines, because we need to know their
12711 // names. So we provide a pre-wrapped version without 'STB_' for convenience;
12712 // to request it, #define STB_CONVENIENT_H, yielding:
12714 // KU -- unsigned integer
12717 // KS -- string constant
12719 // Defaults to functioning in debug build, not in release builds.
12720 // To force on, define STB_ALWAYS_H
12722 #ifdef STB_CONVENIENT_H
12723 #define KI(x) STB_I(x)
12724 #define KU(x) STB_UI(x)
12725 #define KF(x) STB_F(x)
12726 #define KD(x) STB_D(x)
12727 #define KS(x) STB_S(x)
12730 STB_EXTERN
void stb_source_path(char *str
);
12732 char *stb__source_path
;
12733 void stb_source_path(char *path
)
12735 stb__source_path
= path
;
12738 char *stb__get_sourcefile_path(char *file
)
12740 static char filebuf
[512];
12741 if (stb__source_path
) {
12742 sprintf(filebuf
, "%s/%s", stb__source_path
, file
);
12743 if (stb_fexists(filebuf
)) return filebuf
;
12746 if (stb_fexists(file
)) return file
;
12748 sprintf(filebuf
, "../%s", file
);
12749 if (!stb_fexists(filebuf
)) return filebuf
;
12755 #define STB_F(x) ((float) STB_H(x))
12756 #define STB_UI(x) ((unsigned int) STB_I(x))
12758 #if !defined(STB_DEBUG) && !defined(STB_ALWAYS_H)
12759 #define STB_D(x) ((double) (x))
12760 #define STB_I(x) ((int) (x))
12761 #define STB_S(x) ((char *) (x))
12763 #define STB_D(x) stb__double_constant(__FILE__, __LINE__-1, (x))
12764 #define STB_I(x) stb__int_constant(__FILE__, __LINE__-1, (x))
12765 #define STB_S(x) stb__string_constant(__FILE__, __LINE__-1, (x))
12767 STB_EXTERN
double stb__double_constant(char *file
, int line
, double x
);
12768 STB_EXTERN
int stb__int_constant(char *file
, int line
, int x
);
12769 STB_EXTERN
char * stb__string_constant(char *file
, int line
, char *str
);
12795 stb__Entry
*entries
;
12800 unsigned short *line_index
;
12803 static void stb__constant_parse(stb__FileEntry
*f
, int i
)
12807 if (!stb_arr_valid(f
->entries
, i
)) return;
12808 n
= f
->entries
[i
].line
;
12809 if (n
>= f
->file_len
) return;
12810 s
= f
->file_data
[n
];
12811 switch (f
->entries
[i
].type
) {
12812 case STB__CTYPE_float
:
12814 if (!strncmp(s
, "STB_D(", 6)) { s
+=6; goto matched_float
; }
12815 if (!strncmp(s
, "STB_F(", 6)) { s
+=6; goto matched_float
; }
12816 if (!strncmp(s
, "KD(", 3)) { s
+=3; goto matched_float
; }
12817 if (!strncmp(s
, "KF(", 3)) { s
+=3; goto matched_float
; }
12822 f
->entries
[i
].dval
= strtod(s
, NULL
);
12824 case STB__CTYPE_int
:
12826 if (!strncmp(s
, "STB_I(", 6)) { s
+=6; goto matched_int
; }
12827 if (!strncmp(s
, "STB_UI(", 7)) { s
+=7; goto matched_int
; }
12828 if (!strncmp(s
, "KI(", 3)) { s
+=3; goto matched_int
; }
12829 if (!strncmp(s
, "KU(", 3)) { s
+=3; goto matched_int
; }
12835 s
= stb_skipwhite(s
);
12836 while (*s
== '-') { neg
= !neg
; s
= stb_skipwhite(s
+1); } // handle '- - 5', pointlessly
12837 if (s
[0] == '0' && tolower(s
[1]) == 'x')
12838 f
->entries
[i
].ival
= strtol(s
, NULL
, 16);
12839 else if (s
[0] == '0')
12840 f
->entries
[i
].ival
= strtol(s
, NULL
, 8);
12842 f
->entries
[i
].ival
= strtol(s
, NULL
, 10);
12843 if (neg
) f
->entries
[i
].ival
= -f
->entries
[i
].ival
;
12846 case STB__CTYPE_string
:
12852 static stb_sdict
*stb__constant_file_hash
;
12854 stb__Entry
*stb__constant_get_entry(char *filename
, int line
, int type
)
12858 if (stb__constant_file_hash
== NULL
)
12859 stb__constant_file_hash
= stb_sdict_new(STB_TRUE
);
12860 f
= (stb__FileEntry
*) stb_sdict_get(stb__constant_file_hash
, filename
);
12862 char *s
= stb__get_sourcefile_path(filename
);
12863 if (s
== NULL
|| !stb_fexists(s
)) return 0;
12864 f
= (stb__FileEntry
*) malloc(sizeof(*f
));
12865 f
->timestamp
= stb_ftimestamp(s
);
12866 f
->file_data
= stb_stringfile(s
, &f
->file_len
);
12867 f
->filename
= strdup(s
); // cache the full path
12870 stb_arr_setlen(f
->line_index
, f
->file_len
);
12871 memset(f
->line_index
, 0xff, stb_arr_storage(f
->line_index
));
12873 time_t t
= stb_ftimestamp(f
->filename
);
12874 if (f
->timestamp
!= t
) {
12876 free(f
->file_data
);
12877 f
->file_data
= stb_stringfile(f
->filename
, &f
->file_len
);
12878 stb_arr_setlen(f
->line_index
, f
->file_len
);
12879 for (i
=0; i
< stb_arr_len(f
->entries
); ++i
)
12880 stb__constant_parse(f
, i
);
12884 if (line
>= f
->file_len
) return 0;
12886 if (f
->line_index
[line
] >= stb_arr_len(f
->entries
)) {
12887 // need a new entry
12888 int n
= stb_arr_len(f
->entries
);
12891 if (line
< f
->file_len
)
12892 f
->line_index
[line
] = n
;
12894 stb_arr_push(f
->entries
, e
);
12895 stb__constant_parse(f
, n
);
12897 return f
->entries
+ f
->line_index
[line
];
12900 double stb__double_constant(char *file
, int line
, double x
)
12902 stb__Entry
*e
= stb__constant_get_entry(file
, line
, STB__CTYPE_float
);
12907 int stb__int_constant(char *file
, int line
, int x
)
12909 stb__Entry
*e
= stb__constant_get_entry(file
, line
, STB__CTYPE_int
);
12914 char * stb__string_constant(char *file
, int line
, char *x
)
12916 stb__Entry
*e
= stb__constant_get_entry(file
, line
, STB__CTYPE_string
);
12921 #endif // STB_DEFINE
12922 #endif // !STB_DEBUG && !STB_ALWAYS_H
12926 //////////////////////////////////////////////////////////////////////////
12928 // stua: little scripting language
12930 // define STB_STUA to compile it
12932 // see http://nothings.org/stb/stb_stua.html for documentation
12934 // basic parsing model:
12936 // lexical analysis
12937 // use stb_lex() to parse tokens; keywords get their own tokens
12940 // recursive descent parser. too much of a hassle to make an unambiguous
12941 // LR(1) grammar, and one-pass generation is clumsier (recursive descent
12942 // makes it easier to e.g. compile nested functions). on the other hand,
12943 // dictionary syntax required hackery to get extra lookahead.
12946 // output into an evaluation tree, using array indices as 'pointers'
12949 // traverse the tree; support for 'break/continue/return' is tricky
12951 // garbage collection:
12952 // stu__mark and sweep; explicit stack with non-stu__compile_global_scope roots
12954 typedef stb_int32 stua_obj
;
12956 typedef stb_idict stua_dict
;
12958 STB_EXTERN
void stua_run_script(char *s
);
12959 STB_EXTERN
void stua_uninit(void);
12961 extern stua_obj stua_globals
;
12963 STB_EXTERN
double stua_number(stua_obj z
);
12965 STB_EXTERN stua_obj
stua_getnil(void);
12966 STB_EXTERN stua_obj
stua_getfalse(void);
12967 STB_EXTERN stua_obj
stua_gettrue(void);
12968 STB_EXTERN stua_obj
stua_string(char *z
);
12969 STB_EXTERN stua_obj
stua_make_number(double d
);
12970 STB_EXTERN stua_obj
stua_box(int type
, void *data
, int size
);
12974 STUA_op_negate
=129,
12975 STUA_op_shl
, STUA_op_ge
,
12976 STUA_op_shr
, STUA_op_le
,
12981 #define STUA_NO_VALUE 2 // equivalent to a tagged NULL
12982 STB_EXTERN
stua_obj (*stua_overload
)(int op
, stua_obj a
, stua_obj b
, stua_obj c
);
12984 STB_EXTERN stua_obj
stua_error(char *err
, ...);
12986 STB_EXTERN stua_obj
stua_pushroot(stua_obj o
);
12987 STB_EXTERN
void stua_poproot ( void );
12993 // 31-bit floating point implementation
12994 // force the (1 << 30) bit (2nd highest bit) to be zero by re-biasing the exponent;
12995 // then shift and set the bottom bit
12997 static stua_obj
stu__floatp(float *f
)
12999 unsigned int n
= *(unsigned int *) f
;
13000 unsigned int e
= n
& (0xff << 23);
13002 assert(sizeof(int) == 4 && sizeof(float) == 4);
13005 n
= n
; // no change
13006 else if (e
< (64 << 23)) // underflow of the packed encoding?
13007 n
= (n
& 0x80000000); // signed 0
13008 else if (e
> (190 << 23)) // overflow of the encoding? (or INF or NAN)
13009 n
= (n
& 0x80000000) + (127 << 23); // new INF encoding
13013 // now we need to shuffle the bits so that the spare bit is at the bottom
13014 assert((n
& 0x40000000) == 0);
13015 return (n
& 0x80000000) + (n
<< 1) + 1;
13018 static unsigned char stu__getfloat_addend
[256];
13019 static float stu__getfloat(stua_obj v
)
13022 unsigned int e
= ((unsigned int) v
) >> 24;
13024 n
= (int) v
>> 1; // preserve high bit
13025 n
+= stu__getfloat_addend
[e
] << 24;
13026 return *(float *) &n
;
13029 stua_obj
stua_float(float f
)
13031 return stu__floatp(&f
);
13034 static void stu__float_init(void)
13037 stu__getfloat_addend
[0] = 0; // do nothing to biased exponent of 0
13038 for (i
=1; i
< 127; ++i
)
13039 stu__getfloat_addend
[i
] = 32; // undo the -0x20000000
13040 stu__getfloat_addend
[127] = 64; // convert packed INF to INF (0x3f -> 0x7f)
13042 for (i
=0; i
< 128; ++i
) // for signed floats, remove the bit we just shifted down
13043 stu__getfloat_addend
[128+i
] = stu__getfloat_addend
[i
] - 64;
13046 // Tagged data type implementation
13049 #define stu__int_tag 0 // of 2 bits // 00 int
13050 #define stu__float_tag 1 // of 1 bit // 01 float
13051 #define stu__ptr_tag 2 // of 2 bits // 10 boxed
13054 #define stu__tag(x) ((x) & 3)
13055 #define stu__number(x) (stu__tag(x) != stu__ptr_tag)
13056 #define stu__isint(x) (stu__tag(x) == stu__int_tag)
13058 #define stu__int(x) ((x) >> 2)
13059 #define stu__float(x) (stu__getfloat(x))
13061 #define stu__makeint(v) ((v)*4+stu__int_tag)
13063 // boxed data, and tag support for boxed data
13067 STU___float
= 1, STU___int
= 2,
13068 STU___number
= 3, STU___string
= 4,
13069 STU___function
= 5, STU___dict
= 6,
13070 STU___boolean
= 7, STU___error
= 8,
13074 #define STU__BOX short type, stua_gc
13075 typedef struct stu__box
{ STU__BOX
; } stu__box
;
13077 stu__box stu__nil
= { 0, 1 };
13078 stu__box stu__true
= { STU___boolean
, 1, };
13079 stu__box stu__false
= { STU___boolean
, 1, };
13081 #define stu__makeptr(v) ((stua_obj) (v) + stu__ptr_tag)
13083 #define stua_nil stu__makeptr(&stu__nil)
13084 #define stua_true stu__makeptr(&stu__true)
13085 #define stua_false stu__makeptr(&stu__false)
13087 stua_obj
stua_getnil(void) { return stua_nil
; }
13088 stua_obj
stua_getfalse(void) { return stua_false
; }
13089 stua_obj
stua_gettrue(void) { return stua_true
; }
13091 #define stu__ptr(x) ((stu__box *) ((x) - stu__ptr_tag))
13093 #define stu__checkt(t,x) ((t) == STU___float ? ((x) & 1) == stu__float_tag : \
13094 (t) == STU___int ? stu__isint(x) : \
13095 (t) == STU___number ? stu__number(x) : \
13096 stu__tag(x) == stu__ptr_tag && stu__ptr(x)->type == (t))
13104 // implementation of a 'function' or function + closure
13106 typedef struct stu__func
13109 stua_obj closure_source
; // 0 - regular function; 4 - C function
13110 // if closure, pointer to source function
13112 stua_obj closure_data
; // partial-application data
13113 void *store
; // pointer to free that holds 'code'
13114 stua_obj (*func
)(stua_dict
*context
);
13116 // closure ends here
13119 stua_obj
*param
; // list of parameter strings
13122 // apply this to 'short *code' to get at data
13123 #define stu__const(f) ((stua_obj *) (f))
13125 static void stu__free_func(stu__func
*f
)
13127 if (f
->closure_source
== 0) free(f
->f
.store
);
13128 if ((stb_uint
) f
->closure_source
<= 4) free(f
->param
);
13132 #define stu__pd(x) ((stua_dict *) stu__ptr(x))
13133 #define stu__pw(x) ((stu__wrapper *) stu__ptr(x))
13134 #define stu__pf(x) ((stu__func *) stu__ptr(x))
13137 // garbage-collection
13140 static stu__box
** stu__gc_ptrlist
;
13141 static stua_obj
* stu__gc_root_stack
;
13143 stua_obj
stua_pushroot(stua_obj o
) { stb_arr_push(stu__gc_root_stack
, o
); return o
; }
13144 void stua_poproot ( void ) { stb_arr_pop(stu__gc_root_stack
); }
13146 static stb_sdict
*stu__strings
;
13147 static void stu__mark(stua_obj z
)
13150 stu__box
*p
= stu__ptr(z
);
13151 if (p
->stua_gc
== 1) return; // already marked
13152 assert(p
->stua_gc
== 0);
13155 case STU___function
: {
13156 stu__func
*f
= (stu__func
*) p
;
13157 if ((stb_uint
) f
->closure_source
<= 4) {
13158 if (f
->closure_source
== 0) {
13159 for (i
=1; i
<= f
->code
[0]; ++i
)
13160 if (!stu__number(((stua_obj
*) f
->code
)[-i
]))
13161 stu__mark(((stua_obj
*) f
->code
)[-i
]);
13163 for (i
=0; i
< f
->num_param
; ++i
)
13164 stu__mark(f
->param
[i
]);
13166 stu__mark(f
->closure_source
);
13167 stu__mark(f
->f
.closure_data
);
13172 stua_dict
*e
= (stua_dict
*) p
;
13173 for (i
=0; i
< e
->limit
; ++i
)
13174 if (e
->table
[i
].k
!= STB_IEMPTY
&& e
->table
[i
].k
!= STB_IDEL
) {
13175 if (!stu__number(e
->table
[i
].k
)) stu__mark((int) e
->table
[i
].k
);
13176 if (!stu__number(e
->table
[i
].v
)) stu__mark((int) e
->table
[i
].v
);
13183 static int stu__num_allocs
, stu__size_allocs
;
13184 static stua_obj stu__flow_val
= stua_nil
; // used for break & return
13186 static void stua_gc(int force
)
13189 if (!force
&& stu__num_allocs
== 0 && stu__size_allocs
== 0) return;
13190 stu__num_allocs
= stu__size_allocs
= 0;
13191 //printf("[gc]\n");
13194 for (i
=0; i
< stb_arr_len(stu__gc_ptrlist
); ++i
)
13195 stu__gc_ptrlist
[i
]->stua_gc
= 0;
13197 // stu__mark everything reachable
13198 stu__nil
.stua_gc
= stu__true
.stua_gc
= stu__false
.stua_gc
= 1;
13199 stu__mark(stua_globals
);
13200 if (!stu__number(stu__flow_val
))
13201 stu__mark(stu__flow_val
);
13202 for (i
=0; i
< stb_arr_len(stu__gc_root_stack
); ++i
)
13203 if (!stu__number(stu__gc_root_stack
[i
]))
13204 stu__mark(stu__gc_root_stack
[i
]);
13206 // sweep unreachables
13207 for (i
=0; i
< stb_arr_len(stu__gc_ptrlist
);) {
13208 stu__box
*z
= stu__gc_ptrlist
[i
];
13211 case STU___dict
: stb_idict_destroy((stua_dict
*) z
); break;
13212 case STU___error
: free(((stu__wrapper
*) z
)->ptr
); break;
13213 case STU___string
: stb_sdict_remove(stu__strings
, (char*) ((stu__wrapper
*) z
)->ptr
, NULL
); free(z
); break;
13214 case STU___function
: stu__free_func((stu__func
*) z
); break;
13216 // swap in the last item over this, and repeat
13217 z
= stb_arr_pop(stu__gc_ptrlist
);
13218 stu__gc_ptrlist
[i
] = z
;
13224 static void stu__consider_gc(stua_obj x
)
13226 if (stu__size_allocs
< 100000) return;
13227 if (stu__num_allocs
< 10 && stu__size_allocs
< 1000000) return;
13228 stb_arr_push(stu__gc_root_stack
, x
);
13230 stb_arr_pop(stu__gc_root_stack
);
13233 static stua_obj
stu__makeobj(int type
, void *data
, int size
, int safe_to_gc
)
13235 stua_obj x
= stu__makeptr(data
);
13236 ((stu__box
*) data
)->type
= type
;
13237 stb_arr_push(stu__gc_ptrlist
, (stu__box
*) data
);
13238 stu__num_allocs
+= 1;
13239 stu__size_allocs
+= size
;
13240 if (safe_to_gc
) stu__consider_gc(x
);
13244 stua_obj
stua_box(int type
, void *data
, int size
)
13246 stu__wrapper
*p
= (stu__wrapper
*) malloc(sizeof(*p
));
13248 return stu__makeobj(type
, p
, size
, 0);
13251 // a stu string can be directly compared for equality, because
13252 // they go into a hash table
13253 stua_obj
stua_string(char *z
)
13255 stu__wrapper
*b
= (stu__wrapper
*) stb_sdict_get(stu__strings
, z
);
13257 int o
= stua_box(STU___string
, NULL
, strlen(z
) + sizeof(*b
));
13259 stb_sdict_add(stu__strings
, z
, b
);
13260 stb_sdict_getkey(stu__strings
, z
, (char **) &b
->ptr
);
13262 return stu__makeptr(b
);
13265 // stb_obj dictionary is just an stb_idict
13266 static void stu__set(stua_dict
*d
, stua_obj k
, stua_obj v
)
13267 { if (stb_idict_set(d
, k
, v
)) stu__size_allocs
+= 8; }
13269 static stua_obj
stu__get(stua_dict
*d
, stua_obj k
, stua_obj res
)
13271 stb_idict_get_flag(d
, k
, &res
);
13275 static stua_obj
make_string(char *z
, int len
)
13278 char temp
[256], *q
= (char *) stb_temp(temp
, len
+1), *p
= q
;
13281 if (z
[1] == 'n') *p
= '\n';
13282 else if (z
[1] == 'r') *p
= '\r';
13283 else if (z
[1] == 't') *p
= '\t';
13285 p
+= 1; z
+= 2; len
-= 2;
13287 *p
++ = *z
++; len
-= 1;
13291 s
= stua_string(q
);
13292 stb_tempfree(temp
, q
);
13299 ST_shl
= STUA_op_shl
, ST_ge
= STUA_op_ge
,
13300 ST_shr
= STUA_op_shr
, ST_le
= STUA_op_le
,
13301 ST_shru
= STUA_op_shru
, STU__negate
= STUA_op_negate
,
13302 ST__reset_numbering
= STUA_op_last
,
13304 ST_id
, ST_float
, ST_decimal
, ST_hex
, ST_char
,ST_string
, ST_number
,
13305 // make sure the keywords come _AFTER_ ST_id, so stb_lex prefer them
13306 ST_if
, ST_while
, ST_for
, ST_eq
, ST_nil
,
13307 ST_then
, ST_do
, ST_in
, ST_ne
, ST_true
,
13308 ST_else
, ST_break
, ST_let
, ST_and
, ST_false
,
13309 ST_elseif
, ST_continue
, ST_into
, ST_or
, ST_repeat
,
13310 ST_end
, ST_as
, ST_return
, ST_var
, ST_func
,
13311 ST_catch
, ST__frame
,
13314 STU__defaultparm
, STU__seq
,
13317 static stua_dict
* stu__globaldict
;
13318 stua_obj stua_globals
;
13322 FLOW_normal
, FLOW_continue
, FLOW_break
, FLOW_return
, FLOW_error
,
13325 stua_obj
stua_error(char *z
, ...)
13328 char temp
[4096], *x
;
13329 va_list v
; va_start(v
,z
); vsprintf(temp
, z
, v
); va_end(v
);
13331 a
= stua_box(STU___error
, x
, strlen(x
));
13332 stu__flow
= FLOW_error
;
13337 double stua_number(stua_obj z
)
13339 return stu__tag(z
) == stu__int_tag
? stu__int(z
) : stu__float(z
);
13342 stua_obj
stua_make_number(double d
)
13344 double e
= floor(d
);
13345 if (e
== d
&& e
< (1 << 29) && e
>= -(1 << 29))
13346 return stu__makeint((int) e
);
13348 return stua_float((float) d
);
13351 stua_obj (*stua_overload
)(int op
, stua_obj a
, stua_obj b
, stua_obj c
) = NULL
;
13353 static stua_obj
stu__op(int op
, stua_obj a
, stua_obj b
, stua_obj c
)
13355 stua_obj r
= STUA_NO_VALUE
;
13357 if (stu__checkt(STU___string
, a
) && stu__checkt(STU___string
, b
)) {
13358 ;// @TODO: string concatenation
13359 } else if (stu__checkt(STU___function
, a
) && stu__checkt(STU___dict
, b
)) {
13360 stu__func
*f
= (stu__func
*) malloc(12);
13361 assert(offsetof(stu__func
, code
)==12);
13362 f
->closure_source
= a
;
13363 f
->f
.closure_data
= b
;
13364 return stu__makeobj(STU___function
, f
, 16, 1);
13367 if (stua_overload
) r
= stua_overload(op
,a
,b
,c
);
13368 if (stu__flow
!= FLOW_error
&& r
== STUA_NO_VALUE
)
13369 stua_error("Typecheck for operator %d", op
), r
=stua_nil
;
13373 #define STU__EVAL2(a,b) \
13374 a = stu__eval(stu__f[n+1]); if (stu__flow) break; stua_pushroot(a); \
13375 b = stu__eval(stu__f[n+2]); stua_poproot(); if (stu__flow) break;
13377 #define STU__FB(op) \
13379 if (stu__tag(a) == stu__int_tag && stu__tag(b) == stu__int_tag) \
13380 return ((a) op (b)); \
13381 if (stu__number(a) && stu__number(b)) \
13382 return stua_make_number(stua_number(a) op stua_number(b)); \
13383 return stu__op(stu__f[n], a,b, stua_nil)
13385 #define STU__F(op) \
13387 if (stu__number(a) && stu__number(b)) \
13388 return stua_make_number(stua_number(a) op stua_number(b)); \
13389 return stu__op(stu__f[n], a,b, stua_nil)
13391 #define STU__I(op) \
13393 if (stu__tag(a) == stu__int_tag && stu__tag(b) == stu__int_tag) \
13394 return stu__makeint(stu__int(a) op stu__int(b)); \
13395 return stu__op(stu__f[n], a,b, stua_nil)
13397 #define STU__C(op) \
13399 if (stu__number(a) && stu__number(b)) \
13400 return (stua_number(a) op stua_number(b)) ? stua_true : stua_false; \
13401 return stu__op(stu__f[n], a,b, stua_nil)
13403 #define STU__CE(op) \
13405 return (a op b) ? stua_true : stua_false
13407 static short *stu__f
;
13408 static stua_obj stu__f_obj
;
13409 static stua_dict
*stu__c
;
13410 static stua_obj
stu__funceval(stua_obj fo
, stua_obj co
);
13412 static int stu__cond(stua_obj x
)
13414 if (stu__flow
) return 0;
13415 if (!stu__checkt(STU___boolean
, x
))
13416 x
= stu__op('!', x
, stua_nil
, stua_nil
);
13417 if (x
== stua_true
) return 1;
13418 if (x
== stua_false
) return 0;
13419 stu__flow
= FLOW_error
;
13423 // had to manually eliminate tailcall recursion for debugging complex stuff
13424 #define TAILCALL(x) n = (x); goto top;
13425 static stua_obj
stu__eval(int n
)
13428 if (stu__flow
>= FLOW_return
) return stua_nil
; // is this needed?
13429 if (n
< 0) return stu__const(stu__f
)[n
];
13430 assert(n
!= 0 && n
!= 1);
13431 switch (stu__f
[n
]) {
13433 case ST_catch
: a
= stu__eval(stu__f
[n
+1]);
13434 if (stu__flow
== FLOW_error
) { a
=stu__flow_val
; stu__flow
= FLOW_normal
; }
13436 case ST_var
: b
= stu__eval(stu__f
[n
+2]); if (stu__flow
) break;
13437 stu__set(stu__c
, stu__const(stu__f
)[stu__f
[n
+1]], b
);
13439 case STU__seq
: stu__eval(stu__f
[n
+1]); if (stu__flow
) break;
13440 TAILCALL(stu__f
[n
+2]);
13441 case ST_if
: if (!stu__cond(stu__eval(stu__f
[n
+1]))) return stua_nil
;
13442 TAILCALL(stu__f
[n
+2]);
13443 case ST_else
: a
= stu__cond(stu__eval(stu__f
[n
+1]));
13444 TAILCALL(stu__f
[n
+ 2 + !a
]);
13445 #define STU__HANDLE_BREAK \
13446 if (stu__flow >= FLOW_break) { \
13447 if (stu__flow == FLOW_break) { \
13448 a = stu__flow_val; \
13449 stu__flow = FLOW_normal; \
13450 stu__flow_val = stua_nil; \
13455 case ST_as
: stu__eval(stu__f
[n
+3]);
13458 case ST_while
: a
= stua_nil
; stua_pushroot(a
);
13459 while (stu__cond(stu__eval(stu__f
[n
+1]))) {
13461 a
= stu__eval(stu__f
[n
+2]);
13463 stu__flow
= FLOW_normal
; // clear 'continue' flag
13465 if (stu__f
[n
+3]) stu__eval(stu__f
[n
+3]);
13467 stu__flow
= FLOW_normal
; // clear 'continue' flag
13471 case ST_break
: stu__flow
= FLOW_break
; stu__flow_val
= stu__eval(stu__f
[n
+1]); break;
13472 case ST_continue
:stu__flow
= FLOW_continue
; break;
13473 case ST_return
: stu__flow
= FLOW_return
; stu__flow_val
= stu__eval(stu__f
[n
+1]); break;
13474 case ST__frame
: return stu__f_obj
;
13475 case '[': STU__EVAL2(a
,b
);
13476 if (stu__checkt(STU___dict
, a
))
13477 return stu__get(stu__pd(a
), b
, stua_nil
);
13478 return stu__op(stu__f
[n
], a
, b
, stua_nil
);
13479 case '=': a
= stu__eval(stu__f
[n
+2]); if (stu__flow
) break;
13481 if (stu__f
[n
] == ST_id
) {
13482 if (!stb_idict_update(stu__c
, stu__const(stu__f
)[stu__f
[n
+1]], a
))
13483 if (!stb_idict_update(stu__globaldict
, stu__const(stu__f
)[stu__f
[n
+1]], a
))
13484 return stua_error("Assignment to undefined variable");
13485 } else if (stu__f
[n
] == '[') {
13487 b
= stu__eval(stu__f
[n
+1]); if (stu__flow
) { stua_poproot(); break; }
13489 c
= stu__eval(stu__f
[n
+2]); stua_poproot(); stua_poproot();
13490 if (stu__flow
) break;
13491 if (!stu__checkt(STU___dict
, b
)) return stua_nil
;
13492 stu__set(stu__pd(b
), c
, a
);
13494 return stu__op(stu__f
[n
], stu__eval(n
), a
, stua_nil
);
13497 case STU__defaultparm
:
13498 a
= stu__eval(stu__f
[n
+2]);
13499 stu__flow
= FLOW_normal
;
13500 if (stb_idict_add(stu__c
, stu__const(stu__f
)[stu__f
[n
+1]], a
))
13501 stu__size_allocs
+= 8;
13503 case ST_id
: a
= stu__get(stu__c
, stu__const(stu__f
)[stu__f
[n
+1]], STUA_NO_VALUE
); // try local variable
13504 return a
!= STUA_NO_VALUE
// else try stu__compile_global_scope variable
13505 ? a
: stu__get(stu__globaldict
, stu__const(stu__f
)[stu__f
[n
+1]], stua_nil
);
13506 case STU__negate
:a
= stu__eval(stu__f
[n
+1]); if (stu__flow
) break;
13507 return stu__isint(a
) ? -a
: stu__op(stu__f
[n
], a
, stua_nil
, stua_nil
);
13508 case '~': a
= stu__eval(stu__f
[n
+1]); if (stu__flow
) break;
13509 return stu__isint(a
) ? (~a
)&~3 : stu__op(stu__f
[n
], a
, stua_nil
, stua_nil
);
13510 case '!': a
= stu__eval(stu__f
[n
+1]); if (stu__flow
) break;
13511 a
= stu__cond(a
); if (stu__flow
) break;
13512 return a
? stua_true
: stua_false
;
13513 case ST_eq
: STU__CE(==); case ST_le
: STU__C(<=); case '<': STU__C(<);
13514 case ST_ne
: STU__CE(!=); case ST_ge
: STU__C(>=); case '>': STU__C(>);
13515 case '+' : STU__FB(+); case '*': STU__F(*); case '&': STU__I(&); case ST_shl
: STU__I(<<);
13516 case '-' : STU__FB(-); case '/': STU__F(/); case '|': STU__I(|); case ST_shr
: STU__I(>>);
13517 case '%': STU__I(%); case '^': STU__I(^);
13518 case ST_shru
: STU__EVAL2(a
,b
);
13519 if (stu__tag(a
) == stu__int_tag
&& stu__tag(b
) == stu__int_tag
)
13520 return stu__makeint((unsigned) stu__int(a
) >> stu__int(b
));
13521 return stu__op(stu__f
[n
], a
,b
, stua_nil
);
13522 case ST_and
: a
= stu__eval(stu__f
[n
+1]); b
= stu__cond(a
); if (stu__flow
) break;
13523 return a
? stu__eval(stu__f
[n
+2]) : a
;
13524 case ST_or
: a
= stu__eval(stu__f
[n
+1]); b
= stu__cond(a
); if (stu__flow
) break;
13525 return a
? b
: stu__eval(stu__f
[n
+2]);
13526 case'(':case':': STU__EVAL2(a
,b
);
13527 if (!stu__checkt(STU___function
, a
))
13528 return stu__op(stu__f
[n
], a
,b
, stua_nil
);
13529 if (!stu__checkt(STU___dict
, b
))
13531 if (stu__f
[n
] == ':')
13532 b
= stu__makeobj(STU___dict
, stb_idict_copy(stu__pd(b
)), stb_idict_memory_usage(stu__pd(b
)), 0);
13533 a
= stu__funceval(a
,b
);
13537 d
= stb_idict_new_size(stu__f
[n
+1] > 40 ? 64 : 16);
13539 return stua_nil
; // breakpoint fodder
13540 c
= stu__makeobj(STU___dict
, d
, 32, 1);
13543 for (b
=0; b
< a
; ++b
) {
13544 stua_obj x
= stua_pushroot(stu__eval(stu__f
[n
+2 + b
*2 + 0]));
13545 stua_obj y
= stu__eval(stu__f
[n
+2 + b
*2 + 1]);
13547 if (stu__flow
) { stua_poproot(); return stua_nil
; }
13553 default: if (stu__f
[n
] < 0) return stu__const(stu__f
)[stu__f
[n
]];
13554 assert(0); /* NOTREACHED */ // internal error!
13559 int stb__stua_nesting
;
13560 static stua_obj
stu__funceval(stua_obj fo
, stua_obj co
)
13562 stu__func
*f
= stu__pf(fo
);
13563 stua_dict
*context
= stu__pd(co
);
13566 short *tf
= stu__f
; // save previous function
13567 stua_dict
*tc
= stu__c
;
13569 if (stu__flow
== FLOW_error
) return stua_nil
;
13570 assert(stu__flow
== FLOW_normal
);
13574 stu__consider_gc(stua_nil
);
13576 while ((stb_uint
) f
->closure_source
> 4) {
13577 // add data from closure to context
13578 stua_dict
*e
= (stua_dict
*) stu__pd(f
->f
.closure_data
);
13579 for (i
=0; i
< e
->limit
; ++i
)
13580 if (e
->table
[i
].k
!= STB_IEMPTY
&& e
->table
[i
].k
!= STB_IDEL
)
13581 if (stb_idict_add(context
, e
->table
[i
].k
, e
->table
[i
].v
))
13582 stu__size_allocs
+= 8;
13583 // use add so if it's already defined, we don't override it; that way
13584 // explicit parameters win over applied ones, and most recent applications
13585 // win over previous ones
13586 f
= stu__pf(f
->closure_source
);
13589 for (j
=0, i
=0; i
< f
->num_param
; ++i
)
13590 // if it doesn't already exist, add it from the numbered parameters
13591 if (stb_idict_add(context
, f
->param
[i
], stu__get(context
, stu__int(j
), stua_nil
)))
13594 // @TODO: if (stu__get(context, stu__int(f->num_param+1)) != STUA_NO_VALUE) // error: too many parameters
13595 // @TODO: ditto too few parameters
13597 if (f
->closure_source
== 4)
13598 p
= f
->f
.func(context
);
13600 stu__f
= f
->code
, stu__c
= context
;
13602 ++stb__stua_nesting
;
13604 p
= stu__eval(stu__f
[1]);
13607 --stb__stua_nesting
;
13608 stu__f
= tf
, stu__c
= tc
; // restore previous function
13609 if (stu__flow
== FLOW_return
) {
13610 stu__flow
= FLOW_normal
;
13612 stu__flow_val
= stua_nil
;
13624 static int stu__tok
;
13625 static stua_obj stu__tokval
;
13627 static char *stu__curbuf
, *stu__bufstart
;
13629 static stb_matcher
*stu__lex_matcher
;
13631 static unsigned char stu__prec
[ST__max_terminals
], stu__end
[ST__max_terminals
];
13633 static void stu__nexttoken(void)
13638 stu__tok
= stb_lex(stu__lex_matcher
, stu__curbuf
, &len
);
13642 case ST_white
: stu__curbuf
+= len
; goto retry
;
13643 case T__none
: stu__tok
= *stu__curbuf
; break;
13644 case ST_string
: stu__tokval
= make_string(stu__curbuf
+1, len
-2); break;
13645 case ST_id
: stu__tokval
= make_string(stu__curbuf
, len
); break;
13646 case ST_hex
: stu__tokval
= stu__makeint(strtol(stu__curbuf
+2,NULL
,16)); stu__tok
= ST_number
; break;
13647 case ST_decimal
: stu__tokval
= stu__makeint(strtol(stu__curbuf
,NULL
,10)); stu__tok
= ST_number
; break;
13648 case ST_float
: stu__tokval
= stua_float((float) atof(stu__curbuf
)) ; stu__tok
= ST_number
; break;
13649 case ST_char
: stu__tokval
= stu__curbuf
[2] == '\\' ? stu__curbuf
[3] : stu__curbuf
[2];
13650 if (stu__curbuf
[3] == 't') stu__tokval
= '\t';
13651 if (stu__curbuf
[3] == 'n') stu__tokval
= '\n';
13652 if (stu__curbuf
[3] == 'r') stu__tokval
= '\r';
13653 stu__tokval
= stu__makeint(stu__tokval
);
13654 stu__tok
= ST_number
;
13657 stu__curbuf
+= len
;
13660 static struct { int stu__tok
; char *regex
; } stu__lexemes
[] =
13662 ST_white
, "([ \t\n\r]|/\\*(.|\n)*\\*/|//[^\r\n]*([\r\n]|$))+",
13663 ST_id
, "[_a-zA-Z][_a-zA-Z0-9]*",
13664 ST_hex
, "0x[0-9a-fA-F]+",
13665 ST_decimal
, "[0-9]+[0-9]*",
13666 ST_float
, "[0-9]+\\.?[0-9]*([eE][-+]?[0-9]+)?",
13667 ST_float
, "\\.[0-9]+([eE][-+]?[0-9]+)?",
13668 ST_char
, "c'(\\\\.|[^\\'])'",
13669 ST_string
, "\"(\\\\.|[^\\\"\n\r])*\"",
13670 ST_string
, "\'(\\\\.|[^\\\'\n\r])*\'",
13672 #define stua_key4(a,b,c,d) ST_##a, #a, ST_##b, #b, ST_##c, #c, ST_##d, #d,
13673 stua_key4(if,then
,else,elseif
) stua_key4(while,do,for,in
)
13674 stua_key4(func
,var
,let
,break) stua_key4(nil
,true,false,end
)
13675 stua_key4(return,continue,as
,repeat
) stua_key4(_frame
,catch,catch,catch)
13677 ST_shl
, "<<", ST_and
, "&&", ST_eq
, "==", ST_ge
, ">=",
13678 ST_shr
, ">>", ST_or
, "||", ST_ne
, "!=", ST_le
, "<=",
13679 ST_shru
,">>>", ST_into
, "=>",
13685 stua_obj
*data
; // constants being compiled
13686 short *code
; // code being compiled
13688 short *non_local_refs
;
13691 static stu__comp_func stu__pfunc
;
13692 static stu__comp_func
*func_stack
= NULL
;
13693 static void stu__push_func_comp(void)
13695 stb_arr_push(func_stack
, stu__pfunc
);
13696 stu__pfunc
.data
= NULL
;
13697 stu__pfunc
.code
= NULL
;
13698 stu__pfunc
.locals
= stb_idict_new_size(16);
13699 stu__pfunc
.non_local_refs
= NULL
;
13700 stb_arr_push(stu__pfunc
.code
, 0); // number of data items
13701 stb_arr_push(stu__pfunc
.code
, 1); // starting execution address
13704 static void stu__pop_func_comp(void)
13706 stb_arr_free(stu__pfunc
.code
);
13707 stb_arr_free(stu__pfunc
.data
);
13708 stb_idict_destroy(stu__pfunc
.locals
);
13709 stb_arr_free(stu__pfunc
.non_local_refs
);
13710 stu__pfunc
= stb_arr_pop(func_stack
);
13713 // if an id is a reference to an outer lexical scope, this
13714 // function returns the "name" of it, and updates the stack
13715 // structures to make sure the names are propogated in.
13716 static int stu__nonlocal_id(stua_obj var_obj
)
13718 stua_obj dummy
, var
= var_obj
;
13719 int i
, n
= stb_arr_len(func_stack
), j
,k
;
13720 if (stb_idict_get_flag(stu__pfunc
.locals
, var
, &dummy
)) return 0;
13721 for (i
=n
-1; i
> 1; --i
) {
13722 if (stb_idict_get_flag(func_stack
[i
].locals
, var
, &dummy
))
13725 if (i
<= 1) return 0; // stu__compile_global_scope
13726 j
= i
; // need to access variable from j'th frame
13727 for (i
=0; i
< stb_arr_len(stu__pfunc
.non_local_refs
); ++i
)
13728 if (stu__pfunc
.non_local_refs
[i
] == j
) return j
-n
;
13729 stb_arr_push(stu__pfunc
.non_local_refs
, j
-n
);
13730 // now make sure all the parents propogate it down
13731 for (k
=n
-1; k
> 1; --k
) {
13732 if (j
-k
>= 0) return j
-n
; // comes direct from this parent
13733 for(i
=0; i
< stb_arr_len(func_stack
[k
].non_local_refs
); ++i
)
13734 if (func_stack
[k
].non_local_refs
[i
] == j
-k
)
13736 stb_arr_push(func_stack
[k
].non_local_refs
, j
-k
);
13743 static int stu__off(void) { return stb_arr_len(stu__pfunc
.code
); }
13744 static void stu__cc(int a
)
13746 assert(a
>= -2000 && a
< 5000);
13747 stb_arr_push(stu__pfunc
.code
, a
);
13749 static int stu__cc1(int a
) { stu__cc(a
); return stu__off()-1; }
13750 static int stu__cc2(int a
, int b
) { stu__cc(a
); stu__cc(b
); return stu__off()-2; }
13751 static int stu__cc3(int a
, int b
, int c
) {
13752 if (a
== '=') assert(c
!= 0);
13753 stu__cc(a
); stu__cc(b
); stu__cc(c
); return stu__off()-3; }
13754 static int stu__cc4(int a
, int b
, int c
, int d
) { stu__cc(a
); stu__cc(b
); stu__cc(c
); stu__cc(d
); return stu__off()-4; }
13756 static int stu__cdv(stua_obj p
)
13759 assert(p
!= STUA_NO_VALUE
);
13760 for (i
=0; i
< stb_arr_len(stu__pfunc
.data
); ++i
)
13761 if (stu__pfunc
.data
[i
] == p
)
13763 if (i
== stb_arr_len(stu__pfunc
.data
))
13764 stb_arr_push(stu__pfunc
.data
, p
);
13768 static int stu__cdt(void)
13770 int z
= stu__cdv(stu__tokval
);
13775 static int stu__seq(int a
, int b
)
13777 return !a
? b
: !b
? a
: stu__cc3(STU__seq
, a
,b
);
13780 static char stu__comp_err_str
[1024];
13781 static int stu__comp_err_line
;
13782 static int stu__err(char *str
, ...)
13785 char *s
= stu__bufstart
;
13786 stu__comp_err_line
= 1;
13787 while (s
< stu__curbuf
) {
13788 if (s
[0] == '\n' || s
[0] == '\r') {
13789 if (s
[0]+s
[1] == '\n' + '\r') ++s
;
13790 ++stu__comp_err_line
;
13795 vsprintf(stu__comp_err_str
, str
, v
);
13800 static int stu__accept(int p
)
13802 if (stu__tok
!= p
) return 0;
13807 static int stu__demand(int p
)
13809 if (stu__accept(p
)) return 1;
13810 return stu__err("Didn't find expected stu__tok");
13813 static int stu__demandv(int p
, stua_obj
*val
)
13815 if (stu__tok
== p
|| p
==0) {
13816 *val
= stu__tokval
;
13823 static int stu__expr(int p
);
13824 int stu__nexpr(int p
) { stu__nexttoken(); return stu__expr(p
); }
13825 static int stu__statements(int once
, int as
);
13827 static int stu__parse_if(void) // parse both ST_if and ST_elseif
13830 a
= stu__nexpr(1); if (!a
) return 0;
13831 if (!stu__demand(ST_then
)) return stu__err("expecting THEN");
13832 b
= stu__statements(0,0); if (!b
) return 0;
13833 if (b
== 1) b
= -1;
13835 if (stu__tok
== ST_elseif
) {
13836 return stu__parse_if();
13837 } else if (stu__accept(ST_else
)) {
13838 c
= stu__statements(0,0); if (!c
) return 0;
13839 if (!stu__demand(ST_end
)) return stu__err("expecting END after else clause");
13840 return stu__cc4(ST_else
, a
, b
, c
);
13842 if (!stu__demand(ST_end
)) return stu__err("expecting END in if statement");
13843 return stu__cc3(ST_if
, a
, b
);
13847 int stu__varinit(int z
, int in_globals
)
13851 while (stu__demandv(ST_id
, &b
)) {
13852 if (!stb_idict_add(stu__pfunc
.locals
, b
, 1))
13853 if (!in_globals
) return stu__err("Redefined variable %s.", stu__pw(b
)->ptr
);
13854 if (stu__accept('=')) {
13855 a
= stu__expr(1); if (!a
) return 0;
13857 a
= stu__cdv(stua_nil
);
13858 z
= stu__seq(z
, stu__cc3(ST_var
, stu__cdv(b
), a
));
13859 if (!stu__accept(',')) break;
13864 static int stu__compile_unary(int z
, int outparm
, int require_inparm
)
13866 int op
= stu__tok
, a
, b
;
13869 if (require_inparm
|| (stu__tok
&& stu__tok
!= ST_end
&& stu__tok
!= ST_else
&& stu__tok
!= ST_elseif
&& stu__tok
!=';')) {
13870 a
= stu__expr(1); if (!a
) return 0;
13872 a
= stu__cdv(stua_nil
);
13873 b
= stu__cc2(op
, a
);
13876 return stu__seq(z
,b
);
13879 static int stu__assign(void)
13882 stu__accept(ST_let
);
13883 z
= stu__expr(1); if (!z
) return 0;
13884 if (stu__accept('=')) {
13885 int y
,p
= (z
>= 0 ? stu__pfunc
.code
[z
] : 0);
13886 if (z
< 0 || (p
!= ST_id
&& p
!= '[')) return stu__err("Invalid lvalue in assignment");
13887 y
= stu__assign(); if (!y
) return 0;
13888 z
= stu__cc3('=', z
, y
);
13893 static int stu__statements(int once
, int stop_while
)
13897 switch (stu__tok
) {
13898 case ST_if
: a
= stu__parse_if(); if (!a
) return 0;
13899 z
= stu__seq(z
, a
);
13901 case ST_while
: if (stop_while
) return (z
? z
:1);
13902 a
= stu__nexpr(1); if (!a
) return 0;
13903 if (stu__accept(ST_as
)) c
= stu__statements(0,0); else c
= 0;
13904 if (!stu__demand(ST_do
)) return stu__err("expecting DO");
13905 b
= stu__statements(0,0); if (!b
) return 0;
13906 if (!stu__demand(ST_end
)) return stu__err("expecting END");
13907 if (b
== 1) b
= -1;
13908 z
= stu__seq(z
, stu__cc4(ST_while
, a
, b
, c
));
13910 case ST_repeat
: stu__nexttoken();
13911 c
= stu__statements(0,1); if (!c
) return 0;
13912 if (!stu__demand(ST_while
)) return stu__err("expecting WHILE");
13913 a
= stu__expr(1); if (!a
) return 0;
13914 if (!stu__demand(ST_do
)) return stu__err("expecting DO");
13915 b
= stu__statements(0,0); if (!b
) return 0;
13916 if (!stu__demand(ST_end
)) return stu__err("expecting END");
13917 if (b
== 1) b
= -1;
13918 z
= stu__seq(z
, stu__cc4(ST_as
, a
, b
, c
));
13920 case ST_catch
: a
= stu__nexpr(1); if (!a
) return 0;
13921 z
= stu__seq(z
, stu__cc2(ST_catch
, a
));
13923 case ST_var
: z
= stu__varinit(z
,0); break;
13924 case ST_return
: z
= stu__compile_unary(z
,1,1); break;
13925 case ST_continue
:z
= stu__compile_unary(z
,0,0); break;
13926 case ST_break
: z
= stu__compile_unary(z
,1,0); break;
13927 case ST_into
: if (z
== 0 && !once
) return stu__err("=> cannot be first statement in block");
13928 a
= stu__nexpr(99);
13929 b
= (a
>= 0? stu__pfunc
.code
[a
] : 0);
13930 if (a
< 0 || (b
!= ST_id
&& b
!= '[')) return stu__err("Invalid lvalue on right side of =>");
13931 z
= stu__cc3('=', a
, z
);
13933 default : if (stu__end
[stu__tok
]) return once
? 0 : (z
? z
:1);
13934 a
= stu__assign(); if (!a
) return 0;
13936 if (stu__tok
&& !stu__end
[stu__tok
]) {
13938 return stu__err("Constant has no effect");
13939 if (stu__pfunc
.code
[a
] != '(' && stu__pfunc
.code
[a
] != '=')
13940 return stu__err("Expression has no effect");
13942 z
= stu__seq(z
, a
);
13947 if (once
&& stu__tok
!= ST_into
) return z
;
13951 static int stu__postexpr(int z
, int p
);
13952 static int stu__dictdef(int end
, int *count
)
13954 int z
,n
=0,i
,flags
=0;
13957 while (stu__tok
!= end
) {
13958 if (stu__tok
== ST_id
) {
13959 stua_obj id
= stu__tokval
;
13961 if (stu__tok
== '=') {
13963 stb_arr_push(dict
, stu__cdv(id
));
13964 z
= stu__nexpr(1); if (!z
) return 0;
13966 z
= stu__cc2(ST_id
, stu__cdv(id
));
13967 z
= stu__postexpr(z
,1); if (!z
) return 0;
13969 stb_arr_push(dict
, stu__cdv(stu__makeint(n
++)));
13972 z
= stu__expr(1); if (!z
) return 0;
13974 stb_arr_push(dict
, stu__cdv(stu__makeint(n
++)));
13976 if (end
!= ')' && flags
== 3) { z
=stu__err("can't mix initialized and uninitialized defs"); goto done
;}
13977 stb_arr_push(dict
, z
);
13978 if (!stu__accept(',')) break;
13980 if (!stu__demand(end
))
13981 return stu__err(end
== ')' ? "Expecting ) at end of function call"
13982 : "Expecting } at end of dictionary definition");
13983 z
= stu__cc2('{', stb_arr_len(dict
)/2);
13984 for (i
=0; i
< stb_arr_len(dict
); ++i
)
13986 if (count
) *count
= n
;
13988 stb_arr_free(dict
);
13992 static int stu__comp_id(void)
13995 d
= stu__nonlocal_id(stu__tokval
);
13997 return z
= stu__cc2(ST_id
, stu__cdt());
13998 // access a non-local frame by naming it with the appropriate int
14000 z
= stu__cdv(d
); // relative frame # is the 'variable' in our local frame
14001 z
= stu__cc2(ST_id
, z
); // now access that dictionary
14002 return stu__cc3('[', z
, stu__cdt()); // now access the variable from that dir
14005 static stua_obj
stu__funcdef(stua_obj
*id
, stua_obj
*func
);
14006 static int stu__expr(int p
)
14010 switch (stu__tok
) {
14011 case ST_number
: z
= stu__cdt(); break;
14012 case ST_string
: z
= stu__cdt(); break; // @TODO - string concatenation like C
14013 case ST_id
: z
= stu__comp_id(); break;
14014 case ST__frame
: z
= stu__cc1(ST__frame
); stu__nexttoken(); break;
14015 case ST_func
: z
= stu__funcdef(NULL
,NULL
); break;
14016 case ST_if
: z
= stu__parse_if(); break;
14017 case ST_nil
: z
= stu__cdv(stua_nil
); stu__nexttoken(); break;
14018 case ST_true
: z
= stu__cdv(stua_true
); stu__nexttoken(); break;
14019 case ST_false
: z
= stu__cdv(stua_false
); stu__nexttoken(); break;
14020 case '-' : z
= stu__nexpr(99); if (z
) z
=stu__cc2(STU__negate
,z
); else return z
; break;
14021 case '!' : z
= stu__nexpr(99); if (z
) z
=stu__cc2('!',z
); else return z
; break;
14022 case '~' : z
= stu__nexpr(99); if (z
) z
=stu__cc2('~',z
); else return z
; break;
14023 case '{' : z
= stu__dictdef('}', NULL
); break;
14024 default : return stu__err("Unexpected token");
14025 case '(' : stu__nexttoken(); z
= stu__statements(0,0); if (!stu__demand(')')) return stu__err("Expecting )");
14027 return stu__postexpr(z
,p
);
14030 static int stu__postexpr(int z
, int p
)
14034 while (stu__tok
== '(' || stu__tok
== '[' || stu__tok
== '.') {
14035 if (stu__accept('.')) {
14036 // MUST be followed by a plain identifier! use [] for other stuff
14037 if (stu__tok
!= ST_id
) return stu__err("Must follow . with plain name; try [] instead");
14038 z
= stu__cc3('[', z
, stu__cdv(stu__tokval
));
14040 } else if (stu__accept('[')) {
14041 while (stu__tok
!= ']') {
14042 int r
= stu__expr(1); if (!r
) return 0;
14043 z
= stu__cc3('[', z
, r
);
14044 if (!stu__accept(',')) break;
14046 if (!stu__demand(']')) return stu__err("Expecting ]");
14048 int n
, p
= stu__dictdef(')', &n
); if (!p
) return 0;
14049 #if 0 // this is incorrect!
14050 if (z
> 0 && stu__pfunc
.code
[z
] == ST_id
) {
14051 stua_obj q
= stu__get(stu__globaldict
, stu__pfunc
.data
[-stu__pfunc
.code
[z
+1]-1], stua_nil
);
14052 if (stu__checkt(STU___function
, q
))
14053 if ((stu__pf(q
))->num_param
!= n
)
14054 return stu__err("Incorrect number of parameters");
14057 z
= stu__cc3('(', z
, p
);
14060 // binop - this implementation taken from lcc
14061 for (q
=stu__prec
[stu__tok
]; q
>= p
; --q
) {
14062 while (stu__prec
[stu__tok
] == q
) {
14063 int o
= stu__tok
, y
= stu__nexpr(p
+1); if (!y
) return 0;
14064 z
= stu__cc3(o
,z
,y
);
14070 static stua_obj
stu__finish_func(stua_obj
*param
, int start
)
14073 stu__func
*f
= (stu__func
*) malloc(sizeof(*f
));
14074 f
->closure_source
= 0;
14075 f
->num_param
= stb_arr_len(param
);
14076 f
->param
= (int *) stb_copy(param
, f
->num_param
* sizeof(*f
->param
));
14077 size
= stb_arr_storage(stu__pfunc
.code
) + stb_arr_storage(stu__pfunc
.data
) + sizeof(*f
) + 8;
14078 f
->f
.store
= malloc(stb_arr_storage(stu__pfunc
.code
) + stb_arr_storage(stu__pfunc
.data
));
14079 f
->code
= (short *) ((char *) f
->f
.store
+ stb_arr_storage(stu__pfunc
.data
));
14080 memcpy(f
->code
, stu__pfunc
.code
, stb_arr_storage(stu__pfunc
.code
));
14081 f
->code
[1] = start
;
14082 f
->code
[0] = stb_arr_len(stu__pfunc
.data
);
14083 for (n
=0; n
< f
->code
[0]; ++n
)
14084 ((stua_obj
*) f
->code
)[-1-n
] = stu__pfunc
.data
[n
];
14085 return stu__makeobj(STU___function
, f
, size
, 0);
14088 static int stu__funcdef(stua_obj
*id
, stua_obj
*result
)
14091 stua_obj
*param
= NULL
;
14093 stua_obj v
,f
=stua_nil
;
14094 assert(stu__tok
== ST_func
);
14097 if (!stu__demandv(ST_id
, id
)) return stu__err("Expecting function name");
14099 stu__accept(ST_id
);
14100 if (!stu__demand('(')) return stu__err("Expecting ( for function parameter");
14101 stu__push_func_comp();
14102 while (stu__tok
!= ')') {
14103 if (!stu__demandv(ST_id
, &v
)) { z
=stu__err("Expecting parameter name"); goto done
; }
14104 stb_idict_add(stu__pfunc
.locals
, v
, 1);
14105 if (stu__tok
== '=') {
14106 n
= stu__nexpr(1); if (!n
) { z
=0; goto done
; }
14107 z
= stu__seq(z
, stu__cc3(STU__defaultparm
, stu__cdv(v
), n
));
14109 stb_arr_push(param
, v
);
14110 if (!stu__accept(',')) break;
14112 if (!stu__demand(')')) { z
=stu__err("Expecting ) at end of parameter list"); goto done
; }
14113 n
= stu__statements(0,0); if (!n
) { z
=0; goto done
; }
14114 if (!stu__demand(ST_end
)) { z
=stu__err("Expecting END at end of function"); goto done
; }
14117 f
= stu__finish_func(param
, n
);
14118 if (result
) { *result
= f
; z
=1; stu__pop_func_comp(); }
14120 nonlocal
= stu__pfunc
.non_local_refs
;
14121 stu__pfunc
.non_local_refs
= NULL
;
14122 stu__pop_func_comp();
14124 if (nonlocal
) { // build a closure with references to the needed frames
14125 short *initcode
= NULL
;
14126 for (i
=0; i
< stb_arr_len(nonlocal
); ++i
) {
14127 int k
= nonlocal
[i
], p
;
14128 stb_arr_push(initcode
, stu__cdv(k
));
14129 if (k
== -1) p
= stu__cc1(ST__frame
);
14130 else { p
= stu__cdv(stu__makeint(k
+1)); p
= stu__cc2(ST_id
, p
); }
14131 stb_arr_push(initcode
, p
);
14133 q
= stu__cc2('{', stb_arr_len(nonlocal
));
14134 for (i
=0; i
< stb_arr_len(initcode
); ++i
)
14135 stu__cc(initcode
[i
]);
14136 z
= stu__cc3('+', z
, q
);
14137 stb_arr_free(initcode
);
14139 stb_arr_free(nonlocal
);
14142 stb_arr_free(param
);
14143 if (!z
) stu__pop_func_comp();
14147 static int stu__compile_global_scope(void)
14152 stu__push_func_comp();
14153 while (stu__tok
!= 0) {
14154 if (stu__tok
== ST_func
) {
14156 if (!stu__funcdef(&id
,&f
))
14158 stu__set(stu__globaldict
, id
, f
);
14159 } else if (stu__tok
== ST_var
) {
14160 z
= stu__varinit(z
,1); if (!z
) goto error
;
14162 int y
= stu__statements(1,0); if (!y
) goto error
;
14167 o
= stu__finish_func(NULL
, z
);
14168 stu__pop_func_comp();
14170 o
= stu__funceval(o
, stua_globals
); // initialize stu__globaldict
14171 if (stu__flow
== FLOW_error
)
14172 printf("Error: %s\n", ((stu__wrapper
*) stu__ptr(stu__flow_val
))->ptr
);
14175 stu__pop_func_comp();
14179 stua_obj
stu__myprint(stua_dict
*context
)
14181 stua_obj x
= stu__get(context
, stua_string("x"), stua_nil
);
14182 if ((x
& 1) == stu__float_tag
) printf("%f", stu__getfloat(x
));
14183 else if (stu__tag(x
) == stu__int_tag
) printf("%d", stu__int(x
));
14185 stu__wrapper
*s
= stu__pw(x
);
14186 if (s
->type
== STU___string
|| s
->type
== STU___error
)
14187 printf("%s", s
->ptr
);
14188 else if (s
->type
== STU___dict
) printf("{{dictionary}}");
14189 else if (s
->type
== STU___function
) printf("[[function]]");
14191 printf("[[ERROR:%s]]", s
->ptr
);
14196 void stua_init(void)
14198 if (!stu__globaldict
) {
14203 stu__prec
[ST_and
] = stu__prec
[ST_or
] = 1;
14204 stu__prec
[ST_eq
] = stu__prec
[ST_ne
] = stu__prec
[ST_le
] =
14205 stu__prec
[ST_ge
] = stu__prec
['>' ] = stu__prec
['<'] = 2;
14206 stu__prec
[':'] = 3;
14207 stu__prec
['&'] = stu__prec
['|'] = stu__prec
['^'] = 4;
14208 stu__prec
['+'] = stu__prec
['-'] = 5;
14209 stu__prec
['*'] = stu__prec
['/'] = stu__prec
['%'] =
14210 stu__prec
[ST_shl
]= stu__prec
[ST_shr
]= stu__prec
[ST_shru
]= 6;
14212 stu__end
[')'] = stu__end
[ST_end
] = stu__end
[ST_else
] = 1;
14213 stu__end
[ST_do
] = stu__end
[ST_elseif
] = 1;
14216 stu__lex_matcher
= stb_lex_matcher();
14217 for (i
=0; i
< sizeof(stu__lexemes
)/sizeof(stu__lexemes
[0]); ++i
)
14218 stb_lex_item(stu__lex_matcher
, stu__lexemes
[i
].regex
, stu__lexemes
[i
].stu__tok
);
14220 stu__globaldict
= stb_idict_new_size(64);
14221 stua_globals
= stu__makeobj(STU___dict
, stu__globaldict
, 0,0);
14222 stu__strings
= stb_sdict_new(0);
14224 stu__curbuf
= stu__bufstart
= "func _print(x) end\n"
14225 "func print()\n var x=0 while _frame[x] != nil as x=x+1 do _print(_frame[x]) end end\n";
14227 if (!stu__compile_global_scope())
14228 printf("Compile error in line %d: %s\n", stu__comp_err_line
, stu__comp_err_str
);
14230 s
= stu__get(stu__globaldict
, stua_string("_print"), stua_nil
);
14231 if (stu__tag(s
) == stu__ptr_tag
&& stu__ptr(s
)->type
== STU___function
) {
14234 f
->closure_source
= 4;
14235 f
->f
.func
= stu__myprint
;
14241 void stua_uninit(void)
14243 if (stu__globaldict
) {
14244 stb_idict_remove_all(stu__globaldict
);
14245 stb_arr_setlen(stu__gc_root_stack
, 0);
14247 stb_idict_destroy(stu__globaldict
);
14248 stb_sdict_delete(stu__strings
);
14249 stb_matcher_free(stu__lex_matcher
);
14250 stb_arr_free(stu__gc_ptrlist
);
14251 stb_arr_free(func_stack
);
14252 stb_arr_free(stu__gc_root_stack
);
14253 stu__globaldict
= NULL
;
14257 void stua_run_script(char *s
)
14261 stu__curbuf
= stu__bufstart
= s
;
14264 stu__flow
= FLOW_normal
;
14266 if (!stu__compile_global_scope())
14267 printf("Compile error in line %d: %s\n", stu__comp_err_line
, stu__comp_err_str
);
14270 #endif // STB_DEFINE
14276 #endif // STB_INCLUDE_STB_H